91360f25a8
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>
289 lines
8.1 KiB
Diff
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;
|
|
}
|
|
-
|