diff --git a/libpam/pam_account.c b/libpam/pam_account.c
index 572acc4..3a4fb1f 100644
--- a/libpam/pam_account.c
+++ b/libpam/pam_account.c
@@ -19,9 +19,5 @@ int pam_acct_mgmt(pam_handle_t *pamh, int flags)
 
     retval = _pam_dispatch(pamh, flags, PAM_ACCOUNT);
 
-#ifdef HAVE_LIBAUDIT
-    retval = _pam_auditlog(pamh, PAM_ACCOUNT, retval, flags);
-#endif
-
     return retval;
 }
diff --git a/libpam/pam_audit.c b/libpam/pam_audit.c
index 531746a..33c47ed 100644
--- a/libpam/pam_audit.c
+++ b/libpam/pam_audit.c
@@ -6,12 +6,12 @@
    Authors:
    Steve Grubb <sgrubb@redhat.com> */
 
-#include <stdio.h>
-#include <syslog.h>
 #include "pam_private.h"
 #include "pam_modutil_private.h"
 
 #ifdef HAVE_LIBAUDIT
+#include <stdio.h>
+#include <syslog.h>
 #include <libaudit.h>
 #include <pwd.h>
 #include <netdb.h>
@@ -25,17 +25,18 @@
 
 static int
 _pam_audit_writelog(pam_handle_t *pamh, int audit_fd, int type,
-	const char *message, int retval)
+	const char *message, const char *grantors, int retval)
 {
   static int old_errno = -1;
-  int rc;
-  char buf[32];
-
-  snprintf(buf, sizeof(buf), "PAM:%s", message);
-
-  rc = audit_log_acct_message (audit_fd, type, NULL, buf,
-       (retval != PAM_USER_UNKNOWN && pamh->user) ? pamh->user : "?",
-	-1, pamh->rhost, NULL, pamh->tty, retval == PAM_SUCCESS );
+  int rc = -ENOMEM;
+  char *buf;
+
+  if (asprintf(&buf, "PAM:%s%s%s", message, grantors?" grantors=":"", grantors?grantors:"") >= 0) {
+      rc = audit_log_acct_message(audit_fd, type, NULL, buf,
+	(retval != PAM_USER_UNKNOWN && pamh->user) ? pamh->user : "?",
+	-1, pamh->rhost, NULL, pamh->tty, retval == PAM_SUCCESS);
+      free(buf);
+  }
 
   /* libaudit sets errno to his own negative error code. This can be
      an official errno number, but must not. It can also be a audit
@@ -78,12 +79,54 @@ _pam_audit_open(pam_handle_t *pamh)
   return audit_fd;
 }
 
+static int
+_pam_list_grantors(struct handler *hlist, int retval, char **list)
+{
+  *list = NULL;  
+
+  if (retval == PAM_SUCCESS) {
+    struct handler *h;
+    char *p = NULL;
+    size_t len = 0;
+
+    for (h = hlist; h != NULL; h = h->next) {
+      if (h->grantor) {
+        len += strlen(h->mod_name) + 1;
+      }
+    }
+
+    if (len == 0) {
+      return 0;
+    }
+
+    *list = malloc(len);
+    if (*list == NULL) {
+      return -1;
+    }
+
+    for (h = hlist; h != NULL; h = h->next) {
+      if (h->grantor) {
+        if (p == NULL) {
+          p = *list;
+        } else {
+          p = stpcpy(p, ",");
+        }
+
+        p = stpcpy(p, h->mod_name);
+      }
+    }
+  }
+
+  return 0;
+}
+
 int
-_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
+_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags, struct handler *h)
 {
   const char *message;
   int type;
   int audit_fd;
+  char *grantors;
 
   if ((audit_fd=_pam_audit_open(pamh)) == -1) {
     return PAM_SYSTEM_ERR;
@@ -134,8 +177,16 @@ _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
     retval = PAM_SYSTEM_ERR;
   }
 
-  if (_pam_audit_writelog(pamh, audit_fd, type, message, retval) < 0)
+  if (_pam_list_grantors(h, retval, &grantors) < 0) {
+    /* allocation failure */
+    pam_syslog(pamh, LOG_CRIT, "_pam_list_grantors() failed: %m");
     retval = PAM_SYSTEM_ERR;
+  }
+
+  if (_pam_audit_writelog(pamh, audit_fd, type, message, grantors?grantors:"?", retval) < 0)
+    retval = PAM_SYSTEM_ERR;
+
+  free(grantors);
 
   audit_close(audit_fd);
   return retval;
