f2fdff
From 0d29e379601819c7f7ed8de18b54de803a9f4049 Mon Sep 17 00:00:00 2001
f2fdff
From: Tomas Mraz <tmraz@fedoraproject.org>
f2fdff
Date: Fri, 5 Sep 2014 09:09:37 +0200
f2fdff
Subject: [PATCH] Add grantor field to audit records of libpam.
f2fdff
f2fdff
The grantor field gives audit trail of PAM modules which granted access
f2fdff
for successful return from libpam calls. In case of failed return
f2fdff
the grantor field is set to '?'.
f2fdff
libpam/pam_account.c (pam_acct_mgmt): Remove _pam_auditlog() call.
f2fdff
libpam/pam_auth.c (pam_authenticate, pam_setcred): Likewise.
f2fdff
libpam/pam_password.c (pam_chauthtok): Likewise.
f2fdff
libpam/pam_session.c (pam_open_session, pam_close_session): Likewise.
f2fdff
libpam/pam_audit.c (_pam_audit_writelog): Add grantors parameter,
f2fdff
add grantor= field to the message if grantors is set.
f2fdff
(_pam_list_grantors): New function creating the string with grantors list.
f2fdff
(_pam_auditlog): Add struct handler pointer parameter, call _pam_list_grantors()
f2fdff
to list the grantors from the handler list.
f2fdff
(_pam_audit_end): Add NULL handler parameter to _pam_auditlog() call.
f2fdff
(pam_modutil_audit_write): Add NULL grantors parameter to _pam_audit_writelog().
f2fdff
libpam/pam_dispatch.c (_pam_dispatch_aux): Set h->grantor where appropriate.
f2fdff
(_pam_clear_grantors): New function to clear grantor field of handler.
f2fdff
(_pam_dispatch): Call _pam_clear_grantors() before executing the stack.
f2fdff
Call _pam_auditlog() when appropriate.
f2fdff
libpam/pam_handlers.c (extract_modulename): Do not allow empty module name
f2fdff
or just "?" to avoid confusing audit trail.
f2fdff
(_pam_add_handler): Test for NULL return from extract_modulename().
f2fdff
Clear grantor field of handler.
f2fdff
libpam/pam_private.h: Add grantor field to struct handler, add handler pointer
f2fdff
parameter to _pam_auditlog().
f2fdff
---
f2fdff
 libpam/pam_account.c  |  4 ---
f2fdff
 libpam/pam_audit.c    | 84 +++++++++++++++++++++++++++++++++++++++++++--------
f2fdff
 libpam/pam_auth.c     |  8 -----
f2fdff
 libpam/pam_dispatch.c | 41 ++++++++++++++++++++-----
f2fdff
 libpam/pam_handlers.c | 14 +++++++--
f2fdff
 libpam/pam_password.c |  4 ---
f2fdff
 libpam/pam_private.h  |  3 +-
f2fdff
 libpam/pam_session.c  |  7 -----
f2fdff
 8 files changed, 119 insertions(+), 46 deletions(-)
f2fdff
f2fdff
diff --git a/libpam/pam_account.c b/libpam/pam_account.c
f2fdff
index 572acc4..3a4fb1f 100644
f2fdff
--- a/libpam/pam_account.c
f2fdff
+++ b/libpam/pam_account.c
f2fdff
@@ -19,9 +19,5 @@ int pam_acct_mgmt(pam_handle_t *pamh, int flags)
f2fdff
 
f2fdff
     retval = _pam_dispatch(pamh, flags, PAM_ACCOUNT);
f2fdff
 
f2fdff
-#ifdef HAVE_LIBAUDIT
f2fdff
-    retval = _pam_auditlog(pamh, PAM_ACCOUNT, retval, flags);
f2fdff
-#endif
f2fdff
-
f2fdff
     return retval;
f2fdff
 }
f2fdff
diff --git a/libpam/pam_audit.c b/libpam/pam_audit.c
f2fdff
index 531746a..24fb799 100644
f2fdff
--- a/libpam/pam_audit.c
f2fdff
+++ b/libpam/pam_audit.c
f2fdff
@@ -6,12 +6,12 @@
f2fdff
    Authors:
f2fdff
    Steve Grubb <sgrubb@redhat.com> */
f2fdff
 
f2fdff
-#include <stdio.h>
f2fdff
-#include <syslog.h>
f2fdff
 #include "pam_private.h"
f2fdff
 #include "pam_modutil_private.h"
f2fdff
 
f2fdff
 #ifdef HAVE_LIBAUDIT
