]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
src/passwd.c: implement reading password from pipe
authorTomas Halman <tomas@halman.net>
Thu, 25 Jan 2024 10:00:09 +0000 (11:00 +0100)
committerSerge Hallyn <serge@hallyn.com>
Thu, 1 Feb 2024 04:16:02 +0000 (22:16 -0600)
New option --stdin/-t is available for root user. It is useful
for automation/setup and it makes shadow utils passwd more versatile.

Signed-off-by: Tomas Halman <tomas@halman.net>
man/passwd.1.xml
src/passwd.c

index 312f7ded15aca6e655b15c141c1e8b54567f40f1..506b134ed95c4f19c4e6b8b27357d42874218136 100644 (file)
          </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>
 
index beb8057300c19ca7ac4af682ff7f10055b903228..939ad79d46228ae0c76c07d1fc7811c939365993 100644 (file)
@@ -68,7 +68,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,
@@ -158,6 +159,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);
 }
@@ -252,7 +254,7 @@ static int new_password (const struct passwd *pw)
                        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"
@@ -266,56 +268,69 @@ static int new_password (const struct passwd *pw)
                }
        }
 
-       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);
-                       MEMZERO(pass);
                        return -1;
                }
-               if (warned && (strcmp (pass, cp) != 0)) {
-                       warned = false;
-               }
-               STRTCPY(pass, cp);
+               STRTCPY (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);
+                               MEMZERO(pass);
+                               return -1;
+                       }
+                       if (warned && (strcmp (pass, cp) != 0)) {
+                               warned = false;
+                       }
+                       STRTCPY(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);
+                               MEMZERO(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);
+               MEMZERO(orig);
+
+               if (i == 0) {
                        MEMZERO(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);
 
-       if (i == 0) {
-               MEMZERO(pass);
-               return -1;
-       }
 
        /*
         * Encrypt the password, then wipe the cleartext password.
@@ -684,6 +699,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.
  *
@@ -751,10 +767,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':
@@ -847,6 +864,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);
                        }
@@ -1038,7 +1064,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 */
@@ -1072,4 +1107,3 @@ int main (int argc, char **argv)
 
        return E_SUCCESS;
 }
-