@@ -149,7 +200,7 @@ _pam_audit_end(pam_handle_t *pamh, int status UNUSED)
      * stacks having been run. Assume that this is sshd faking
      * things for an unknown user.
      */
-    _pam_auditlog(pamh, _PAM_ACTION_DONE, PAM_USER_UNKNOWN, 0);
+    _pam_auditlog(pamh, _PAM_ACTION_DONE, PAM_USER_UNKNOWN, 0, NULL);
   }
 
   return 0;
@@ -168,7 +219,7 @@ pam_modutil_audit_write(pam_handle_t *pamh, int type,
     return retval;
   }
 
-  rc = _pam_audit_writelog(pamh, audit_fd, type, message, retval);
+  rc = _pam_audit_writelog(pamh, audit_fd, type, message, NULL, retval);
 
   audit_close(audit_fd);
 
diff --git a/libpam/pam_auth.c b/libpam/pam_auth.c
index 5984fa5..1e7bc6e 100644
--- a/libpam/pam_auth.c
+++ b/libpam/pam_auth.c
@@ -45,10 +45,6 @@ int pam_authenticate(pam_handle_t *pamh, int flags)
     prelude_send_alert(pamh, retval);
 #endif
 
-#ifdef HAVE_LIBAUDIT
-    retval = _pam_auditlog(pamh, PAM_AUTHENTICATE, retval, flags);
-#endif
-
     return retval;
 }
 
@@ -71,10 +67,6 @@ int pam_setcred(pam_handle_t *pamh, int flags)
 
     retval = _pam_dispatch(pamh, flags, PAM_SETCRED);
 
-#ifdef HAVE_LIBAUDIT
-    retval = _pam_auditlog(pamh, PAM_SETCRED, retval, flags);
-#endif
-
     D(("pam_setcred exit"));
 
     return retval;
diff --git a/libpam/pam_dispatch.c b/libpam/pam_dispatch.c
index eb52c82..72b730e 100644
--- a/libpam/pam_dispatch.c
+++ b/libpam/pam_dispatch.c
@@ -217,8 +217,14 @@ static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
                     status = retval;
                 }
 	    }
-	    if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) {
-		goto decision_made;
+	    if ( impression == _PAM_POSITIVE ) {
+		if ( retval == PAM_SUCCESS ) {
+		    h->grantor = 1;
+		}
+
+		if ( action == _PAM_ACTION_DONE ) {
+		    goto decision_made;
+		}
 	    }
 	    break;
 
@@ -308,6 +314,13 @@ decision_made:     /* by getting  here we have made a decision */
     return status;
 }
 
+static void _pam_clear_grantors(struct handler *h)
+{
+    for (; h != NULL; h = h->next) {
+	h->grantor = 0;
+    }
+}
+
 /*
  * This function translates the module dispatch request into a pointer
  * to the stack of modules that will actually be run.  the
@@ -318,21 +331,21 @@ decision_made:     /* by getting  here we have made a decision */
 int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
 {
     struct handler *h = NULL;
-    int retval, use_cached_chain;
+    int retval = PAM_SYSTEM_ERR, use_cached_chain;
     _pam_boolean resumed;
 
     IF_NO_PAMH("_pam_dispatch", pamh, PAM_SYSTEM_ERR);
 
     if (__PAM_FROM_MODULE(pamh)) {
 	D(("called from a module!?"));
-	return PAM_SYSTEM_ERR;
+	goto end;
     }
 
     /* Load all modules, resolve all symbols */
 
     if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) {
 	pam_syslog(pamh, LOG_ERR, "unable to dispatch function");
-	return retval;
+	goto end;
     }
 
     use_cached_chain = _PAM_PLEASE_FREEZE;
@@ -360,7 +373,8 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
 	break;
     default:
 	pam_syslog(pamh, LOG_ERR, "undefined fn choice; %d", choice);