f2fdff
+#include <stdio.h>
f2fdff
+#include <syslog.h>
f2fdff
 #include <libaudit.h>
f2fdff
 #include <pwd.h>
f2fdff
 #include <netdb.h>
f2fdff
@@ -25,17 +25,24 @@
f2fdff
 
f2fdff
 static int
f2fdff
 _pam_audit_writelog(pam_handle_t *pamh, int audit_fd, int type,
f2fdff
-	const char *message, int retval)
f2fdff
+	const char *message, const char *grantors, int retval)
f2fdff
 {
f2fdff
   static int old_errno = -1;
f2fdff
-  int rc;
f2fdff
-  char buf[32];
f2fdff
+  int rc = -ENOMEM;
f2fdff
+  char *buf;
f2fdff
+  const char *grantors_field = " grantors=";
f2fdff
 
f2fdff
-  snprintf(buf, sizeof(buf), "PAM:%s", message);
f2fdff
+  if (grantors == NULL) {
f2fdff
+      grantors = "";
f2fdff
+      grantors_field = "";
f2fdff
+  }
f2fdff
 
f2fdff
-  rc = audit_log_acct_message (audit_fd, type, NULL, buf,
f2fdff
-       (retval != PAM_USER_UNKNOWN && pamh->user) ? pamh->user : "?",
f2fdff
-	-1, pamh->rhost, NULL, pamh->tty, retval == PAM_SUCCESS );
f2fdff
+  if (asprintf(&buf, "PAM:%s%s%s", message, grantors_field, grantors) >= 0) {
f2fdff
+      rc = audit_log_acct_message(audit_fd, type, NULL, buf,
f2fdff
+	(retval != PAM_USER_UNKNOWN && pamh->user) ? pamh->user : "?",
f2fdff
+	-1, pamh->rhost, NULL, pamh->tty, retval == PAM_SUCCESS);
f2fdff
+      free(buf);
f2fdff
+  }
f2fdff
 
f2fdff
   /* libaudit sets errno to his own negative error code. This can be
f2fdff
      an official errno number, but must not. It can also be a audit
f2fdff
@@ -78,12 +85,54 @@ _pam_audit_open(pam_handle_t *pamh)
f2fdff
   return audit_fd;
f2fdff
 }
f2fdff
 
f2fdff
+static int
f2fdff
+_pam_list_grantors(struct handler *hlist, int retval, char **list)
f2fdff
+{
f2fdff
+  *list = NULL;
f2fdff
+
f2fdff
+  if (retval == PAM_SUCCESS) {
f2fdff
+    struct handler *h;
f2fdff
+    char *p = NULL;
f2fdff
+    size_t len = 0;
f2fdff
+
f2fdff
+    for (h = hlist; h != NULL; h = h->next) {
f2fdff
+      if (h->grantor) {
f2fdff
+        len += strlen(h->mod_name) + 1;
f2fdff
+      }
f2fdff
+    }
f2fdff
+
f2fdff
+    if (len == 0) {
f2fdff
+      return 0;
f2fdff
+    }
f2fdff
+
f2fdff
+    *list = malloc(len);
f2fdff
+    if (*list == NULL) {
f2fdff
+      return -1;
f2fdff
+    }
f2fdff
+
f2fdff
+    for (h = hlist; h != NULL; h = h->next) {
f2fdff
+      if (h->grantor) {
f2fdff
+        if (p == NULL) {
f2fdff
+          p = *list;
f2fdff
+        } else {
f2fdff
+          p = stpcpy(p, ",");
f2fdff
+        }
f2fdff
+
f2fdff
+        p = stpcpy(p, h->mod_name);
f2fdff
+      }
f2fdff
+    }
f2fdff
+  }
f2fdff
+
f2fdff
+  return 0;
f2fdff
+}
f2fdff
+
f2fdff
 int
f2fdff
-_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
f2fdff
+_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags, struct handler *h)
f2fdff
 {
f2fdff
   const char *message;
f2fdff
   int type;
f2fdff
   int audit_fd;
f2fdff
+  char *grantors;
f2fdff
 
f2fdff
   if ((audit_fd=_pam_audit_open(pamh)) == -1) {
f2fdff
     return PAM_SYSTEM_ERR;
f2fdff
@@ -134,8 +183,17 @@ _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
f2fdff
     retval = PAM_SYSTEM_ERR;
f2fdff
   }
f2fdff
 
f2fdff
-  if (_pam_audit_writelog(pamh, audit_fd, type, message, retval) < 0)
f2fdff
+  if (_pam_list_grantors(h, retval, &grantors) < 0) {
f2fdff
+    /* allocation failure */
f2fdff
+    pam_syslog(pamh, LOG_CRIT, "_pam_list_grantors() failed: %m");
f2fdff
     retval = PAM_SYSTEM_ERR;
f2fdff
+  }
f2fdff
+
f2fdff
+  if (_pam_audit_writelog(pamh, audit_fd, type, message,
f2fdff
+      grantors ? grantors : "?", retval) < 0)
f2fdff
+    retval = PAM_SYSTEM_ERR;
f2fdff
+
f2fdff
+  free(grantors);
f2fdff
 
