diff --git a/SOURCES/shadow-4.1.5-2ndskip.patch b/SOURCES/shadow-4.1.5-2ndskip.patch new file mode 100644 index 00000000..8a9cf68a --- /dev/null +++ b/SOURCES/shadow-4.1.5-2ndskip.patch @@ -0,0 +1,100 @@ +diff -up shadow-4.1.5/src/grpconv.c.2ndskip shadow-4.1.5/src/grpconv.c +--- shadow-4.1.5/src/grpconv.c.2ndskip 2012-06-18 13:08:34.438910815 +0200 ++++ shadow-4.1.5/src/grpconv.c 2012-06-18 13:12:51.270764552 +0200 +@@ -143,6 +143,7 @@ int main (int argc, char **argv) + struct group grent; + const struct sgrp *sg; + struct sgrp sgent; ++ char *np; + + Prog = Basename (argv[0]); + +@@ -184,20 +185,25 @@ int main (int argc, char **argv) + * Remove /etc/gshadow entries for groups not in /etc/group. + */ + (void) sgr_rewind (); +- while ((sg = sgr_next ()) != NULL) { +- if (gr_locate (sg->sg_name) != NULL) { +- continue; +- } +- +- if (sgr_remove (sg->sg_name) == 0) { +- /* +- * This shouldn't happen (the entry exists) but... +- */ +- fprintf (stderr, +- _("%s: cannot remove entry '%s' from %s\n"), +- Prog, sg->sg_name, sgr_dbname ()); +- fail_exit (3); ++ sg = sgr_next (); ++ np=NULL; ++ while (sg != NULL) { ++ np = strdup(sg->sg_name); ++ sg = sgr_next (); ++ ++ if(gr_locate (np) == NULL) { ++ if (sgr_remove (np) == 0) { ++ /* ++ * This shouldn't happen (the entry exists) but... ++ */ ++ fprintf (stderr, ++ _("%s: cannot remove entry '%s' from %s\n"), ++ Prog, np, sgr_dbname ()); ++ free(np); ++ fail_exit (3); ++ } + } ++ free(np); + } + + /* +diff -up shadow-4.1.5/src/pwconv.c.2ndskip shadow-4.1.5/src/pwconv.c +--- shadow-4.1.5/src/pwconv.c.2ndskip 2012-06-18 11:23:33.938511797 +0200 ++++ shadow-4.1.5/src/pwconv.c 2012-06-18 12:57:18.396426194 +0200 +@@ -173,6 +173,7 @@ int main (int argc, char **argv) + struct passwd pwent; + const struct spwd *sp; + struct spwd spent; ++ char *np; + + Prog = Basename (argv[0]); + +@@ -223,20 +224,25 @@ int main (int argc, char **argv) + * Remove /etc/shadow entries for users not in /etc/passwd. + */ + (void) spw_rewind (); +- while ((sp = spw_next ()) != NULL) { +- if (pw_locate (sp->sp_namp) != NULL) { +- continue; +- } +- +- if (spw_remove (sp->sp_namp) == 0) { +- /* +- * This shouldn't happen (the entry exists) but... +- */ +- fprintf (stderr, +- _("%s: cannot remove entry '%s' from %s\n"), +- Prog, sp->sp_namp, spw_dbname ()); +- fail_exit (E_FAILURE); ++ sp = spw_next (); ++ np = NULL; ++ while (sp != NULL) { ++ np = strdup(sp->sp_namp); ++ sp = spw_next (); ++ ++ if (pw_locate (np) == NULL) { ++ if (spw_remove (np) == 0) { ++ /* ++ * This shouldn't happen (the entry exists) but... ++ */ ++ fprintf (stderr, ++ _("%s: cannot remove entry '%s' from %s\n"), ++ Prog, np, spw_dbname ()); ++ free(np); ++ fail_exit (E_FAILURE); ++ } + } ++ free(np); + } + + /* diff --git a/SOURCES/shadow-4.1.5-redhat.patch b/SOURCES/shadow-4.1.5-redhat.patch new file mode 100644 index 00000000..a785b299 --- /dev/null +++ b/SOURCES/shadow-4.1.5-redhat.patch @@ -0,0 +1,42 @@ +diff -up shadow-4.1.5/man/useradd.8.redhat shadow-4.1.5/man/useradd.8 +diff -up shadow-4.1.5/src/useradd.c.redhat shadow-4.1.5/src/useradd.c +--- shadow-4.1.5/src/useradd.c.redhat 2011-12-09 23:23:15.000000000 +0100 ++++ shadow-4.1.5/src/useradd.c 2012-03-19 09:50:05.227588669 +0100 +@@ -93,7 +93,7 @@ const char *Prog; + static gid_t def_group = 100; + static const char *def_gname = "other"; + static const char *def_home = "/home"; +-static const char *def_shell = ""; ++static const char *def_shell = "/sbin/nologin"; + static const char *def_template = SKEL_DIR; + static const char *def_create_mail_spool = "no"; + +@@ -103,7 +103,7 @@ static const char *def_expire = ""; + #define VALID(s) (strcspn (s, ":\n") == strlen (s)) + + static const char *user_name = ""; +-static const char *user_pass = "!"; ++static const char *user_pass = "!!"; + static uid_t user_id; + static gid_t user_gid; + static const char *user_comment = ""; +@@ -1011,9 +1011,9 @@ static void process_flags (int argc, cha + }; + while ((c = getopt_long (argc, argv, + #ifdef WITH_SELINUX +- "b:c:d:De:f:g:G:hk:K:lmMNop:rR:s:u:UZ:", ++ "b:c:d:De:f:g:G:hk:K:lmMnNop:rR:s:u:UZ:", + #else /* !WITH_SELINUX */ +- "b:c:d:De:f:g:G:hk:K:lmMNop:rR:s:u:U", ++ "b:c:d:De:f:g:G:hk:K:lmMnNop:rR:s:u:U", + #endif /* !WITH_SELINUX */ + long_options, NULL)) != -1) { + switch (c) { +@@ -1164,6 +1164,7 @@ static void process_flags (int argc, cha + case 'M': + Mflg = true; + break; ++ case 'n': + case 'N': + Nflg = true; + break; diff --git a/SOURCES/shadow-4.1.5-uflg.patch b/SOURCES/shadow-4.1.5-uflg.patch new file mode 100644 index 00000000..f72bca3a --- /dev/null +++ b/SOURCES/shadow-4.1.5-uflg.patch @@ -0,0 +1,23 @@ +diff -up shadow-4.1.5/libmisc/find_new_gid.c.uflg shadow-4.1.5/libmisc/find_new_gid.c +--- shadow-4.1.5/libmisc/find_new_gid.c.uflg 2011-07-30 01:10:27.000000000 +0200 ++++ shadow-4.1.5/libmisc/find_new_gid.c 2012-03-19 12:51:46.090554116 +0100 +@@ -68,7 +68,7 @@ int find_new_gid (bool sys_group, + return -1; + } + } else { +- gid_min = (gid_t) getdef_ulong ("SYS_GID_MIN", 101UL); ++ 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) { +@@ -100,6 +100,10 @@ int find_new_gid (bool sys_group, + 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); + + /* + * Search the entire group file, diff --git a/SOURCES/shadow-4.1.5.1-audit-owner.patch b/SOURCES/shadow-4.1.5.1-audit-owner.patch new file mode 100644 index 00000000..6fbbdbf7 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-audit-owner.patch @@ -0,0 +1,32 @@ +diff -up shadow-4.1.5.1/src/usermod.c.audit shadow-4.1.5.1/src/usermod.c +--- shadow-4.1.5.1/src/usermod.c.audit 2011-11-21 23:02:16.000000000 +0100 ++++ shadow-4.1.5.1/src/usermod.c 2013-06-14 14:54:20.237026550 +0200 +@@ -1513,6 +1513,14 @@ static void move_home (void) + fail_exit (E_HOMEDIR); + } + ++#ifdef WITH_AUDIT ++ if (uflg || gflg) { ++ audit_logger (AUDIT_USER_CHAUTHTOK, Prog, ++ "changing home directory owner", ++ user_newname, (unsigned int) user_newid, 1); ++ } ++#endif ++ + if (rename (user_home, user_newhome) == 0) { + /* FIXME: rename above may have broken symlinks + * pointing to the user's home directory +@@ -1947,6 +1955,13 @@ int main (int argc, char **argv) + * ownership. + * + */ ++#ifdef WITH_AUDIT ++ if (uflg || gflg) { ++ audit_logger (AUDIT_USER_CHAUTHTOK, Prog, ++ "changing home directory owner", ++ user_newname, (unsigned int) user_newid, 1); ++ } ++#endif + if (chown_tree (dflg ? user_newhome : user_home, + user_id, + uflg ? user_newid : (uid_t)-1, diff --git a/SOURCES/shadow-4.1.5.1-audit-update.patch b/SOURCES/shadow-4.1.5.1-audit-update.patch new file mode 100644 index 00000000..17930bfc --- /dev/null +++ b/SOURCES/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", (unsigned long)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", (unsigned long)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-shadow-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-shadow-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-shadow-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-shadow-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/SOURCES/shadow-4.1.5.1-backup-mode.patch b/SOURCES/shadow-4.1.5.1-backup-mode.patch new file mode 100644 index 00000000..7366b86e --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-backup-mode.patch @@ -0,0 +1,20 @@ +diff -up shadow-4.1.5.1/lib/commonio.c.backup-mode shadow-4.1.5.1/lib/commonio.c +--- shadow-4.1.5.1/lib/commonio.c.backup-mode 2012-05-18 21:44:54.000000000 +0200 ++++ shadow-4.1.5.1/lib/commonio.c 2012-09-19 20:27:16.089444234 +0200 +@@ -301,15 +301,12 @@ static int create_backup (const char *ba + struct utimbuf ub; + FILE *bkfp; + int c; +- mode_t mask; + + if (fstat (fileno (fp), &sb) != 0) { + return -1; + } + +- mask = umask (077); +- bkfp = fopen (backup, "w"); +- (void) umask (mask); ++ bkfp = fopen_set_perms (backup, "w", &sb); + if (NULL == bkfp) { + return -1; + } diff --git a/SOURCES/shadow-4.1.5.1-chgrp-guard.patch b/SOURCES/shadow-4.1.5.1-chgrp-guard.patch new file mode 100644 index 00000000..220884c5 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-chgrp-guard.patch @@ -0,0 +1,44 @@ +diff -up shadow-4.1.5.1/man/usermod.8.xml.chgrp-guard shadow-4.1.5.1/man/usermod.8.xml +--- shadow-4.1.5.1/man/usermod.8.xml.chgrp-guard 2016-05-04 13:44:17.267917583 +0200 ++++ shadow-4.1.5.1/man/usermod.8.xml 2016-05-04 13:44:17.284917968 +0200 +@@ -198,6 +198,12 @@ + The group ownership of files outside of the user's home directory + must be fixed manually. + ++ ++ The change of the group ownership of files inside of the user's ++ home directory is also not done if the home dir owner uid is ++ different from the current or new user id. This is safety measure ++ for special home directories such as /. ++ + + + +@@ -364,6 +370,12 @@ + must be fixed manually. + + ++ The change of the user ownership of files inside of the user's ++ home directory is also not done if the home dir owner uid is ++ different from the current or new user id. This is safety measure ++ for special home directories such as /. ++ ++ + No checks will be performed with regard to the + , , + , or +diff -up shadow-4.1.5.1/src/usermod.c.chgrp-guard shadow-4.1.5.1/src/usermod.c +--- shadow-4.1.5.1/src/usermod.c.chgrp-guard 2016-05-04 13:44:17.280917877 +0200 ++++ shadow-4.1.5.1/src/usermod.c 2016-05-04 13:44:17.285917991 +0200 +@@ -1971,7 +1971,10 @@ int main (int argc, char **argv) + } + + if (!mflg && (uflg || gflg)) { +- if (access (dflg ? user_newhome : user_home, F_OK) == 0) { ++ struct stat sb; ++ ++ if (stat (dflg ? user_newhome : user_home, &sb) == 0 && ++ ((uflg && sb.st_uid == user_newid) || sb.st_uid == user_id)) { + /* + * Change the UID on all of the files owned by + * `user_id' to `user_newid' in the user's home diff --git a/SOURCES/shadow-4.1.5.1-crypt-null.patch b/SOURCES/shadow-4.1.5.1-crypt-null.patch new file mode 100644 index 00000000..fba72e77 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-crypt-null.patch @@ -0,0 +1,195 @@ +diff -up shadow-4.1.5.1/lib/encrypt.c.crypt-null shadow-4.1.5.1/lib/encrypt.c +--- shadow-4.1.5.1/lib/encrypt.c.crypt-null 2010-08-22 15:05:02.000000000 +0200 ++++ shadow-4.1.5.1/lib/encrypt.c 2013-07-25 12:27:30.438355782 +0200 +@@ -49,11 +49,10 @@ + if (!cp) { + /* + * Single Unix Spec: crypt() may return a null pointer, +- * and set errno to indicate an error. The caller doesn't +- * expect us to return NULL, so... ++ * and set errno to indicate an error. In this case return ++ * the NULL so the caller can handle appropriately. + */ +- perror ("crypt"); +- exit (EXIT_FAILURE); ++ return cp; + } + + /* The GNU crypt does not return NULL if the algorithm is not +diff -up shadow-4.1.5.1/libmisc/valid.c.crypt-null shadow-4.1.5.1/libmisc/valid.c +--- shadow-4.1.5.1/libmisc/valid.c.crypt-null 2010-08-22 21:14:41.000000000 +0200 ++++ shadow-4.1.5.1/libmisc/valid.c 2013-07-25 12:27:30.440355847 +0200 +@@ -95,6 +95,7 @@ bool valid (const char *password, const + */ + + if ( (NULL != ent->pw_name) ++ && (NULL != encrypted) + && (strcmp (encrypted, ent->pw_passwd) == 0)) { + return true; + } else { +diff -up shadow-4.1.5.1/lib/pwauth.c.crypt-null shadow-4.1.5.1/lib/pwauth.c +--- shadow-4.1.5.1/lib/pwauth.c.crypt-null 2009-07-13 00:24:48.000000000 +0200 ++++ shadow-4.1.5.1/lib/pwauth.c 2013-07-25 12:27:30.438355782 +0200 +@@ -73,6 +73,7 @@ int pw_auth (const char *cipher, + char prompt[1024]; + char *clear = NULL; + const char *cp; ++ const char *encrypted; + int retval; + + #ifdef SKEY +@@ -177,7 +178,11 @@ int pw_auth (const char *cipher, + * the results there as well. + */ + +- retval = strcmp (pw_encrypt (input, cipher), cipher); ++ encrypted = pw_encrypt (input, cipher); ++ if (encrypted!=NULL) ++ retval = strcmp (encrypted, cipher); ++ else ++ retval = -1; + + #ifdef SKEY + /* +diff -up shadow-4.1.5.1/src/chgpasswd.c.crypt-null shadow-4.1.5.1/src/chgpasswd.c +--- shadow-4.1.5.1/src/chgpasswd.c.crypt-null 2011-12-09 22:31:40.000000000 +0100 ++++ shadow-4.1.5.1/src/chgpasswd.c 2013-07-25 12:27:30.440355847 +0200 +@@ -469,6 +469,10 @@ int main (int argc, char **argv) + #endif + cp = pw_encrypt (newpwd, + crypt_make_salt (crypt_method, arg)); ++ if (cp == NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } + } + + /* +diff -up shadow-4.1.5.1/src/chpasswd.c.crypt-null shadow-4.1.5.1/src/chpasswd.c +--- shadow-4.1.5.1/src/chpasswd.c.crypt-null 2011-12-09 22:31:40.000000000 +0100 ++++ shadow-4.1.5.1/src/chpasswd.c 2013-07-25 12:27:30.440355847 +0200 +@@ -492,6 +492,10 @@ int main (int argc, char **argv) + #endif + cp = pw_encrypt (newpwd, + crypt_make_salt(crypt_method, arg)); ++ if (cp == NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } + } + + /* +diff -up shadow-4.1.5.1/src/gpasswd.c.crypt-null shadow-4.1.5.1/src/gpasswd.c +--- shadow-4.1.5.1/src/gpasswd.c.crypt-null 2011-11-19 23:55:04.000000000 +0100 ++++ shadow-4.1.5.1/src/gpasswd.c 2013-07-25 12:27:30.441355866 +0200 +@@ -939,6 +939,10 @@ static void change_passwd (struct group + } + + cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL)); ++ if (cp==NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } + memzero (pass, sizeof pass); + #ifdef SHADOWGRP + if (is_shadowgrp) { +diff -up shadow-4.1.5.1/src/newgrp.c.crypt-null shadow-4.1.5.1/src/newgrp.c +--- shadow-4.1.5.1/src/newgrp.c.crypt-null 2011-07-30 03:50:01.000000000 +0200 ++++ shadow-4.1.5.1/src/newgrp.c 2013-07-25 12:27:30.442355881 +0200 +@@ -184,7 +184,8 @@ static void check_perms (const struct gr + cpasswd = pw_encrypt (cp, grp->gr_passwd); + strzero (cp); + +- if (grp->gr_passwd[0] == '\0' || ++ if (cpasswd == NULL || ++ grp->gr_passwd[0] == '\0' || + strcmp (cpasswd, grp->gr_passwd) != 0) { + #ifdef WITH_AUDIT + snprintf (audit_buf, sizeof(audit_buf), +diff -up shadow-4.1.5.1/src/newusers.c.crypt-null shadow-4.1.5.1/src/newusers.c +--- shadow-4.1.5.1/src/newusers.c.crypt-null 2011-12-09 22:31:40.000000000 +0100 ++++ shadow-4.1.5.1/src/newusers.c 2013-07-25 12:27:30.442355881 +0200 +@@ -387,6 +387,7 @@ static int add_user (const char *name, u + static void update_passwd (struct passwd *pwd, const char *password) + { + void *crypt_arg = NULL; ++ char *cp; + if (crypt_method != NULL) { + #ifdef USE_SHA_CRYPT + if (sflg) { +@@ -398,9 +399,13 @@ static void update_passwd (struct passwd + if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) { + pwd->pw_passwd = (char *)password; + } else { +- pwd->pw_passwd = pw_encrypt (password, +- crypt_make_salt (crypt_method, +- crypt_arg)); ++ cp=pw_encrypt (password, crypt_make_salt (crypt_method, ++ crypt_arg)); ++ if (cp == NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } ++ pwd->pw_passwd = cp; + } + } + #endif /* !USE_PAM */ +@@ -412,6 +417,7 @@ static int add_passwd (struct passwd *pw + { + const struct spwd *sp; + struct spwd spent; ++ char *cp; + + #ifndef USE_PAM + void *crypt_arg = NULL; +@@ -448,7 +454,12 @@ static int add_passwd (struct passwd *pw + } else { + const char *salt = crypt_make_salt (crypt_method, + crypt_arg); +- spent.sp_pwdp = pw_encrypt (password, salt); ++ cp = pw_encrypt (password, salt); ++ if (cp == NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } ++ spent.sp_pwdp = cp; + } + spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE; + if (0 == spent.sp_lstchg) { +@@ -492,7 +503,12 @@ static int add_passwd (struct passwd *pw + spent.sp_pwdp = (char *)password; + } else { + const char *salt = crypt_make_salt (crypt_method, crypt_arg); +- spent.sp_pwdp = pw_encrypt (password, salt); ++ cp = pw_encrypt (password, salt); ++ if (cp == NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } ++ spent.sp_pwdp = cp; + } + #else + /* +diff -up shadow-4.1.5.1/src/passwd.c.crypt-null shadow-4.1.5.1/src/passwd.c +--- shadow-4.1.5.1/src/passwd.c.crypt-null 2012-02-13 21:32:01.000000000 +0100 ++++ shadow-4.1.5.1/src/passwd.c 2013-07-25 12:27:30.443355896 +0200 +@@ -242,7 +242,7 @@ static int new_password (const struct pa + } + + cipher = pw_encrypt (clear, crypt_passwd); +- if (strcmp (cipher, crypt_passwd) != 0) { ++ if ((cipher == NULL) || (strcmp (cipher, crypt_passwd) != 0)) { + strzero (clear); + strzero (cipher); + SYSLOG ((LOG_WARN, "incorrect password for %s", +@@ -349,6 +349,10 @@ static int new_password (const struct pa + * Encrypt the password, then wipe the cleartext password. + */ + cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL)); ++ if (cp == NULL) { ++ perror ("crypt"); ++ exit (EXIT_FAILURE); ++ } + memzero (pass, sizeof pass); + + #ifdef HAVE_LIBCRACK_HIST diff --git a/SOURCES/shadow-4.1.5.1-date-parsing.patch b/SOURCES/shadow-4.1.5.1-date-parsing.patch new file mode 100644 index 00000000..38ec0916 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-date-parsing.patch @@ -0,0 +1,138 @@ +diff -up shadow-4.1.5.1/libmisc/getdate.c.date-parsing shadow-4.1.5.1/libmisc/getdate.c +--- shadow-4.1.5.1/libmisc/getdate.c.date-parsing 2008-06-14 00:07:51.000000000 +0200 ++++ shadow-4.1.5.1/libmisc/getdate.c 2014-08-29 13:41:22.553267506 +0200 +@@ -261,6 +261,7 @@ static int yyHaveDay; + static int yyHaveRel; + static int yyHaveTime; + static int yyHaveZone; ++static int yyHaveYear; + static int yyTimezone; + static int yyDay; + static int yyHour; +@@ -1730,6 +1731,7 @@ yyreduce: + yyDay = (yyvsp[(3) - (5)].Number); + yyYear = (yyvsp[(5) - (5)].Number); + } ++ yyHaveYear++; + } + break; + +@@ -1740,6 +1742,7 @@ yyreduce: + yyYear = (yyvsp[(1) - (3)].Number); + yyMonth = -(yyvsp[(2) - (3)].Number); + yyDay = -(yyvsp[(3) - (3)].Number); ++ yyHaveYear++; + } + break; + +@@ -1750,6 +1753,7 @@ yyreduce: + yyDay = (yyvsp[(1) - (3)].Number); + yyMonth = (yyvsp[(2) - (3)].Number); + yyYear = -(yyvsp[(3) - (3)].Number); ++ yyHaveYear++; + } + break; + +@@ -1767,6 +1771,7 @@ yyreduce: + yyMonth = (yyvsp[(1) - (4)].Number); + yyDay = (yyvsp[(2) - (4)].Number); + yyYear = (yyvsp[(4) - (4)].Number); ++ yyHaveYear++; + } + break; + +@@ -1784,6 +1789,7 @@ yyreduce: + yyMonth = (yyvsp[(2) - (3)].Number); + yyDay = (yyvsp[(1) - (3)].Number); + yyYear = (yyvsp[(3) - (3)].Number); ++ yyHaveYear++; + } + break; + +@@ -1928,7 +1934,8 @@ yyreduce: + case 49: + #line 397 "getdate.y" + { +- if ((yyHaveTime != 0) && (yyHaveDate != 0) && (yyHaveRel == 0)) ++ if ((yyHaveTime != 0 || (yyvsp[(1) - (1)].Number) >= 100) && !yyHaveYear ++ && (yyHaveDate != 0) && (yyHaveRel == 0)) + yyYear = (yyvsp[(1) - (1)].Number); + else + { +@@ -2556,7 +2563,7 @@ yylex (void) + return LookupWord (buff); + } + if (c != '(') +- return *yyInput++; ++ return (unsigned char)*yyInput++; + Count = 0; + do + { +diff -up shadow-4.1.5.1/libmisc/getdate.y.date-parsing shadow-4.1.5.1/libmisc/getdate.y +--- shadow-4.1.5.1/libmisc/getdate.y.date-parsing 2008-05-26 10:57:51.000000000 +0200 ++++ shadow-4.1.5.1/libmisc/getdate.y 2014-08-29 13:40:37.502229879 +0200 +@@ -152,6 +152,7 @@ static int yyHaveDay; + static int yyHaveRel; + static int yyHaveTime; + static int yyHaveZone; ++static int yyHaveYear; + static int yyTimezone; + static int yyDay; + static int yyHour; +@@ -293,18 +294,21 @@ date : tUNUMBER '/' tUNUMBER { + yyDay = $3; + yyYear = $5; + } ++ yyHaveYear++; + } + | tUNUMBER tSNUMBER tSNUMBER { + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = $1; + yyMonth = -$2; + yyDay = -$3; ++ yyHaveYear++; + } + | tUNUMBER tMONTH tSNUMBER { + /* e.g. 17-JUN-1992. */ + yyDay = $1; + yyMonth = $2; + yyYear = -$3; ++ yyHaveYear++; + } + | tMONTH tUNUMBER { + yyMonth = $1; +@@ -314,6 +318,7 @@ date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; ++ yyHaveYear++; + } + | tUNUMBER tMONTH { + yyMonth = $2; +@@ -323,6 +328,7 @@ date : tUNUMBER '/' tUNUMBER { + yyMonth = $2; + yyDay = $1; + yyYear = $3; ++ yyHaveYear++; + } + ; + +@@ -395,7 +401,8 @@ relunit : tUNUMBER tYEAR_UNIT { + + number : tUNUMBER + { +- if ((yyHaveTime != 0) && (yyHaveDate != 0) && (yyHaveRel == 0)) ++ if ((yyHaveTime != 0 || $1 >= 100) && !yyHaveYear ++ && (yyHaveDate != 0) && (yyHaveRel == 0)) + yyYear = $1; + else + { +@@ -802,7 +809,7 @@ yylex (void) + return LookupWord (buff); + } + if (c != '(') +- return *yyInput++; ++ return (unsigned char)*yyInput++; + Count = 0; + do + { diff --git a/SOURCES/shadow-4.1.5.1-default-range.patch b/SOURCES/shadow-4.1.5.1-default-range.patch new file mode 100644 index 00000000..45c677a0 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-default-range.patch @@ -0,0 +1,35 @@ +diff -up shadow-4.1.5.1/lib/semanage.c.default-range shadow-4.1.5.1/lib/semanage.c +--- shadow-4.1.5.1/lib/semanage.c.default-range 2012-01-08 17:35:44.000000000 +0100 ++++ shadow-4.1.5.1/lib/semanage.c 2013-06-14 15:14:51.970237594 +0200 +@@ -143,6 +143,7 @@ static int semanage_user_mod (semanage_h + goto done; + } + ++#if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { + fprintf (stderr, +@@ -150,6 +151,7 @@ static int semanage_user_mod (semanage_h + ret = 1; + goto done; + } ++#endif + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { +@@ -200,6 +202,7 @@ static int semanage_user_add (semanage_h + goto done; + } + ++#if 0 + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { + fprintf (stderr, +@@ -208,6 +211,7 @@ static int semanage_user_add (semanage_h + ret = 1; + goto done; + } ++#endif + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { diff --git a/SOURCES/shadow-4.1.5.1-errmsg.patch b/SOURCES/shadow-4.1.5.1-errmsg.patch new file mode 100644 index 00000000..6f3a1d2a --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-errmsg.patch @@ -0,0 +1,23 @@ +diff -up shadow-4.1.5.1/src/useradd.c.logmsg shadow-4.1.5.1/src/useradd.c +--- shadow-4.1.5.1/src/useradd.c.logmsg 2013-02-20 15:41:44.000000000 +0100 ++++ shadow-4.1.5.1/src/useradd.c 2013-06-14 14:22:59.529661095 +0200 +@@ -1760,6 +1760,9 @@ static void create_home (void) + if (access (user_home, F_OK) != 0) { + #ifdef WITH_SELINUX + if (set_selinux_file_context (user_home, NULL) != 0) { ++ fprintf (stderr, ++ _("%s: cannot set SELinux context for home directory %s\n"), ++ Prog, user_home); + fail_exit (E_HOMEDIR); + } + #endif +@@ -1789,6 +1792,9 @@ static void create_home (void) + #ifdef WITH_SELINUX + /* Reset SELinux to create files with default contexts */ + if (reset_selinux_file_context () != 0) { ++ fprintf (stderr, ++ _("%s: cannot reset SELinux file creation context\n"), ++ Prog); + fail_exit (E_HOMEDIR); + } + #endif diff --git a/SOURCES/shadow-4.1.5.1-goodname.patch b/SOURCES/shadow-4.1.5.1-goodname.patch new file mode 100644 index 00000000..2bbf38a4 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-goodname.patch @@ -0,0 +1,113 @@ +diff -up shadow-4.1.5.1/libmisc/chkname.c.goodname shadow-4.1.5.1/libmisc/chkname.c +--- shadow-4.1.5.1/libmisc/chkname.c.goodname 2009-07-13 00:24:45.000000000 +0200 ++++ shadow-4.1.5.1/libmisc/chkname.c 2018-04-24 16:32:40.970529916 +0200 +@@ -49,25 +49,44 @@ + static bool is_valid_name (const char *name) + { + /* +- * User/group names must match [a-z_][a-z0-9_-]*[$] +- */ +- if (('\0' == *name) || +- !((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) { ++ * User/group names must match gnu e-regex: ++ * [a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,30}[a-zA-Z0-9_.$-]? ++ * ++ * as a non-POSIX, extension, allow "$" as the last char for ++ * sake of Samba 3.x "add machine script" ++ * ++ * Also do not allow fully numeric names or just "." or "..". ++ */ ++ int numeric; ++ ++ if ('\0' == *name || ++ ('.' == *name && (('.' == name[1] && '\0' == name[2]) || ++ '\0' == name[1])) || ++ !((*name >= 'a' && *name <= 'z') || ++ (*name >= 'A' && *name <= 'Z') || ++ (*name >= '0' && *name <= '9') || ++ *name == '_' || ++ *name == '.')) { + return false; + } + ++ numeric = isdigit(*name); ++ + while ('\0' != *++name) { +- if (!(( ('a' <= *name) && ('z' >= *name) ) || +- ( ('0' <= *name) && ('9' >= *name) ) || +- ('_' == *name) || +- ('-' == *name) || +- ( ('$' == *name) && ('\0' == *(name + 1)) ) ++ if (!((*name >= 'a' && *name <= 'z') || ++ (*name >= 'A' && *name <= 'Z') || ++ (*name >= '0' && *name <= '9') || ++ *name == '_' || ++ *name == '.' || ++ *name == '-' || ++ (*name == '$' && name[1] == '\0') + )) { + return false; + } ++ numeric &= isdigit(*name); + } + +- return true; ++ return !numeric || getenv("SHADOW_ALLOW_ALL_NUMERIC_USER") != NULL; + } + + bool is_valid_user_name (const char *name) +diff -up shadow-4.1.5.1/man/groupadd.8.xml.goodname shadow-4.1.5.1/man/groupadd.8.xml +--- shadow-4.1.5.1/man/groupadd.8.xml.goodname 2012-05-25 13:45:27.000000000 +0200 ++++ shadow-4.1.5.1/man/groupadd.8.xml 2012-09-19 18:43:53.492160653 +0200 +@@ -259,10 +259,14 @@ + + CAVEATS + +- Groupnames must start with a lower case letter or an underscore, +- followed by lower case letters, digits, underscores, or dashes. +- They can end with a dollar sign. +- In regular expression terms: [a-z_][a-z0-9_-]*[$]? ++ Groupnames may contain only lower and upper case letters, digits, ++ underscores, or dashes. They can end with a dollar sign. ++ ++ Dashes are not allowed at the beginning of the groupname. ++ Fully numeric groupnames and groupnames . or .. are ++ also disallowed. ++ ++ In regular expression terms: [a-zA-Z0-9_.][a-zA-Z0-9_.-]*[$]? + + + Groupnames may only be up to &GROUP_NAME_MAX_LENGTH; characters long. +diff -up shadow-4.1.5.1/man/useradd.8.xml.goodname shadow-4.1.5.1/man/useradd.8.xml +--- shadow-4.1.5.1/man/useradd.8.xml.goodname 2012-05-25 13:45:29.000000000 +0200 ++++ shadow-4.1.5.1/man/useradd.8.xml 2012-09-19 18:43:53.493160675 +0200 +@@ -366,7 +366,7 @@ + + + +- Do no create the user's home directory, even if the system ++ Do not create the user's home directory, even if the system + wide setting from /etc/login.defs + () is set to + yes. +@@ -654,10 +654,16 @@ + + + +- Usernames must start with a lower case letter or an underscore, +- followed by lower case letters, digits, underscores, or dashes. +- They can end with a dollar sign. +- In regular expression terms: [a-z_][a-z0-9_-]*[$]? ++ Usernames may contain only lower and upper case letters, digits, ++ underscores, or dashes. They can end with a dollar sign. ++ ++ Dashes are not allowed at the beginning of the username. ++ Fully numeric usernames and usernames . or .. are ++ also disallowed. It is not recommended to use usernames beginning ++ with . character as their home directories will be hidden in ++ the ls output. ++ ++ In regular expression terms: [a-zA-Z0-9_.][a-zA-Z0-9_.-]*[$]? + + + Usernames may only be up to 32 characters long. diff --git a/SOURCES/shadow-4.1.5.1-id-alloc.patch b/SOURCES/shadow-4.1.5.1-id-alloc.patch new file mode 100644 index 00000000..6c55739e --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-id-alloc.patch @@ -0,0 +1,1213 @@ +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 two 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). + +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/SOURCES/shadow-4.1.5.1-info-parent-dir.patch b/SOURCES/shadow-4.1.5.1-info-parent-dir.patch new file mode 100644 index 00000000..b05e5bb7 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-info-parent-dir.patch @@ -0,0 +1,20 @@ +diff -up shadow-4.1.5.1/man/newusers.8.xml.info-parent-dir shadow-4.1.5.1/man/newusers.8.xml +--- shadow-4.1.5.1/man/newusers.8.xml.info-parent-dir 2012-05-25 13:45:28.000000000 +0200 ++++ shadow-4.1.5.1/man/newusers.8.xml 2012-09-19 18:46:35.651613365 +0200 +@@ -216,7 +216,15 @@ + + If this field does not specify an existing directory, the + specified directory is created, with ownership set to the +- user being created or updated and its primary group. ++ user being created or updated and its primary group. Note ++ that newusers does not create parent directories of the new ++ user's home directory. The newusers command will fail to ++ create the home directory if the parent directories do not ++ exist, and will send a message to stderr informing the user ++ of the failure. The newusers command will not halt or return ++ a failure to the calling shell if it fails to create the home ++ directory, it will continue to process the batch of new users ++ specified. + + + If the home directory of an existing user is changed, diff --git a/SOURCES/shadow-4.1.5.1-ingroup.patch b/SOURCES/shadow-4.1.5.1-ingroup.patch new file mode 100644 index 00000000..1844fbce --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-ingroup.patch @@ -0,0 +1,121 @@ +diff -up shadow-4.1.5.1/src/newgrp.c.ingroup shadow-4.1.5.1/src/newgrp.c +--- shadow-4.1.5.1/src/newgrp.c.ingroup 2018-04-24 16:55:24.546677529 +0200 ++++ shadow-4.1.5.1/src/newgrp.c 2018-04-24 16:58:17.113445562 +0200 +@@ -83,15 +83,29 @@ static void usage (void) + } + } + ++static bool ingroup(const char *name, struct group *gr) ++{ ++ char **look; ++ bool notfound = true; ++ ++ look = gr->gr_mem; ++ while (*look && notfound) ++ notfound = strcmp (*look++, name); ++ ++ return !notfound; ++} ++ + /* +- * find_matching_group - search all groups of a given group id for ++ * find_matching_group - search all groups of a gr's group id for + * membership of a given username ++ * but check gr itself first + */ +-static /*@null@*/struct group *find_matching_group (const char *name, gid_t gid) ++static /*@null@*/struct group *find_matching_group (const char *name, struct group *gr) + { +- struct group *gr; +- char **look; +- bool notfound = true; ++ gid_t gid = gr->gr_gid; ++ ++ if (ingroup(name, gr)) ++ return gr; + + setgrent (); + while ((gr = getgrent ()) != NULL) { +@@ -103,14 +117,8 @@ static /*@null@*/struct group *find_matc + * A group with matching GID was found. + * Test for membership of 'name'. + */ +- look = gr->gr_mem; +- while ((NULL != *look) && notfound) { +- notfound = (strcmp (*look, name) != 0); +- look++; +- } +- if (!notfound) { ++ if (ingroup(name, gr)) + break; +- } + } + endgrent (); + return gr; +@@ -373,6 +381,7 @@ int main (int argc, char **argv) + { + bool initflag = false; + int i; ++ bool is_member = false; + bool cflag = false; + int err = 0; + gid_t gid; +@@ -611,22 +620,36 @@ int main (int argc, char **argv) + goto failure; + } + ++#ifdef HAVE_SETGROUPS ++ /* when using pam_group, she will not be listed in the groups ++ * database. However getgroups() will return the group. So ++ * if she is listed there already it is ok to grant membership. ++ */ ++ for (i = 0; i < ngroups; i++) { ++ if (grp->gr_gid == grouplist[i]) { ++ is_member = true; ++ break; ++ } ++ } ++#endif /* HAVE_SETGROUPS */ + /* + * For splitted groups (due to limitations of NIS), check all + * groups of the same GID like the requested group for + * membership of the current user. + */ +- grp = find_matching_group (name, grp->gr_gid); +- if (NULL == grp) { +- /* +- * No matching group found. As we already know that +- * the group exists, this happens only in the case +- * of a requested group where the user is not member. +- * +- * Re-read the group entry for further processing. +- */ +- grp = xgetgrnam (group); +- assert (NULL != grp); ++ if (!is_member) { ++ grp = find_matching_group (name, grp); ++ if (NULL == grp) { ++ /* ++ * No matching group found. As we already know that ++ * the group exists, this happens only in the case ++ * of a requested group where the user is not member. ++ * ++ * Re-read the group entry for further processing. ++ */ ++ grp = xgetgrnam (group); ++ assert (NULL != grp); ++ } + } + #ifdef SHADOWGRP + sgrp = getsgnam (group); +@@ -639,7 +662,9 @@ int main (int argc, char **argv) + /* + * Check if the user is allowed to access this group. + */ +- check_perms (grp, pwd, group); ++ if (!is_member) { ++ check_perms (grp, pwd, group); ++ } + + /* + * all successful validations pass through this point. The group id diff --git a/SOURCES/shadow-4.1.5.1-ja-translation.patch b/SOURCES/shadow-4.1.5.1-ja-translation.patch new file mode 100644 index 00000000..407cc3fa --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-ja-translation.patch @@ -0,0 +1,25 @@ +From f2ce4cc54edc7dfeb6b12f3e8fff98255a9f477d Mon Sep 17 00:00:00 2001 +From: Taizo Ito +Date: Tue, 17 Mar 2015 13:51:27 +0900 +Subject: [PATCH 1/1] typo in japanese man page of useradd + +--- + po/ja.po | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/po/ja.po b/po/ja.po +index a68a698..0c21c29 100644 +--- a/po/ja.po ++++ b/po/ja.po +@@ -2047,7 +2047,7 @@ msgid " -s, --shell SHELL login shell of the new account\n" + msgstr " -s, --shell SHELL 新アカウントのログインシェル\n" + + msgid " -u, --uid UID user ID of the new account\n" +-msgstr " -u, --iud UID 新アカウントのユーザ ID\n" ++msgstr " -u, --uid UID 新アカウントのユーザ ID\n" + + msgid "" + " -U, --user-group create a group with the same name as the " +-- +1.8.3.1 + diff --git a/SOURCES/shadow-4.1.5.1-lastlog-unexpire.patch b/SOURCES/shadow-4.1.5.1-lastlog-unexpire.patch new file mode 100644 index 00000000..6a7ae2a8 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-lastlog-unexpire.patch @@ -0,0 +1,263 @@ +diff -up shadow-4.1.5.1/man/lastlog.8.xml.unexpire shadow-4.1.5.1/man/lastlog.8.xml +--- shadow-4.1.5.1/man/lastlog.8.xml.unexpire 2012-05-25 13:45:28.000000000 +0200 ++++ shadow-4.1.5.1/man/lastlog.8.xml 2016-04-28 15:09:11.026084219 +0200 +@@ -105,6 +105,17 @@ + + + ++ , ++ ++ ++ ++ Clear lastlog record of an user. This option can be used only together ++ with ()). ++ ++ ++ ++ ++ + , + + +@@ -124,6 +135,17 @@ + + + ++ ++ ++ , ++ ++ ++ ++ Set lastlog record of an user to the current time. This option can be ++ used only together with ()). ++ ++ ++ + + + , +diff -up shadow-4.1.5.1/src/lastlog.c.unexpire shadow-4.1.5.1/src/lastlog.c +--- shadow-4.1.5.1/src/lastlog.c.unexpire 2011-11-06 21:54:18.000000000 +0100 ++++ shadow-4.1.5.1/src/lastlog.c 2016-04-28 15:49:30.253371990 +0200 +@@ -55,6 +55,13 @@ + #endif + + /* ++ * Needed for systems with older audit library. ++ */ ++#ifndef AUDIT_ACCT_UNLOCK ++#define AUDIT_ACCT_UNLOCK 1136 ++#endif ++ ++/* + * Global variables + */ + const char *Prog; /* Program name */ +@@ -71,6 +78,8 @@ static struct stat statbuf; /* fstat buf + static bool uflg = false; /* print only an user of range of users */ + static bool tflg = false; /* print is restricted to most recent days */ + static bool bflg = false; /* print excludes most recent days */ ++static bool Cflg = false; /* clear record for user */ ++static bool Sflg = false; /* set record for user */ + + #define NOW (time ((time_t *) 0)) + +@@ -83,8 +92,10 @@ static /*@noreturn@*/void usage (int sta + "Options:\n"), + Prog); + (void) fputs (_(" -b, --before DAYS print only lastlog records older than DAYS\n"), usageout); ++ (void) fputs (_(" -C, --clear clear lastlog record of an user (usable only with -u)\n"), usageout); + (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); + (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); ++ (void) fputs (_(" -S, --set set lastlog record to current time (usable only with -u)\n"), usageout); + (void) fputs (_(" -t, --time DAYS print only lastlog records more recent than DAYS\n"), usageout); + (void) fputs (_(" -u, --user LOGIN print lastlog record of the specified LOGIN\n"), usageout); + (void) fputs ("\n", usageout); +@@ -194,6 +205,80 @@ static void print (void) + } + } + ++static void update_one (/*@null@*/const struct passwd *pw) ++{ ++ off_t offset; ++ struct lastlog ll; ++ int err; ++ ++ if (NULL == pw) { ++ return; ++ } ++ ++ offset = (off_t) pw->pw_uid * sizeof (ll); ++ /* fseeko errors are not really relevant for us. */ ++ err = fseeko (lastlogfile, offset, SEEK_SET); ++ assert (0 == err); ++ ++ memzero (&ll, sizeof (ll)); ++ ++ if (Sflg) { ++ ll.ll_time = NOW; ++#ifdef HAVE_LL_HOST ++ strcpy (ll.ll_host, "localhost"); ++#endif ++ strcpy (ll.ll_line, "lastlog"); ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_ACCT_UNLOCK, Prog, ++ "clearing-lastlog", ++ pw->pw_name, (unsigned int) pw->pw_uid, SHADOW_AUDIT_SUCCESS); ++#endif ++ } ++#ifdef WITH_AUDIT ++ else { ++ audit_logger (AUDIT_ACCT_UNLOCK, Prog, ++ "refreshing-lastlog", ++ pw->pw_name, (unsigned int) pw->pw_uid, SHADOW_AUDIT_SUCCESS); ++ } ++#endif ++ ++ if (fwrite (&ll, sizeof(ll), 1, lastlogfile) != 1) { ++ fprintf (stderr, ++ _("%s: Failed to update the entry for UID %lu\n"), ++ Prog, (unsigned long int)pw->pw_uid); ++ exit (EXIT_FAILURE); ++ } ++} ++ ++static void update (void) ++{ ++ const struct passwd *pwent; ++ ++ if (!uflg) /* safety measure */ ++ return; ++ ++ if (has_umin && has_umax && (umin == umax)) { ++ update_one (getpwuid ((uid_t)umin)); ++ } else { ++ setpwent (); ++ while ( (pwent = getpwent ()) != NULL ) { ++ if ((has_umin && (pwent->pw_uid < (uid_t)umin)) ++ || (has_umax && (pwent->pw_uid > (uid_t)umax))) { ++ continue; ++ } ++ update_one (pwent); ++ } ++ endpwent (); ++ } ++ ++ if (fflush (lastlogfile) != 0 || fsync (fileno (lastlogfile)) != 0) { ++ fprintf (stderr, ++ _("%s: Failed to update the lastlog file\n"), ++ Prog); ++ exit (EXIT_FAILURE); ++ } ++} ++ + int main (int argc, char **argv) + { + /* +@@ -208,18 +293,24 @@ int main (int argc, char **argv) + + process_root_flag ("-R", argc, argv); + ++#ifdef WITH_AUDIT ++ audit_help_open (); ++#endif ++ + { + int c; + static struct option const longopts[] = { + {"before", required_argument, NULL, 'b'}, ++ {"clear", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, + {"root", required_argument, NULL, 'R'}, ++ {"set", no_argument, NULL, 'S'}, + {"time", required_argument, NULL, 't'}, + {"user", required_argument, NULL, 'u'}, + {NULL, 0, NULL, '\0'} + }; + +- while ((c = getopt_long (argc, argv, "b:hR:t:u:", longopts, ++ while ((c = getopt_long (argc, argv, "b:ChR:St:u:", longopts, + NULL)) != -1) { + switch (c) { + case 'b': +@@ -235,11 +326,21 @@ int main (int argc, char **argv) + bflg = true; + break; + } ++ case 'C': ++ { ++ Cflg = true; ++ break; ++ } + case 'h': + usage (EXIT_SUCCESS); + /*@notreached@*/break; + case 'R': /* no-op, handled in process_root_flag () */ + break; ++ case 'S': ++ { ++ Sflg = true; ++ break; ++ } + case 't': + { + unsigned long days; +@@ -294,9 +395,21 @@ int main (int argc, char **argv) + Prog, argv[optind]); + usage (EXIT_FAILURE); + } ++ if (Cflg && Sflg) { ++ fprintf (stderr, ++ _("%s: Option -C cannot be used together with option -S\n"), ++ Prog); ++ usage (EXIT_FAILURE); ++ } ++ if ((Cflg || Sflg) && !uflg) { ++ fprintf (stderr, ++ _("%s: Options -C and -S require option -u to specify the user\n"), ++ Prog); ++ usage (EXIT_FAILURE); ++ } + } + +- lastlogfile = fopen (LASTLOG_FILE, "r"); ++ lastlogfile = fopen (LASTLOG_FILE, (Cflg || Sflg)?"r+":"r"); + if (NULL == lastlogfile) { + perror (LASTLOG_FILE); + exit (EXIT_FAILURE); +@@ -310,7 +423,10 @@ int main (int argc, char **argv) + exit (EXIT_FAILURE); + } + +- print (); ++ if (Cflg || Sflg) ++ update (); ++ else ++ print (); + + (void) fclose (lastlogfile); + +diff -up shadow-4.1.5.1/src/Makefile.am.unexpire shadow-4.1.5.1/src/Makefile.am +--- shadow-4.1.5.1/src/Makefile.am.unexpire 2011-11-18 22:23:30.000000000 +0100 ++++ shadow-4.1.5.1/src/Makefile.am 2016-04-28 15:09:11.027084241 +0200 +@@ -90,6 +90,7 @@ groupmod_LDADD = $(LDADD) $(LIBPAM_SUID) + grpck_LDADD = $(LDADD) $(LIBSELINUX) + grpconv_LDADD = $(LDADD) $(LIBSELINUX) + grpunconv_LDADD = $(LDADD) $(LIBSELINUX) ++lastlog_LDADD = $(LDADD) $(LIBAUDIT) + login_SOURCES = \ + login.c \ + login_nopam.c +diff -up shadow-4.1.5.1/src/Makefile.in.unexpire shadow-4.1.5.1/src/Makefile.in +--- shadow-4.1.5.1/src/Makefile.in.unexpire 2012-05-25 13:56:51.000000000 +0200 ++++ shadow-4.1.5.1/src/Makefile.in 2016-04-28 15:09:11.027084241 +0200 +@@ -162,7 +162,7 @@ id_DEPENDENCIES = $(am__DEPENDENCIES_1) + $(top_builddir)/lib/libshadow.la + lastlog_SOURCES = lastlog.c + lastlog_OBJECTS = lastlog.$(OBJEXT) +-lastlog_LDADD = $(LDADD) ++lastlog_LDADD = $(LDADD) $(LIBAUDIT) + lastlog_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(top_builddir)/libmisc/libmisc.a \ + $(top_builddir)/lib/libshadow.la diff --git a/SOURCES/shadow-4.1.5.1-logmsg.patch b/SOURCES/shadow-4.1.5.1-logmsg.patch new file mode 100644 index 00000000..7d5cbc83 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-logmsg.patch @@ -0,0 +1,12 @@ +diff -up shadow-4.1.5.1/src/useradd.c.logmsg shadow-4.1.5.1/src/useradd.c +--- shadow-4.1.5.1/src/useradd.c.logmsg 2013-02-20 15:41:44.000000000 +0100 ++++ shadow-4.1.5.1/src/useradd.c 2013-03-19 18:40:04.908292810 +0100 +@@ -275,7 +275,7 @@ static void fail_exit (int code) + user_name, AUDIT_NO_ID, + SHADOW_AUDIT_FAILURE); + #endif +- SYSLOG ((LOG_INFO, "failed adding user '%s', data deleted", user_name)); ++ SYSLOG ((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code)); + exit (code); + } + diff --git a/SOURCES/shadow-4.1.5.1-long-entry.patch b/SOURCES/shadow-4.1.5.1-long-entry.patch new file mode 100644 index 00000000..eaf96897 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-long-entry.patch @@ -0,0 +1,84 @@ +diff -up shadow-4.1.5.1/lib/defines.h.long-entry shadow-4.1.5.1/lib/defines.h +--- shadow-4.1.5.1/lib/defines.h.long-entry 2011-09-18 22:44:10.000000000 +0200 ++++ shadow-4.1.5.1/lib/defines.h 2018-04-24 16:34:31.261417493 +0200 +@@ -382,4 +382,7 @@ extern char *strerror (); + # endif + #endif + ++/* Maximum length of passwd entry */ ++#define PASSWD_ENTRY_MAX_LENGTH 32768 ++ + #endif /* _DEFINES_H_ */ +diff -up shadow-4.1.5.1/lib/pwio.c.long-entry shadow-4.1.5.1/lib/pwio.c +--- shadow-4.1.5.1/lib/pwio.c.long-entry 2011-02-16 21:32:24.000000000 +0100 ++++ shadow-4.1.5.1/lib/pwio.c 2018-04-24 16:34:31.263417454 +0200 +@@ -79,7 +79,10 @@ static int passwd_put (const void *ent, + || (pw->pw_gid == (gid_t)-1) + || (valid_field (pw->pw_gecos, ":\n") == -1) + || (valid_field (pw->pw_dir, ":\n") == -1) +- || (valid_field (pw->pw_shell, ":\n") == -1)) { ++ || (valid_field (pw->pw_shell, ":\n") == -1) ++ || (strlen (pw->pw_name) + strlen (pw->pw_passwd) + ++ strlen (pw->pw_gecos) + strlen (pw->pw_dir) + ++ strlen (pw->pw_shell) + 100 > PASSWD_ENTRY_MAX_LENGTH)) { + return -1; + } + +diff -up shadow-4.1.5.1/lib/sgetpwent.c.long-entry shadow-4.1.5.1/lib/sgetpwent.c +--- shadow-4.1.5.1/lib/sgetpwent.c.long-entry 2009-04-06 06:28:53.000000000 +0200 ++++ shadow-4.1.5.1/lib/sgetpwent.c 2018-04-24 16:34:31.263417454 +0200 +@@ -57,7 +57,7 @@ + struct passwd *sgetpwent (const char *buf) + { + static struct passwd pwent; +- static char pwdbuf[1024]; ++ static char pwdbuf[PASSWD_ENTRY_MAX_LENGTH]; + register int i; + register char *cp; + char *fields[NFIELDS]; +@@ -67,8 +67,10 @@ struct passwd *sgetpwent (const char *bu + * the password structure remain valid. + */ + +- if (strlen (buf) >= sizeof pwdbuf) ++ if (strlen (buf) >= sizeof pwdbuf) { ++ fprintf (stderr, "Too long passwd entry encountered, file corruption?\n"); + return 0; /* fail if too long */ ++ } + strcpy (pwdbuf, buf); + + /* +diff -up shadow-4.1.5.1/lib/sgetspent.c.long-entry shadow-4.1.5.1/lib/sgetspent.c +--- shadow-4.1.5.1/lib/sgetspent.c.long-entry 2009-04-12 04:46:43.000000000 +0200 ++++ shadow-4.1.5.1/lib/sgetspent.c 2018-04-24 16:34:31.264417435 +0200 +@@ -48,7 +48,7 @@ + */ + struct spwd *sgetspent (const char *string) + { +- static char spwbuf[1024]; ++ static char spwbuf[PASSWD_ENTRY_MAX_LENGTH]; + static struct spwd spwd; + char *fields[FIELDS]; + char *cp; +@@ -61,6 +61,7 @@ struct spwd *sgetspent (const char *stri + */ + + if (strlen (string) >= sizeof spwbuf) { ++ fprintf (stderr, "Too long shadow entry encountered, file corruption?\n"); + return 0; /* fail if too long */ + } + strcpy (spwbuf, string); +diff -up shadow-4.1.5.1/lib/shadowio.c.long-entry shadow-4.1.5.1/lib/shadowio.c +--- shadow-4.1.5.1/lib/shadowio.c.long-entry 2011-02-16 21:32:24.000000000 +0100 ++++ shadow-4.1.5.1/lib/shadowio.c 2018-04-24 16:34:31.265417416 +0200 +@@ -78,7 +78,9 @@ static int shadow_put (const void *ent, + + if ( (NULL == sp) + || (valid_field (sp->sp_namp, ":\n") == -1) +- || (valid_field (sp->sp_pwdp, ":\n") == -1)) { ++ || (valid_field (sp->sp_pwdp, ":\n") == -1) ++ || (strlen (sp->sp_namp) + strlen (sp->sp_pwdp) + ++ 1000 > PASSWD_ENTRY_MAX_LENGTH)) { + return -1; + } + diff --git a/SOURCES/shadow-4.1.5.1-manfix.patch b/SOURCES/shadow-4.1.5.1-manfix.patch new file mode 100644 index 00000000..18dc3428 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-manfix.patch @@ -0,0 +1,281 @@ +diff -up shadow-4.1.5.1/man/chage.1.xml.manfix shadow-4.1.5.1/man/chage.1.xml +--- shadow-4.1.5.1/man/chage.1.xml.manfix 2012-05-25 13:45:27.000000000 +0200 ++++ shadow-4.1.5.1/man/chage.1.xml 2018-04-24 16:43:48.545743715 +0200 +@@ -102,6 +102,9 @@ + Set the number of days since January 1st, 1970 when the password + was last changed. The date may also be expressed in the format + YYYY-MM-DD (or the format more commonly used in your area). ++ If the LAST_DAY is set to ++ 0 the user is forced to change his password ++ on the next log on. + + + +@@ -123,6 +126,13 @@ + EXPIRE_DATE will remove an account + expiration date. + ++ ++ For example the following command can be used ++ to set an account to expire in 180 days: ++ ++ ++ chage -E $(date -d +180days +%Y-%m-%d) ++ + + + +diff -up shadow-4.1.5.1/man/groupmems.8.xml.manfix shadow-4.1.5.1/man/groupmems.8.xml +--- shadow-4.1.5.1/man/groupmems.8.xml.manfix 2012-05-25 13:45:28.000000000 +0200 ++++ shadow-4.1.5.1/man/groupmems.8.xml 2015-12-18 12:27:08.466909647 +0100 +@@ -194,6 +194,13 @@ + $ chown root.groups groupmems + $ groupmems -g groups -a gk4 + ++ ++ ++ In the Red Hat Enterprise Linux 7 the groupmems ++ command is not setuid and regular users cannot use it to manipulate ++ the membership of their own group. This might change in future ++ major releases of the Red Hat Enterprise Linux. ++ + + + +diff -up shadow-4.1.5.1/man/ja/man5/login.defs.5.manfix shadow-4.1.5.1/man/ja/man5/login.defs.5 +--- shadow-4.1.5.1/man/ja/man5/login.defs.5.manfix 2012-05-25 13:45:27.000000000 +0200 ++++ shadow-4.1.5.1/man/ja/man5/login.defs.5 2015-12-18 12:34:08.080715842 +0100 +@@ -147,10 +147,6 @@ 以下の参照表は、 + shadow パスワード機能のどのプログラムが + どのパラメータを使用するかを示したものである。 + .na +-.IP chfn 12 +-CHFN_AUTH CHFN_RESTRICT +-.IP chsh 12 +-CHFN_AUTH + .IP groupadd 12 + GID_MAX GID_MIN + .IP newusers 12 +diff -up shadow-4.1.5.1/man/login.defs.5.xml.manfix shadow-4.1.5.1/man/login.defs.5.xml +--- shadow-4.1.5.1/man/login.defs.5.xml.manfix 2012-05-25 13:45:28.000000000 +0200 ++++ shadow-4.1.5.1/man/login.defs.5.xml 2014-08-29 13:31:38.364812323 +0200 +@@ -160,6 +160,17 @@ + long numeric parameters is machine-dependent. + + ++ ++ Please note that the parameters in this configuration file control the ++ behavior of the tools from the shadow-utils component. None of these ++ tools uses the PAM mechanism, and the utilities that use PAM (such as the ++ passwd command) should be configured elsewhere. The only values that ++ affect PAM modules are ENCRYPT_METHOD and SHA_CRYPT_MAX_ROUNDS ++ for pam_unix module, FAIL_DELAY for pam_faildelay module, ++ and UMASK for pam_umask module. Refer to ++ pam(8) for more information. ++ ++ + The following configuration items are provided: + + +@@ -248,26 +258,6 @@ + + + +- chfn +- +- +- CHFN_AUTH +- CHFN_RESTRICT +- LOGIN_STRING +- +- +- +- +- chgpasswd +- +- +- ENCRYPT_METHOD MAX_MEMBERS_PER_GROUP MD5_CRYPT_ENAB +- SHA_CRYPT_MAX_ROUNDS +- SHA_CRYPT_MIN_ROUNDS +- +- +- +- + chpasswd + + +@@ -278,14 +268,6 @@ + + + +- +- chsh +- +- +- CHSH_AUTH LOGIN_STRING +- +- +- + + + +@@ -346,34 +328,6 @@ + + + +- +- login +- +- +- CONSOLE +- CONSOLE_GROUPS DEFAULT_HOME +- ENV_HZ ENV_PATH ENV_SUPATH +- ENV_TZ ENVIRON_FILE +- ERASECHAR FAIL_DELAY +- FAILLOG_ENAB +- FAKE_SHELL +- FTMP_FILE +- HUSHLOGIN_FILE +- ISSUE_FILE +- KILLCHAR +- LASTLOG_ENAB +- LOGIN_RETRIES +- LOGIN_STRING +- LOGIN_TIMEOUT LOG_OK_LOGINS LOG_UNKFAIL_ENAB +- MAIL_CHECK_ENAB MAIL_DIR MAIL_FILE +- MOTD_FILE NOLOGINS_FILE PORTTIME_CHECKS_ENAB +- QUOTAS_ENAB +- TTYGROUP TTYPERM TTYTYPE_FILE +- ULIMIT UMASK +- USERGROUPS_ENAB +- +- +- + + + newgrp / sg +@@ -399,17 +353,6 @@ + + + +- +- passwd +- +- +- ENCRYPT_METHOD MD5_CRYPT_ENAB OBSCURE_CHECKS_ENAB +- PASS_ALWAYS_WARN PASS_CHANGE_TRIES PASS_MAX_LEN PASS_MIN_LEN +- SHA_CRYPT_MAX_ROUNDS +- SHA_CRYPT_MIN_ROUNDS +- +- +- + + pwck + +@@ -436,32 +379,6 @@ + + + +- +- su +- +- +- CONSOLE +- CONSOLE_GROUPS DEFAULT_HOME +- ENV_HZ ENVIRON_FILE +- ENV_PATH ENV_SUPATH +- ENV_TZ LOGIN_STRING MAIL_CHECK_ENAB +- MAIL_DIR MAIL_FILE QUOTAS_ENAB +- SULOG_FILE SU_NAME +- SU_WHEEL_ONLY +- SYSLOG_SU_ENAB +- USERGROUPS_ENAB +- +- +- +- +- sulogin +- +- +- ENV_HZ +- ENV_TZ +- +- +- + + useradd + +diff -up shadow-4.1.5.1/man/useradd.8.xml.manfix shadow-4.1.5.1/man/useradd.8.xml +--- shadow-4.1.5.1/man/useradd.8.xml.manfix 2015-12-17 14:05:47.930742412 +0100 ++++ shadow-4.1.5.1/man/useradd.8.xml 2015-12-17 14:05:47.945742754 +0100 +@@ -134,8 +134,8 @@ + HOME_DIR is not specified. + BASE_DIR is + concatenated with the account name to define the home directory. +- If the option is not used, +- BASE_DIR must exist. ++ The BASE_DIR must exist otherwise ++ the home directory cannot be created. + + + If this option is not specified, useradd +@@ -161,7 +161,7 @@ + + + +- , ++ , + HOME_DIR + + +@@ -171,8 +171,7 @@ + login directory. The default is to append the + LOGIN name to + BASE_DIR and use that as the login +- directory name. The directory HOME_DIR +- does not have to exist but will not be created if it is missing. ++ directory name. + + + +@@ -358,11 +357,16 @@ + is not enabled, no home + directories are created. + ++ ++ The directory where the user's home directory is created must ++ exist and have proper SELinux context and permissions. Otherwise ++ the user's home directory cannot be created or accessed. ++ + + + + +- ++ , + + + +diff -up shadow-4.1.5.1/man/usermod.8.xml.manfix shadow-4.1.5.1/man/usermod.8.xml +--- shadow-4.1.5.1/man/usermod.8.xml.manfix 2012-05-25 13:45:29.000000000 +0200 ++++ shadow-4.1.5.1/man/usermod.8.xml 2014-08-29 13:33:40.814632618 +0200 +@@ -132,7 +132,8 @@ + If the + option is given, the contents of the current home directory will + be moved to the new home directory, which is created if it does +- not already exist. ++ not already exist. If the current home directory does not exist ++ the new home directory will not be created. + + + +@@ -261,7 +262,8 @@ + + + Move the content of the user's home directory to the new +- location. ++ location. If the current home directory does not exist ++ the new home directory will not be created. + + + This option is only valid in combination with the diff --git a/SOURCES/shadow-4.1.5.1-merge-group.patch b/SOURCES/shadow-4.1.5.1-merge-group.patch new file mode 100644 index 00000000..f5cea103 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-merge-group.patch @@ -0,0 +1,27 @@ +diff -up shadow-4.1.5.1/lib/groupio.c.merge-group shadow-4.1.5.1/lib/groupio.c +--- shadow-4.1.5.1/lib/groupio.c.merge-group 2011-02-16 21:32:24.000000000 +0100 ++++ shadow-4.1.5.1/lib/groupio.c 2013-01-29 13:56:43.049275513 +0100 +@@ -330,12 +330,12 @@ static /*@null@*/struct commonio_entry * + + /* Concatenate the 2 lines */ + new_line_len = strlen (gr1->line) + strlen (gr2->line) +1; +- new_line = (char *)malloc ((new_line_len + 1) * sizeof(char*)); ++ new_line = (char *)malloc (new_line_len + 1); + if (NULL == new_line) { + errno = ENOMEM; + return NULL; + } +- snprintf(new_line, new_line_len, "%s\n%s", gr1->line, gr2->line); ++ snprintf(new_line, new_line_len + 1, "%s\n%s", gr1->line, gr2->line); + new_line[new_line_len] = '\0'; + + /* Concatenate the 2 list of members */ +@@ -353,7 +353,7 @@ static /*@null@*/struct commonio_entry * + members++; + } + } +- new_members = (char **)malloc ( (members+1) * sizeof(char*) ); ++ new_members = (char **)calloc (members+1, sizeof(char*)); + if (NULL == new_members) { + free (new_line); + errno = ENOMEM; diff --git a/SOURCES/shadow-4.1.5.1-move-home.patch b/SOURCES/shadow-4.1.5.1-move-home.patch new file mode 100644 index 00000000..c87e2320 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-move-home.patch @@ -0,0 +1,15 @@ +diff -up shadow-4.1.5.1/src/usermod.c.move-home shadow-4.1.5.1/src/usermod.c +--- shadow-4.1.5.1/src/usermod.c.move-home 2014-08-29 13:31:38.000000000 +0200 ++++ shadow-4.1.5.1/src/usermod.c 2014-08-29 14:14:13.860671177 +0200 +@@ -1571,6 +1571,11 @@ static void move_home (void) + Prog, user_home, user_newhome); + fail_exit (E_HOMEDIR); + } ++ } else { ++ fprintf (stderr, ++ _("%s: The previous home directory (%s) does " ++ "not exist or is inaccessible. Move cannot be completed.\n"), ++ Prog, user_home); + } + } + diff --git a/SOURCES/shadow-4.1.5.1-null-tm.patch b/SOURCES/shadow-4.1.5.1-null-tm.patch new file mode 100644 index 00000000..e531d144 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-null-tm.patch @@ -0,0 +1,86 @@ +diff -up shadow-4.1.5.1/src/faillog.c.null-tm shadow-4.1.5.1/src/faillog.c +--- shadow-4.1.5.1/src/faillog.c.null-tm 2011-11-19 23:54:47.000000000 +0100 ++++ shadow-4.1.5.1/src/faillog.c 2016-06-14 11:54:58.582314219 +0200 +@@ -163,10 +163,14 @@ static void print_one (/*@null@*/const s + } + + tm = localtime (&fl.fail_time); ++ if (tm == NULL) { ++ cp = "(unknown)"; ++ } else { + #ifdef HAVE_STRFTIME +- strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm); +- cp = ptime; ++ strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm); ++ cp = ptime; + #endif ++ } + printf ("%-9s %5d %5d ", + pw->pw_name, fl.fail_cnt, fl.fail_max); + /* FIXME: cp is not defined ifndef HAVE_STRFTIME */ +diff -up shadow-4.1.5.1/src/chage.c.null-tm shadow-4.1.5.1/src/chage.c +--- shadow-4.1.5.1/src/chage.c.null-tm 2016-05-04 13:44:55.639787900 +0200 ++++ shadow-4.1.5.1/src/chage.c 2016-06-14 11:54:58.583314243 +0200 +@@ -168,6 +168,10 @@ static void date_to_str (char *buf, size + struct tm *tp; + + tp = gmtime (&date); ++ if (tp == NULL) { ++ (void) snprintf (buf, maxsize, "(unknown)"); ++ return; ++ } + #ifdef HAVE_STRFTIME + (void) strftime (buf, maxsize, "%Y-%m-%d", tp); + #else +diff -up shadow-4.1.5.1/src/lastlog.c.null-tm shadow-4.1.5.1/src/lastlog.c +--- shadow-4.1.5.1/src/lastlog.c.null-tm 2016-05-04 13:44:55.647788082 +0200 ++++ shadow-4.1.5.1/src/lastlog.c 2016-06-14 11:54:58.584314267 +0200 +@@ -165,13 +165,17 @@ static void print_one (/*@null@*/const s + + ll_time = ll.ll_time; + tm = localtime (&ll_time); ++ if (tm == NULL) { ++ cp = "(unknown)"; ++ } else { + #ifdef HAVE_STRFTIME +- strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", tm); +- cp = ptime; ++ strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", tm); ++ cp = ptime; + #else +- cp = asctime (tm); +- cp[24] = '\0'; ++ cp = asctime (tm); ++ cp[24] = '\0'; + #endif ++ } + + if (ll.ll_time == (time_t) 0) { + cp = _("**Never logged in**\0"); +diff -up shadow-4.1.5.1/src/passwd.c.null-tm shadow-4.1.5.1/src/passwd.c +--- shadow-4.1.5.1/src/passwd.c.null-tm 2016-05-04 13:44:55.634787787 +0200 ++++ shadow-4.1.5.1/src/passwd.c 2016-06-14 11:54:58.584314267 +0200 +@@ -438,6 +438,9 @@ static /*@observer@*/const char *date_to + struct tm *tm; + + tm = gmtime (&t); ++ if (tm == NULL) { ++ return "(unknown)"; ++ } + #ifdef HAVE_STRFTIME + (void) strftime (buf, sizeof buf, "%m/%d/%Y", tm); + #else /* !HAVE_STRFTIME */ +diff -up shadow-4.1.5.1/src/usermod.c.null-tm shadow-4.1.5.1/src/usermod.c +--- shadow-4.1.5.1/src/usermod.c.null-tm 2016-05-04 13:44:55.648788104 +0200 ++++ shadow-4.1.5.1/src/usermod.c 2016-06-14 11:54:58.585314291 +0200 +@@ -186,6 +186,10 @@ static void date_to_str (/*@unique@*//*@ + } else { + time_t t = (time_t) date; + tp = gmtime (&t); ++ if (tp == NULL) { ++ strncpy (buf, "unknown", maxsize); ++ return; ++ } + #ifdef HAVE_STRFTIME + strftime (buf, maxsize, "%Y-%m-%d", tp); + #else diff --git a/SOURCES/shadow-4.1.5.1-orig-context.patch b/SOURCES/shadow-4.1.5.1-orig-context.patch new file mode 100644 index 00000000..c1ddb133 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-orig-context.patch @@ -0,0 +1,128 @@ +diff -up shadow-4.1.5.1/lib/commonio.c.orig-context shadow-4.1.5.1/lib/commonio.c +--- shadow-4.1.5.1/lib/commonio.c.orig-context 2012-09-19 20:27:16.000000000 +0200 ++++ shadow-4.1.5.1/lib/commonio.c 2013-02-20 15:20:55.064962324 +0100 +@@ -941,7 +941,7 @@ int commonio_close (struct commonio_db * + snprintf (buf, sizeof buf, "%s-", db->filename); + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (buf) != 0) { ++ if (set_selinux_file_context (buf, db->filename) != 0) { + errors++; + } + #endif +@@ -975,7 +975,7 @@ int commonio_close (struct commonio_db * + snprintf (buf, sizeof buf, "%s+", db->filename); + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (buf) != 0) { ++ if (set_selinux_file_context (buf, db->filename) != 0) { + errors++; + } + #endif +diff -up shadow-4.1.5.1/libmisc/copydir.c.orig-context shadow-4.1.5.1/libmisc/copydir.c +--- shadow-4.1.5.1/libmisc/copydir.c.orig-context 2012-02-13 20:16:32.000000000 +0100 ++++ shadow-4.1.5.1/libmisc/copydir.c 2013-02-20 15:19:01.495623232 +0100 +@@ -484,7 +484,7 @@ static int copy_dir (const char *src, co + */ + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + return -1; + } + #endif /* WITH_SELINUX */ +@@ -605,7 +605,7 @@ static int copy_symlink (const char *src + } + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + free (oldlink); + return -1; + } +@@ -684,7 +684,7 @@ static int copy_special (const char *src + int err = 0; + + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + return -1; + } + #endif /* WITH_SELINUX */ +@@ -744,7 +744,7 @@ static int copy_file (const char *src, c + return -1; + } + #ifdef WITH_SELINUX +- if (set_selinux_file_context (dst) != 0) { ++ if (set_selinux_file_context (dst, NULL) != 0) { + return -1; + } + #endif /* WITH_SELINUX */ +diff -up shadow-4.1.5.1/lib/prototypes.h.orig-context shadow-4.1.5.1/lib/prototypes.h +--- shadow-4.1.5.1/lib/prototypes.h.orig-context 2012-01-08 17:04:29.000000000 +0100 ++++ shadow-4.1.5.1/lib/prototypes.h 2013-02-20 15:24:17.251126575 +0100 +@@ -295,7 +295,7 @@ extern /*@observer@*/const char *crypt_m + + /* selinux.c */ + #ifdef WITH_SELINUX +-extern int set_selinux_file_context (const char *dst_name); ++extern int set_selinux_file_context (const char *dst_name, const char *orig_name); + extern int reset_selinux_file_context (void); + #endif + +diff -up shadow-4.1.5.1/lib/selinux.c.orig-context shadow-4.1.5.1/lib/selinux.c +--- shadow-4.1.5.1/lib/selinux.c.orig-context 2012-01-08 17:35:44.000000000 +0100 ++++ shadow-4.1.5.1/lib/selinux.c 2013-02-20 15:16:40.383716877 +0100 +@@ -50,7 +50,7 @@ static bool selinux_enabled; + * Callers may have to Reset SELinux to create files with default + * contexts with reset_selinux_file_context + */ +-int set_selinux_file_context (const char *dst_name) ++int set_selinux_file_context (const char *dst_name, const char *orig_name) + { + /*@null@*/security_context_t scontext = NULL; + +@@ -62,19 +62,23 @@ int set_selinux_file_context (const char + if (selinux_enabled) { + /* Get the default security context for this file */ + if (matchpathcon (dst_name, 0, &scontext) < 0) { +- if (security_getenforce () != 0) { +- return 1; +- } ++ /* We could not get the default, copy the original */ ++ if (orig_name == NULL) ++ goto error; ++ if (getfilecon (orig_name, &scontext) < 0) ++ goto error; + } + /* Set the security context for the next created file */ +- if (setfscreatecon (scontext) < 0) { +- if (security_getenforce () != 0) { +- return 1; +- } +- } ++ if (setfscreatecon (scontext) < 0) ++ goto error; + freecon (scontext); + } + return 0; ++ error: ++ if (security_getenforce () != 0) { ++ return 1; ++ } ++ return 0; + } + + /* +diff -up shadow-4.1.5.1/src/useradd.c.orig-context shadow-4.1.5.1/src/useradd.c +--- shadow-4.1.5.1/src/useradd.c.orig-context 2012-09-19 20:23:33.000000000 +0200 ++++ shadow-4.1.5.1/src/useradd.c 2013-02-20 15:19:31.221235459 +0100 +@@ -1759,7 +1759,7 @@ static void create_home (void) + { + if (access (user_home, F_OK) != 0) { + #ifdef WITH_SELINUX +- if (set_selinux_file_context (user_home) != 0) { ++ if (set_selinux_file_context (user_home, NULL) != 0) { + fail_exit (E_HOMEDIR); + } + #endif diff --git a/SOURCES/shadow-4.1.5.1-selinux-perms.patch b/SOURCES/shadow-4.1.5.1-selinux-perms.patch new file mode 100644 index 00000000..3c702960 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-selinux-perms.patch @@ -0,0 +1,289 @@ +diff -up shadow-4.1.5.1/src/chgpasswd.c.selinux-perms shadow-4.1.5.1/src/chgpasswd.c +--- shadow-4.1.5.1/src/chgpasswd.c.selinux-perms 2016-05-04 13:44:55.633787764 +0200 ++++ shadow-4.1.5.1/src/chgpasswd.c 2016-05-30 12:01:30.421587253 +0200 +@@ -39,6 +39,13 @@ + #include + #include + #include ++#ifdef WITH_SELINUX ++#include ++#include ++#endif ++#ifdef WITH_LIBAUDIT ++#include ++#endif + #ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + #include "pam_defs.h" +@@ -76,6 +83,9 @@ static bool sgr_locked = false; + #endif + static bool gr_locked = false; + ++/* The name of the caller */ ++static char *myname = NULL; ++ + /* local function prototypes */ + static void fail_exit (int code); + static /*@noreturn@*/void usage (int status); +@@ -300,6 +310,63 @@ static void check_perms (void) + #endif /* ACCT_TOOLS_SETUID */ + } + ++#ifdef WITH_SELINUX ++static int ++log_callback (int type, const char *fmt, ...) ++{ ++ int audit_fd; ++ va_list ap; ++ ++ va_start(ap, fmt); ++#ifdef WITH_AUDIT ++ audit_fd = audit_open(); ++ ++ if (audit_fd >= 0) { ++ char *buf; ++ ++ if (vasprintf (&buf, fmt, ap) < 0) ++ goto ret; ++ audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, ++ NULL, 0); ++ audit_close(audit_fd); ++ free(buf); ++ goto ret; ++ } ++ ++#endif ++ vsyslog (LOG_USER | LOG_INFO, fmt, ap); ++ret: ++ va_end(ap); ++ return 0; ++} ++ ++static void ++selinux_check_root (void) ++{ ++ int status = -1; ++ security_context_t user_context; ++ union selinux_callback old_callback; ++ ++ if (is_selinux_enabled() < 1) ++ return; ++ ++ old_callback = selinux_get_callback(SELINUX_CB_LOG); ++ /* setup callbacks */ ++ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback); ++ if ((status = getprevcon(&user_context)) < 0) { ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ exit(1); ++ } ++ ++ status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL); ++ ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ freecon(user_context); ++ if (status != 0 && security_getenforce() != 0) ++ exit(1); ++} ++#endif ++ + /* + * open_files - lock and open the group databases + */ +@@ -393,6 +460,7 @@ int main (int argc, char **argv) + + const struct group *gr; + struct group newgr; ++ struct passwd *pw = NULL; + int errors = 0; + int line = 0; + +@@ -408,8 +476,33 @@ int main (int argc, char **argv) + + OPENLOG ("chgpasswd"); + ++#ifdef WITH_AUDIT ++ audit_help_open (); ++#endif ++ ++ /* ++ * Determine the name of the user that invoked this command. This ++ * is really hit or miss because there are so many ways that command ++ * can be executed and so many ways to trip up the routines that ++ * report the user name. ++ */ ++ pw = get_my_pwent (); ++ if (NULL == pw) { ++ fprintf (stderr, _("%s: Cannot determine your user name.\n"), ++ Prog); ++ SYSLOG ((LOG_WARN, ++ "Cannot determine the user name of the caller (UID %lu)", ++ (unsigned long) getuid ())); ++ exit (E_NOPERM); ++ } ++ myname = xstrdup (pw->pw_name); ++ + check_perms (); + ++#ifdef WITH_SELINUX ++ selinux_check_root (); ++#endif ++ + #ifdef SHADOWGRP + is_shadow_grp = sgr_file_present (); + #endif +@@ -533,6 +626,15 @@ int main (int argc, char **argv) + newgr.gr_passwd = cp; + } + ++#ifdef WITH_AUDIT ++ { ++ ++ audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog, ++ "change-password", ++ myname, AUDIT_NO_ID, gr->gr_name, ++ SHADOW_AUDIT_SUCCESS); ++ } ++#endif + /* + * The updated group file entry is then put back and will + * be written to the group file later, after all the +diff -up shadow-4.1.5.1/src/chpasswd.c.selinux-perms shadow-4.1.5.1/src/chpasswd.c +--- shadow-4.1.5.1/src/chpasswd.c.selinux-perms 2016-05-04 13:44:55.633787764 +0200 ++++ shadow-4.1.5.1/src/chpasswd.c 2016-05-30 12:01:42.877859957 +0200 +@@ -39,6 +39,13 @@ + #include + #include + #include ++#ifdef WITH_SELINUX ++#include ++#include ++#endif ++#ifdef WITH_LIBAUDIT ++#include ++#endif + #ifdef USE_PAM + #include "pam_defs.h" + #endif /* USE_PAM */ +@@ -297,6 +304,63 @@ static void check_perms (void) + #endif /* USE_PAM */ + } + ++#ifdef WITH_SELINUX ++static int ++log_callback (int type, const char *fmt, ...) ++{ ++ int audit_fd; ++ va_list ap; ++ ++ va_start(ap, fmt); ++#ifdef WITH_AUDIT ++ audit_fd = audit_open(); ++ ++ if (audit_fd >= 0) { ++ char *buf; ++ ++ if (vasprintf (&buf, fmt, ap) < 0) ++ goto ret; ++ audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, ++ NULL, 0); ++ audit_close(audit_fd); ++ free(buf); ++ goto ret; ++ } ++ ++#endif ++ vsyslog (LOG_USER | LOG_INFO, fmt, ap); ++ret: ++ va_end(ap); ++ return 0; ++} ++ ++static void ++selinux_check_root (void) ++{ ++ int status = -1; ++ security_context_t user_context; ++ union selinux_callback old_callback; ++ ++ if (is_selinux_enabled() < 1) ++ return; ++ ++ old_callback = selinux_get_callback(SELINUX_CB_LOG); ++ /* setup callbacks */ ++ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback); ++ if ((status = getprevcon(&user_context)) < 0) { ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ exit(1); ++ } ++ ++ status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL); ++ ++ selinux_set_callback(SELINUX_CB_LOG, old_callback); ++ freecon(user_context); ++ if (status != 0 && security_getenforce() != 0) ++ exit(1); ++} ++#endif ++ + /* + * open_files - lock and open the password databases + */ +@@ -405,8 +469,16 @@ int main (int argc, char **argv) + + OPENLOG ("chpasswd"); + ++#ifdef WITH_AUDIT ++ audit_help_open (); ++#endif ++ + check_perms (); + ++#ifdef WITH_SELINUX ++ selinux_check_root (); ++#endif ++ + #ifdef USE_PAM + if (!use_pam) + #endif /* USE_PAM */ +@@ -563,6 +635,11 @@ int main (int argc, char **argv) + newpw.pw_passwd = cp; + } + ++#ifdef WITH_AUDIT ++ audit_logger (AUDIT_USER_CHAUTHTOK, Prog, ++ "updating-password", ++ pw->pw_name, (unsigned int) pw->pw_uid, 1); ++#endif + /* + * The updated password file entry is then put back and will + * be written to the password file later, after all the +diff -up shadow-4.1.5.1/src/Makefile.am.selinux-perms shadow-4.1.5.1/src/Makefile.am +--- shadow-4.1.5.1/src/Makefile.am.selinux-perms 2016-05-04 13:44:55.647788082 +0200 ++++ shadow-4.1.5.1/src/Makefile.am 2016-05-27 16:04:49.446582632 +0200 +@@ -79,9 +79,9 @@ endif + + chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) + chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) +-chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT) ++chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) +-chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) ++chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) + groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) + groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) +diff -up shadow-4.1.5.1/src/Makefile.in.selinux-perms shadow-4.1.5.1/src/Makefile.in +--- shadow-4.1.5.1/src/Makefile.in.selinux-perms 2016-05-04 13:44:55.647788082 +0200 ++++ shadow-4.1.5.1/src/Makefile.in 2016-05-27 16:04:49.447582654 +0200 +@@ -437,9 +437,9 @@ AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/l + @USE_PAM_TRUE@LIBCRYPT_NOPAM = + chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) + chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) +-chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT) ++chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) +-chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT) ++chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT) + gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) + groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) + groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) diff --git a/SOURCES/shadow-4.1.5.1-selinux.patch b/SOURCES/shadow-4.1.5.1-selinux.patch new file mode 100644 index 00000000..4ac32d26 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-selinux.patch @@ -0,0 +1,99 @@ +diff -up shadow-4.1.5.1/lib/semanage.c.selinux shadow-4.1.5.1/lib/semanage.c +--- shadow-4.1.5.1/lib/semanage.c.selinux 2012-01-08 17:35:44.000000000 +0100 ++++ shadow-4.1.5.1/lib/semanage.c 2014-09-10 10:11:55.417506128 +0200 +@@ -294,6 +294,9 @@ int set_seuser (const char *login_name, + + ret = 0; + ++ /* drop obsolete matchpathcon cache */ ++ matchpathcon_fini(); ++ + done: + semanage_seuser_key_free (key); + semanage_handle_destroy (handle); +@@ -369,6 +372,10 @@ int del_seuser (const char *login_name) + } + + ret = 0; ++ ++ /* drop obsolete matchpathcon cache */ ++ matchpathcon_fini(); ++ + done: + semanage_handle_destroy (handle); + return ret; +diff -up shadow-4.1.5.1/src/useradd.c.selinux shadow-4.1.5.1/src/useradd.c +--- shadow-4.1.5.1/src/useradd.c.selinux 2014-09-10 10:10:18.791280619 +0200 ++++ shadow-4.1.5.1/src/useradd.c 2014-09-10 10:10:18.798280781 +0200 +@@ -1850,6 +1850,7 @@ static void create_mail (void) + */ + int main (int argc, char **argv) + { ++ int rv = E_SUCCESS; + #ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + pam_handle_t *pamh = NULL; +@@ -2037,10 +2038,33 @@ int main (int argc, char **argv) + + usr_update (); + ++ close_files (); ++ ++ nscd_flush_cache ("passwd"); ++ nscd_flush_cache ("group"); ++ ++#ifdef WITH_SELINUX ++ if (Zflg && *user_selinux) { ++ if (is_selinux_enabled () > 0) { ++ if (set_seuser (user_name, user_selinux) != 0) { ++ fprintf (stderr, ++ _("%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); ++#endif /* WITH_AUDIT */ ++ rv = E_SE_UPDATE; ++ } ++ } ++ } ++#endif ++ + if (mflg) { + create_home (); + if (home_added) { +- copy_tree (def_template, user_home, false, false, ++ copy_tree (def_template, user_home, false, true, + (uid_t)-1, user_id, (gid_t)-1, user_gid); + } else { + fprintf (stderr, +@@ -2056,27 +2080,6 @@ int main (int argc, char **argv) + create_mail (); + } + +- close_files (); +- +-#ifdef WITH_SELINUX +- if (Zflg) { +- if (set_seuser (user_name, user_selinux) != 0) { +- fprintf (stderr, +- _("%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); +-#endif /* WITH_AUDIT */ +- fail_exit (E_SE_UPDATE); +- } +- } +-#endif /* WITH_SELINUX */ +- +- nscd_flush_cache ("passwd"); +- nscd_flush_cache ("group"); +- +- return E_SUCCESS; ++ return rv; + } + diff --git a/SOURCES/shadow-4.1.5.1-userdel-helpfix.patch b/SOURCES/shadow-4.1.5.1-userdel-helpfix.patch new file mode 100644 index 00000000..b79baee6 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-userdel-helpfix.patch @@ -0,0 +1,15 @@ +diff -up shadow-4.1.5.1/src/userdel.c.userdel shadow-4.1.5.1/src/userdel.c +--- shadow-4.1.5.1/src/userdel.c.userdel 2012-05-25 13:51:55.000000000 +0200 ++++ shadow-4.1.5.1/src/userdel.c 2014-02-12 11:40:30.707686132 +0100 +@@ -130,8 +130,9 @@ static void usage (int status) + "\n" + "Options:\n"), + Prog); +- (void) fputs (_(" -f, --force force removal of files,\n" +- " even if not owned by user\n"), ++ (void) fputs (_(" -f, --force force some actions that would fail otherwise\n" ++ " e.g. removal of user still logged in\n" ++ " or files, even if not owned by the user\n"), + usageout); + (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); + (void) fputs (_(" -r, --remove remove home directory and mail spool\n"), usageout); diff --git a/SOURCES/shadow-4.1.5.1-usermod-passwd.patch b/SOURCES/shadow-4.1.5.1-usermod-passwd.patch new file mode 100644 index 00000000..8096cfd6 --- /dev/null +++ b/SOURCES/shadow-4.1.5.1-usermod-passwd.patch @@ -0,0 +1,63 @@ +diff -up shadow-4.1.5.1/src/usermod.c.passwd shadow-4.1.5.1/src/usermod.c +--- shadow-4.1.5.1/src/usermod.c.passwd 2015-12-17 14:05:47.959743073 +0100 ++++ shadow-4.1.5.1/src/usermod.c 2015-12-18 12:42:28.290405529 +0100 +@@ -360,14 +360,17 @@ static char *new_pw_passwd (char *pw_pas + strcat (buf, pw_pass); + pw_pass = buf; + } else if (Uflg && pw_pass[0] == '!') { +- char *s; ++ char *s = pw_pass; + +- if (pw_pass[1] == '\0') { ++ while ('!' == *s) ++ ++s; ++ ++ if (*s == '\0') { + fprintf (stderr, + _("%s: unlocking the user's password would result in a passwordless account.\n" + "You should set a password with usermod -p to unlock this user's password.\n"), + Prog); +- return pw_pass; ++ return NULL; + } + + #ifdef WITH_AUDIT +@@ -376,12 +379,15 @@ static char *new_pw_passwd (char *pw_pas + user_newname, (unsigned int) user_newid, 1); + #endif + SYSLOG ((LOG_INFO, "unlock user '%s' password", user_newname)); +- s = pw_pass; +- while ('\0' != *s) { +- *s = *(s + 1); +- s++; +- } ++ memmove (pw_pass, s, strlen (s) + 1); + } else if (pflg) { ++ if (strchr (user_pass, ':') != NULL) { ++ fprintf (stderr, ++ _("%s: The password field cannot contain a colon character.\n"), ++ Prog); ++ return NULL; ++ ++ } + #ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "updating-password", +@@ -430,6 +436,8 @@ static void new_pwent (struct passwd *pw + if ( (!is_shadow_pwd) + || (strcmp (pwent->pw_passwd, SHADOW_PASSWD_STRING) != 0)) { + pwent->pw_passwd = new_pw_passwd (pwent->pw_passwd); ++ if (pwent->pw_passwd == NULL) ++ fail_exit (E_PW_UPDATE); + } + + if (uflg) { +@@ -544,6 +552,8 @@ static void new_spent (struct spwd *spen + * + aging has been requested + */ + spent->sp_pwdp = new_pw_passwd (spent->sp_pwdp); ++ if (spent->sp_pwdp == NULL) ++ fail_exit(E_PW_UPDATE); + + if (pflg) { + spent->sp_lstchg = (long) time ((time_t *) 0) / SCALE; diff --git a/SOURCES/shadow-utils.login.defs b/SOURCES/shadow-utils.login.defs new file mode 100644 index 00000000..3f27f88c --- /dev/null +++ b/SOURCES/shadow-utils.login.defs @@ -0,0 +1,72 @@ +# +# Please note that the parameters in this configuration file control the +# behavior of the tools from the shadow-utils component. None of these +# tools uses the PAM mechanism, and the utilities that use PAM (such as the +# passwd command) should therefore be configured elsewhere. Refer to +# /etc/pam.d/system-auth for more information. +# + +# *REQUIRED* +# Directory where mailboxes reside, _or_ name of file, relative to the +# home directory. If you _do_ define both, MAIL_DIR takes precedence. +# QMAIL_DIR is for Qmail +# +#QMAIL_DIR Maildir +MAIL_DIR /var/spool/mail +#MAIL_FILE .mail + +# Password aging controls: +# +# PASS_MAX_DAYS Maximum number of days a password may be used. +# PASS_MIN_DAYS Minimum number of days allowed between password changes. +# PASS_MIN_LEN Minimum acceptable password length. +# PASS_WARN_AGE Number of days warning given before a password expires. +# +PASS_MAX_DAYS 99999 +PASS_MIN_DAYS 0 +PASS_MIN_LEN 5 +PASS_WARN_AGE 7 + +# +# Min/max values for automatic uid selection in useradd +# +UID_MIN 1000 +UID_MAX 60000 +# System accounts +SYS_UID_MIN 201 +SYS_UID_MAX 999 + +# +# Min/max values for automatic gid selection in groupadd +# +GID_MIN 1000 +GID_MAX 60000 +# System accounts +SYS_GID_MIN 201 +SYS_GID_MAX 999 + +# +# If defined, this command is run when removing a user. +# It should remove any at/cron/print jobs etc. owned by +# the user to be removed (passed as the first argument). +# +#USERDEL_CMD /usr/sbin/userdel_local + +# +# If useradd should create home directories for users by default +# On RH systems, we do. This option is overridden with the -m flag on +# useradd command line. +# +CREATE_HOME yes + +# The permission mask is initialized to this value. If not specified, +# the permission mask will be initialized to 022. +UMASK 077 + +# This enables userdel to remove user groups if no members exist. +# +USERGROUPS_ENAB yes + +# Use SHA512 to encrypt password. +ENCRYPT_METHOD SHA512 + diff --git a/SOURCES/shadow-utils.useradd b/SOURCES/shadow-utils.useradd new file mode 100644 index 00000000..4e811469 --- /dev/null +++ b/SOURCES/shadow-utils.useradd @@ -0,0 +1,9 @@ +# useradd defaults file +GROUP=100 +HOME=/home +INACTIVE=-1 +EXPIRE= +SHELL=/bin/bash +SKEL=/etc/skel +CREATE_MAIL_SPOOL=yes + diff --git a/SPECS/shadow-utils.spec b/SPECS/shadow-utils.spec new file mode 100644 index 00000000..0133135d --- /dev/null +++ b/SPECS/shadow-utils.spec @@ -0,0 +1,1086 @@ +Summary: Utilities for managing accounts and shadow password files +Name: shadow-utils +Version: 4.1.5.1 +Release: 25%{?dist} +Epoch: 2 +URL: http://pkg-shadow.alioth.debian.org/ +Source0: http://pkg-shadow.alioth.debian.org/releases/shadow-%{version}.tar.bz2 +Source3: http://pkg-shadow.alioth.debian.org/releases/shadow-%{version}.tar.bz2.sig +Source1: shadow-utils.login.defs +Source2: shadow-utils.useradd +Patch0: shadow-4.1.5-redhat.patch +Patch1: shadow-4.1.5.1-goodname.patch +Patch2: shadow-4.1.5.1-info-parent-dir.patch +Patch3: shadow-4.1.5-uflg.patch +Patch6: shadow-4.1.5.1-selinux.patch +Patch7: shadow-4.1.5-2ndskip.patch +Patch8: shadow-4.1.5.1-backup-mode.patch +Patch9: shadow-4.1.5.1-merge-group.patch +Patch10: shadow-4.1.5.1-orig-context.patch +Patch11: shadow-4.1.5.1-logmsg.patch +Patch12: shadow-4.1.5.1-errmsg.patch +Patch13: shadow-4.1.5.1-audit-owner.patch +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-date-parsing.patch +Patch19: shadow-4.1.5.1-ingroup.patch +Patch20: shadow-4.1.5.1-move-home.patch +Patch21: shadow-4.1.5.1-audit-update.patch +Patch22: shadow-4.1.5.1-ja-translation.patch +Patch23: shadow-4.1.5.1-usermod-passwd.patch +Patch24: shadow-4.1.5.1-id-alloc.patch +Patch25: shadow-4.1.5.1-lastlog-unexpire.patch +Patch26: shadow-4.1.5.1-chgrp-guard.patch +Patch27: shadow-4.1.5.1-selinux-perms.patch +Patch28: shadow-4.1.5.1-null-tm.patch +Patch29: shadow-4.1.5.1-long-entry.patch + +License: BSD and GPLv2+ +Group: System Environment/Base +BuildRequires: libselinux-devel >= 1.25.2-1 +BuildRequires: audit-libs-devel >= 1.6.5 +BuildRequires: libsemanage-devel +BuildRequires: libacl-devel libattr-devel +BuildRequires: gnome-doc-utils docbook-style-xsl gettext +#BuildRequires: autoconf, automake, libtool, gettext-devel +Requires: libselinux >= 1.25.2-1 +Requires: audit-libs >= 1.6.5 +Requires: setup +Requires(pre): coreutils +Requires(post): coreutils +Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +The shadow-utils package includes the necessary programs for +converting UNIX password files to the shadow password format, plus +programs for managing user and group accounts. The pwconv command +converts passwords to the shadow password format. The pwunconv command +unconverts shadow passwords and generates a passwd file (a standard +UNIX password file). The pwck command checks the integrity of password +and shadow files. The lastlog command prints out the last login times +for all users. The useradd, userdel, and usermod commands are used for +managing user accounts. The groupadd, groupdel, and groupmod commands +are used for managing group accounts. + +%prep +%setup -q -n shadow-%{version} +%patch0 -p1 -b .redhat +%patch1 -p1 -b .goodname +%patch2 -p1 -b .info-parent-dir +%patch3 -p1 -b .uflg +%patch6 -p1 -b .selinux +%patch7 -p1 -b .2ndskip +%patch8 -p1 -b .backup-mode +%patch9 -p1 -b .merge-group +%patch10 -p1 -b .orig-context +%patch11 -p1 -b .logmsg +%patch12 -p1 -b .errmsg +%patch13 -p1 -b .audit-owner +%patch14 -p1 -b .default-range +%patch15 -p1 -b .manfix +%patch16 -p1 -b .crypt-null +%patch17 -p1 -b .userdel +%patch18 -p1 -b .date-parsing +%patch19 -p1 -b .ingroup +%patch20 -p1 -b .move-home +%patch21 -p1 -b .audit-update +%patch22 -p1 -b .ja-translation +%patch23 -p1 -b .usermod-passwd +%patch24 -p1 -b .id-alloc +%patch25 -p1 -b .unexpire +%patch26 -p1 -b .chgrp-guard +%patch27 -p1 -b .selinux-perms +%patch28 -p1 -b .null-tm +%patch29 -p1 -b .long-entry + +iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 +cp -f doc/HOWTO.utf8 doc/HOWTO + +#rm po/*.gmo +#rm po/stamp-po +#aclocal +#libtoolize --force +#automake -a +#autoconf + +%build + +%ifarch sparc64 +#sparc64 need big PIE +export CFLAGS="$RPM_OPT_FLAGS -fPIE" +export LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" +%else +export CFLAGS="$RPM_OPT_FLAGS -fpie" +export LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" +%endif + +export LC_ALL=C +%configure \ + --enable-shadowgrp \ + --enable-man \ + --with-audit \ + --with-sha-crypt \ + --with-selinux \ + --without-libcrack \ + --without-libpam \ + --disable-shared \ + --with-group-name-max-length=32 +# update the japanese translation +(cd po; make ja.gmo) +make + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT gnulocaledir=$RPM_BUILD_ROOT/%{_datadir}/locale MKINSTALLDIRS=`pwd`/mkinstalldirs +install -d -m 755 $RPM_BUILD_ROOT/%{_sysconfdir}/default +install -p -c -m 0644 %{SOURCE1} $RPM_BUILD_ROOT/%{_sysconfdir}/login.defs +install -p -c -m 0600 %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/default/useradd + + +ln -s useradd $RPM_BUILD_ROOT%{_sbindir}/adduser +#ln -s %{_mandir}/man8/useradd.8 $RPM_BUILD_ROOT/%{_mandir}/man8/adduser.8 +ln -s useradd.8 $RPM_BUILD_ROOT/%{_mandir}/man8/adduser.8 +for subdir in $RPM_BUILD_ROOT/%{_mandir}/{??,??_??,??_??.*}/man* ; do + test -d $subdir && test -e $subdir/useradd.8 && echo ".so man8/useradd.8" > $subdir/adduser.8 +done + +# Remove binaries we don't use. +rm $RPM_BUILD_ROOT/%{_bindir}/chfn +rm $RPM_BUILD_ROOT/%{_bindir}/chsh +rm $RPM_BUILD_ROOT/%{_bindir}/expiry +rm $RPM_BUILD_ROOT/%{_bindir}/groups +rm $RPM_BUILD_ROOT/%{_bindir}/login +rm $RPM_BUILD_ROOT/%{_bindir}/passwd +rm $RPM_BUILD_ROOT/%{_bindir}/su +rm $RPM_BUILD_ROOT/%{_bindir}/faillog +rm $RPM_BUILD_ROOT/%{_sysconfdir}/login.access +rm $RPM_BUILD_ROOT/%{_sysconfdir}/limits +rm $RPM_BUILD_ROOT/%{_sbindir}/logoutd +rm $RPM_BUILD_ROOT/%{_sbindir}/nologin +rm $RPM_BUILD_ROOT/%{_sbindir}/chgpasswd +rm $RPM_BUILD_ROOT/%{_mandir}/man1/chfn.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/chfn.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/chsh.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/chsh.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/expiry.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/expiry.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/groups.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/groups.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/login.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/login.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man1/su.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man1/su.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/limits.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/limits.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/login.access.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/login.access.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/passwd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/porttime.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/porttime.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/suauth.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/suauth.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/logoutd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/logoutd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/nologin.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/nologin.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/chgpasswd.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/chgpasswd.* +rm $RPM_BUILD_ROOT/%{_mandir}/man3/getspnam.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man3/getspnam.* +rm $RPM_BUILD_ROOT/%{_mandir}/man5/faillog.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man5/faillog.* +rm $RPM_BUILD_ROOT/%{_mandir}/man8/faillog.* +rm $RPM_BUILD_ROOT/%{_mandir}/*/man8/faillog.* + +find $RPM_BUILD_ROOT%{_mandir} -depth -type d -empty -delete +%find_lang shadow +for dir in $(ls -1d $RPM_BUILD_ROOT%{_mandir}/{??,??_??}) ; do + dir=$(echo $dir | sed -e "s|^$RPM_BUILD_ROOT||") + lang=$(basename $dir) +# echo "%%lang($lang) $dir" >> shadow.lang +# echo "%%lang($lang) $dir/man*" >> shadow.lang + echo "%%lang($lang) $dir/man*/*" >> shadow.lang +done + +%clean +rm -rf $RPM_BUILD_ROOT + +%files -f shadow.lang +%defattr(-,root,root) +%doc NEWS doc/HOWTO README +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/login.defs +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/default/useradd +%{_bindir}/sg +%attr(4755,root,root) %{_bindir}/chage +%attr(4755,root,root) %{_bindir}/gpasswd +%{_bindir}/lastlog +%attr(4755,root,root) %{_bindir}/newgrp +%{_sbindir}/adduser +%attr(0750,root,root) %{_sbindir}/user* +%attr(0750,root,root) %{_sbindir}/group* +%{_sbindir}/grpck +%{_sbindir}/pwck +%{_sbindir}/*conv +%{_sbindir}/chpasswd +%{_sbindir}/newusers +%{_sbindir}/vipw +%{_sbindir}/vigr +%{_mandir}/man1/chage.1* +%{_mandir}/man1/gpasswd.1* +%{_mandir}/man1/sg.1* +%{_mandir}/man1/newgrp.1* +%{_mandir}/man3/shadow.3* +%{_mandir}/man5/shadow.5* +%{_mandir}/man5/login.defs.5* +%{_mandir}/man5/gshadow.5* +%{_mandir}/man8/adduser.8* +%{_mandir}/man8/group*.8* +%{_mandir}/man8/user*.8* +%{_mandir}/man8/pwck.8* +%{_mandir}/man8/grpck.8* +%{_mandir}/man8/chpasswd.8* +%{_mandir}/man8/newusers.8* +%{_mandir}/man8/*conv.8* +%{_mandir}/man8/lastlog.8* +%{_mandir}/man8/vipw.8* +%{_mandir}/man8/vigr.8* + +%changelog +* Fri Feb 1 2019 Tomáš Mráz - 2:4.1.5.1-25.1 +- re-allow all numeric usernames when SHADOW_ALLOW_ALL_NUMERIC_USER + environment variable is set (#1651450) + +* Tue Apr 24 2018 Tomáš Mráz - 2:4.1.5.1-25 +- prevent creating users ".." or "." or with all numeric usernames (#1373645) +- raise limit for passwd and shadow entry length but also prevent + writing longer entries (#1422497) +- consider also supplementary group membership in newgrp (#1425078) + +* Tue Jun 28 2016 Tomáš Mráz - 2:4.1.5.1-24 +- useradd: fix typo in japanese translation (#1202629) + +* Tue Jun 14 2016 Tomáš Mráz - 2:4.1.5.1-23 +- guard for localtime() and gmtime() failure (#1341167) + +* Mon May 30 2016 Tomáš Mráz - 2:4.1.5.1-22 +- chpasswd: add selinux_check_access() call (#1336902) + +* Wed May 4 2016 Tomáš Mráz - 2:4.1.5.1-20 +- usermod: guard against unsafe change of ownership of + special home directories (#1225560) + +* Thu Apr 28 2016 Tomáš Mráz - 2:4.1.5.1-19 +- documentation fixes (#1292820) +- usermod: make password unlocking compatible with passwd (#1185425) +- usermod: disallow ':' in raw password setting (#1292815) +- improve the gid and uid allocation mechanism (#1279321) +- lastlog: add options to unexpire unused accounts (#1285547) + +* Tue Nov 25 2014 Tomáš Mráz - 2:4.1.5.1-18 +- properly audit modification of gshadow + +* Fri Oct 17 2014 Tomáš Mráz - 2:4.1.5.1-16 +- update auditing to cover more events and fix some incorrect audit + records - patch by Steve Grubb (#1151580) + +* Wed Sep 10 2014 Tomas Mraz - 2:4.1.5.1-15 +- discard obsolete matchpathcon cache after semanage_commit() + +* Fri Aug 29 2014 Tomas Mraz - 2:4.1.5.1-14 +- label the newly created home dir correctly (#1077809) +- mention that chage -d 0 forces password change (#1135010) +- improve date parsing and error detecting in chage +- avoid full group database scanning in newgrp in most common case +- report error if usermod asked for moving homedir and it does not exist + +* Wed Feb 12 2014 Tomas Mraz - 2:4.1.5.1-13 +- clean up login.defs manpage +- properly document userdel -f behavior + +* Fri Jan 24 2014 Daniel Mach - 2:4.1.5.1-11 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 2:4.1.5.1-10 +- Mass rebuild 2013-12-27 + +* Fri Oct 18 2013 Tomas Mraz - 2:4.1.5.1-9 +- document that the directory where user's home is created must exist + +* Thu Jul 25 2013 Tomas Mraz - 2:4.1.5.1-8 +- slightly more meaningful error messages if crypt() returns NULL (#988184) +- explicit suid permissions + +* Fri Jul 19 2013 Tomas Mraz - 2:4.1.5.1-7 +- fix useradd man page bugs + +* Fri Jun 14 2013 Tomas Mraz - 2:4.1.5.1-6 +- report error to stdout when SELinux context for home directory + cannot be determined (#973647) +- audit the changing home directory owner (#885797) +- do not set the default SELinux MLS range (#852676) + +* Tue Mar 19 2013 Tomas Mraz - 2:4.1.5.1-5 +- improve the failure syslog message in useradd (#830617) + +* Wed Feb 20 2013 Tomas Mraz - 2:4.1.5.1-4 +- keep the original context if matchpathcon() fails (#912399) + +* Tue Jan 29 2013 Tomas Mraz - 2:4.1.5.1-3 +- fix bugs in merge_group_entries() + +* Fri Jan 11 2013 Tomas Mraz - 2:4.1.5.1-2 +- /etc/default is owned by glibc-common now (#894194) + +* Wed Sep 19 2012 Tomas Mraz - 2:4.1.5.1-1 +- new upstream version +- use the original file permissions when creating backup (#853102) + +* Wed Jul 25 2012 Peter Vrabec - 2:4.1.5-5 +- make /etc/default/useradd world-readable (#835137) + +* Sat Jul 21 2012 Fedora Release Engineering - 2:4.1.5-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jun 18 2012 Peter Vrabec - 2:4.1.5-3 +- pwconv/grpconv skipped 2nd of consecutive failures (#832995) + +* Thu Mar 22 2012 Peter Vrabec - 2:4.1.5-2 +- fix selinux context handling +- reset selinux context on files copied from skel + +* Mon Mar 19 2012 Peter Vrabec - 2:4.1.5-1 +- upgrade + +* Tue Feb 07 2012 Peter Vrabec - 2:4.1.4.3-14 +- compile with PIE and RELRO flags (#784349) + +* Sat Jan 14 2012 Fedora Release Engineering - 2:4.1.4.3-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 20 2011 Peter Vrabec - 2:4.1.4.3-12 +- fix leaks in .IDs patch (#734340) + +* Wed Nov 16 2011 Peter Vrabec - 2:4.1.4.3-11 +- free memory associated with SELinux security contexts + +* Wed Nov 09 2011 Peter Vrabec - 2:4.1.4.3-10 +- replace semanage call by library call +- useradd man page (#739147) + +* Tue Aug 02 2011 Peter Vrabec - 2:4.1.4.3-9 +- man page adjustment (userdel -Z) + +* Tue Aug 02 2011 Peter Vrabec - 2:4.1.4.3-8 +- fixing semanage issue (#701355) + +* Fri Jul 22 2011 Miloslav Trmač - 2:4.1.4.3-7 +- Make sure /etc/login.defs is not changed on upgrades from Fedora 1[345]. + +* Wed Jun 29 2011 Peter Vrabec - 2:4.1.4.3-6 +- man page fixes (#696213 #674878) + +* Tue Jun 28 2011 Peter Vrabec - 2:4.1.4.3-5 +- userdel option to remove Linux login <-> SELinux login mapping (#639900) +- useradd special exit value if SELinux user mapping is invalid (#639975) +- usermod special exit value if SELinux user mapping is invalid (#639976) + +* Mon Jun 27 2011 Peter Vrabec - 2:4.1.4.3-4 +- refer to PAM in /etc/login.defs (#629277) + +* Mon Jun 06 2011 Peter Vrabec - 2:4.1.4.3-3 +- fix shadow-4.1.4.2-underflow.patch + +* Tue May 31 2011 Peter Vrabec - 2:4.1.4.3-2 +- fix integer underflow in laslog (#706321) + +* Fri May 20 2011 Peter Vrabec - 2:4.1.4.3-1 +- upgrade +- change UID/GID_MIN to #1000 +- fix find_new_uid/gid for big UID/GID_MAX + +* Wed Feb 09 2011 Peter Vrabec - 2:4.1.4.2-11 +- useradd man page (-m option) +- create home directory on fs with noacl +- remove faillog app (pam_tally.so is no longer shipped) + Resolves: #523265, #622320 + +* Tue Feb 01 2011 Peter Vrabec - 2:4.1.4.2-10 +- do not use gshadow functions from glibc, there is a bug + in glibc sgetsgent(#674361) + Resolves: #674234 + +* Wed Jan 05 2011 Peter Vrabec - 2:4.1.4.2-9 +- fix gshadow functions from shadow utils +- make shadow utils use gshadow functions from glibc + Resolves: #665780 + +* Tue Jul 20 2010 Peter Vrabec - 2:4.1.4.2-8 +- fix pwck/grpck hang + Resolves: #586322 + +* Mon Jun 14 2010 Peter Vrabec - 2:4.1.4.2-7 +- fix integer underflow in faillog (#603683) +- use preferred GID for reserved static IDs + +* Thu Apr 29 2010 Peter Vrabec - 2:4.1.4.2-6 +- preserve ACL's on files in /etc/skel + Resolves: #513055 + +* Wed Apr 28 2010 Peter Vrabec - 2:4.1.4.2-5 +- newusers man page more informative +- userdel should not need to run semanage + Resolves: #586330 #586408 + +* Thu Apr 01 2010 Peter Vrabec - 2:4.1.4.2-4 +- fix man directories ownership (#569418) + +* Fri Mar 26 2010 Peter Vrabec - 2:4.1.4.2-3 +- max group name length set to 32 characters + +* Wed Nov 18 2009 Peter Vrabec - 2:4.1.4.2-2 +- apply patches{1,2,3} +- enable SHA512 in /etc/login.defs + +* Mon Sep 07 2009 Peter Vrabec - 2:4.1.4.2-1 +- upgrade + +* Fri Aug 21 2009 Tomas Mraz - 2:4.1.4.1-7 +- rebuilt with new audit + +* Wed Aug 05 2009 Peter Vrabec 2:4.1.4.1-6 +- increase threshold for uid/gid reservations to 200 (#515667) + +* Sun Jul 26 2009 Fedora Release Engineering - 2:4.1.4.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jul 16 2009 Peter Vrabec 2:4.1.4.1-4 +- fix a list of owned directories (#510366) + +* Thu Jul 16 2009 Peter Vrabec 2:4.1.4.1-3 +- reduce the reuse of system IDs + +* Wed Jul 15 2009 Peter Vrabec 2:4.1.4.1-2 +- speed up sys users look up on LDAP boxes (#511813) + +* Tue Jun 16 2009 Peter Vrabec 2:4.1.4.1-1 +- upgrade + +* Fri May 15 2009 Peter Vrabec 2:4.1.4-1 +- upgrade + +* Wed Apr 22 2009 Peter Vrabec 2:4.1.3.1-2 +- lastlog fix + +* Fri Apr 17 2009 Peter Vrabec 2:4.1.3.1-1 +- upgrade + +* Tue Apr 14 2009 Peter Vrabec 2:4.1.3-2 +- get "-n" option back +- fix selinux issues + +* Tue Apr 14 2009 Peter Vrabec 2:4.1.3-1 +- upgrade + +* Tue Mar 24 2009 Peter Vrabec 2:4.1.2-12 +- don not allow UID/GID = 4294967295 (#484040) + +* Mon Jan 19 2009 Peter Vrabec 2:4.1.2-11 +- fix license tag (#226416) +- get rid of tabs in spec file (#226416) +- convert HOWTO to UTF8 (#226416) + +* Mon Jan 05 2009 Peter Vrabec 2:4.1.2-10 +- Add policycoreutils as Requires, because of restorecon (#478494) + +* Sun Dec 21 2008 Jesse Keating - 2:4.1.2-9 +- Add setup as a Requires. Perhaps this should be a files requires. (#477529) + +* Wed Sep 24 2008 Peter Vrabec 2:4.1.2-8 +- groupmems: check username for valid character (#455603) +- groupmems: don't segfault on nonexistent group (#456088) + +* Thu Sep 11 2008 Peter Vrabec 2:4.1.2-7 +- fix usermod SELinux user mappings change (#458766) + +* Tue Sep 02 2008 Peter Vrabec 2:4.1.2-6 +- audit improvements, thnx. to sgrubb@redhat.com + +* Tue Sep 02 2008 Peter Vrabec 2:4.1.2-5 +- fix groupmems issues (#459825) + +* Mon Jul 28 2008 Peter Vrabec 2:4.1.2-4 +- fix configure options (#456748) + +* Thu Jul 24 2008 Peter Vrabec 2:4.1.2-3 +- recreate selinux patch + +* Tue Jul 22 2008 Peter Vrabec 2:4.1.2-2 +- provide getspnam by man-pages + +* Mon May 26 2008 Peter Vrabec 2:4.1.2-1 +- upgrade + +* Tue May 20 2008 Peter Vrabec 2:4.1.1-2 +- fix salt size problem (#447136) + +* Mon Apr 07 2008 Peter Vrabec 2:4.1.1-1 +- upgrade + +* Fri Mar 07 2008 Peter Vrabec 2:4.1.0-5 +- improve newgrp audit patch + +* Mon Mar 03 2008 Peter Vrabec 2:4.1.0-4 +- fix selinux labeling (#433757) + +* Tue Feb 19 2008 Peter Vrabec 2:4.1.0-3 +- fix groupmems segmentation fault (#430813) + +* Wed Feb 13 2008 Peter Vrabec 2:4.1.0-2 +- fix newgrp audit event + +* Wed Dec 12 2007 Peter Vrabec 2:4.1.0-1 +- new upgrade release from new upstream +- provide vipw and vigr + +* Thu Nov 29 2007 Peter Vrabec 2:4.0.18.1-20 +- do not create mail spool entries for system accounts (#402351) + +* Thu Oct 18 2007 Peter Vrabec 2:4.0.18.1-19 +- fix timestamps when moving home dirs to another file system (#278571) + +* Mon Oct 08 2007 Peter Vrabec 2:4.0.18.1-18 +- mark localized man pages with %%lang + +* Wed Aug 22 2007 Peter Vrabec 2:4.0.18.1-17 +- rebuild + +* Tue Jun 26 2007 Peter Vrabec 2:4.0.18.1-16 +- fix "CAVEATS" section of groupadd man page (#245590) + +* Wed Jun 06 2007 Peter Vrabec 2:4.0.18.1-15 +- fix infinitive loop if there are duplicate entries + in /etc/group (#240915) + +* Wed Jun 06 2007 Peter Vrabec 2:4.0.18.1-14 +- do not run find_new_uid() twice and use getpwuid() to check + UID uniqueness (#236871) + +* Tue Apr 10 2007 Peter Vrabec 2:4.0.18.1-13 +- fix useradd dump core when build without WITH_SELINUX (#235641) + +* Mon Mar 26 2007 Peter Vrabec 2:4.0.18.1-12 +- create user's mailbox file by default (#231311) + +* Fri Mar 16 2007 Peter Vrabec 2:4.0.18.1-11 +- assign system dynamic UID/GID from the top of available UID/GID (#190523) + +* Wed Feb 28 2007 Peter Vrabec 2:4.0.18.1-10 +- spec file fixes to meet fedora standarts. +- fix useless call of restorecon(). (#222159) + +* Sun Jan 14 2007 Peter Vrabec 2:4.0.18.1-9 +- fix append option in usermod (#222540). + +* Thu Dec 21 2006 Dan Walsh 2:4.0.18.1-8 +- Fix execution and creation of Home Directories under SELinux +- Resolves: rhbz#217441 + +* Thu Dec 14 2006 Peter Vrabec 2:4.0.18.1-7 +- fix rpmlint issues + +* Wed Dec 06 2006 Peter Vrabec 2:4.0.18.1-6 +- use MD5 encryption by default (#218629). + +* Thu Nov 30 2006 Steve Grubb 2:4.0.18.1-5 +- Fix SELinux context on home directories created with useradd (#217441) + +* Tue Nov 14 2006 Peter Vrabec 2:4.0.18.1-4 +- fix chpasswd and chgpasswd stack overflow (#213052) + +* Sat Nov 04 2006 Peter Vrabec 2:4.0.18.1-3 +- fix "-g" and "-G" option. + +* Fri Nov 03 2006 Peter Vrabec 2:4.0.18.1-2 +- improve audit logging (#211659) +- improve "-l" option. Do not reset faillog if it's used (#213450). + +* Wed Nov 01 2006 Peter Vrabec 2:4.0.18.1-1 +- upgrade + +* Wed Oct 25 2006 Peter Vrabec 2:4.0.17-7 +- add dist-tag + +* Wed Oct 04 2006 Peter Vrabec 2:4.0.17-6 +- fix regression. Permissions on user* group* binaries + should be 0750, because of CAPP/LSPP certification +- fix groupdel man page + +* Fri Aug 11 2006 Peter Vrabec 2:4.0.17-5 +- fix bug introduced with UIG_GID.patch (#201991) + +* Sat Aug 05 2006 Peter Vrabec 2:4.0.17-4 +- fix userdel, it didn't delete user's group (#201379) + +* Fri Aug 04 2006 Peter Vrabec 2:4.0.17-3 +- fix UID/GID overflow in user* group* (#198920) + +* Fri Aug 04 2006 Peter Vrabec 2:4.0.17-2 +- do not inherit file desc. in execve(nscd) + +* Mon Jul 17 2006 Peter Vrabec 2:4.0.17-1 +- upgrade + +* Wed Jul 12 2006 Jesse Keating - 2:4.0.16-3.1 +- rebuild + +* Tue Jun 13 2006 Peter Vrabec 2:4.0.16-3 +- call "nscd -i" to flush nscd cache (#191464) + +* Sat Jun 10 2006 Peter Vrabec 2:4.0.16-2 +- "useradd -r" must create a system group (#194728) + +* Tue Jun 06 2006 Peter Vrabec 2:4.0.16-1 +- upgrade +- do not replace login.defs file (#190014) + +* Sat Apr 08 2006 Peter Vrabec 2:4.0.15-3 +- fix typo in shadow-4.0.15-login.defs (#188263) + +* Tue Apr 04 2006 Peter Vrabec 2:4.0.15-2 +- properly notify nscd to flush its cache(#186803) + +* Mon Apr 03 2006 Peter Vrabec 2:4.0.15-1 +- upgrade + +* Fri Mar 10 2006 Peter Vrabec 2:4.0.14-4 +- fix lrename() function to handle relative symlinks too + +* Tue Mar 07 2006 Peter Vrabec 2:4.0.14-3 +- set default umask to 077 in login.defs + +* Mon Mar 06 2006 Peter Vrabec 2:4.0.14-2 +- use lrename() function, which follow a destination symbolic link(#181977) + +* Fri Feb 10 2006 Jesse Keating - 2:4.0.14-1.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 2:4.0.14-1.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Jan 06 2006 Peter Vrabec 2:4.0.14-1 +- upgrade + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Tue Nov 29 2005 Peter Vrabec 2:4.0.13-4 +- fix incorrect audit record in userdel (#174392) + +* Wed Nov 16 2005 Peter Vrabec 2:4.0.13-3 +- fix useradd segfaults (#173241) + +* Sat Nov 5 2005 Steve Grubb 2:4.0.13-2 +- Update audit communication to standard format messages + +* Fri Oct 21 2005 Peter Vrabec 2:4.0.13-1 +- upgrade + +* Fri Sep 23 2005 Peter Vrabec 2:4.0.12-4 +- add useradd -l option back, it was removed by mistake + +* Tue Sep 20 2005 Peter Vrabec 2:4.0.12-3 +- provide login.defs man page +- adjust audit patch + +* Tue Aug 30 2005 Peter Vrabec 2:4.0.12-2 +- audit support + +* Sat Aug 27 2005 Peter Vrabec 2:4.0.12-1 +- upgrade + +* Sat Aug 13 2005 Dan Walsh 2:4.0.11.1-5 +- Change to use new selinux api for selinux_check_passwd_access + +* Tue Aug 09 2005 Peter Vrabec 2:4.0.11.1-4 +- change the password last changed field in the shadow file + when "usermod -p" is used (#164943) + +* Mon Aug 08 2005 Peter Vrabec 2:4.0.11.1-3 +- provide getspnam.3 man page(#162476) +- fix useradd man page(#97131) + +* Mon Aug 08 2005 Peter Vrabec 2:4.0.11.1-2 +- do not copy files from skel directory if home directory + already exist (#89591,#80242) + +* Fri Aug 05 2005 Peter Vrabec 2:4.0.11.1-1 +- upgrade + +* Mon May 23 2005 Peter Vrabec 2:4.0.7-9 +- remove vigr binary + +* Mon May 23 2005 Peter Vrabec 2:4.0.7-8 +- fix nscd socket path + +* Fri Apr 29 2005 Jeremy Katz - 2:4.0.7-7 +- don't assume selinux is enabled if is_selinux_enabled() returns -1 + +* Mon Apr 18 2005 Peter Vrabec 2:4.0.7-6 +- fix chage -l option (#109499, #137498) + +* Mon Apr 04 2005 Peter Vrabec 2:4.0.7-5 +- fix memory leak, and CPU spinning when grp_update() and + duplicate group entries in /etc/group (#151484) + +* Tue Mar 29 2005 Peter Vrabec 2:4.0.7-4 +- use newgrp binary +- newgrp don't ask for password if user's default GID = group ID, + ask for password if there is some in /etc/gshadow + and in /etc/group is 'x' (#149997) + +* Mon Mar 14 2005 Peter Vrabec +- gcc4 fix (#150994) 2:4.0.7-3 + +* Mon Mar 07 2005 Peter Vrabec +- man pages cs,es,ko,ru,zh_CN,zh_TW to UTF-8 + +* Wed Mar 02 2005 Peter Vrabec +- upgrade 2:4.0.7-1 + +* Fri Feb 25 2005 Peter Vrabec 2:4.0.3-59 +- static limit on group count to dynamic (#125510, #148994, #147742) + +* Mon Feb 21 2005 Peter Vrabec 2:4.0.3-58 +- add "-l" option #146214 + +* Mon Feb 14 2005 Adrian Havill +- rebuilt + +* Wed Feb 9 2005 Dan Walsh 2:4.0.3-39 +- Change useradd to use matchpathcon + +* Thu Oct 21 2004 Dan Walsh 2:4.0.3-37 +- Add matchpathcon to create the files correctly when they do not exist. + +* Mon Oct 18 2004 Miloslav Trmac - 2:4.0.3-36 +- Change symlink ownership when copying from /etc/skel (#66819, patch by + Michael Weiser) + +* Fri Oct 15 2004 Adrian Havill 2:4.0.3-35 +- make the limit for the group name the same as the username (determined + by the header files, rather than a constant) (#56850) + +* Wed Oct 13 2004 Adrian Havill 2:4.0.3-33 +- allow for mixed case and dots in usernames (#135401) +- all man pages to UTF-8, not just Japanese (#133883) +- add Polish blurb for useradd -n man page option (#82177) + +* Tue Oct 12 2004 Adrian Havill 2:4.0.3-31 +- check for non-standard legacy place for ncsd HUP (/var/run/nscd.pid) and + then the std FHS place (/var/run/nscd.pid) (#125421) + +* Fri Oct 1 2004 Dan Walsh 2:4.0.3-30 +- Add checkPasswdAccess for chage in SELinux + +* Sun Sep 26 2004 Adrian Havill 2:4.0.3-29 +- always unlock all files on any exit (#126709) + +* Tue Aug 24 2004 Warren Togami 2:4.0.3-26 +- #126596 fix Req and BuildReqs + +* Sun Aug 1 2004 Alan Cox 4.0.3-25 +- Fix build deps etc, move to current auto* (Steve Grubb) + +* Sat Jul 10 2004 Alan Cox 4.0.3-24 +- Fix nscd path. This fixes various stale data caching bugs (#125421) + +* Thu Jun 17 2004 Dan Walsh 4.0.3-23 +- Add get_enforce checks +- Clean up patch for potential upstream submission +- Add removemalloc patch to get it to build on 3.4 + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Mar 30 2004 Nalin Dahyabhai 4.0.3-21 +- rebuild + +* Tue Mar 30 2004 Nalin Dahyabhai 4.0.3-20 +- make /etc/default world-readable, needed for #118338 + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Wed Jan 21 2004 Dan Walsh 4.0.3-18 +- Fix selinux relabel of /etc/passwd file + +* Wed Jan 7 2004 Nalin Dahyabhai 4.0.3-17 +- fix use of uninitialized memory in useradd (#89145) + +* Tue Dec 16 2003 Nalin Dahyabhai 4.0.3-16 +- back to UTF-8 again +- remove getspnam(3) man page, now conflicts with man-pages 1.64 + +* Thu Nov 13 2003 Nalin Dahyabhai 4.0.3-15 +- don't convert man pages to UTF-8 for RHEL 3, conditionalized using macro +- fixup dangling man page references + +* Mon Nov 10 2003 Nalin Dahyabhai 4.0.3-14 +- lastlog: don't pass a possibly-smaller field to localtime (#109648) +- configure: call AC_SYS_LARGEFILE to get large file support + +* Fri Nov 7 2003 Dan Walsh 4.0.3-13.sel +- turn on SELinux support + +* Wed Oct 22 2003 Nalin Dahyabhai 4.0.3-12 +- convert ja man pages to UTF-8 (#106051) +- override MKINSTALLDIRS at install-time (#107476) + +* Mon Sep 8 2003 Dan Walsh +- turn off SELinux support + +* Thu Sep 4 2003 Dan Walsh 4.0.3-11.sel +- build with SELinux support + +* Mon Jul 28 2003 Dan Walsh 4.0.3-10 +- Add SELinux support + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed Jun 4 2003 Nalin Dahyabhai 4.0.3-8 +- rebuild + +* Tue Jun 3 2003 Nalin Dahyabhai 4.0.3-7 +- run autoconf to generate updated configure at compile-time + +* Wed Feb 12 2003 Nalin Dahyabhai 4.0.3-6 +- adjust mailspool patch to complain if no group named "mail" exists, even + though that should never happen + +* Tue Feb 11 2003 Nalin Dahyabhai 4.0.3-5 +- fix perms on mailspools created by useradd to be owned by the "mail" + group (#59810) + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Mon Dec 9 2002 Nalin Dahyabhai 4.0.3-3 +- install the shadow.3 man page + +* Mon Nov 25 2002 Nalin Dahyabhai 4.0.3-2 +- disable use of cracklib at build-time +- fixup reserved-account changes for useradd + +* Thu Nov 21 2002 Nalin Dahyabhai 4.0.3-1 +- update to 4.0.3, bumping epoch + +* Mon Nov 18 2002 Nalin Dahyabhai 20000902-14 +- remove man pages which conflict with the man-pages package(s) + +* Fri Nov 15 2002 Nalin Dahyabhai 20000902-13 +- prevent libshadow from being built more than once, to keep automake happy +- change how md5 and md5crypt are enabled, to keep autoconf happy +- remove unpackaged files after %%install + +* Thu Aug 29 2002 Nalin Dahyabhai 20000902-12 +- force .mo files to be regenerated with current gettext to flush out possible + problems +- fixup non-portable encodings in translations +- make sv translation header non-fuzzy so that it will be included (#71281) + +* Fri Aug 23 2002 Nalin Dahyabhai 20000902-11 +- don't apply aging parameters when creating system accounts (#67408) + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Fri May 17 2002 Nalin Dahyabhai 20000902-8 +- rebuild in new environment + +* Wed Mar 27 2002 Nalin Dahyabhai 20000902-7 +- rebuild with proper defines to get support for large lastlog files (#61983) + +* Fri Feb 22 2002 Nalin Dahyabhai 20000902-6 +- rebuild + +* Fri Jan 25 2002 Nalin Dahyabhai 20000902-5 +- fix autoheader breakage and random other things autotools complain about + +* Mon Aug 27 2001 Nalin Dahyabhai 20000902-4 +- use -O0 instead of -O on ia64 +- build in source directory +- don't leave lock files on the filesystem when useradd creates a group for + the user (#50269) +- fix the -o option to check for duplicate UIDs instead of login names (#52187) + +* Thu Jul 26 2001 Bill Nottingham 20000902-3 +- build with -O on ia64 + +* Fri Jun 08 2001 Than Ngo 20000902-2 +- fixup broken specfile + +* Tue May 22 2001 Bernhard Rosenkraenzer 20000902-1 +- Create an empty mailspool when creating a user so non-setuid/non-setgid + MDAs (postfix+procmail) can deliver mail (#41811) +- 20000902 +- adapt patches + +* Fri Mar 9 2001 Nalin Dahyabhai +- don't overwrite user dot files in useradd (#19982) +- truncate new files when moving overwriting files with the contents of other + files while moving directories (keeps files from looking weird later on) +- configure using %%{_prefix} as the prefix + +* Fri Feb 23 2001 Trond Eivind Glomsrxd +- langify + +* Wed Aug 30 2000 Bernhard Rosenkraenzer +- Fix up chage behavior (Bug #15883) + +* Wed Aug 30 2000 Bernhard Rosenkraenzer +- 20000826 +- Fix up useradd man page (Bug #17036) + +* Tue Aug 8 2000 Bernhard Rosenkraenzer +- check for vipw lock before adding or deleting users (Bug #6489) + +* Mon Aug 7 2000 Nalin Dahyabhai +- take LOG_CONS out of the openlog() call so that we don't litter the + screen during text-mode upgrades + +* Tue Jul 18 2000 Bernhard Rosenkraenzer +- Remove a fixed-size buffer that caused problems when adding a huge number + of users to a group (>8192 bytes) (Bugs #3809, #11930) + +* Tue Jul 18 2000 Bernhard Rosenkraenzer +- remove dependency on util-linux because it causes prereq loops + +* Tue Jul 18 2000 Nalin Dahyabhai +- change symlinked man pages to includers +- require /usr/bin/newgrp (util-linux) so that /usr/bin/sg isn't left dangling + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Sun Jun 18 2000 Matt Wilson +- use mandir for FHS +- added patches in src/ and po/ to honor DESTDIR +- use make install DESTDIR=$RPM_BUILD_ROOT + +* Wed Feb 16 2000 Bernhard Rosenkraenzer +- Fix up usermod's symlink behavior (Bug #5458) + +* Fri Feb 11 2000 Cristian Gafton +- get rid of mkpasswd + +* Mon Feb 7 2000 Nalin Dahyabhai +- fix usermod patch to check for shadow before doing any shadow-specific stuff + and merge it into the pwlock patch + +* Sat Feb 5 2000 Bernhard Rosenkraenzer +- fix man symlinks + +* Wed Feb 2 2000 Nalin Dahyabhai +- make -p only change shadow password (bug #8923) + +* Mon Jan 31 2000 Cristian Gafton +- rebuild to fix dependeencies +- man pages are compressed + +* Wed Jan 19 2000 Bernhard Rosenkraenzer +- Fix a security bug (adduser could overwrite previously existing + groups, Bug #8609) + +* Sun Jan 9 2000 Bernhard Rosenkraenzer +- unset LINGUAS before building +- Fix typo in newusers manpage (Bug #8258) +- libtoolize + +* Wed Sep 22 1999 Cristian Gafton +- fix segfault for userdel when the primary group for the user is not + defined + +* Tue Sep 21 1999 Cristian Gafton +- Serial: 1 because now we are using 19990827 (why the heck can't they have + a normal version just like everybody else?!) +- ported all patches to the new code base + +* Thu Apr 15 1999 Bill Nottingham +- SIGHUP nscd from usermod, too + +* Fri Apr 09 1999 Michael K. Johnson +- added usermod password locking from Chris Adams + +* Thu Apr 08 1999 Bill Nottingham +- have things that modify users/groups SIGHUP nscd on exit + +* Wed Mar 31 1999 Michael K. Johnson +- have userdel remove user private groups when it is safe to do so +- allow -f to force user removal even when user appears busy in utmp + +* Tue Mar 23 1999 Preston Brown +- edit out unused CHFN fields from login.defs. + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 7) + +* Wed Jan 13 1999 Bill Nottingham +- configure fix for arm + +* Wed Dec 30 1998 Cristian Gafton +- build against glibc 2.1 + +* Fri Aug 21 1998 Jeff Johnson +- Note that /usr/sbin/mkpasswd conflicts with /usr/bin/mkpasswd; + one of these (I think /usr/sbin/mkpasswd but other opinions are valid) + should probably be renamed. In any case, mkpasswd.8 from this package + needs to be installed. (problem #823) + +* Fri May 08 1998 Prospector System +- translations modified for de, fr, tr + +* Tue Apr 21 1998 Cristian Gafton +- updated to 980403 +- redid the patches + +* Tue Dec 30 1997 Cristian Gafton +- updated the spec file +- updated the patch so that new accounts created on shadowed system won't + confuse pam_pwdb anymore ('!!' default password instead on '!') +- fixed a bug that made useradd -G segfault +- the check for the ut_user is now patched into configure + +* Thu Nov 13 1997 Erik Troan +- added patch for XOPEN oddities in glibc headers +- check for ut_user before checking for ut_name -- this works around some + confusion on glibc 2.1 due to the utmpx header not defining the ut_name + compatibility stuff. I used a gross sed hack here because I couldn't make + automake work properly on the sparc (this could be a glibc 2.0.99 problem + though). The utuser patch works fine, but I don't apply it. +- sleep after running autoconf + +* Thu Nov 06 1997 Cristian Gafton +- added forgot lastlog command to the spec file + +* Mon Oct 27 1997 Cristian Gafton +- obsoletes adduser + +* Thu Oct 23 1997 Cristian Gafton +- modified groupadd; updated the patch + +* Fri Sep 12 1997 Cristian Gafton +- updated to 970616 +- changed useradd to meet RH specs +- fixed some bugs + +* Tue Jun 17 1997 Erik Troan +- built against glibc