-	return PAM_ABORT;
+	retval = PAM_ABORT;
+	goto end;
     }
 
     if (h == NULL) {     /* there was no handlers.conf... entry; will use
@@ -393,11 +407,13 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
 	    pam_syslog(pamh, LOG_ERR,
 			    "application failed to re-exec stack [%d:%d]",
 			    pamh->former.choice, choice);
-	    return PAM_ABORT;
+	    retval = PAM_ABORT;
+	    goto end;
 	}
 	resumed = PAM_TRUE;
     } else {
 	resumed = PAM_FALSE;
+	_pam_clear_grantors(h);
     }
 
     __PAM_TO_MODULE(pamh);
@@ -417,5 +433,13 @@ int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
 	pamh->former.choice = PAM_NOT_STACKED;
     }
 
+end:
+
+#ifdef HAVE_LIBAUDIT
+    if (choice != PAM_CHAUTHTOK || flags & PAM_UPDATE_AUTHTOK || retval != PAM_SUCCESS) {
+	retval = _pam_auditlog(pamh, choice, retval, flags, h);
+    }
+#endif
+
     return retval;
 }
diff --git a/libpam/pam_handlers.c b/libpam/pam_handlers.c
index 02714f7..e3f8ff6 100644
--- a/libpam/pam_handlers.c
+++ b/libpam/pam_handlers.c
@@ -889,6 +889,7 @@ int _pam_add_handler(pam_handle_t *pamh
     (*handler_p)->argc = argc;
     (*handler_p)->argv = argv;                       /* not a copy */
     (*handler_p)->mod_name = extract_modulename(mod_path);
+    (*handler_p)->grantor = 0;
     (*handler_p)->next = NULL;
 
     /* some of the modules have a second calling function */
@@ -921,6 +922,7 @@ int _pam_add_handler(pam_handle_t *pamh
 	    (*handler_p2)->argv = NULL;              /* no arguments */
 	}
 	(*handler_p2)->mod_name = extract_modulename(mod_path);
+	(*handler_p2)->grantor = 0;
 	(*handler_p2)->next = NULL;
     }
 
diff --git a/libpam/pam_password.c b/libpam/pam_password.c
index 75db5e5..592e01f 100644
--- a/libpam/pam_password.c
+++ b/libpam/pam_password.c
@@ -57,9 +57,5 @@ int pam_chauthtok(pam_handle_t *pamh, int flags)
 	D(("will resume when ready", retval));
     }
 
-#ifdef HAVE_LIBAUDIT
-    retval = _pam_auditlog(pamh, PAM_CHAUTHTOK, retval, flags);
-#endif
-
     return retval;
 }
diff --git a/libpam/pam_private.h b/libpam/pam_private.h
index 134dc72..d93283c 100644
--- a/libpam/pam_private.h
+++ b/libpam/pam_private.h
@@ -55,6 +55,7 @@ struct handler {
     struct handler *next;
     char *mod_name;
     int stack_level;
+    int grantor;
 };
 
 #define PAM_HT_MODULE       0
@@ -316,7 +317,7 @@ if ((pamh) == NULL) {                             \
         do { (pamh)->caller_is = _PAM_CALLED_FROM_APP; } while (0)
 
 #ifdef HAVE_LIBAUDIT
-extern int _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags);
+extern int _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags, struct handler *h);
 extern int _pam_audit_end(pam_handle_t *pamh, int pam_status);
 #endif
 
diff --git a/libpam/pam_session.c b/libpam/pam_session.c
index 512153f..cb393c1 100644
--- a/libpam/pam_session.c
+++ b/libpam/pam_session.c
@@ -22,9 +22,6 @@ int pam_open_session(pam_handle_t *pamh, int flags)
     }
     retval = _pam_dispatch(pamh, flags, PAM_OPEN_SESSION);
 
-#ifdef HAVE_LIBAUDIT
-    retval = _pam_auditlog(pamh, PAM_OPEN_SESSION, retval, flags);
-#endif
     return retval;
 }
 
@@ -43,10 +40,6 @@ int pam_close_session(pam_handle_t *pamh, int flags)
 
     retval = _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);
 
-#ifdef HAVE_LIBAUDIT
-    retval = _pam_auditlog(pamh, PAM_CLOSE_SESSION, retval, flags);
-#endif
-
     return retval;
 
 }
