]> granicus.if.org Git - linux-pam/blobdiff - modules/pam_tally2/pam_tally2.c
pam_tally2: Optionally log the tally count when checking.
[linux-pam] / modules / pam_tally2 / pam_tally2.c
index 3490aa15e21750d3ab065cd81ca26f4ccaf1ebb1..e513f64c9c7f73d08f54b4a206ebc7c67b0fc7bf 100644 (file)
@@ -124,6 +124,7 @@ struct tally_options {
 #define OPT_AUDIT                       0100
 #define OPT_NOLOGNOTICE                 0400
 #define OPT_SERIALIZE                  01000
+#define OPT_DEBUG                      02000
 
 #define MAX_LOCK_WAITING_TIME 10
 
@@ -159,7 +160,7 @@ static void
 log_phase_no_auth(pam_handle_t *pamh, int phase, const char *argv)
 {
     if ( phase != PHASE_AUTH ) {
-       pam_syslog(pamh, LOG_ERR,
+       pam_syslog(pamh, LOG_ERR,
                   "option %s allowed in auth phase only", argv);
     }
 }
@@ -196,6 +197,9 @@ tally_parse_args(pam_handle_t *pamh, struct tally_options *opts,
       else if ( ! strcmp( *argv, "serialize" ) ) {
         opts->ctrl |= OPT_SERIALIZE;
       }
+      else if ( ! strcmp( *argv, "debug" ) ) {
+        opts->ctrl |= OPT_DEBUG;
+      }
       else if ( ! strcmp( *argv, "even_deny_root_account" ) ||
                 ! strcmp( *argv, "even_deny_root" ) ) {
        log_phase_no_auth(pamh, phase, *argv);
@@ -223,7 +227,7 @@ tally_parse_args(pam_handle_t *pamh, struct tally_options *opts,
         }
       }
       else if ( ! strncmp( *argv, "root_unlock_time=", 17 ) ) {
-       log_phase_no_auth(pamh, phase, *argv);  
+       log_phase_no_auth(pamh, phase, *argv);
         if ( sscanf((*argv)+17,"%ld",&opts->root_unlock_time) != 1 ) {
           pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
           return PAM_AUTH_ERR;
@@ -373,7 +377,7 @@ get_tally(pam_handle_t *pamh, uid_t uid, const char *filename,
 
     lstat_ret = lstat(filename, &fileinfo);
     if (lstat_ret) {
-      *tfile=open(filename, O_APPEND|O_CREAT, 0700);
+      *tfile=open(filename, O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
       /* Create file, or append-open in pathological case. */
       if (*tfile == -1) {
 #ifndef MAIN
@@ -407,8 +411,8 @@ get_tally(pam_handle_t *pamh, uid_t uid, const char *filename,
     if ((*tfile = open(filename, O_RDWR)) == -1) {
 #ifndef MAIN
       if (errno == EACCES) /* called with insufficient access rights */
-         return PAM_IGNORE;
-#endif 
+         return PAM_IGNORE;
+#endif
       pam_syslog(pamh, LOG_ALERT, "Error opening %s for update: %m", filename);
 
       return PAM_AUTH_ERR;
@@ -418,7 +422,7 @@ skip_open:
     if (lseek(*tfile, (off_t)uid*(off_t)sizeof(*tally), SEEK_SET) == (off_t)-1) {
         pam_syslog(pamh, LOG_ALERT, "lseek failed for %s: %m", filename);
         if (!preopened) {
-           close(*tfile);
+           close(*tfile);
             *tfile = -1;
         }
         return PAM_AUTH_ERR;
@@ -438,7 +442,7 @@ skip_open:
 
        rv = lockf(*tfile, F_LOCK, sizeof(*tally));
        /* lock failure is not fatal, we attempt to read the tally anyway */
-       
+
        /* reinstate the eventual old alarm handler */
        if (rv == -1 && errno == EINTR) {
            if (oldalarm > MAX_LOCK_WAITING_TIME) {
@@ -451,15 +455,12 @@ skip_open:
        alarm(oldalarm);
     }
 
-    if (fileinfo.st_size < (off_t)(uid+1)*(off_t)sizeof(*tally)) {
-       memset(tally, 0, sizeof(*tally));
-    } else if (pam_modutil_read(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) {
+    if (pam_modutil_read(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) {
        memset(tally, 0, sizeof(*tally));
-       /* Shouldn't happen */
     }
 
     tally->fail_line[sizeof(tally->fail_line)-1] = '\0';
-    
+
     return PAM_SUCCESS;
 }
 
@@ -506,11 +507,13 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
             struct tallylog *tally)
 {
     int rv = PAM_SUCCESS;
+    int loglevel = LOG_DEBUG;
 #ifdef HAVE_LIBAUDIT
     char buf[64];
     int audit_fd = -1;
+    const void *rhost = NULL, *tty = NULL;
 #endif
-    
+
     if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
       return PAM_SUCCESS;
     }
@@ -521,6 +524,8 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
     if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT ||
                             errno == EAFNOSUPPORT))
          return PAM_SYSTEM_ERR;
+    (void)pam_get_item(pamh, PAM_TTY, &tty);
+    (void)pam_get_item(pamh, PAM_RHOST, &rhost);
 #endif
     if (opts->deny != 0 &&                        /* deny==0 means no deny        */
         tally->fail_cnt > opts->deny &&           /* tally>deny means exceeded    */
@@ -530,36 +535,36 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
             /* First say that max number was hit. */
             snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
             audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf,
-                                   NULL, NULL, NULL, 1);
+                                   rhost, NULL, tty, 1);
         }
 #endif
-        if (uid) {      
+        if (uid) {
             /* Unlock time check */
             if (opts->unlock_time && oldtime) {
-                if (opts->unlock_time + oldtime <= time(NULL))         {
+                if (opts->unlock_time + oldtime <= time(NULL)) {
                     /* ignore deny check after unlock_time elapsed */
 #ifdef HAVE_LIBAUDIT
                     snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
                     audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
-                                   NULL, NULL, NULL, 1);
+                                   rhost, NULL, tty, 1);
 #endif
-                   rv = PAM_SUCCESS;
-                   goto cleanup;
-               }
+                   rv = PAM_SUCCESS;
+                   goto cleanup;
+               }
             }
         } else {
             /* Root unlock time check */
             if (opts->root_unlock_time && oldtime) {
                 if (opts->root_unlock_time + oldtime <= time(NULL)) {
-                   /* ignore deny check after unlock_time elapsed */
+                   /* ignore deny check after unlock_time elapsed */
 #ifdef HAVE_LIBAUDIT
                     snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
                     audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
-                                   NULL, NULL, NULL, 1);
+                                   rhost, NULL, tty, 1);
 #endif
-                   rv = PAM_SUCCESS;
-                   goto cleanup;
-               }
+                   rv = PAM_SUCCESS;
+                   goto cleanup;
+               }
             }
         }
 
@@ -567,7 +572,7 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
         if (tally->fail_cnt == opts->deny+1) {
             /* First say that max number was hit. */
             audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf,
-                                   NULL, NULL, NULL, 1);
+                                   rhost, NULL, tty, 1);
         }
 #endif
 
@@ -575,11 +580,7 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
             pam_info(pamh, _("Account locked due to %u failed logins"),
                    (unsigned int)tally->fail_cnt);
         }
-       if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
-            pam_syslog(pamh, LOG_NOTICE,
-                   "user %s (%lu) tally %hu, deny %hu",
-                  user, (unsigned long)uid, tally->fail_cnt, opts->deny);
-       }
+       loglevel = LOG_NOTICE;
         rv = PAM_AUTH_ERR;                 /* Only unconditional failure   */
         goto cleanup;
     }
@@ -597,7 +598,7 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
                          oldtime+opts->lock_time-time(NULL));
             }
            if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
