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
}