f2fdff
   audit_close(audit_fd);
f2fdff
   return retval;
f2fdff
@@ -149,7 +207,7 @@ _pam_audit_end(pam_handle_t *pamh, int status UNUSED)
f2fdff
      * stacks having been run. Assume that this is sshd faking
f2fdff
      * things for an unknown user.
f2fdff
      */
f2fdff
-    _pam_auditlog(pamh, _PAM_ACTION_DONE, PAM_USER_UNKNOWN, 0);
f2fdff
+    _pam_auditlog(pamh, _PAM_ACTION_DONE, PAM_USER_UNKNOWN, 0, NULL);
f2fdff
   }
f2fdff
 
f2fdff
   return 0;
f2fdff
@@ -168,7 +226,7 @@ pam_modutil_audit_write(pam_handle_t *pamh, int type,
f2fdff
     return retval;
f2fdff
   }
f2fdff
 
f2fdff
-  rc = _pam_audit_writelog(pamh, audit_fd, type, message, retval);
f2fdff
+  rc = _pam_audit_writelog(pamh, audit_fd, type, message, NULL, retval);
f2fdff
 
f2fdff
   audit_close(audit_fd);
f2fdff
 
f2fdff
diff --git a/libpam/pam_auth.c b/libpam/pam_auth.c
f2fdff
index 5984fa5..1e7bc6e 100644
f2fdff
--- a/libpam/pam_auth.c
f2fdff
+++ b/libpam/pam_auth.c
f2fdff
@@ -45,10 +45,6 @@ int pam_authenticate(pam_handle_t *pamh, int flags)
f2fdff
     prelude_send_alert(pamh, retval);
f2fdff
 #endif
f2fdff
 
f2fdff
-#ifdef HAVE_LIBAUDIT
f2fdff
-    retval = _pam_auditlog(pamh, PAM_AUTHENTICATE, retval, flags);
f2fdff
-#endif
f2fdff
-
f2fdff
     return retval;
f2fdff
 }
f2fdff
 
f2fdff
@@ -71,10 +67,6 @@ int pam_setcred(pam_handle_t *pamh, int flags)
f2fdff
 
f2fdff
     retval = _pam_dispatch(pamh, flags, PAM_SETCRED);
f2fdff
 
f2fdff
-#ifdef HAVE_LIBAUDIT
f2fdff
-    retval = _pam_auditlog(pamh, PAM_SETCRED, retval, flags);
f2fdff
-#endif
f2fdff
-
f2fdff
     D(("pam_setcred exit"));
f2fdff
 
f2fdff
     return retval;
f2fdff
diff --git a/libpam/pam_dispatch.c b/libpam/pam_dispatch.c
f2fdff
index eb52c82..cf632e8 100644
f2fdff
--- a/libpam/pam_dispatch.c
f2fdff
+++ b/libpam/pam_dispatch.c
f2fdff
@@ -217,8 +217,14 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
f2fdff
                     status = retval;
f2fdff
                 }
f2fdff
 	    }
f2fdff
-	    if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) {
f2fdff
-		goto decision_made;
f2fdff
+	    if ( impression == _PAM_POSITIVE ) {
f2fdff
+		if ( retval == PAM_SUCCESS ) {
f2fdff
+		    h->grantor = 1;
f2fdff
+		}
f2fdff
+
f2fdff
+		if ( action == _PAM_ACTION_DONE ) {
f2fdff
+		    goto decision_made;
f2fdff
+		}
f2fdff
 	    }
f2fdff
 	    break;
f2fdff
 
f2fdff
@@ -262,6 +268,9 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
f2fdff
 			|| (impression == _PAM_POSITIVE
f2fdff
 			    && status == PAM_SUCCESS) ) {
f2fdff
 			if ( retval != PAM_IGNORE || cached_retval == retval ) {
f2fdff
+			    if ( impression == _PAM_UNDEF && retval == PAM_SUCCESS ) {
f2fdff
+				h->grantor = 1;
f2fdff
+			    }
f2fdff
 			    impression = _PAM_POSITIVE;
f2fdff
 			    status = retval;
f2fdff
 			}
f2fdff
@@ -308,6 +317,13 @@ decision_made:     /* by getting  here we have made a decision */
f2fdff
     return status;
f2fdff
 }
