Print this page
4107 Add passwd option to read passwords from stdin

@@ -28,10 +28,13 @@
 
 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
 /*        All Rights Reserved   */
 
 /*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+/*
  * passwd is a program whose sole purpose is to manage
  * the password file, map, or table. It allows system administrator
  * to add, change and display password attributes.
  * Non privileged user can change password or display
  * password attributes which corresponds to their login name.

@@ -82,10 +85,11 @@
 #define EFLAG 0x400             /* change shell */
 #define GFLAG 0x800             /* change gecos information */
 #define HFLAG 0x1000            /* change home directory */
 #define XFLAG 0x2000            /* no login */
 #define UFLAG 0x4000            /* unlock user's password */
+#define STFLAG 0x6000           /* read the password from stdin */
 
 #define NONAGEFLAG      (EFLAG | GFLAG | HFLAG)
 #define AGEFLAG (LFLAG | FFLAG | MFLAG | NFLAG | WFLAG | XFLAG | UFLAG)
 #define MUTEXFLAG       (DFLAG | LFLAG | XFLAG | UFLAG | SAFLAG)
 

@@ -176,10 +180,12 @@
 static uid_t            uid;
 static char             *prognamep;
 static long             maxdate;        /* password aging information */
 static int              passwd_conv(int, struct pam_message **,
                             struct pam_response **, void *);
+static int              stdin_conv(int, struct pam_message **,
+                            struct pam_response **, void *);
 static struct pam_conv  pam_conv = {passwd_conv, NULL};
 static pam_handle_t     *pamh;          /* Authentication handle */
 static char             *usrname;       /* user whose attribute we update */
 static adt_session_data_t *ah;  /* audit session handle */
 static adt_event_data_t *event = NULL; /* event to be generated */

@@ -232,12 +238,13 @@
         int     i;
         attrlist *attributes = NULL;
         char    *input;
         int     tries = 1;
         int     updated_reps;
+        ssize_t s;
+        char    st_pass[PASS_MAX];
 
-
         if ((prognamep = strrchr(argv[0], '/')) != NULL)
                 ++prognamep;
         else
                 prognamep = argv[0];
 

@@ -292,10 +299,20 @@
                 }
         } else {
                 usrname = argv[optind];
         }
 
+        if (flag == STFLAG) {
+                if ((s = read(STDIN_FILENO, st_pass, sizeof (st_pass))) <= 0)
+                        passwd_exit(FMERR);
+
+                st_pass[s - 1] = '\0';
+                if ((pam_conv.appdata_ptr = strdup(st_pass)) == NULL)
+                        passwd_exit(FMERR);
+                pam_conv.conv = stdin_conv;
+        }
+
         if (pam_start("passwd", usrname, &pam_conv, &pamh) != PAM_SUCCESS) {
                 passwd_exit(NOPERM);
         }
 
         auth_rep.type = repository.type;

@@ -360,11 +377,11 @@
                 /* system error */
                 passwd_exit(FMERR);
                 break;
         }
 
-        if (flag == 0) {                        /* changing user password */
+        if (flag == STFLAG || flag == 0) {      /* changing user password */
                 int     chk_authtok = 0;        /* check password strength */
 
                 dprintf1("call pam_chauthtok() repository name =%s\n",
                     repository.type);
 

@@ -686,11 +703,11 @@
         int     opt;
         int     flag;
 
         flag = 0;
 
-        while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:N")) != EOF) {
+        while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:N:S")) != EOF) {
                 switch (opt) {
 
                 case 'r': /* Repository Specified */
                         /* repository: this option should be specified first */
 

@@ -738,11 +755,11 @@
 
                         if (ckuid() != SUCCESS) {
                                 retval = NOPERM;
                                 return (FAIL);
                         }
-                        if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG)) {
+                        if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG|STFLAG)) {
                                 rusage();
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= DFLAG;

@@ -770,11 +787,11 @@
                          * for FILES or LDAP
                          */
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             ((retval = ckuid()) != SUCCESS))
                                 return (FAIL);
-                        if (flag & (MUTEXFLAG|NONAGEFLAG)) {
+                        if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
                                 rusage();       /* exit */
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= XFLAG;

@@ -802,11 +819,11 @@
                          * for FILES or LDAP
                          */
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             ((retval = ckuid()) != SUCCESS))
                                 return (FAIL);
-                        if (flag & (MUTEXFLAG|NONAGEFLAG)) {
+                        if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
                                 rusage();       /* exit */
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= LFLAG;

@@ -834,11 +851,11 @@
                          * for FILES or LDAP
                          */
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             ((retval = ckuid()) != SUCCESS))
                                 return (FAIL);
-                        if (flag & (MUTEXFLAG|NONAGEFLAG)) {
+                        if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
                                 rusage();       /* exit */
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= UFLAG;

@@ -869,11 +886,11 @@
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             (ckuid() != SUCCESS)) {
                                 retval = NOPERM;
                                 return (FAIL);
                         }
