diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/.gitignore b/.gitignore index 422ed12..3023995 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,33 @@ shadow-4.1.4.2.tar.bz2 /shadow-4.13.tar.xz.asc /shadow-4.14.0.tar.xz /shadow-4.14.0.tar.xz.asc +/shadow-4.15.0rc2.tar.xz +/shadow-4.15.0rc2.tar.xz.asc +/shadow-4.15.0rc3.tar.xz +/shadow-4.15.0rc3.tar.xz.asc +/shadow-4.15.0.tar.xz +/shadow-4.15.0.tar.xz.asc +/shadow-4.15.1.tar.xz +/shadow-4.15.1.tar.xz.asc +/shadow-4.16.0.tar.xz +/shadow-4.16.0.tar.xz.asc +/shadow-4.17.0-rc1.tar.xz +/shadow-4.17.0-rc1.tar.xz.asc +/shadow-4.17.0.tar.xz +/shadow-4.17.0.tar.xz.asc +/shadow-4.17.4.tar.xz +/shadow-4.17.4.tar.xz.asc +/shadow-4.18.0.tar.xz +/shadow-4.18.0.tar.xz.asc +/shadow-4.19.0.tar.xz +/shadow-4.19.0.tar.xz.asc +/shadow-4.19.2.tar.xz +/shadow-4.19.2.tar.xz.asc +/shadow-4.19.3.tar.xz +/shadow-4.19.3.tar.xz.asc +/shadow-4.20.0-rc2.tar.xz +/shadow-4.20.0-rc2.tar.xz.asc +/shadow-4.20.0-rc3.tar.xz +/shadow-4.20.0-rc3.tar.xz.asc +/shadow-4.20.0.tar.xz +/shadow-4.20.0.tar.xz.asc diff --git a/passwd.pamd b/passwd.pamd new file mode 100644 index 0000000..fd03d03 --- /dev/null +++ b/passwd.pamd @@ -0,0 +1,5 @@ +#%PAM-1.0 +# This tool only uses the password stack. +password substack system-auth +-password optional pam_gnome_keyring.so use_authtok +password substack postlogin diff --git a/plans/tier0-functional.fmf b/plans/tier0-functional.fmf new file mode 100644 index 0000000..a9939b5 --- /dev/null +++ b/plans/tier0-functional.fmf @@ -0,0 +1,51 @@ +summary: Tier 0 functional tests for shadow-utils +description: | + Run comprehensive system tests for shadow-utils. These tests validate user and group + account management functionality by testing actual system operations including user + creation, password management, group operations, and verification of system files + (i.e. /etc/passwd, /etc/shadow). + +provision: + how: virtual + image: fedora + +prepare: + - name: Install general dependencies + how: install + package: + - expect + - gcc + - git + - libssh-devel + - python3-devel + - python3-pip + + - name: Setup SSH keys for localhost testing + how: shell + script: + - ssh-keygen -t rsa -f /root/.ssh/id_rsa -N "" -q + - cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys + - chmod 600 /root/.ssh/authorized_keys + - ssh-keyscan -H localhost >> /root/.ssh/known_hosts + + - name: Clone shadow repository + how: shell + script: + - git clone https://github.com/shadow-maint/shadow.git /tmp/shadow-test + + - name: Copy test topology for Fedora CI + how: shell + script: + - cp tests/mhc-fedora-ci.yaml /tmp/shadow-test/tests/system + + - name: Install test dependencies + how: shell + script: + - pip3 install -r /tmp/shadow-test/tests/system/requirements.txt + +execute: + how: tmt + duration: 30m + script: | + cd /tmp/shadow-test/tests/system + pytest --mh-config=mhc-fedora-ci.yaml --mh-lazy-ssh -v diff --git a/shadow-4.13-newidmap-support-passing-pid-as-fd.patch b/shadow-4.13-newidmap-support-passing-pid-as-fd.patch deleted file mode 100644 index 37e0d41..0000000 --- a/shadow-4.13-newidmap-support-passing-pid-as-fd.patch +++ /dev/null @@ -1,441 +0,0 @@ -From 6974df39a708abf8bafbdfa2b7827e0f70f874cb Mon Sep 17 00:00:00 2001 -From: Serge Hallyn -Date: Mon, 6 Feb 2023 22:49:42 -0600 -Subject: [PATCH] newuidmap and newgidmap: support passing pid as fd - -Closes #635 - -newuidmap and newgidmap currently take an integner pid as -the first argument, determining the process id on which to -act. Accept also "fd:N", where N must be an open file -descriptor to the /proc/pid directory for the process to -act upon. This way, if you - -exec 10 ---- - lib/get_pid.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ - lib/prototypes.h | 2 ++ - man/newgidmap.1.xml | 11 ++++++++++ - man/newuidmap.1.xml | 11 ++++++++++ - src/newgidmap.c | 41 ++++++++++++++---------------------- - src/newuidmap.c | 40 +++++++++++++---------------------- - 6 files changed, 106 insertions(+), 50 deletions(-) - -diff --git a/lib/get_pid.c b/lib/get_pid.c -index 10184bf0..ab91d158 100644 ---- a/lib/get_pid.c -+++ b/lib/get_pid.c -@@ -10,6 +10,9 @@ - - #include "prototypes.h" - #include "defines.h" -+#include -+#include -+#include - - int get_pid (const char *pidstr, pid_t *pid) - { -@@ -29,3 +32,51 @@ int get_pid (const char *pidstr, pid_t *pid) - return 1; - } - -+/* -+ * If use passed in fd:4 as an argument, then return the -+ * value '4', the fd to use. -+ */ -+int get_pidfd_from_fd(const char *pidfdstr) -+{ -+ long long int val; -+ char *endptr; -+ -+ errno = 0; -+ val = strtoll (pidfdstr, &endptr, 10); -+ if ( ('\0' == *pidfdstr) -+ || ('\0' != *endptr) -+ || (ERANGE == errno) -+ || (/*@+longintegral@*/val != (pid_t)val)/*@=longintegral@*/) { -+ return 0; -+ } -+ -+ return (int)val; -+} -+ -+int open_pidfd(const char *pidstr) -+{ -+ int proc_dir_fd; -+ int written; -+ char proc_dir_name[32]; -+ pid_t target; -+ -+ if (get_pid(pidstr, &target) == 0) -+ return -ENOENT; -+ -+ /* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */ -+ written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/", -+ target); -+ if ((written <= 0) || ((size_t)written >= sizeof(proc_dir_name))) { -+ fprintf(stderr, "snprintf of proc path failed for %u: %s\n", -+ target, strerror(errno)); -+ return -EINVAL; -+ } -+ -+ proc_dir_fd = open(proc_dir_name, O_DIRECTORY); -+ if (proc_dir_fd < 0) { -+ fprintf(stderr, _("Could not open proc directory for target %u: %s\n"), -+ target, strerror(errno)); -+ return -EINVAL; -+ } -+ return proc_dir_fd; -+} -diff --git a/lib/prototypes.h b/lib/prototypes.h -index 400d5b97..21df6f61 100644 ---- a/lib/prototypes.h -+++ b/lib/prototypes.h -@@ -160,6 +160,8 @@ extern int getlong (const char *numstr, /*@out@*/long int *result); - - /* get_pid.c */ - extern int get_pid (const char *pidstr, pid_t *pid); -+extern int get_pidfd_from_fd(const char *pidfdstr); -+extern int open_pidfd(const char *pidstr); - - /* getrange */ - extern int getrange (const char *range, -diff --git a/man/newgidmap.1.xml b/man/newgidmap.1.xml -index e4ebc69e..9b7683eb 100644 ---- a/man/newgidmap.1.xml -+++ b/man/newgidmap.1.xml -@@ -116,6 +116,17 @@ - - Note that newgidmap may be used only once for a given process. - -+ -+ Instead of an integer process id, the first argument may be -+ specified as fd:N, where the integer N -+ is the file descriptor number for the calling process's opened -+ file for /proc/[pid[. In this case, -+ newgidmap will use -+ openat2 -+ to open the gid_map file under that -+ directory, avoiding a TOCTTOU in case the process exits and -+ the pid is immediately reused. -+ - - - -diff --git a/man/newuidmap.1.xml b/man/newuidmap.1.xml -index f5cb5b48..ca917a77 100644 ---- a/man/newuidmap.1.xml -+++ b/man/newuidmap.1.xml -@@ -116,6 +116,17 @@ - - Note that newuidmap may be used only once for a given process. - -+ -+ Instead of an integer process id, the first argument may be -+ specified as fd:N, where the integer N -+ is the file descriptor number for the calling process's opened -+ file for /proc/[pid[. In this case, -+ newuidmap will use -+ openat2 -+ to open the uid_map file under that -+ directory, avoiding a TOCTTOU in case the process exits and -+ the pid is immediately reused. -+ - - - -diff --git a/src/newgidmap.c b/src/newgidmap.c -index 01d0fe90..d6d29725 100644 ---- a/src/newgidmap.c -+++ b/src/newgidmap.c -@@ -69,7 +69,7 @@ static void verify_ranges(struct passwd *pw, int ranges, - - static void usage(void) - { -- fprintf(stderr, _("usage: %s [ ] ... \n"), Prog); -+ fprintf(stderr, _("usage: %s [] [ ] ... \n"), Prog); - exit(EXIT_FAILURE); - } - -@@ -143,15 +143,12 @@ out: - */ - int main(int argc, char **argv) - { -- char proc_dir_name[32]; - char *target_str; -- pid_t target; - int proc_dir_fd; - int ranges; - struct map_range *mappings; - struct stat st; - struct passwd *pw; -- int written; - bool allow_setgroups = false; - - Prog = Basename (argv[0]); -@@ -168,25 +165,19 @@ int main(int argc, char **argv) - /* Find the process that needs its user namespace - * gid mapping set. - */ -- target_str = argv[1]; -- if (!get_pid(target_str, &target)) -- usage(); - -- /* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */ -- written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/", -- target); -- if ((written <= 0) || (written >= sizeof(proc_dir_name))) { -- fprintf(stderr, "%s: snprintf of proc path failed: %s\n", -- Prog, strerror(errno)); -- } -- -- proc_dir_fd = open(proc_dir_name, O_DIRECTORY); -- if (proc_dir_fd < 0) { -- fprintf(stderr, _("%s: Could not open proc directory for target %u\n"), -- Prog, target); -- return EXIT_FAILURE; -+ target_str = argv[1]; -+ if (strlen(target_str) > 3 && strncmp(target_str, "fd:", 3) == 0) { -+ /* the user passed in a /proc/pid fd for the process */ -+ target_str = &target_str[3]; -+ proc_dir_fd = get_pidfd_from_fd(target_str); -+ if (proc_dir_fd < 0) -+ usage(); -+ } else { -+ proc_dir_fd = open_pidfd(target_str); -+ if (proc_dir_fd < 0) -+ usage(); - } -- - /* Who am i? */ - pw = get_my_pwent (); - if (NULL == pw) { -@@ -200,8 +191,8 @@ int main(int argc, char **argv) - - /* Get the effective uid and effective gid of the target process */ - if (fstat(proc_dir_fd, &st) < 0) { -- fprintf(stderr, _("%s: Could not stat directory for target %u\n"), -- Prog, target); -+ fprintf(stderr, _("%s: Could not stat directory for process\n"), -+ Prog); - return EXIT_FAILURE; - } - -@@ -213,8 +204,8 @@ int main(int argc, char **argv) - (!getdef_bool("GRANT_AUX_GROUP_SUBIDS") && (getgid() != pw->pw_gid)) || - (pw->pw_uid != st.st_uid) || - (getgid() != st.st_gid)) { -- fprintf(stderr, _( "%s: Target %u is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), -- Prog, target, -+ fprintf(stderr, _( "%s: Target process is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), -+ Prog, - (unsigned long int)getuid(), (unsigned long int)pw->pw_uid, (unsigned long int)st.st_uid, - (unsigned long int)getgid(), (unsigned long int)pw->pw_gid, (unsigned long int)st.st_gid); - return EXIT_FAILURE; -diff --git a/src/newuidmap.c b/src/newuidmap.c -index e8798409..e99655c9 100644 ---- a/src/newuidmap.c -+++ b/src/newuidmap.c -@@ -64,7 +64,7 @@ static void verify_ranges(struct passwd *pw, int ranges, - - static void usage(void) - { -- fprintf(stderr, _("usage: %s [ ] ... \n"), Prog); -+ fprintf(stderr, _("usage: %s [|fd:] [ ] ... \n"), Prog); - exit(EXIT_FAILURE); - } - -@@ -73,15 +73,12 @@ static void usage(void) - */ - int main(int argc, char **argv) - { -- char proc_dir_name[32]; - char *target_str; -- pid_t target; - int proc_dir_fd; - int ranges; - struct map_range *mappings; - struct stat st; - struct passwd *pw; -- int written; - - Prog = Basename (argv[0]); - log_set_progname(Prog); -@@ -94,26 +91,20 @@ int main(int argc, char **argv) - if (argc < 2) - usage(); - -+ target_str = argv[1]; - /* Find the process that needs its user namespace - * uid mapping set. - */ -- target_str = argv[1]; -- if (!get_pid(target_str, &target)) -- usage(); -- -- /* max string length is 6 + 10 + 1 + 1 = 18, allocate 32 bytes */ -- written = snprintf(proc_dir_name, sizeof(proc_dir_name), "/proc/%u/", -- target); -- if ((written <= 0) || (written >= sizeof(proc_dir_name))) { -- fprintf(stderr, "%s: snprintf of proc path failed: %s\n", -- Prog, strerror(errno)); -- } -- -- proc_dir_fd = open(proc_dir_name, O_DIRECTORY); -- if (proc_dir_fd < 0) { -- fprintf(stderr, _("%s: Could not open proc directory for target %u\n"), -- Prog, target); -- return EXIT_FAILURE; -+ if (strlen(target_str) > 3 && strncmp(target_str, "fd:", 3) == 0) { -+ /* the user passed in a /proc/pid fd for the process */ -+ target_str = &target_str[3]; -+ proc_dir_fd = get_pidfd_from_fd(target_str); -+ if (proc_dir_fd < 0) -+ usage(); -+ } else { -+ proc_dir_fd = open_pidfd(target_str); -+ if (proc_dir_fd < 0) -+ usage(); - } - - /* Who am i? */ -@@ -129,8 +120,7 @@ int main(int argc, char **argv) - - /* Get the effective uid and effective gid of the target process */ - if (fstat(proc_dir_fd, &st) < 0) { -- fprintf(stderr, _("%s: Could not stat directory for target %u\n"), -- Prog, target); -+ fprintf(stderr, _("%s: Could not stat directory for target process\n"), Prog); - return EXIT_FAILURE; - } - -@@ -142,8 +132,8 @@ int main(int argc, char **argv) - (!getdef_bool("GRANT_AUX_GROUP_SUBIDS") && (getgid() != pw->pw_gid)) || - (pw->pw_uid != st.st_uid) || - (getgid() != st.st_gid)) { -- fprintf(stderr, _( "%s: Target process %u is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), -- Prog, target, -+ fprintf(stderr, _( "%s: Target process is owned by a different user: uid:%lu pw_uid:%lu st_uid:%lu, gid:%lu pw_gid:%lu st_gid:%lu\n" ), -+ Prog, - (unsigned long int)getuid(), (unsigned long int)pw->pw_uid, (unsigned long int)st.st_uid, - (unsigned long int)getgid(), (unsigned long int)pw->pw_gid, (unsigned long int)st.st_gid); - return EXIT_FAILURE; --- -2.39.2 - -From 7ff33fae6f9cd79c0e012671c37a172e9a681d0b Mon Sep 17 00:00:00 2001 -From: Serge Hallyn -Date: Fri, 24 Feb 2023 13:52:32 -0600 -Subject: [PATCH] get_pidfd_from_fd: return -1 on error, not 0 - -Fixes: 6974df39a: newuidmap and newgidmap: support passing pid as fd -Signed-off-by: Serge Hallyn ---- - lib/get_pid.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lib/get_pid.c b/lib/get_pid.c -index ab91d158..5b6d9da4 100644 ---- a/lib/get_pid.c -+++ b/lib/get_pid.c -@@ -35,6 +35,7 @@ int get_pid (const char *pidstr, pid_t *pid) - /* - * If use passed in fd:4 as an argument, then return the - * value '4', the fd to use. -+ * On error, return -1. - */ - int get_pidfd_from_fd(const char *pidfdstr) - { -@@ -47,7 +48,7 @@ int get_pidfd_from_fd(const char *pidfdstr) - || ('\0' != *endptr) - || (ERANGE == errno) - || (/*@+longintegral@*/val != (pid_t)val)/*@=longintegral@*/) { -- return 0; -+ return -1; - } - - return (int)val; --- -2.39.2 - -From 05e2adf509ba0e3779dae66a276b86927a8e1e0e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= - -Date: Fri, 24 Feb 2023 18:06:02 -0300 -Subject: [PATCH] Validate fds created by the user - -write_mapping() will do the following: - -openat(proc_dir_fd, map_file, O_WRONLY); - -An attacker could create a directory containing a symlink named -"uid_map" pointing to any file owned by root, and thus allow him to -overwrite any root-owned file. ---- - lib/get_pid.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/lib/get_pid.c b/lib/get_pid.c -index 5b6d9da4..8e5e6014 100644 ---- a/lib/get_pid.c -+++ b/lib/get_pid.c -@@ -41,6 +41,8 @@ int get_pidfd_from_fd(const char *pidfdstr) - { - long long int val; - char *endptr; -+ struct stat st; -+ dev_t proc_st_dev, proc_st_rdev; - - errno = 0; - val = strtoll (pidfdstr, &endptr, 10); -@@ -51,6 +53,21 @@ int get_pidfd_from_fd(const char *pidfdstr) - return -1; - } - -+ if (stat("/proc/self/uid_map", &st) < 0) { -+ return -1; -+ } -+ -+ proc_st_dev = st.st_dev; -+ proc_st_rdev = st.st_rdev; -+ -+ if (fstat(val, &st) < 0) { -+ return -1; -+ } -+ -+ if (st.st_dev != proc_st_dev || st.st_rdev != proc_st_rdev) { -+ return -1; -+ } -+ - return (int)val; - } - --- -2.39.2 - diff --git a/shadow-4.14.0-audit-update.patch b/shadow-4.14.0-audit-update.patch deleted file mode 100644 index 0ff7dae..0000000 --- a/shadow-4.14.0-audit-update.patch +++ /dev/null @@ -1,2105 +0,0 @@ -diff -up shadow-4.14.0/libmisc/audit_help.c.audit-update shadow-4.14.0/libmisc/audit_help.c ---- shadow-4.14.0/libmisc/audit_help.c.audit-update 2023-05-26 04:56:11.000000000 +0200 -+++ shadow-4.14.0/libmisc/audit_help.c 2023-08-04 09:30:25.206963536 +0200 -@@ -46,7 +46,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" -@@ -66,6 +66,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 -up shadow-4.14.0/libmisc/cleanup_group.c.audit-update shadow-4.14.0/libmisc/cleanup_group.c ---- shadow-4.14.0/libmisc/cleanup_group.c.audit-update 2023-05-26 04:56:11.000000000 +0200 -+++ shadow-4.14.0/libmisc/cleanup_group.c 2023-08-04 09:30:25.207963539 +0200 -@@ -61,7 +61,7 @@ void cleanup_report_mod_group (void *cle - gr_dbname (), - info->action)); - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_ACCT, log_get_progname(), -+ audit_logger (AUDIT_GRP_MGMT, log_get_progname(), - info->audit_msg, - info->name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); -@@ -79,7 +79,7 @@ void cleanup_report_mod_gshadow (void *c - sgr_dbname (), - info->action)); - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_ACCT, log_get_progname(), -+ audit_logger (AUDIT_GRP_MGMT, log_get_progname(), - info->audit_msg, - info->name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); -@@ -100,7 +100,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, log_get_progname(), -- "adding group to /etc/group", -+ "adding-group", - name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -119,8 +119,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, log_get_progname(), -- "adding group to /etc/gshadow", -+ audit_logger (AUDIT_GRP_MGMT, log_get_progname(), -+ "adding-shadow-group", - name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -142,8 +142,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, log_get_progname(), -- "removing group from /etc/group", -+ audit_logger (AUDIT_DEL_GROUP, log_get_progname(), -+ "removing-group", - name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -165,8 +165,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, log_get_progname(), -- "removing group from /etc/gshadow", -+ audit_logger (AUDIT_GRP_MGMT, log_get_progname(), -+ "removing-shadow-group", - name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -186,7 +186,7 @@ void cleanup_unlock_group (unused void * - log_get_progname(), 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 - } -@@ -206,7 +206,7 @@ void cleanup_unlock_gshadow (unused void - log_get_progname(), 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 -up shadow-4.14.0/libmisc/cleanup_user.c.audit-update shadow-4.14.0/libmisc/cleanup_user.c ---- shadow-4.14.0/libmisc/cleanup_user.c.audit-update 2023-05-26 04:56:11.000000000 +0200 -+++ shadow-4.14.0/libmisc/cleanup_user.c 2023-08-04 09:30:25.207963539 +0200 -@@ -43,7 +43,7 @@ void cleanup_report_mod_passwd (void *cl - pw_dbname (), - info->action)); - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_ACCT, log_get_progname(), -+ audit_logger (AUDIT_USER_MGMT, log_get_progname(), - info->audit_msg, - info->name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); -@@ -64,7 +64,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, log_get_progname(), -- "adding user to /etc/passwd", -+ "adding-user", - name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -83,8 +83,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, log_get_progname(), -- "adding user to /etc/shadow", -+ audit_logger (AUDIT_USER_MGMT, log_get_progname(), -+ "adding-shadow-user", - name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -103,7 +103,7 @@ void cleanup_unlock_passwd (unused void - log_get_progname(), 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 - } -@@ -122,7 +122,7 @@ void cleanup_unlock_shadow (unused void - log_get_progname(), 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 -up shadow-4.14.0/lib/prototypes.h.audit-update shadow-4.14.0/lib/prototypes.h ---- shadow-4.14.0/lib/prototypes.h.audit-update 2023-08-03 18:28:35.000000000 +0200 -+++ shadow-4.14.0/lib/prototypes.h 2023-08-04 09:30:25.207963539 +0200 -@@ -202,12 +202,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 -up shadow-4.14.0/src/chage.c.audit-update shadow-4.14.0/src/chage.c ---- shadow-4.14.0/src/chage.c.audit-update 2023-08-04 09:30:25.207963539 +0200 -+++ shadow-4.14.0/src/chage.c 2023-08-04 09:31:12.237080212 +0200 -@@ -106,8 +106,8 @@ fail_exit (int code) - - #ifdef WITH_AUDIT - if (E_SUCCESS != code) { -- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "change age", user_name, user_uid, 0); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "change-age", user_name, user_uid, SHADOW_AUDIT_FAILURE); - } - #endif - -@@ -841,10 +841,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, user_uid, 1); --#endif -+ /* Displaying fields is not of interest to audit */ - list_fields (); - fail_exit (E_SUCCESS); - } -@@ -863,39 +860,39 @@ int main (int argc, char **argv) - } - #ifdef WITH_AUDIT - else { -- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "change all aging information", -- user_name, user_uid, 1); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "change-all-aging-information", -+ user_name, user_uid, SHADOW_AUDIT_SUCCESS); - } - #endif - } else { - #ifdef WITH_AUDIT - if (Mflg) { -- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "change max age", user_name, user_uid, 1); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "change-max-age", user_name, user_uid, SHADOW_AUDIT_SUCCESS); - } - if (mflg) { -- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "change min age", user_name, user_uid, 1); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "change-min-age", user_name, 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, 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, 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, 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, user_uid, 1); - } - #endif -diff -up shadow-4.14.0/src/gpasswd.c.audit-update shadow-4.14.0/src/gpasswd.c ---- shadow-4.14.0/src/gpasswd.c.audit-update 2023-06-11 03:35:50.000000000 +0200 -+++ shadow-4.14.0/src/gpasswd.c 2023-08-04 09:30:25.207963539 +0200 -@@ -118,7 +118,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 -@@ -377,21 +377,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) { -@@ -399,13 +392,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) { -@@ -413,13 +402,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) { -@@ -427,13 +412,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) { -@@ -443,13 +424,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 - } -@@ -459,13 +436,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 - } -@@ -474,13 +447,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 - } -@@ -511,21 +480,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) { -@@ -533,13 +495,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) { -@@ -547,13 +505,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) { -@@ -561,13 +515,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) { -@@ -577,13 +527,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 - } -@@ -593,13 +539,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 - } -@@ -608,13 +550,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 -up shadow-4.14.0/src/groupadd.c.audit-update shadow-4.14.0/src/groupadd.c ---- shadow-4.14.0/src/groupadd.c.audit-update 2023-05-26 04:56:11.000000000 +0200 -+++ shadow-4.14.0/src/groupadd.c 2023-08-04 09:34:34.125581046 +0200 -@@ -114,6 +114,15 @@ usage (int status) - 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, group_id, SHADOW_AUDIT_SUCCESS); - #endif - SYSLOG ((LOG_INFO, "group added to %s: name=%s, GID=%u", -@@ -281,11 +290,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, group_id, SHADOW_AUDIT_SUCCESS); - #endif - SYSLOG ((LOG_INFO, "group added to %s: name=%s", -@@ -298,10 +307,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, 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); -@@ -319,7 +324,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); - -@@ -329,7 +334,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); - } -@@ -345,7 +350,7 @@ static void open_files (void) - if (gr_open (O_CREAT | 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 -@@ -355,7 +360,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 */ -@@ -492,7 +497,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 && (prefix_getgrgid (group_id) != NULL)) { -@@ -511,7 +516,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); - } - } - } -@@ -539,7 +544,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); -@@ -559,7 +564,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 */ -@@ -594,7 +599,7 @@ int main (int argc, char **argv) - fprintf (stderr, - _("%s: Cannot setup cleanup service.\n"), - Prog); -- exit (1); -+ fail_exit (1); - } - - /* -@@ -621,7 +626,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 -up shadow-4.14.0/src/groupdel.c.audit-update shadow-4.14.0/src/groupdel.c ---- shadow-4.14.0/src/groupdel.c.audit-update 2023-05-26 04:56:11.000000000 +0200 -+++ shadow-4.14.0/src/groupdel.c 2023-08-04 09:36:42.778900250 +0200 -@@ -87,6 +87,15 @@ usage (int status) - 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 - * -@@ -113,7 +122,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 -@@ -125,7 +134,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 */ -@@ -144,12 +153,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, group_id, SHADOW_AUDIT_SUCCESS); - #endif - SYSLOG ((LOG_INFO, -@@ -168,12 +177,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, group_id, SHADOW_AUDIT_SUCCESS); - #endif - SYSLOG ((LOG_INFO, -@@ -186,11 +195,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, group_id, SHADOW_AUDIT_SUCCESS); --#endif - SYSLOG ((LOG_INFO, "group '%s' removed\n", group_name)); - del_cleanup (cleanup_report_del_group); - } -@@ -207,7 +211,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 -@@ -216,7 +220,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); - } -@@ -234,7 +238,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) { -@@ -243,7 +247,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 */ -@@ -284,7 +288,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); - } - - /* -@@ -372,7 +376,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); -@@ -386,7 +390,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); -@@ -407,7 +411,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 */ -@@ -427,7 +431,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; -@@ -451,7 +455,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 -up shadow-4.14.0/src/groupmod.c.audit-update shadow-4.14.0/src/groupmod.c ---- shadow-4.14.0/src/groupmod.c.audit-update 2023-06-10 02:02:29.000000000 +0200 -+++ shadow-4.14.0/src/groupmod.c 2023-08-04 09:30:25.208963541 +0200 -@@ -473,7 +473,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); -@@ -496,7 +496,14 @@ static void close_files (void) - exit (E_GRP_UPDATE); - } - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_ACCT, Prog, -+ /* If both happened, log password change as its more important */ -+ if (pflg) -+ audit_logger (AUDIT_GRP_CHAUTHTOK, Prog, -+ info_gshadow.audit_msg, -+ group_name, AUDIT_NO_ID, -+ SHADOW_AUDIT_SUCCESS); -+ else -+ audit_logger (AUDIT_GRP_MGMT, Prog, - info_gshadow.audit_msg, - group_name, AUDIT_NO_ID, - SHADOW_AUDIT_SUCCESS); -@@ -519,7 +526,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); -@@ -534,8 +541,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 -diff -up shadow-4.14.0/src/newgrp.c.audit-update shadow-4.14.0/src/newgrp.c ---- shadow-4.14.0/src/newgrp.c.audit-update 2023-08-04 09:30:25.208963541 +0200 -+++ shadow-4.14.0/src/newgrp.c 2023-08-04 09:51:28.354208322 +0200 -@@ -186,10 +186,10 @@ 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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - #endif - SYSLOG ((LOG_INFO, - "Invalid password for group '%s' from '%s'", -@@ -200,10 +200,10 @@ 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, getuid (), 1); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_SUCCESS); - #endif - } - -@@ -214,17 +214,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, getuid (), 0); -- } else { -- audit_logger (AUDIT_CHGRP_ID, Prog, -- "changing", NULL, getuid (), 0); -- } --#endif - exit (EXIT_FAILURE); - } - -@@ -298,13 +287,23 @@ 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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - } else { - audit_logger (AUDIT_CHGRP_ID, Prog, -- "changing", NULL, getuid (), 0); -+ "changing", NULL, getuid (), SHADOW_AUDIT_FAILURE); - } - #endif - exit (EXIT_FAILURE); -@@ -440,7 +439,7 @@ int main (int argc, char **argv) - Prog); - #ifdef WITH_AUDIT - audit_logger (AUDIT_CHGRP_ID, Prog, -- "changing", NULL, getuid (), 0); -+ "changing", NULL, getuid (), SHADOW_AUDIT_FAILURE); - #endif - SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", - (unsigned long) getuid ())); -@@ -556,13 +555,22 @@ 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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - } else { - audit_logger (AUDIT_CHGRP_ID, Prog, -- "changing", NULL, getuid (), 0); -+ "changing", NULL, getuid (), SHADOW_AUDIT_FAILURE); - } - #endif - exit (EXIT_FAILURE); -@@ -717,9 +725,9 @@ 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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - #endif - exit (EXIT_FAILURE); - } -@@ -728,9 +736,9 @@ 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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - #endif - exit (EXIT_FAILURE); - } -@@ -744,9 +752,9 @@ int main (int argc, char **argv) - execl (SHELL, "sh", "-c", command, (char *) NULL); - #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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - #endif - perror (SHELL); - exit ((errno == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); -@@ -810,10 +818,10 @@ 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, getuid (), 1); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_SUCCESS); - #endif - /* - * Exec the login shell and go away. We are trying to get back to -@@ -837,13 +845,22 @@ 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, getuid (), 0); -+ audit_buf, NULL, getuid (), SHADOW_AUDIT_FAILURE); - } else { - audit_logger (AUDIT_CHGRP_ID, Prog, -- "changing", NULL, getuid (), 0); -+ "changing", NULL, getuid (), SHADOW_AUDIT_FAILURE); - } - #endif - exit (EXIT_FAILURE); -diff -up shadow-4.14.0/src/useradd.c.audit-update shadow-4.14.0/src/useradd.c ---- shadow-4.14.0/src/useradd.c.audit-update 2023-07-30 12:38:39.000000000 +0200 -+++ shadow-4.14.0/src/useradd.c 2023-08-04 10:02:18.851935396 +0200 -@@ -240,6 +240,8 @@ static void check_uid_range(int rflg, ui - */ - static void fail_exit (int code) - { -+ int type; -+ - if (home_added && rmdir(prefix_user_home) != 0) { - fprintf(stderr, - _("%s: %s was created, but could not be removed\n"), -@@ -250,38 +252,22 @@ static void fail_exit (int code) - if (spw_locked && 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 */ - } - if (pw_locked && 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 */ - } - if (gr_locked && 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 */ - } - #ifdef SHADOWGRP - if (sgr_locked && 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 -@@ -289,27 +275,23 @@ static void fail_exit (int code) - if (sub_uid_locked && sub_uid_unlock() == 0) { - fprintf(stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname()); - SYSLOG((LOG_ERR, "failed to unlock %s", sub_uid_dbname())); --# ifdef WITH_AUDIT -- audit_logger(AUDIT_ADD_USER, Prog, -- "unlocking subordinate user file", -- user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); --# endif - /* continue */ - } - if (sub_gid_locked && sub_gid_unlock() == 0) { - fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname()); - SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname())); --# ifdef WITH_AUDIT -- audit_logger(AUDIT_ADD_USER, Prog, -- "unlocking subordinate group file", -- user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); --# endif - /* continue */ - } - #endif /* ENABLE_SUBIDS */ - - #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 - SYSLOG((LOG_INFO, "failed adding user '%s', exit code: %d", user_name, code)); -@@ -759,7 +741,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 -@@ -1096,12 +1078,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 */ - } - -@@ -1115,18 +1091,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, -@@ -1171,12 +1141,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 */ - } - -@@ -1190,18 +1154,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, -@@ -1596,7 +1555,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 -@@ -1705,7 +1664,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 -@@ -1718,7 +1677,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 -@@ -1735,7 +1694,7 @@ static void close_files (void) - SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ())); - #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, -- "unlocking subordinate user file", -+ "unlocking-subordinate-user-file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -1749,7 +1708,7 @@ static void close_files (void) - SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ())); - #ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, -- "unlocking subordinate group file", -+ "unlocking-subordinate-group-file", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_FAILURE); - #endif -@@ -2012,7 +1971,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 -@@ -2028,7 +1987,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 -@@ -2038,7 +1997,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 -@@ -2240,11 +2199,6 @@ static void usr_update (unsigned long su - 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, user_id, SHADOW_AUDIT_FAILURE); --#endif - fail_exit (E_PW_UPDATE); - } - #ifdef ENABLE_SUBIDS -@@ -2271,7 +2225,7 @@ static void usr_update (unsigned long su - * and we can use the real ID thereafter. - */ - audit_logger (AUDIT_ADD_USER, Prog, -- "adding user", -+ "add-user", - user_name, AUDIT_NO_ID, - SHADOW_AUDIT_SUCCESS); - #endif -@@ -2365,10 +2319,6 @@ static void create_home (void) - if (mkdir(path, 0) != 0) { - fprintf(stderr, _("%s: cannot create directory %s\n"), - Prog, path); --#ifdef WITH_AUDIT -- audit_logger(AUDIT_ADD_USER, Prog, "adding home directory", -- user_name, user_id, SHADOW_AUDIT_FAILURE); --#endif - fail_exit(E_HOMEDIR); - } - if (chown(path, 0, 0) < 0) { -@@ -2393,7 +2343,7 @@ static void create_home (void) - } - 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, user_id, SHADOW_AUDIT_SUCCESS); - #endif - #ifdef WITH_SELINUX -@@ -2637,12 +2587,6 @@ int main (int argc, char **argv) - */ - if (prefix_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); - } - -@@ -2658,12 +2602,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); - } - } -@@ -2693,12 +2631,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, user_id, -- SHADOW_AUDIT_FAILURE); --#endif - fail_exit (E_UID_IN_USE); - } - } -@@ -2773,9 +2705,9 @@ 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, user_id, 0); -+ audit_logger (AUDIT_ROLE_ASSIGN, Prog, -+ "add-selinux-user-mapping", -+ user_name, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - fail_exit (E_SE_UPDATE); - } -diff -up shadow-4.14.0/src/userdel.c.audit-update shadow-4.14.0/src/userdel.c ---- shadow-4.14.0/src/userdel.c.audit-update 2023-06-10 02:02:29.000000000 +0200 -+++ shadow-4.14.0/src/userdel.c 2023-08-04 10:26:18.225695416 +0200 -@@ -204,9 +204,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, user_id, SHADOW_AUDIT_SUCCESS); -+ audit_logger_with_group (AUDIT_USER_MGMT, Prog, -+ "deleting-user-from-group", -+ user_name, user_id, ngrp->gr_name, SHADOW_AUDIT_SUCCESS); - #endif /* WITH_AUDIT */ - SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", - user_name, ngrp->gr_name)); -@@ -265,9 +265,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, user_id, SHADOW_AUDIT_SUCCESS); -+ audit_logger_with_group (AUDIT_USER_MGMT, Prog, -+ "deleting-user-from-shadow-group", -+ user_name, user_id, nsgrp->sg_name, SHADOW_AUDIT_SUCCESS); - #endif /* WITH_AUDIT */ - SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", - user_name, nsgrp->sg_name)); -@@ -343,9 +343,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, -@@ -361,9 +361,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, -@@ -525,7 +525,7 @@ static void fail_exit (int code) - - #ifdef WITH_AUDIT - audit_logger (AUDIT_DEL_USER, Prog, -- "deleting user", -+ "delete-user", - user_name, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - -@@ -544,22 +544,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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_PW_UPDATE); - } - pw_locked = true; - if (pw_open (O_CREAT | 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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_PW_UPDATE); - } - if (is_shadow_pwd) { -@@ -567,11 +557,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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_PW_UPDATE); - } - spw_locked = true; -@@ -579,11 +564,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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_PW_UPDATE); - } - } -@@ -591,21 +571,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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_GRP_UPDATE); - } - gr_locked = true; - if (gr_open (O_CREAT | 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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_GRP_UPDATE); - } - #ifdef SHADOWGRP -@@ -614,22 +584,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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_GRP_UPDATE); - } - sgr_locked= true; - if (sgr_open (O_CREAT | 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, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_GRP_UPDATE); - } - } -@@ -640,22 +600,12 @@ static void open_files (void) - fprintf (stderr, - _("%s: cannot lock %s; try again later.\n"), - Prog, sub_uid_dbname ()); --#ifdef WITH_AUDIT -- audit_logger (AUDIT_DEL_USER, Prog, -- "locking subordinate user file", -- user_name, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_SUB_UID_UPDATE); - } - sub_uid_locked = true; - if (sub_uid_open (O_CREAT | O_RDWR) == 0) { - fprintf (stderr, - _("%s: cannot open %s\n"), Prog, sub_uid_dbname ()); --#ifdef WITH_AUDIT -- audit_logger (AUDIT_DEL_USER, Prog, -- "opening subordinate user file", -- user_name, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_SUB_UID_UPDATE); - } - } -@@ -664,22 +614,12 @@ static void open_files (void) - fprintf (stderr, - _("%s: cannot lock %s; try again later.\n"), - Prog, sub_gid_dbname ()); --#ifdef WITH_AUDIT -- audit_logger (AUDIT_DEL_USER, Prog, -- "locking subordinate group file", -- user_name, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_SUB_GID_UPDATE); - } - sub_gid_locked = true; - if (sub_gid_open (O_CREAT | O_RDWR) == 0) { - fprintf (stderr, - _("%s: cannot open %s\n"), Prog, sub_gid_dbname ()); --#ifdef WITH_AUDIT -- audit_logger (AUDIT_DEL_USER, Prog, -- "opening subordinate group file", -- user_name, user_id, SHADOW_AUDIT_FAILURE); --#endif /* WITH_AUDIT */ - fail_exit (E_SUB_GID_UPDATE); - } - } -@@ -724,7 +664,7 @@ static void update_user (void) - #endif /* ENABLE_SUBIDS */ - #ifdef WITH_AUDIT - audit_logger (AUDIT_DEL_USER, Prog, -- "deleting user entries", -+ "delete-user", - user_name, user_id, SHADOW_AUDIT_SUCCESS); - #endif /* WITH_AUDIT */ - SYSLOG ((LOG_INFO, "delete user '%s'\n", user_name)); -@@ -831,7 +771,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, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - free(mailfile); -@@ -847,7 +787,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, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - errors = 1; -@@ -856,8 +796,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, user_id, SHADOW_AUDIT_SUCCESS); - } - #endif /* WITH_AUDIT */ -@@ -874,7 +814,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, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - free(mailfile); -@@ -890,7 +830,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, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - errors = 1; -@@ -899,8 +839,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, user_id, SHADOW_AUDIT_SUCCESS); - } - #endif /* WITH_AUDIT */ -@@ -1118,7 +1058,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 */ -@@ -1174,7 +1114,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 */ -@@ -1268,8 +1208,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, user_id, SHADOW_AUDIT_SUCCESS); - } - #endif /* WITH_AUDIT */ -@@ -1277,7 +1217,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); - } -@@ -1290,8 +1230,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, user_id, SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ - fail_exit (E_SE_UPDATE); -diff -up shadow-4.14.0/src/usermod.c.audit-update shadow-4.14.0/src/usermod.c ---- shadow-4.14.0/src/usermod.c.audit-update 2023-07-30 12:38:39.000000000 +0200 -+++ shadow-4.14.0/src/usermod.c 2023-08-04 10:33:04.601749324 +0200 -@@ -427,7 +427,7 @@ static char *new_pw_passwd (char *pw_pas - - #ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "updating passwd", user_newname, user_newid, 0); -+ "updating-passwd", user_newname, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, "lock user '%s' password", user_newname)); - strcpy (buf, "!"); -@@ -444,14 +444,14 @@ static char *new_pw_passwd (char *pw_pas - - #ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "updating password", user_newname, user_newid, 0); -+ "updating-password", user_newname, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, "unlock user '%s' password", user_newname)); - memmove(pw_pass, pw_pass + 1, strlen(pw_pass)); - } else if (pflg) { - #ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "changing password", user_newname, user_newid, 1); -+ "updating-password", user_newname, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, "change user '%s' password", user_newname)); - pw_pass = xstrdup (user_pass); -@@ -479,8 +479,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", user_newname, user_newid, 1); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "changing-name", user_newname, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, - "change user name '%s' to '%s'", -@@ -499,8 +499,8 @@ static void new_pwent (struct passwd *pw - - if (uflg) { - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "changing uid", user_newname, user_newid, 1); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "changing-uid", user_newname, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, - "change user '%s' UID from '%d' to '%d'", -@@ -509,8 +509,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, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, -@@ -520,16 +520,16 @@ static void new_pwent (struct passwd *pw - } - if (cflg) { - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -- "changing comment", user_newname, user_newid, 1); -+ audit_logger (AUDIT_USER_MGMT, Prog, -+ "changing-comment", user_newname, user_newid, 1); - #endif - pwent->pw_gecos = user_newcomment; - } - - 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, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, -@@ -545,8 +545,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, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, -@@ -576,8 +576,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, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, -@@ -591,8 +591,8 @@ static void new_spent (struct spwd *spen - date_to_str (sizeof(new_exp), new_exp, user_newexpire * DAY); - date_to_str (sizeof(old_exp), 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, user_newid, 1); - #endif - SYSLOG ((LOG_INFO, -@@ -677,9 +677,9 @@ fail_exit (int code) - #endif /* ENABLE_SUBIDS */ - - #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); - } -@@ -741,9 +741,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'", -@@ -757,9 +760,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'", -@@ -772,9 +777,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)); -@@ -859,9 +866,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'", -@@ -881,9 +889,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'", -@@ -897,9 +906,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'", -@@ -912,9 +922,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)); -@@ -1830,8 +1841,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, user_newid, 1); - } - #endif -@@ -1849,8 +1860,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, user_newid, 1); - #endif - return; -@@ -1877,9 +1888,9 @@ static void move_home (void) - Prog, prefix_user_home); - } - #ifdef WITH_AUDIT -- audit_logger (AUDIT_USER_CHAUTHTOK, -+ audit_logger (AUDIT_USER_MGMT, - Prog, -- "moving home directory", -+ "moving-home-dir", - user_newname, - user_newid, - 1); -@@ -2100,8 +2111,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, user_newid, 1); - } - #endif -@@ -2129,8 +2140,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, user_newid, 1); - } - -@@ -2331,8 +2342,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, user_id, - SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ -@@ -2344,8 +2355,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, user_id, - SHADOW_AUDIT_FAILURE); - #endif /* WITH_AUDIT */ -@@ -2388,8 +2399,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, user_newid, 1); - } - #endif diff --git a/shadow-4.14.0-manfix.patch b/shadow-4.14.0-manfix.patch deleted file mode 100644 index 70f030e..0000000 --- a/shadow-4.14.0-manfix.patch +++ /dev/null @@ -1,180 +0,0 @@ -diff -up shadow-4.8.1/man/groupmems.8.xml.manfix shadow-4.8.1/man/groupmems.8.xml ---- shadow-4.8.1/man/groupmems.8.xml.manfix 2020-03-17 15:34:48.750414984 +0100 -+++ shadow-4.8.1/man/groupmems.8.xml 2020-03-17 15:41:13.383588722 +0100 -@@ -179,20 +179,10 @@ - - SETUP - -- The groupmems executable should be in mode -- 2710 as user root and in group -- groups. The system administrator can add users to -- group groups to allow or disallow them using the -- groupmems utility to manage their own group -- membership list. -+ In this operating system the groupmems executable -+ is not setuid and regular users cannot use it to manipulate -+ the membership of their own group. - -- -- -- $ groupadd -r groups -- $ chmod 2710 groupmems -- $ chown root:groups groupmems -- $ groupmems -g groups -a gk4 -- - - - -diff -up shadow-4.8.1/man/ja/man5/login.defs.5.manfix shadow-4.8.1/man/ja/man5/login.defs.5 ---- shadow-4.8.1/man/ja/man5/login.defs.5.manfix 2019-07-23 17:26:08.000000000 +0200 -+++ shadow-4.8.1/man/ja/man5/login.defs.5 2020-03-17 15:34:48.750414984 +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.8.1/man/login.defs.5.xml.manfix shadow-4.8.1/man/login.defs.5.xml ---- shadow-4.8.1/man/login.defs.5.xml.manfix 2020-01-17 16:47:56.000000000 +0100 -+++ shadow-4.8.1/man/login.defs.5.xml 2020-03-17 15:34:48.750414984 +0100 -@@ -164,6 +164,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: - - -@@ -256,16 +267,6 @@ - - - -- chfn -- -- -- CHFN_AUTH -- CHFN_RESTRICT -- LOGIN_STRING -- -- -- -- - chgpasswd - - -@@ -286,14 +287,6 @@ - - - -- -- chsh -- -- -- CHSH_AUTH LOGIN_STRING -- -- -- - - - -@@ -359,34 +352,6 @@ - LASTLOG_UID_MAX - - -- -- 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 LASTLOG_UID_MAX -- 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 -@@ -415,17 +380,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 - -@@ -452,32 +406,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 --git a/shadow-4.14.0-useradd-def-usrtemplate-selinux-label.patch b/shadow-4.14.0-useradd-def-usrtemplate-selinux-label.patch deleted file mode 100644 index 97b709a..0000000 --- a/shadow-4.14.0-useradd-def-usrtemplate-selinux-label.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 48aa12af31c0b72872b411857d03a518a4200a3d Mon Sep 17 00:00:00 2001 -From: Johannes Segitz -Date: Tue, 26 Sep 2023 15:14:14 +0200 -Subject: [PATCH] useradd: Set proper SELinux labels for def_usrtemplate - -Fixes: 74c17c716 ("Add support for skeleton files from /usr/etc/skel") - -Signed-off-by: Johannes Segitz ---- - src/useradd.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/useradd.c b/src/useradd.c -index 76a4d649..fe62a051 100644 ---- a/src/useradd.c -+++ b/src/useradd.c -@@ -2788,7 +2788,7 @@ int main (int argc, char **argv) - if (home_added) { - copy_tree (def_template, prefix_user_home, false, true, - (uid_t)-1, user_id, (gid_t)-1, user_gid); -- copy_tree (def_usrtemplate, prefix_user_home, false, false, -+ copy_tree (def_usrtemplate, prefix_user_home, false, true, - (uid_t)-1, user_id, (gid_t)-1, user_gid); - } else { - fprintf (stderr, --- -2.41.0 - diff --git a/shadow-4.2.1-date-parsing.patch b/shadow-4.2.1-date-parsing.patch deleted file mode 100644 index 2a798d0..0000000 --- a/shadow-4.2.1-date-parsing.patch +++ /dev/null @@ -1,69 +0,0 @@ -Index: shadow-4.5/libmisc/getdate.y -=================================================================== ---- shadow-4.5.orig/libmisc/getdate.y -+++ shadow-4.5/libmisc/getdate.y -@@ -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/shadow-utils-configure-gshadow.patch b/shadow-utils-configure-gshadow.patch deleted file mode 100644 index a983ce0..0000000 --- a/shadow-utils-configure-gshadow.patch +++ /dev/null @@ -1,20 +0,0 @@ -The missing #include causes the configure check to fail -spuriously, resulting in HAVE_SHADOWGRP not being defined. - -Submitted upstream: - -diff --git a/configure.ac b/configure.ac -index 924254a0c8171802..6c7d9839979e037d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -116,6 +116,10 @@ if test "$ac_cv_header_shadow_h" = "yes"; then - ac_cv_libc_shadowgrp, - AC_RUN_IFELSE([AC_LANG_SOURCE([ - #include -+ #ifdef HAVE_GSHADOW_H -+ #include -+ #endif -+ int - main() - { - struct sgrp *sg = sgetsgent("test:x::"); diff --git a/shadow-utils.login.defs b/shadow-utils.login.defs index c0295b1..e84c7ab 100644 --- a/shadow-utils.login.defs +++ b/shadow-utils.login.defs @@ -130,10 +130,9 @@ HOME_MODE 0700 # PASS_MAX_DAYS 99999 PASS_MIN_DAYS 0 +PASS_MIN_LEN 8 PASS_WARN_AGE 7 -# Currently PASS_MIN_LEN is not supported - # Currently SU_WHEEL_ONLY is not supported # Currently CRACKLIB_DICTPATH is not supported @@ -174,11 +173,22 @@ SUB_GID_COUNT 65536 # #LOGIN_TIMEOUT 60 -# Currently PASS_CHANGE_TRIES is not supported +# +# Maximum number of attempts to change password if rejected (too easy) +# +PASS_CHANGE_TRIES 5 -# Currently PASS_ALWAYS_WARN is not supported +# +# Warn about weak passwords (but still allow them) if you are root. +# +PASS_ALWAYS_WARN yes -# Currently PASS_MAX_LEN is not supported +# +# Number of significant characters in the password for crypt(). +# Default is 8, don't change unless your crypt() is better. +# Ignored if MD5_CRYPT_ENAB set to "yes". +# +#PASS_MAX_LEN 8 # Currently CHFN_AUTH is not supported diff --git a/shadow-utils.spec b/shadow-utils.spec index 49a7819..7bc7e8b 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,34 +1,30 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils -Version: 4.14.0 -Release: 2%{?dist} +Version: 4.20.0 +Release: 1%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow -Source0: https://github.com/shadow-maint/shadow/releases/download/v%{version}/shadow-%{version}.tar.xz -Source1: https://github.com/shadow-maint/shadow/releases/download/v%{version}/shadow-%{version}.tar.xz.asc +Source0: https://github.com/shadow-maint/shadow/releases/download/4.20.0/shadow-4.20.0.tar.xz +Source1: https://github.com/shadow-maint/shadow/releases/download/4.20.0/shadow-4.20.0.tar.xz.asc Source2: shadow-utils.useradd Source3: shadow-utils.login.defs Source4: shadow-bsd.txt Source5: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt Source6: shadow-utils.HOME_MODE.xml +Source7: passwd.pamd ### Globals ### %global includesubiddir %{_includedir}/shadow +# Fail linking if there are undefined symbols. +%global _ld_strict_symbol_defs 1 ### Patches ### -# Misc manual page changes - non-upstreamable -Patch0: shadow-4.14.0-manfix.patch -# Date parsing improvement - could be upstreamed -Patch1: shadow-4.2.1-date-parsing.patch -# Audit message changes - partially upstreamed -Patch2: shadow-4.14.0-audit-update.patch -# https://github.com/shadow-maint/shadow/pull/812 -Patch3: shadow-4.14.0-useradd-def-usrtemplate-selinux-label.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 Requires: libselinux >= 1.25.2-1 +Requires: pam-libs Requires: setup ### Build Dependencies ### @@ -45,15 +41,34 @@ BuildRequires: git BuildRequires: itstool BuildRequires: libacl-devel BuildRequires: libattr-devel +BuildRequires: libcmocka-devel BuildRequires: libeconf-devel BuildRequires: libselinux-devel >= 1.25.2-1 BuildRequires: libsemanage-devel BuildRequires: libtool +BuildRequires: libxcrypt-devel BuildRequires: libxslt BuildRequires: make +BuildRequires: pam +BuildRequires: pam-devel ### Provides ### Provides: shadow = %{epoch}:%{version}-%{release} +Provides: passwd = 0.80-18 +Obsoletes: passwd <= 0.80-19 + +%if "%{_sbindir}" == "%{_bindir}" +# Compat symlinks for Requires in other packages. +# We rely on filesystem to create the symlinks for us. +Requires: filesystem(unmerged-sbin-symlinks) +Provides: /usr/sbin/adduser +Provides: /usr/sbin/useradd +Provides: /usr/sbin/userdel +Provides: /usr/sbin/usermod +Provides: /usr/sbin/groupadd +Provides: /usr/sbin/groupdel +Provides: /usr/sbin/groupmod +%endif %description The shadow-utils package includes the necessary programs for @@ -62,16 +77,14 @@ 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. +and shadow files. The useradd, userdel, and usermod commands are used +for managing user accounts. The groupadd, groupdel, and groupmod +commands are used for managing group accounts. ### Subpackages ### %package subid Summary: A library to manage subordinate uid and gid ranges -License: BSD and GPLv2+ %description subid Utility library that provides a way to manage subid ranges. @@ -79,14 +92,13 @@ Utility library that provides a way to manage subid ranges. %package subid-devel Summary: Development package for shadow-utils-subid -License: BSD and GPLv2+ Requires: shadow-utils-subid = %{epoch}:%{version}-%{release} %description subid-devel Development files for shadow-utils-subid. %prep -%autosetup -p 1 -S git -n shadow-%{version} +%autosetup -p 1 -S git -n shadow-4.20.0 iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8 cp -f doc/HOWTO.utf8 doc/HOWTO @@ -94,42 +106,39 @@ cp -f doc/HOWTO.utf8 doc/HOWTO cp -a %{SOURCE4} %{SOURCE5} . cp -a %{SOURCE6} man/login.defs.d/HOME_MODE.xml -# Force regeneration of getdate.c -rm libmisc/getdate.c - %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 - autoreconf %configure \ - --enable-shadowgrp \ + --disable-account-tools-setuid \ + --enable-logind=no \ --enable-man \ + --enable-shadowgrp \ + --enable-shared \ --with-audit \ - --with-sha-crypt \ --with-bcrypt \ - --with-yescrypt \ + --with-group-name-max-length=32 \ + --with-libpam \ --with-selinux \ + --with-sha-crypt \ + --with-yescrypt \ --without-libbsd \ --without-libcrack \ - --without-libpam \ - --enable-shared \ - --with-group-name-max-length=32 \ - --enable-lastlog \ - --enable-logind=no + --without-nscd \ + --without-sssd %make_build +%check +make check + %install %make_install gnulocaledir=$RPM_BUILD_ROOT%{_datadir}/locale MKINSTALLDIRS=`pwd`/mkinstalldirs install -d -m 755 $RPM_BUILD_ROOT%{_sysconfdir}/default install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT%{_sysconfdir}/login.defs install -p -c -m 0600 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/default/useradd +install -d -m 755 $RPM_BUILD_ROOT%{_pam_confdir} +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pam_confdir}/chpasswd +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pam_confdir}/newusers +install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pam_confdir}/passwd ln -s useradd $RPM_BUILD_ROOT%{_sbindir}/adduser @@ -138,45 +147,28 @@ 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 +%if "%{_sbindir}" == "%{_bindir}" +# The installation script doesn't actually use the configured paths :( +mv -v $RPM_BUILD_ROOT/usr/sbin/* $RPM_BUILD_ROOT%{_bindir}/ +%endif + # 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%{_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}/man3/getspnam.* @@ -186,6 +178,12 @@ rm $RPM_BUILD_ROOT%{_mandir}/*/man5/faillog.* rm $RPM_BUILD_ROOT%{_mandir}/man8/faillog.* rm $RPM_BUILD_ROOT%{_mandir}/*/man8/faillog.* +# Remove PAM service files we don't use. +rm $RPM_BUILD_ROOT%{_pam_confdir}/chfn +rm $RPM_BUILD_ROOT%{_pam_confdir}/chsh +rm $RPM_BUILD_ROOT%{_pam_confdir}/login +rm $RPM_BUILD_ROOT%{_pam_confdir}/su + find $RPM_BUILD_ROOT%{_mandir} -depth -type d -empty -delete %find_lang shadow for dir in $(ls -1d $RPM_BUILD_ROOT%{_mandir}/{??,??_??}) ; do @@ -210,13 +208,16 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %license gpl-2.0.txt shadow-bsd.txt %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/login.defs %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/default/useradd +%config(noreplace) %{_pam_confdir}/chpasswd +%config(noreplace) %{_pam_confdir}/newusers +%config(noreplace) %{_pam_confdir}/passwd %{_bindir}/sg %attr(4755,root,root) %{_bindir}/chage %attr(4755,root,root) %{_bindir}/gpasswd -%{_bindir}/lastlog %attr(4755,root,root) %{_bindir}/newgrp %attr(0755,root,root) %caps(cap_setgid=ep) %{_bindir}/newgidmap %attr(0755,root,root) %caps(cap_setuid=ep) %{_bindir}/newuidmap +%attr(4755,root,root) %{_bindir}/passwd %{_sbindir}/adduser %attr(0755,root,root) %{_sbindir}/user* %attr(0755,root,root) %{_sbindir}/group* @@ -234,6 +235,7 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_mandir}/man1/newgrp.1* %{_mandir}/man1/newgidmap.1* %{_mandir}/man1/newuidmap.1* +%{_mandir}/man1/passwd.* %{_mandir}/man3/shadow.3* %{_mandir}/man5/shadow.5* %{_mandir}/man5/login.defs.5* @@ -249,7 +251,6 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_mandir}/man8/chgpasswd.8* %{_mandir}/man8/newusers.8* %{_mandir}/man8/*conv.8* -%{_mandir}/man8/lastlog.8* %{_mandir}/man8/vipw.8* %{_mandir}/man8/vigr.8* @@ -263,6 +264,164 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed Jul 29 2026 Iker Pedrosa - 2:4.20.0-1 +- Rebase to version 4.20.0 + +* Wed Jul 22 2026 Iker Pedrosa - 2:4.20.0-rc3-1 +- Rebase to version 4.20.0-rc3 + +* Fri Jul 17 2026 Fedora Release Engineering - 2:4.19.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild + +* Wed May 27 2026 Iker Pedrosa - 2:4.19.3-3 +- Enable use of PAM for chpasswd and newusers + Resolves: #2461179 and #2283963 + +* Thu Apr 23 2026 Iker Pedrosa - 2:4.19.3-2 +- btrfs: simplify checks improve useradd behavior for non-btrfs + +* Wed Feb 11 2026 Debarshi Ray - 2:4.19.3-1 +- Rebase to version 4.19.3 + Resolves: #2426288 + +* Tue Jan 27 2026 Adam Williamson - 2:4.19.0-6 +- chkhash.c: fix escaping in SHA-256 / SHA-512 / MD5 regexes + +* Mon Jan 26 2026 Iker Pedrosa - 2:4.19.0-5 +- chkhash.c: fix support for ! and * in hashes +- usermod.c: add back optimizations + +* Sat Jan 17 2026 Fedora Release Engineering - 2:4.19.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild + +* Mon Jan 12 2026 Iker Pedrosa - 2:4.19.0-3 +- useradd: Support config for creating home dirs as Btrfs subvolumes + +* Fri Jan 9 2026 Iker Pedrosa - 2:4.19.0-2 +- Enable unit-tests + +* Fri Jan 9 2026 Iker Pedrosa - 2:4.19.0-1 +- Rebase to version 4.19.0 + Resolves: #2426288 and #2249524 + +* Tue Nov 25 2025 Adam Williamson - 2:4.18.0-7 +- Also revert changes from -4 (last known good was -3) + +* Tue Nov 25 2025 Adam Williamson - 2:4.18.0-6 +- Revert changes from -5 (they were only meant for testing) + +* Tue Nov 25 2025 Iker Pedrosa - 2:4.18.0-5 +- Test CI + +* Fri Oct 31 2025 Iker Pedrosa - 2:4.18.0-4 +- Stop setting SELinux labels in chroot and prefix environments + Resolves: #2249524 + +* Tue Jul 29 2025 Alexey Tikhonov - 2:4.18.0-3 +- Revert "Stop assigning subids by default" + Resolves: #2382662 + +* Fri Jul 25 2025 Fedora Release Engineering - 2:4.18.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Tue Jul 22 2025 Iker Pedrosa - 2:4.18.0-1 +- Rebase to version 4.18.0. Resolves: #2374710 + +* Fri Jul 18 2025 Iker Pedrosa - 2:4.17.4-5 +- Stop assigning subids by default + Resolves: CVE-2024-56433 and #2334168 + +* Tue Jul 15 2025 Iker Pedrosa - 2:4.17.4-4 +- FSWC: Migrate to lastlog2 + Link: + Resolves: #2361588 + +* Tue Mar 25 2025 Iker Pedrosa - 2:4.17.4-2 +- Add pam dependency for _pam_confdir missing macro. Resolves: #2354806 + +* Thu Mar 20 2025 Iker Pedrosa - 2:4.17.4-1 +- Rebase to version 4.17.4. Resolves: #2353491 +- Fixes problems with expiration dates + +* Sat Feb 01 2025 Björn Esser - 2:4.17.0-5 +- Add explicit BR: libxcrypt-devel + +* Sun Jan 19 2025 Fedora Release Engineering - 2:4.17.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Sun Jan 12 2025 Zbigniew Jędrzejewski-Szmek - 2:4.17.0-3 +- Rebuilt for the bin-sbin merge (2nd attempt) + +* Thu Dec 26 2024 Iker Pedrosa - 2:4.17.0 +- Rebase to version 4.17.0. Resolves: #2293678 + +* Sun Dec 22 2024 Björn Esser - 2:4.17.0~rc1-2 +- Remove potentially dangerous {C,LD}FLAGS shenanigans +- Fail linking if there are undefined symbols at link-time + +* Mon Dec 9 2024 Iker Pedrosa - 2:4.17.0~rc1-1 +- Rebase to version 4.17.0-rc1 + +* Tue Nov 12 2024 Iker Pedrosa - 2:4.16.0-7 +- SPDX license migration for subpackages + +* Wed Oct 16 2024 Iker Pedrosa - 2:4.16.0-6 +- Rebuilt for libeconf soname bump + +* Mon Oct 7 2024 Iker Pedrosa - 2:4.16.0-5 +- useradd: fix write_full() return value. Resolves: #2313559 + +* Fri Sep 13 2024 Iker Pedrosa - 2:4.16.0-3 +- Disable nscd + +* Wed Aug 28 2024 Iker Pedrosa - 2:4.16.0-2 +- Rebase to version 4.16.0 (#2293678) + +* Tue Jul 23 2024 Kevin Fenzi - 2:4.15.1-9 +- Revert chpasswd: use PAM again for now. + +* Sat Jul 20 2024 Fedora Release Engineering - 2:4.15.1-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Tue Jul 09 2024 Zbigniew Jędrzejewski-Szmek - 2:4.15.1-7 +- Rebuilt for the bin-sbin merge + +* Thu May 30 2024 Iker Pedrosa - 2:4.15.1-6 +- chpasswd: use PAM again (#2283963) + +* Mon May 20 2024 Iker Pedrosa - 2:4.15.1-5 +- Several fixes for issues detected by static analyzer tools + +* Thu Apr 11 2024 Zbigniew Jedrzejewski-Szmek - 2:4.15.1-4 +- Fix build with %%_bindir==%%_sbindir +- Add virtual Provides for old file paths used by other packages + +* Thu Mar 21 2024 Iker Pedrosa - 2:4.15.1-2 +- getdef: avoid spurious error messages about unknown configuration options. + Resolves: #2265291 + +* Tue Mar 12 2024 Iker Pedrosa - 2:4.15.1-1 +- Wrong versioning for 4.15.0 RC releases makes the oficial release look lower than them. + Fix it by bumping the minor release to 4.15.1. Resolves: #2268690 + +* Mon Mar 11 2024 Iker Pedrosa - 2:4.15.0-1 +- Rebase to version 4.15.0 + +* Mon Feb 12 2024 Iker Pedrosa - 2:4.14.0-6 +- Build linking `libpam` + +* Thu Feb 1 2024 Iker Pedrosa - 2:4.14.0-5 +- passwd: Provide binary from this package. Enable libpam and + disable account-tools-setuid. Provide passwd PAM service file. + Resolves: #2233275 +- passwd: provide --stdin option + +* Mon Jan 29 2024 Iker Pedrosa - 2:4.14.0-4 +- Disable SSSD support. Resolves: #2253182 + +* Sat Jan 27 2024 Fedora Release Engineering - 2:4.14.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Tue Oct 3 2023 Iker Pedrosa - 2:4.14.0-2 - useradd: Set proper SELinux labels for def_usrtemplate diff --git a/sources b/sources index 1ec1caa..7669083 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (shadow-4.14.0.tar.xz) = ff960481d576f9db5a9f10becc4e1a74c03de484ecfdcd7f1ea735fded683d7ba0f9cd895dc6a431b77e5a633752273178b1bcda4cefaa5adbf0f143c9a0c86f -SHA512 (shadow-4.14.0.tar.xz.asc) = d011a732d73b4b066ca8d204c0420303f925c87efc7655feb5c5f60b619d67da450e220ee44f6c86929ae79cbd4343136fe9c20d25b39fa0a228a48e57636309 +SHA512 (shadow-4.20.0.tar.xz) = 0b8afded372e4d37a78f38cb972c0ab877870ef6356cdd1c45be3c708af3d1496c6f87de6bf6a5b1d217d4d52d7e2d15c28b26530949cc6de0231a4028930406 +SHA512 (shadow-4.20.0.tar.xz.asc) = e4b134543768f323df30a1e450c22086d013020928d62bd3207db7f633beea3587b67802da5b575d5a794e8c2bebd7a0abeba6ed69d44bf08adc37df3bf352ac diff --git a/tests/mhc-fedora-ci.yaml b/tests/mhc-fedora-ci.yaml new file mode 100644 index 0000000..8747e67 --- /dev/null +++ b/tests/mhc-fedora-ci.yaml @@ -0,0 +1,13 @@ +provisioned_topologies: +- shadow +domains: +- id: shadow + hosts: + - hostname: localhost + role: shadow + conn: + type: ssh + host: localhost + user: root + artifacts: + - /var/log/* diff --git a/tests/sanity/Makefile b/tests/sanity/Makefile deleted file mode 100644 index 386221b..0000000 --- a/tests/sanity/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2006 Red Hat, Inc. All rights reserved. This copyrighted material -# is made available to anyone wishing to use, modify, copy, or -# redistribute it subject to the terms and conditions of the GNU General -# Public License v.2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# Author: Jakub Hrozek - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# -# Example Makefile for RHTS # -# This example is geared towards a test for a specific package # -# It does most of the work for you, but may require further coding # -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# - -# The toplevel namespace within which the test lives. -TOPLEVEL_NAMESPACE=CoreOS - -# The name of the package under test: -PACKAGE_NAME=shadow-utils - -# The path of the test below the package: -RELATIVE_PATH=sanity - -# Version of the Test. Used with make tag. -export TESTVERSION=1.1 - -# The combined namespace of the test. -export TEST=/$(TOPLEVEL_NAMESPACE)/$(PACKAGE_NAME)/$(RELATIVE_PATH) - -# A phony target is one that is not really the name of a file. -# It is just a name for some commands to be executed when you -# make an explicit request. There are two reasons to use a -# phony target: to avoid a conflict with a file of the same -# name, and to improve performance. -.PHONY: all install download clean - -# Executables to be built should be added here, they will be generated on the system under test. -BUILT_FILES= - -# Data files, .c files, scripts anything needed to either compile the test and/or run it. -FILES=$(METADATA) Makefile PURPOSE sanity_test.py runtest.sh - -run: $(FILES) build - ./runtest.sh - -build: $(BUILT_FILES) - chmod a+x ./sanity_test.py - chmod a+x ./runtest.sh - -clean: - rm -f *~ *.rpm $(BUILT_FILES) - -# Include Common Makefile -include /usr/share/rhts/lib/rhts-make.include - -# Generate the testinfo.desc here: -$(METADATA): Makefile - @touch $(METADATA) - @echo "Owner: Jakub Hrozek " > $(METADATA) - @echo "Name: $(TEST)" >> $(METADATA) - @echo "Path: $(TEST_DIR)" >> $(METADATA) - @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) - @echo "License: GNU GPL" >> $(METADATA) - @echo "Description: Basic sanity test for shadow-utils" >> $(METADATA) - @echo "TestTime: 5m" >> $(METADATA) - @echo "RunFor: $(PACKAGE_NAME)" >> $(METADATA) - @echo "Requires: $(PACKAGE_NAME)" >> $(METADATA) - @echo "Requires: python" >> $(METADATA) - rhts-lint $(METADATA) - diff --git a/tests/sanity/PURPOSE b/tests/sanity/PURPOSE deleted file mode 100644 index 27062e1..0000000 --- a/tests/sanity/PURPOSE +++ /dev/null @@ -1,10 +0,0 @@ -This is a basic sanity test for the shadow-utils package. It is implemented -in python on top of the unittesting.py module. - -Its purpose is to ensure that the binaries in the shadow-utils package behave -as expected and its switches/options work correctly. - -For the most part, every binary in the shadow-utils package is represented by -a single class named Test, i.e. TestUsermod etc. There are some -exceptions, like TestUseraddWeirdNameTest though. - diff --git a/tests/sanity/runtest.sh b/tests/sanity/runtest.sh deleted file mode 100755 index cb2a2b5..0000000 --- a/tests/sanity/runtest.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -. /usr/bin/rhts-environment.sh -. /usr/share/beakerlib/beakerlib.sh || exit 1 - -rlJournalStart -rlFileBackup --clean /etc/default/useradd- /etc/default/useradd -setenforce 0 -python sanity_test.py -v -setenforce 1 -rlFileRestore - -EXIT=$? -if [[ $EXIT -eq 0 ]]; then - RESULT="PASS" -else - RESULT="FAIL" -fi - - -rlJournalEnd - -echo "Result: $RESULT" -echo "Exit: $EXIT" -report_result $TEST $RESULT $EXIT diff --git a/tests/sanity/sanity_test.py b/tests/sanity/sanity_test.py deleted file mode 100755 index e9c45c2..0000000 --- a/tests/sanity/sanity_test.py +++ /dev/null @@ -1,1013 +0,0 @@ -#!/usr/bin/env python -""" -A script that tests functionality of the shadow-utils package. - -Author: Jakub Hrozek, -License: GNU GPL v2 -Date: 2007 - -TODO: - * tests for password aging - * if something fails, print out the command issued for easier debugging - * test long options variants along with the short ones -""" - -import unittest -import pwd -import grp -import commands -import os -import os.path -import sys -import copy -import tempfile -import rpm -import shutil - -from UserDict import UserDict - -class RedHatVersion(object): - def __init__(self, type=None, version=None, release=None): - self.type = type - self.version = version - self.release = release - self.rhel = False - - def __eq__( self, other): - """ - Don't compare if either of the values is None - so we can do comparisons like 'is it fedora?' or 'is it rhel4?' - """ - ok = (self.type == other.type) - if ok == False: return False - - if self.version and other.version: - ok = (self.version == other.version) - if ok == False: return False - - if (self.release == other.release): - ok = (self.release == other.release) - - return ok - - def __ne__( self, other): - return not self.__eq__(other) - - def __get_fedora_info(self, mi): - return [ (h['version'],h['release']) for h in mi ][0] - - def __get_rhel_info(self, mi): - # The rules for RHEL versions are braindead..releases even more - ver_rpm, rel_rpm = [ (h['version'],h['release']) for h in mi ][0] - rhel_versions = { '3AS' : 3, '4AS' : 4, '5Server' : 5, '5Client' : 5, '6' : 6 } - if ver_rpm[:3] == '5.9' or ver_rpm[:1] == '6': # rhel6 prerelease and release hack - rhel_versions[ver_rpm] = 6 - if ver_rpm in rhel_versions.keys(): - return (rhel_versions[ver_rpm], rel_rpm) - - def is_rhel(self): - return self.rhel - - def get_info(self): - """ - Returns a tuple containing (type, version, release) of RHEL or Fedora. - Type is either RHEL or Fedora. - Returns None if it cannot parse the info - """ - - ts = rpm.TransactionSet() - mi = ts.dbMatch() - mi.pattern('name', rpm.RPMMIRE_GLOB, 'redhat-release*') - - if mi: - self.rhel = True - return ('RHEL',) + self.__get_rhel_info(mi) - else: - mi = ts.dbMatch('name','fedora-release') - self.rhel = False - if mi.count() != 0: - return ('Fedora',) + self.__get_fedora_info(mi) - - return None - - -class UserInfo(UserDict): - fields = { "pw_name" : 0, "pw_passwd" : 1, "pw_uid" : 2, "pw_gid" : 3, - "pw_gecos" : 4, "pw_dir" : 5, "pw_shell" : 6 } - - def __init__(self): - UserDict.__init__(self) - for f in UserInfo.fields: self[f] = None - - def __getitem__(self, key): - return UserDict.__getitem__(self, key) - - def __setitem__(self, key, value): - UserDict.__setitem__(self, key, value) - - def __cmp__(self, other): - return UserDict.__cmp__(self, other) - - def __repr__(self): - return " ; ".join( [ "%s => %s" % (k, v) for k, v in self.data.items() ] ) - - def __parse_info(self, struct): - for f in UserInfo.fields: - self[f] = struct[UserInfo.fields[f]] - - def get_info_uid(self, uid): - self.__parse_info(pwd.getpwuid(uid)) - - def get_info_name(self, name): - try: - self.__parse_info(pwd.getpwnam(name)) - except KeyError: - return None - - def lazy_compare(self, pattern): - """ Compare pattern against self. If any field in pattern is set - to None, it is automatically considered equal with the corresponding - field in self. """ - for field in UserInfo.fields: - if pattern[field] and pattern[field] != self[field]: - return False - - return True - -class GroupInfo(UserDict): - fields = { "gr_name" : 0, "gr_passwd" : 1, - "gr_gid" : 2, "gr_mem" : 3} - - def __init__(self): - UserDict.__init__(self) - for f in GroupInfo.fields: self[f] = None - - def __getitem__(self, key): - return UserDict.__getitem__(self, key) - - def __setitem__(self, key, value): - UserDict.__setitem__(self, key, value) - - def __cmp__(self, other): - return UserDict.__cmp__(self, other) - - def __repr__(self): - return " ; ".join( [ "%s => %s" % (k, v) for k, v in self.data.items() ] ) - - def __parse_info(self, struct): - for f in GroupInfo.fields: - self[f] = struct[GroupInfo.fields[f]] - - def get_info_gid(self, gid): - self.__parse_info(grp.getgrgid(gid)) - - def get_info_name(self, name): - self.__parse_info(grp.getgrnam(name)) - - def lazy_compare(self, pattern): - """ Compare pattern against self. If any field in pattern is set - to None, it is automatically considered equal with the corresponding - field in self. """ - for field in GroupInfo.fields: - if pattern[field] and pattern[field] != self[field]: - return False - - return True - -class LoginDefsParser(UserDict): - "A quick-n-dirty way how to fetch the defaults from /etc/login.defs into a dictionary" - - def __getitem__(self, key): - try: - return UserDict.__getitem__(self, key) - except KeyError: - # if a name-value is not defined in the config file, return defaults - if key == "CREATE_MAIL_SPOOL": - return "yes" - if key == "UMASK": - return "077" - - def __init__(self, path="/etc/login.defs",split=None): - self.path = path - UserDict.__init__(self) - try: - defs = open(path) - except IOError: - print "Could not open the config file %s" % (path) - - for line in defs: - if line.startswith('#'): continue - fields = line.split(split) - if len(fields) != 2: continue # yeah, we're dirty - self.data[fields[0]] = fields[1] - - def serialize(self): - output = open(self.path, "w+") - for k,v in self.data.items(): - output.write("%s=%s" % (k, v)) - - output.write("\n") - output.close() - -class TestUserInfo(unittest.TestCase): - def testLazyCompare(self): - """ (test sanity): Test comparing two UserInfo records """ - a = UserInfo() - a["pw_name"] = "foo" - a["pw_uid"] = 555 - b = copy.deepcopy(a) - c = UserInfo() - - self.assertEqual(a.lazy_compare(b), True) - self.assertEqual(a.lazy_compare(c), True) - - c["pw_name"] = "foo" - c["pw_uid"] = None - self.assertEqual(a.lazy_compare(c), True) - self.assertEqual(c.lazy_compare(a), False) - - c["pw_name"] = "bar" - self.assertNotEqual(a.lazy_compare(c), True) - - def testGetInfoUid(self): - """ (test sanity): Test getting user info based on his UID """ - a = UserInfo() - a.get_info_uid(0) - self.assertEqual(a["pw_name"], "root") - - def testGetInfoName(self): - """ (test sanity): Test getting user info based on his name """ - a = UserInfo() - a.get_info_name("root") - self.assertEqual(a["pw_uid"], 0) - -class ShadowUtilsTestBase: - """ Handy routines """ - def getDefaults(self): - # get the default values for so we can compare against that - (status, defaults_str) = commands.getstatusoutput('useradd -D') - if status != 0: - raise RuntimeError("Could not get the default values for useradd") - return dict([ rec.split("=") for rec in defaults_str.split("\n") ]) - - def getDefaultUserInfo(self, username): - expected = UserInfo() - defaults = self.getDefaults() - - expected["pw_name"] = username - expected["pw_dir"] = defaults["HOME"] + "/" + username - expected["pw_shell"] = defaults["SHELL"] - - return expected - -class TestUseradd(ShadowUtilsTestBase, unittest.TestCase): - def setUp(self): - self.username = "test-shadow-utils-useradd" - - def tearDown(self): - commands.getstatusoutput("userdel -r %s" % (self.username)) - - def testBasicAdd(self): - """ useradd: Tests basic adding of a user """ - expected = self.getDefaultUserInfo(self.username) - - runme = "useradd %s" % (self.username) - (status, output) = commands.getstatusoutput(runme) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a user\nIssued command: %s" % (runme)) - - def testExistingUser(self): - """ useradd: Test that user with an existing name cannot be added """ - (status, output) = commands.getstatusoutput("useradd %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - self.assertNotEqual(commands.getstatusoutput("useradd %s" % (self.username))[0], 0, "FAIL: User that already exists added") - - def testCustomUID(self): - """ useradd: Adding an user with a specific UID """ - UID = 23456 # FIXME - test for a free UID slot first - - expected = self.getDefaultUserInfo(self.username) - expected["pw_uid"] = UID - - runme = "useradd %s -u %d" % (self.username, UID) - (status, output) = commands.getstatusoutput(runme) - self.failUnlessEqual(status, 0, "Issued command: %s\n" % (runme) + "Got from useradd: %s\n" % (output)) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a user with a specific UID\nIssued command: %s" % (runme)) - - def testNegativeUID(self): - """ useradd: Tests that user cannot have a negative UID assigned """ - self.assertNotEqual(commands.getstatusoutput("useradd %s --uid -5" % (self.username))[0], 0, "FAIL: User with UID < 0 added") - - def testCustomExistingUID(self): - """ useradd: Adding a user with a specific existing UID """ - UID = 32112 - - expected = self.getDefaultUserInfo(self.username) - expected["pw_uid"] = UID - - (status_u, output_u) = commands.getstatusoutput("useradd %s -u %d" % (self.username, UID)) - - # must fail without -o flag - (status_u_no_o, output_u_no_o) = commands.getstatusoutput("useradd foo -u %d" % (UID)) - - # must pass with -o flag - (status_o, output_o) = commands.getstatusoutput("useradd foo -u %d -o" % (UID)) - - # clean up - (status, output) = commands.getstatusoutput("userdel -r foo") - - self.failUnlessEqual(status_u, 0, "FAIL: cannot add an user with a specified UID\n"+output_u) - self.assertEqual(status_o, 0, "FAIL: cannot add an user with an existing UID using the -o flag\n"+output_o) - self.failUnlessEqual(status, 0, output) - self.assertNotEqual(status_u_no_o, 0, "FAIL: user with an existing UID added\n"+output_u_no_o) - - def testCustomGID(self): - """ useradd: Adding an user with a specific GID """ - GID = 100 # users group should be everywhere - should we test before? - expected = self.getDefaultUserInfo(self.username) - expected["pw_gid"] = GID - - (status, output) = commands.getstatusoutput("useradd %s -g %d" % (self.username, GID)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a user with a specific GID") - - def testCustomShell(self): - """ useradd: Adding an user with a specific login shell """ - shell = "/bin/ksh" - expected = self.getDefaultUserInfo(self.username) - expected["pw_shell"] = shell - - (status, output) = commands.getstatusoutput("useradd %s -s %s" % (self.username, shell)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a user with a specific shell") - - def testCustomHome(self): - """ useradd: Adding an user with a specific home directory """ - home = "/tmp/useradd-test" - os.mkdir(home) - expected = self.getDefaultUserInfo(self.username) - expected["pw_dir"] = home - - (status, output) = commands.getstatusoutput("useradd %s -d %s" % (self.username, home)) - shutil.rmtree(home) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a user with a specific home") - - def testSystemAccount(self): - """ useradd: Adding a system user (UID < UID_MIN from /etc/login.defs) """ - defaults = LoginDefsParser() - - # system account with no home dir - expected = self.getDefaultUserInfo(self.username) - - (status, output) = commands.getstatusoutput("useradd -r %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(os.path.exists(created["pw_dir"]), False, "FAIL: System user has a home dir created") - self.assertEqual(created["pw_uid"] < defaults['UID_MIN'], True, "FAIL: System user has UID > UID_MIN") - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a system user") - - def testAddToMoreGroups(self): - """ useradd: Creating an user that belongs to more than one group """ - (status, output) = commands.getstatusoutput("useradd -G bin %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - gr_bin = GroupInfo() - gr_bin.get_info_name("bin") - self.assertEqual(self.username in gr_bin["gr_mem"], True, "FAIL: User not in supplementary group after usermod -G -a") - - - def testAddWithCommonName(self): - """ useradd: Specifying a comment (user for account name) """ - comment = "zzzzzz" - (status, output) = commands.getstatusoutput("useradd -c %s %s" % (comment, self.username)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created["pw_gecos"], comment, "FAIL: failed to create a user with a GECOS comment") - - def testHomePermissions(self): - """ useradd: Check if permissions on newly created home dir match the umask """ - defaults = LoginDefsParser() - - (status, output) = commands.getstatusoutput("useradd %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - - import stat - perm = os.stat(created["pw_dir"])[stat.ST_MODE] - mode = int(oct(perm & 0777)) - - self.assertEqual(defaults["UMASK"], "077", "FAIL: umask setting is not sane - is %s, should be 077" % (defaults["UMASK"])) - self.assertEqual(int(defaults["UMASK"]) + mode , 777, "FAIL: newly-created home dir does not match the umask") - - def testCreateMailSpool(self): - """ useradd: Check whether the mail spool gets created when told to""" - # set up creating of mail spool - defaults = LoginDefsParser("/etc/default/useradd", split="=") - - create_mail = defaults["CREATE_MAIL_SPOOL"] - defaults["CREATE_MAIL_SPOOL"] = "yes" - defaults.serialize() - - login_defs = LoginDefsParser() - - (status, output) = commands.getstatusoutput("useradd %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - # clean up - defaults["CREATE_MAIL_SPOOL"] = create_mail - defaults.serialize() - self.assertEqual(os.path.exists(login_defs["MAIL_DIR"] + "/" + self.username), True, "FAIL: useradd did not create mail spool") - - def testDefaultMailSettings(self): - """ useradd: Check whether the mail spool is on by default""" - defaults = LoginDefsParser("/etc/default/useradd", split="=") - self.assertEqual(defaults["CREATE_MAIL_SPOOL"], "yes\n") - - def testNoLastlog(self): - """ useradd: Check if the -l option prevents from being added to the lastlog """ - pass # FIXME - add some code here - - -class TestUseraddWeirdNameTest(unittest.TestCase, ShadowUtilsTestBase): - """ Tests addition/removal of usernames that have proven to be problematic in the past. - The reason to separate these from the main useradd test suite is to not run the setUp - and tearDown methods """ - - def addAndRemove(self, username, success=True): - expected = self.getDefaultUserInfo(username) - expected["pw_name"] = username - - (status, output) = commands.getstatusoutput("useradd %s" % (username)) - if success: - self.failUnlessEqual(status, 0, output) - else: - self.failIfEqual(status, 0, output) - return True - - created = UserInfo() - created.get_info_name(username) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: TestUseraddWeirdName::addAndRemove - could not add a user") - - # the cleanup method won't help this time - (status, output) = commands.getstatusoutput("userdel -r %s" % (username)) - self.failUnlessEqual(status, 0, output) - - def testNumericName(self): - """ useradd: Test if an user with a purely numerical name can be added (123) """ - return self.addAndRemove("123") - - def testSambaName(self): - """ useradd: Test if an user with a name with a dollar at the end can be added (joepublic$ ) """ - return self.addAndRemove("joepublic$") - - def testDotInName(self): - """ useradd: Test if an user with a name with a dot in it can be added (joe.public ) """ - return self.addAndRemove("joe.public") - - def testAtInName(self): - """ useradd: Test if an user with an '@' in name can be added (joe@public.com) - should fail """ - return self.addAndRemove("joe@public.com", False) - - def testUppercase(self): - """ useradd: Test if an user with UPPERCASE or Uppercase name can be added """ - return self.addAndRemove("JOEPUBLIC") - return self.addAndRemove("Joepublic") - -class TestUseraddDefaultsChange(unittest.TestCase, ShadowUtilsTestBase): - def testDefaultsChange(self): - """ useradd: Test overriding default settings (shell, home dir, group) with a -D option """ - save = self.getDefaults() - - new_defs = dict() - new_defs["SHELL"] = "/bin/ksh" - new_defs["GROUP"] = "1" - new_defs["HOME"] = "/tmp" - - command = "useradd -D -s%s -g%s -b%s" % (new_defs["SHELL"], new_defs["GROUP"], new_defs["HOME"]) - (status, output) = commands.getstatusoutput(command) - self.failUnlessEqual(status, 0, output) - - overriden = self.getDefaults() - [ self.assertEqual(overriden[k], new_defs[k]) for k in new_defs.keys() ] - - command = "useradd -D -s%s -g%s -b%s" % (save["SHELL"], save["GROUP"], save["HOME"]) - (status, output) = commands.getstatusoutput(command) - self.failUnlessEqual(status, 0, output) - - -class TestUserdel(unittest.TestCase, ShadowUtilsTestBase): - def setUp(self): - self.username = "test-shadow-utils-userdel" - (status, output) = commands.getstatusoutput("useradd %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - def testRemoveUserGroup(self): - """ userdel: test if userdel removes user's group when he's deleted - regression test for #201379 """ - (status, output) = commands.getstatusoutput("userdel -r %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - # This would fail if we did not have the group removed - (status, output) = commands.getstatusoutput("useradd %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - (status, output) = commands.getstatusoutput("userdel -r %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - -class TestUsermod(unittest.TestCase, ShadowUtilsTestBase): - def setUp(self): - self.username = "test-shadow-utils-usermod" - (status, output) = commands.getstatusoutput("useradd %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - def tearDown(self): - (status, output) = commands.getstatusoutput("userdel -r %s" % (self.username)) - self.failUnlessEqual(status, 0, output) - - def testAppendToSupplementaryGroup(self): - """ usermod: Test if a user can be added to a supplementary group """ - add_group = "additional_group" - (status, output) = commands.getstatusoutput("groupadd %s" % (add_group)) - self.failUnlessEqual(status, 0, output) - - (status_mod, output_mod) = commands.getstatusoutput("usermod -a -G %s %s" % (add_group, self.username)) - add_group_info = GroupInfo() - add_group_info.get_info_name(add_group) - (status, output) = commands.getstatusoutput("groupdel %s" % (add_group)) - - self.failUnlessEqual(status, 0, output) - self.failUnlessEqual(status_mod, 0, output_mod) - self.assertEqual(self.username in add_group_info["gr_mem"], True, "User not in supplementary group after usermod -G --append") - - - def testAppendToSupplementaryGroupLongOption(self): - """ usermod: Test if a user can be added to a supplementary group via --append rather that -a (regression test for 222540) """ - # this is known to not work on older RHELs - test what we are running - rhv = RedHatVersion() - runs = rhv.get_info() - if rhv.is_rhel(): - if runs[1] < 5: - print "This test makes sense for RHEL5+" - return - else: - if runs[1] < 6: - print "This test makes sense for Fedora 6+" - return - - type, release, version = RedHatVersion().get_info() - if RedHatVersion().is_rhel(): - if release < 5 or (release == 5 and version < 2): - print "This test makes sense for RHEL 5.2+" - return - - add_group = "additional_group" - (status, output) = commands.getstatusoutput("groupadd %s" % (add_group)) - self.failUnlessEqual(status, 0, output) - - (status_mod, output_mod) = commands.getstatusoutput("usermod --append -G %s %s" % (add_group, self.username)) - add_group_info = GroupInfo() - add_group_info.get_info_name(add_group) - (status, output) = commands.getstatusoutput("groupdel %s" % (add_group)) - - self.failUnlessEqual(status, 0, output) - self.failUnlessEqual(status_mod, 0, output_mod) - self.assertEqual(self.username in add_group_info["gr_mem"], True, "User not in supplementary group after usermod -G --append") - - - def testNameChange(self): - """ usermod: Test if the comment field (used as the Common Name) can be changed """ - new_comment = "zzzzzz" - - (status, output) = commands.getstatusoutput("usermod -c %s %s" % (new_comment, self.username)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - - self.assertEqual(created["pw_gecos"], new_comment) - - def testHomeChange(self): - """ usermod: Test if user's home directory can be changed """ - new_home = "/tmp" - created = UserInfo() - created.get_info_name(self.username) - old_home = created["pw_dir"] - - (status, output) = commands.getstatusoutput("usermod -d %s %s" % (new_home, self.username)) - self.failUnlessEqual(status, 0, output) - - created.get_info_name(self.username) - self.assertEqual(created["pw_dir"], new_home) - - # revert to old home so we can userdel -r in tearDown - (status, output) = commands.getstatusoutput("usermod -d %s %s" % (old_home, self.username)) - self.failUnlessEqual(status, 0, output) - - # FIXME - test if contents of /home directories are transferred with the -m option - # FIXME - test if new home is created if does not exist before - - def testGIDChange(self): - """ usermod: Test if user's gid can be changed. """ - new_group = "root" - # test non-existing group - (status_fail, output_fail) = commands.getstatusoutput("usermod -g no-such-group %s" % (self.username)) - (status, output) = commands.getstatusoutput("usermod -g %s %s" % (new_group, self.username)) - - created = UserInfo() - created.get_info_name(self.username) - - left = GroupInfo() - if left.get_info_name(self.username) == None: - (status_del, output_del) = commands.getstatusoutput("groupdel %s" % (self.username)) - self.failUnlessEqual(status_del, 0, output_del) - - self.failIfEqual(status_fail, 0, output_fail) - self.failUnlessEqual(status, 0, output) - self.assertEqual(created["pw_gid"], 0) #0 is root group - - def testLoginChange(self): - """ usermod: Test if user's login can be changed """ - new_login = "usermod-login-change" - user = UserInfo() - user.get_info_name(self.username) - uid = user["pw_uid"] # UID won't change even when login does - - # test changing to an existing user name - (status, output) = commands.getstatusoutput("usermod -l root %s" % (self.username)) - self.failIfEqual(status, 0, output) - - (status, output) = commands.getstatusoutput("usermod -l %s %s" % (new_login, self.username)) - self.failUnlessEqual(status, 0, output) - user.get_info_name(new_login) - self.assertEqual(user["pw_uid"], uid) - - # revert so we can userdel -r on tearDown - (status, output) = commands.getstatusoutput("usermod -l %s %s" % (self.username, new_login)) - self.failUnlessEqual(status, 0, output) - - def testShellChange(self): - """ usermod: Test if user's shell can be changed """ - new_shell = "/bin/sh" - - (status, output) = commands.getstatusoutput("usermod -s %s %s" % (new_shell, self.username)) - self.failUnlessEqual(status, 0, output) - - created = UserInfo() - created.get_info_name(self.username) - self.assertEqual(created["pw_shell"], new_shell) - -class TestGroupadd(unittest.TestCase, ShadowUtilsTestBase): - def setUp(self): - self.groupname = "test-shadow-utils-groups" - - def tearDown(self): - commands.getstatusoutput("groupdel %s" % (self.groupname)) - - def testAddGroup(self): - """ groupadd: Basic adding of a group """ - - expected = GroupInfo() - expected["gr_name"] = self.groupname - - (status, output) = commands.getstatusoutput("groupadd %s" % (self.groupname)) - self.failUnlessEqual(status, 0, output) - - created = GroupInfo() - created.get_info_name(self.groupname) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a group") - - def testAddSystemGroup(self): - """ groupadd: Adding a system group with gid < MIN_GID """ - - expected = GroupInfo() - expected["gr_name"] = self.groupname - defaults = LoginDefsParser() - - (status, output) = commands.getstatusoutput("groupadd -r %s" % (self.groupname)) - self.failUnlessEqual(status, 0, output) - - created = GroupInfo() - created.get_info_name(self.groupname) - self.assertEqual(created["gr_gid"] < defaults["GID_MIN"], True, "FAIL: System group has gid >= GID_MIN") - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not add a system group") - - def testAddExistingGid(self): - """ groupadd: Test if we group with an existing GID can be added """ - (status, output) = commands.getstatusoutput("groupadd %s" % (self.groupname)) - self.failUnlessEqual(status, 0, output) - - gname = "%s-2" % (self.groupname) - - created = GroupInfo() - created.get_info_name(self.groupname) - - # no -o option -> this should fail - (status, output) = commands.getstatusoutput("groupadd -g%s %s" % (created["gr_gid"], gname)) - self.failIfEqual(status, 0, output) - - # override with -o option, should pass now - (status, output) = commands.getstatusoutput("groupadd -g%s -o %s" % (created["gr_gid"], gname)) - self.failUnlessEqual(status, 0, output) - - # test if the new GID is really the same - same_gid = GroupInfo() - same_gid.get_info_name(gname) - self.assertEqual(same_gid["gr_gid"], created["gr_gid"]) - - # clean up - (status, output) = commands.getstatusoutput("groupdel %s" % (gname)) - self.failUnlessEqual(status, 0, output) - - - def testOverrideDefaults(self): - """ groupadd: Test if the defaults can be overriden with the -K option """ - # this is known to not work on older RHELs - test what we are running - rhv = RedHatVersion() - runs = rhv.get_info() - if rhv.is_rhel(): - if runs[1] < 5: - print "This test makes sense for RHEL5+" - return - else: - if runs[1] < 6: - print "This test makes sense for Fedora 6+" - return - - - GID_MIN = 600 - GID_MAX = 625 - - (status, output) = commands.getstatusoutput("groupadd -K GID_MIN=%d -K GID_MAX=%d %s" % - (GID_MIN, GID_MAX, self.groupname)) - self.failUnlessEqual(status, 0, output) - - created = GroupInfo() - created.get_info_name(self.groupname) - self.assertEqual(GID_MIN <= created["gr_gid"] <= GID_MAX, True, "FAIL: created an user with UID of %d" % (created["gr_gid"])) - - - def testFOption(self): - """ groupadd: Tests the -f option of groupadd """ - (status, output) = commands.getstatusoutput("groupadd %s" % (self.groupname)) - self.failUnlessEqual(status, 0, output) - - (status, output) = commands.getstatusoutput("groupadd -f %s" % (self.groupname)) - self.assertEqual(status, 0, output) - -class TestGroupaddInvalidName(unittest.TestCase, ShadowUtilsTestBase): - def testGroupaddInvalidName(self): - """ groupadd: Test adding of a group with an invalid name """ - (status, output) = commands.getstatusoutput("groupadd foo?") - self.assertNotEqual(status, 0, output) - (status, output) = commands.getstatusoutput("groupadd aaaaabbbbbcccccdddddeeeeefffffggg") #33 chars - self.assertNotEqual(status, 0, output) - -class TestGroupaddValidName(unittest.TestCase, ShadowUtilsTestBase): - def testGroupaddValidName(self): - """ groupadd: Test adding and removing of groups with maximal valid name and name ending with $ """ - (status, output) = commands.getstatusoutput("groupadd aaaaabbbbbcccccdddddeeeeefffffgg") #32 chars - self.assertEqual(status, 0, output) - (status, output) = commands.getstatusoutput("groupadd aaaaabbbbbcccccdddddeeeeefffffg\$") #32 chars - self.assertEqual(status, 0, output) - (status, output) = commands.getstatusoutput("groupdel aaaaabbbbbcccccdddddeeeeefffffgg") #32 chars - self.assertEqual(status, 0, output) - (status, output) = commands.getstatusoutput("groupdel aaaaabbbbbcccccdddddeeeeefffffg\$") #32 chars - self.assertEqual(status, 0, output) - - -class TestGroupmod(unittest.TestCase, ShadowUtilsTestBase): - def setUp(self): - self.groupname = "test-shadow-utils-groups" - (status, output) = commands.getstatusoutput("groupadd %s" % (self.groupname)) - self.failUnlessEqual(status, 0, output) - - def tearDown(self): - commands.getstatusoutput("groupdel %s" % (self.groupname)) - - def testChangeGID(self): - """ groupmod: Test changing a gid of a group """ - expected = GroupInfo() - expected["gr_name"] = self.groupname - expected["gr_gid"] = 54321 - - (status, output) = commands.getstatusoutput("groupmod -g%d %s" % (expected["gr_gid"], self.groupname)) - self.failUnlessEqual(status, 0, output) - - created = GroupInfo() - created.get_info_name(self.groupname) - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not change GID of an existing group") - - def testChangeGIDToExistingValue(self): - """ groupmod: Test changing GID to an existing value """ - second_name = "%s-2" % (self.groupname) - - created = GroupInfo() - created.get_info_name(self.groupname) - - expected = GroupInfo() - expected["gr_name"] = self.groupname - expected["gr_gid"] = created["gr_gid"] - - (status, output) = commands.getstatusoutput("groupadd %s" % (second_name)) - self.failUnlessEqual(status, 0, output) - - # try to assingn GID of the first group to the second - this should fail without the -o option - (status, output) = commands.getstatusoutput("groupmod -g%d %s" % (created["gr_gid"], second_name)) - self.failIfEqual(status, 0, output) - - # should pass with the -o option - (status, output) = commands.getstatusoutput("groupmod -g%d -o %s" % (created["gr_gid"], second_name)) - self.failUnlessEqual(status, 0, output) - - self.assertEqual(created.lazy_compare(expected), True, "FAIL: Could not change GID of an existing group to an existing one") - - # clean up - commands.getstatusoutput("groupdel %s" % (second_name)) - self.failUnlessEqual(status, 0, output) - - def testChangeGroupName(self): - """ groupmod: Test changing a group's name """ - second_name = "%s-2" % (self.groupname) - - created = GroupInfo() - created.get_info_name(self.groupname) - - (status, output) = commands.getstatusoutput("groupmod -n%s %s" % (second_name, self.groupname)) - self.failUnlessEqual(status, 0, output) - - changed = GroupInfo() - changed.get_info_gid(created["gr_gid"]) - self.assertEqual(changed["gr_name"], second_name) - self.assertEqual(changed["gr_gid"], created["gr_gid"]) - - # change back, so the group could be deleted by tearDown - (status, output) = commands.getstatusoutput("groupmod -n%s %s" % (self.groupname, second_name)) - self.failUnlessEqual(status, 0, output) - - def testChangeGroupNameExisting(self): - """ groupmod: Test changing a group's name to an existing one """ - existing = "bin" - (status, output) = commands.getstatusoutput("groupmod -n%s %s" % (existing, self.groupname)) - self.assertNotEqual(status, 0, output) # man groupmod -> 9: group name already in use - - def testChangeNonExistingGroup(self): - """ groupmod: Test properties of a non-existing group """ - nonexistent = "foobar" - (status, output) = commands.getstatusoutput("groupmod -nspameggs %s" % (nonexistent)) - self.assertNotEqual(status, 0, status) # man groupmod -> 6: specified group doesn't exist - -class TestGroupdel(unittest.TestCase, ShadowUtilsTestBase): - def testCorrectGroupdel(self): - """ groupdel: Basic usage of groupdel """ - self.groupname = "test-shadow-utils-groups" - (status, output) = commands.getstatusoutput("groupadd %s" % (self.groupname)) - self.failUnlessEqual(status, 0, output) - (status, output) = commands.getstatusoutput("groupdel %s" % (self.groupname)) - self.assertEqual(status, 0, output) - - def testGroupdelNoSuchGroup(self): - """ groupdel: Remove non-existing group """ - (status, output) = commands.getstatusoutput("groupdel foobar") - self.assertNotEqual(status, 0, output) - - def testRemovePrimaryGroup(self): - """ groupdel: Remove a primary group of an user """ - username = "test-groupdel-primary" - (status, output) = commands.getstatusoutput("useradd %s" % (username)) - self.failUnlessEqual(status, 0, output) - - (status, output) = commands.getstatusoutput("groupdel %s" % (username)) - self.assertNotEqual(status, 0, output) - - # clean up - (status, output) = commands.getstatusoutput("userdel -r %s" % (username)) - self.failUnlessEqual(status, 0, output) - -class TestPwckGrpck(unittest.TestCase): - def setUp(self): - self.passwd_path = tempfile.mktemp(suffix="test-pwck-passwd") - self.passwd_file = open(self.passwd_path, "w") - self.group_path = tempfile.mktemp(suffix="test-pwck-grp") - self.group_file = open(self.group_path, "w") - self.gshadow_path = tempfile.mktemp(suffix="test-pwck-gshadow") - self.gshadow_file = open(self.gshadow_path, "w") - - def tearDown(self): - self.passwd_file.close() - self.group_file.close() - self.gshadow_file.close() - - os.remove(self.passwd_path) - os.remove(self.group_path) - os.remove(self.gshadow_path) - - def runPwckCheck(self, passwd, group): - self.passwd_file.truncate() - self.group_file.truncate() - - self.passwd_file.write(passwd) - self.passwd_file.flush() - self.group_file.write(group) - self.group_file.flush() - - command = "pwck -r %s %s" % (self.passwd_path, self.group_path) - return commands.getstatusoutput(command) - - def runGrpCheck(self, group, gshadow): - self.group_file.truncate() - self.gshadow_file.truncate() - - self.gshadow_file.write(gshadow) - self.gshadow_file.flush() - - self.group_file.write(group) - self.group_file.flush() - - command = "grpck -r %s %s" % (self.group_path, self.gshadow_path) - return commands.getstatusoutput(command) - - - def testValidEntries(self): - """ pwck: a valid entry """ - status, output = self.runPwckCheck("foo:x:685:0::/dev/null:/bin/bash", "") - rhv = RedHatVersion() - runs = rhv.get_info() - if rhv.is_rhel(): - if runs[1] < 6: - self.assertEqual(status, 0, output) - else: - self.assertNotEqual(status, 0, output) - - def testNumberOfFields(self): - """ pwck: invalid number of fields in the record """ - not_enough = "foo:x:685:685::/dev/null" - too_many = "foo:x:685:685::/dev/null:/bin/bash:comment" - status, output = self.runPwckCheck(not_enough, "") - self.assertNotEqual(status, 0, output) - - status, output = self.runPwckCheck(too_many, "") - self.assertNotEqual(status, 0, output) - - def testUniqueUserName(self): - """ pwck: unique user name in the record """ - duplicate_username = "foo:x:685:685::/dev/null:/bin/bash\nfoo:x:686:686::/dev/null:/bin/bash" - status, output = self.runPwckCheck(duplicate_username, "") - self.assertNotEqual(status, 0, output) - - def testValidID(self): - """ pwck: invalid UID in the records """ - invalid_ids = [ "foo:x:-1:685::/dev/null:/bin/bash", "foo:x:blah:685::/dev/null:/bin/bash", "foo:x:1234567890:685::/dev/null:/bin/bash" ] - for record in invalid_ids: - status, output = self.runPwckCheck(record, "") - self.assertNotEqual(status, 0, record) - - - def testValidPrimaryGroup(self): - """ pwck: invalid primary group """ - invalid_groups = [ "foo:x:685:-1::/dev/null:/bin/bash", "foo:x:685:blah::/dev/null:/bin/bash", "foo:x:685:1234567890::/dev/null:/bin/bash" ] - for record in invalid_groups: - status, output = self.runPwckCheck("", record) - self.assertNotEqual(status, 0, output) - - def testValidHomeDir(self): - """ pwck: invalid home dir """ - for record in [ "foo:x:685:685::123:/bin/bash", "foo:x:685:685::/path/to/nowhere:/bin/bash", "foo:x:685:1234567890::!:/bin/bash" ]: - status, output = self.runPwckCheck(record, "") - self.assertNotEqual(status, 0, output) - - def testBZ164954(self): - """ grpck: regression test for BZ164954 """ - record = "root:x:0:root\nbin:x:1:root,bin,daemon\ndaemon:x:2:root,bin,daemon\nsys:x:3:root,bin,adm\nadm:x:4:root,adm,daemon" - status, output = self.runGrpCheck("", record) - self.assertNotEqual(status, 0, output) - -if __name__ == "__main__": - broken_on_rhel4 = { "TestUseradd" : [ "testCustomUID", "testCustomGID" ] } - - if os.getuid() != 0: - print "This test must be run as root" - sys.exit(1) - - unittest.main() - diff --git a/tests/tests.yml b/tests/tests.yml deleted file mode 100644 index 09f4769..0000000 --- a/tests/tests.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -# This first play always runs on the local staging system -- hosts: localhost - roles: - - role: standard-test-beakerlib - tags: - - classic - - atomic - tests: - - sanity - required_packages: - - shadow-utils # sanity test needs shadow-utils - - python # sanity test needs python