xref: /onnv-gate/usr/src/lib/pam_modules/dhkeys/dhkeys.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <syslog.h>
31*0Sstevel@tonic-gate #include <errno.h>
32*0Sstevel@tonic-gate #include <string.h>
33*0Sstevel@tonic-gate #include <rpc/rpc.h>
34*0Sstevel@tonic-gate #include <unistd.h>
35*0Sstevel@tonic-gate #include <assert.h>
36*0Sstevel@tonic-gate #include <stdarg.h>
37*0Sstevel@tonic-gate #include <sys/types.h>
38*0Sstevel@tonic-gate #include <sys/wait.h>
39*0Sstevel@tonic-gate #include <limits.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include <rpcsvc/nis.h>
42*0Sstevel@tonic-gate #include <rpcsvc/nispasswd.h>
43*0Sstevel@tonic-gate #include <rpcsvc/yppasswd.h>
44*0Sstevel@tonic-gate #include <rpcsvc/ypclnt.h>
45*0Sstevel@tonic-gate #include <rpc/key_prot.h>
46*0Sstevel@tonic-gate #include <rpc/rpc.h>
47*0Sstevel@tonic-gate #include <nfs/nfs.h>
48*0Sstevel@tonic-gate #include <nfs/nfssys.h>
49*0Sstevel@tonic-gate #include <nss_dbdefs.h>
50*0Sstevel@tonic-gate #include <nsswitch.h>
51*0Sstevel@tonic-gate #include <rpcsvc/nis_dhext.h>
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #include <security/pam_appl.h>
54*0Sstevel@tonic-gate #include <security/pam_modules.h>
55*0Sstevel@tonic-gate #include <security/pam_impl.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #include <libintl.h>
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #include <sys/mman.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #include <passwdutil.h>
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #include "key_call_uid.h"
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate /* to keep track of codepath */
66*0Sstevel@tonic-gate #define	CODEPATH_PAM_SM_AUTHENTICATE	0
67*0Sstevel@tonic-gate #define	CODEPATH_PAM_SM_SETCRED		1
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate #define	SUNW_OLDRPCPASS	"SUNW-OLD-RPC-PASSWORD"
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate extern	int	_nfssys(int, void *);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate /*
74*0Sstevel@tonic-gate  * int msg(pamh, ...)
75*0Sstevel@tonic-gate  *
76*0Sstevel@tonic-gate  * display message to the user
77*0Sstevel@tonic-gate  */
78*0Sstevel@tonic-gate /*PRINTFLIKE2*/
79*0Sstevel@tonic-gate int
80*0Sstevel@tonic-gate msg(pam_handle_t *pamh, char *fmt, ...)
81*0Sstevel@tonic-gate {
82*0Sstevel@tonic-gate 	va_list	ap;
83*0Sstevel@tonic-gate 	char	messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	va_start(ap, fmt);
86*0Sstevel@tonic-gate 	(void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap);
87*0Sstevel@tonic-gate 	va_end(ap);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	return (__pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL));
90*0Sstevel@tonic-gate }
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate /*
94*0Sstevel@tonic-gate  * Get the secret key for the given netname, key length, and algorithm
95*0Sstevel@tonic-gate  * type and send it to keyserv if the given pw decrypts it.  Update the
96*0Sstevel@tonic-gate  * following counter args as necessary: get_seckey_cnt, good_pw_cnt, and
97*0Sstevel@tonic-gate  * set_seckey_cnt.
98*0Sstevel@tonic-gate  *
99*0Sstevel@tonic-gate  * Returns 0 on malloc failure, else 1.
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate static int
102*0Sstevel@tonic-gate get_and_set_seckey(
103*0Sstevel@tonic-gate 	pam_handle_t	*pamh,			/* in */
104*0Sstevel@tonic-gate 	const char	*netname,		/* in */
105*0Sstevel@tonic-gate 	keylen_t	keylen,			/* in */
106*0Sstevel@tonic-gate 	algtype_t	algtype,		/* in */
107*0Sstevel@tonic-gate 	const char	*pw,			/* in */
108*0Sstevel@tonic-gate 	uid_t		uid,			/* in */
109*0Sstevel@tonic-gate 	gid_t		gid,			/* in */
110*0Sstevel@tonic-gate 	int		*get_seckey_cnt,	/* out */
111*0Sstevel@tonic-gate 	int		*good_pw_cnt,		/* out */
112*0Sstevel@tonic-gate 	int		*set_seckey_cnt,	/* out */
113*0Sstevel@tonic-gate 	int		flags,			/* in */
114*0Sstevel@tonic-gate 	int		debug)			/* in */
115*0Sstevel@tonic-gate {
116*0Sstevel@tonic-gate 	char	*skey;
117*0Sstevel@tonic-gate 	int	skeylen;
118*0Sstevel@tonic-gate 	char	messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	skeylen = BITS2NIBBLES(keylen) + 1;
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	if ((skey = malloc(skeylen)) == NULL) {
123*0Sstevel@tonic-gate 		return (0);
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	if (getsecretkey_g(netname, keylen, algtype, skey, skeylen, pw)) {
127*0Sstevel@tonic-gate 		(*get_seckey_cnt)++;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 		if (skey[0]) {
130*0Sstevel@tonic-gate 			/* password does decrypt secret key */
131*0Sstevel@tonic-gate 			(*good_pw_cnt)++;
132*0Sstevel@tonic-gate 			if (key_setnet_g_uid(netname, skey, keylen, NULL, 0,
133*0Sstevel@tonic-gate 						algtype, uid, gid) >= 0) {
134*0Sstevel@tonic-gate 				(*set_seckey_cnt)++;
135*0Sstevel@tonic-gate 			} else {
136*0Sstevel@tonic-gate 				if (debug)
137*0Sstevel@tonic-gate 					syslog(LOG_DEBUG, "pam_dhkeys: "
138*0Sstevel@tonic-gate 						"get_and_set_seckey: could not "
139*0Sstevel@tonic-gate 						"set secret key for keytype "
140*0Sstevel@tonic-gate 						"%d-%d", keylen, algtype);
141*0Sstevel@tonic-gate 			}
142*0Sstevel@tonic-gate 		} else {
143*0Sstevel@tonic-gate 			if (pamh && !(flags & PAM_SILENT)) {
144*0Sstevel@tonic-gate 				(void) snprintf(messages[0],
145*0Sstevel@tonic-gate 				    sizeof (messages[0]),
146*0Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
147*0Sstevel@tonic-gate 					"Password does not "
148*0Sstevel@tonic-gate 					"decrypt secret key (type = %d-%d) "
149*0Sstevel@tonic-gate 					"for '%s'."), keylen, algtype, netname);
150*0Sstevel@tonic-gate 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
151*0Sstevel@tonic-gate 							messages, NULL);
152*0Sstevel@tonic-gate 			}
153*0Sstevel@tonic-gate 		}
154*0Sstevel@tonic-gate 	} else {
155*0Sstevel@tonic-gate 		if (debug)
156*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: get_and_set_seckey: "
157*0Sstevel@tonic-gate 				"could not get secret key for keytype %d-%d",
158*0Sstevel@tonic-gate 				keylen, algtype);
159*0Sstevel@tonic-gate 	}
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	free(skey);
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	return (1);
164*0Sstevel@tonic-gate }
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate /*
167*0Sstevel@tonic-gate  * int establish_key(pamh, flags, debug, netname)
168*0Sstevel@tonic-gate  *
169*0Sstevel@tonic-gate  * This routine established the Secure RPC Credentials for the
170*0Sstevel@tonic-gate  * user specified in PAM_USER, using the password in PAM_AUTHTOK.
171*0Sstevel@tonic-gate  *
172*0Sstevel@tonic-gate  * Because this routine is used for both pam_authenticate *and*
173*0Sstevel@tonic-gate  * pam_setcred, we have to be somewhat careful:
174*0Sstevel@tonic-gate  *
175*0Sstevel@tonic-gate  *      - if called from pam_sm_authenticate:
176*0Sstevel@tonic-gate  *		1. if we don't need creds (no NIS+ or not tight), we don't
177*0Sstevel@tonic-gate  *		   set them (they will be set by pam_sm_setcred()) and return
178*0Sstevel@tonic-gate  *		   PAM_IGNORE.
179*0Sstevel@tonic-gate  *              2. if we do need to set them (passwd == "*NP*"), we try to
180*0Sstevel@tonic-gate  *		   do so. Not having credentials in this case results in
181*0Sstevel@tonic-gate  *		   PAM_AUTH_ERR.
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  *	- if called from pam_sm_setcred:
184*0Sstevel@tonic-gate  *		If we are root (uid == 0), we do nothing and return PAM_IGNORE.
185*0Sstevel@tonic-gate  *		Otherwise, we try to establish the credentials.
186*0Sstevel@tonic-gate  *		Not having credentials in this case results in PAM_IGNORE.
187*0Sstevel@tonic-gate  *
188*0Sstevel@tonic-gate  *	For both modi, we return PAM_IGNORE if the creds are established.
189*0Sstevel@tonic-gate  *	If we fail, we return
190*0Sstevel@tonic-gate  *	   - PAM_AUTH_ERR if the password didn't decrypt the cred
191*0Sstevel@tonic-gate  *	   - PAM_SYSTEM_ERR if the cred's could not be stored.
192*0Sstevel@tonic-gate  *
193*0Sstevel@tonic-gate  * This routine returns the user's netname in "netname".
194*0Sstevel@tonic-gate  *
195*0Sstevel@tonic-gate  * All tools--but the PAM stack--currently use getpass() to obtain
196*0Sstevel@tonic-gate  * the user's secure RPC password. We must make sure we don't use more than
197*0Sstevel@tonic-gate  * the first des_block (eight) characters of whatever is handed down to us.
198*0Sstevel@tonic-gate  * Therefore, we use a local variable "short_pass" to hold those 8 char's.
199*0Sstevel@tonic-gate  */
200*0Sstevel@tonic-gate int
201*0Sstevel@tonic-gate establish_key(pam_handle_t *pamh, int flags, int codepath, int debug,
202*0Sstevel@tonic-gate 	char *netname)
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate 	char	*user;
205*0Sstevel@tonic-gate 	char	*passwd;
206*0Sstevel@tonic-gate 	char	short_pass[sizeof (des_block)+1], *short_passp;
207*0Sstevel@tonic-gate 	int	result;
208*0Sstevel@tonic-gate 	uid_t	uid;
209*0Sstevel@tonic-gate 	gid_t	gid;
210*0Sstevel@tonic-gate 	int	err;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	struct passwd pw;	/* Needed to obtain uid */
213*0Sstevel@tonic-gate 	char	*scratch;
214*0Sstevel@tonic-gate 	int	scratchlen;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	int	need_cred;	/* is not having credentials set a failure? */
217*0Sstevel@tonic-gate 	char *repository_name = NULL;	/* which repository are we using */
218*0Sstevel@tonic-gate 	char *repository_pass = NULL;	/* user's password from that rep */
219*0Sstevel@tonic-gate 	pwu_repository_t *pwu_rep;
220*0Sstevel@tonic-gate 	struct pam_repository *auth_rep;
221*0Sstevel@tonic-gate 	attrlist attr_pw[2];
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	mechanism_t	**mechs;
224*0Sstevel@tonic-gate 	mechanism_t	**mpp;
225*0Sstevel@tonic-gate 	int	get_seckey_cnt = 0;
226*0Sstevel@tonic-gate 	int	set_seckey_cnt = 0;
227*0Sstevel@tonic-gate 	int	good_pw_cnt = 0;
228*0Sstevel@tonic-gate 	int	valid_mech_cnt = 0;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_USER, (void **)&user);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	if (user == NULL || *user == '\0') {
233*0Sstevel@tonic-gate 		if (debug)
234*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: user NULL or empty");
235*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&passwd);
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	scratchlen = sysconf(_SC_GETPW_R_SIZE_MAX);
241*0Sstevel@tonic-gate 	if ((scratch = malloc(scratchlen)) == NULL)
242*0Sstevel@tonic-gate 		return (PAM_BUF_ERR);
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	if (getpwnam_r(user, &pw, scratch, scratchlen) == NULL) {
245*0Sstevel@tonic-gate 		result = PAM_USER_UNKNOWN;
246*0Sstevel@tonic-gate 		goto out;
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	uid = pw.pw_uid;
250*0Sstevel@tonic-gate 	gid = pw.pw_gid;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	/*
253*0Sstevel@tonic-gate 	 * We don't set credentials when root logs in.
254*0Sstevel@tonic-gate 	 * We do, however, need to set the credentials if the NIS+ permissions
255*0Sstevel@tonic-gate 	 * require so. Thus, we only bail out if we're root and we're
256*0Sstevel@tonic-gate 	 * called from pam_setcred.
257*0Sstevel@tonic-gate 	 */
258*0Sstevel@tonic-gate 	if (uid == 0 && codepath == CODEPATH_PAM_SM_SETCRED) {
259*0Sstevel@tonic-gate 		result = PAM_IGNORE;
260*0Sstevel@tonic-gate 		goto out;
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/*
264*0Sstevel@tonic-gate 	 * Check to see if we REALLY need to set the credentials, i.e.
265*0Sstevel@tonic-gate 	 * whether not being able to do so is an error or whether we
266*0Sstevel@tonic-gate 	 * can ignore it.
267*0Sstevel@tonic-gate 	 * We need to get the password from the repository that we're
268*0Sstevel@tonic-gate 	 * currently authenticating against. IFF this password equals
269*0Sstevel@tonic-gate 	 * "*NP" *AND* we are authenticating against NIS+, we actually
270*0Sstevel@tonic-gate 	 * do need to set the credentials. In all other cases, we
271*0Sstevel@tonic-gate 	 * can forget about them.
272*0Sstevel@tonic-gate 	 */
273*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep);
274*0Sstevel@tonic-gate 	if (auth_rep != NULL) {
275*0Sstevel@tonic-gate 		if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL)
276*0Sstevel@tonic-gate 			return (PAM_BUF_ERR);
277*0Sstevel@tonic-gate 		pwu_rep->type = auth_rep->type;
278*0Sstevel@tonic-gate 		pwu_rep->scope = auth_rep->scope;
279*0Sstevel@tonic-gate 		pwu_rep->scope_len = auth_rep->scope_len;
280*0Sstevel@tonic-gate 	} else
281*0Sstevel@tonic-gate 		pwu_rep = PWU_DEFAULT_REP;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	attr_pw[0].type = ATTR_PASSWD; attr_pw[0].next = &attr_pw[1];
284*0Sstevel@tonic-gate 	attr_pw[1].type = ATTR_REP_NAME; attr_pw[1].next = NULL;
285*0Sstevel@tonic-gate 	result = __get_authtoken_attr(user, pwu_rep, attr_pw);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	if (pwu_rep != PWU_DEFAULT_REP)
288*0Sstevel@tonic-gate 		free(pwu_rep);
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	if (result == PWU_NOT_FOUND) {
291*0Sstevel@tonic-gate 		if (debug)
292*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: user %s not found",
293*0Sstevel@tonic-gate 				user);
294*0Sstevel@tonic-gate 		result = PAM_USER_UNKNOWN;
295*0Sstevel@tonic-gate 		goto out;
296*0Sstevel@tonic-gate 	} else if (result != PWU_SUCCESS) {
297*0Sstevel@tonic-gate 		result = PAM_PERM_DENIED;
298*0Sstevel@tonic-gate 		goto out;
299*0Sstevel@tonic-gate 	}
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	repository_name = attr_pw[1].data.val_s;
302*0Sstevel@tonic-gate 	repository_pass = attr_pw[0].data.val_s;
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	need_cred = (strcmp(repository_name, "nisplus") == 0 &&
305*0Sstevel@tonic-gate 		strcmp(repository_pass, "*NP*") == 0);
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	if (codepath == CODEPATH_PAM_SM_AUTHENTICATE && need_cred == 0) {
308*0Sstevel@tonic-gate 		/*
309*0Sstevel@tonic-gate 		 * No need to set credentials right now.
310*0Sstevel@tonic-gate 		 * Will do so later through pam_sm_setcred()
311*0Sstevel@tonic-gate 		 */
312*0Sstevel@tonic-gate 		result = PAM_IGNORE;
313*0Sstevel@tonic-gate 		goto out;
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	if (uid == 0)		/* "root", need to create a host-netname */
317*0Sstevel@tonic-gate 		err = host2netname(netname, NULL, NULL);
318*0Sstevel@tonic-gate 	else
319*0Sstevel@tonic-gate 		err = user2netname(netname, uid, NULL);
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	if (err != 1) {
322*0Sstevel@tonic-gate 		if (debug)
323*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: user2netname failed");
324*0Sstevel@tonic-gate 		if (need_cred) {
325*0Sstevel@tonic-gate 			syslog(LOG_ALERT, "pam_dhkeys: user %s needs "
326*0Sstevel@tonic-gate 			    "Secure RPC Credentials to login.", user);
327*0Sstevel@tonic-gate 			result = PAM_SERVICE_ERR;
328*0Sstevel@tonic-gate 		} else
329*0Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
330*0Sstevel@tonic-gate 		goto out;
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	/* passwd can be NULL (no passwd or su as root) */
334*0Sstevel@tonic-gate 	if (passwd) {
335*0Sstevel@tonic-gate 		(void) strlcpy(short_pass, passwd, sizeof (short_pass));
336*0Sstevel@tonic-gate 		short_passp = short_pass;
337*0Sstevel@tonic-gate 	} else
338*0Sstevel@tonic-gate 		short_passp = NULL;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	if (mechs = __nis_get_mechanisms(FALSE)) {
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 		for (mpp = mechs; *mpp; mpp++) {
343*0Sstevel@tonic-gate 			mechanism_t *mp = *mpp;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 			if (AUTH_DES_COMPAT_CHK(mp))
346*0Sstevel@tonic-gate 				break;	/* fall through to AUTH_DES below */
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 			if (!VALID_MECH_ENTRY(mp))
349*0Sstevel@tonic-gate 				continue;
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 			if (debug)
352*0Sstevel@tonic-gate 				syslog(LOG_DEBUG, "pam_dhkeys: trying "
353*0Sstevel@tonic-gate 					"key type = %d-%d", mp->keylen,
354*0Sstevel@tonic-gate 					mp->algtype);
355*0Sstevel@tonic-gate 			valid_mech_cnt++;
356*0Sstevel@tonic-gate 			if (!get_and_set_seckey(pamh, netname, mp->keylen,
357*0Sstevel@tonic-gate 						mp->algtype, short_passp,
358*0Sstevel@tonic-gate 						uid, gid,
359*0Sstevel@tonic-gate 						&get_seckey_cnt, &good_pw_cnt,
360*0Sstevel@tonic-gate 						&set_seckey_cnt, flags,
361*0Sstevel@tonic-gate 						debug)) {
362*0Sstevel@tonic-gate 				result = PAM_BUF_ERR;
363*0Sstevel@tonic-gate 				goto out;
364*0Sstevel@tonic-gate 			}
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 		__nis_release_mechanisms(mechs);
367*0Sstevel@tonic-gate 		/* fall through to AUTH_DES below */
368*0Sstevel@tonic-gate 	} else {
369*0Sstevel@tonic-gate 		/*
370*0Sstevel@tonic-gate 		 * No usable mechs found in NIS+ security cf thus
371*0Sstevel@tonic-gate 		 * fallback to AUTH_DES compat.
372*0Sstevel@tonic-gate 		 */
373*0Sstevel@tonic-gate 		if (debug)
374*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: no valid mechs "
375*0Sstevel@tonic-gate 				"found. Trying AUTH_DES.");
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	/*
379*0Sstevel@tonic-gate 	 * We always perform AUTH_DES for the benefit of non-NIS+
380*0Sstevel@tonic-gate 	 * services (e.g. NFS) that may depend on the classic des
381*0Sstevel@tonic-gate 	 * 192bit key being set.
382*0Sstevel@tonic-gate 	 */
383*0Sstevel@tonic-gate 	if (!get_and_set_seckey(pamh, netname, AUTH_DES_KEYLEN,
384*0Sstevel@tonic-gate 	    AUTH_DES_ALGTYPE, short_passp, uid, gid, &get_seckey_cnt,
385*0Sstevel@tonic-gate 	    &good_pw_cnt, &set_seckey_cnt, flags, debug)) {
386*0Sstevel@tonic-gate 		result = PAM_BUF_ERR;
387*0Sstevel@tonic-gate 		goto out;
388*0Sstevel@tonic-gate 	}
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	if (debug) {
391*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: mech key totals:\n");
392*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d valid mechanism(s)",
393*0Sstevel@tonic-gate 			valid_mech_cnt);
394*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d secret key(s) retrieved",
395*0Sstevel@tonic-gate 			get_seckey_cnt);
396*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d passwd decrypt successes",
397*0Sstevel@tonic-gate 			good_pw_cnt);
398*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d secret key(s) set",
399*0Sstevel@tonic-gate 			set_seckey_cnt);
400*0Sstevel@tonic-gate 	}
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	if (get_seckey_cnt == 0) {		/* No credentials */
403*0Sstevel@tonic-gate 		result = need_cred ? PAM_AUTH_ERR : PAM_IGNORE;
404*0Sstevel@tonic-gate 		goto out;
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	if (good_pw_cnt == 0) {			/* wrong password */
408*0Sstevel@tonic-gate 		result = PAM_AUTH_ERR;
409*0Sstevel@tonic-gate 		goto out;
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	if (set_seckey_cnt == 0) {
413*0Sstevel@tonic-gate 		result = PAM_SYSTEM_ERR;
414*0Sstevel@tonic-gate 		goto out;
415*0Sstevel@tonic-gate 	}
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	result = PAM_IGNORE;
418*0Sstevel@tonic-gate out:
419*0Sstevel@tonic-gate 	if (repository_name)
420*0Sstevel@tonic-gate 		free(repository_name);
421*0Sstevel@tonic-gate 	if (repository_pass)
422*0Sstevel@tonic-gate 		free(repository_pass);
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	free(scratch);
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	(void) memset(short_pass, '\0', sizeof (short_pass));
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	return (result);
429*0Sstevel@tonic-gate }
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate int
432*0Sstevel@tonic-gate pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
433*0Sstevel@tonic-gate {
434*0Sstevel@tonic-gate 	int	i;
435*0Sstevel@tonic-gate 	int	debug = 0;
436*0Sstevel@tonic-gate 	int	result;
437*0Sstevel@tonic-gate 	char	netname[MAXNETNAMELEN + 1];
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
440*0Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
441*0Sstevel@tonic-gate 			debug = 1;
442*0Sstevel@tonic-gate 		else if (strcmp(argv[i], "nowarn") == 0)
443*0Sstevel@tonic-gate 			flags |= PAM_SILENT;
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	result = establish_key(pamh, flags, CODEPATH_PAM_SM_AUTHENTICATE, debug,
447*0Sstevel@tonic-gate 				netname);
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	return (result);
450*0Sstevel@tonic-gate }
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate int
453*0Sstevel@tonic-gate remove_key(pam_handle_t *pamh, int flags, int debug)
454*0Sstevel@tonic-gate {
455*0Sstevel@tonic-gate 	int result;
456*0Sstevel@tonic-gate 	char *uname;
457*0Sstevel@tonic-gate 	attrlist attr_pw[2];
458*0Sstevel@tonic-gate 	struct pam_repository *auth_rep = NULL;
459*0Sstevel@tonic-gate 	pwu_repository_t *pwu_rep;
460*0Sstevel@tonic-gate 	uid_t uid;
461*0Sstevel@tonic-gate 	gid_t gid;
462*0Sstevel@tonic-gate 	struct nfs_revauth_args nra;
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_USER, (void **)&uname);
465*0Sstevel@tonic-gate 	if (uname == NULL || *uname == NULL) {
466*0Sstevel@tonic-gate 		if (debug)
467*0Sstevel@tonic-gate 			syslog(LOG_DEBUG,
468*0Sstevel@tonic-gate 			    "pam_dhkeys: user NULL or empty in remove_key()");
469*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	if (strcmp(uname, "root") == 0) {
473*0Sstevel@tonic-gate 		if ((flags & PAM_SILENT) == 0) {
474*0Sstevel@tonic-gate 			char msg[3][PAM_MAX_MSG_SIZE];
475*0Sstevel@tonic-gate 			(void) snprintf(msg[0], sizeof (msg[0]),
476*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
477*0Sstevel@tonic-gate 				"removing root credentials would"
478*0Sstevel@tonic-gate 				" break the rpc services that"));
479*0Sstevel@tonic-gate 			(void) snprintf(msg[1], sizeof (msg[1]),
480*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
481*0Sstevel@tonic-gate 				"use secure rpc on this host!"));
482*0Sstevel@tonic-gate 			(void) snprintf(msg[2], sizeof (msg[2]),
483*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
484*0Sstevel@tonic-gate 				"root may use keylogout -f to do"
485*0Sstevel@tonic-gate 				" this (at your own risk)!"));
486*0Sstevel@tonic-gate 			(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 3,
487*0Sstevel@tonic-gate 			    msg, NULL);
488*0Sstevel@tonic-gate 		}
489*0Sstevel@tonic-gate 		return (PAM_PERM_DENIED);
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep);
493*0Sstevel@tonic-gate 	if (auth_rep != NULL) {
494*0Sstevel@tonic-gate 		if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL)
495*0Sstevel@tonic-gate 			return (PAM_BUF_ERR);
496*0Sstevel@tonic-gate 		pwu_rep->type = auth_rep->type;
497*0Sstevel@tonic-gate 		pwu_rep->scope = auth_rep->scope;
498*0Sstevel@tonic-gate 		pwu_rep->scope_len = auth_rep->scope_len;
499*0Sstevel@tonic-gate 	} else
500*0Sstevel@tonic-gate 		pwu_rep = PWU_DEFAULT_REP;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	/* Retrieve user's uid/gid from the password repository */
503*0Sstevel@tonic-gate 	attr_pw[0].type = ATTR_UID; attr_pw[0].next = &attr_pw[1];
504*0Sstevel@tonic-gate 	attr_pw[1].type = ATTR_GID; attr_pw[1].next = NULL;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	result = __get_authtoken_attr(uname, pwu_rep, attr_pw);
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	if (pwu_rep != PWU_DEFAULT_REP)
509*0Sstevel@tonic-gate 		free(pwu_rep);
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	if (result == PWU_NOT_FOUND)
512*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
513*0Sstevel@tonic-gate 	if (result == PWU_DENIED)
514*0Sstevel@tonic-gate 		return (PAM_PERM_DENIED);
515*0Sstevel@tonic-gate 	if (result != PWU_SUCCESS)
516*0Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	uid = (uid_t)attr_pw[0].data.val_i;
519*0Sstevel@tonic-gate 	gid = (gid_t)attr_pw[1].data.val_i;
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	(void) key_removesecret_g_uid(uid, gid);
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	/* Revoke NFS DES credentials */
524*0Sstevel@tonic-gate 	nra.authtype = AUTH_DES;
525*0Sstevel@tonic-gate 	nra.uid = uid;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	if (_nfssys(NFS_REVAUTH, &nra) < 0) {
528*0Sstevel@tonic-gate 		if ((flags & PAM_SILENT) == 0) {
529*0Sstevel@tonic-gate 			(void) msg(pamh, dgettext(TEXT_DOMAIN,
530*0Sstevel@tonic-gate 				"Warning: NFS credentials not destroyed"));
531*0Sstevel@tonic-gate 		}
532*0Sstevel@tonic-gate 		return (PAM_AUTH_ERR);
533*0Sstevel@tonic-gate 	}
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	return (PAM_IGNORE);
536*0Sstevel@tonic-gate }
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate int
539*0Sstevel@tonic-gate pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
540*0Sstevel@tonic-gate {
541*0Sstevel@tonic-gate 	int	i;
542*0Sstevel@tonic-gate 	int	debug = 0;
543*0Sstevel@tonic-gate 	int	result;
544*0Sstevel@tonic-gate 	char	netname[MAXNETNAMELEN + 1];
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
547*0Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
548*0Sstevel@tonic-gate 			debug = 1;
549*0Sstevel@tonic-gate 		else if (strcmp(argv[i], "nowarn") == 0)
550*0Sstevel@tonic-gate 			flags |= PAM_SILENT;
551*0Sstevel@tonic-gate 	}
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	/* Check for invalid flags */
554*0Sstevel@tonic-gate 	if (flags && (flags & PAM_ESTABLISH_CRED) == 0 &&
555*0Sstevel@tonic-gate 			(flags & PAM_REINITIALIZE_CRED) == 0 &&
556*0Sstevel@tonic-gate 			(flags & PAM_REFRESH_CRED) == 0 &&
557*0Sstevel@tonic-gate 			(flags & PAM_DELETE_CRED) == 0 &&
558*0Sstevel@tonic-gate 			(flags & PAM_SILENT) == 0) {
559*0Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_dhkeys: pam_setcred: illegal flags %d",
560*0Sstevel@tonic-gate 				flags);
561*0Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
562*0Sstevel@tonic-gate 	}
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	if ((flags & PAM_REINITIALIZE_CRED) || (flags & PAM_REFRESH_CRED)) {
566*0Sstevel@tonic-gate 		/* doesn't apply to UNIX */
567*0Sstevel@tonic-gate 		if (debug)
568*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: cred reinit/refresh "
569*0Sstevel@tonic-gate 			    "ignored\n");
570*0Sstevel@tonic-gate 		return (PAM_IGNORE);
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (flags & PAM_DELETE_CRED) {
574*0Sstevel@tonic-gate 		if (debug)
575*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: removing creds\n");
576*0Sstevel@tonic-gate 		result = remove_key(pamh, flags, debug);
577*0Sstevel@tonic-gate 	} else {
578*0Sstevel@tonic-gate 		result = establish_key(pamh, flags, CODEPATH_PAM_SM_SETCRED,
579*0Sstevel@tonic-gate 					debug, netname);
580*0Sstevel@tonic-gate 		/* Some diagnostics */
581*0Sstevel@tonic-gate 		if ((flags & PAM_SILENT) == 0) {
582*0Sstevel@tonic-gate 			if (result == PAM_AUTH_ERR)
583*0Sstevel@tonic-gate 				(void) msg(pamh, dgettext(TEXT_DOMAIN,
584*0Sstevel@tonic-gate 				    "Password does not decrypt any secret "
585*0Sstevel@tonic-gate 				    "keys for %s."), netname);
586*0Sstevel@tonic-gate 			else if (result == PAM_SYSTEM_ERR && netname[0])
587*0Sstevel@tonic-gate 				(void) msg(pamh, dgettext(TEXT_DOMAIN,
588*0Sstevel@tonic-gate 				    "Could not set secret key(s) for %s. "
589*0Sstevel@tonic-gate 				    "The key server may be down."), netname);
590*0Sstevel@tonic-gate 		}
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 		/* Not having credentials set is not an error... */
593*0Sstevel@tonic-gate 		result = PAM_IGNORE;
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	return (result);
597*0Sstevel@tonic-gate }
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate /*ARGSUSED*/
600*0Sstevel@tonic-gate void
601*0Sstevel@tonic-gate rpc_cleanup(pam_handle_t *pamh, void *data, int pam_status)
602*0Sstevel@tonic-gate {
603*0Sstevel@tonic-gate 	if (data) {
604*0Sstevel@tonic-gate 		(void) memset(data, 0, strlen(data));
605*0Sstevel@tonic-gate 		free(data);
606*0Sstevel@tonic-gate 	}
607*0Sstevel@tonic-gate }
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate int
610*0Sstevel@tonic-gate pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
611*0Sstevel@tonic-gate {
612*0Sstevel@tonic-gate 	int i;
613*0Sstevel@tonic-gate 	int debug = 0;
614*0Sstevel@tonic-gate 	int res;
615*0Sstevel@tonic-gate 	pam_repository_t *pam_rep;
616*0Sstevel@tonic-gate 	pwu_repository_t *pwu_rep;
617*0Sstevel@tonic-gate 	char *oldpw;
618*0Sstevel@tonic-gate 	char *user;
619*0Sstevel@tonic-gate 	int tries;
620*0Sstevel@tonic-gate 	int oldpw_ok;
621*0Sstevel@tonic-gate 	char *oldrpcpw;
622*0Sstevel@tonic-gate 	char *oldrpcpass;
623*0Sstevel@tonic-gate 	char *data;
624*0Sstevel@tonic-gate 	/* password truncated at 8 chars, see comment at establish_key() */
625*0Sstevel@tonic-gate 	char short_pass[sizeof (des_block)+1], *short_passp;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	for (i = 0; i < argc; i++)
628*0Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
629*0Sstevel@tonic-gate 			debug = 1;
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	if (debug)
632*0Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: entered pam_sm_chauthtok()");
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	if ((flags & PAM_PRELIM_CHECK) == 0)
635*0Sstevel@tonic-gate 		return (PAM_IGNORE);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	/*
638*0Sstevel@tonic-gate 	 * See if the old secure-rpc password has already been set
639*0Sstevel@tonic-gate 	 */
640*0Sstevel@tonic-gate 	res = pam_get_data(pamh, SUNW_OLDRPCPASS, (const void **)&oldrpcpass);
641*0Sstevel@tonic-gate 	if (res == PAM_SUCCESS) {
642*0Sstevel@tonic-gate 		if (debug)
643*0Sstevel@tonic-gate 			syslog(LOG_DEBUG,
644*0Sstevel@tonic-gate 			    "pam_dhkeys: OLDRPCPASS already set");
645*0Sstevel@tonic-gate 		return (PAM_IGNORE);
646*0Sstevel@tonic-gate 	}
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&pam_rep);
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_USER, (void **)&user);
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&oldpw);
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	if (user == NULL || *user == '\0') {
655*0Sstevel@tonic-gate 		if (debug)
656*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: user NULL or empty");
657*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
658*0Sstevel@tonic-gate 	}
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	/* oldpw can be NULL (eg. root changing someone's passwd) */
661*0Sstevel@tonic-gate 	if (oldpw) {
662*0Sstevel@tonic-gate 		(void) strlcpy(short_pass, oldpw, sizeof (short_pass));
663*0Sstevel@tonic-gate 		short_passp = short_pass;
664*0Sstevel@tonic-gate 	} else
665*0Sstevel@tonic-gate 		short_passp = NULL;
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	/*
668*0Sstevel@tonic-gate 	 * For NIS+ we need to check whether the old password equals
669*0Sstevel@tonic-gate 	 * the RPC password. If it doesn't, we won't be able to update
670*0Sstevel@tonic-gate 	 * the secure RPC credentials later on in the process.
671*0Sstevel@tonic-gate 	 */
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	if (pam_rep == NULL)
674*0Sstevel@tonic-gate 		pwu_rep = PWU_DEFAULT_REP;
675*0Sstevel@tonic-gate 	else {
676*0Sstevel@tonic-gate 		if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL)
677*0Sstevel@tonic-gate 			return (PAM_BUF_ERR);
678*0Sstevel@tonic-gate 		pwu_rep->type = pam_rep->type;
679*0Sstevel@tonic-gate 		pwu_rep->scope = pam_rep->scope;
680*0Sstevel@tonic-gate 		pwu_rep->scope_len = pam_rep->scope_len;
681*0Sstevel@tonic-gate 	}
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	switch (__verify_rpc_passwd(user, short_passp, pwu_rep)) {
684*0Sstevel@tonic-gate 	case PWU_SUCCESS:
685*0Sstevel@tonic-gate 		/* oldpw matches RPC password, or no RPC password needed */
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 		if (pwu_rep != PWU_DEFAULT_REP)
688*0Sstevel@tonic-gate 			free(pwu_rep);
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 		if (short_passp) {
691*0Sstevel@tonic-gate 			if ((data = strdup(short_pass)) == NULL) {
692*0Sstevel@tonic-gate 				(void) memset(short_pass, '\0',
693*0Sstevel@tonic-gate 				    sizeof (short_pass));
694*0Sstevel@tonic-gate 				return (PAM_BUF_ERR);
695*0Sstevel@tonic-gate 			}
696*0Sstevel@tonic-gate 		} else
697*0Sstevel@tonic-gate 			data = NULL;
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 		(void) pam_set_data(pamh, SUNW_OLDRPCPASS, data, rpc_cleanup);
700*0Sstevel@tonic-gate 		return (PAM_IGNORE);
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	case PWU_NOT_FOUND:
703*0Sstevel@tonic-gate 		if (pwu_rep != PWU_DEFAULT_REP)
704*0Sstevel@tonic-gate 			free(pwu_rep);
705*0Sstevel@tonic-gate 		(void) memset(short_pass, '\0', sizeof (short_pass));
706*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
707*0Sstevel@tonic-gate 	case PWU_CRED_ERROR:
708*0Sstevel@tonic-gate 		/* The old password does not decrypt any credentials */
709*0Sstevel@tonic-gate 		break;
710*0Sstevel@tonic-gate 	default:
711*0Sstevel@tonic-gate 		if (pwu_rep != PWU_DEFAULT_REP)
712*0Sstevel@tonic-gate 			free(pwu_rep);
713*0Sstevel@tonic-gate 		(void) memset(short_pass, '\0', sizeof (short_pass));
714*0Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
715*0Sstevel@tonic-gate 	}
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	/*
718*0Sstevel@tonic-gate 	 * We got here because the OLDAUTHTOK doesn't match the Secure RPC
719*0Sstevel@tonic-gate 	 * password. In compliance with the old behavior, we give the
720*0Sstevel@tonic-gate 	 * user two chances to get the password right. If that succeeds
721*0Sstevel@tonic-gate 	 * all is well; if it doesn't, we'll return an error.
722*0Sstevel@tonic-gate 	 */
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	(void) msg(pamh, dgettext(TEXT_DOMAIN,
725*0Sstevel@tonic-gate 		"This password differs from your secure RPC password."));
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	tries = 0;
728*0Sstevel@tonic-gate 	oldpw_ok = 0;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	while (oldpw_ok == 0 && ++tries < 3) {
731*0Sstevel@tonic-gate 		if (tries > 1)
732*0Sstevel@tonic-gate 			(void) msg(pamh, dgettext(TEXT_DOMAIN,
733*0Sstevel@tonic-gate 				"This password does not decrypt your "
734*0Sstevel@tonic-gate 				"secure RPC password."));
735*0Sstevel@tonic-gate 		res = __pam_get_authtok(pamh, PAM_PROMPT, 0,
736*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN,
737*0Sstevel@tonic-gate 		    "Please enter your old Secure RPC password: "), &oldpw);
738*0Sstevel@tonic-gate 		if (res != PAM_SUCCESS) {
739*0Sstevel@tonic-gate 			if (pwu_rep != PWU_DEFAULT_REP)
740*0Sstevel@tonic-gate 				free(pwu_rep);
741*0Sstevel@tonic-gate 			return (res);
742*0Sstevel@tonic-gate 		}
743*0Sstevel@tonic-gate 		(void) strlcpy(short_pass, oldpw, sizeof (short_pass));
744*0Sstevel@tonic-gate 		(void) memset(oldpw, 0, strlen(oldpw));
745*0Sstevel@tonic-gate 		free(oldpw);
746*0Sstevel@tonic-gate 		oldpw = NULL;
747*0Sstevel@tonic-gate 		if (__verify_rpc_passwd(user, short_pass, pwu_rep) ==
748*0Sstevel@tonic-gate 		    PWU_SUCCESS)
749*0Sstevel@tonic-gate 			oldpw_ok = 1;
750*0Sstevel@tonic-gate 	}
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	if (pwu_rep != PWU_DEFAULT_REP)
753*0Sstevel@tonic-gate 		free(pwu_rep);
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	if (oldpw_ok == 0) {
756*0Sstevel@tonic-gate 		(void) memset(short_pass, '\0', sizeof (short_pass));
757*0Sstevel@tonic-gate 		return (PAM_AUTHTOK_ERR);
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	/*
761*0Sstevel@tonic-gate 	 * Since the PAM framework only provides space for two different
762*0Sstevel@tonic-gate 	 * password (one old and one current), there is officially no
763*0Sstevel@tonic-gate 	 * place to put additional passwords (like our old rpc password).
764*0Sstevel@tonic-gate 	 * We have no choice but to stuff it in a data item, and hope it
765*0Sstevel@tonic-gate 	 * will be picked up by the password-update routines.
766*0Sstevel@tonic-gate 	 */
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	oldrpcpw = strdup(short_pass);
769*0Sstevel@tonic-gate 	(void) memset(short_pass, '\0', sizeof (short_pass));
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 	if (oldrpcpw == NULL)
772*0Sstevel@tonic-gate 		return (PAM_BUF_ERR);
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	res = pam_set_data(pamh, SUNW_OLDRPCPASS, oldrpcpw, rpc_cleanup);
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	return (res);
777*0Sstevel@tonic-gate }
778