17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b82017d3Sgww  * Common Development and Distribution License (the "License").
6b82017d3Sgww  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*36e852a1SRaja Andra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <syslog.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
347c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
357c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <passwdutil.h>
4066e150d7SJohn Sonnenschein #include <shadow.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
43b82017d3Sgww static void
error(int nowarn,pam_handle_t * pamh,char * fmt,...)447c478bd9Sstevel@tonic-gate error(int nowarn, pam_handle_t *pamh, char *fmt, ...)
457c478bd9Sstevel@tonic-gate {
467c478bd9Sstevel@tonic-gate 	va_list ap;
477c478bd9Sstevel@tonic-gate 	char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
507c478bd9Sstevel@tonic-gate 	(void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap);
517c478bd9Sstevel@tonic-gate 	if (nowarn == 0)
527c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages,
537c478bd9Sstevel@tonic-gate 		    NULL);
547c478bd9Sstevel@tonic-gate 	va_end(ap);
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate 
57b82017d3Sgww /*PRINTFLIKE3*/
58b82017d3Sgww static void
info(int nowarn,pam_handle_t * pamh,char * fmt,...)59b82017d3Sgww info(int nowarn, pam_handle_t *pamh, char *fmt, ...)
60b82017d3Sgww {
61b82017d3Sgww 	va_list ap;
62b82017d3Sgww 	char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
63b82017d3Sgww 
64b82017d3Sgww 	va_start(ap, fmt);
65b82017d3Sgww 	(void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap);
66b82017d3Sgww 	if (nowarn == 0)
67b82017d3Sgww 		(void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages,
68b82017d3Sgww 		    NULL);
69b82017d3Sgww 	va_end(ap);
70b82017d3Sgww }
71b82017d3Sgww 
727c478bd9Sstevel@tonic-gate #if defined(ENABLE_AGING)
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * test if authtok is aged.
757c478bd9Sstevel@tonic-gate  * returns 1 if it is, 0 otherwise
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate static int
authtok_is_aged(pam_handle_t * pamh)787c478bd9Sstevel@tonic-gate authtok_is_aged(pam_handle_t *pamh)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	unix_authtok_data *status;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	if (pam_get_data(pamh, UNIX_AUTHTOK_DATA,
83*36e852a1SRaja Andra 	    (const void **)status) != PAM_SUCCESS)
847c478bd9Sstevel@tonic-gate 		return (0);
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	return (status->age_status == PAM_NEW_AUTHTOK_REQD)
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate int
917c478bd9Sstevel@tonic-gate pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 	int i;
947c478bd9Sstevel@tonic-gate 	int debug = 0;
957c478bd9Sstevel@tonic-gate 	int nowarn = 0;
967c478bd9Sstevel@tonic-gate 	attrlist l;
977c478bd9Sstevel@tonic-gate 	pwu_repository_t *pwu_rep;
987c478bd9Sstevel@tonic-gate 	char *user;
997c478bd9Sstevel@tonic-gate 	char *oldpw;
1007c478bd9Sstevel@tonic-gate 	char *newpw;
1017c478bd9Sstevel@tonic-gate 	char *service;
1027c478bd9Sstevel@tonic-gate 	struct pam_repository *auth_rep;
1037c478bd9Sstevel@tonic-gate 	int res;
1047c478bd9Sstevel@tonic-gate 	char msg[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
1057c478bd9Sstevel@tonic-gate 	int updated_reps = 0;
1067c478bd9Sstevel@tonic-gate 	int server_policy = 0;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
1097c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
1107c478bd9Sstevel@tonic-gate 			debug = 1;
1117c478bd9Sstevel@tonic-gate 		else if (strcmp(argv[i], "nowarn") == 0)
1127c478bd9Sstevel@tonic-gate 			nowarn = 1;
1137c478bd9Sstevel@tonic-gate 		else if (strcmp(argv[i], "server_policy") == 0)
1147c478bd9Sstevel@tonic-gate 			server_policy = 1;
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	if ((flags & PAM_PRELIM_CHECK) != 0)
1187c478bd9Sstevel@tonic-gate 		return (PAM_IGNORE);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if ((flags & PAM_UPDATE_AUTHTOK) == 0)
1217c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if ((flags & PAM_SILENT) != 0)
1247c478bd9Sstevel@tonic-gate 		nowarn = 1;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (debug)
1277c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_authtok_store: storing authtok");
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate #if defined(ENABLE_AGING)
1307c478bd9Sstevel@tonic-gate 	if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) && !authtok_is_aged(pamh)) {
1317c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_authtok_store: System password young");
132*36e852a1SRaja Andra 		return (PAM_IGNORE);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate #endif
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	res = pam_get_item(pamh, PAM_SERVICE, (void **)&service);
1377c478bd9Sstevel@tonic-gate 	if (res != PAM_SUCCESS) {
1387c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_authtok_store: error getting SERVICE");
1397c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	res = pam_get_item(pamh, PAM_USER, (void **)&user);
1437c478bd9Sstevel@tonic-gate 	if (res != PAM_SUCCESS) {
1447c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_authtok_store: error getting USER");
1457c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	if (user == NULL || *user == '\0') {
1497c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_authtok_store: username is empty");
1507c478bd9Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	res = pam_get_item(pamh, PAM_OLDAUTHTOK, (void **)&oldpw);
1547c478bd9Sstevel@tonic-gate 	if (res != PAM_SUCCESS) {
1557c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_authtok_store: error getting OLDAUTHTOK");
1567c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&newpw);
1607c478bd9Sstevel@tonic-gate 	if (res != PAM_SUCCESS || newpw == NULL) {
1617c478bd9Sstevel@tonic-gate 		/*
1627c478bd9Sstevel@tonic-gate 		 * A module on the stack has removed PAM_AUTHTOK. We fail
1637c478bd9Sstevel@tonic-gate 		 */
1647c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	l.data.val_s = newpw;
1687c478bd9Sstevel@tonic-gate 	/*
1697c478bd9Sstevel@tonic-gate 	 * If the server_policy option is specified,
1707c478bd9Sstevel@tonic-gate 	 * use the special attribute, ATTR_PASSWD_SERVER_POLICY,
1717c478bd9Sstevel@tonic-gate 	 * to tell the update routine for each repository
1727c478bd9Sstevel@tonic-gate 	 * to perform the necessary special operations.
1737c478bd9Sstevel@tonic-gate 	 * For now, only the LDAP routine treats this attribute
1747c478bd9Sstevel@tonic-gate 	 * differently that ATTR_PASSWD. It will skip the
1757c478bd9Sstevel@tonic-gate 	 * crypting of the password before storing it in the LDAP
176*36e852a1SRaja Andra 	 * server. NIS, and FILES will handle ATTR_PASSWD_SERVER_POLICY
177*36e852a1SRaja Andra 	 * the same as ATTR_PASSWD.
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	if (server_policy)
1807c478bd9Sstevel@tonic-gate 		l.type = ATTR_PASSWD_SERVER_POLICY;
1817c478bd9Sstevel@tonic-gate 	else
1827c478bd9Sstevel@tonic-gate 		l.type = ATTR_PASSWD;
1837c478bd9Sstevel@tonic-gate 	l.next = NULL;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	res = pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep);
1867c478bd9Sstevel@tonic-gate 	if (res != PAM_SUCCESS) {
1877c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_authtok_store: error getting repository");
1887c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (auth_rep == NULL) {
1927c478bd9Sstevel@tonic-gate 		pwu_rep = PWU_DEFAULT_REP;
1937c478bd9Sstevel@tonic-gate 	} else {
1947c478bd9Sstevel@tonic-gate 		if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL)
1957c478bd9Sstevel@tonic-gate 			return (PAM_BUF_ERR);
1967c478bd9Sstevel@tonic-gate 		pwu_rep->type = auth_rep->type;
1977c478bd9Sstevel@tonic-gate 		pwu_rep->scope = auth_rep->scope;
1987c478bd9Sstevel@tonic-gate 		pwu_rep->scope_len = auth_rep->scope_len;
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
201*36e852a1SRaja Andra 	res = __set_authtoken_attr(user, oldpw, pwu_rep, &l, &updated_reps);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	if (pwu_rep != PWU_DEFAULT_REP)
2047c478bd9Sstevel@tonic-gate 		free(pwu_rep);
2057c478bd9Sstevel@tonic-gate 	/*
2067c478bd9Sstevel@tonic-gate 	 * now map the various passwdutil return states to user messages
2077c478bd9Sstevel@tonic-gate 	 * and PAM return codes.
2087c478bd9Sstevel@tonic-gate 	 */
2097c478bd9Sstevel@tonic-gate 	switch (res) {
2107c478bd9Sstevel@tonic-gate 	case PWU_SUCCESS:
2117c478bd9Sstevel@tonic-gate 		for (i = 1; i <= REP_LAST; i <<= 1) {
2127c478bd9Sstevel@tonic-gate 			if ((updated_reps & i) == 0)
2137c478bd9Sstevel@tonic-gate 				continue;
214b82017d3Sgww 			info(nowarn, pamh, dgettext(TEXT_DOMAIN,
2157c478bd9Sstevel@tonic-gate 			    "%s: password successfully changed for %s"),
2167c478bd9Sstevel@tonic-gate 			    service, user);
2177c478bd9Sstevel@tonic-gate 		}
2187c478bd9Sstevel@tonic-gate 		res = PAM_SUCCESS;
2197c478bd9Sstevel@tonic-gate 		break;
2207c478bd9Sstevel@tonic-gate 	case PWU_BUSY:
2217c478bd9Sstevel@tonic-gate 		error(nowarn, pamh, dgettext(TEXT_DOMAIN,
222*36e852a1SRaja Andra 		    "%s: Password database busy. Try again later."),
223*36e852a1SRaja Andra 		    service);
2247c478bd9Sstevel@tonic-gate 		res = PAM_AUTHTOK_LOCK_BUSY;
2257c478bd9Sstevel@tonic-gate 		break;
2267c478bd9Sstevel@tonic-gate 	case PWU_STAT_FAILED:
2277c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: stat of password file failed", service);
2287c478bd9Sstevel@tonic-gate 		res = PAM_AUTHTOK_ERR;
2297c478bd9Sstevel@tonic-gate 		break;
2307c478bd9Sstevel@tonic-gate 	case PWU_OPEN_FAILED:
2317c478bd9Sstevel@tonic-gate 	case PWU_WRITE_FAILED:
2327c478bd9Sstevel@tonic-gate 	case PWU_CLOSE_FAILED:
2337c478bd9Sstevel@tonic-gate 	case PWU_UPDATE_FAILED:
2347c478bd9Sstevel@tonic-gate 		error(nowarn, pamh, dgettext(TEXT_DOMAIN,
2357c478bd9Sstevel@tonic-gate 		    "%s: Unexpected failure. Password database unchanged."),
2367c478bd9Sstevel@tonic-gate 		    service);
2377c478bd9Sstevel@tonic-gate 		res = PAM_SYSTEM_ERR;
2387c478bd9Sstevel@tonic-gate 		break;
2397c478bd9Sstevel@tonic-gate 	case PWU_NOT_FOUND:
2407c478bd9Sstevel@tonic-gate 		/* Different error if repository was explicitly specified */
2417c478bd9Sstevel@tonic-gate 		if (auth_rep != NULL) {
2427c478bd9Sstevel@tonic-gate 			error(nowarn, pamh, dgettext(TEXT_DOMAIN,
243*36e852a1SRaja Andra 			    "%s: System error: no %s password for %s."),
244*36e852a1SRaja Andra 			    service, auth_rep->type, user);
2457c478bd9Sstevel@tonic-gate 		} else {
2467c478bd9Sstevel@tonic-gate 			error(nowarn, pamh, dgettext(TEXT_DOMAIN,
2477c478bd9Sstevel@tonic-gate 			    "%s: %s does not exist."), service, user);
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		res = PAM_USER_UNKNOWN;
2507c478bd9Sstevel@tonic-gate 		break;
2517c478bd9Sstevel@tonic-gate 	case PWU_NOMEM:
2527c478bd9Sstevel@tonic-gate 		error(nowarn, pamh, dgettext(TEXT_DOMAIN,
253*36e852a1SRaja Andra 		    "%s: Internal memory allocation failure."), service);
2547c478bd9Sstevel@tonic-gate 		res = PAM_BUF_ERR;
2557c478bd9Sstevel@tonic-gate 		break;
2567c478bd9Sstevel@tonic-gate 	case PWU_SERVER_ERROR:
2577c478bd9Sstevel@tonic-gate 		res = PAM_SYSTEM_ERR;
2587c478bd9Sstevel@tonic-gate 		break;
2597c478bd9Sstevel@tonic-gate 	case PWU_SYSTEM_ERROR:
2607c478bd9Sstevel@tonic-gate 		res = PAM_SYSTEM_ERR;
2617c478bd9Sstevel@tonic-gate 		break;
2627c478bd9Sstevel@tonic-gate 	case PWU_DENIED:
2637c478bd9Sstevel@tonic-gate 		res = PAM_PERM_DENIED;
2647c478bd9Sstevel@tonic-gate 		break;
2657c478bd9Sstevel@tonic-gate 	case PWU_NO_CHANGE:
2667c478bd9Sstevel@tonic-gate 		/*
2677c478bd9Sstevel@tonic-gate 		 * yppasswdd detected that we're not changing anything.
2687c478bd9Sstevel@tonic-gate 		 */
269b82017d3Sgww 		info(nowarn, pamh, dgettext(TEXT_DOMAIN,
2707c478bd9Sstevel@tonic-gate 		    "%s: Password information unchanged."), service);
2717c478bd9Sstevel@tonic-gate 		res = PAM_SUCCESS;
2727c478bd9Sstevel@tonic-gate 		break;
2737c478bd9Sstevel@tonic-gate 	case PWU_REPOSITORY_ERROR:
2747c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE, "pam_authtok_store: detected "
2757c478bd9Sstevel@tonic-gate 		    "unsupported configuration in /etc/nsswitch.conf.");
2767c478bd9Sstevel@tonic-gate 		error(nowarn, pamh, dgettext(TEXT_DOMAIN,
2777c478bd9Sstevel@tonic-gate 		    "%s: System error: repository out of range."), service);
2787c478bd9Sstevel@tonic-gate 		res = PAM_SYSTEM_ERR;
2797c478bd9Sstevel@tonic-gate 		break;
2807c478bd9Sstevel@tonic-gate 	case PWU_PWD_TOO_SHORT:
2817c478bd9Sstevel@tonic-gate 		(void) snprintf(msg[0], sizeof (msg[0]),
2827c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "%s: Password too short."), service);
2837c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL);
2847c478bd9Sstevel@tonic-gate 		res = PAM_AUTHTOK_ERR;
2857c478bd9Sstevel@tonic-gate 		break;
2867c478bd9Sstevel@tonic-gate 	case PWU_PWD_INVALID:
2877c478bd9Sstevel@tonic-gate 		(void) snprintf(msg[0], sizeof (msg[0]),
2887c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "%s: Invalid password syntax."),
289*36e852a1SRaja Andra 		    service);
2907c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL);
2917c478bd9Sstevel@tonic-gate 		res = PAM_AUTHTOK_ERR;
2927c478bd9Sstevel@tonic-gate 		break;
2937c478bd9Sstevel@tonic-gate 	case PWU_PWD_IN_HISTORY:
2947c478bd9Sstevel@tonic-gate 		(void) snprintf(msg[0], sizeof (msg[0]),
2957c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "%s: Reuse of old passwords not "
296*36e852a1SRaja Andra 		    "allowed, the new password is in the history list."),
297*36e852a1SRaja Andra 		    service);
2987c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL);
2997c478bd9Sstevel@tonic-gate 		res = PAM_AUTHTOK_ERR;
3007c478bd9Sstevel@tonic-gate 		break;
3017c478bd9Sstevel@tonic-gate 	case PWU_CHANGE_NOT_ALLOWED:
3027c478bd9Sstevel@tonic-gate 		(void) snprintf(msg[0], sizeof (msg[0]),
3037c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "%s: You may not change "
304*36e852a1SRaja Andra 		    "this password."), service);
3057c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL);
3067c478bd9Sstevel@tonic-gate 		res = PAM_PERM_DENIED;
3077c478bd9Sstevel@tonic-gate 		break;
3087c478bd9Sstevel@tonic-gate 	case PWU_WITHIN_MIN_AGE:
3097c478bd9Sstevel@tonic-gate 		(void) snprintf(msg[0], sizeof (msg[0]),
3107c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN,
311*36e852a1SRaja Andra 		    "%s: Password can not be changed yet, "
312*36e852a1SRaja Andra 		    "not enough time has passed."), service);
3137c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL);
3147c478bd9Sstevel@tonic-gate 		res = PAM_PERM_DENIED;
3157c478bd9Sstevel@tonic-gate 		break;
3167c478bd9Sstevel@tonic-gate 	default:
3177c478bd9Sstevel@tonic-gate 		res = PAM_SYSTEM_ERR;
3187c478bd9Sstevel@tonic-gate 		break;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	return (res);
3227c478bd9Sstevel@tonic-gate }
323