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
53125ebfcSsemery  * Common Development and Distribution License (the "License").
63125ebfcSsemery  * 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 /*
2236e852a1SRaja 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 #include <stdlib.h>
277c478bd9Sstevel@tonic-gate #include <syslog.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <assert.h>
337c478bd9Sstevel@tonic-gate #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/wait.h>
367c478bd9Sstevel@tonic-gate #include <limits.h>
37573374d3Sjjj #include <signal.h>
38573374d3Sjjj #include <pthread.h>
39573374d3Sjjj #include <synch.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h>
427c478bd9Sstevel@tonic-gate #include <rpcsvc/yppasswd.h>
437c478bd9Sstevel@tonic-gate #include <rpcsvc/ypclnt.h>
447c478bd9Sstevel@tonic-gate #include <rpc/key_prot.h>
457c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
467c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
477c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
487c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
497c478bd9Sstevel@tonic-gate #include <nsswitch.h>
507c478bd9Sstevel@tonic-gate #include <rpcsvc/nis_dhext.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
537c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
547c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <libintl.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <sys/mman.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #include <passwdutil.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include "key_call_uid.h"
6366e150d7SJohn Sonnenschein #include <shadow.h>
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate extern	int	_nfssys(int, void *);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * int msg(pamh, ...)
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  * display message to the user
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
73573374d3Sjjj static int
msg(pam_handle_t * pamh,char * fmt,...)747c478bd9Sstevel@tonic-gate msg(pam_handle_t *pamh, char *fmt, ...)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	va_list	ap;
777c478bd9Sstevel@tonic-gate 	char	messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
807c478bd9Sstevel@tonic-gate 	(void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap);
817c478bd9Sstevel@tonic-gate 	va_end(ap);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	return (__pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL));
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Get the secret key for the given netname, key length, and algorithm
897c478bd9Sstevel@tonic-gate  * type and send it to keyserv if the given pw decrypts it.  Update the
907c478bd9Sstevel@tonic-gate  * following counter args as necessary: get_seckey_cnt, good_pw_cnt, and
917c478bd9Sstevel@tonic-gate  * set_seckey_cnt.
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * Returns 0 on malloc failure, else 1.
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate static int
get_and_set_seckey(pam_handle_t * pamh,const char * netname,keylen_t keylen,algtype_t algtype,const char * pw,uid_t uid,gid_t gid,int * get_seckey_cnt,int * good_pw_cnt,int * set_seckey_cnt,int flags,int debug)967c478bd9Sstevel@tonic-gate get_and_set_seckey(
977c478bd9Sstevel@tonic-gate 	pam_handle_t	*pamh,			/* in */
987c478bd9Sstevel@tonic-gate 	const char	*netname,		/* in */
997c478bd9Sstevel@tonic-gate 	keylen_t	keylen,			/* in */
1007c478bd9Sstevel@tonic-gate 	algtype_t	algtype,		/* in */
1017c478bd9Sstevel@tonic-gate 	const char	*pw,			/* in */
1027c478bd9Sstevel@tonic-gate 	uid_t		uid,			/* in */
1037c478bd9Sstevel@tonic-gate 	gid_t		gid,			/* in */
1047c478bd9Sstevel@tonic-gate 	int		*get_seckey_cnt,	/* out */
1057c478bd9Sstevel@tonic-gate 	int		*good_pw_cnt,		/* out */
1067c478bd9Sstevel@tonic-gate 	int		*set_seckey_cnt,	/* out */
1077c478bd9Sstevel@tonic-gate 	int		flags,			/* in */
1087c478bd9Sstevel@tonic-gate 	int		debug)			/* in */
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	char	*skey;
1117c478bd9Sstevel@tonic-gate 	int	skeylen;
1127c478bd9Sstevel@tonic-gate 	char	messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	skeylen = BITS2NIBBLES(keylen) + 1;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if ((skey = malloc(skeylen)) == NULL) {
1177c478bd9Sstevel@tonic-gate 		return (0);
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if (getsecretkey_g(netname, keylen, algtype, skey, skeylen, pw)) {
1217c478bd9Sstevel@tonic-gate 		(*get_seckey_cnt)++;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 		if (skey[0]) {
1247c478bd9Sstevel@tonic-gate 			/* password does decrypt secret key */
1257c478bd9Sstevel@tonic-gate 			(*good_pw_cnt)++;
1267c478bd9Sstevel@tonic-gate 			if (key_setnet_g_uid(netname, skey, keylen, NULL, 0,
127573374d3Sjjj 			    algtype, uid, gid) >= 0) {
1287c478bd9Sstevel@tonic-gate 				(*set_seckey_cnt)++;
1297c478bd9Sstevel@tonic-gate 			} else {
1307c478bd9Sstevel@tonic-gate 				if (debug)
1317c478bd9Sstevel@tonic-gate 					syslog(LOG_DEBUG, "pam_dhkeys: "
132573374d3Sjjj 					    "get_and_set_seckey: could not "
133573374d3Sjjj 					    "set secret key for keytype "
134573374d3Sjjj 					    "%d-%d", keylen, algtype);
1357c478bd9Sstevel@tonic-gate 			}
1367c478bd9Sstevel@tonic-gate 		} else {
1377c478bd9Sstevel@tonic-gate 			if (pamh && !(flags & PAM_SILENT)) {
1387c478bd9Sstevel@tonic-gate 				(void) snprintf(messages[0],
1397c478bd9Sstevel@tonic-gate 				    sizeof (messages[0]),
1407c478bd9Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
141573374d3Sjjj 				    "Password does not "
142573374d3Sjjj 				    "decrypt secret key (type = %d-%d) "
143573374d3Sjjj 				    "for '%s'."), keylen, algtype, netname);
1447c478bd9Sstevel@tonic-gate 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
145573374d3Sjjj 				    messages, NULL);
1467c478bd9Sstevel@tonic-gate 			}
1477c478bd9Sstevel@tonic-gate 		}
1487c478bd9Sstevel@tonic-gate 	} else {
1497c478bd9Sstevel@tonic-gate 		if (debug)
1507c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: get_and_set_seckey: "
151573374d3Sjjj 			    "could not get secret key for keytype %d-%d",
152573374d3Sjjj 			    keylen, algtype);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	free(skey);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	return (1);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate  * int establish_key(pamh, flags, debug, netname)
1627c478bd9Sstevel@tonic-gate  *
163730bc278Ssdussud  * This routine establishes the Secure RPC Credentials for the
1647c478bd9Sstevel@tonic-gate  * user specified in PAM_USER, using the password in PAM_AUTHTOK.
1657c478bd9Sstevel@tonic-gate  *
166730bc278Ssdussud  * Establishing RPC credentials is considered a "helper" function for the PAM
167730bc278Ssdussud  * stack so we should only return failures or PAM_IGNORE. Returning PAM_SUCCESS
168730bc278Ssdussud  * may short circuit the stack and circumvent later critical checks.
169730bc278Ssdussud  *
17036e852a1SRaja Andra  * we are called from pam_sm_setcred:
17136e852a1SRaja Andra  *	1. if we are root (uid == 0), we do nothing and return
17236e852a1SRaja Andra  *	   PAM_IGNORE.
17336e852a1SRaja Andra  *	2. else, we try to establish credentials.
1747c478bd9Sstevel@tonic-gate  *
17536e852a1SRaja Andra  * We return framework errors as appropriate such as PAM_USER_UNKNOWN,
17636e852a1SRaja Andra  * PAM_BUF_ERR, PAM_PERM_DENIED.
177730bc278Ssdussud  *
17836e852a1SRaja Andra  * If we succeed in establishing credentials we return PAM_IGNORE.
1797c478bd9Sstevel@tonic-gate  *
18036e852a1SRaja Andra  * If we fail to establish credentials then we return:
18136e852a1SRaja Andra  *    - PAM_SERVICE_ERR (credentials needed) or PAM_SYSTEM_ERR
18236e852a1SRaja Andra  *      (credentials not needed) if netname could not be created;
18336e852a1SRaja Andra  *    - PAM_AUTH_ERR (credentials needed) or PAM_IGNORE (credentials
18436e852a1SRaja Andra  *      not needed) if no credentials were retrieved;
18536e852a1SRaja Andra  *    - PAM_AUTH_ERR if the password didn't decrypt the cred;
18636e852a1SRaja Andra  *    - PAM_SYSTEM_ERR if the cred's could not be stored.
1877c478bd9Sstevel@tonic-gate  *
1887c478bd9Sstevel@tonic-gate  * This routine returns the user's netname in "netname".
1897c478bd9Sstevel@tonic-gate  *
1907c478bd9Sstevel@tonic-gate  * All tools--but the PAM stack--currently use getpass() to obtain
1917c478bd9Sstevel@tonic-gate  * the user's secure RPC password. We must make sure we don't use more than
1927c478bd9Sstevel@tonic-gate  * the first des_block (eight) characters of whatever is handed down to us.
1937c478bd9Sstevel@tonic-gate  * Therefore, we use a local variable "short_pass" to hold those 8 char's.
1947c478bd9Sstevel@tonic-gate  */
195573374d3Sjjj static int
establish_key(pam_handle_t * pamh,int flags,int debug,char * netname)19636e852a1SRaja Andra establish_key(pam_handle_t *pamh, int flags, int debug, char *netname)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	char	*user;
1997c478bd9Sstevel@tonic-gate 	char	*passwd;
2007c478bd9Sstevel@tonic-gate 	char	short_pass[sizeof (des_block)+1], *short_passp;
2017c478bd9Sstevel@tonic-gate 	int	result;
2027c478bd9Sstevel@tonic-gate 	uid_t	uid;
2037c478bd9Sstevel@tonic-gate 	gid_t	gid;
2047c478bd9Sstevel@tonic-gate 	int	err;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	struct passwd pw;	/* Needed to obtain uid */
2077c478bd9Sstevel@tonic-gate 	char	*scratch;
2087c478bd9Sstevel@tonic-gate 	int	scratchlen;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	mechanism_t	**mechs;
2117c478bd9Sstevel@tonic-gate 	mechanism_t	**mpp;
2127c478bd9Sstevel@tonic-gate 	int	get_seckey_cnt = 0;
2137c478bd9Sstevel@tonic-gate 	int	set_seckey_cnt = 0;
2147c478bd9Sstevel@tonic-gate 	int	good_pw_cnt = 0;
2157c478bd9Sstevel@tonic-gate 	int	valid_mech_cnt = 0;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_USER, (void **)&user);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (user == NULL || *user == '\0') {
2207c478bd9Sstevel@tonic-gate 		if (debug)
2217c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: user NULL or empty");
2227c478bd9Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&passwd);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	scratchlen = sysconf(_SC_GETPW_R_SIZE_MAX);
2287c478bd9Sstevel@tonic-gate 	if ((scratch = malloc(scratchlen)) == NULL)
2297c478bd9Sstevel@tonic-gate 		return (PAM_BUF_ERR);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	if (getpwnam_r(user, &pw, scratch, scratchlen) == NULL) {
2327c478bd9Sstevel@tonic-gate 		result = PAM_USER_UNKNOWN;
2337c478bd9Sstevel@tonic-gate 		goto out;
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	uid = pw.pw_uid;
2377c478bd9Sstevel@tonic-gate 	gid = pw.pw_gid;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/*
2407c478bd9Sstevel@tonic-gate 	 * We don't set credentials when root logs in.
2417c478bd9Sstevel@tonic-gate 	 */
24236e852a1SRaja Andra 	if (uid == 0) {
2437c478bd9Sstevel@tonic-gate 		result = PAM_IGNORE;
2447c478bd9Sstevel@tonic-gate 		goto out;
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
24736e852a1SRaja Andra 	err = user2netname(netname, uid, NULL);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (err != 1) {
2507c478bd9Sstevel@tonic-gate 		if (debug)
2517c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: user2netname failed");
252504dd8f6SToomas Soome 		result = PAM_SYSTEM_ERR;
2537c478bd9Sstevel@tonic-gate 		goto out;
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/* passwd can be NULL (no passwd or su as root) */
2577c478bd9Sstevel@tonic-gate 	if (passwd) {
2587c478bd9Sstevel@tonic-gate 		(void) strlcpy(short_pass, passwd, sizeof (short_pass));
2597c478bd9Sstevel@tonic-gate 		short_passp = short_pass;
260*d6469564SToomas Soome 	} else {
2617c478bd9Sstevel@tonic-gate 		short_passp = NULL;
262*d6469564SToomas Soome 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	if (mechs = __nis_get_mechanisms(FALSE)) {
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		for (mpp = mechs; *mpp; mpp++) {
2677c478bd9Sstevel@tonic-gate 			mechanism_t *mp = *mpp;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 			if (AUTH_DES_COMPAT_CHK(mp))
2707c478bd9Sstevel@tonic-gate 				break;	/* fall through to AUTH_DES below */
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 			if (!VALID_MECH_ENTRY(mp))
2737c478bd9Sstevel@tonic-gate 				continue;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 			if (debug)
2767c478bd9Sstevel@tonic-gate 				syslog(LOG_DEBUG, "pam_dhkeys: trying "
277573374d3Sjjj 				    "key type = %d-%d", mp->keylen,
278573374d3Sjjj 				    mp->algtype);
2797c478bd9Sstevel@tonic-gate 			valid_mech_cnt++;
2807c478bd9Sstevel@tonic-gate 			if (!get_and_set_seckey(pamh, netname, mp->keylen,
281573374d3Sjjj 			    mp->algtype, short_passp, uid, gid,
282573374d3Sjjj 			    &get_seckey_cnt, &good_pw_cnt, &set_seckey_cnt,
28336e852a1SRaja Andra 			    flags, debug)) {
2847c478bd9Sstevel@tonic-gate 				result = PAM_BUF_ERR;
2857c478bd9Sstevel@tonic-gate 				goto out;
2867c478bd9Sstevel@tonic-gate 			}
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 		__nis_release_mechanisms(mechs);
2897c478bd9Sstevel@tonic-gate 		/* fall through to AUTH_DES below */
2907c478bd9Sstevel@tonic-gate 	} else {
2917c478bd9Sstevel@tonic-gate 		/*
29236e852a1SRaja Andra 		 * No usable mechs found in security congifuration file thus
2937c478bd9Sstevel@tonic-gate 		 * fallback to AUTH_DES compat.
2947c478bd9Sstevel@tonic-gate 		 */
2957c478bd9Sstevel@tonic-gate 		if (debug)
2967c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: no valid mechs "
297573374d3Sjjj 			    "found. Trying AUTH_DES.");
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	/*
30136e852a1SRaja Andra 	 * We always perform AUTH_DES for the benefit of services like NFS
30236e852a1SRaja Andra 	 * that may depend on the classic des 192bit key being set.
3037c478bd9Sstevel@tonic-gate 	 */
3047c478bd9Sstevel@tonic-gate 	if (!get_and_set_seckey(pamh, netname, AUTH_DES_KEYLEN,
3057c478bd9Sstevel@tonic-gate 	    AUTH_DES_ALGTYPE, short_passp, uid, gid, &get_seckey_cnt,
30636e852a1SRaja Andra 	    &good_pw_cnt, &set_seckey_cnt, flags, debug)) {
3077c478bd9Sstevel@tonic-gate 		result = PAM_BUF_ERR;
3087c478bd9Sstevel@tonic-gate 		goto out;
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (debug) {
3127c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: mech key totals:\n");
3137c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d valid mechanism(s)",
314573374d3Sjjj 		    valid_mech_cnt);
3157c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d secret key(s) retrieved",
316573374d3Sjjj 		    get_seckey_cnt);
3177c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d passwd decrypt successes",
318573374d3Sjjj 		    good_pw_cnt);
3197c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "pam_dhkeys: %d secret key(s) set",
320573374d3Sjjj 		    set_seckey_cnt);
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	if (get_seckey_cnt == 0) {		/* No credentials */
32436e852a1SRaja Andra 		result = PAM_IGNORE;
3257c478bd9Sstevel@tonic-gate 		goto out;
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (good_pw_cnt == 0) {			/* wrong password */
329730bc278Ssdussud 		result = PAM_AUTH_ERR;
3307c478bd9Sstevel@tonic-gate 		goto out;
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (set_seckey_cnt == 0) {
334730bc278Ssdussud 		result = PAM_SYSTEM_ERR;
3357c478bd9Sstevel@tonic-gate 		goto out;
3367c478bd9Sstevel@tonic-gate 	}
33736e852a1SRaja Andra 	/* Credentials have been successfully established, return PAM_IGNORE */
3387c478bd9Sstevel@tonic-gate 	result = PAM_IGNORE;
3397c478bd9Sstevel@tonic-gate out:
340730bc278Ssdussud 	/*
341730bc278Ssdussud 	 * If we are authenticating we attempt to establish credentials
342730bc278Ssdussud 	 * where appropriate. Failure to do so is only an error if we
343730bc278Ssdussud 	 * definitely needed them. Thus always return PAM_IGNORE
344730bc278Ssdussud 	 * if we are authenticating and credentials were not needed.
345730bc278Ssdussud 	 */
3467c478bd9Sstevel@tonic-gate 	free(scratch);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	(void) memset(short_pass, '\0', sizeof (short_pass));
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	return (result);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
35336e852a1SRaja Andra /*ARGSUSED*/
3547c478bd9Sstevel@tonic-gate int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)3557c478bd9Sstevel@tonic-gate pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
3567c478bd9Sstevel@tonic-gate {
35736e852a1SRaja Andra 	return (PAM_IGNORE);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
360573374d3Sjjj 
361573374d3Sjjj typedef struct argres {
362573374d3Sjjj 	uid_t uid;
363573374d3Sjjj 	int result;
364573374d3Sjjj } argres_t;
365573374d3Sjjj 
366573374d3Sjjj /*
367573374d3Sjjj  * Revoke NFS DES credentials.
368573374d3Sjjj  * NFS may not be installed so we need to deal with SIGSYS
369573374d3Sjjj  * when we call _nfssys(); we thus call _nfssys() in a seperate thread that
370573374d3Sjjj  * is created specifically for this call. The thread specific signalmask
371573374d3Sjjj  * is set to ignore SIGSYS. After the call to _nfssys(), the thread
372573374d3Sjjj  * ceases to exist.
373573374d3Sjjj  */
374573374d3Sjjj static void *
revoke_nfs_cred(void * ap)375573374d3Sjjj revoke_nfs_cred(void *ap)
376573374d3Sjjj {
377573374d3Sjjj 	struct nfs_revauth_args nra;
378573374d3Sjjj 	sigset_t isigset;
379573374d3Sjjj 	argres_t *argres = (argres_t *)ap;
380573374d3Sjjj 
381573374d3Sjjj 	nra.authtype = AUTH_DES;
382573374d3Sjjj 	nra.uid = argres->uid;
383573374d3Sjjj 
384573374d3Sjjj 	(void) sigemptyset(&isigset);
385573374d3Sjjj 	(void) sigaddset(&isigset, SIGSYS);
386573374d3Sjjj 
387573374d3Sjjj 	if (pthread_sigmask(SIG_BLOCK, &isigset, NULL) == 0) {
388573374d3Sjjj 		argres->result = _nfssys(NFS_REVAUTH, &nra);
389573374d3Sjjj 		if (argres->result < 0 && errno == ENOSYS) {
390573374d3Sjjj 			argres->result = 0;
391573374d3Sjjj 		}
392573374d3Sjjj 	} else {
393573374d3Sjjj 		argres->result = -1;
394573374d3Sjjj 	}
395573374d3Sjjj 	return (NULL);
396573374d3Sjjj }
397573374d3Sjjj 
398573374d3Sjjj static int
remove_key(pam_handle_t * pamh,int flags,int debug)3997c478bd9Sstevel@tonic-gate remove_key(pam_handle_t *pamh, int flags, int debug)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	int result;
4027c478bd9Sstevel@tonic-gate 	char *uname;
4037c478bd9Sstevel@tonic-gate 	attrlist attr_pw[2];
4047c478bd9Sstevel@tonic-gate 	struct pam_repository *auth_rep = NULL;
4057c478bd9Sstevel@tonic-gate 	pwu_repository_t *pwu_rep;
4067c478bd9Sstevel@tonic-gate 	uid_t uid;
4077c478bd9Sstevel@tonic-gate 	gid_t gid;
408573374d3Sjjj 	argres_t argres;
40993050252SRaja Andra 	pthread_t tid;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_USER, (void **)&uname);
412*d6469564SToomas Soome 	if (uname == NULL || *uname == '\0') {
4137c478bd9Sstevel@tonic-gate 		if (debug)
4147c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
4157c478bd9Sstevel@tonic-gate 			    "pam_dhkeys: user NULL or empty in remove_key()");
4167c478bd9Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (strcmp(uname, "root") == 0) {
4207c478bd9Sstevel@tonic-gate 		if ((flags & PAM_SILENT) == 0) {
4217c478bd9Sstevel@tonic-gate 			char msg[3][PAM_MAX_MSG_SIZE];
4227c478bd9Sstevel@tonic-gate 			(void) snprintf(msg[0], sizeof (msg[0]),
4237c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
424573374d3Sjjj 			    "removing root credentials would"
425573374d3Sjjj 			    " break the rpc services that"));
4267c478bd9Sstevel@tonic-gate 			(void) snprintf(msg[1], sizeof (msg[1]),
4277c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
428573374d3Sjjj 			    "use secure rpc on this host!"));
4297c478bd9Sstevel@tonic-gate 			(void) snprintf(msg[2], sizeof (msg[2]),
4307c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
431573374d3Sjjj 			    "root may use keylogout -f to do"
432573374d3Sjjj 			    " this (at your own risk)!"));
4337c478bd9Sstevel@tonic-gate 			(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 3,
4347c478bd9Sstevel@tonic-gate 			    msg, NULL);
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 		return (PAM_PERM_DENIED);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep);
4407c478bd9Sstevel@tonic-gate 	if (auth_rep != NULL) {
4417c478bd9Sstevel@tonic-gate 		if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL)
4427c478bd9Sstevel@tonic-gate 			return (PAM_BUF_ERR);
4437c478bd9Sstevel@tonic-gate 		pwu_rep->type = auth_rep->type;
4447c478bd9Sstevel@tonic-gate 		pwu_rep->scope = auth_rep->scope;
4457c478bd9Sstevel@tonic-gate 		pwu_rep->scope_len = auth_rep->scope_len;
446*d6469564SToomas Soome 	} else {
4477c478bd9Sstevel@tonic-gate 		pwu_rep = PWU_DEFAULT_REP;
448*d6469564SToomas Soome 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/* Retrieve user's uid/gid from the password repository */
4517c478bd9Sstevel@tonic-gate 	attr_pw[0].type = ATTR_UID; attr_pw[0].next = &attr_pw[1];
4527c478bd9Sstevel@tonic-gate 	attr_pw[1].type = ATTR_GID; attr_pw[1].next = NULL;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	result = __get_authtoken_attr(uname, pwu_rep, attr_pw);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if (pwu_rep != PWU_DEFAULT_REP)
4577c478bd9Sstevel@tonic-gate 		free(pwu_rep);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (result == PWU_NOT_FOUND)
4607c478bd9Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
4617c478bd9Sstevel@tonic-gate 	if (result == PWU_DENIED)
4627c478bd9Sstevel@tonic-gate 		return (PAM_PERM_DENIED);
4637c478bd9Sstevel@tonic-gate 	if (result != PWU_SUCCESS)
4647c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	uid = (uid_t)attr_pw[0].data.val_i;
4677c478bd9Sstevel@tonic-gate 	gid = (gid_t)attr_pw[1].data.val_i;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	(void) key_removesecret_g_uid(uid, gid);
4707c478bd9Sstevel@tonic-gate 
471573374d3Sjjj 	argres.uid = uid;
472573374d3Sjjj 	argres.result = -1;
473573374d3Sjjj 
474573374d3Sjjj 	if (pthread_create(&tid, NULL, revoke_nfs_cred, (void *)&argres) == 0)
475573374d3Sjjj 		(void) pthread_join(tid, NULL);
4767c478bd9Sstevel@tonic-gate 
477573374d3Sjjj 	if (argres.result < 0) {
4787c478bd9Sstevel@tonic-gate 		if ((flags & PAM_SILENT) == 0) {
4797c478bd9Sstevel@tonic-gate 			(void) msg(pamh, dgettext(TEXT_DOMAIN,
480573374d3Sjjj 			    "Warning: NFS credentials not destroyed"));
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 		return (PAM_AUTH_ERR);
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	return (PAM_IGNORE);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)4897c478bd9Sstevel@tonic-gate pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	int	i;
4927c478bd9Sstevel@tonic-gate 	int	debug = 0;
4937c478bd9Sstevel@tonic-gate 	int	result;
4947c478bd9Sstevel@tonic-gate 	char	netname[MAXNETNAMELEN + 1];
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
4977c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
4987c478bd9Sstevel@tonic-gate 			debug = 1;
4997c478bd9Sstevel@tonic-gate 		else if (strcmp(argv[i], "nowarn") == 0)
5007c478bd9Sstevel@tonic-gate 			flags |= PAM_SILENT;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/* Check for invalid flags */
5047c478bd9Sstevel@tonic-gate 	if (flags && (flags & PAM_ESTABLISH_CRED) == 0 &&
505573374d3Sjjj 	    (flags & PAM_REINITIALIZE_CRED) == 0 &&
506573374d3Sjjj 	    (flags & PAM_REFRESH_CRED) == 0 &&
507573374d3Sjjj 	    (flags & PAM_DELETE_CRED) == 0 &&
508573374d3Sjjj 	    (flags & PAM_SILENT) == 0) {
5097c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "pam_dhkeys: pam_setcred: illegal flags %d",
510573374d3Sjjj 		    flags);
5117c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	if ((flags & PAM_REINITIALIZE_CRED) || (flags & PAM_REFRESH_CRED)) {
5167c478bd9Sstevel@tonic-gate 		/* doesn't apply to UNIX */
5177c478bd9Sstevel@tonic-gate 		if (debug)
5187c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: cred reinit/refresh "
5197c478bd9Sstevel@tonic-gate 			    "ignored\n");
5207c478bd9Sstevel@tonic-gate 		return (PAM_IGNORE);
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	if (flags & PAM_DELETE_CRED) {
5247c478bd9Sstevel@tonic-gate 		if (debug)
5257c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_dhkeys: removing creds\n");
5267c478bd9Sstevel@tonic-gate 		result = remove_key(pamh, flags, debug);
5277c478bd9Sstevel@tonic-gate 	} else {
52836e852a1SRaja Andra 		result = establish_key(pamh, flags, debug, netname);
5297c478bd9Sstevel@tonic-gate 		/* Some diagnostics */
5307c478bd9Sstevel@tonic-gate 		if ((flags & PAM_SILENT) == 0) {
5317c478bd9Sstevel@tonic-gate 			if (result == PAM_AUTH_ERR)
5327c478bd9Sstevel@tonic-gate 				(void) msg(pamh, dgettext(TEXT_DOMAIN,
5337c478bd9Sstevel@tonic-gate 				    "Password does not decrypt any secret "
5347c478bd9Sstevel@tonic-gate 				    "keys for %s."), netname);
5357c478bd9Sstevel@tonic-gate 			else if (result == PAM_SYSTEM_ERR && netname[0])
5367c478bd9Sstevel@tonic-gate 				(void) msg(pamh, dgettext(TEXT_DOMAIN,
5377c478bd9Sstevel@tonic-gate 				    "Could not set secret key(s) for %s. "
5387c478bd9Sstevel@tonic-gate 				    "The key server may be down."), netname);
5397c478bd9Sstevel@tonic-gate 		}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 		/* Not having credentials set is not an error... */
5427c478bd9Sstevel@tonic-gate 		result = PAM_IGNORE;
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	return (result);
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5497c478bd9Sstevel@tonic-gate void
rpc_cleanup(pam_handle_t * pamh,void * data,int pam_status)5507c478bd9Sstevel@tonic-gate rpc_cleanup(pam_handle_t *pamh, void *data, int pam_status)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	if (data) {
5537c478bd9Sstevel@tonic-gate 		(void) memset(data, 0, strlen(data));
5547c478bd9Sstevel@tonic-gate 		free(data);
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
55836e852a1SRaja Andra /*ARGSUSED*/
5597c478bd9Sstevel@tonic-gate int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)5607c478bd9Sstevel@tonic-gate pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
5617c478bd9Sstevel@tonic-gate {
56236e852a1SRaja Andra 	return (PAM_IGNORE);
5637c478bd9Sstevel@tonic-gate }
564