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/shadow-4.14.0-account-tools-setuid.patch b/shadow-4.14.0-account-tools-setuid.patch new file mode 100644 index 0000000..17d8918 --- /dev/null +++ b/shadow-4.14.0-account-tools-setuid.patch @@ -0,0 +1,383 @@ +diff --git a/src/chpasswd.c b/src/chpasswd.c +index 3a4bd4fe..246e4176 100644 +--- a/src/chpasswd.c ++++ b/src/chpasswd.c +@@ -443,9 +443,11 @@ int main (int argc, char **argv) + char *cp; + const char *salt; + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + bool use_pam = true; + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + + int errors = 0; + int line = 0; +@@ -470,19 +472,23 @@ int main (int argc, char **argv) + process_root_flag ("-R", argc, argv); + prefix = process_prefix_flag ("-P", argc, argv); + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + if (md5flg || eflg || cflg || prefix[0]) { + use_pam = false; + } + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + + OPENLOG ("chpasswd"); + + check_perms (); + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + if (!use_pam) + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + { + is_shadow_pwd = spw_file_present (); + +@@ -544,6 +550,7 @@ int main (int argc, char **argv) + } + newpwd = cp; + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + if (use_pam) { + if (do_pam_passwd_non_interactive ("chpasswd", name, newpwd) != 0) { +@@ -554,6 +561,7 @@ int main (int argc, char **argv) + } + } else + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + { + const struct spwd *sp; + struct spwd newsp; +@@ -673,9 +681,11 @@ int main (int argc, char **argv) + * password database. + */ + if (0 != errors) { ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + if (!use_pam) + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + { + fprintf (stderr, + _("%s: error detected, changes ignored\n"), +@@ -684,9 +694,11 @@ int main (int argc, char **argv) + fail_exit (1); + } + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + if (!use_pam) + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + { + /* Save the changes */ + close_files (); +diff --git a/src/groupmems.c b/src/groupmems.c +index 63a1601c..73f7310e 100644 +--- a/src/groupmems.c ++++ b/src/groupmems.c +@@ -14,9 +14,11 @@ + #include + #include + #include ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + #include "pam_defs.h" + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + #include + + #include "alloc.h" +@@ -430,6 +432,7 @@ static void process_flags (int argc, char **argv) + static void check_perms (void) + { + if (!list) { ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + pam_handle_t *pamh = NULL; + int retval; +@@ -463,7 +466,8 @@ static void check_perms (void) + fail_exit (1); + } + (void) pam_end (pamh, retval); +-#endif ++#endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + } + } + +diff --git a/src/newusers.c b/src/newusers.c +index 09e14a48..96b60de2 100644 +--- a/src/newusers.c ++++ b/src/newusers.c +@@ -59,6 +59,7 @@ + const char *Prog; + + static bool rflg = false; /* create a system account */ ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + static /*@null@*//*@observer@*/char *crypt_method = NULL; + #define cflg (NULL != crypt_method) +@@ -75,6 +76,7 @@ static long bcrypt_rounds = 13; + static long yescrypt_cost = 5; + #endif /* USE_YESCRYPT */ + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + + static bool is_shadow; + #ifdef SHADOWGRP +@@ -97,9 +99,11 @@ NORETURN static void fail_exit (int); + static int add_group (const char *, const char *, gid_t *, gid_t); + static int get_user_id (const char *, uid_t *); + static int add_user (const char *, uid_t, gid_t); ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + static int update_passwd (struct passwd *, const char *); + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + static int add_passwd (struct passwd *, const char *); + static void process_flags (int argc, char **argv); + static void check_flags (void); +@@ -121,6 +125,7 @@ static void usage (int status) + "Options:\n"), + Prog); + (void) fputs (_(" -b, --badname allow bad names\n"), usageout); ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + (void) fprintf (usageout, + _(" -c, --crypt-method METHOD the crypt method (one of %s)\n"), +@@ -136,9 +141,11 @@ static void usage (int status) + #endif + ); + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); + (void) fputs (_(" -r, --system create system accounts\n"), usageout); + (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) + (void) fputs (_(" -s, --sha-rounds number of rounds for the SHA, BCRYPT\n" +@@ -146,6 +153,7 @@ static void usage (int status) + usageout); + #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + (void) fputs ("\n", usageout); + + exit (status); +@@ -405,6 +413,7 @@ static int add_user (const char *name, uid_t uid, gid_t gid) + return (pw_update (&pwent) == 0) ? -1 : 0; + } + ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + /* + * update_passwd - update the password in the passwd entry +@@ -457,6 +466,7 @@ static int update_passwd (struct passwd *pwd, const char *password) + return 0; + } + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + + /* + * add_passwd - add or update the encrypted password +@@ -465,10 +475,13 @@ static int add_passwd (struct passwd *pwd, const char *password) + { + const struct spwd *sp; + struct spwd spent; ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + char *cp; + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + void *crypt_arg = NULL; + if (NULL != crypt_method) { +@@ -505,13 +518,14 @@ static int add_passwd (struct passwd *pwd, const char *password) + return update_passwd (pwd, password); + } + #endif /* USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + + /* + * Do the first and easiest shadow file case. The user already + * exists in the shadow password file. + */ + sp = spw_locate (pwd->pw_name); +-#ifndef USE_PAM ++#if !defined(ACCT_TOOLS_SETUID) && !defined(USE_PAM) + if (NULL != sp) { + spent = *sp; + if ( (NULL != crypt_method) +@@ -547,7 +561,7 @@ static int add_passwd (struct passwd *pwd, const char *password) + if (strcmp (pwd->pw_passwd, "x") != 0) { + return update_passwd (pwd, password); + } +-#else /* USE_PAM */ ++#else /* !ACCT_TOOLS_SETUID && !USE_PAM */ + /* + * If there is already a shadow entry, do not touch it. + * If there is already a passwd entry with a password, do not +@@ -558,14 +572,14 @@ static int add_passwd (struct passwd *pwd, const char *password) + || (strcmp (pwd->pw_passwd, "x") != 0)) { + return 0; + } +-#endif /* USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID && !USE_PAM */ + + /* + * Now the really hard case - I need to create an entirely new + * shadow password file entry. + */ + spent.sp_namp = pwd->pw_name; +-#ifndef USE_PAM ++#if !defined(ACCT_TOOLS_SETUID) && !defined(USE_PAM) + if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) { + spent.sp_pwdp = (char *)password; + } else { +@@ -610,35 +624,41 @@ static int add_passwd (struct passwd *pwd, const char *password) + static void process_flags (int argc, char **argv) + { + int c; ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) + int bad_s; + #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + static struct option long_options[] = { + {"badname", no_argument, NULL, 'b'}, ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + {"crypt-method", required_argument, NULL, 'c'}, + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + {"help", no_argument, NULL, 'h'}, + {"system", no_argument, NULL, 'r'}, + {"root", required_argument, NULL, 'R'}, ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) + {"sha-rounds", required_argument, NULL, 's'}, + #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + {NULL, 0, NULL, '\0'} + }; + + while ((c = getopt_long (argc, argv, +-#ifndef USE_PAM ++#if !defined(ACCT_TOOLS_SETUID) && !defined(USE_PAM) + #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) + "c:bhrs:", + #else /* !USE_SHA_CRYPT && !USE_BCRYPT && !USE_YESCRYPT */ + "c:bhr", + #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ +-#else /* USE_PAM */ ++#else /* !ACCT_TOOLS_SETUID && !USE_PAM */ + "bhr", + #endif + long_options, NULL)) != -1) { +@@ -646,11 +666,13 @@ static void process_flags (int argc, char **argv) + case 'b': + allow_bad_names = true; + break; ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + case 'c': + crypt_method = optarg; + break; + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + case 'h': + usage (EXIT_SUCCESS); + break; +@@ -659,6 +681,7 @@ static void process_flags (int argc, char **argv) + break; + case 'R': /* no-op, handled in process_root_flag () */ + break; ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) + case 's': +@@ -698,6 +721,7 @@ static void process_flags (int argc, char **argv) + break; + #endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_YESCRYPT */ + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + default: + usage (EXIT_FAILURE); + break; +@@ -730,6 +754,7 @@ static void process_flags (int argc, char **argv) + */ + static void check_flags (void) + { ++#ifndef ACCT_TOOLS_SETUID + #ifndef USE_PAM + #if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_YESCRYPT) + if (sflg && !cflg) { +@@ -762,6 +787,7 @@ static void check_flags (void) + } + } + #endif /* !USE_PAM */ ++#endif /* !ACCT_TOOLS_SETUID */ + } + + /* +@@ -1052,12 +1078,14 @@ int main (int argc, char **argv) + int line = 0; + uid_t uid; + gid_t gid; ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + int *lines = NULL; + char **usernames = NULL; + char **passwords = NULL; + unsigned int nusers = 0; + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + + Prog = Basename (argv[0]); + log_set_progname(Prog); +@@ -1196,6 +1224,7 @@ int main (int argc, char **argv) + } + newpw = *pw; + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + /* keep the list of user/password for later update by PAM */ + nusers++; +@@ -1212,6 +1241,7 @@ int main (int argc, char **argv) + usernames[nusers-1] = strdup (fields[0]); + passwords[nusers-1] = strdup (fields[1]); + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + if (add_passwd (&newpw, fields[1]) != 0) { + fprintf (stderr, + _("%s: line %d: can't update password\n"), +@@ -1328,6 +1358,7 @@ int main (int argc, char **argv) + nscd_flush_cache ("group"); + sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP); + ++#ifdef ACCT_TOOLS_SETUID + #ifdef USE_PAM + unsigned int i; + /* Now update the passwords using PAM */ +@@ -1340,6 +1371,7 @@ int main (int argc, char **argv) + } + } + #endif /* USE_PAM */ ++#endif /* ACCT_TOOLS_SETUID */ + + exit (EXIT_SUCCESS); + } diff --git a/shadow-4.14.0-passwd-stdin.patch b/shadow-4.14.0-passwd-stdin.patch new file mode 100644 index 0000000..2603350 --- /dev/null +++ b/shadow-4.14.0-passwd-stdin.patch @@ -0,0 +1,288 @@ +diff -up shadow-4.14.0/libmisc/agetpass.c.orig shadow-4.14.0/libmisc/agetpass.c +--- shadow-4.14.0/libmisc/agetpass.c.orig 2024-01-24 20:06:20.557577853 +0100 ++++ shadow-4.14.0/libmisc/agetpass.c 2024-01-24 21:21:06.379445080 +0100 +@@ -32,6 +32,7 @@ + * SYNOPSIS + * [[gnu::malloc(erase_pass)]] + * char *agetpass(const char *prompt); ++ * char *agetpass_stdin(); + * + * void erase_pass(char *pass); + * +@@ -64,6 +65,10 @@ + * erased by calling erase_pass(), to avoid possibly leaking the + * password. + * ++ * agetpass_stdin() ++ * This function is the same as previous one (agetpass). Just the ++ * password is read from stdin and terminal is not required. ++ * + * erase_pass() + * This function first clears the password, by calling + * explicit_bzero(3) (or an equivalent call), and then frees the +@@ -92,8 +97,8 @@ + */ + + +-char * +-agetpass(const char *prompt) ++static char * ++agetpass_internal(const char *prompt, int flags) + { + char *pass; + size_t len; +@@ -110,7 +115,7 @@ agetpass(const char *prompt) + if (pass == NULL) + return NULL; + +- if (readpassphrase(prompt, pass, PASS_MAX + 2, RPP_REQUIRE_TTY) == NULL) ++ if (readpassphrase(prompt, pass, PASS_MAX + 2, flags) == NULL) + goto fail; + + len = strlen(pass); +@@ -126,6 +131,17 @@ fail: + return NULL; + } + ++char * ++agetpass(const char *prompt) ++{ ++ return agetpass_internal(prompt, RPP_REQUIRE_TTY); ++} ++ ++char * ++agetpass_stdin() ++{ ++ return agetpass_internal(NULL, RPP_STDIN); ++} + + void + erase_pass(char *pass) +diff -up shadow-4.14.0/lib/prototypes.h.orig shadow-4.14.0/lib/prototypes.h +--- shadow-4.14.0/lib/prototypes.h.orig 2024-01-24 22:06:18.786184942 +0100 ++++ shadow-4.14.0/lib/prototypes.h 2024-01-24 20:19:45.299231059 +0100 +@@ -47,6 +47,7 @@ extern int expire (const struct passwd * + extern void erase_pass(char *pass); + ATTR_MALLOC(erase_pass) + extern char *agetpass(const char *prompt); ++extern char *agetpass_stdin(); + + /* isexpired.c */ + extern int isexpired (const struct passwd *, /*@null@*/const struct spwd *); +diff -up shadow-4.14.0/man/passwd.1.xml.orig shadow-4.14.0/man/passwd.1.xml +--- shadow-4.14.0/man/passwd.1.xml.orig 2024-01-24 20:33:31.438972506 +0100 ++++ shadow-4.14.0/man/passwd.1.xml 2024-01-29 17:36:31.082495245 +0100 +@@ -341,6 +341,17 @@ + + + ++ ++ ++ , ++ ++ ++ ++ This option is used to indicate that passwd should read the new password from standard ++ input, which can be a pipe. ++ ++ ++ + + + +diff -up shadow-4.14.0/src/passwd.c.orig shadow-4.14.0/src/passwd.c +--- shadow-4.14.0/src/passwd.c.orig 2024-01-24 13:57:15.714549266 +0100 ++++ shadow-4.14.0/src/passwd.c 2024-01-29 17:33:59.421508534 +0100 +@@ -65,7 +65,8 @@ static bool + Sflg = false, /* -S - show password status */ + uflg = false, /* -u - unlock the user's password */ + wflg = false, /* -w - set warning days */ +- xflg = false; /* -x - set maximum days */ ++ xflg = false, /* -x - set maximum days */ ++ sflg = false; /* -s - read passwd from stdin */ + + /* + * set to 1 if there are any flags which require root privileges, +@@ -156,6 +157,7 @@ usage (int status) + (void) fputs (_(" -w, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"), usageout); + (void) fputs (_(" -x, --maxdays MAX_DAYS set maximum number of days before password\n" + " change to MAX_DAYS\n"), usageout); ++ (void) fputs (_(" -s, --stdin read new token from stdin\n"), usageout); + (void) fputs ("\n", usageout); + exit (status); + } +@@ -275,7 +277,7 @@ static int new_password (const struct pa + pass_max_len = getdef_num ("PASS_MAX_LEN", 8); + } + } +- if (!qflg) { ++ if (!qflg && !sflg) { + if (pass_max_len == -1) { + (void) printf (_( + "Enter the new password (minimum of %d characters)\n" +@@ -289,55 +291,67 @@ static int new_password (const struct pa + } + } + +- warned = false; +- for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) { +- cp = agetpass (_("New password: ")); ++ if (sflg) { ++ /* ++ * root is setting the passphrase from stdin ++ */ ++ cp = agetpass_stdin (); + if (NULL == cp) { +- memzero (orig, sizeof orig); +- memzero (pass, sizeof pass); + return -1; + } +- if (warned && (strcmp (pass, cp) != 0)) { +- warned = false; +- } + STRFCPY (pass, cp); + erase_pass (cp); ++ } else { ++ warned = false; ++ for (i = getdef_num ("PASS_CHANGE_TRIES", 5); i > 0; i--) { ++ cp = agetpass (_("New password: ")); ++ if (NULL == cp) { ++ memzero (orig, sizeof orig); ++ memzero (pass, sizeof pass); ++ return -1; ++ } ++ if (warned && (strcmp (pass, cp) != 0)) { ++ warned = false; ++ } ++ STRFCPY (pass, cp); ++ erase_pass (cp); + +- if (!amroot && !obscure(orig, pass, pw)) { +- (void) puts (_("Try again.")); +- continue; +- } ++ if (!amroot && !obscure(orig, pass, pw)) { ++ (void) puts (_("Try again.")); ++ continue; ++ } + +- /* +- * If enabled, warn about weak passwords even if you are +- * root (enter this password again to use it anyway). +- * --marekm +- */ +- if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN") +- && !obscure(orig, pass, pw)) { +- (void) puts (_("\nWarning: weak password (enter it again to use it anyway).")); +- warned = true; +- continue; ++ /* ++ * If enabled, warn about weak passwords even if you are ++ * root (enter this password again to use it anyway). ++ * --marekm ++ */ ++ if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN") ++ && !obscure(orig, pass, pw)) { ++ (void) puts (_("\nWarning: weak password (enter it again to use it anyway).")); ++ warned = true; ++ continue; ++ } ++ cp = agetpass (_("Re-enter new password: ")); ++ if (NULL == cp) { ++ memzero (orig, sizeof orig); ++ memzero (pass, sizeof pass); ++ return -1; ++ } ++ if (strcmp (cp, pass) != 0) { ++ erase_pass (cp); ++ (void) fputs (_("They don't match; try again.\n"), stderr); ++ } else { ++ erase_pass (cp); ++ break; ++ } + } +- cp = agetpass (_("Re-enter new password: ")); +- if (NULL == cp) { +- memzero (orig, sizeof orig); ++ memzero (orig, sizeof orig); ++ ++ if (i == 0) { + memzero (pass, sizeof pass); + return -1; + } +- if (strcmp (cp, pass) != 0) { +- erase_pass (cp); +- (void) fputs (_("They don't match; try again.\n"), stderr); +- } else { +- erase_pass (cp); +- break; +- } +- } +- memzero (orig, sizeof orig); +- +- if (i == 0) { +- memzero (pass, sizeof pass); +- return -1; + } + + /* +@@ -714,6 +728,7 @@ static void update_shadow (void) + * -u unlock the password of the named account (*) + * -w # set sp_warn to # days (*) + * -x # set sp_max to # days (*) ++ * -s read password from stdin + * + * (*) requires root permission to execute. + * +@@ -781,10 +796,11 @@ int main (int argc, char **argv) + {"unlock", no_argument, NULL, 'u'}, + {"warndays", required_argument, NULL, 'w'}, + {"maxdays", required_argument, NULL, 'x'}, ++ {"stdin", no_argument, NULL, 's'}, + {NULL, 0, NULL, '\0'} + }; + +- while ((c = getopt_long (argc, argv, "adehi:kln:qr:R:P:Suw:x:", ++ while ((c = getopt_long (argc, argv, "adehi:kln:qr:R:P:Suw:x:s", + long_options, NULL)) != -1) { + switch (c) { + case 'a': +@@ -877,6 +893,15 @@ int main (int argc, char **argv) + xflg = true; + anyflag = true; + break; ++ case 's': ++ if (!amroot) { ++ (void) fprintf (stderr, ++ _("%s: only root can use --stdin/-s option\n"), ++ Prog); ++ usage (E_BAD_ARG); ++ } ++ sflg = true; ++ break; + default: + usage (E_BAD_ARG); + } +@@ -1068,7 +1093,16 @@ int main (int argc, char **argv) + * Don't set the real UID for PAM... + */ + if (!anyflag && use_pam) { +- do_pam_passwd (name, qflg, kflg); ++ if (sflg) { ++ cp = agetpass_stdin (); ++ if (cp == NULL) { ++ exit (E_FAILURE); ++ } ++ do_pam_passwd_non_interactive ("passwd", name, cp); ++ erase_pass (cp); ++ } else { ++ do_pam_passwd (name, qflg, kflg); ++ } + exit (E_SUCCESS); + } + #endif /* USE_PAM */ +@@ -1102,4 +1136,3 @@ int main (int argc, char **argv) + + return E_SUCCESS; + } +- diff --git a/shadow-4.14.0-remove-libcrack.patch b/shadow-4.14.0-remove-libcrack.patch new file mode 100644 index 0000000..4dc1328 --- /dev/null +++ b/shadow-4.14.0-remove-libcrack.patch @@ -0,0 +1,306 @@ +From 43b4e5a6c41f5c43cad18810f9229e40e8c4a57e Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Mon, 30 Oct 2023 12:53:37 +0100 +Subject: [PATCH 1/2] Remove FascistHistory() and FascistHistoryPw() calls + +These functions don't seem to exist anymore. I can't find them in +Debian, nor in a web search. They probably were functions from an +ancient implementation of cracklib that doesn't exist anymore. + +$ git remote -v +origin git@github.com:cracklib/cracklib.git (fetch) +origin git@github.com:cracklib/cracklib.git (push) +$ grep -rni fascisthistory +$ git log --grep FascistHistory +$ git log -S FascistHistory + +Closes: +Cc: Mike Frysinger +Acked-by: Michael Vetter +Signed-off-by: Alejandro Colomar +--- + configure.ac | 4 ---- + libmisc/obscure.c | 8 -------- + src/passwd.c | 33 ++------------------------------- + 3 files changed, 2 insertions(+), 43 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 2c8cca3f..5c8c7764 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -526,10 +526,6 @@ if test "$with_libcrack" = "yes"; then + echo "checking cracklib flavour, don't be surprised by the results" + AC_CHECK_LIB(crack, FascistCheck, + [LIBCRACK=-lcrack AC_DEFINE(HAVE_LIBCRACK, 1, [Defined if you have libcrack.])]) +- AC_CHECK_LIB(crack, FascistHistory, +- AC_DEFINE(HAVE_LIBCRACK_HIST, 1, [Defined if you have the ts&szs cracklib.])) +- AC_CHECK_LIB(crack, FascistHistoryPw, +- AC_DEFINE(HAVE_LIBCRACK_PW, 1, [Defined if it includes *Pw functions.])) + fi + + if test "$with_btrfs" != "no"; then +diff --git a/libmisc/obscure.c b/libmisc/obscure.c +index ccffb71d..4070d4e4 100644 +--- a/libmisc/obscure.c ++++ b/libmisc/obscure.c +@@ -100,11 +100,7 @@ static /*@observer@*//*@null@*/const char *password_check ( + #ifdef HAVE_LIBCRACK + char *dictpath; + +-#ifdef HAVE_LIBCRACK_PW +- char *FascistCheckPw (); +-#else + char *FascistCheck (); +-#endif + #endif + + if (strcmp (new, old) == 0) { +@@ -133,11 +129,7 @@ static /*@observer@*//*@null@*/const char *password_check ( + + dictpath = getdef_str ("CRACKLIB_DICTPATH"); + if (NULL != dictpath) { +-#ifdef HAVE_LIBCRACK_PW +- msg = FascistCheckPw (new, dictpath, pwdp); +-#else + msg = FascistCheck (new, dictpath); +-#endif + } + #endif + } +diff --git a/src/passwd.c b/src/passwd.c +index 67608619..a4f49320 100644 +--- a/src/passwd.c ++++ b/src/passwd.c +@@ -114,7 +114,6 @@ static bool do_update_pwd = false; + /* local function prototypes */ + NORETURN static void usage (int); + +-static bool reuse (const char *, const struct passwd *); + static int new_password (const struct passwd *); + + static void check_password (const struct passwd *, const struct spwd *); +@@ -163,27 +162,6 @@ usage (int status) + exit (status); + } + +-static bool reuse (const char *pass, const struct passwd *pw) +-{ +-#ifdef HAVE_LIBCRACK_HIST +- const char *reason; +- +-#ifdef HAVE_LIBCRACK_PW +- const char *FascistHistoryPw (const char *, const struct passwd *); +- +- reason = FascistHistory (pass, pw); +-#else /* !HAVE_LIBCRACK_PW */ +- const char *FascistHistory (const char *, int); +- +- reason = FascistHistory (pass, pw->pw_uid); +-#endif /* !HAVE_LIBCRACK_PW */ +- if (NULL != reason) { +- (void) printf (_("Bad password: %s. "), reason); +- return true; +- } +-#endif /* HAVE_LIBCRACK_HIST */ +- return false; +-} + + /* + * new_password - validate old password and replace with new (both old and +@@ -202,10 +180,6 @@ static int new_password (const struct passwd *pw) + int pass_max_len = -1; + const char *method; + +-#ifdef HAVE_LIBCRACK_HIST +- int HistUpdate (const char *, const char *); +-#endif /* HAVE_LIBCRACK_HIST */ +- + /* + * Authenticate the user. The user will be prompted for their own + * password. +@@ -306,7 +280,7 @@ static int new_password (const struct passwd *pw) + STRFCPY (pass, cp); + erase_pass (cp); + +- if (!amroot && (!obscure (orig, pass, pw) || reuse (pass, pw))) { ++ if (!amroot && !obscure(orig, pass, pw)) { + (void) puts (_("Try again.")); + continue; + } +@@ -317,7 +291,7 @@ static int new_password (const struct passwd *pw) + * --marekm + */ + if (amroot && !warned && getdef_bool ("PASS_ALWAYS_WARN") +- && (!obscure (orig, pass, pw) || reuse (pass, pw))) { ++ && !obscure(orig, pass, pw)) { + (void) puts (_("\nWarning: weak password (enter it again to use it anyway).")); + warned = true; + continue; +@@ -357,9 +331,6 @@ static int new_password (const struct passwd *pw) + return -1; + } + +-#ifdef HAVE_LIBCRACK_HIST +- HistUpdate (pw->pw_name, crypt_passwd); +-#endif /* HAVE_LIBCRACK_HIST */ + STRFCPY (crypt_passwd, cp); + return 0; + } +-- +2.43.0 + + +From 45f34ee8c196a98397504cb7ed8576b6f1825cf9 Mon Sep 17 00:00:00 2001 +From: Alejandro Colomar +Date: Mon, 30 Oct 2023 13:31:42 +0100 +Subject: [PATCH 2/2] Remove libcrack support + +Signed-off-by: Alejandro Colomar +--- + configure.ac | 11 ----------- + etc/login.defs | 5 ----- + lib/getdef.c | 1 - + libmisc/obscure.c | 22 ---------------------- + libsubid/Makefile.am | 1 - + src/Makefile.am | 2 +- + 7 files changed, 2 insertions(+), 42 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 5c8c7764..c2b0a1a5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -243,9 +243,6 @@ AC_ARG_WITH(skey, + AC_ARG_WITH(tcb, + [AS_HELP_STRING([--with-tcb], [use tcb support (incomplete) @<:@default=yes if found@:>@])], + [with_tcb=$withval], [with_tcb=maybe]) +-AC_ARG_WITH(libcrack, +- [AS_HELP_STRING([--with-libcrack], [use libcrack @<:@default=no@:>@])], +- [with_libcrack=$withval], [with_libcrack=no]) + AC_ARG_WITH(sha-crypt, + [AS_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])], + [with_sha_crypt=$withval], [with_sha_crypt=yes]) +@@ -521,13 +518,6 @@ if test "$with_audit" != "no"; then + fi + fi + +-AC_SUBST(LIBCRACK) +-if test "$with_libcrack" = "yes"; then +- echo "checking cracklib flavour, don't be surprised by the results" +- AC_CHECK_LIB(crack, FascistCheck, +- [LIBCRACK=-lcrack AC_DEFINE(HAVE_LIBCRACK, 1, [Defined if you have libcrack.])]) +-fi +- + if test "$with_btrfs" != "no"; then + AC_CHECK_HEADERS([sys/statfs.h linux/magic.h linux/btrfs_tree.h], \ + [btrfs_headers="yes"], [btrfs_headers="no"]) +@@ -768,7 +758,6 @@ echo + echo "shadow will be compiled with the following features:" + echo + echo " auditing support: $with_audit" +-echo " CrackLib support: $with_libcrack" + echo " PAM support: $with_libpam" + if test "$with_libpam" = "yes"; then + echo " suid account management tools: $enable_acct_tools_setuid" +diff --git a/etc/login.defs b/etc/login.defs +index 114dbcd9..33622c29 100644 +--- a/etc/login.defs ++++ b/etc/login.defs +@@ -227,11 +227,6 @@ PASS_WARN_AGE 7 + # + SU_WHEEL_ONLY no + +-# +-# If compiled with cracklib support, sets the path to the dictionaries +-# +-CRACKLIB_DICTPATH /var/cache/cracklib/cracklib_dict +- + # + # Min/max values for automatic uid selection in useradd(8) + # +diff --git a/lib/getdef.c b/lib/getdef.c +index 977660c2..d64e6343 100644 +--- a/lib/getdef.c ++++ b/lib/getdef.c +@@ -39,7 +39,6 @@ struct itemdef { + #define PAMDEFS \ + {"CHFN_AUTH", NULL}, \ + {"CHSH_AUTH", NULL}, \ +- {"CRACKLIB_DICTPATH", NULL}, \ + {"ENV_HZ", NULL}, \ + {"ENVIRON_FILE", NULL}, \ + {"ENV_TZ", NULL}, \ +diff --git a/libmisc/obscure.c b/libmisc/obscure.c +index 4070d4e4..2aece68b 100644 +--- a/libmisc/obscure.c ++++ b/libmisc/obscure.c +@@ -12,11 +12,6 @@ + #ident "$Id$" + + +-/* +- * This version of obscure.c contains modifications to support "cracklib" +- * by Alec Muffet (alec.muffett@uk.sun.com). You must obtain the Cracklib +- * library source code for this function to operate. +- */ + #include + #include + +@@ -97,12 +92,6 @@ static /*@observer@*//*@null@*/const char *password_check ( + const char *msg = NULL; + char *oldmono, *newmono, *wrapped; + +-#ifdef HAVE_LIBCRACK +- char *dictpath; +- +- char *FascistCheck (); +-#endif +- + if (strcmp (new, old) == 0) { + return _("no change"); + } +@@ -121,17 +110,6 @@ static /*@observer@*//*@null@*/const char *password_check ( + msg = _("too similar"); + } else if (strstr (wrapped, newmono) != NULL) { + msg = _("rotated"); +- } else { +-#ifdef HAVE_LIBCRACK +- /* +- * Invoke Alec Muffett's cracklib routines. +- */ +- +- dictpath = getdef_str ("CRACKLIB_DICTPATH"); +- if (NULL != dictpath) { +- msg = FascistCheck (new, dictpath); +- } +-#endif + } + strzero (newmono); + strzero (oldmono); +diff --git a/libsubid/Makefile.am b/libsubid/Makefile.am +index 5ba0ab35..b6488e77 100644 +--- a/libsubid/Makefile.am ++++ b/libsubid/Makefile.am +@@ -8,7 +8,6 @@ MISCLIBS = \ + $(LIBAUDIT) \ + $(LIBSELINUX) \ + $(LIBSEMANAGE) \ +- $(LIBCRACK) \ + $(LIBCRYPT_NOPAM) \ + $(LIBSKEY) \ + $(LIBMD) \ +diff --git a/src/Makefile.am b/src/Makefile.am +index fcfee9d2..b6cb09ef 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -123,7 +123,7 @@ login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(L + newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT) $(LIBECONF) + newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT) $(LIBECONF) -ldl + nologin_LDADD = +-passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBECONF) -ldl ++passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBECONF) -ldl + pwck_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) + pwconv_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) + pwunconv_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBECONF) +-- +2.43.0 + 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 633f1fe..416cfa1 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.14.0 -Release: 4%{?dist} +Release: 5%{?dist} Epoch: 2 License: BSD-3-Clause AND GPL-2.0-or-later URL: https://github.com/shadow-maint/shadow @@ -12,6 +12,7 @@ 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 @@ -25,10 +26,18 @@ Patch1: shadow-4.2.1-date-parsing.patch 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 +# Probably non-upstreamable +Patch4: shadow-4.14.0-account-tools-setuid.patch +# https://github.com/shadow-maint/shadow/commit/43b4e5a6c41f5c43cad18810f9229e40e8c4a57e +# https://github.com/shadow-maint/shadow/commit/45f34ee8c196a98397504cb7ed8576b6f1825cf9 +Patch5: shadow-4.14.0-remove-libcrack.patch +# https://github.com/shadow-maint/shadow/pull/927 +Patch6: shadow-4.14.0-passwd-stdin.patch ### Dependencies ### Requires: audit-libs >= 1.6.5 Requires: libselinux >= 1.25.2-1 +Requires: pam-libs Requires: setup ### Build Dependencies ### @@ -51,9 +60,12 @@ BuildRequires: libsemanage-devel BuildRequires: libtool BuildRequires: libxslt BuildRequires: make +BuildRequires: pam-devel ### Provides ### Provides: shadow = %{epoch}:%{version}-%{release} +Provides: passwd = 0.80-18 +Obsoletes: passwd <= 0.80-19 %description The shadow-utils package includes the necessary programs for @@ -112,6 +124,7 @@ autoreconf --enable-shadowgrp \ --enable-man \ --with-audit \ + --with-libpam \ --with-sha-crypt \ --with-bcrypt \ --with-yescrypt \ @@ -123,7 +136,8 @@ autoreconf --enable-shared \ --with-group-name-max-length=32 \ --enable-lastlog \ - --enable-logind=no + --enable-logind=no \ + --disable-account-tools-setuid %make_build %install @@ -131,6 +145,8 @@ autoreconf 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}/passwd ln -s useradd $RPM_BUILD_ROOT%{_sbindir}/adduser @@ -145,7 +161,6 @@ 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 @@ -162,8 +177,6 @@ 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.* @@ -187,6 +200,8 @@ 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. + find $RPM_BUILD_ROOT%{_mandir} -depth -type d -empty -delete %find_lang shadow for dir in $(ls -1d $RPM_BUILD_ROOT%{_mandir}/{??,??_??}) ; do @@ -211,6 +226,7 @@ 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}/passwd %{_bindir}/sg %attr(4755,root,root) %{_bindir}/chage %attr(4755,root,root) %{_bindir}/gpasswd @@ -218,6 +234,7 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %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* @@ -235,6 +252,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* @@ -264,6 +282,12 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.a %{_libdir}/libsubid.so %changelog +* 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