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
53bfb48feSsemery  * Common Development and Distribution License (the "License").
63bfb48feSsemery  * 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 /*
223bfb48feSsemery  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <libintl.h>
297c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
307c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <pwd.h>
367c478bd9Sstevel@tonic-gate #include <syslog.h>
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <krb5.h>
397c478bd9Sstevel@tonic-gate #include <netdb.h>
407c478bd9Sstevel@tonic-gate #include <unistd.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <fcntl.h>
43505d05c7Sgtb #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <com_err.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include "utils.h"
477c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #define	PAMTXD			"SUNW_OST_SYSOSPAM"
507c478bd9Sstevel@tonic-gate #define	KRB5_DEFAULT_LIFE	60*60*10  /* 10 hours */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate extern void krb5_cleanup(pam_handle_t *, void *, int);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static int attempt_refresh_cred(krb5_module_data_t *, char *, int);
557c478bd9Sstevel@tonic-gate static int attempt_delete_initcred(krb5_module_data_t *);
567c478bd9Sstevel@tonic-gate static krb5_error_code krb5_renew_tgt(krb5_module_data_t *, krb5_principal,
577c478bd9Sstevel@tonic-gate 		krb5_principal, int);
587c478bd9Sstevel@tonic-gate static krb5_boolean creds_match(krb5_context, const krb5_creds *,
597c478bd9Sstevel@tonic-gate 	const krb5_creds *);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate extern uint_t kwarn_add_warning(char *, int);
627c478bd9Sstevel@tonic-gate extern uint_t kwarn_del_warning(char *);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * pam_sm_setcred
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate int
687c478bd9Sstevel@tonic-gate pam_sm_setcred(
697c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh,
707c478bd9Sstevel@tonic-gate 	int	flags,
717c478bd9Sstevel@tonic-gate 	int	argc,
727c478bd9Sstevel@tonic-gate 	const char **argv)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	int	i;
757c478bd9Sstevel@tonic-gate 	int	err = 0;
767c478bd9Sstevel@tonic-gate 	int	debug = 0;
777c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd = NULL;
783bfb48feSsemery 	char			*user = NULL;
797c478bd9Sstevel@tonic-gate 	int			result;
807c478bd9Sstevel@tonic-gate 	krb5_repository_data_t	*krb5_data = NULL;
817c478bd9Sstevel@tonic-gate 	pam_repository_t	*rep_data = NULL;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
847c478bd9Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
857c478bd9Sstevel@tonic-gate 			debug = 1;
867c478bd9Sstevel@tonic-gate 		else if (strcasecmp(argv[i], "nowarn") == 0)
877c478bd9Sstevel@tonic-gate 			flags = flags | PAM_SILENT;
887c478bd9Sstevel@tonic-gate 	}
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if (debug)
913bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
927c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): start: nowarn = %d, flags = 0x%x",
937c478bd9Sstevel@tonic-gate 		    flags & PAM_SILENT ? 1 : 0, flags);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/* make sure flags are valid */
967c478bd9Sstevel@tonic-gate 	if (flags &&
977c478bd9Sstevel@tonic-gate 	    !(flags & PAM_ESTABLISH_CRED) &&
987c478bd9Sstevel@tonic-gate 	    !(flags & PAM_REINITIALIZE_CRED) &&
997c478bd9Sstevel@tonic-gate 	    !(flags & PAM_REFRESH_CRED) &&
1007c478bd9Sstevel@tonic-gate 	    !(flags & PAM_DELETE_CRED) &&
1017c478bd9Sstevel@tonic-gate 	    !(flags & PAM_SILENT)) {
1023bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
1033bfb48feSsemery 			    "PAM-KRB5 (setcred): illegal flag %d", flags);
1047c478bd9Sstevel@tonic-gate 		err = PAM_SYSTEM_ERR;
1057c478bd9Sstevel@tonic-gate 		goto out;
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 
1083bfb48feSsemery 	(void) pam_get_item(pamh, PAM_USER, (void**) &user);
1097c478bd9Sstevel@tonic-gate 
1103bfb48feSsemery 	if (user == NULL || *user == '\0')
1113bfb48feSsemery 		return (PAM_USER_UNKNOWN);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	if (pam_get_data(pamh, KRB5_DATA, (const void**)&kmd) != PAM_SUCCESS) {
1147c478bd9Sstevel@tonic-gate 		if (debug) {
1153bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1167c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): kmd get failed, kmd=0x%p",
1177c478bd9Sstevel@tonic-gate 			    kmd);
1187c478bd9Sstevel@tonic-gate 		}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 		/*
1217c478bd9Sstevel@tonic-gate 		 * User  doesn't need to authenticate for PAM_REFRESH_CRED
1227c478bd9Sstevel@tonic-gate 		 * or for PAM_DELETE_CRED
1237c478bd9Sstevel@tonic-gate 		 */
1247c478bd9Sstevel@tonic-gate 		if (flags & (PAM_REFRESH_CRED|PAM_DELETE_CRED)) {
1253bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1267c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): inst kmd structure");
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 			kmd = calloc(1, sizeof (krb5_module_data_t));
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 			if (kmd == NULL) {
1317c478bd9Sstevel@tonic-gate 				result = PAM_BUF_ERR;
1327c478bd9Sstevel@tonic-gate 				return (result);
1337c478bd9Sstevel@tonic-gate 			}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 			if ((err = pam_set_data(pamh, KRB5_DATA,
1367c478bd9Sstevel@tonic-gate 				kmd, &krb5_cleanup)) != PAM_SUCCESS) {
1377c478bd9Sstevel@tonic-gate 				free(kmd);
1387c478bd9Sstevel@tonic-gate 				return (PAM_SYSTEM_ERR);
1397c478bd9Sstevel@tonic-gate 			}
1407c478bd9Sstevel@tonic-gate 		} else {
141*3441f6a1Ssemery 			/*
142*3441f6a1Ssemery 			 * This could mean that we are not the account authority
143*3441f6a1Ssemery 			 * for the authenticated user.  Therefore we should
144*3441f6a1Ssemery 			 * return PAM_IGNORE in order to not affect the
145*3441f6a1Ssemery 			 * login process of said user.
146*3441f6a1Ssemery 			 */
147*3441f6a1Ssemery 			err = PAM_IGNORE;
148*3441f6a1Ssemery 			goto out;
1497c478bd9Sstevel@tonic-gate 		}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	} else {  /* pam_get_data success */
1527c478bd9Sstevel@tonic-gate 		if (kmd == NULL) {
1537c478bd9Sstevel@tonic-gate 			if (debug) {
1543bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
1557c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (setcred): kmd structure"
1567c478bd9Sstevel@tonic-gate 				    " gotten but is NULL for user %s", user);
1577c478bd9Sstevel@tonic-gate 			}
1587c478bd9Sstevel@tonic-gate 			err = PAM_CRED_UNAVAIL;
1597c478bd9Sstevel@tonic-gate 			goto out;
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		if (debug)
1633bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1647c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): kmd auth_status: %s",
1657c478bd9Sstevel@tonic-gate 			    pam_strerror(pamh, kmd->auth_status));
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		/*
1687c478bd9Sstevel@tonic-gate 		 * pam_auth has set status to ignore, so we also return ignore
1697c478bd9Sstevel@tonic-gate 		 */
1707c478bd9Sstevel@tonic-gate 		if (kmd->auth_status == PAM_IGNORE) {
1717c478bd9Sstevel@tonic-gate 			err = PAM_IGNORE;
1727c478bd9Sstevel@tonic-gate 			goto out;
1737c478bd9Sstevel@tonic-gate 		}
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	kmd->debug = debug;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1797c478bd9Sstevel@tonic-gate 	 * User must have passed pam_authenticate()
1807c478bd9Sstevel@tonic-gate 	 * in order to use PAM_ESTABLISH_CRED or PAM_REINITIALIZE_CRED
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	if ((flags & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED)) &&
1837c478bd9Sstevel@tonic-gate 	    (kmd->auth_status != PAM_SUCCESS)) {
1847c478bd9Sstevel@tonic-gate 		if (kmd->debug)
1853bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1867c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
1877c478bd9Sstevel@tonic-gate 			    "setcreds, not authenticated!");
1887c478bd9Sstevel@tonic-gate 		return (PAM_CRED_UNAVAIL);
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/*
1927c478bd9Sstevel@tonic-gate 	 * We cannot assume that kmd->kcontext being non-NULL
1937c478bd9Sstevel@tonic-gate 	 * means it is valid.  Other pam_krb5 mods may have
1947c478bd9Sstevel@tonic-gate 	 * freed it but not reset it to NULL.
1957c478bd9Sstevel@tonic-gate 	 * Log a message when debugging to track down memory
1967c478bd9Sstevel@tonic-gate 	 * leaks.
1977c478bd9Sstevel@tonic-gate 	 */
1987c478bd9Sstevel@tonic-gate 	if (kmd->kcontext != NULL && kmd->debug)
1993bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2007c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): kcontext != NULL, "
2017c478bd9Sstevel@tonic-gate 			"possible memory leak.");
2027c478bd9Sstevel@tonic-gate 
2033bfb48feSsemery 	/*
2043bfb48feSsemery 	 * Use the authenticated and validated user, if applicable.
2053bfb48feSsemery 	 */
2063bfb48feSsemery 	if (kmd->user != NULL)
2073bfb48feSsemery 		user = kmd->user;
2083bfb48feSsemery 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * If auth was short-circuited we will not have anything to
2117c478bd9Sstevel@tonic-gate 	 * renew, so just return here.
2127c478bd9Sstevel@tonic-gate 	 */
2133bfb48feSsemery 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
2143bfb48feSsemery 
2157c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
2167c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
2177c478bd9Sstevel@tonic-gate 			if (debug)
2183bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
2193bfb48feSsemery 					"PAM-KRB5 (setcred): wrong"
2207c478bd9Sstevel@tonic-gate 					"repository found (%s), returning "
2217c478bd9Sstevel@tonic-gate 					"PAM_IGNORE", rep_data->type);
2227c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 		if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
2257c478bd9Sstevel@tonic-gate 			krb5_data = (krb5_repository_data_t *)rep_data->scope;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			if (krb5_data->flags ==
2287c478bd9Sstevel@tonic-gate 				SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
2297c478bd9Sstevel@tonic-gate 				krb5_data->principal != NULL &&
2307c478bd9Sstevel@tonic-gate 				strlen(krb5_data->principal)) {
2317c478bd9Sstevel@tonic-gate 				if (debug)
2323bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
2337c478bd9Sstevel@tonic-gate 						"PAM-KRB5 (setcred): "
2347c478bd9Sstevel@tonic-gate 						"Principal %s already "
2357c478bd9Sstevel@tonic-gate 						"authenticated, "
2367c478bd9Sstevel@tonic-gate 						"cannot setcred",
2377c478bd9Sstevel@tonic-gate 						krb5_data->principal);
2387c478bd9Sstevel@tonic-gate 				return (PAM_SUCCESS);
2397c478bd9Sstevel@tonic-gate 			}
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (flags & PAM_REINITIALIZE_CRED)
2447c478bd9Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_REINITIALIZE_CRED);
2457c478bd9Sstevel@tonic-gate 	else if (flags & PAM_REFRESH_CRED)
2467c478bd9Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_REFRESH_CRED);
2477c478bd9Sstevel@tonic-gate 	else if (flags & PAM_DELETE_CRED)
2487c478bd9Sstevel@tonic-gate 		err = attempt_delete_initcred(kmd);
2497c478bd9Sstevel@tonic-gate 	else {
2507c478bd9Sstevel@tonic-gate 		/*
2517c478bd9Sstevel@tonic-gate 		 * Default case:  PAM_ESTABLISH_CRED
2527c478bd9Sstevel@tonic-gate 		 */
2537c478bd9Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_ESTABLISH_CRED);
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate 
2563bfb48feSsemery 	if (err != PAM_SUCCESS)
2573bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
2587c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): pam_setcred failed "
2597c478bd9Sstevel@tonic-gate 		    "for %s (%s).", user, pam_strerror(pamh, err));
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate out:
2627c478bd9Sstevel@tonic-gate 	if (kmd && kmd->kcontext) {
2637c478bd9Sstevel@tonic-gate 		/*
2647c478bd9Sstevel@tonic-gate 		 * free 'kcontext' field if it is allocated,
2657c478bd9Sstevel@tonic-gate 		 * kcontext is local to the operation being performed
2667c478bd9Sstevel@tonic-gate 		 * not considered global to the entire pam module.
2677c478bd9Sstevel@tonic-gate 		 */
2687c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
2697c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * 'kmd' is not freed here, it is handled in krb5_cleanup
2747c478bd9Sstevel@tonic-gate 	 */
2757c478bd9Sstevel@tonic-gate 	if (debug)
2763bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2777c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): end: %s",
2787c478bd9Sstevel@tonic-gate 		    pam_strerror(pamh, err));
2797c478bd9Sstevel@tonic-gate 	return (err);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate static int
2837c478bd9Sstevel@tonic-gate attempt_refresh_cred(
2847c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd,
2857c478bd9Sstevel@tonic-gate 	char		*user,
2867c478bd9Sstevel@tonic-gate 	int	flag)
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate 	krb5_principal	me;
2897c478bd9Sstevel@tonic-gate 	krb5_principal	server;
2907c478bd9Sstevel@tonic-gate 	krb5_error_code	code;
2917c478bd9Sstevel@tonic-gate 	char		kuser[2*MAXHOSTNAMELEN];
2927c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
2937c478bd9Sstevel@tonic-gate 		0,
2947c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
2957c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
2967c478bd9Sstevel@tonic-gate 	};
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/* User must have passed pam_authenticate() */
2997c478bd9Sstevel@tonic-gate 	if (kmd->auth_status != PAM_SUCCESS) {
3007c478bd9Sstevel@tonic-gate 		if (kmd->debug)
3013bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3027c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
3037c478bd9Sstevel@tonic-gate 			    "setcreds, not authenticated!");
3047c478bd9Sstevel@tonic-gate 		return (PAM_CRED_UNAVAIL);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* Create a new context here. */
3087c478bd9Sstevel@tonic-gate 	if (krb5_init_context(&kmd->kcontext) != 0) {
3097c478bd9Sstevel@tonic-gate 		if (kmd->debug)
3103bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3117c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
3127c478bd9Sstevel@tonic-gate 			    "initialize krb5 context");
3137c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if (krb5_cc_default(kmd->kcontext, &kmd->ccache) != 0) {
3173bfb48feSsemery 		return (PAM_SYSTEM_ERR);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
3217c478bd9Sstevel@tonic-gate 		2*MAXHOSTNAMELEN)) != 0) {
3227c478bd9Sstevel@tonic-gate 		return (code);
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if (krb5_parse_name(kmd->kcontext, kuser, &me) != 0) {
3263bfb48feSsemery 		return (PAM_SYSTEM_ERR);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if (code = krb5_build_principal_ext(kmd->kcontext, &server,
3307c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
3317c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data,
3327c478bd9Sstevel@tonic-gate 			    tgtname.length, tgtname.data,
3337c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
3347c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
3353bfb48feSsemery 		krb5_free_principal(kmd->kcontext, me);
3363bfb48feSsemery 		return (PAM_SYSTEM_ERR);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	code = krb5_renew_tgt(kmd, me, server, flag);
3407c478bd9Sstevel@tonic-gate 
3413bfb48feSsemery 	krb5_free_principal(kmd->kcontext, server);
3423bfb48feSsemery 	krb5_free_principal(kmd->kcontext, me);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	if (code) {
3453bfb48feSsemery 		if (kmd->debug)
3463bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3473bfb48feSsemery 				"PAM-KRB5(setcred): krb5_renew_tgt() "
3483bfb48feSsemery 				"failed: %s", error_message((errcode_t)code));
3497c478bd9Sstevel@tonic-gate 		return (PAM_CRED_ERR);
3507c478bd9Sstevel@tonic-gate 	} else {
3517c478bd9Sstevel@tonic-gate 		return (PAM_SUCCESS);
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate  * This code will update the credential matching "server" in the user's
3577c478bd9Sstevel@tonic-gate  * credential cache.  The flag may be set to one of:
3587c478bd9Sstevel@tonic-gate  * PAM_ESTABLISH_CRED -  Create a new cred cache if one doesnt exist,
3597c478bd9Sstevel@tonic-gate  *                       else refresh the existing one.
3607c478bd9Sstevel@tonic-gate  * PAM_REINITIALIZE_CRED  - destroy current cred cache and create a new one
3617c478bd9Sstevel@tonic-gate  * PAM_REFRESH_CRED  - update the existing cred cache (default action)
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate static krb5_error_code
3647c478bd9Sstevel@tonic-gate krb5_renew_tgt(
3657c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd,
3667c478bd9Sstevel@tonic-gate 	krb5_principal	me,
3677c478bd9Sstevel@tonic-gate 	krb5_principal	server,
3687c478bd9Sstevel@tonic-gate 	int	flag)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
3717c478bd9Sstevel@tonic-gate 	krb5_creds	creds;
3721dac1dbeSgtb 	krb5_creds	*renewed_cred = NULL;
3737c478bd9Sstevel@tonic-gate 	char		*client_name = NULL;
3747c478bd9Sstevel@tonic-gate 	typedef struct _cred_node {
3757c478bd9Sstevel@tonic-gate 		krb5_creds		*creds;
3767c478bd9Sstevel@tonic-gate 		struct _cred_node	*next;
3777c478bd9Sstevel@tonic-gate 	} cred_node;
3787c478bd9Sstevel@tonic-gate 	cred_node *cred_list_head = NULL;
3797c478bd9Sstevel@tonic-gate 	cred_node *fetched = NULL;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate #define	my_creds	(kmd->initcreds)
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if ((flag != PAM_REFRESH_CRED) &&
3847c478bd9Sstevel@tonic-gate 		(flag != PAM_REINITIALIZE_CRED) &&
3857c478bd9Sstevel@tonic-gate 		(flag != PAM_ESTABLISH_CRED))
3863bfb48feSsemery 			return (KRB5KRB_ERR_GENERIC);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/* this is needed only for the ktkt_warnd */
3893bfb48feSsemery 	if ((retval = krb5_unparse_name(kmd->kcontext, me, &client_name)) != 0)
3903bfb48feSsemery 		return (retval);
3917c478bd9Sstevel@tonic-gate 
3921dac1dbeSgtb 	(void) memset(&creds, 0, sizeof (krb5_creds));
3937c478bd9Sstevel@tonic-gate 	if ((retval = krb5_copy_principal(kmd->kcontext,
3941dac1dbeSgtb 				server, &creds.server))) {
3957c478bd9Sstevel@tonic-gate 		if (kmd->debug)
3963bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3977c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_copy_principal "
3987c478bd9Sstevel@tonic-gate 				"failed: %s",
3997c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
4007c478bd9Sstevel@tonic-gate 		goto cleanup_creds;
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/* obtain ticket & session key */
4047c478bd9Sstevel@tonic-gate 	retval = krb5_cc_get_principal(kmd->kcontext,
4051dac1dbeSgtb 				kmd->ccache, &creds.client);
4067c478bd9Sstevel@tonic-gate 	if (retval && (kmd->debug))
4073bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
4087c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): User not in cred "
4093bfb48feSsemery 			"cache (%s)", error_message((errcode_t)retval));
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if ((retval == KRB5_FCC_NOFILE) &&
4127c478bd9Sstevel@tonic-gate 		(flag & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED))) {
4137c478bd9Sstevel@tonic-gate 		/*
4147c478bd9Sstevel@tonic-gate 		 * Create a fresh ccache, and store the credentials
4157c478bd9Sstevel@tonic-gate 		 * we got from pam_authenticate()
4167c478bd9Sstevel@tonic-gate 		 */
4177c478bd9Sstevel@tonic-gate 		if ((retval = krb5_cc_initialize(kmd->kcontext,
4187c478bd9Sstevel@tonic-gate 				kmd->ccache, me)) != 0) {
4193bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4207c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_cc_initialize "
4217c478bd9Sstevel@tonic-gate 				"failed: %s",
4227c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
4237c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
4247c478bd9Sstevel@tonic-gate 		} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
4257c478bd9Sstevel@tonic-gate 				kmd->ccache, &my_creds)) != 0) {
4263bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4277c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_cc_store_cred "
4287c478bd9Sstevel@tonic-gate 				"failed: %s",
4297c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
4307c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 	} else if (retval) {
4337c478bd9Sstevel@tonic-gate 		/*
4347c478bd9Sstevel@tonic-gate 		 * We failed to get the user's credentials.
4357c478bd9Sstevel@tonic-gate 		 * This might be due to permission error on the cache,
4367c478bd9Sstevel@tonic-gate 		 * or maybe we are looking in the wrong cache file!
4377c478bd9Sstevel@tonic-gate 		 */
4383bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
4397c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): Cannot find creds"
4403bfb48feSsemery 			" for %s (%s)",
4417c478bd9Sstevel@tonic-gate 			client_name ? client_name : "(unknown)",
4427c478bd9Sstevel@tonic-gate 			error_message((errcode_t)retval));
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	} else if (flag & PAM_REINITIALIZE_CRED) {
4457c478bd9Sstevel@tonic-gate 		/*
4467c478bd9Sstevel@tonic-gate 		 * This destroys the credential cache, and stores a new
4477c478bd9Sstevel@tonic-gate 		 * krbtgt with updated startime, endtime and renewable
4487c478bd9Sstevel@tonic-gate 		 * lifetime.
4497c478bd9Sstevel@tonic-gate 		 */
4507c478bd9Sstevel@tonic-gate 		creds.times.starttime = my_creds.times.starttime;
4517c478bd9Sstevel@tonic-gate 		creds.times.endtime = my_creds.times.endtime;
4527c478bd9Sstevel@tonic-gate 		creds.times.renew_till = my_creds.times.renew_till;
4537c478bd9Sstevel@tonic-gate 		if ((retval = krb5_get_credentials_renew(kmd->kcontext, 0,
4541dac1dbeSgtb 				kmd->ccache, &creds, &renewed_cred))) {
4557c478bd9Sstevel@tonic-gate 			if (kmd->debug)
4563bfb48feSsemery 			    __pam_log(LOG_AUTH | LOG_DEBUG,
4577c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_get_credentials",
4587c478bd9Sstevel@tonic-gate 				"_renew(reinitialize) failed: %s",
4597c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
4607c478bd9Sstevel@tonic-gate 			/* perhaps the tgt lifetime has expired */
4617c478bd9Sstevel@tonic-gate 			if ((retval = krb5_cc_initialize(kmd->kcontext,
4627c478bd9Sstevel@tonic-gate 					kmd->ccache, me)) != 0) {
4637c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
4647c478bd9Sstevel@tonic-gate 			} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
4657c478bd9Sstevel@tonic-gate 					kmd->ccache, &my_creds)) != 0) {
4667c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
4677c478bd9Sstevel@tonic-gate 			}
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 	} else {
4707c478bd9Sstevel@tonic-gate 		/*
4717c478bd9Sstevel@tonic-gate 		 * Creds already exist, update them if possible.
4727c478bd9Sstevel@tonic-gate 		 * We got here either with the ESTABLISH or REFRESH flag.
4737c478bd9Sstevel@tonic-gate 		 *
4747c478bd9Sstevel@tonic-gate 		 * The credential cache does exist, and we are going to
4757c478bd9Sstevel@tonic-gate 		 * read in each cred, looking for our own.  When we find
4767c478bd9Sstevel@tonic-gate 		 * a matching credential, we will update it, and store it.
4777c478bd9Sstevel@tonic-gate 		 * Any nonmatching credentials are stored as is.
4787c478bd9Sstevel@tonic-gate 		 *
4797c478bd9Sstevel@tonic-gate 		 * Rules:
4807c478bd9Sstevel@tonic-gate 		 *    TGT must exist in cache to get to this point.
4817c478bd9Sstevel@tonic-gate 		 *	if flag == ESTABLISH
4827c478bd9Sstevel@tonic-gate 		 *		refresh it if possible, else overwrite
4837c478bd9Sstevel@tonic-gate 		 *		with new TGT, other tickets in cache remain
4847c478bd9Sstevel@tonic-gate 		 *		unchanged.
4857c478bd9Sstevel@tonic-gate 		 *	else if flag == REFRESH
4867c478bd9Sstevel@tonic-gate 		 *		refresh it if possible, else return error.
4877c478bd9Sstevel@tonic-gate 		 *		- Will not work if "R" flag is not set in
4887c478bd9Sstevel@tonic-gate 		 *		original cred, we dont want to 2nd guess the
4897c478bd9Sstevel@tonic-gate 		 *		intention of the person who created the
4907c478bd9Sstevel@tonic-gate 		 *		existing TGT.
4917c478bd9Sstevel@tonic-gate 		 *
4927c478bd9Sstevel@tonic-gate 		 */
4937c478bd9Sstevel@tonic-gate 		krb5_cc_cursor	cursor;
4947c478bd9Sstevel@tonic-gate 		krb5_creds	nextcred;
4957c478bd9Sstevel@tonic-gate 		boolean_t	found = 0;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		if ((retval = krb5_cc_start_seq_get(kmd->kcontext,
4987c478bd9Sstevel@tonic-gate 				kmd->ccache, &cursor)) != 0)
4997c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		while ((krb5_cc_next_cred(kmd->kcontext, kmd->ccache,
5027c478bd9Sstevel@tonic-gate 					&cursor, &nextcred) == 0)) {
5037c478bd9Sstevel@tonic-gate 			/* if two creds match, we just update the first */
5047c478bd9Sstevel@tonic-gate 			if ((!found) && (creds_match(kmd->kcontext,
5057c478bd9Sstevel@tonic-gate 						&nextcred, &creds))) {
5067c478bd9Sstevel@tonic-gate 				/*
5077c478bd9Sstevel@tonic-gate 				 * Mark it as found, don't store it
5087c478bd9Sstevel@tonic-gate 				 * in the list or else it will be
5097c478bd9Sstevel@tonic-gate 				 * stored twice later.
5107c478bd9Sstevel@tonic-gate 				 */
5117c478bd9Sstevel@tonic-gate 				found = 1;
5127c478bd9Sstevel@tonic-gate 			} else {
5137c478bd9Sstevel@tonic-gate 				/*
5147c478bd9Sstevel@tonic-gate 				 * Add a new node to the list
5157c478bd9Sstevel@tonic-gate 				 * of creds that must be replaced
5167c478bd9Sstevel@tonic-gate 				 * in the cache later.
5177c478bd9Sstevel@tonic-gate 				 */
5187c478bd9Sstevel@tonic-gate 				cred_node *newnode = (cred_node *)malloc(
5197c478bd9Sstevel@tonic-gate 						sizeof (cred_node));
5207c478bd9Sstevel@tonic-gate 				if (newnode == NULL) {
5217c478bd9Sstevel@tonic-gate 					retval = ENOMEM;
5227c478bd9Sstevel@tonic-gate 					goto cleanup_creds;
5237c478bd9Sstevel@tonic-gate 				}
5247c478bd9Sstevel@tonic-gate 				newnode->creds = NULL;
5257c478bd9Sstevel@tonic-gate 				newnode->next = NULL;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 				if (cred_list_head == NULL) {
5287c478bd9Sstevel@tonic-gate 					cred_list_head = newnode;
5297c478bd9Sstevel@tonic-gate 					fetched = cred_list_head;
5307c478bd9Sstevel@tonic-gate 				} else {
5317c478bd9Sstevel@tonic-gate 					fetched->next = newnode;
5327c478bd9Sstevel@tonic-gate 					fetched = fetched->next;
5337c478bd9Sstevel@tonic-gate 				}
5347c478bd9Sstevel@tonic-gate 				retval = krb5_copy_creds(kmd->kcontext,
5357c478bd9Sstevel@tonic-gate 						&nextcred, &fetched->creds);
5367c478bd9Sstevel@tonic-gate 				if (retval)
5377c478bd9Sstevel@tonic-gate 					goto cleanup_creds;
5387c478bd9Sstevel@tonic-gate 			}
5397c478bd9Sstevel@tonic-gate 		}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 		if ((retval = krb5_cc_end_seq_get(kmd->kcontext,
5427c478bd9Sstevel@tonic-gate 					kmd->ccache, &cursor)) != 0)
5437c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		/*
5467c478bd9Sstevel@tonic-gate 		 * If we found a matching cred, renew it.
5477c478bd9Sstevel@tonic-gate 		 * This destroys the credential cache, if and only
5487c478bd9Sstevel@tonic-gate 		 * if it passes.
5497c478bd9Sstevel@tonic-gate 		 */
5507c478bd9Sstevel@tonic-gate 		if (found &&
5517c478bd9Sstevel@tonic-gate 		    (retval = krb5_get_credentials_renew(kmd->kcontext,
5521dac1dbeSgtb 				0, kmd->ccache, &creds, &renewed_cred))) {
5537c478bd9Sstevel@tonic-gate 			if (kmd->debug)
5543bfb48feSsemery 			    __pam_log(LOG_AUTH | LOG_DEBUG,
5557c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_get_credentials"
5567c478bd9Sstevel@tonic-gate 				"_renew(update) failed: %s",
5577c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
5587c478bd9Sstevel@tonic-gate 			/*
5597c478bd9Sstevel@tonic-gate 			 * If we only wanted to refresh the creds but failed
5607c478bd9Sstevel@tonic-gate 			 * due to expiration, lack of "R" flag, or other
5617c478bd9Sstevel@tonic-gate 			 * problems, return an error.  If we were trying to
5627c478bd9Sstevel@tonic-gate 			 * establish new creds, add them to the cache.
5637c478bd9Sstevel@tonic-gate 			 */
5647c478bd9Sstevel@tonic-gate 			if ((retval = krb5_cc_initialize(kmd->kcontext,
5657c478bd9Sstevel@tonic-gate 					kmd->ccache, me)) != 0) {
5667c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
5677c478bd9Sstevel@tonic-gate 			} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
5687c478bd9Sstevel@tonic-gate 					kmd->ccache, &my_creds)) != 0) {
5697c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
5707c478bd9Sstevel@tonic-gate 			}
5717c478bd9Sstevel@tonic-gate 		}
5727c478bd9Sstevel@tonic-gate 		/*
5737c478bd9Sstevel@tonic-gate 		 * If no matching creds were found, we must
5747c478bd9Sstevel@tonic-gate 		 * initialize the cache before we can store stuff
5757c478bd9Sstevel@tonic-gate 		 * in it.
5767c478bd9Sstevel@tonic-gate 		 */
5777c478bd9Sstevel@tonic-gate 		if (!found) {
5787c478bd9Sstevel@tonic-gate 			if ((retval = krb5_cc_initialize(kmd->kcontext,
5797c478bd9Sstevel@tonic-gate 					kmd->ccache, me)) != 0) {
5807c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
5817c478bd9Sstevel@tonic-gate 			}
5827c478bd9Sstevel@tonic-gate 		}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		/* now store all the other tickets */
5857c478bd9Sstevel@tonic-gate 		fetched = cred_list_head;
5867c478bd9Sstevel@tonic-gate 		while (fetched != NULL) {
5877c478bd9Sstevel@tonic-gate 			retval = krb5_cc_store_cred(kmd->kcontext,
5887c478bd9Sstevel@tonic-gate 					kmd->ccache, fetched->creds);
5897c478bd9Sstevel@tonic-gate 			fetched = fetched->next;
5907c478bd9Sstevel@tonic-gate 			if (retval) {
5917c478bd9Sstevel@tonic-gate 			    if (kmd->debug)
5923bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
5937c478bd9Sstevel@tonic-gate 				    "PAM-KRB5(setcred): krb5_cc_store_cred() "
5947c478bd9Sstevel@tonic-gate 				    "failed: %s",
5957c478bd9Sstevel@tonic-gate 				    error_message((errcode_t)retval));
5967c478bd9Sstevel@tonic-gate 			    goto cleanup_creds;
5977c478bd9Sstevel@tonic-gate 			}
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate cleanup_creds:
6027c478bd9Sstevel@tonic-gate 	/* Cleanup the list of creds read from the cache if necessary */
6037c478bd9Sstevel@tonic-gate 	fetched = cred_list_head;
6047c478bd9Sstevel@tonic-gate 	while (fetched != NULL) {
6057c478bd9Sstevel@tonic-gate 		cred_node *old = fetched;
6067c478bd9Sstevel@tonic-gate 		/* Free the contents and the cred structure itself */
6077c478bd9Sstevel@tonic-gate 		krb5_free_creds(kmd->kcontext, fetched->creds);
6087c478bd9Sstevel@tonic-gate 		fetched = fetched->next;
6097c478bd9Sstevel@tonic-gate 		free(old);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	if ((retval == 0) && (client_name != NULL)) {
6137c478bd9Sstevel@tonic-gate 		/*
6147c478bd9Sstevel@tonic-gate 		 * Credential update was successful!
6157c478bd9Sstevel@tonic-gate 		 *
6167c478bd9Sstevel@tonic-gate 		 * We now chown the ccache to the appropriate uid/gid
6177c478bd9Sstevel@tonic-gate 		 * combination, if its a FILE based ccache.
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		if (strstr(kmd->env, "FILE:")) {
6207c478bd9Sstevel@tonic-gate 			uid_t uuid;
6217c478bd9Sstevel@tonic-gate 			gid_t ugid;
6227c478bd9Sstevel@tonic-gate 			char *username = NULL, *tmpname = NULL;
6237c478bd9Sstevel@tonic-gate 			char *filepath = NULL;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 			username = strdup(client_name);
6267c478bd9Sstevel@tonic-gate 			if ((tmpname = strchr(username, '@')))
6277c478bd9Sstevel@tonic-gate 				*tmpname = '\0';
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 			if (get_pw_uid(username, &uuid) == 0 ||
6307c478bd9Sstevel@tonic-gate 			    get_pw_gid(username, &ugid) == 0) {
6313bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_ERR,
6323bfb48feSsemery 				    "PAM-KRB5 (setcred): Unable to "
6337c478bd9Sstevel@tonic-gate 				    "find matching uid/gid pair for user `%s'",
6347c478bd9Sstevel@tonic-gate 				    username);
6351dac1dbeSgtb 				retval = KRB5KRB_ERR_GENERIC;
6361dac1dbeSgtb 				goto error;
6377c478bd9Sstevel@tonic-gate 			}
6387c478bd9Sstevel@tonic-gate 			if (!(filepath = strchr(kmd->env, ':')) ||
6397c478bd9Sstevel@tonic-gate 			    !(filepath+1)) {
6403bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_ERR,
6417c478bd9Sstevel@tonic-gate 					"PAM-KRB5 (setcred): Invalid pathname "
6427c478bd9Sstevel@tonic-gate 					"for credential cache of user `%s'",
6437c478bd9Sstevel@tonic-gate 					username);
6441dac1dbeSgtb 				retval = KRB5KRB_ERR_GENERIC;
6451dac1dbeSgtb 				goto error;
6467c478bd9Sstevel@tonic-gate 			}
6477c478bd9Sstevel@tonic-gate 			if (chown(filepath+1, uuid, ugid)) {
6487c478bd9Sstevel@tonic-gate 				if (kmd->debug)
6493bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
6507c478bd9Sstevel@tonic-gate 					    "PAM-KRB5 (setcred): chown to user "
6517c478bd9Sstevel@tonic-gate 					    "`%s' failed for FILE=%s",
6527c478bd9Sstevel@tonic-gate 					    username, filepath);
6537c478bd9Sstevel@tonic-gate 			}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 			free(username);
6567c478bd9Sstevel@tonic-gate 		}
6571dac1dbeSgtb 	}
6587c478bd9Sstevel@tonic-gate 
6591dac1dbeSgtb error:
6601dac1dbeSgtb 	if (retval == 0) {
6611dac1dbeSgtb 		krb5_timestamp endtime;
6621dac1dbeSgtb 
6631dac1dbeSgtb 		if (renewed_cred && renewed_cred->times.endtime != 0)
6641dac1dbeSgtb 			endtime = renewed_cred->times.endtime;
6651dac1dbeSgtb 		else
6661dac1dbeSgtb 			endtime = my_creds.times.endtime;
6671dac1dbeSgtb 
6681dac1dbeSgtb 		if (kmd->debug)
6691dac1dbeSgtb 			__pam_log(LOG_AUTH | LOG_DEBUG,
6701dac1dbeSgtb 				"PAM-KRB5 (setcred): delete/add warning");
6711dac1dbeSgtb 
6721dac1dbeSgtb 		kwarn_del_warning(client_name);
6731dac1dbeSgtb 		if (kwarn_add_warning(client_name, endtime) != 0) {
6741dac1dbeSgtb 			__pam_log(LOG_AUTH | LOG_NOTICE,
6751dac1dbeSgtb 				"PAM-KRB5 (setcred): kwarn_add_warning"
6761dac1dbeSgtb 				" failed: ktkt_warnd(1M) down?");
6777c478bd9Sstevel@tonic-gate 		}
6787c478bd9Sstevel@tonic-gate 	}
6791dac1dbeSgtb 
6801dac1dbeSgtb 	if (renewed_cred != NULL)
6811dac1dbeSgtb 		krb5_free_creds(kmd->kcontext, renewed_cred);
6821dac1dbeSgtb 
6837c478bd9Sstevel@tonic-gate 	if (client_name != NULL)
6847c478bd9Sstevel@tonic-gate 		free(client_name);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &creds);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	return (retval);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate static krb5_boolean
6927c478bd9Sstevel@tonic-gate creds_match(krb5_context ctx, const krb5_creds *mcreds,
6937c478bd9Sstevel@tonic-gate 	const krb5_creds *creds)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate 	char *s1, *s2, *c1, *c2;
6967c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, mcreds->client, &c1);
6977c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, mcreds->server, &s1);
6987c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, creds->client, &c2);
6997c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, creds->server, &s2);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	return (krb5_principal_compare(ctx, mcreds->client, creds->client) &&
7027c478bd9Sstevel@tonic-gate 		krb5_principal_compare(ctx, mcreds->server, creds->server));
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate /*
7067c478bd9Sstevel@tonic-gate  * Delete the user's credentials for this session
7077c478bd9Sstevel@tonic-gate  */
7087c478bd9Sstevel@tonic-gate static int
7097c478bd9Sstevel@tonic-gate attempt_delete_initcred(krb5_module_data_t *kmd)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	if (kmd == NULL)
7123bfb48feSsemery 		return (PAM_SUCCESS);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	if (kmd->debug) {
7153bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
7167c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): deleting user's "
7177c478bd9Sstevel@tonic-gate 			"credentials (initcreds)");
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
7207c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
7217c478bd9Sstevel@tonic-gate 	kmd->auth_status = PAM_AUTHINFO_UNAVAIL;
7223bfb48feSsemery 	return (PAM_SUCCESS);
7237c478bd9Sstevel@tonic-gate }
724