-               pam_syslog(pamh, LOG_NOTICE,
+               pam_syslog(pamh, LOG_NOTICE,
                       "user %s (%lu) has time limit [%lds left]"
                       " since last failure.",
                        user, (unsigned long)uid,
@@ -605,10 +606,15 @@ tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
            }
            rv = PAM_AUTH_ERR;
            goto cleanup;
-       }
+       }
     }
 
 cleanup:
+    if (!(opts->ctrl & OPT_NOLOGNOTICE) && (loglevel != LOG_DEBUG || opts->ctrl & OPT_DEBUG)) {
+        pam_syslog(pamh, loglevel,
+            "user %s (%lu) tally %hu, deny %hu",
+            user, (unsigned long)uid, tally->fail_cnt, opts->deny);
+    }
 #ifdef HAVE_LIBAUDIT
     if (audit_fd != -1) {
         close(audit_fd);
@@ -621,7 +627,7 @@ cleanup:
 
 static int
 tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
-            uid_t uid, const char *user, struct tally_options *opts, int *tfile) 
+            uid_t uid, const char *user, struct tally_options *opts, int *tfile)
 {
     struct tallylog tally;
     tally_t oldcnt;
@@ -629,7 +635,7 @@ tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
     int i, rv;
 
     tally.fail_cnt = 0;  /* !TALLY_HI --> Log opened for update */
-    
+
     i = get_tally(pamh, uid, opts->filename, tfile, &tally, opts->ctrl);
     if (i != PAM_SUCCESS) {
         if (*tfile != -1) {
@@ -643,23 +649,23 @@ tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
     if (oldtime) {
         *oldtime = (time_t)tally.fail_time;
     }
-    
+
     tally.fail_time = time(NULL);
 
     (void) pam_get_item(pamh, PAM_RHOST, &remote_host);
     if (!remote_host) {
-       (void) pam_get_item(pamh, PAM_TTY, &remote_host);
+       (void) pam_get_item(pamh, PAM_TTY, &remote_host);
        if (!remote_host) {
-           remote_host = "unknown";
-       }
+           remote_host = "unknown";
+       }
     }
-    
+
     strncpy(tally.fail_line, remote_host,
                    sizeof(tally.fail_line)-1);
     tally.fail_line[sizeof(tally.fail_line)-1] = 0;
 
     oldcnt = tally.fail_cnt;
-    
+
     if (!(opts->ctrl & OPT_MAGIC_ROOT) || getuid()) {
       /* magic_root doesn't change tally */
       tally.fail_cnt += inc;
@@ -693,14 +699,14 @@ tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
 static int
 tally_reset (pam_handle_t *pamh, uid_t uid, struct tally_options *opts, int old_tfile)
 {
-    struct tallylog tally; 
+    struct tallylog tally;
     int tfile = old_tfile;
     int i;
-    
+
     /* resets only if not magic root */
 
     if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
-        return PAM_SUCCESS; 
+        return PAM_SUCCESS;
     }
 
     tally.fail_cnt = 0;  /* !TALLY_HI --> Log opened for update */
@@ -711,9 +717,9 @@ tally_reset (pam_handle_t *pamh, uid_t uid, struct tally_options *opts, int old_
             close(tfile);
         RETURN_ERROR(i);
     }
-    
+
     memset(&tally, 0, sizeof(tally));
-    
+
     i=set_tally(pamh, uid, opts->filename, &tfile, &tally);
     if (i != PAM_SUCCESS) {
         if (tfile != old_tfile) /* the descriptor is not owned by pam data */
@@ -844,7 +850,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
 
 /* static module data */
 
-struct pam_module _pam_tally_modstruct = {
+struct pam_module _pam_tally2_modstruct = {
      MODULE_NAME,
 #ifdef PAM_SM_AUTH
      pam_sm_authenticate,
@@ -878,7 +884,7 @@ static int cline_quiet =  0;
  */
 
 static const char *
-pam_errors( int i ) 
+pam_errors( int i )
 {
   switch (i) {
   case PAM_AUTH_ERR:     return _("Authentication error");
@@ -889,7 +895,7 @@ pam_errors( int i )
 }
 
 static int
-getopts( char **argv ) 
+getopts( char **argv )
 {
   const char *pname = *argv;
   for ( ; *argv ; (void)(*argv && ++argv) ) {
@@ -944,7 +950,7 @@ print_one(const struct tallylog *tally, uid_t uid)
    putchar ('\n');
 }
 
-int 
+int
 main( int argc UNUSED, char **argv )
 {
   struct tallylog tally;
@@ -996,7 +1002,7 @@ main( int argc UNUSED, char **argv )
         int audit_fd = audit_open();
         snprintf(buf, sizeof(buf), "pam_tally2 uid=%u reset=%hu", uid, cline_reset);
         audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
-                buf, NULL, NULL, NULL, 1);
+                buf, NULL, NULL, ttyname(STDIN_FILENO), 1);
         if (audit_fd >=0)
                 close(audit_fd);
 #endif
@@ -1019,14 +1025,14 @@ main( int argc UNUSED, char **argv )
     FILE *tfile=fopen(cline_filename, "r");
     uid_t uid=0;
     if (!tfile  && cline_reset != 0) {
-       perror(*argv);
-       exit(1);
+       perror(*argv);
+       exit(1);
     }
 
     for ( ; tfile && !feof(tfile); uid++ ) {
       if ( !fread(&tally, sizeof(tally), 1, tfile)
           || !tally.fail_cnt ) {
-        continue;
+        continue;
       }
       print_one(&tally, uid);
     }
@@ -1041,7 +1047,7 @@ main( int argc UNUSED, char **argv )
       int audit_fd = audit_open();
       snprintf(buf, sizeof(buf), "pam_tally2 uid=all reset=0");
       audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
-              buf, NULL, NULL, NULL, 1);
+              buf, NULL, NULL, ttyname(STDIN_FILENO), 1);
       if (audit_fd >=0)
               close(audit_fd);
 #endif