--- old/usr/src/cmd/passwd/passwd.c	Mon Jun 22 09:35:36 2015
+++ new/usr/src/cmd/passwd/passwd.c	Mon Jun 22 09:35:36 2015
@@ -30,6 +30,9 @@
 /*	  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.
@@ -84,6 +87,7 @@
 #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)
@@ -178,6 +182,8 @@
 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 */
@@ -234,8 +240,9 @@
 	char	*input;
 	int	tries = 1;
 	int	updated_reps;
+	ssize_t s;
+	char	st_pass[PASS_MAX];
 
-
 	if ((prognamep = strrchr(argv[0], '/')) != NULL)
 		++prognamep;
 	else
@@ -294,6 +301,16 @@
 		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);
 	}
@@ -362,7 +379,7 @@
 		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",
@@ -688,7 +705,7 @@
 
 	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 */
@@ -740,7 +757,7 @@
 				retval = NOPERM;
 				return (FAIL);
 			}
-			if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG)) {
+			if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG|STFLAG)) {
 				rusage();
 				retval = BADOPT;
 				return (FAIL);
@@ -772,7 +789,7 @@
 			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);
@@ -804,7 +821,7 @@
 			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);
@@ -836,7 +853,7 @@
 			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);
@@ -871,7 +888,7 @@
 				retval = NOPERM;
 				return (FAIL);
 			}
-			if (flag & (SAFLAG|MFLAG|NONAGEFLAG)) {
+			if (flag & (SAFLAG|MFLAG|NONAGEFLAG|STFLAG)) {
 				retval = BADOPT;
 				return (FAIL);
 			}
@@ -910,7 +927,7 @@
 			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);
 			}
@@ -951,7 +968,7 @@
 				retval = NOPERM;
 				return (FAIL);
 			}
-			if (flag & (SAFLAG|WFLAG|NONAGEFLAG)) {
+			if (flag & (SAFLAG|WFLAG|NONAGEFLAG|STFLAG)) {
 				retval = BADOPT;
 				return (FAIL);
 			}
@@ -1052,7 +1069,7 @@
 			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);
 			}
@@ -1066,7 +1083,7 @@
 			if (repository.type == NULL)
 				repository = __REPFILES;
 
-			if (flag & (EFLAG|SAFLAG|AGEFLAG)) {
+			if (flag & (EFLAG|SAFLAG|AGEFLAG|STFLAG)) {
 				retval = BADOPT;
 				return (FAIL);
 			}
@@ -1087,7 +1104,7 @@
 				retval = NOPERM;
 				return (FAIL);
 			}
-			if (flag & (GFLAG|SAFLAG|AGEFLAG)) {
+			if (flag & (GFLAG|SAFLAG|AGEFLAG|STFLAG)) {
 				retval = BADOPT;
 				return (FAIL);
 			}
@@ -1114,13 +1131,24 @@
 				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;
@@ -1673,6 +1701,57 @@
 }
 
 /*
+ *
+ * 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
  */
 
@@ -1775,5 +1854,6 @@
 	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
 }
