392 lines
12 KiB
Diff
392 lines
12 KiB
Diff
|
diff -up Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.8.xml.inactive Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.8.xml
|
||
|
--- Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.8.xml.inactive 2011-06-21 11:04:56.000000000 +0200
|
||
|
+++ Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.8.xml 2012-05-09 11:35:42.810209582 +0200
|
||
|
@@ -12,7 +12,7 @@
|
||
|
|
||
|
<refnamediv id="pam_lastlog-name">
|
||
|
<refname>pam_lastlog</refname>
|
||
|
- <refpurpose>PAM module to display date of last login</refpurpose>
|
||
|
+ <refpurpose>PAM module to display date of last login and perform inactive account lock out</refpurpose>
|
||
|
</refnamediv>
|
||
|
|
||
|
<refsynopsisdiv>
|
||
|
@@ -45,6 +45,9 @@
|
||
|
<arg choice="opt">
|
||
|
showfailed
|
||
|
</arg>
|
||
|
+ <arg choice="opt">
|
||
|
+ inactive=<days>
|
||
|
+ </arg>
|
||
|
</cmdsynopsis>
|
||
|
</refsynopsisdiv>
|
||
|
|
||
|
@@ -61,6 +64,12 @@
|
||
|
Some applications may perform this function themselves. In such
|
||
|
cases, this module is not necessary.
|
||
|
</para>
|
||
|
+ <para>
|
||
|
+ If the module is called in the auth or account phase, the accounts that
|
||
|
+ were not used recently enough will be disallowed to log in. The
|
||
|
+ check is not performed for the root account so the root is never
|
||
|
+ locked out.
|
||
|
+ </para>
|
||
|
</refsect1>
|
||
|
|
||
|
<refsect1 id="pam_lastlog-options">
|
||
|
@@ -165,13 +174,30 @@
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
+ <varlistentry>
|
||
|
+ <term>
|
||
|
+ <option>inactive=<days></option>
|
||
|
+ </term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ This option is specific for the auth or account phase. It
|
||
|
+ specifies the number of days after the last login of the user
|
||
|
+ when the user will be locked out by the module. The default
|
||
|
+ value is 90.
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
</variablelist>
|
||
|
</refsect1>
|
||
|
|
||
|
<refsect1 id="pam_lastlog-types">
|
||
|
<title>MODULE TYPES PROVIDED</title>
|
||
|
<para>
|
||
|
- Only the <option>session</option> module type is provided.
|
||
|
+ The <option>auth</option> and <option>account</option> module type
|
||
|
+ allows to lock out users which did not login recently enough.
|
||
|
+ The <option>session</option> module type is provided for displaying
|
||
|
+ the information about the last login and/or updating the lastlog and
|
||
|
+ wtmp files.
|
||
|
</para>
|
||
|
</refsect1>
|
||
|
|
||
|
@@ -207,6 +233,27 @@
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
|
||
|
+ <varlistentry>
|
||
|
+ <term>PAM_AUTH_ERR</term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ User locked out in the auth or account phase due to
|
||
|
+ inactivity.
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
+
|
||
|
+ <varlistentry>
|
||
|
+ <term>PAM_IGNORE</term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ There was an error during reading the lastlog file
|
||
|
+ in the auth or account phase and thus inactivity
|
||
|
+ of the user cannot be determined.
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
+
|
||
|
</variablelist>
|
||
|
</para>
|
||
|
</refsect1>
|
||
|
@@ -220,6 +267,13 @@
|
||
|
<programlisting>
|
||
|
session required pam_lastlog.so nowtmp
|
||
|
</programlisting>
|
||
|
+ <para>
|
||
|
+ To reject the user if he did not login during the previous 50 days
|
||
|
+ the following line can be used:
|
||
|
+ </para>
|
||
|
+ <programlisting>
|
||
|
+ auth required pam_lastlog.so inactive=50
|
||
|
+ </programlisting>
|
||
|
</refsect1>
|
||
|
|
||
|
<refsect1 id="pam_lastlog-files">
|
||
|
@@ -254,6 +308,9 @@
|
||
|
<para>
|
||
|
pam_lastlog was written by Andrew G. Morgan <morgan@kernel.org>.
|
||
|
</para>
|
||
|
+ <para>
|
||
|
+ Inactive account lock out added by Tomáš Mráz <tm@t8m.info>.
|
||
|
+ </para>
|
||
|
</refsect1>
|
||
|
|
||
|
</refentry>
|
||
|
diff -up Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.c.inactive Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.c
|
||
|
--- Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.c.inactive 2011-06-21 11:04:56.000000000 +0200
|
||
|
+++ Linux-PAM-1.1.5/modules/pam_lastlog/pam_lastlog.c 2012-05-09 11:35:22.363759805 +0200
|
||
|
@@ -56,6 +56,9 @@ struct lastlog {
|
||
|
#define DEFAULT_HOST "" /* "[no.where]" */
|
||
|
#define DEFAULT_TERM "" /* "tt???" */
|
||
|
|
||
|
+#define DEFAULT_INACTIVE_DAYS 90
|
||
|
+#define MAX_INACTIVE_DAYS 100000
|
||
|
+
|
||
|
/*
|
||
|
* here, we make a definition for the externally accessible function
|
||
|
* in this file (this definition is required for static a module
|
||
|
@@ -64,6 +67,8 @@ struct lastlog {
|
||
|
*/
|
||
|
|
||
|
#define PAM_SM_SESSION
|
||
|
+#define PAM_SM_AUTH
|
||
|
+#define PAM_SM_ACCOUNT
|
||
|
|
||
|
#include <security/pam_modules.h>
|
||
|
#include <security/_pam_macros.h>
|
||
|
@@ -83,7 +88,45 @@ struct lastlog {
|
||
|
#define LASTLOG_UPDATE 0400 /* update the lastlog and wtmp files (default) */
|
||
|
|
||
|
static int
|
||
|
-_pam_parse(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||
|
+_pam_auth_parse(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
||
|
+ time_t *inactive)
|
||
|
+{
|
||
|
+ int ctrl = 0;
|
||
|
+
|
||
|
+ *inactive = DEFAULT_INACTIVE_DAYS;
|
||
|
+
|
||
|
+ /* does the appliction require quiet? */
|
||
|
+ if (flags & PAM_SILENT) {
|
||
|
+ ctrl |= LASTLOG_QUIET;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* step through arguments */
|
||
|
+ for (; argc-- > 0; ++argv) {
|
||
|
+ char *ep = NULL;
|
||
|
+ long l;
|
||
|
+
|
||
|
+ if (!strcmp(*argv,"debug")) {
|
||
|
+ ctrl |= LASTLOG_DEBUG;
|
||
|
+ } else if (!strcmp(*argv,"silent")) {
|
||
|
+ ctrl |= LASTLOG_QUIET;
|
||
|
+ } else if (!strncmp(*argv,"inactive=", 9)) {
|
||
|
+ l = strtol(*argv+9, &ep, 10);
|
||
|
+ if (ep != *argv+9 && l > 0 && l < MAX_INACTIVE_DAYS)
|
||
|
+ *inactive = l;
|
||
|
+ else {
|
||
|
+ pam_syslog(pamh, LOG_ERR, "bad option value: %s", *argv);
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ D(("ctrl = %o", ctrl));
|
||
|
+ return ctrl;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+_pam_session_parse(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||
|
{
|
||
|
int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE|LASTLOG_WTMP|LASTLOG_UPDATE);
|
||
|
|
||
|
@@ -145,6 +188,44 @@ get_tty(pam_handle_t *pamh)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
+last_login_open(pam_handle_t *pamh, int announce, uid_t uid)
|
||
|
+{
|
||
|
+ int last_fd;
|
||
|
+
|
||
|
+ /* obtain the last login date and all the relevant info */
|
||
|
+ last_fd = open(_PATH_LASTLOG, announce&LASTLOG_UPDATE ? O_RDWR : O_RDONLY);
|
||
|
+ if (last_fd < 0) {
|
||
|
+ if (errno == ENOENT && (announce & LASTLOG_UPDATE)) {
|
||
|
+ last_fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT,
|
||
|
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||
|
+ if (last_fd < 0) {
|
||
|
+ pam_syslog(pamh, LOG_ERR,
|
||
|
+ "unable to create %s: %m", _PATH_LASTLOG);
|
||
|
+ D(("unable to create %s file", _PATH_LASTLOG));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ pam_syslog(pamh, LOG_WARNING,
|
||
|
+ "file %s created", _PATH_LASTLOG);
|
||
|
+ D(("file %s created", _PATH_LASTLOG));
|
||
|
+ } else {
|
||
|
+ pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_LASTLOG);
|
||
|
+ D(("unable to open %s file", _PATH_LASTLOG));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (lseek(last_fd, sizeof(struct lastlog) * (off_t) uid, SEEK_SET) < 0) {
|
||
|
+ pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG);
|
||
|
+ D(("unable to lseek %s file", _PATH_LASTLOG));
|
||
|
+ close(last_fd);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return last_fd;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int
|
||
|
last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t *lltime)
|
||
|
{
|
||
|
struct flock last_lock;
|
||
|
@@ -338,31 +419,9 @@ last_login_date(pam_handle_t *pamh, int
|
||
|
int last_fd;
|
||
|
|
||
|
/* obtain the last login date and all the relevant info */
|
||
|
- last_fd = open(_PATH_LASTLOG, announce&LASTLOG_UPDATE ? O_RDWR : O_RDONLY);
|
||
|
+ last_fd = last_login_open(pamh, announce, uid);
|
||
|
if (last_fd < 0) {
|
||
|
- if (errno == ENOENT) {
|
||
|
- last_fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT,
|
||
|
- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||
|
- if (last_fd < 0) {
|
||
|
- pam_syslog(pamh, LOG_ERR,
|
||
|
- "unable to create %s: %m", _PATH_LASTLOG);
|
||
|
- D(("unable to create %s file", _PATH_LASTLOG));
|
||
|
- return PAM_SERVICE_ERR;
|
||
|
- }
|
||
|
- pam_syslog(pamh, LOG_WARNING,
|
||
|
- "file %s created", _PATH_LASTLOG);
|
||
|
- D(("file %s created", _PATH_LASTLOG));
|
||
|
- } else {
|
||
|
- pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_LASTLOG);
|
||
|
- D(("unable to open %s file", _PATH_LASTLOG));
|
||
|
- return PAM_SERVICE_ERR;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- if (lseek(last_fd, sizeof(struct lastlog) * (off_t) uid, SEEK_SET) < 0) {
|
||
|
- pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG);
|
||
|
- D(("unable to lseek %s file", _PATH_LASTLOG));
|
||
|
- return PAM_SERVICE_ERR;
|
||
|
+ return PAM_SERVICE_ERR;
|
||
|
}
|
||
|
|
||
|
retval = last_login_read(pamh, announce, last_fd, uid, lltime);
|
||
|
@@ -502,7 +561,91 @@ cleanup:
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
-/* --- authentication management functions (only) --- */
|
||
|
+/* --- authentication (locking out inactive users) functions --- */
|
||
|
+PAM_EXTERN int
|
||
|
+pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||
|
+ int argc, const char **argv)
|
||
|
+{
|
||
|
+ int retval, ctrl;
|
||
|
+ const char *user = NULL;
|
||
|
+ const struct passwd *pwd;
|
||
|
+ uid_t uid;
|
||
|
+ time_t lltime = 0;
|
||
|
+ time_t inactive_days = 0;
|
||
|
+ int last_fd;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Lock out the user if he did not login recently enough.
|
||
|
+ */
|
||
|
+
|
||
|
+ ctrl = _pam_auth_parse(pamh, flags, argc, argv, &inactive_days);
|
||
|
+
|
||
|
+ /* which user? */
|
||
|
+
|
||
|
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL
|
||
|
+ || *user == '\0') {
|
||
|
+ pam_syslog(pamh, LOG_ERR, "cannot determine the user's name");
|
||
|
+ return PAM_USER_UNKNOWN;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* what uid? */
|
||
|
+
|
||
|
+ pwd = pam_modutil_getpwnam (pamh, user);
|
||
|
+ if (pwd == NULL) {
|
||
|
+ pam_syslog(pamh, LOG_ERR, "user unknown");
|
||
|
+ return PAM_USER_UNKNOWN;
|
||
|
+ }
|
||
|
+ uid = pwd->pw_uid;
|
||
|
+ pwd = NULL; /* tidy up */
|
||
|
+
|
||
|
+ if (uid == 0)
|
||
|
+ return PAM_SUCCESS;
|
||
|
+
|
||
|
+ /* obtain the last login date and all the relevant info */
|
||
|
+ last_fd = last_login_open(pamh, ctrl, uid);
|
||
|
+ if (last_fd < 0) {
|
||
|
+ return PAM_IGNORE;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = last_login_read(pamh, ctrl|LASTLOG_QUIET, last_fd, uid, &lltime);
|
||
|
+ close(last_fd);
|
||
|
+
|
||
|
+ if (retval != PAM_SUCCESS) {
|
||
|
+ D(("error while reading lastlog file"));
|
||
|
+ return PAM_IGNORE;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (lltime == 0) { /* user never logged in before */
|
||
|
+ if (ctrl & LASTLOG_DEBUG)
|
||
|
+ pam_syslog(pamh, LOG_DEBUG, "user never logged in - pass");
|
||
|
+ return PAM_SUCCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ lltime = (time(NULL) - lltime) / (24*60*60);
|
||
|
+
|
||
|
+ if (lltime > inactive_days) {
|
||
|
+ pam_syslog(pamh, LOG_INFO, "user %s inactive for %d days - denied", user, lltime);
|
||
|
+ return PAM_AUTH_ERR;
|
||
|
+ }
|
||
|
+
|
||
|
+ return PAM_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+PAM_EXTERN int
|
||
|
+pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
|
||
|
+ int argc UNUSED, const char **argv UNUSED)
|
||
|
+{
|
||
|
+ return PAM_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+PAM_EXTERN int
|
||
|
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
|
||
|
+ int argc, const char **argv)
|
||
|
+{
|
||
|
+ return pam_sm_authenticate(pamh, flags, argc, argv);
|
||
|
+}
|
||
|
+
|
||
|
+/* --- session management functions --- */
|
||
|
|
||
|
PAM_EXTERN int
|
||
|
pam_sm_open_session(pam_handle_t *pamh, int flags,
|
||
|
@@ -519,7 +662,7 @@ pam_sm_open_session(pam_handle_t *pamh,
|
||
|
* last login info and then updates the lastlog for that user.
|
||
|
*/
|
||
|
|
||
|
- ctrl = _pam_parse(pamh, flags, argc, argv);
|
||
|
+ ctrl = _pam_session_parse(pamh, flags, argc, argv);
|
||
|
|
||
|
/* which user? */
|
||
|
|
||
|
@@ -560,7 +703,7 @@ pam_sm_close_session (pam_handle_t *pamh
|
||
|
{
|
||
|
const char *terminal_line;
|
||
|
|
||
|
- if (!(_pam_parse(pamh, flags, argc, argv) & LASTLOG_WTMP))
|
||
|
+ if (!(_pam_session_parse(pamh, flags, argc, argv) & LASTLOG_WTMP))
|
||
|
return PAM_SUCCESS;
|
||
|
|
||
|
terminal_line = get_tty(pamh);
|
||
|
@@ -577,9 +720,9 @@ pam_sm_close_session (pam_handle_t *pamh
|
||
|
|
||
|
struct pam_module _pam_lastlog_modstruct = {
|
||
|
"pam_lastlog",
|
||
|
- NULL,
|
||
|
- NULL,
|
||
|
- NULL,
|
||
|
+ pam_sm_authenticate,
|
||
|
+ pam_sm_setcred,
|
||
|
+ pam_sm_acct_mgmt,
|
||
|
pam_sm_open_session,
|
||
|
pam_sm_close_session,
|
||
|
NULL,
|