From 8d1821d0edc6f07fcb9ad02f43e4a77025a4f481 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Wed, 11 Feb 2026 12:56:11 +0100 Subject: [PATCH] passwd.c: add audit messages for passwd Resolves: RHEL-141919 Signed-off-by: Iker Pedrosa --- shadow-4.15.0-passwd-audit.patch | 176 +++++++++++++++++++++++++++++++ shadow-utils.spec | 7 +- 2 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 shadow-4.15.0-passwd-audit.patch diff --git a/shadow-4.15.0-passwd-audit.patch b/shadow-4.15.0-passwd-audit.patch new file mode 100644 index 0000000..d2230db --- /dev/null +++ b/shadow-4.15.0-passwd-audit.patch @@ -0,0 +1,176 @@ +From 7b3deac2de133c45af5b266c573e7ec0b9157b0b Mon Sep 17 00:00:00 2001 +From: Iker Pedrosa +Date: Mon, 9 Feb 2026 10:03:32 +0100 +Subject: [PATCH] src/passwd.c: add audit messages for passwd + +Add comprehensive audit messages for password operations, including +unlock, delete, expire and aging operations. + +Signed-off-by: Iker Pedrosa +--- + src/passwd.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 95 insertions(+), 4 deletions(-) + +diff --git a/src/passwd.c b/src/passwd.c +index 0afae4d7..1fa99448 100644 +--- a/src/passwd.c ++++ b/src/passwd.c +@@ -547,6 +547,7 @@ static void update_noshadow (void) + { + const struct passwd *pw; + struct passwd *npw; ++ int ret; + + if (pw_lock () == 0) { + (void) fprintf (stderr, +@@ -573,8 +574,29 @@ static void update_noshadow (void) + if (NULL == npw) { + oom (); + } +- npw->pw_passwd = update_crypt_pw (npw->pw_passwd); +- if (pw_update (npw) == 0) { ++ npw->pw_passwd = update_crypt_pw (npw->pw_passwd); ++ ret = pw_update(npw); ++#ifdef WITH_AUDIT ++ if (lflg) { ++ audit_logger(AUDIT_ACCT_LOCK, "passwd", ++ "locked-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++ if (uflg) { ++ audit_logger(AUDIT_ACCT_UNLOCK, "passwd", ++ "unlocked-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++ if (dflg) { ++ audit_logger(AUDIT_USER_CHAUTHTOK, "passwd", ++ "deleted-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++#endif /* WITH_AUDIT */ ++ if (ret == 0) { + (void) fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, pw_dbname (), npw->pw_name); +@@ -599,8 +621,18 @@ static void update_noshadow (void) + + static void update_shadow (void) + { ++ const struct passwd *pw; + const struct spwd *sp; + struct spwd *nsp; ++ int ret; ++ ++ pw = pw_locate(name); ++ if (NULL == pw) { ++ fprintf(stderr, ++ _("%s: user '%s' does not exist in %s\n"), ++ Prog, name, pw_dbname ()); ++ fail_exit (E_NOPERM); ++ } + + if (spw_lock () == 0) { + (void) fprintf (stderr, +@@ -691,7 +722,45 @@ static void update_shadow(bool process_selinux) + nsp->sp_lstchg = 0; + } + +- if (spw_update (nsp) == 0) { ++ ret = spw_update(nsp); ++#ifdef WITH_AUDIT ++ if (lflg) { ++ audit_logger(AUDIT_ACCT_LOCK, "passwd", ++ "locked-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++ if (uflg) { ++ audit_logger(AUDIT_ACCT_UNLOCK, "passwd", ++ "unlocked-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++ if (dflg) { ++ audit_logger(AUDIT_USER_CHAUTHTOK, "passwd", ++ "deleted-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++ if (eflg) { ++ audit_logger(AUDIT_USER_MGMT, "passwd", ++ "expired-password", ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++ /* Audit aging parameter changes if any were modified */ ++ if (xflg || nflg || wflg || iflg) { ++ char aging_msg[256]; ++ snprintf(aging_msg, sizeof(aging_msg), ++ "changed-password-aging min=%ld max=%ld warn=%ld inact=%ld", ++ nsp->sp_min, nsp->sp_max, nsp->sp_warn, nsp->sp_inact); ++ audit_logger (AUDIT_USER_MGMT, "passwd", ++ aging_msg, ++ NULL, pw->pw_uid, ++ ret ? SHADOW_AUDIT_SUCCESS : SHADOW_AUDIT_FAILURE); ++ } ++#endif /* WITH_AUDIT */ ++ if (ret == 0) { + (void) fprintf (stderr, + _("%s: failed to prepare the new %s entry '%s'\n"), + Prog, spw_dbname (), nsp->sp_namp); +@@ -755,6 +824,10 @@ main(int argc, char **argv) + do_update_age = true; + } + ++#ifdef WITH_AUDIT ++ audit_help_open(); ++#endif /* WITH_AUDIT */ ++ + /* + * The program behaves differently when executed by root than when + * executed by a normal user. +@@ -987,6 +1060,12 @@ main(int argc, char **argv) + } + + if (anyflag && !amroot) { ++#ifdef WITH_AUDIT ++ audit_logger(AUDIT_USER_CHAUTHTOK, "passwd", ++ "attempted-to-change-password-attribute", ++ NULL, getuid(), ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ + (void) fprintf (stderr, _("%s: Permission denied.\n"), Prog); + exit (E_NOPERM); + } +@@ -1002,6 +1081,12 @@ main(int argc, char **argv) + /* only do this check when getuid()==0 because it's a pre-condition for + changing a password without entering the old one */ + if (amroot && (check_selinux_permit (Prog) != 0)) { ++#ifdef WITH_AUDIT ++ audit_logger(AUDIT_USER_CHAUTHTOK, "passwd", ++ "attempted-to-change-password", ++ NULL, pw->pw_uid, ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ + SYSLOG ((LOG_ALERT, + "root is not authorized by SELinux to change the password of %s", + name)); +@@ -1017,6 +1102,12 @@ main(int argc, char **argv) + * check if I'm root. + */ + if (!amroot && (pw->pw_uid != getuid ())) { ++#ifdef WITH_AUDIT ++ audit_logger(AUDIT_USER_CHAUTHTOK, "passwd", ++ "attempted-to-change-password", ++ NULL, pw->pw_uid, ++ SHADOW_AUDIT_FAILURE); ++#endif /* WITH_AUDIT */ + (void) fprintf (stderr, + _("%s: You may not view or modify password information for %s.\n"), + Prog, name); +-- +2.53.0 + diff --git a/shadow-utils.spec b/shadow-utils.spec index 7f516e5..43d8959 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.15.0 -Release: 9%{?dist} +Release: 10%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow @@ -36,6 +36,8 @@ Patch6: shadow-4.15.0-useradd-fix-write-full-return.patch Patch7: shadow-4.15.0-vipw-restore-terminal.patch # https://github.com/shadow-maint/shadow/commit/c1678a9e2759f60a2daf5e136c76fa6e47d6f400 Patch8: shadow-4.15.0-groupmod-help.patch +# https://github.com/shadow-maint/shadow/commit/03a10499fb6d499e6db06d44007d67893db48e32 +Patch9: shadow-4.15.0-passwd-audit.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 @@ -284,6 +286,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* Wed Feb 11 2026 Iker Pedrosa - 2:4.15.0-10 +- passwd.c: add audit messages for passwd. Resolves: RHEL-141919 + * Thu Nov 27 2025 Iker Pedrosa - 2:4.15.0-9 - groupmod.c: --help wfix. Resolves: RHEL-105779