f2fdff
 
f2fdff
+static void _pam_clear_grantors(struct handler *h)
f2fdff
+{
f2fdff
+    for (; h != NULL; h = h->next) {
f2fdff
+	h->grantor = 0;
f2fdff
+    }
f2fdff
+}
f2fdff
+
f2fdff
 /*
f2fdff
  * This function translates the module dispatch request into a pointer
f2fdff
  * to the stack of modules that will actually be run.  the
f2fdff
@@ -318,21 +334,21 @@ decision_made:     /* by getting  here we have made a decision */
f2fdff
 int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
f2fdff
 {
f2fdff
     struct handler *h = NULL;
f2fdff
-    int retval, use_cached_chain;
f2fdff
+    int retval = PAM_SYSTEM_ERR, use_cached_chain;
f2fdff
     _pam_boolean resumed;
f2fdff
 
f2fdff
     IF_NO_PAMH("_pam_dispatch", pamh, PAM_SYSTEM_ERR);
f2fdff
 
f2fdff
     if (__PAM_FROM_MODULE(pamh)) {
f2fdff
 	D(("called from a module!?"));
f2fdff
-	return PAM_SYSTEM_ERR;
f2fdff
+	goto end;
f2fdff
     }
f2fdff
 
f2fdff
     /* Load all modules, resolve all symbols */
f2fdff
 
f2fdff
     if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) {
f2fdff
 	pam_syslog(pamh, LOG_ERR, "unable to dispatch function");
f2fdff
-	return retval;
f2fdff
+	goto end;
f2fdff
     }
f2fdff
 
f2fdff
     use_cached_chain = _PAM_PLEASE_FREEZE;
f2fdff
@@ -360,7 +376,8 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
f2fdff
 	break;
f2fdff
     default:
f2fdff
 	pam_syslog(pamh, LOG_ERR, "undefined fn choice; %d", choice);
f2fdff
-	return PAM_ABORT;
f2fdff
+	retval = PAM_ABORT;
f2fdff
+	goto end;
f2fdff
     }
f2fdff
 
f2fdff
     if (h == NULL) {     /* there was no handlers.conf... entry; will use
f2fdff
@@ -393,11 +410,13 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
f2fdff
 	    pam_syslog(pamh, LOG_ERR,
f2fdff
 			    "application failed to re-exec stack [%d:%d]",
f2fdff
 			    pamh->former.choice, choice);
f2fdff
-	    return PAM_ABORT;
f2fdff
+	    retval = PAM_ABORT;
f2fdff
+	    goto end;
f2fdff
 	}
f2fdff
 	resumed = PAM_TRUE;
f2fdff
     } else {
f2fdff
 	resumed = PAM_FALSE;
f2fdff
+	_pam_clear_grantors(h);
f2fdff
     }
f2fdff
 
f2fdff
     __PAM_TO_MODULE(pamh);
f2fdff
@@ -417,5 +436,13 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
f2fdff
 	pamh->former.choice = PAM_NOT_STACKED;
f2fdff
     }
f2fdff
 
f2fdff
+end:
f2fdff
+
f2fdff
+#ifdef HAVE_LIBAUDIT
f2fdff
+    if (choice != PAM_CHAUTHTOK || flags & PAM_UPDATE_AUTHTOK || retval != PAM_SUCCESS) {
f2fdff
+	retval = _pam_auditlog(pamh, choice, retval, flags, h);
f2fdff
+    }
f2fdff
+#endif
f2fdff
+
f2fdff
     return retval;
f2fdff
 }
f2fdff
diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
f2fdff
index 02714f7..df3a1d9 100644
f2fdff
--- a/libpam/pam_handlers.c
f2fdff
+++ b/libpam/pam_handlers.c
f2fdff
@@ -611,6 +611,12 @@ extract_modulename(const char *mod_path)
f2fdff
   if (dot)
f2fdff
     *dot = '\0';
f2fdff
 
f2fdff
+  if (*retval == '\0' || strcmp(retval, "?") == 0) {
f2fdff
+    /* do not allow empty module name or "?" to avoid confusing audit trail */
f2fdff
+    _pam_drop(retval);
f2fdff
+    return NULL;
f2fdff
+  }
f2fdff
+
f2fdff
   return retval;
f2fdff
 }
f2fdff
 
