shadow-utils/shadow-4.14.0-passwd-stdin.patch
Iker Pedrosa 91360f25a8 passwd: Provide binary from this package
Provide binary from this package. Enable libpam and disable
account-tools-setuid. Provide passwd PAM service file. Finally, provide
--stdin option in passwd.

Resolves: #2233275

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2024-02-06 17:16:37 +01:00

289 lines
8.1 KiB
Diff

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 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>-s</option>, <option>--stdin</option>
+ </term>
+ <listitem>
+ <para>
+ This option is used to indicate that passwd should read the new password from standard
+ input, which can be a pipe.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
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;
}
-