[shadow-utils] update auditing to cover more events and fix some incorrect audit records
Tomáš Mráz
tmraz at fedoraproject.org
Fri Oct 17 15:03:35 UTC 2014
commit e1ce821d4521d7ede777a6cd51f4cbcfeb1b5d9a
Author: Tomas Mraz <tmraz at fedoraproject.org>
Date: Fri Oct 17 17:03:29 2014 +0200
update auditing to cover more events and fix some incorrect audit records
(auditing patch by Steve Grubb (#1151580))
- apply the same new allocation algorithm to uids as for gids
shadow-4.1.5.1-audit-update.patch | 2250 +++++++++++++++++++++++++++++++++++++
shadow-4.1.5.1-group-alloc.patch | 642 -----------
shadow-4.1.5.1-id-alloc.patch | 1219 ++++++++++++++++++++
shadow-utils.spec | 13 +-
4 files changed, 3479 insertions(+), 645 deletions(-)
---
diff --git a/shadow-4.1.5.1-audit-update.patch b/shadow-4.1.5.1-audit-update.patch
new file mode 100644
index 0000000..c25db61
--- /dev/null
+++ b/shadow-4.1.5.1-audit-update.patch
@@ -0,0 +1,2250 @@
+diff -urp shadow-4.1.5.1.orig/lib/prototypes.h shadow-4.1.5.1/lib/prototypes.h
+--- shadow-4.1.5.1.orig/lib/prototypes.h 2014-09-13 15:45:54.953829562 -0400
++++ shadow-4.1.5.1/lib/prototypes.h 2014-10-14 08:39:23.785884075 -0400
+@@ -195,12 +195,21 @@ extern int audit_fd;
+ extern void audit_help_open (void);
+ /* Use AUDIT_NO_ID when a name is provided to audit_logger instead of an ID */
+ #define AUDIT_NO_ID ((unsigned int) -1)
++#ifndef AUDIT_GRP_MGMT
++#define AUDIT_GRP_MGMT 1132 /* Group account was modified */
++#endif
++#ifndef AUDIT_GRP_CHAUTHTOK
++#define AUDIT_GRP_CHAUTHTOK 1133 /* Group account password was changed */
++#endif
+ typedef enum {
+ SHADOW_AUDIT_FAILURE = 0,
+ SHADOW_AUDIT_SUCCESS = 1} shadow_audit_result;
+ extern void audit_logger (int type, const char *pgname, const char *op,
+ const char *name, unsigned int id,
+ shadow_audit_result result);
++void audit_logger_with_group (int type, unused const char *pgname,
++ const char *op, const char *name, unsigned int id,
++ const char *grp, shadow_audit_result result);
+ void audit_logger_message (const char *message, shadow_audit_result result);
+ #endif
+
+diff -urp shadow-4.1.5.1.orig/libmisc/audit_help.c shadow-4.1.5.1/libmisc/audit_help.c
+--- shadow-4.1.5.1.orig/libmisc/audit_help.c 2010-08-21 07:41:28.000000000 -0400
++++ shadow-4.1.5.1/libmisc/audit_help.c 2014-10-14 08:39:23.785884075 -0400
+@@ -68,7 +68,7 @@ void audit_help_open (void)
+ * This function will log a message to the audit system using a predefined
+ * message format. Parameter usage is as follows:
+ *
+- * type - type of message: AUDIT_USER_CHAUTHTOK for changing any account
++ * type - type of message: AUDIT_USER_MGMT for changing any account
+ * attributes.
+ * pgname - program's name
+ * op - operation. "adding user", "changing finger info", "deleting group"
+@@ -88,6 +88,39 @@ void audit_logger (int type, unused cons
+ }
+ }
+
++/*
++ * This function will log a message to the audit system using a predefined
++ * message format. Parameter usage is as follows:
++ *
++ * type - type of message: AUDIT_USER_MGMT for changing any account
++ * attributes.
++ * pgname - program's name
++ * op - operation. "adding user", "changing finger info", "deleting group"
++ * name - user's account or group name. If not available use NULL.
++ * id - uid or gid that the operation is being performed on. This is used
++ * only when user is NULL.
++ * grp - group name associated with event
++ */
++void audit_logger_with_group (int type, unused const char *pgname,
++ const char *op, const char *name, unsigned int id,
++ const char *grp, shadow_audit_result result)
++{
++ int len;
++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1], buf[1024];
++ if (audit_fd < 0) {
++ return;
++ }
++ len = strnlen(grp, sizeof(enc_group)/2);
++ if (audit_value_needs_encoding(grp, len)) {
++ snprintf(buf, sizeof(buf), "%s grp=%s", op,
++ audit_encode_value(enc_group, grp, len));
++ } else {
++ snprintf(buf, sizeof(buf), "%s grp=\"%s\"", op, grp);
++ }
++ audit_log_acct_message (audit_fd, type, NULL, buf, name, id,
++ NULL, NULL, NULL, (int) result);
++}
++
+ void audit_logger_message (const char *message, shadow_audit_result result)
+ {
+ if (audit_fd < 0) {
+diff -urp shadow-4.1.5.1.orig/libmisc/cleanup_group.c shadow-4.1.5.1/libmisc/cleanup_group.c
+--- shadow-4.1.5.1.orig/libmisc/cleanup_group.c 2008-12-23 17:45:18.000000000 -0500
++++ shadow-4.1.5.1/libmisc/cleanup_group.c 2014-10-14 09:00:33.594753105 -0400
+@@ -83,7 +83,7 @@ void cleanup_report_mod_group (void *cle
+ gr_dbname (),
+ info->action));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
++ audit_logger (AUDIT_GRP_MGMT, Prog,
+ info->audit_msg,
+ info->name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+@@ -101,7 +101,7 @@ void cleanup_report_mod_gshadow (void *c
+ sgr_dbname (),
+ info->action));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
++ audit_logger (AUDIT_GRP_MGMT, Prog,
+ info->audit_msg,
+ info->name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+@@ -122,7 +122,7 @@ void cleanup_report_add_group_group (voi
+ SYSLOG ((LOG_ERR, "failed to add group %s to %s", name, gr_dbname ()));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group to /etc/group",
++ "adding-group",
+ name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -141,8 +141,8 @@ void cleanup_report_add_group_gshadow (v
+
+ SYSLOG ((LOG_ERR, "failed to add group %s to %s", name, sgr_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group to /etc/gshadow",
++ audit_logger (AUDIT_GRP_MGMT, Prog,
++ "adding-shadow-group",
+ name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -164,8 +164,8 @@ void cleanup_report_del_group_group (voi
+ "failed to remove group %s from %s",
+ name, gr_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_GROUP, Prog,
+- "removing group from /etc/group",
++ audit_logger (AUDIT_DEL_GROUP, Prog,
++ "removing-group",
+ name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -187,8 +187,8 @@ void cleanup_report_del_group_gshadow (v
+ "failed to remove group %s from %s",
+ name, sgr_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_GROUP, Prog,
+- "removing group from /etc/gshadow",
++ audit_logger (AUDIT_GRP_MGMT, Prog,
++ "removing-shadow-group",
+ name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -208,7 +208,7 @@ void cleanup_unlock_group (unused void *
+ Prog, gr_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger_message ("unlocking group file",
++ audit_logger_message ("unlocking-group",
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+@@ -228,7 +228,7 @@ void cleanup_unlock_gshadow (unused void
+ Prog, sgr_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger_message ("unlocking gshadow file",
++ audit_logger_message ("unlocking-gshadow",
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+diff -urp shadow-4.1.5.1.orig/libmisc/cleanup_user.c shadow-4.1.5.1/libmisc/cleanup_user.c
+--- shadow-4.1.5.1.orig/libmisc/cleanup_user.c 2008-12-23 17:45:18.000000000 -0500
++++ shadow-4.1.5.1/libmisc/cleanup_user.c 2014-10-14 09:01:51.878745031 -0400
+@@ -65,7 +65,7 @@ void cleanup_report_mod_passwd (void *cl
+ pw_dbname (),
+ info->action));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
++ audit_logger (AUDIT_USER_MGMT, Prog,
+ info->audit_msg,
+ info->name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+@@ -86,7 +86,7 @@ void cleanup_report_add_user_passwd (voi
+ SYSLOG ((LOG_ERR, "failed to add user %s to %s", name, pw_dbname ()));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to /etc/passwd",
++ "adding-user",
+ name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -105,8 +105,8 @@ void cleanup_report_add_user_shadow (voi
+
+ SYSLOG ((LOG_ERR, "failed to add user %s to %s", name, spw_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to /etc/shadow",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "adding-shadow-user",
+ name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -125,7 +125,7 @@ void cleanup_unlock_passwd (unused void
+ Prog, pw_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger_message ("unlocking passwd file",
++ audit_logger_message ("unlocking-passwd",
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+@@ -144,7 +144,7 @@ void cleanup_unlock_shadow (unused void
+ Prog, spw_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
+ #ifdef WITH_AUDIT
+- audit_logger_message ("unlocking shadow file",
++ audit_logger_message ("unlocking-shadow",
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+diff -urp shadow-4.1.5.1.orig/src/chage.c shadow-4.1.5.1/src/chage.c
+--- shadow-4.1.5.1.orig/src/chage.c 2011-11-19 17:54:47.000000000 -0500
++++ shadow-4.1.5.1/src/chage.c 2014-10-14 08:39:23.787884075 -0400
+@@ -126,9 +126,10 @@ static /*@noreturn@*/void fail_exit (int
+
+ #ifdef WITH_AUDIT
+ if (E_SUCCESS != code) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change age",
+- user_name, (unsigned int) user_uid, 0);
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-age",
++ user_name, (unsigned int) user_uid,
++ SHADOW_AUDIT_FAILURE);
+ }
+ #endif
+
+@@ -873,11 +874,7 @@ int main (int argc, char **argv)
+ fprintf (stderr, _("%s: Permission denied.\n"), Prog);
+ fail_exit (E_NOPERM);
+ }
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "display aging info",
+- user_name, (unsigned int) user_uid, 1);
+-#endif
++ /* Displaying fields is not of interest to audit */
+ list_fields ();
+ fail_exit (E_SUCCESS);
+ }
+@@ -896,41 +893,43 @@ int main (int argc, char **argv)
+ }
+ #ifdef WITH_AUDIT
+ else {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change all aging information",
+- user_name, (unsigned int) user_uid, 1);
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-all-aging-information",
++ user_name, (unsigned int) user_uid,
++ SHADOW_AUDIT_SUCCESS);
+ }
+ #endif
+ } else {
+ #ifdef WITH_AUDIT
+ if (Mflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change max age",
+- user_name, (unsigned int) user_uid, 1);
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-max-age",
++ user_name, (unsigned int) user_uid,
++ SHADOW_AUDIT_SUCCESS);
+ }
+ if (mflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change min age",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-min-age",
+ user_name, (unsigned int) user_uid, 1);
+ }
+ if (dflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change last change date",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-last-change-date",
+ user_name, (unsigned int) user_uid, 1);
+ }
+ if (Wflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change passwd warning",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-passwd-warning",
+ user_name, (unsigned int) user_uid, 1);
+ }
+ if (Iflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change inactive days",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-inactive-days",
+ user_name, (unsigned int) user_uid, 1);
+ }
+ if (Eflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "change passwd expiration",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "change-passwd-expiration",
+ user_name, (unsigned int) user_uid, 1);
+ }
+ #endif
+diff -urp shadow-4.1.5.1.orig/src/gpasswd.c shadow-4.1.5.1/src/gpasswd.c
+--- shadow-4.1.5.1.orig/src/gpasswd.c 2014-09-13 15:45:54.989829559 -0400
++++ shadow-4.1.5.1/src/gpasswd.c 2014-10-14 08:43:07.393861012 -0400
+@@ -137,7 +137,7 @@ static void usage (int status)
+ (void) fputs (_(" -d, --delete USER remove USER from GROUP\n"), usageout);
+ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
+ (void) fputs (_(" -Q, --root CHROOT_DIR directory to chroot into\n"), usageout);
+- (void) fputs (_(" -r, --remove-password remove the GROUP's password\n"), usageout);
++ (void) fputs (_(" -r, --delete-password remove the GROUP's password\n"), usageout);
+ (void) fputs (_(" -R, --restrict restrict access to GROUP to its members\n"), usageout);
+ (void) fputs (_(" -M, --members USER,... set the list of members of GROUP\n"), usageout);
+ #ifdef SHADOWGRP
+@@ -397,21 +397,14 @@ static void open_files (void)
+
+ static void log_gpasswd_failure (const char *suffix)
+ {
+-#ifdef WITH_AUDIT
+- char buf[1024];
+-#endif
+ if (aflg) {
+ SYSLOG ((LOG_ERR,
+ "%s failed to add user %s to group %s%s",
+ myname, user, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to add user %s to group %s%s",
+- myname, user, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-user-to-group",
++ user, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ } else if (dflg) {
+@@ -419,13 +412,9 @@ static void log_gpasswd_failure (const c
+ "%s failed to remove user %s from group %s%s",
+ myname, user, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to remove user %s from group %s%s",
+- myname, user, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "delete-user-from-group",
++ user, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ } else if (rflg) {
+@@ -433,13 +422,9 @@ static void log_gpasswd_failure (const c
+ "%s failed to remove password of group %s%s",
+ myname, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to remove password of group %s%s",
+- myname, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog,
++ "delete-group-password",
++ myname, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ } else if (Rflg) {
+@@ -447,13 +432,9 @@ static void log_gpasswd_failure (const c
+ "%s failed to restrict access to group %s%s",
+ myname, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to restrict access to group %s%s",
+- myname, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog,
++ "restrict-group",
++ myname, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ } else if (Aflg || Mflg) {
+@@ -463,13 +444,9 @@ static void log_gpasswd_failure (const c
+ "%s failed to set the administrators of group %s to %s%s",
+ myname, group, admins, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to set the administrators of group %s to %s%s",
+- myname, group, admins, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog,
++ "set-admins-of-group",
++ admins, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+@@ -479,13 +456,9 @@ static void log_gpasswd_failure (const c
+ "%s failed to set the members of group %s to %s%s",
+ myname, group, members, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to set the members of group %s to %s%s",
+- myname, group, members, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-users-to-group",
++ members, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+@@ -494,13 +467,9 @@ static void log_gpasswd_failure (const c
+ "%s failed to change password of group %s%s",
+ myname, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "%s failed to change password of group %s%s",
+- myname, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog,
++ "change-password",
++ myname, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+ }
+@@ -531,21 +500,14 @@ static void log_gpasswd_failure_gshadow
+
+ static void log_gpasswd_success (const char *suffix)
+ {
+-#ifdef WITH_AUDIT
+- char buf[1024];
+-#endif
+ if (aflg) {
+ SYSLOG ((LOG_INFO,
+ "user %s added by %s to group %s%s",
+ user, myname, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "user %s added by %s to group %s%s",
+- user, myname, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-user-to-group",
++ user, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ } else if (dflg) {
+@@ -553,13 +515,9 @@ static void log_gpasswd_success (const c
+ "user %s removed by %s from group %s%s",
+ user, myname, group, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "user %s removed by %s from group %s%s",
+- user, myname, group, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "delete-user-from-group",
++ user, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ } else if (rflg) {
+@@ -567,13 +525,9 @@ static void log_gpasswd_success (const c
+ "password of group %s removed by %s%s",
+ group, myname, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "password of group %s removed by %s%s",
+- group, myname, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog,
++ "delete-group-password",
++ myname, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ } else if (Rflg) {
+@@ -581,13 +535,9 @@ static void log_gpasswd_success (const c
+ "access to group %s restricted by %s%s",
+ group, myname, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "access to group %s restricted by %s%s",
+- group, myname, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog,
++ "restrict-group",
++ myname, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ } else if (Aflg || Mflg) {
+@@ -597,13 +547,9 @@ static void log_gpasswd_success (const c
+ "administrators of group %s set by %s to %s%s",
+ group, myname, admins, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "administrators of group %s set by %s to %s%s",
+- group, myname, admins, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog,
++ "set-admins-of-group",
++ admins, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ }
+@@ -613,13 +559,9 @@ static void log_gpasswd_success (const c
+ "members of group %s set by %s to %s%s",
+ group, myname, members, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "members of group %s set by %s to %s%s",
+- group, myname, members, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-users-to-group",
++ members, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ }
+@@ -628,13 +570,9 @@ static void log_gpasswd_success (const c
+ "password of group %s changed by %s%s",
+ group, myname, suffix));
+ #ifdef WITH_AUDIT
+- snprintf (buf, 1023,
+- "password of group %s changed by %s%s",
+- group, myname, suffix);
+- buf[1023] = '\0';
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- buf,
+- group, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog,
++ "change-password",
++ myname, AUDIT_NO_ID, group,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ }
+diff -urp shadow-4.1.5.1.orig/src/groupadd.c shadow-4.1.5.1/src/groupadd.c
+--- shadow-4.1.5.1.orig/src/groupadd.c 2011-11-18 16:23:30.000000000 -0500
++++ shadow-4.1.5.1/src/groupadd.c 2014-10-14 08:39:23.800884073 -0400
+@@ -127,6 +127,15 @@ static /*@noreturn@*/void usage (int sta
+ exit (status);
+ }
+
++static void fail_exit(int status)
++{
++#ifdef WITH_AUDIT
++ audit_logger(AUDIT_ADD_GROUP, Prog, "add-group", group_name,
++ AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
++#endif
++ exit (status);
++}
++
+ /*
+ * new_grent - initialize the values in a group file entry
+ *
+@@ -210,7 +219,7 @@ static void grp_update (void)
+ fprintf (stderr,
+ _("%s: failed to prepare the new %s entry '%s'\n"),
+ Prog, gr_dbname (), grp.gr_name);
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef SHADOWGRP
+ /*
+@@ -220,7 +229,7 @@ static void grp_update (void)
+ fprintf (stderr,
+ _("%s: failed to prepare the new %s entry '%s'\n"),
+ Prog, sgr_dbname (), sgrp.sg_name);
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ #endif /* SHADOWGRP */
+ }
+@@ -244,7 +253,7 @@ static void check_new_name (void)
+ fprintf (stderr, _("%s: '%s' is not a valid group name\n"),
+ Prog, group_name);
+
+- exit (E_BAD_ARG);
++ fail_exit (E_BAD_ARG);
+ }
+
+ /*
+@@ -260,11 +269,11 @@ static void close_files (void)
+ fprintf (stderr,
+ _("%s: failure while writing changes to %s\n"),
+ Prog, gr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group to /etc/group",
++ "add-group",
+ group_name, (unsigned int) group_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -282,11 +291,11 @@ static void close_files (void)
+ fprintf (stderr,
+ _("%s: failure while writing changes to %s\n"),
+ Prog, sgr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group to /etc/gshadow",
++ audit_logger (AUDIT_GRP_MGMT, Prog,
++ "add-shadow-group",
+ group_name, (unsigned int) group_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -300,12 +309,6 @@ static void close_files (void)
+ #endif /* SHADOWGRP */
+
+ /* Report success at the system level */
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_GROUP, Prog,
+- "",
+- group_name, (unsigned int) group_id,
+- SHADOW_AUDIT_SUCCESS);
+-#endif
+ SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u",
+ group_name, (unsigned int) group_id));
+ del_cleanup (cleanup_report_add_group);
+@@ -323,7 +326,7 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, gr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ add_cleanup (cleanup_unlock_group, NULL);
+
+@@ -333,7 +336,7 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, sgr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ add_cleanup (cleanup_unlock_gshadow, NULL);
+ }
+@@ -349,7 +352,7 @@ static void open_files (void)
+ if (gr_open (O_RDWR) == 0) {
+ fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
+ SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+
+ #ifdef SHADOWGRP
+@@ -359,7 +362,7 @@ static void open_files (void)
+ _("%s: cannot open %s\n"),
+ Prog, sgr_dbname ());
+ SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ }
+ #endif /* SHADOWGRP */
+@@ -489,7 +492,7 @@ static void check_flags (void)
+ fprintf (stderr,
+ _("%s: group '%s' already exists\n"),
+ Prog, group_name);
+- exit (E_NAME_IN_USE);
++ fail_exit (E_NAME_IN_USE);
+ }
+
+ if (gflg && (getgrgid (group_id) != NULL)) {
+@@ -508,7 +511,7 @@ static void check_flags (void)
+ fprintf (stderr,
+ _("%s: GID '%lu' already exists\n"),
+ Prog, (unsigned long int) group_id);
+- exit (E_GID_IN_USE);
++ fail_exit (E_GID_IN_USE);
+ }
+ }
+ }
+@@ -536,7 +539,7 @@ static void check_perms (void)
+ fprintf (stderr,
+ _("%s: Cannot determine your user name.\n"),
+ Prog);
+- exit (1);
++ fail_exit (1);
+ }
+
+ retval = pam_start ("groupadd", pampw->pw_name, &conv, &pamh);
+@@ -556,7 +559,7 @@ static void check_perms (void)
+ if (NULL != pamh) {
+ (void) pam_end (pamh, retval);
+ }
+- exit (1);
++ fail_exit (1);
+ }
+ (void) pam_end (pamh, retval);
+ #endif /* USE_PAM */
+@@ -588,7 +591,7 @@ int main (int argc, char **argv)
+ fprintf (stderr,
+ _("%s: Cannot setup cleanup service.\n"),
+ Prog);
+- exit (1);
++ fail_exit (1);
+ }
+
+ /*
+@@ -610,7 +613,7 @@ int main (int argc, char **argv)
+
+ if (!gflg) {
+ if (find_new_gid (rflg, &group_id, NULL) < 0) {
+- exit (E_GID_IN_USE);
++ fail_exit (E_GID_IN_USE);
+ }
+ }
+
+diff -urp shadow-4.1.5.1.orig/src/groupdel.c shadow-4.1.5.1/src/groupdel.c
+--- shadow-4.1.5.1.orig/src/groupdel.c 2011-11-18 16:23:30.000000000 -0500
++++ shadow-4.1.5.1/src/groupdel.c 2014-10-14 08:39:23.801884073 -0400
+@@ -100,6 +100,15 @@ static /*@noreturn@*/void usage (int sta
+ exit (status);
+ }
+
++static void fail_exit(int status)
++{
++#ifdef WITH_AUDIT
++ audit_logger(AUDIT_GRP_MGMT, Prog, "delete-group", group_name,
++ AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
++#endif
++ exit (status);
++}
++
+ /*
+ * grp_update - update group file entries
+ *
+@@ -126,7 +135,7 @@ static void grp_update (void)
+ fprintf (stderr,
+ _("%s: cannot remove entry '%s' from %s\n"),
+ Prog, group_name, gr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+
+ #ifdef SHADOWGRP
+@@ -138,7 +147,7 @@ static void grp_update (void)
+ fprintf (stderr,
+ _("%s: cannot remove entry '%s' from %s\n"),
+ Prog, group_name, sgr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ }
+ #endif /* SHADOWGRP */
+@@ -157,12 +166,12 @@ static void close_files (void)
+ fprintf (stderr,
+ _("%s: failure while writing changes to %s\n"),
+ Prog, gr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_GROUP, Prog,
+- "removing group from /etc/group",
++ "delete-group",
+ group_name, (unsigned int) group_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -182,12 +191,12 @@ static void close_files (void)
+ fprintf (stderr,
+ _("%s: failure while writing changes to %s\n"),
+ Prog, sgr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_GROUP, Prog,
+- "removing group from /etc/gshadow",
++ audit_logger (AUDIT_GRP_MGMT, Prog,
++ "delete-shadow-group",
+ group_name, (unsigned int) group_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -201,13 +210,6 @@ static void close_files (void)
+ }
+ #endif /* SHADOWGRP */
+
+- /* Report success at the system level */
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_GROUP, Prog,
+- "",
+- group_name, (unsigned int) group_id,
+- SHADOW_AUDIT_SUCCESS);
+-#endif
+ SYSLOG ((LOG_INFO, "group '%s' removed\n", group_name));
+ del_cleanup (cleanup_report_del_group);
+ }
+@@ -224,7 +226,7 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, gr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ add_cleanup (cleanup_unlock_group, NULL);
+ #ifdef SHADOWGRP
+@@ -233,7 +235,7 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, sgr_dbname ());
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ add_cleanup (cleanup_unlock_gshadow, NULL);
+ }
+@@ -251,7 +253,7 @@ static void open_files (void)
+ _("%s: cannot open %s\n"),
+ Prog, gr_dbname ());
+ SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef SHADOWGRP
+ if (is_shadow_grp) {
+@@ -260,7 +262,7 @@ static void open_files (void)
+ _("%s: cannot open %s\n"),
+ Prog, sgr_dbname ());
+ SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
+- exit (E_GRP_UPDATE);
++ fail_exit (E_GRP_UPDATE);
+ }
+ }
+ #endif /* SHADOWGRP */
+@@ -301,7 +303,7 @@ static void group_busy (gid_t gid)
+ fprintf (stderr,
+ _("%s: cannot remove the primary group of user '%s'\n"),
+ Prog, pwd->pw_name);
+- exit (E_GROUP_BUSY);
++ fail_exit (E_GROUP_BUSY);
+ }
+
+ /*
+@@ -379,7 +381,7 @@ int main (int argc, char **argv)
+ fprintf (stderr,
+ _("%s: Cannot setup cleanup service.\n"),
+ Prog);
+- exit (1);
++ fail_exit (1);
+ }
+
+ process_flags (argc, argv);
+@@ -393,7 +395,7 @@ int main (int argc, char **argv)
+ fprintf (stderr,
+ _("%s: Cannot determine your user name.\n"),
+ Prog);
+- exit (1);
++ fail_exit (1);
+ }
+
+ retval = pam_start ("groupdel", pampw->pw_name, &conv, &pamh);
+@@ -414,7 +416,7 @@ int main (int argc, char **argv)
+ if (NULL != pamh) {
+ (void) pam_end (pamh, retval);
+ }
+- exit (1);
++ fail_exit (1);
+ }
+ (void) pam_end (pamh, retval);
+ #endif /* USE_PAM */
+@@ -434,7 +436,7 @@ int main (int argc, char **argv)
+ fprintf (stderr,
+ _("%s: group '%s' does not exist\n"),
+ Prog, group_name);
+- exit (E_NOTFOUND);
++ fail_exit (E_NOTFOUND);
+ }
+
+ group_id = grp->gr_gid;
+@@ -458,7 +460,7 @@ int main (int argc, char **argv)
+ _("%s: %s is the NIS master\n"),
+ Prog, nis_master);
+ }
+- exit (E_NOTFOUND);
++ fail_exit (E_NOTFOUND);
+ }
+ #endif
+
+diff -urp shadow-4.1.5.1.orig/src/groupmod.c shadow-4.1.5.1/src/groupmod.c
+--- shadow-4.1.5.1.orig/src/groupmod.c 2011-11-18 16:23:30.000000000 -0500
++++ shadow-4.1.5.1/src/groupmod.c 2014-10-14 08:49:28.517821702 -0400
+@@ -438,7 +438,7 @@ static void close_files (void)
+ exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
++ audit_logger (AUDIT_GRP_MGMT, Prog,
+ info_group.audit_msg,
+ group_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_SUCCESS);
+@@ -461,7 +461,7 @@ static void close_files (void)
+ exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
++ audit_logger (AUDIT_GRP_MGMT, Prog,
+ info_gshadow.audit_msg,
+ group_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_SUCCESS);
+@@ -484,7 +484,7 @@ static void close_files (void)
+ exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
++ audit_logger (AUDIT_GRP_MGMT, Prog,
+ info_passwd.audit_msg,
+ group_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_SUCCESS);
+@@ -499,8 +499,8 @@ static void close_files (void)
+ }
+
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_ACCT, Prog,
+- "modifying group",
++ audit_logger (AUDIT_GRP_MGMT, Prog,
++ "modify-group",
+ group_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -512,6 +512,8 @@ static void close_files (void)
+ */
+ static void prepare_failure_reports (void)
+ {
++ char *nv_pair, nv[64];
++
+ info_group.name = group_name;
+ #ifdef SHADOWGRP
+ info_gshadow.name = group_name;
+@@ -524,76 +526,106 @@ static void prepare_failure_reports (voi
+ #endif
+ info_passwd.audit_msg = xmalloc (512);
+
+- (void) snprintf (info_group.audit_msg, 511,
+- "changing %s; ", gr_dbname ());
++ info_group.action = xmalloc (512);
+ #ifdef SHADOWGRP
+- (void) snprintf (info_gshadow.audit_msg, 511,
+- "changing %s; ", sgr_dbname ());
++ info_gshadow.action = xmalloc (512);
+ #endif
+- (void) snprintf (info_passwd.audit_msg, 511,
+- "changing %s; ", pw_dbname ());
++ info_passwd.action = xmalloc (512);
+
+- info_group.action = info_group.audit_msg
+- + strlen (info_group.audit_msg);
++ (void) snprintf (info_group.audit_msg, 511,
++ "changing-group");
+ #ifdef SHADOWGRP
+- info_gshadow.action = info_gshadow.audit_msg
+- + strlen (info_gshadow.audit_msg);
++ (void) snprintf (info_gshadow.audit_msg, 511,
++ "changing-shadow-group");
+ #endif
+- info_passwd.action = info_passwd.audit_msg
+- + strlen (info_passwd.audit_msg);
++ (void) snprintf (info_passwd.audit_msg, 511,
++ "changing-group-passwd");
+
++ nv_pair = audit_encode_nv_string(" grp", group_name,
++ strlen(group_name));
++ if(nv_pair) {
++ strncat(info_group.audit_msg, nv_pair,
++ 511 - strlen(info_group.audit_msg));
++#ifdef SHADOWGRP
++ strncat(info_gshadow.audit_msg, nv_pair,
++ 511 - strlen(info_gshadow.audit_msg));
++#endif
++ strncat(info_passwd.audit_msg, nv_pair,
++ 511 - strlen(info_passwd.audit_msg));
++ free(nv_pair);
++ }
++ snprintf(nv, sizeof(nv), " gid=%lu", group_id);
++ strncat(info_group.audit_msg, nv, 511 - strlen(info_group.audit_msg));
++ strncat(info_passwd.audit_msg, nv, 511 - strlen(info_passwd.audit_msg));
++
+ (void) snprintf (info_group.action,
+- 511 - strlen (info_group.audit_msg),
++ 511,
+ "group %s/%lu",
+ group_name, (unsigned long int) group_id);
+ #ifdef SHADOWGRP
+ (void) snprintf (info_gshadow.action,
+- 511 - strlen (info_group.audit_msg),
++ 511,
+ "group %s", group_name);
+ #endif
+ (void) snprintf (info_passwd.action,
+- 511 - strlen (info_group.audit_msg),
++ 511,
+ "group %s/%lu",
+ group_name, (unsigned long int) group_id);
+
+ if (nflg) {
++ nv_pair = audit_encode_nv_string(" new_group", group_newname,
++ strlen(group_newname));
++ strncat(info_group.audit_msg, nv_pair,
++ 511 - strlen(info_group.audit_msg));
+ strncat (info_group.action, ", new name: ",
+- 511 - strlen (info_group.audit_msg));
++ 511 - strlen (info_group.action));
+ strncat (info_group.action, group_newname,
+- 511 - strlen (info_group.audit_msg));
++ 511 - strlen (info_group.action));
+
+ #ifdef SHADOWGRP
++ strncat(info_gshadow.audit_msg, nv_pair,
++ 511 - strlen(info_gshadow.audit_msg));
+ strncat (info_gshadow.action, ", new name: ",
+- 511 - strlen (info_gshadow.audit_msg));
++ 511 - strlen (info_gshadow.action));
+ strncat (info_gshadow.action, group_newname,
+- 511 - strlen (info_gshadow.audit_msg));
++ 511 - strlen (info_gshadow.action));
+ #endif
+
++ strncat(info_passwd.audit_msg, nv_pair,
++ 511 - strlen(info_passwd.audit_msg));
+ strncat (info_passwd.action, ", new name: ",
+- 511 - strlen (info_passwd.audit_msg));
++ 511 - strlen (info_passwd.action));
+ strncat (info_passwd.action, group_newname,
+- 511 - strlen (info_passwd.audit_msg));
++ 511 - strlen (info_passwd.action));
++ free(nv_pair);
+ }
+ if (pflg) {
++ /* Note: audit doesn't want this value recorded */
+ strncat (info_group.action, ", new password",
+- 511 - strlen (info_group.audit_msg));
++ 511 - strlen (info_group.action));
+
+ #ifdef SHADOWGRP
+ strncat (info_gshadow.action, ", new password",
+- 511 - strlen (info_gshadow.audit_msg));
++ 511 - strlen (info_gshadow.action));
+ #endif
+ }
+ if (gflg) {
++ snprintf(nv, sizeof(nv), " new_gid=%lu", group_newid);
++ strncat(info_group.audit_msg, nv,
++ 511 - strlen(info_group.audit_msg));
++ strncat(info_passwd.audit_msg, nv,
++ 511 - strlen(info_passwd.audit_msg));
++
+ strncat (info_group.action, ", new gid: ",
+- 511 - strlen (info_group.audit_msg));
++ 511 - strlen (info_group.action));
+ (void) snprintf (info_group.action+strlen (info_group.action),
+- 511 - strlen (info_group.audit_msg),
++ 511 - strlen (info_group.action),
+ "%lu", (unsigned long int) group_newid);
+
+ strncat (info_passwd.action, ", new gid: ",
+- 511 - strlen (info_passwd.audit_msg));
++ 511 - strlen (info_passwd.action));
+ (void) snprintf (info_passwd.action+strlen (info_passwd.action),
+- 511 - strlen (info_passwd.audit_msg),
++ 511 - strlen (info_passwd.action),
+ "%lu", (unsigned long int) group_newid);
+ }
+ info_group.audit_msg[511] = '\0';
+@@ -601,6 +633,11 @@ static void prepare_failure_reports (voi
+ info_gshadow.audit_msg[511] = '\0';
+ #endif
+ info_passwd.audit_msg[511] = '\0';
++ info_group.action[511] = '\0';
++#ifdef SHADOWGRP
++ info_gshadow.action[511] = '\0';
++#endif
++ info_passwd.action[511] = '\0';
+
+ // FIXME: add a system cleanup
+ add_cleanup (cleanup_report_mod_group, &info_group);
+diff -urp shadow-4.1.5.1.orig/src/newgrp.c shadow-4.1.5.1/src/newgrp.c
+--- shadow-4.1.5.1.orig/src/newgrp.c 2014-09-13 15:45:55.010829557 -0400
++++ shadow-4.1.5.1/src/newgrp.c 2014-10-14 08:39:23.802884073 -0400
+@@ -197,11 +197,12 @@ static void check_perms (const struct gr
+ strcmp (cpasswd, grp->gr_passwd) != 0) {
+ #ifdef WITH_AUDIT
+ snprintf (audit_buf, sizeof(audit_buf),
+- "authentication new-gid=%lu",
++ "authentication new_gid=%lu",
+ (unsigned long) grp->gr_gid);
+ audit_logger (AUDIT_GRP_AUTH, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (),
++ SHADOW_AUDIT_FAILURE);
+ #endif
+ SYSLOG ((LOG_INFO,
+ "Invalid password for group '%s' from '%s'",
+@@ -212,11 +213,12 @@ static void check_perms (const struct gr
+ }
+ #ifdef WITH_AUDIT
+ snprintf (audit_buf, sizeof(audit_buf),
+- "authentication new-gid=%lu",
++ "authentication new_gid=%lu",
+ (unsigned long) grp->gr_gid);
+ audit_logger (AUDIT_GRP_AUTH, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 1);
++ (unsigned int) getuid (),
++ SHADOW_AUDIT_SUCCESS);
+ #endif
+ }
+
+@@ -227,19 +229,6 @@ failure:
+ * harm. -- JWP
+ */
+ closelog ();
+-#ifdef WITH_AUDIT
+- if (groupname) {
+- snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-group=%s", groupname);
+- audit_logger (AUDIT_CHGRP_ID, Prog,
+- audit_buf, NULL,
+- (unsigned int) getuid (), 0);
+- } else {
+- audit_logger (AUDIT_CHGRP_ID, Prog,
+- "changing", NULL,
+- (unsigned int) getuid (), 0);
+- }
+-#endif
+ exit (EXIT_FAILURE);
+ }
+
+@@ -308,15 +297,27 @@ static void syslog_sg (const char *name,
+ is_newgrp ? "newgrp" : "sg", strerror (errno));
+ #ifdef WITH_AUDIT
+ if (group) {
+- snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-group=%s", group);
++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1];
++ int len = strnlen(group, sizeof(enc_group)/2);
++ if (audit_value_needs_encoding(group, len)) {
++ snprintf (audit_buf, sizeof(audit_buf),
++ "changing new_group=%s",
++ audit_encode_value(enc_group,
++ group, len));
++ } else {
++ snprintf (audit_buf, sizeof(audit_buf),
++ "changing new_group=\"%s\"",
++ group);
++ }
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (),
++ SHADOW_AUDIT_FAILURE);
+ } else {
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ "changing", NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (),
++ SHADOW_AUDIT_FAILURE);
+ }
+ #endif
+ exit (EXIT_FAILURE);
+@@ -442,7 +443,7 @@ int main (int argc, char **argv)
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ "changing", NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE);
+ #endif
+ SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
+ (unsigned long) getuid ()));
+@@ -558,15 +559,26 @@ int main (int argc, char **argv)
+ perror ("getgroups");
+ #ifdef WITH_AUDIT
+ if (group) {
+- snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-group=%s", group);
++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1];
++ int len = strnlen(group, sizeof(enc_group)/2);
++ if (audit_value_needs_encoding(group, len)) {
++ snprintf (audit_buf, sizeof(audit_buf),
++ "changing new_group=%s",
++ audit_encode_value(enc_group,
++ group, len));
++ } else {
++ snprintf (audit_buf, sizeof(audit_buf),
++ "changing new_group=\"%s\"", group);
++ }
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (),
++ SHADOW_AUDIT_FAILURE);
+ } else {
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ "changing", NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (),
++ SHADOW_AUDIT_FAILURE);
+ }
+ #endif
+ exit (EXIT_FAILURE);
+@@ -707,10 +719,10 @@ int main (int argc, char **argv)
+ perror ("setgid");
+ #ifdef WITH_AUDIT
+ snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-gid=%lu", (unsigned long) gid);
++ "changing new_gid=%lu", (unsigned long) gid);
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE);
+ #endif
+ exit (EXIT_FAILURE);
+ }
+@@ -719,10 +731,10 @@ int main (int argc, char **argv)
+ perror ("setuid");
+ #ifdef WITH_AUDIT
+ snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-gid=%lu", (unsigned long) gid);
++ "changing new_gid=%lu", (unsigned long) gid);
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE);
+ #endif
+ exit (EXIT_FAILURE);
+ }
+@@ -736,10 +748,10 @@ int main (int argc, char **argv)
+ execl (SHELL, "sh", "-c", command, (char *) 0);
+ #ifdef WITH_AUDIT
+ snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-gid=%lu", (unsigned long) gid);
++ "changing new_gid=%lu", (unsigned long) gid);
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE);
+ #endif
+ perror (SHELL);
+ exit ((errno == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
+@@ -803,11 +815,11 @@ int main (int argc, char **argv)
+ }
+
+ #ifdef WITH_AUDIT
+- snprintf (audit_buf, sizeof(audit_buf), "changing new-gid=%lu",
++ snprintf (audit_buf, sizeof(audit_buf), "changing new_gid=%lu",
+ (unsigned long) gid);
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 1);
++ (unsigned int) getuid (), SHADOW_AUDIT_SUCCESS);
+ #endif
+ /*
+ * Exec the login shell and go away. We are trying to get back to
+@@ -831,15 +843,24 @@ int main (int argc, char **argv)
+ closelog ();
+ #ifdef WITH_AUDIT
+ if (NULL != group) {
+- snprintf (audit_buf, sizeof(audit_buf),
+- "changing new-group=%s", group);
++ char enc_group[(GROUP_NAME_MAX_LENGTH*2)+1];
++ int len = strnlen(group, sizeof(enc_group)/2);
++ if (audit_value_needs_encoding(group, len)) {
++ snprintf (audit_buf, sizeof(audit_buf),
++ "changing new_group=%s",
++ audit_encode_value(enc_group,
++ group, len));
++ } else {
++ snprintf (audit_buf, sizeof(audit_buf),
++ "changing new_group=\"%s\"", group);
++ }
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ audit_buf, NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE);
+ } else {
+ audit_logger (AUDIT_CHGRP_ID, Prog,
+ "changing", NULL,
+- (unsigned int) getuid (), 0);
++ (unsigned int) getuid (), SHADOW_AUDIT_FAILURE);
+ }
+ #endif
+ exit (EXIT_FAILURE);
+diff -urp shadow-4.1.5.1.orig/src/useradd.c shadow-4.1.5.1/src/useradd.c
+--- shadow-4.1.5.1.orig/src/useradd.c 2014-09-13 15:45:54.957829561 -0400
++++ shadow-4.1.5.1/src/useradd.c 2014-10-14 08:52:53.066800605 -0400
+@@ -205,6 +205,8 @@ static void create_mail (void);
+ */
+ static void fail_exit (int code)
+ {
++ int type;
++
+ if (home_added) {
+ if (rmdir (user_home) != 0) {
+ fprintf (stderr,
+@@ -218,12 +220,6 @@ static void fail_exit (int code)
+ if (spw_unlock () == 0) {
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking shadow file",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ /* continue */
+ }
+ }
+@@ -231,12 +227,6 @@ static void fail_exit (int code)
+ if (pw_unlock () == 0) {
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking passwd file",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ /* continue */
+ }
+ }
+@@ -244,12 +234,6 @@ static void fail_exit (int code)
+ if (gr_unlock () == 0) {
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking group file",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ /* continue */
+ }
+ }
+@@ -258,20 +242,19 @@ static void fail_exit (int code)
+ if (sgr_unlock () == 0) {
+ fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
+ SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking gshadow file",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ /* continue */
+ }
+ }
+ #endif
+
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user",
++ if (code == E_PW_UPDATE || code >= E_GRP_UPDATE)
++ type = AUDIT_USER_MGMT;
++ else
++ type = AUDIT_ADD_USER;
++
++ audit_logger (type, Prog,
++ "add-user",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -578,7 +561,7 @@ static int set_defaults (void)
+ }
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_USYS_CONFIG, Prog,
+- "changing useradd defaults",
++ "changing-useradd-defaults",
+ NULL, AUDIT_NO_ID,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -848,12 +831,6 @@ static void grp_update (void)
+ _("%s: Out of memory. Cannot update %s.\n"),
+ Prog, gr_dbname ());
+ SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", gr_dbname (), user_name));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to group",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_GRP_UPDATE); /* XXX */
+ }
+
+@@ -867,18 +844,12 @@ static void grp_update (void)
+ _("%s: failed to prepare the new %s entry '%s'\n"),
+ Prog, gr_dbname (), ngrp->gr_name);
+ SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", gr_dbname (), user_name));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to group",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to group",
+- user_name, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-user-to-group",
++ user_name, AUDIT_NO_ID, ngrp->gr_name,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -923,12 +894,6 @@ static void grp_update (void)
+ _("%s: Out of memory. Cannot update %s.\n"),
+ Prog, sgr_dbname ());
+ SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", sgr_dbname (), user_name));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to shadow group",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_GRP_UPDATE); /* XXX */
+ }
+
+@@ -942,18 +907,13 @@ static void grp_update (void)
+ _("%s: failed to prepare the new %s entry '%s'\n"),
+ Prog, sgr_dbname (), nsgrp->sg_name);
+ SYSLOG ((LOG_ERR, "failed to prepare the new %s entry '%s'", sgr_dbname (), user_name));
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to shadow group",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
++
+ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user to shadow group",
+- user_name, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-to-shadow-group",
++ user_name, AUDIT_NO_ID, nsgrp->sg_name,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -1296,7 +1256,7 @@ static void process_flags (int argc, cha
+ Prog, user_name);
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user",
++ "add-user",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1385,7 +1345,7 @@ static void close_files (void)
+ SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ()));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking shadow file",
++ "unlocking-shadow-file",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1398,7 +1358,7 @@ static void close_files (void)
+ SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ()));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking passwd file",
++ "unlocking-passwd-file",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1410,7 +1370,7 @@ static void close_files (void)
+ SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking group file",
++ "unlocking-group-file",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1424,7 +1384,7 @@ static void close_files (void)
+ SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "unlocking gshadow file",
++ "unlocking-gshadow-file",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1584,7 +1544,7 @@ static void grp_add (void)
+ Prog, gr_dbname (), grp.gr_name);
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group",
++ "add-group",
+ grp.gr_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1600,7 +1560,7 @@ static void grp_add (void)
+ Prog, sgr_dbname (), sgrp.sg_name);
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group",
++ "add-group",
+ grp.gr_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif
+@@ -1610,7 +1570,7 @@ static void grp_add (void)
+ SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u", user_name, user_gid));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_GROUP, Prog,
+- "adding group",
++ "add-group",
+ grp.gr_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -1725,17 +1685,11 @@ static void usr_update (void)
+ fprintf (stderr,
+ _("%s: failed to prepare the new %s entry '%s'\n"),
+ Prog, spw_dbname (), spent.sp_namp);
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding shadow password",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_PW_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user",
++ "add-user",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -1771,12 +1725,6 @@ static void create_home (void)
+ fprintf (stderr,
+ _("%s: cannot create directory %s\n"),
+ Prog, user_home);
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding home directory",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_HOMEDIR);
+ }
+ chown (user_home, user_id, user_gid);
+@@ -1784,8 +1732,8 @@ static void create_home (void)
+ 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
+ home_added = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding home directory",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "add-home-dir",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif
+@@ -1951,12 +1899,6 @@ int main (int argc, char **argv)
+ */
+ if (getpwnam (user_name) != NULL) { /* local, no need for xgetpwnam */
+ fprintf (stderr, _("%s: user '%s' already exists\n"), Prog, user_name);
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_NAME_IN_USE);
+ }
+
+@@ -1972,12 +1914,6 @@ int main (int argc, char **argv)
+ fprintf (stderr,
+ _("%s: group %s exists - if you want to add this user to that group, use -g.\n"),
+ Prog, user_name);
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding group",
+- user_name, AUDIT_NO_ID,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_NAME_IN_USE);
+ }
+ }
+@@ -2007,12 +1943,6 @@ int main (int argc, char **argv)
+ fprintf (stderr,
+ _("%s: UID %lu is not unique\n"),
+ Prog, (unsigned long) user_id);
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding user",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif
+ fail_exit (E_UID_IN_USE);
+ }
+ }
+@@ -2057,9 +1987,10 @@ int main (int argc, char **argv)
+ _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
+ Prog, user_name, user_selinux);
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding SELinux user mapping",
+- user_name, (unsigned int) user_id, 0);
++ audit_logger (AUDIT_ROLE_ASSIGN, Prog,
++ "add-selinux-user-mapping",
++ user_name, (unsigned int) user_id,
++ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+ rv = E_SE_UPDATE;
+ }
+diff -urp shadow-4.1.5.1.orig/src/userdel.c shadow-4.1.5.1/src/userdel.c
+--- shadow-4.1.5.1.orig/src/userdel.c 2014-09-13 15:45:55.001829558 -0400
++++ shadow-4.1.5.1/src/userdel.c 2014-10-14 08:44:52.714850149 -0400
+@@ -201,9 +201,9 @@ static void update_groups (void)
+ * Update the DBM group file with the new entry as well.
+ */
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting user from group",
+- user_name, (unsigned int) user_id,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "deleting-user-from-group",
++ user_name, (unsigned int) user_id, ngrp->gr_name,
+ SHADOW_AUDIT_SUCCESS);
+ #endif /* WITH_AUDIT */
+ SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n",
+@@ -263,9 +263,9 @@ static void update_groups (void)
+ exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting user from shadow group",
+- user_name, (unsigned int) user_id,
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "deleting-user-from-shadow-group",
++ user_name, (unsigned int) user_id, nsgrp->sg_name,
+ SHADOW_AUDIT_SUCCESS);
+ #endif /* WITH_AUDIT */
+ SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n",
+@@ -342,9 +342,9 @@ static void remove_usergroup (void)
+ }
+
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_GROUP, Prog,
+- "deleting group",
+- user_name, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_DEL_GROUP, Prog,
++ "delete-group",
++ user_name, AUDIT_NO_ID, user_name,
+ SHADOW_AUDIT_SUCCESS);
+ #endif /* WITH_AUDIT */
+ SYSLOG ((LOG_INFO,
+@@ -360,9 +360,9 @@ static void remove_usergroup (void)
+ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_GROUP, Prog,
+- "deleting shadow group",
+- user_name, AUDIT_NO_ID,
++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog,
++ "delete-shadow-group",
++ user_name, AUDIT_NO_ID, user_name,
+ SHADOW_AUDIT_SUCCESS);
+ #endif /* WITH_AUDIT */
+ SYSLOG ((LOG_INFO,
+@@ -478,7 +478,7 @@ static void fail_exit (int code)
+
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting user",
++ "delete-user",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -498,24 +498,12 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, pw_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "locking password file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_PW_UPDATE);
+ }
+ pw_locked = true;
+ if (pw_open (O_RDWR) == 0) {
+ fprintf (stderr,
+ _("%s: cannot open %s\n"), Prog, pw_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "opening password file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_PW_UPDATE);
+ }
+ if (is_shadow_pwd) {
+@@ -523,12 +511,6 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, spw_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "locking shadow password file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_PW_UPDATE);
+ }
+ spw_locked = true;
+@@ -536,12 +518,6 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot open %s\n"),
+ Prog, spw_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "opening shadow password file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_PW_UPDATE);
+ }
+ }
+@@ -549,23 +525,11 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, gr_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "locking group file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_GRP_UPDATE);
+ }
+ gr_locked = true;
+ if (gr_open (O_RDWR) == 0) {
+ fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "opening group file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_GRP_UPDATE);
+ }
+ #ifdef SHADOWGRP
+@@ -574,24 +538,12 @@ static void open_files (void)
+ fprintf (stderr,
+ _("%s: cannot lock %s; try again later.\n"),
+ Prog, sgr_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "locking shadow group file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_GRP_UPDATE);
+ }
+ sgr_locked= true;
+ if (sgr_open (O_RDWR) == 0) {
+ fprintf (stderr, _("%s: cannot open %s\n"),
+ Prog, sgr_dbname ());
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "opening shadow group file",
+- user_name, (unsigned int) user_id,
+- SHADOW_AUDIT_FAILURE);
+-#endif /* WITH_AUDIT */
+ fail_exit (E_GRP_UPDATE);
+ }
+ }
+@@ -622,7 +574,7 @@ static void update_user (void)
+ }
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting user entries",
++ "delete-user",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_SUCCESS);
+ #endif /* WITH_AUDIT */
+@@ -716,7 +668,7 @@ static int remove_mailbox (void)
+ SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno)));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting mail file",
++ "delete-mail-file",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -732,7 +684,7 @@ static int remove_mailbox (void)
+ SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno)));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting mail file",
++ "delete-mail-file",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -742,8 +694,8 @@ static int remove_mailbox (void)
+ #ifdef WITH_AUDIT
+ else
+ {
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting mail file",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "delete-mail-file",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_SUCCESS);
+ }
+@@ -760,7 +712,7 @@ static int remove_mailbox (void)
+ mailfile, strerror (errno)));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting mail file",
++ "delete-mail-file",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -775,7 +727,7 @@ static int remove_mailbox (void)
+ SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno)));
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting mail file",
++ "delete-mail-file",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -785,8 +737,8 @@ static int remove_mailbox (void)
+ #ifdef WITH_AUDIT
+ else
+ {
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting mail file",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "delete-mail-file",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_SUCCESS);
+ }
+@@ -980,7 +932,7 @@ int main (int argc, char **argv)
+ Prog, user_name);
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting user not found",
++ "deleting-user-not-found",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -1024,7 +976,7 @@ int main (int argc, char **argv)
+ if (!fflg) {
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting user logged in",
++ "deleting-user-logged-in",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -1101,8 +1053,8 @@ int main (int argc, char **argv)
+ #ifdef WITH_AUDIT
+ else
+ {
+- audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting home directory",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "deleting-home-directory",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_SUCCESS);
+ }
+@@ -1111,7 +1063,7 @@ int main (int argc, char **argv)
+ #ifdef WITH_AUDIT
+ if (0 != errors) {
+ audit_logger (AUDIT_DEL_USER, Prog,
+- "deleting home directory",
++ "deleting-home-directory",
+ user_name, AUDIT_NO_ID,
+ SHADOW_AUDIT_FAILURE);
+ }
+@@ -1124,8 +1076,8 @@ int main (int argc, char **argv)
+ _("%s: warning: the user name %s to SELinux user mapping removal failed.\n"),
+ Prog, user_name);
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "removing SELinux user mapping",
++ audit_logger (AUDIT_ROLE_REMOVE, Prog,
++ "delete-selinux-user-mapping",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+diff -urp shadow-4.1.5.1.orig/src/usermod.c shadow-4.1.5.1/src/usermod.c
+--- shadow-4.1.5.1.orig/src/usermod.c 2014-09-13 15:45:55.013829557 -0400
++++ shadow-4.1.5.1/src/usermod.c 2014-10-14 08:50:05.817817855 -0400
+@@ -352,8 +352,8 @@ static char *new_pw_passwd (char *pw_pas
+
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "updating passwd",
+- user_newname, (unsigned int) user_newid, 0);
++ "updating-password",
++ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO, "lock user '%s' password", user_newname));
+ strcpy (buf, "!");
+@@ -372,8 +372,8 @@ static char *new_pw_passwd (char *pw_pas
+
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "updating password",
+- user_newname, (unsigned int) user_newid, 0);
++ "updating-password",
++ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO, "unlock user '%s' password", user_newname));
+ s = pw_pass;
+@@ -384,7 +384,7 @@ static char *new_pw_passwd (char *pw_pas
+ } else if (pflg) {
+ #ifdef WITH_AUDIT
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing password",
++ "updating-password",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO, "change user '%s' password", user_newname));
+@@ -413,8 +413,8 @@ static void new_pwent (struct passwd *pw
+ fail_exit (E_NAME_IN_USE);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing name",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-name",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -434,8 +434,8 @@ static void new_pwent (struct passwd *pw
+
+ if (uflg) {
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing uid",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-uid",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -445,8 +445,8 @@ static void new_pwent (struct passwd *pw
+ }
+ if (gflg) {
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing primary group",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-primary-group",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -456,8 +456,8 @@ static void new_pwent (struct passwd *pw
+ }
+ if (cflg) {
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing comment",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-comment",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ pwent->pw_gecos = user_newcomment;
+@@ -465,8 +465,8 @@ static void new_pwent (struct passwd *pw
+
+ if (dflg) {
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing home directory",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-home-dir",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -476,8 +476,8 @@ static void new_pwent (struct passwd *pw
+ }
+ if (sflg) {
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing user shell",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-shell",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -507,8 +507,8 @@ static void new_spent (struct spwd *spen
+
+ if (fflg) {
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing inactive days",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-inactive-days",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -524,8 +524,8 @@ static void new_spent (struct spwd *spen
+ date_to_str (old_exp, sizeof(old_exp),
+ user_expire * DAY);
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing expiration date",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "changing-expiration-date",
+ user_newname, (unsigned int) user_newid, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+@@ -592,9 +592,9 @@ static /*@noreturn@*/void fail_exit (int
+ }
+
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "modifying account",
+- user_name, AUDIT_NO_ID, 0);
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "modify-account",
++ user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE);
+ #endif
+ exit (code);
+ }
+@@ -648,9 +648,12 @@ static void update_group (void)
+ user_newname);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing group member",
+- user_newname, AUDIT_NO_ID, 1);
++ audit_logger_with_group (
++ AUDIT_USER_MGMT, Prog,
++ "update-member-in-group",
++ user_newname, AUDIT_NO_ID,
++ ngrp->gr_name,
++ SHADOW_AUDIT_SUCCESS);
+ #endif
+ SYSLOG ((LOG_INFO,
+ "change '%s' to '%s' in group '%s'",
+@@ -664,9 +667,11 @@ static void update_group (void)
+ ngrp->gr_mem = del_list (ngrp->gr_mem, user_name);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "removing group member",
+- user_name, AUDIT_NO_ID, 1);
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "delete-user-from-group",
++ user_name, AUDIT_NO_ID,
++ ngrp->gr_name,
++ SHADOW_AUDIT_SUCCESS);
+ #endif
+ SYSLOG ((LOG_INFO,
+ "delete '%s' from group '%s'",
+@@ -679,9 +684,11 @@ static void update_group (void)
+ ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "adding user to group",
+- user_name, AUDIT_NO_ID, 1);
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-user-to-group",
++ user_name, AUDIT_NO_ID,
++ ngrp->gr_name,
++ SHADOW_AUDIT_SUCCESS);
+ #endif
+ SYSLOG ((LOG_INFO, "add '%s' to group '%s'",
+ user_newname, ngrp->gr_name));
+@@ -756,9 +763,10 @@ static void update_gshadow (void)
+ nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing admin name in shadow group",
+- user_name, AUDIT_NO_ID, 1);
++ audit_logger_with_group (AUDIT_GRP_MGMT, Prog,
++ "update-admin-name-in-group",
++ user_name, AUDIT_NO_ID, nsgrp->sg_name,
++ SHADOW_AUDIT_SUCCESS);
+ #endif
+ SYSLOG ((LOG_INFO,
+ "change admin '%s' to '%s' in shadow group '%s'",
+@@ -778,9 +786,10 @@ static void update_gshadow (void)
+ user_newname);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing member in shadow group",
+- user_name, AUDIT_NO_ID, 1);
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "update-member-in-group",
++ user_name, AUDIT_NO_ID,
++ nsgrp->sg_name, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+ "change '%s' to '%s' in shadow group '%s'",
+@@ -794,9 +803,10 @@ static void update_gshadow (void)
+ nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "removing user from shadow group",
+- user_name, AUDIT_NO_ID, 1);
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "delete-user-from-group",
++ user_name, AUDIT_NO_ID,
++ nsgrp->sg_name, 1);
+ #endif
+ SYSLOG ((LOG_INFO,
+ "delete '%s' from shadow group '%s'",
+@@ -809,9 +819,10 @@ static void update_gshadow (void)
+ nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_newname);
+ changed = true;
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "adding user to shadow group",
+- user_newname, AUDIT_NO_ID, 1);
++ audit_logger_with_group (AUDIT_USER_MGMT, Prog,
++ "add-user-to-group",
++ user_newname, AUDIT_NO_ID,
++ nsgrp->sg_name, 1);
+ #endif
+ SYSLOG ((LOG_INFO, "add '%s' to shadow group '%s'",
+ user_newname, nsgrp->sg_name));
+@@ -1515,8 +1526,8 @@ static void move_home (void)
+
+ #ifdef WITH_AUDIT
+ if (uflg || gflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing home directory owner",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "updating-home-dir-owner",
+ user_newname, (unsigned int) user_newid, 1);
+ }
+ #endif
+@@ -1534,8 +1545,8 @@ static void move_home (void)
+ fail_exit (E_HOMEDIR);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "moving home directory",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "moving-home-dir",
+ user_newname, (unsigned int) user_newid,
+ 1);
+ #endif
+@@ -1554,9 +1565,9 @@ static void move_home (void)
+ Prog, user_home);
+ }
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK,
++ audit_logger (AUDIT_USER_MGMT,
+ Prog,
+- "moving home directory",
++ "moving-home-dir",
+ user_newname,
+ (unsigned int) user_newid,
+ 1);
+@@ -1760,8 +1771,8 @@ static void move_mailbox (void)
+ }
+ #ifdef WITH_AUDIT
+ else {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing mail file owner",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "updating-mail-file-owner",
+ user_newname, (unsigned int) user_newid, 1);
+ }
+ #endif
+@@ -1779,8 +1790,8 @@ static void move_mailbox (void)
+ }
+ #ifdef WITH_AUDIT
+ else {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing mail file name",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "updating-mail-file-name",
+ user_newname, (unsigned int) user_newid, 1);
+ }
+ #endif
+@@ -1910,8 +1921,8 @@ int main (int argc, char **argv)
+ _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
+ Prog, user_name, user_selinux);
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "modifying User mapping ",
++ audit_logger (AUDIT_ROLE_ASSIGN, Prog,
++ "changing-selinux-user-mapping ",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -1923,8 +1934,8 @@ int main (int argc, char **argv)
+ _("%s: warning: the user name %s to SELinux user mapping removal failed.\n"),
+ Prog, user_name);
+ #ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "removing SELinux user mapping",
++ audit_logger (AUDIT_ROLE_REMOVE, Prog,
++ "delete-selinux-user-mapping",
+ user_name, (unsigned int) user_id,
+ SHADOW_AUDIT_FAILURE);
+ #endif /* WITH_AUDIT */
+@@ -1962,8 +1973,8 @@ int main (int argc, char **argv)
+ */
+ #ifdef WITH_AUDIT
+ if (uflg || gflg) {
+- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+- "changing home directory owner",
++ audit_logger (AUDIT_USER_MGMT, Prog,
++ "updating-home-dir-owner",
+ user_newname, (unsigned int) user_newid, 1);
+ }
+ #endif
diff --git a/shadow-4.1.5.1-id-alloc.patch b/shadow-4.1.5.1-id-alloc.patch
new file mode 100644
index 0000000..df6f89f
--- /dev/null
+++ b/shadow-4.1.5.1-id-alloc.patch
@@ -0,0 +1,1219 @@
+Previously, this allocation was optimized for an outdated
+deployment style (that of /etc/group alongside nss_db). The issue
+here is that this results in extremely poor performance when using
+SSSD, Winbind or nss_ldap.
+
+There were actually three serious bugs here that have been addressed:
+
+1) Running getgrent() loops won't work in most SSSD or Winbind
+environments, as full group enumeration is disabled by default.
+This could easily result in auto-allocating a group that was
+already in use. (This might result in a security issue as well, if
+the shared GID is a privileged group).
+
+2) For system groups, the loop was always iterating through the
+complete SYS_GID_MIN->SYS_GID_MAX range. On SSSD and Winbind, this
+means hundreds of round-trips to LDAP (unless the GIDs were
+specifically configured to be ignored by the SSSD or winbindd).
+To a user with a slow connection to their LDAP server, this would
+appear as if groupadd -r was hung. (Though it would eventually
+complete).
+
+3) This patch also adds better error-handling for errno from
+getgrgid(), since if this function returns an unexpected error, we
+should not be treating it as "ID is available". This could result
+in assigning a GID that was already in use, with all the same
+issues as 1) above.
+
+This patch changes the algorithm to be more favorable for LDAP
+environments, at the expense of some performance when using nss_db.
+Given that the DB is a local service, this should have a negligible
+effect from a user's perspective.
+
+With the new algorithm, we simply first iterate through all entries
+in the local database with gr_next(), recording the IDs that are in
+use. We then start from the highest presumed-available entry and
+call getgrgid() to see if it is available. We continue this until
+we come to the first unused GID. We then select that and return it.
+
+If we make it through all the remaining IDs without finding a free
+one, we start over from the beginning of the range and try to find
+room in one of the gaps in the range.
+
+The patch was originally written by Stephen Gallagher and applied
+identically also to the user allocation by Tomáš Mráz.
+
+diff -up shadow-4.1.5.1/libmisc/find_new_gid.c.id-alloc shadow-4.1.5.1/libmisc/find_new_gid.c
+--- shadow-4.1.5.1/libmisc/find_new_gid.c.id-alloc 2014-09-10 10:25:41.165524986 +0200
++++ shadow-4.1.5.1/libmisc/find_new_gid.c 2014-09-10 10:25:41.195525677 +0200
+@@ -39,6 +39,118 @@
+ #include "getdef.h"
+
+ /*
++ * get_ranges - Get the minimum and maximum ID ranges for the search
++ *
++ * This function will return the minimum and maximum ranges for IDs
++ *
++ * 0: The function completed successfully
++ * EINVAL: The provided ranges are impossible (such as maximum < minimum)
++ *
++ * preferred_min: The special-case minimum value for a specifically-
++ * requested ID, which may be lower than the standard min_id
++ */
++static int get_ranges(bool sys_group, gid_t *min_id, gid_t *max_id,
++ gid_t *preferred_min)
++{
++ gid_t gid_def_max = 0;
++
++ if (sys_group) {
++ /* System groups */
++
++ /* A requested ID is allowed to be below the autoselect range */
++ *preferred_min = (gid_t) 1;
++
++ /* Get the minimum ID range from login.defs or default to 101 */
++ *min_id = (gid_t) getdef_ulong("SYS_GID_MIN", 101UL);
++
++ /*
++ * If SYS_GID_MAX is unspecified, we should assume it to be one
++ * less than the GID_MIN (which is reserved for non-system accounts)
++ */
++ gid_def_max = (gid_t) getdef_ulong("GID_MIN", 1000UL) - 1;
++ *max_id = (gid_t) getdef_ulong("SYS_GID_MAX",
++ (unsigned long) gid_def_max);
++
++ /* Check that the ranges make sense */
++ if (*max_id < *min_id) {
++ (void) fprintf (stderr,
++ _("%s: Invalid configuration: SYS_GID_MIN (%lu), "
++ "GID_MIN (%lu), SYS_GID_MAX (%lu)\n"),
++ Prog, (unsigned long) *min_id,
++ getdef_ulong ("GID_MIN", 1000UL),
++ (unsigned long) *max_id);
++ return EINVAL;
++ }
++ } else {
++ /* Non-system groups */
++
++ /* Get the values from login.defs or use reasonable defaults */
++ *min_id = (gid_t) getdef_ulong("GID_MIN", 1000UL);
++ *max_id = (gid_t) getdef_ulong("GID_MAX", 60000UL);
++
++ /*
++ * The preferred minimum should match the standard ID minimum
++ * for non-system groups.
++ */
++ *preferred_min = *min_id;
++
++ /* Check that the ranges make sense */
++ if (*max_id < *min_id) {
++ (void) fprintf(stderr,
++ _("%s: Invalid configuration: GID_MIN (%lu), "
++ "GID_MAX (%lu)\n"),
++ Prog, (unsigned long) *min_id,
++ (unsigned long) *max_id);
++ return EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * check_gid - See if the requested GID is available
++ *
++ * On success, return 0
++ * If the ID is in use, return EEXIST
++ * If the ID is outside the range, return ERANGE
++ * In other cases, return errno from getgrgid()
++ */
++static int check_gid(const gid_t gid,
++ const gid_t gid_min,
++ const gid_t gid_max,
++ bool *used_gids)
++{
++ /* First test that the preferred ID is in the range */
++ if (gid < gid_min || gid > gid_max) {
++ return ERANGE;
++ }
++
++ /*
++ * Check whether we already detected this GID
++ * using the gr_next() loop
++ */
++ if (used_gids != NULL && used_gids[gid]) {
++ return EEXIST;
++ }
++ /* Check if the GID exists according to NSS */
++ errno = 0;
++ if (getgrgid(gid) != NULL) {
++ return EEXIST;
++ } else {
++ /* getgrgid() was NULL, check whether this was
++ * due to an error, so we can report it.
++ */
++ /* ignore errors for now * if (errno != 0) {
++ return errno;
++ } */
++ }
++
++ /* If we've made it here, the GID must be available */
++ return 0;
++}
++
++/*
+ * find_new_gid - Find a new unused GID.
+ *
+ * If successful, find_new_gid provides an unused group ID in the
+@@ -48,166 +160,339 @@
+ *
+ * Return 0 on success, -1 if no unused GIDs are available.
+ */
+-int find_new_gid (bool sys_group,
+- gid_t *gid,
+- /*@null@*/gid_t const *preferred_gid)
++int find_new_gid(bool sys_group,
++ gid_t *gid,
++ /*@null@*/gid_t const *preferred_gid)
+ {
+- const struct group *grp;
+- gid_t gid_min, gid_max, group_id;
+ bool *used_gids;
++ const struct group *grp;
++ gid_t gid_min, gid_max, preferred_min;
++ gid_t group_id, id;
++ gid_t lowest_found, highest_found;
++ int result;
++ int nospam = 0;
+
+- assert (gid != NULL);
++ assert(gid != NULL);
+
+- if (!sys_group) {
+- gid_min = (gid_t) getdef_ulong ("GID_MIN", 1000UL);
+- gid_max = (gid_t) getdef_ulong ("GID_MAX", 60000UL);
+- if (gid_max < gid_min) {
+- (void) fprintf (stderr,
+- _("%s: Invalid configuration: GID_MIN (%lu), GID_MAX (%lu)\n"),
+- Prog, (unsigned long) gid_min, (unsigned long) gid_max);
+- return -1;
+- }
+- } else {
+- gid_min = (gid_t) 1;
+- gid_max = (gid_t) getdef_ulong ("GID_MIN", 1000UL) - 1;
+- gid_max = (gid_t) getdef_ulong ("SYS_GID_MAX", (unsigned long) gid_max);
+- if (gid_max < gid_min) {
+- (void) fprintf (stderr,
+- _("%s: Invalid configuration: SYS_GID_MIN (%lu), GID_MIN (%lu), SYS_GID_MAX (%lu)\n"),
+- Prog, (unsigned long) gid_min, getdef_ulong ("GID_MIN", 1000UL), (unsigned long) gid_max);
++ /*
++ * First, figure out what ID range is appropriate for
++ * automatic assignment
++ */
++ result = get_ranges(sys_group, &gid_min, &gid_max, &preferred_min);
++ if (result == EINVAL) {
++ return -1;
++ }
++
++ /* Check if the preferred GID is available */
++ if (preferred_gid) {
++ result = check_gid(*preferred_gid, preferred_min, gid_max, NULL);
++ if (result == 0) {
++ /*
++ * Make sure the GID isn't queued for use already
++ */
++ if (gr_locate_gid (*preferred_gid) == NULL) {
++ *gid = *preferred_gid;
++ return 0;
++ }
++ /*
++ * gr_locate_gid() found the GID in an as-yet uncommitted
++ * entry. We'll proceed below and auto-set a GID.
++ */
++ } else if (result == EEXIST || result == ERANGE) {
++ /*
++ * Continue on below. At this time, we won't
++ * treat these two cases differently.
++ */
++ } else {
++ /*
++ * An unexpected error occurred. We should report
++ * this and fail the group creation.
++ * This differs from the automatic creation
++ * behavior below, since if a specific GID was
++ * requested and generated an error, the user is
++ * more likely to want to stop and address the
++ * issue.
++ */
++ fprintf(stderr,
++ _("%s: Encountered error attempting to use "
++ "preferred GID: %s\n"),
++ Prog, strerror(result));
+ return -1;
+ }
+ }
++
++ /*
++ * Search the entire group file,
++ * looking for the next unused value.
++ *
++ * We first check the local database with gr_rewind/gr_next to find
++ * all local values that are in use.
++ *
++ * We then compare the next free value to all databases (local and
++ * remote) and iterate until we find a free one. If there are free
++ * values beyond the lowest (system groups) or highest (non-system
++ * groups), we will prefer those and avoid potentially reclaiming a
++ * deleted group (which can be a security issue, since it may grant
++ * access to files belonging to that former group).
++ *
++ * If there are no GIDs available at the end of the search, we will
++ * have no choice but to iterate through the range looking for gaps.
++ *
++ */
++
++ /* Create an array to hold all of the discovered GIDs */
+ used_gids = malloc (sizeof (bool) * (gid_max +1));
+ if (NULL == used_gids) {
+ fprintf (stderr,
+- _("%s: failed to allocate memory: %s\n"),
+- Prog, strerror (errno));
++ _("%s: failed to allocate memory: %s\n"),
++ Prog, strerror (errno));
+ return -1;
+ }
+ memset (used_gids, false, sizeof (bool) * (gid_max + 1));
+
+- if ( (NULL != preferred_gid)
+- && (*preferred_gid >= gid_min)
+- && (*preferred_gid <= gid_max)
+- /* Check if the user exists according to NSS */
+- && (getgrgid (*preferred_gid) == NULL)
+- /* Check also the local database in case of uncommitted
+- * changes */
+- && (gr_locate_gid (*preferred_gid) == NULL)) {
+- *gid = *preferred_gid;
+- free (used_gids);
+- return 0;
+- }
+-
+- /* if we did not find free preffered system gid, we start to look for
+- * one in the range assigned to dynamic system IDs */
+- if (sys_group)
+- gid_min = (gid_t) getdef_ulong ("SYS_GID_MIN", 101UL);
++ /* First look for the lowest and highest value in the local database */
++ (void) gr_rewind ();
++ highest_found = gid_min;
++ lowest_found = gid_max;
++ while ((grp = gr_next ()) != NULL) {
++ /*
++ * Does this entry have a lower GID than the lowest we've found
++ * so far?
++ */
++ if ((grp->gr_gid <= lowest_found) && (grp->gr_gid >= gid_min)) {
++ lowest_found = grp->gr_gid - 1;
++ }
++
++ /*
++ * Does this entry have a higher GID than the highest we've found
++ * so far?
++ */
++ if ((grp->gr_gid >= highest_found) && (grp->gr_gid <= gid_max)) {
++ highest_found = grp->gr_gid + 1;
++ }
++
++ /* create index of used GIDs */
++ if (grp->gr_gid >= gid_min
++ && grp->gr_gid <= gid_max) {
++
++ used_gids[grp->gr_gid] = true;
++ }
++ }
+
+- /*
+- * Search the entire group file,
+- * looking for the largest unused value.
+- *
+- * We check the list of groups according to NSS (setgrent/getgrent),
+- * but we also check the local database (gr_rewind/gr_next) in case
+- * some groups were created but the changes were not committed yet.
+- */
+ if (sys_group) {
+- gid_t id;
+- /* setgrent / getgrent / endgrent can be very slow with
+- * LDAP configurations (and many accounts).
+- * Since there is a limited amount of IDs to be tested
+- * for system accounts, we just check the existence
+- * of IDs with getgrgid.
+- */
+- group_id = gid_max;
+- for (id = gid_max; id >= gid_min; id--) {
+- if (getgrgid (id) != NULL) {
+- group_id = id - 1;
+- used_gids[id] = true;
+- }
++ /*
++ * For system groups, we want to start from the
++ * top of the range and work downwards.
++ */
++
++ /*
++ * At the conclusion of the gr_next() search, we will either
++ * have a presumed-free GID or we will be at GID_MIN - 1.
++ */
++ if (lowest_found < gid_min) {
++ /*
++ * In this case, a GID is in use at GID_MIN.
++ *
++ * We will reset the search to GID_MAX and proceed down
++ * through all the GIDs (skipping those we detected with
++ * used_gids) for a free one. It is a known issue that
++ * this may result in reusing a previously-deleted GID,
++ * so administrators should be instructed to use this
++ * auto-detection with care (and prefer to assign GIDs
++ * explicitly).
++ */
++ lowest_found = gid_max;
+ }
+
+- (void) gr_rewind ();
+- while ((grp = gr_next ()) != NULL) {
+- if ((grp->gr_gid <= group_id) && (grp->gr_gid >= gid_min)) {
+- group_id = grp->gr_gid - 1;
+- }
+- /* create index of used GIDs */
+- if (grp->gr_gid <= gid_max) {
+- used_gids[grp->gr_gid] = true;
++ /* Search through all of the IDs in the range */
++ for (id = lowest_found; id >= gid_min; id--) {
++ result = check_gid(id, gid_min, gid_max, used_gids);
++ if (result == 0) {
++ /* This GID is available. Return it. */
++ *gid = id;
++ free(used_gids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This GID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique system GID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available GIDs: %s",
++ strerror(result)));
++ nospam = 1;
++ }
++ /*
++ * We will continue anyway. Hopefully a later GID
++ * will work properly.
++ */
+ }
+ }
+- } else {
+- group_id = gid_min;
+- setgrent ();
+- while ((grp = getgrent ()) != NULL) {
+- if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
+- group_id = grp->gr_gid + 1;
+- }
+- /* create index of used GIDs */
+- if (grp->gr_gid <= gid_max) {
+- used_gids[grp->gr_gid] = true;
++
++ /*
++ * If we get all the way through the loop, try again from GID_MAX,
++ * unless that was where we previously started. (NOTE: the worst-case
++ * scenario here is that we will run through (GID_MAX - GID_MIN - 1)
++ * cycles *again* if we fall into this case with lowest_found as
++ * GID_MAX - 1, all groups in the range in use and maintained by
++ * network services such as LDAP.)
++ */
++ if (lowest_found != gid_max) {
++ for (id = gid_max; id >= gid_min; id--) {
++ result = check_gid(id, gid_min, gid_max, used_gids);
++ if (result == 0) {
++ /* This GID is available. Return it. */
++ *gid = id;
++ free(used_gids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This GID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique system GID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available GIDs: %s",
++ strerror(result)));
++ nospam = 1;
++ }
++ /*
++ * We will continue anyway. Hopefully a later GID
++ * will work properly.
++ */
++ }
+ }
+ }
+- endgrent ();
++ } else { /* !sys_group */
++ /*
++ * For non-system groups, we want to start from the
++ * bottom of the range and work upwards.
++ */
+
+- (void) gr_rewind ();
+- while ((grp = gr_next ()) != NULL) {
+- if ((grp->gr_gid >= group_id) && (grp->gr_gid <= gid_max)) {
+- group_id = grp->gr_gid + 1;
+- }
+- /* create index of used GIDs */
+- if (grp->gr_gid <= gid_max) {
+- used_gids[grp->gr_gid] = true;
+- }
++ /*
++ * At the conclusion of the gr_next() search, we will either
++ * have a presumed-free GID or we will be at GID_MAX + 1.
++ */
++ if (highest_found > gid_max) {
++ /*
++ * In this case, a GID is in use at GID_MAX.
++ *
++ * We will reset the search to GID_MIN and proceed up
++ * through all the GIDs (skipping those we detected with
++ * used_gids) for a free one. It is a known issue that
++ * this may result in reusing a previously-deleted GID,
++ * so administrators should be instructed to use this
++ * auto-detection with care (and prefer to assign GIDs
++ * explicitly).
++ */
++ highest_found = gid_min;
+ }
+- }
+
+- /*
+- * If a group (resp. system group) with GID equal to GID_MAX (resp.
+- * GID_MIN) exists, the above algorithm will give us GID_MAX+1
+- * (resp. GID_MIN-1) even if not unique. Search for the first free
+- * GID starting with GID_MIN (resp. GID_MAX).
+- */
+- if (sys_group) {
+- if (group_id < gid_min) {
+- for (group_id = gid_max; group_id >= gid_min; group_id--) {
+- if (false == used_gids[group_id]) {
+- break;
++ /* Search through all of the IDs in the range */
++ for (id = highest_found; id <= gid_max; id++) {
++ result = check_gid(id, gid_min, gid_max, used_gids);
++ if (result == 0) {
++ /* This GID is available. Return it. */
++ *gid = id;
++ free(used_gids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This GID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique GID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available GIDs: %s",
++ strerror(result)));
++ nospam = 1;
+ }
+- }
+- if (group_id < gid_min) {
+- fprintf (stderr,
+- _("%s: Can't get unique system GID (no more available GIDs)\n"),
+- Prog);
+- SYSLOG ((LOG_WARN,
+- "no more available GID on the system"));
+- free (used_gids);
+- return -1;
++ /*
++ * We will continue anyway. Hopefully a later GID
++ * will work properly.
++ */
+ }
+ }
+- } else {
+- if (group_id > gid_max) {
+- for (group_id = gid_min; group_id <= gid_max; group_id++) {
+- if (false == used_gids[group_id]) {
+- break;
++
++ /*
++ * If we get all the way through the loop, try again from GID_MIN,
++ * unless that was where we previously started. (NOTE: the worst-case
++ * scenario here is that we will run through (GID_MAX - GID_MIN - 1)
++ * cycles *again* if we fall into this case with highest_found as
++ * GID_MIN + 1, all groups in the range in use and maintained by
++ * network services such as LDAP.)
++ */
++ if (highest_found != gid_min) {
++ for (id = gid_min; id <= gid_max; id++) {
++ result = check_gid(id, gid_min, gid_max, used_gids);
++ if (result == 0) {
++ /* This GID is available. Return it. */
++ *gid = id;
++ free(used_gids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This GID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique GID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available GIDs: %s",
++ strerror(result)));
++ nospam = 1;
++ }
++ /*
++ * We will continue anyway. Hopefully a later GID
++ * will work properly.
++ */
+ }
+ }
+- if (group_id > gid_max) {
+- fprintf (stderr,
+- _("%s: Can't get unique GID (no more available GIDs)\n"),
+- Prog);
+- SYSLOG ((LOG_WARN, "no more available GID on the system"));
+- free (used_gids);
+- return -1;
+- }
+ }
+ }
+
+- free (used_gids);
+- *gid = group_id;
+- return 0;
++ /* The code reached here and found no available IDs in the range */
++ fprintf(stderr,
++ _("%s: Can't get unique GID (no more available GIDs)\n"),
++ Prog);
++ SYSLOG((LOG_WARN, "no more available GIDs on the system"));
++ free(used_gids);
++ return -1;
+ }
+
+diff -up shadow-4.1.5.1/libmisc/find_new_uid.c.id-alloc shadow-4.1.5.1/libmisc/find_new_uid.c
+--- shadow-4.1.5.1/libmisc/find_new_uid.c.id-alloc 2011-07-29 17:39:16.000000000 +0200
++++ shadow-4.1.5.1/libmisc/find_new_uid.c 2014-10-17 16:52:30.481217270 +0200
+@@ -39,6 +39,118 @@
+ #include "getdef.h"
+
+ /*
++ * get_ranges - Get the minimum and maximum ID ranges for the search
++ *
++ * This function will return the minimum and maximum ranges for IDs
++ *
++ * 0: The function completed successfully
++ * EINVAL: The provided ranges are impossible (such as maximum < minimum)
++ *
++ * preferred_min: The special-case minimum value for a specifically-
++ * requested ID, which may be lower than the standard min_id
++ */
++static int get_ranges(bool sys_user, uid_t *min_id, uid_t *max_id,
++ uid_t *preferred_min)
++{
++ uid_t uid_def_max = 0;
++
++ if (sys_user) {
++ /* System users */
++
++ /* A requested ID is allowed to be below the autoselect range */
++ *preferred_min = (uid_t) 1;
++
++ /* Get the minimum ID range from login.defs or default to 101 */
++ *min_id = (uid_t) getdef_ulong("SYS_UID_MIN", 101UL);
++
++ /*
++ * If SYS_UID_MAX is unspecified, we should assume it to be one
++ * less than the UID_MIN (which is reserved for non-system accounts)
++ */
++ uid_def_max = (uid_t) getdef_ulong("UID_MIN", 1000UL) - 1;
++ *max_id = (uid_t) getdef_ulong("SYS_UID_MAX",
++ (unsigned long) uid_def_max);
++
++ /* Check that the ranges make sense */
++ if (*max_id < *min_id) {
++ (void) fprintf (stderr,
++ _("%s: Invalid configuration: SYS_UID_MIN (%lu), "
++ "UID_MIN (%lu), SYS_UID_MAX (%lu)\n"),
++ Prog, (unsigned long) *min_id,
++ getdef_ulong ("UID_MIN", 1000UL),
++ (unsigned long) *max_id);
++ return EINVAL;
++ }
++ } else {
++ /* Non-system users */
++
++ /* Get the values from login.defs or use reasonable defaults */
++ *min_id = (uid_t) getdef_ulong("UID_MIN", 1000UL);
++ *max_id = (uid_t) getdef_ulong("UID_MAX", 60000UL);
++
++ /*
++ * The preferred minimum should match the standard ID minimum
++ * for non-system users.
++ */
++ *preferred_min = *min_id;
++
++ /* Check that the ranges make sense */
++ if (*max_id < *min_id) {
++ (void) fprintf(stderr,
++ _("%s: Invalid configuration: UID_MIN (%lu), "
++ "UID_MAX (%lu)\n"),
++ Prog, (unsigned long) *min_id,
++ (unsigned long) *max_id);
++ return EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * check_uid - See if the requested UID is available
++ *
++ * On success, return 0
++ * If the ID is in use, return EEXIST
++ * If the ID is outside the range, return ERANGE
++ * In other cases, return errno from getpwuid()
++ */
++static int check_uid(const uid_t uid,
++ const uid_t uid_min,
++ const uid_t uid_max,
++ bool *used_uids)
++{
++ /* First test that the preferred ID is in the range */
++ if (uid < uid_min || uid > uid_max) {
++ return ERANGE;
++ }
++
++ /*
++ * Check whether we already detected this UID
++ * using the pw_next() loop
++ */
++ if (used_uids != NULL && used_uids[uid]) {
++ return EEXIST;
++ }
++ /* Check if the UID exists according to NSS */
++ errno = 0;
++ if (getpwuid(uid) != NULL) {
++ return EEXIST;
++ } else {
++ /* getpwuid() was NULL, check whether this was
++ * due to an error, so we can report it.
++ */
++ /* ignore errors for now * if (errno != 0) {
++ return errno;
++ } */
++ }
++
++ /* If we've made it here, the UID must be available */
++ return 0;
++}
++
++/*
+ * find_new_uid - Find a new unused UID.
+ *
+ * If successful, find_new_uid provides an unused user ID in the
+@@ -48,162 +160,339 @@
+ *
+ * Return 0 on success, -1 if no unused UIDs are available.
+ */
+-int find_new_uid (bool sys_user,
+- uid_t *uid,
+- /*@null@*/uid_t const *preferred_uid)
++int find_new_uid(bool sys_user,
++ uid_t *uid,
++ /*@null@*/uid_t const *preferred_uid)
+ {
+- const struct passwd *pwd;
+- uid_t uid_min, uid_max, user_id;
+ bool *used_uids;
++ const struct passwd *pwd;
++ uid_t uid_min, uid_max, preferred_min;
++ uid_t user_id, id;
++ uid_t lowest_found, highest_found;
++ int result;
++ int nospam = 0;
+
+ assert (uid != NULL);
+
+- if (!sys_user) {
+- uid_min = (uid_t) getdef_ulong ("UID_MIN", 1000UL);
+- uid_max = (uid_t) getdef_ulong ("UID_MAX", 60000UL);
+- if (uid_max < uid_min) {
+- (void) fprintf (stderr,
+- _("%s: Invalid configuration: UID_MIN (%lu), UID_MAX (%lu)\n"),
+- Prog, (unsigned long) uid_min, (unsigned long) uid_max);
+- return -1;
+- }
+- } else {
+- uid_min = (uid_t) getdef_ulong ("SYS_UID_MIN", 101UL);
+- uid_max = (uid_t) getdef_ulong ("UID_MIN", 1000UL) - 1;
+- uid_max = (uid_t) getdef_ulong ("SYS_UID_MAX", (unsigned long) uid_max);
+- if (uid_max < uid_min) {
+- (void) fprintf (stderr,
+- _("%s: Invalid configuration: SYS_UID_MIN (%lu), UID_MIN (%lu), SYS_UID_MAX (%lu)\n"),
+- Prog, (unsigned long) uid_min, getdef_ulong ("UID_MIN", 1000UL), (unsigned long) uid_max);
++ /*
++ * First, figure out what ID range is appropriate for
++ * automatic assignment
++ */
++ result = get_ranges(sys_user, &uid_min, &uid_max, &preferred_min);
++ if (result == EINVAL) {
++ return -1;
++ }
++
++ /* Check if the preferred UID is available */
++ if (preferred_uid) {
++ result = check_uid(*preferred_uid, preferred_min, uid_max, NULL);
++ if (result == 0) {
++ /*
++ * Make sure the UID isn't queued for use already
++ */
++ if (pw_locate_uid (*preferred_uid) == NULL) {
++ *uid = *preferred_uid;
++ return 0;
++ }
++ /*
++ * pw_locate_uid() found the UID in an as-yet uncommitted
++ * entry. We'll proceed below and auto-set an UID.
++ */
++ } else if (result == EEXIST || result == ERANGE) {
++ /*
++ * Continue on below. At this time, we won't
++ * treat these two cases differently.
++ */
++ } else {
++ /*
++ * An unexpected error occurred. We should report
++ * this and fail the user creation.
++ * This differs from the automatic creation
++ * behavior below, since if a specific UID was
++ * requested and generated an error, the user is
++ * more likely to want to stop and address the
++ * issue.
++ */
++ fprintf(stderr,
++ _("%s: Encountered error attempting to use "
++ "preferred UID: %s\n"),
++ Prog, strerror(result));
+ return -1;
+ }
+ }
++
++ /*
++ * Search the entire passwd file,
++ * looking for the next unused value.
++ *
++ * We first check the local database with pw_rewind/pw_next to find
++ * all local values that are in use.
++ *
++ * We then compare the next free value to all databases (local and
++ * remote) and iterate until we find a free one. If there are free
++ * values beyond the lowest (system users) or highest (non-system
++ * users), we will prefer those and avoid potentially reclaiming a
++ * deleted user (which can be a security issue, since it may grant
++ * access to files belonging to that former user).
++ *
++ * If there are no UIDs available at the end of the search, we will
++ * have no choice but to iterate through the range looking for gaps.
++ *
++ */
++
++ /* Create an array to hold all of the discovered UIDs */
+ used_uids = malloc (sizeof (bool) * (uid_max +1));
+ if (NULL == used_uids) {
+ fprintf (stderr,
+- _("%s: failed to allocate memory: %s\n"),
+- Prog, strerror (errno));
++ _("%s: failed to allocate memory: %s\n"),
++ Prog, strerror (errno));
+ return -1;
+ }
+ memset (used_uids, false, sizeof (bool) * (uid_max + 1));
+
+- if ( (NULL != preferred_uid)
+- && (*preferred_uid >= uid_min)
+- && (*preferred_uid <= uid_max)
+- /* Check if the user exists according to NSS */
+- && (getpwuid (*preferred_uid) == NULL)
+- /* Check also the local database in case of uncommitted
+- * changes */
+- && (pw_locate_uid (*preferred_uid) == NULL)) {
+- *uid = *preferred_uid;
+- free (used_uids);
+- return 0;
+- }
++ /* First look for the lowest and highest value in the local database */
++ (void) pw_rewind ();
++ highest_found = uid_min;
++ lowest_found = uid_max;
++ while ((pwd = pw_next ()) != NULL) {
++ /*
++ * Does this entry have a lower UID than the lowest we've found
++ * so far?
++ */
++ if ((pwd->pw_uid <= lowest_found) && (pwd->pw_uid >= uid_min)) {
++ lowest_found = pwd->pw_uid - 1;
++ }
+
++ /*
++ * Does this entry have a higher UID than the highest we've found
++ * so far?
++ */
++ if ((pwd->pw_uid >= highest_found) && (pwd->pw_uid <= uid_max)) {
++ highest_found = pwd->pw_uid + 1;
++ }
++
++ /* create index of used UIDs */
++ if (pwd->pw_uid >= uid_min
++ && pwd->pw_uid <= uid_max) {
++
++ used_uids[pwd->pw_uid] = true;
++ }
++ }
+
+- /*
+- * Search the entire password file,
+- * looking for the largest unused value.
+- *
+- * We check the list of users according to NSS (setpwent/getpwent),
+- * but we also check the local database (pw_rewind/pw_next) in case
+- * some users were created but the changes were not committed yet.
+- */
+ if (sys_user) {
+- uid_t id;
+- /* setpwent / getpwent / endpwent can be very slow with
+- * LDAP configurations (and many accounts).
+- * Since there is a limited amount of IDs to be tested
+- * for system accounts, we just check the existence
+- * of IDs with getpwuid.
+- */
+- user_id = uid_max;
+- for (id = uid_max; id >= uid_min; id--) {
+- if (getpwuid (id) != NULL) {
+- user_id = id - 1;
+- used_uids[id] = true;
+- }
++ /*
++ * For system users, we want to start from the
++ * top of the range and work downwards.
++ */
++
++ /*
++ * At the conclusion of the pw_next() search, we will either
++ * have a presumed-free UID or we will be at UID_MIN - 1.
++ */
++ if (lowest_found < uid_min) {
++ /*
++ * In this case, an UID is in use at UID_MIN.
++ *
++ * We will reset the search to UID_MAX and proceed down
++ * through all the UIDs (skipping those we detected with
++ * used_uids) for a free one. It is a known issue that
++ * this may result in reusing a previously-deleted UID,
++ * so administrators should be instructed to use this
++ * auto-detection with care (and prefer to assign UIDs
++ * explicitly).
++ */
++ lowest_found = uid_max;
+ }
+
+- (void) pw_rewind ();
+- while ((pwd = pw_next ()) != NULL) {
+- if ((pwd->pw_uid <= user_id) && (pwd->pw_uid >= uid_min)) {
+- user_id = pwd->pw_uid - 1;
+- }
+- /* create index of used UIDs */
+- if (pwd->pw_uid <= uid_max) {
+- used_uids[pwd->pw_uid] = true;
++ /* Search through all of the IDs in the range */
++ for (id = lowest_found; id >= uid_min; id--) {
++ result = check_uid(id, uid_min, uid_max, used_uids);
++ if (result == 0) {
++ /* This UID is available. Return it. */
++ *uid = id;
++ free(used_uids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This UID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique system UID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available UIDs: %s",
++ strerror(result)));
++ nospam = 1;
++ }
++ /*
++ * We will continue anyway. Hopefully a later UID
++ * will work properly.
++ */
+ }
+ }
+- } else {
+- user_id = uid_min;
+- setpwent ();
+- while ((pwd = getpwent ()) != NULL) {
+- if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
+- user_id = pwd->pw_uid + 1;
+- }
+- /* create index of used UIDs */
+- if (pwd->pw_uid <= uid_max) {
+- used_uids[pwd->pw_uid] = true;
++
++ /*
++ * If we get all the way through the loop, try again from UID_MAX,
++ * unless that was where we previously started. (NOTE: the worst-case
++ * scenario here is that we will run through (UID_MAX - UID_MIN - 1)
++ * cycles *again* if we fall into this case with lowest_found as
++ * UID_MAX - 1, all users in the range in use and maintained by
++ * network services such as LDAP.)
++ */
++ if (lowest_found != uid_max) {
++ for (id = uid_max; id >= uid_min; id--) {
++ result = check_uid(id, uid_min, uid_max, used_uids);
++ if (result == 0) {
++ /* This UID is available. Return it. */
++ *uid = id;
++ free(used_uids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This UID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique system UID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available UIDs: %s",
++ strerror(result)));
++ nospam = 1;
++ }
++ /*
++ * We will continue anyway. Hopefully a later UID
++ * will work properly.
++ */
++ }
+ }
+ }
+- endpwent ();
++ } else { /* !sys_user */
++ /*
++ * For non-system users, we want to start from the
++ * bottom of the range and work upwards.
++ */
+
+- (void) pw_rewind ();
+- while ((pwd = pw_next ()) != NULL) {
+- if ((pwd->pw_uid >= user_id) && (pwd->pw_uid <= uid_max)) {
+- user_id = pwd->pw_uid + 1;
+- }
+- /* create index of used UIDs */
+- if (pwd->pw_uid <= uid_max) {
+- used_uids[pwd->pw_uid] = true;
+- }
++ /*
++ * At the conclusion of the pw_next() search, we will either
++ * have a presumed-free UID or we will be at UID_MAX + 1.
++ */
++ if (highest_found > uid_max) {
++ /*
++ * In this case, a UID is in use at UID_MAX.
++ *
++ * We will reset the search to UID_MIN and proceed up
++ * through all the UIDs (skipping those we detected with
++ * used_uids) for a free one. It is a known issue that
++ * this may result in reusing a previously-deleted UID,
++ * so administrators should be instructed to use this
++ * auto-detection with care (and prefer to assign UIDs
++ * explicitly).
++ */
++ highest_found = uid_min;
+ }
+- }
+
+- /*
+- * If a user (resp. system user) with UID equal to UID_MAX (resp.
+- * UID_MIN) exists, the above algorithm will give us UID_MAX+1
+- * (resp. UID_MIN-1) even if not unique. Search for the first free
+- * UID starting with UID_MIN (resp. UID_MAX).
+- */
+- if (sys_user) {
+- if (user_id < uid_min) {
+- for (user_id = uid_max; user_id >= uid_min; user_id--) {
+- if (false == used_uids[user_id]) {
+- break;
++ /* Search through all of the IDs in the range */
++ for (id = highest_found; id <= uid_max; id++) {
++ result = check_uid(id, uid_min, uid_max, used_uids);
++ if (result == 0) {
++ /* This UID is available. Return it. */
++ *uid = id;
++ free(used_uids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This UID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique UID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available UIDs: %s",
++ strerror(result)));
++ nospam = 1;
+ }
+- }
+- if (user_id < uid_min ) {
+- fprintf (stderr,
+- _("%s: Can't get unique system UID (no more available UIDs)\n"),
+- Prog);
+- SYSLOG ((LOG_WARN,
+- "no more available UID on the system"));
+- free (used_uids);
+- return -1;
++ /*
++ * We will continue anyway. Hopefully a later UID
++ * will work properly.
++ */
+ }
+ }
+- } else {
+- if (user_id > uid_max) {
+- for (user_id = uid_min; user_id <= uid_max; user_id++) {
+- if (false == used_uids[user_id]) {
+- break;
++
++ /*
++ * If we get all the way through the loop, try again from UID_MIN,
++ * unless that was where we previously started. (NOTE: the worst-case
++ * scenario here is that we will run through (UID_MAX - UID_MIN - 1)
++ * cycles *again* if we fall into this case with highest_found as
++ * UID_MIN + 1, all users in the range in use and maintained by
++ * network services such as LDAP.)
++ */
++ if (highest_found != uid_min) {
++ for (id = uid_min; id <= uid_max; id++) {
++ result = check_uid(id, uid_min, uid_max, used_uids);
++ if (result == 0) {
++ /* This UID is available. Return it. */
++ *uid = id;
++ free(used_uids);
++ return 0;
++ } else if (result == EEXIST) {
++ /* This UID is in use, we'll continue to the next */
++ } else {
++ /*
++ * An unexpected error occurred.
++ *
++ * Only report it the first time to avoid spamming
++ * the logs
++ *
++ */
++ if (!nospam) {
++ fprintf(stderr,
++ _("%s: Can't get unique UID (%s). "
++ "Suppressing additional messages.\n"),
++ Prog, strerror(result));
++ SYSLOG((LOG_ERR,
++ "Error checking available UIDs: %s",
++ strerror(result)));
++ nospam = 1;
++ }
++ /*
++ * We will continue anyway. Hopefully a later UID
++ * will work properly.
++ */
+ }
+ }
+- if (user_id > uid_max) {
+- fprintf (stderr,
+- _("%s: Can't get unique UID (no more available UIDs)\n"),
+- Prog);
+- SYSLOG ((LOG_WARN, "no more available UID on the system"));
+- free (used_uids);
+- return -1;
+- }
+ }
+ }
+
+- free (used_uids);
+- *uid = user_id;
+- return 0;
++ /* The code reached here and found no available IDs in the range */
++ fprintf(stderr,
++ _("%s: Can't get unique UID (no more available UIDs)\n"),
++ Prog);
++ SYSLOG((LOG_WARN, "no more available UIDs on the system"));
++ free(used_uids);
++ return -1;
+ }
+
diff --git a/shadow-utils.spec b/shadow-utils.spec
index e3d6b90..f1edde1 100644
--- a/shadow-utils.spec
+++ b/shadow-utils.spec
@@ -1,7 +1,7 @@
Summary: Utilities for managing accounts and shadow password files
Name: shadow-utils
Version: 4.1.5.1
-Release: 20%{?dist}
+Release: 21%{?dist}
Epoch: 2
URL: http://pkg-shadow.alioth.debian.org/
Source0: http://pkg-shadow.alioth.debian.org/releases/shadow-%{version}.tar.bz2
@@ -26,10 +26,11 @@ Patch14: shadow-4.1.5.1-default-range.patch
Patch15: shadow-4.1.5.1-manfix.patch
Patch16: shadow-4.1.5.1-crypt-null.patch
Patch17: shadow-4.1.5.1-userdel-helpfix.patch
-Patch18: shadow-4.1.5.1-group-alloc.patch
+Patch18: shadow-4.1.5.1-id-alloc.patch
Patch19: shadow-4.1.5.1-date-parsing.patch
Patch20: shadow-4.1.5.1-ingroup.patch
Patch21: shadow-4.1.5.1-move-home.patch
+Patch22: shadow-4.1.5.1-audit-update.patch
License: BSD and GPLv2+
Group: System Environment/Base
@@ -75,10 +76,11 @@ are used for managing group accounts.
%patch15 -p1 -b .manfix
%patch16 -p1 -b .crypt-null
%patch17 -p1 -b .userdel
-%patch18 -p1 -b .group-alloc
+%patch18 -p1 -b .id-alloc
%patch19 -p1 -b .date-parsing
%patch20 -p1 -b .ingroup
%patch21 -p1 -b .move-home
+%patch22 -p1 -b .audit-update
iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8
cp -f doc/HOWTO.utf8 doc/HOWTO
@@ -236,6 +238,11 @@ rm -rf $RPM_BUILD_ROOT
%{_mandir}/man8/vigr.8*
%changelog
+* Fri Oct 17 2014 Tomáš Mráz <tmraz at redhat.com> - 2:4.1.5.1-21
+- update auditing to cover more events and fix some incorrect audit
+ records - patch by Steve Grubb (#1151580)
+- apply the same new allocation algorithm to uids as for gids
+
* Wed Sep 10 2014 Tomas Mraz <tmraz at redhat.com> - 2:4.1.5.1-20
- discard obsolete matchpathcon cache after semanage_commit()
More information about the scm-commits
mailing list