-                        if (flag & (SAFLAG|MFLAG|NONAGEFLAG)) {
+                        if (flag & (SAFLAG|MFLAG|NONAGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= MFLAG;
                         if ((int)strlen(optarg)  <= 0 ||

@@ -908,11 +925,11 @@
                          * for FILES or LDAP
                          */
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             ((retval = ckuid()) != SUCCESS))
                                 return (FAIL);
-                        if (flag & (SAFLAG|NFLAG|NONAGEFLAG)) {
+                        if (flag & (SAFLAG|NFLAG|NONAGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= NFLAG;
                         if ((int)strlen(optarg)  <= 0 ||

@@ -949,11 +966,11 @@
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             (ckuid() != SUCCESS)) {
                                 retval = NOPERM;
                                 return (FAIL);
                         }
-                        if (flag & (SAFLAG|WFLAG|NONAGEFLAG)) {
+                        if (flag & (SAFLAG|WFLAG|NONAGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= WFLAG;
                         if ((int)strlen(optarg)  <= 0 ||

@@ -1050,11 +1067,11 @@
                          * for FILES or LDAP
                          */
                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
                             ((retval = ckuid()) != SUCCESS))
                                 return (FAIL);
-                        if (flag & (SAFLAG|FFLAG|NONAGEFLAG)) {
+                        if (flag & (SAFLAG|FFLAG|NONAGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= FFLAG;
                         attrlist_add(attributes, ATTR_EXPIRE_PASSWORD, NULL);

@@ -1064,11 +1081,11 @@
 
                         /* if no repository the default for -e is files */
                         if (repository.type == NULL)
                                 repository = __REPFILES;
 
-                        if (flag & (EFLAG|SAFLAG|AGEFLAG)) {
+                        if (flag & (EFLAG|SAFLAG|AGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= EFLAG;
                         break;

@@ -1085,11 +1102,11 @@
                          */
                         if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
                                 retval = NOPERM;
                                 return (FAIL);
                         }
-                        if (flag & (GFLAG|SAFLAG|AGEFLAG)) {
+                        if (flag & (GFLAG|SAFLAG|AGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= GFLAG;
                         break;

@@ -1112,17 +1129,28 @@
                                     gettext(MSG_NIS_HOMEDIR));
                                 retval = BADSYN;
                                 return (FAIL);
                         }
 
-                        if (flag & (HFLAG|SAFLAG|AGEFLAG)) {
+                        if (flag & (HFLAG|SAFLAG|AGEFLAG|STFLAG)) {
                                 retval = BADOPT;
                                 return (FAIL);
                         }
                         flag |= HFLAG;
                         break;
-
+                case 'S':
+                        if (ckuid() != SUCCESS) {
+                                retval = NOPERM;
+                                return (FAIL);
+                        }
+                        if (flag & (MUTEXFLAG|NONAGEFLAG|AGEFLAG)) {
+                                rusage();       /* exit */
+                                retval = BADOPT;
+                                return (FAIL);
+                        }
+                        flag |= STFLAG;
+                        break;
                 case '?':
                         rusage();
                         retval = BADOPT;
                         return (FAIL);
                 }

@@ -1671,10 +1699,61 @@
         }
         return (PAM_SUCCESS);
 }
 
 /*
+ *
+ * stdin_conv():
+ *      This is the conv function called for reading
+ *      the password from standard input.
+ *
+ */
+/*ARGSUSED*/
+static int
+stdin_conv(int num_msg, struct pam_message **msg,
+            struct pam_response **response, void *appdata_ptr)
+{
+        struct pam_response *reply = NULL;
+        int                     replies = 0;
+
+        if (num_msg <= 0)
+                return (PAM_CONV_ERR);
+
+        reply = calloc(num_msg, sizeof (struct pam_response));
+        if (reply == NULL)
+                return (PAM_BUF_ERR);
+
+        for (replies = 0; replies < num_msg; replies ++) {
+                reply[replies].resp = NULL;
+                reply[replies].resp_retcode = PAM_SUCCESS;
+                switch (msg[replies]->msg_style) {
+                case PAM_PROMPT_ECHO_OFF:
+                        reply[replies].resp = strdup(appdata_ptr);
+                        if (reply[replies].resp == NULL)
+                                goto err;
+                        break;
+                case PAM_PROMPT_ECHO_ON:
+                case PAM_ERROR_MSG:
+                case PAM_TEXT_INFO:
+                        reply[replies].resp = strdup("");
+                        if (reply[replies].resp == NULL)
+                                goto err;
+                        break;
+                default:
+                        free(reply);
+                        return (PAM_CONV_ERR);
+                }
+        }
+        *response = reply;
+        return (PAM_SUCCESS);
+
+err:
+        free(reply);
+        return (PAM_BUF_ERR);
+}
+
+/*
  *              Utilities Functions
  */
 
 /*
  * int attrlist_add(attrlist **l, attrtype type, char *val)

@@ -1773,7 +1852,8 @@
         MSG("\tpasswd -r ldap [-egh] [name]\n");
         MSG("\tpasswd -r ldap -sa\n");
         MSG("\tpasswd -r ldap -s [name]\n");
         MSG("\tpasswd -r ldap [-l|-N|-u] [-f] [-n min] [-w warn] "
             "[-x max] name\n");
+        MSG("\tpasswd -S [name]\n");
 #undef MSG
 }