f2fdff
@@ -888,7 +894,9 @@ int _pam_add_handler(pam_handle_t *pamh
f2fdff
     (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
f2fdff
     (*handler_p)->argc = argc;
f2fdff
     (*handler_p)->argv = argv;                       /* not a copy */
f2fdff
-    (*handler_p)->mod_name = extract_modulename(mod_path);
f2fdff
+    if (((*handler_p)->mod_name = extract_modulename(mod_path)) == NULL)
f2fdff
+	return PAM_ABORT;
f2fdff
+    (*handler_p)->grantor = 0;
f2fdff
     (*handler_p)->next = NULL;
f2fdff
 
f2fdff
     /* some of the modules have a second calling function */
f2fdff
@@ -920,7 +928,9 @@ int _pam_add_handler(pam_handle_t *pamh
f2fdff
 	} else {
f2fdff
 	    (*handler_p2)->argv = NULL;              /* no arguments */
f2fdff
 	}
f2fdff
-	(*handler_p2)->mod_name = extract_modulename(mod_path);
f2fdff
+	if (((*handler_p2)->mod_name = extract_modulename(mod_path)) == NULL)
f2fdff
+	    return PAM_ABORT;
f2fdff
+	(*handler_p2)->grantor = 0;
f2fdff
 	(*handler_p2)->next = NULL;
f2fdff
     }
f2fdff
 
f2fdff
diff --git a/libpam/pam_password.c b/libpam/pam_password.c
f2fdff
index 75db5e5..592e01f 100644
f2fdff
--- a/libpam/pam_password.c
f2fdff
+++ b/libpam/pam_password.c
f2fdff
@@ -57,9 +57,5 @@ int pam_chauthtok(pam_handle_t *pamh, int flags)
f2fdff
 	D(("will resume when ready", retval));
f2fdff
     }
f2fdff
 
f2fdff
-#ifdef HAVE_LIBAUDIT
f2fdff
-    retval = _pam_auditlog(pamh, PAM_CHAUTHTOK, retval, flags);
f2fdff
-#endif
f2fdff
-
f2fdff
     return retval;
f2fdff
 }
f2fdff
diff --git a/libpam/pam_private.h b/libpam/pam_private.h
f2fdff
index 134dc72..d93283c 100644
f2fdff
--- a/libpam/pam_private.h
f2fdff
+++ b/libpam/pam_private.h
f2fdff
@@ -55,6 +55,7 @@ struct handler {
f2fdff
     struct handler *next;
f2fdff
     char *mod_name;
f2fdff
     int stack_level;
f2fdff
+    int grantor;
f2fdff
 };
f2fdff
 
f2fdff
 #define PAM_HT_MODULE       0
f2fdff
@@ -316,7 +317,7 @@ if ((pamh) == NULL) {                             \
f2fdff
         do { (pamh)->caller_is = _PAM_CALLED_FROM_APP; } while (0)
f2fdff
 
f2fdff
 #ifdef HAVE_LIBAUDIT
f2fdff
-extern int _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags);
f2fdff
+extern int _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags, struct handler *h);
f2fdff
 extern int _pam_audit_end(pam_handle_t *pamh, int pam_status);
f2fdff
 #endif
f2fdff
 
f2fdff
diff --git a/libpam/pam_session.c b/libpam/pam_session.c
f2fdff
index 512153f..cb393c1 100644
f2fdff
--- a/libpam/pam_session.c
f2fdff
+++ b/libpam/pam_session.c
f2fdff
@@ -22,9 +22,6 @@ int pam_open_session(pam_handle_t *pamh, int flags)
f2fdff
     }
f2fdff
     retval = _pam_dispatch(pamh, flags, PAM_OPEN_SESSION);
f2fdff
 
f2fdff
-#ifdef HAVE_LIBAUDIT
f2fdff
-    retval = _pam_auditlog(pamh, PAM_OPEN_SESSION, retval, flags);
f2fdff
-#endif
f2fdff
     return retval;
f2fdff
 }
f2fdff
 
f2fdff
@@ -43,10 +40,6 @@ int pam_close_session(pam_handle_t *pamh, int flags)
f2fdff
 
f2fdff
     retval = _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);
f2fdff
 
f2fdff
-#ifdef HAVE_LIBAUDIT
f2fdff
-    retval = _pam_auditlog(pamh, PAM_CLOSE_SESSION, retval, flags);
f2fdff
-#endif
f2fdff
-
f2fdff
     return retval;
f2fdff
 
f2fdff
 }
f2fdff
-- 
f2fdff
1.8.3.1
f2fdff