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
5a0709436Smp  * Common Development and Distribution License (the "License").
6a0709436Smp  * 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  */
215ad42b1bSSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23*70f41fc1SWill Fiveash  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
287c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
297c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <pwd.h>
367c478bd9Sstevel@tonic-gate #include <syslog.h>
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <k5-int.h>
397c478bd9Sstevel@tonic-gate #include "profile/prof_int.h"
407c478bd9Sstevel@tonic-gate #include <netdb.h>
417c478bd9Sstevel@tonic-gate #include <ctype.h>
427c478bd9Sstevel@tonic-gate #include "utils.h"
437c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #define	KRB5_DEFAULT_OPTIONS 0
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate int forwardable_flag = 0;
487c478bd9Sstevel@tonic-gate int renewable_flag = 0;
497c478bd9Sstevel@tonic-gate int proxiable_flag = 0;
507c478bd9Sstevel@tonic-gate int no_address_flag = 0;
517c478bd9Sstevel@tonic-gate profile_options_boolean config_option[] = {
527c478bd9Sstevel@tonic-gate 	{ "forwardable", &forwardable_flag, 0 },
537c478bd9Sstevel@tonic-gate 	{ "renewable",  &renewable_flag, 0 },
547c478bd9Sstevel@tonic-gate 	{ "proxiable", &proxiable_flag, 0 },
557c478bd9Sstevel@tonic-gate 	{ "no_addresses", &no_address_flag, 0 },
567c478bd9Sstevel@tonic-gate 	{ NULL, NULL, 0 }
577c478bd9Sstevel@tonic-gate };
587c478bd9Sstevel@tonic-gate char *renew_timeval;
597c478bd9Sstevel@tonic-gate char *life_timeval;
607c478bd9Sstevel@tonic-gate profile_option_strings config_times[] = {
617c478bd9Sstevel@tonic-gate 	{ "max_life", &life_timeval, 0 },
627c478bd9Sstevel@tonic-gate 	{ "max_renewable_life",  &renew_timeval, 0 },
637c478bd9Sstevel@tonic-gate 	{ NULL, NULL, 0 }
647c478bd9Sstevel@tonic-gate };
657c478bd9Sstevel@tonic-gate char *realmdef[] = { "realms", NULL, NULL, NULL };
667c478bd9Sstevel@tonic-gate char *appdef[] = { "appdefaults", "kinit", NULL };
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	krb_realm (*(realmdef + 1))
697c478bd9Sstevel@tonic-gate 
70*70f41fc1SWill Fiveash int	attempt_krb5_auth(pam_handle_t *, krb5_module_data_t *, char *,
71*70f41fc1SWill Fiveash 	char **, boolean_t);
727c478bd9Sstevel@tonic-gate void	krb5_cleanup(pam_handle_t *, void *, int);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_boolean();
757c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_string();
762278144aSsemery extern int krb5_verifypw(char *, char *, int);
777c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_verify_init_creds(krb5_context,
787c478bd9Sstevel@tonic-gate 		krb5_creds *, krb5_principal, krb5_keytab, krb5_ccache *,
797c478bd9Sstevel@tonic-gate 		krb5_verify_init_creds_opt *);
803125ebfcSsemery extern krb5_error_code __krb5_get_init_creds_password(krb5_context,
813125ebfcSsemery 		krb5_creds *, krb5_principal, char *, krb5_prompter_fct, void *,
823125ebfcSsemery 		krb5_deltat, char *, krb5_get_init_creds_opt *,
833125ebfcSsemery 		krb5_kdc_rep **);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * pam_sm_authenticate		- Authenticate user
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate int
897c478bd9Sstevel@tonic-gate pam_sm_authenticate(
907c478bd9Sstevel@tonic-gate 	pam_handle_t		*pamh,
917c478bd9Sstevel@tonic-gate 	int 			flags,
927c478bd9Sstevel@tonic-gate 	int			argc,
937c478bd9Sstevel@tonic-gate 	const char		**argv)
947c478bd9Sstevel@tonic-gate {
950be37caaSsemery 	char			*user = NULL;
967c478bd9Sstevel@tonic-gate 	int			err;
977c478bd9Sstevel@tonic-gate 	int			result = PAM_AUTH_ERR;
987c478bd9Sstevel@tonic-gate 	/* pam.conf options */
997c478bd9Sstevel@tonic-gate 	int			debug = 0;
1007c478bd9Sstevel@tonic-gate 	int			warn = 1;
1017c478bd9Sstevel@tonic-gate 	/* return an error on password expire */
1027c478bd9Sstevel@tonic-gate 	int			err_on_exp = 0;
1037c478bd9Sstevel@tonic-gate 	int			i;
1047c478bd9Sstevel@tonic-gate 	char			*password = NULL;
1057c478bd9Sstevel@tonic-gate 	uid_t			pw_uid;
1067c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd = NULL;
1077c478bd9Sstevel@tonic-gate 	krb5_repository_data_t  *krb5_data = NULL;
1087c478bd9Sstevel@tonic-gate 	pam_repository_t	*rep_data = NULL;
109*70f41fc1SWill Fiveash 	boolean_t		do_pkinit = FALSE;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
1127c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0) {
1137c478bd9Sstevel@tonic-gate 			debug = 1;
1147c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[i], "nowarn") == 0) {
1157c478bd9Sstevel@tonic-gate 			warn = 0;
1167c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[i], "err_on_exp") == 0) {
1177c478bd9Sstevel@tonic-gate 			err_on_exp = 1;
118*70f41fc1SWill Fiveash 		} else if (strcmp(argv[i], "pkinit") == 0) {
119*70f41fc1SWill Fiveash 			do_pkinit = TRUE;
1207c478bd9Sstevel@tonic-gate 		} else {
1213bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
122*70f41fc1SWill Fiveash 			    "PAM-KRB5 (auth) unrecognized option %s", argv[i]);
1237c478bd9Sstevel@tonic-gate 		}
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 	if (flags & PAM_SILENT) warn = 0;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if (debug)
1283bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1297c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): pam_sm_authenticate flags=%d",
1307c478bd9Sstevel@tonic-gate 		    flags);
1317c478bd9Sstevel@tonic-gate 
132*70f41fc1SWill Fiveash 	/*
133*70f41fc1SWill Fiveash 	 * pam_get_data could fail if we are being called for the first time
134*70f41fc1SWill Fiveash 	 * or if the module is not found, PAM_NO_MODULE_DATA is not an error
135*70f41fc1SWill Fiveash 	 */
136*70f41fc1SWill Fiveash 	err = pam_get_data(pamh, KRB5_DATA, (const void**)&kmd);
137*70f41fc1SWill Fiveash 	if (!(err == PAM_SUCCESS || err == PAM_NO_MODULE_DATA))
138*70f41fc1SWill Fiveash 		return (PAM_SYSTEM_ERR);
139*70f41fc1SWill Fiveash 
140*70f41fc1SWill Fiveash 	/*
141*70f41fc1SWill Fiveash 	 * If pam_krb5 was stacked higher in the auth stack and did PKINIT
142*70f41fc1SWill Fiveash 	 * preauth sucessfully then this instance is a fallback to password
143*70f41fc1SWill Fiveash 	 * based preauth and should just return PAM_IGNORE.
144*70f41fc1SWill Fiveash 	 *
145*70f41fc1SWill Fiveash 	 * The else clause is handled further down.
146*70f41fc1SWill Fiveash 	 */
147*70f41fc1SWill Fiveash 	if (kmd != NULL) {
148*70f41fc1SWill Fiveash 		if (++(kmd->auth_calls) > 2) {
149*70f41fc1SWill Fiveash 			/*
150*70f41fc1SWill Fiveash 			 * pam_krb5 has been stacked > 2 times in the auth
151*70f41fc1SWill Fiveash 			 * stack.  Clear out the current kmd and proceed as if
152*70f41fc1SWill Fiveash 			 * this is the first time pam_krb5 auth has been called.
153*70f41fc1SWill Fiveash 			 */
154*70f41fc1SWill Fiveash 			if (debug) {
155*70f41fc1SWill Fiveash 				__pam_log(LOG_AUTH | LOG_DEBUG,
156*70f41fc1SWill Fiveash 				    "PAM-KRB5 (auth): stacked more than"
157*70f41fc1SWill Fiveash 				    " two times, clearing kmd");
158*70f41fc1SWill Fiveash 			}
159*70f41fc1SWill Fiveash 			/* clear out/free current kmd */
160*70f41fc1SWill Fiveash 			err = pam_set_data(pamh, KRB5_DATA, NULL, NULL);
161*70f41fc1SWill Fiveash 			if (err != PAM_SUCCESS) {
162*70f41fc1SWill Fiveash 				krb5_cleanup(pamh, kmd, err);
163*70f41fc1SWill Fiveash 				result = err;
164*70f41fc1SWill Fiveash 				goto out;
165*70f41fc1SWill Fiveash 			}
166*70f41fc1SWill Fiveash 			kmd = NULL;
167*70f41fc1SWill Fiveash 		} else if (kmd->auth_calls == 2 &&
168*70f41fc1SWill Fiveash 		    kmd->auth_status == PAM_SUCCESS) {
169*70f41fc1SWill Fiveash 			/*
170*70f41fc1SWill Fiveash 			 * The previous instance of pam_krb5 succeeded and this
171*70f41fc1SWill Fiveash 			 * instance was a fall back in case it didn't succeed so
172*70f41fc1SWill Fiveash 			 * return ignore.
173*70f41fc1SWill Fiveash 			 */
174*70f41fc1SWill Fiveash 			if (debug) {
175*70f41fc1SWill Fiveash 				__pam_log(LOG_AUTH | LOG_DEBUG,
176*70f41fc1SWill Fiveash 				    "PAM-KRB5 (auth): PKINIT succeeded "
177*70f41fc1SWill Fiveash 				    "earlier so returning PAM_IGNORE");
178*70f41fc1SWill Fiveash 			}
179*70f41fc1SWill Fiveash 			return (PAM_IGNORE);
180*70f41fc1SWill Fiveash 		}
181*70f41fc1SWill Fiveash 	}
182*70f41fc1SWill Fiveash 
1830be37caaSsemery 	(void) pam_get_item(pamh, PAM_USER, (void**) &user);
1847c478bd9Sstevel@tonic-gate 
185a0e56b0eSsemery 	if (user == NULL || *user == '\0') {
186*70f41fc1SWill Fiveash 		if (do_pkinit) {
187*70f41fc1SWill Fiveash 			/*
188*70f41fc1SWill Fiveash 			 * If doing PKINIT it is okay to prompt for the user
189*70f41fc1SWill Fiveash 			 * name.
190*70f41fc1SWill Fiveash 			 */
191*70f41fc1SWill Fiveash 			if ((err = pam_get_user(pamh, &user, NULL)) !=
192*70f41fc1SWill Fiveash 			    PAM_SUCCESS) {
193*70f41fc1SWill Fiveash 				if (debug) {
194*70f41fc1SWill Fiveash 					__pam_log(LOG_AUTH | LOG_DEBUG,
195*70f41fc1SWill Fiveash 					    "PAM-KRB5 (auth): get user failed: "
196*70f41fc1SWill Fiveash 					    "%s", pam_strerror(pamh, err));
197*70f41fc1SWill Fiveash 				}
198*70f41fc1SWill Fiveash 				return (err);
199*70f41fc1SWill Fiveash 			}
200*70f41fc1SWill Fiveash 		} else {
201*70f41fc1SWill Fiveash 			if (debug)
202*70f41fc1SWill Fiveash 				__pam_log(LOG_AUTH | LOG_DEBUG,
203*70f41fc1SWill Fiveash 				    "PAM-KRB5 (auth): user empty or null");
204*70f41fc1SWill Fiveash 			return (PAM_USER_UNKNOWN);
205*70f41fc1SWill Fiveash 		}
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* make sure a password entry exists for this user */
2090be37caaSsemery 	if (!get_pw_uid(user, &pw_uid))
2100be37caaSsemery 		return (PAM_USER_UNKNOWN);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (kmd == NULL) {
2137c478bd9Sstevel@tonic-gate 		kmd = calloc(1, sizeof (krb5_module_data_t));
2147c478bd9Sstevel@tonic-gate 		if (kmd == NULL) {
2157c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
2167c478bd9Sstevel@tonic-gate 			goto out;
2177c478bd9Sstevel@tonic-gate 		}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		err = pam_set_data(pamh, KRB5_DATA, kmd, &krb5_cleanup);
2207c478bd9Sstevel@tonic-gate 		if (err != PAM_SUCCESS) {
2217c478bd9Sstevel@tonic-gate 			free(kmd);
2227c478bd9Sstevel@tonic-gate 			result = err;
2237c478bd9Sstevel@tonic-gate 			goto out;
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (!kmd->env) {
2287c478bd9Sstevel@tonic-gate 		char buffer[512];
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		if (snprintf(buffer, sizeof (buffer),
2317c478bd9Sstevel@tonic-gate 			    "%s=FILE:/tmp/krb5cc_%d",
2327c478bd9Sstevel@tonic-gate 			    KRB5_ENV_CCNAME, (int)pw_uid) >= sizeof (buffer)) {
2337c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
2347c478bd9Sstevel@tonic-gate 			goto out;
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 		/* we MUST copy this to the heap for the putenv to work! */
2387c478bd9Sstevel@tonic-gate 		kmd->env = strdup(buffer);
2397c478bd9Sstevel@tonic-gate 		if (!kmd->env) {
2407c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
2417c478bd9Sstevel@tonic-gate 			goto out;
2427c478bd9Sstevel@tonic-gate 		} else {
2437c478bd9Sstevel@tonic-gate 			if (putenv(kmd->env)) {
2447c478bd9Sstevel@tonic-gate 				result = PAM_SYSTEM_ERR;
2457c478bd9Sstevel@tonic-gate 				goto out;
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
25067c90040Ssemery 	if (kmd->user != NULL)
25167c90040Ssemery 		free(kmd->user);
2523bfb48feSsemery 	if ((kmd->user = strdup(user)) == NULL) {
2533bfb48feSsemery 		result = PAM_BUF_ERR;
2543bfb48feSsemery 		goto out;
2553bfb48feSsemery 	}
2563bfb48feSsemery 
2577c478bd9Sstevel@tonic-gate 	kmd->auth_status = PAM_AUTH_ERR;
2587c478bd9Sstevel@tonic-gate 	kmd->debug = debug;
2597c478bd9Sstevel@tonic-gate 	kmd->warn = warn;
2607c478bd9Sstevel@tonic-gate 	kmd->err_on_exp = err_on_exp;
2617c478bd9Sstevel@tonic-gate 	kmd->ccache = NULL;
2627c478bd9Sstevel@tonic-gate 	kmd->kcontext = NULL;
2637c478bd9Sstevel@tonic-gate 	kmd->password = NULL;
2647c478bd9Sstevel@tonic-gate 	kmd->age_status = PAM_SUCCESS;
2657c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
266*70f41fc1SWill Fiveash 	kmd->auth_calls = 1;
267*70f41fc1SWill Fiveash 	kmd->preauth_type = do_pkinit ? KRB_PKINIT : KRB_PASSWD;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/*
2707c478bd9Sstevel@tonic-gate 	 * For apps that already did krb5 auth exchange...
2717c478bd9Sstevel@tonic-gate 	 * Now that we've created the kmd structure, we can
2727c478bd9Sstevel@tonic-gate 	 * return SUCCESS.  'kmd' may be needed later by other
2737c478bd9Sstevel@tonic-gate 	 * PAM functions, thats why we wait until this point to
2747c478bd9Sstevel@tonic-gate 	 * return.
2757c478bd9Sstevel@tonic-gate 	 */
2760be37caaSsemery 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
2797c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
2807c478bd9Sstevel@tonic-gate 			if (debug)
2813bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
2823bfb48feSsemery 					"PAM-KRB5 (auth): wrong"
2837c478bd9Sstevel@tonic-gate 					"repository found (%s), returning "
2847c478bd9Sstevel@tonic-gate 					"PAM_IGNORE", rep_data->type);
2857c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 		if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
2887c478bd9Sstevel@tonic-gate 			krb5_data = (krb5_repository_data_t *)rep_data->scope;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 			if (krb5_data->flags ==
2917c478bd9Sstevel@tonic-gate 				SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
2927c478bd9Sstevel@tonic-gate 				krb5_data->principal != NULL &&
2937c478bd9Sstevel@tonic-gate 				strlen(krb5_data->principal)) {
2947c478bd9Sstevel@tonic-gate 				if (debug)
2953bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
2967c478bd9Sstevel@tonic-gate 						"PAM-KRB5 (auth): Principal "
2977c478bd9Sstevel@tonic-gate 						"%s already authenticated",
2987c478bd9Sstevel@tonic-gate 						krb5_data->principal);
2997c478bd9Sstevel@tonic-gate 				kmd->auth_status = PAM_SUCCESS;
3007c478bd9Sstevel@tonic-gate 				return (PAM_SUCCESS);
3017c478bd9Sstevel@tonic-gate 			}
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	/*
3067c478bd9Sstevel@tonic-gate 	 * if root key exists in the keytab, it's a random key so no
3077c478bd9Sstevel@tonic-gate 	 * need to prompt for pw and we just return IGNORE.
3087c478bd9Sstevel@tonic-gate 	 *
3097c478bd9Sstevel@tonic-gate 	 * note we don't need to force a prompt for pw as authtok_get
3107c478bd9Sstevel@tonic-gate 	 * is required to be stacked above this module.
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	if ((strcmp(user, ROOT_UNAME) == 0) &&
3137c478bd9Sstevel@tonic-gate 	    key_in_keytab(user, debug)) {
3147c478bd9Sstevel@tonic-gate 		if (debug)
3153bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3167c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (auth): "
3177c478bd9Sstevel@tonic-gate 			    "key for '%s' in keytab, returning IGNORE", user);
3187c478bd9Sstevel@tonic-gate 		result = PAM_IGNORE;
3197c478bd9Sstevel@tonic-gate 		goto out;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3220be37caaSsemery 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&password);
3237c478bd9Sstevel@tonic-gate 
324*70f41fc1SWill Fiveash 	result = attempt_krb5_auth(pamh, kmd, user, &password, 1);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate out:
3277c478bd9Sstevel@tonic-gate 	if (kmd) {
3287c478bd9Sstevel@tonic-gate 		if (debug)
3293bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3307c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (auth): pam_sm_auth finalize"
3317c478bd9Sstevel@tonic-gate 			    " ccname env, result =%d, env ='%s',"
3327c478bd9Sstevel@tonic-gate 			    " age = %d, status = %d",
3337c478bd9Sstevel@tonic-gate 			    result, kmd->env ? kmd->env : "<null>",
3347c478bd9Sstevel@tonic-gate 			    kmd->age_status, kmd->auth_status);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 		if (kmd->env &&
3377c478bd9Sstevel@tonic-gate 		    !(kmd->age_status == PAM_NEW_AUTHTOK_REQD &&
3387c478bd9Sstevel@tonic-gate 			    kmd->auth_status == PAM_SUCCESS)) {
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 			if (result == PAM_SUCCESS) {
3427c478bd9Sstevel@tonic-gate 				/*
3437c478bd9Sstevel@tonic-gate 				 * Put ccname into the pamh so that login
3447c478bd9Sstevel@tonic-gate 				 * apps can pick this up when they run
3457c478bd9Sstevel@tonic-gate 				 * pam_getenvlist().
3467c478bd9Sstevel@tonic-gate 				 */
3477c478bd9Sstevel@tonic-gate 				if ((result = pam_putenv(pamh, kmd->env))
3487c478bd9Sstevel@tonic-gate 				    != PAM_SUCCESS) {
3497c478bd9Sstevel@tonic-gate 					/* should not happen but... */
3503bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
3517c478bd9Sstevel@tonic-gate 					    "PAM-KRB5 (auth):"
3523bfb48feSsemery 					    " pam_putenv failed: result: %d",
3537c478bd9Sstevel@tonic-gate 					    result);
3547c478bd9Sstevel@tonic-gate 					goto cleanupccname;
3557c478bd9Sstevel@tonic-gate 				}
3567c478bd9Sstevel@tonic-gate 			} else {
3577c478bd9Sstevel@tonic-gate 			cleanupccname:
3587c478bd9Sstevel@tonic-gate 				/* for lack of a Solaris unputenv() */
3597c478bd9Sstevel@tonic-gate 				krb5_unsetenv(KRB5_ENV_CCNAME);
3607c478bd9Sstevel@tonic-gate 				free(kmd->env);
3617c478bd9Sstevel@tonic-gate 				kmd->env = NULL;
3627c478bd9Sstevel@tonic-gate 			}
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 		kmd->auth_status = result;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	if (debug)
3683bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3697c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): end: %s", pam_strerror(pamh, result));
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	return (result);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
374*70f41fc1SWill Fiveash static krb5_error_code
375*70f41fc1SWill Fiveash pam_krb5_prompter(
376*70f41fc1SWill Fiveash 	krb5_context ctx,
377*70f41fc1SWill Fiveash 	void *data,
378*70f41fc1SWill Fiveash 	/* ARGSUSED1 */
379*70f41fc1SWill Fiveash 	const char *name,
380*70f41fc1SWill Fiveash 	const char *banner,
381*70f41fc1SWill Fiveash 	int num_prompts,
382*70f41fc1SWill Fiveash 	krb5_prompt prompts[])
383*70f41fc1SWill Fiveash {
384*70f41fc1SWill Fiveash 	krb5_error_code rc;
385*70f41fc1SWill Fiveash 	pam_handle_t *pamh = (pam_handle_t *)data;
386*70f41fc1SWill Fiveash 	struct pam_conv	*pam_convp;
387*70f41fc1SWill Fiveash 	struct pam_message *msgs;
388*70f41fc1SWill Fiveash 	struct pam_response *ret_respp;
389*70f41fc1SWill Fiveash 	int i;
390*70f41fc1SWill Fiveash 	krb5_prompt_type *prompt_type = krb5_get_prompt_types(ctx);
391*70f41fc1SWill Fiveash 	char tmpbuf[PAM_MAX_MSG_SIZE];
392*70f41fc1SWill Fiveash 
393*70f41fc1SWill Fiveash 	/*
394*70f41fc1SWill Fiveash 	 * Because this function should never be used for password prompts,
395*70f41fc1SWill Fiveash 	 * disallow password prompts.
396*70f41fc1SWill Fiveash 	 */
397*70f41fc1SWill Fiveash 	for (i = 0; i < num_prompts; i++) {
398*70f41fc1SWill Fiveash 		if (prompt_type[i] == KRB5_PROMPT_TYPE_PASSWORD)
399*70f41fc1SWill Fiveash 			return (KRB5_LIBOS_CANTREADPWD);
400*70f41fc1SWill Fiveash 	}
401*70f41fc1SWill Fiveash 
402*70f41fc1SWill Fiveash 	if (num_prompts == 0) {
403*70f41fc1SWill Fiveash 		if (prompts) {
404*70f41fc1SWill Fiveash 			/* This shouldn't happen */
405*70f41fc1SWill Fiveash 			return (PAM_SYSTEM_ERR);
406*70f41fc1SWill Fiveash 		} else {
407*70f41fc1SWill Fiveash 			/* no prompts so return */
408*70f41fc1SWill Fiveash 			return (0);
409*70f41fc1SWill Fiveash 		}
410*70f41fc1SWill Fiveash 	}
411*70f41fc1SWill Fiveash 	if ((rc = pam_get_item(pamh, PAM_CONV, (void **)&pam_convp))
412*70f41fc1SWill Fiveash 	    != PAM_SUCCESS) {
413*70f41fc1SWill Fiveash 		return (rc);
414*70f41fc1SWill Fiveash 	}
415*70f41fc1SWill Fiveash 	if (pam_convp == NULL) {
416*70f41fc1SWill Fiveash 		return (PAM_SYSTEM_ERR);
417*70f41fc1SWill Fiveash 	}
418*70f41fc1SWill Fiveash 
419*70f41fc1SWill Fiveash 	msgs = (struct pam_message *)calloc(num_prompts,
420*70f41fc1SWill Fiveash 	    sizeof (struct pam_message));
421*70f41fc1SWill Fiveash 	if (msgs == NULL) {
422*70f41fc1SWill Fiveash 		return (PAM_BUF_ERR);
423*70f41fc1SWill Fiveash 	}
424*70f41fc1SWill Fiveash 	(void) memset(msgs, 0, sizeof (struct pam_message) * num_prompts);
425*70f41fc1SWill Fiveash 
426*70f41fc1SWill Fiveash 	for (i = 0; i < num_prompts; i++) {
427*70f41fc1SWill Fiveash 		/* convert krb prompt style to PAM style */
428*70f41fc1SWill Fiveash 		if (prompts[i].hidden) {
429*70f41fc1SWill Fiveash 			msgs[i].msg_style = PAM_PROMPT_ECHO_OFF;
430*70f41fc1SWill Fiveash 		} else {
431*70f41fc1SWill Fiveash 			msgs[i].msg_style = PAM_PROMPT_ECHO_ON;
432*70f41fc1SWill Fiveash 		}
433*70f41fc1SWill Fiveash 		/*
434*70f41fc1SWill Fiveash 		 * krb expects the prompting function to append ": " to the
435*70f41fc1SWill Fiveash 		 * prompt string.
436*70f41fc1SWill Fiveash 		 */
437*70f41fc1SWill Fiveash 		if (snprintf(tmpbuf, sizeof (tmpbuf), "%s: ",
438*70f41fc1SWill Fiveash 		    prompts[i].prompt) < 0) {
439*70f41fc1SWill Fiveash 			rc = PAM_BUF_ERR;
440*70f41fc1SWill Fiveash 			goto cleanup;
441*70f41fc1SWill Fiveash 		}
442*70f41fc1SWill Fiveash 		msgs[i].msg = strdup(tmpbuf);
443*70f41fc1SWill Fiveash 		if (msgs[i].msg == NULL) {
444*70f41fc1SWill Fiveash 			rc = PAM_BUF_ERR;
445*70f41fc1SWill Fiveash 			goto cleanup;
446*70f41fc1SWill Fiveash 		}
447*70f41fc1SWill Fiveash 	}
448*70f41fc1SWill Fiveash 
449*70f41fc1SWill Fiveash 	/*
450*70f41fc1SWill Fiveash 	 * Call PAM conv function to display the prompt.
451*70f41fc1SWill Fiveash 	 */
452*70f41fc1SWill Fiveash 	rc = (pam_convp->conv)(num_prompts, &msgs, &ret_respp,
453*70f41fc1SWill Fiveash 	    pam_convp->appdata_ptr);
454*70f41fc1SWill Fiveash 
455*70f41fc1SWill Fiveash 	if (rc == PAM_SUCCESS) {
456*70f41fc1SWill Fiveash 		for (i = 0; i < num_prompts; i++) {
457*70f41fc1SWill Fiveash 			/* convert PAM response to krb prompt reply format */
458*70f41fc1SWill Fiveash 			prompts[i].reply->length = strlen(ret_respp[i].resp) +
459*70f41fc1SWill Fiveash 			    1; /* adding 1 for NULL terminator */
460*70f41fc1SWill Fiveash 			prompts[i].reply->data = ret_respp[i].resp;
461*70f41fc1SWill Fiveash 		}
462*70f41fc1SWill Fiveash 		/*
463*70f41fc1SWill Fiveash 		 * Note, just free ret_respp, not the resp data since that is
464*70f41fc1SWill Fiveash 		 * being referenced by the krb prompt reply data pointer.
465*70f41fc1SWill Fiveash 		 */
466*70f41fc1SWill Fiveash 		free(ret_respp);
467*70f41fc1SWill Fiveash 	}
468*70f41fc1SWill Fiveash 
469*70f41fc1SWill Fiveash cleanup:
470*70f41fc1SWill Fiveash 	for (i = 0; i < num_prompts; i++) {
471*70f41fc1SWill Fiveash 		if (msgs[i].msg) {
472*70f41fc1SWill Fiveash 			free(msgs[i].msg);
473*70f41fc1SWill Fiveash 		}
474*70f41fc1SWill Fiveash 	}
475*70f41fc1SWill Fiveash 	free(msgs);
476*70f41fc1SWill Fiveash 	return (rc);
477*70f41fc1SWill Fiveash }
478*70f41fc1SWill Fiveash 
4797c478bd9Sstevel@tonic-gate int
4807c478bd9Sstevel@tonic-gate attempt_krb5_auth(
481*70f41fc1SWill Fiveash 	pam_handle_t *pamh,
4827c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd,
4837c478bd9Sstevel@tonic-gate 	char		*user,
4847c478bd9Sstevel@tonic-gate 	char		**krb5_pass,
4850be37caaSsemery 	boolean_t	verify_tik)
4867c478bd9Sstevel@tonic-gate {
48767c90040Ssemery 	krb5_principal	me = NULL, clientp = NULL;
48867c90040Ssemery 	krb5_principal	server = NULL, serverp = NULL;
4897c478bd9Sstevel@tonic-gate 	krb5_creds	*my_creds;
4907c478bd9Sstevel@tonic-gate 	krb5_timestamp	now;
4917c478bd9Sstevel@tonic-gate 	krb5_error_code	code = 0;
4927c478bd9Sstevel@tonic-gate 	char		kuser[2*MAXHOSTNAMELEN];
4937c478bd9Sstevel@tonic-gate 	krb5_deltat	lifetime;
4947c478bd9Sstevel@tonic-gate 	krb5_deltat	rlife;
4957c478bd9Sstevel@tonic-gate 	krb5_deltat	krb5_max_duration;
4967c478bd9Sstevel@tonic-gate 	int		options = KRB5_DEFAULT_OPTIONS;
4977c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
4987c478bd9Sstevel@tonic-gate 		0,
4997c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
5007c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
5017c478bd9Sstevel@tonic-gate 	};
5027c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt opts;
5033125ebfcSsemery 	krb5_kdc_rep *as_reply = NULL;
5047c478bd9Sstevel@tonic-gate 	/*
5057c478bd9Sstevel@tonic-gate 	 * "result" should not be assigned PAM_SUCCESS unless
5067c478bd9Sstevel@tonic-gate 	 * authentication has succeeded and there are no other errors.
5077c478bd9Sstevel@tonic-gate 	 *
5087c478bd9Sstevel@tonic-gate 	 * "code" is sometimes used for PAM codes, sometimes for krb5
5097c478bd9Sstevel@tonic-gate 	 * codes.  Be careful.
5107c478bd9Sstevel@tonic-gate 	 */
5117c478bd9Sstevel@tonic-gate 	int result = PAM_AUTH_ERR;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (kmd->debug)
5143bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
5157c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth: start: user='%s'",
5167c478bd9Sstevel@tonic-gate 		    user ? user : "<null>");
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_init(&opts);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	/* need to free context with krb5_free_context */
5218ce3ffdfSPeter Shoults 	if (code = krb5_init_secure_context(&kmd->kcontext)) {
5223bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
5237c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (auth): Error initializing "
5243bfb48feSsemery 			"krb5: %s",
5257c478bd9Sstevel@tonic-gate 			error_message(code));
5267c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
5307c478bd9Sstevel@tonic-gate 		2*MAXHOSTNAMELEN)) != 0) {
5317c478bd9Sstevel@tonic-gate 		/* get_kmd_kuser returns proper PAM error statuses */
5327c478bd9Sstevel@tonic-gate 		return (code);
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if ((code = krb5_parse_name(kmd->kcontext, kuser, &me)) != 0) {
5367c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
5377c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
5383bfb48feSsemery 		return (PAM_SYSTEM_ERR);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/* call krb5_free_cred_contents() on error */
5427c478bd9Sstevel@tonic-gate 	my_creds = &kmd->initcreds;
5437c478bd9Sstevel@tonic-gate 
5443bfb48feSsemery 	if ((code =
5453bfb48feSsemery 	    krb5_copy_principal(kmd->kcontext, me, &my_creds->client))) {
5463bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5473bfb48feSsemery 		goto out_err;
5483bfb48feSsemery 	}
54967c90040Ssemery 	clientp = my_creds->client;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (code = krb5_build_principal_ext(kmd->kcontext, &server,
5527c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
5537c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data,
5547c478bd9Sstevel@tonic-gate 			    tgtname.length, tgtname.data,
5557c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
5567c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
5573bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
5583bfb48feSsemery 			"PAM-KRB5 (auth): attempt_krb5_auth: "
5593bfb48feSsemery 			"krb5_build_princ_ext failed: %s",
5603bfb48feSsemery 			error_message(code));
5613bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5627c478bd9Sstevel@tonic-gate 		goto out;
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	if (code = krb5_copy_principal(kmd->kcontext, server,
5667c478bd9Sstevel@tonic-gate 				&my_creds->server)) {
5673bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5687c478bd9Sstevel@tonic-gate 		goto out_err;
5697c478bd9Sstevel@tonic-gate 	}
57067c90040Ssemery 	serverp = my_creds->server;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (code = krb5_timeofday(kmd->kcontext, &now)) {
5733bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
5743bfb48feSsemery 			"PAM-KRB5 (auth): attempt_krb5_auth: "
5753bfb48feSsemery 			"krb5_timeofday failed: %s",
5763bfb48feSsemery 			error_message(code));
5773bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5787c478bd9Sstevel@tonic-gate 		goto out;
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	/*
5827c478bd9Sstevel@tonic-gate 	 * set the values for lifetime and rlife to be the maximum
5837c478bd9Sstevel@tonic-gate 	 * possible
5847c478bd9Sstevel@tonic-gate 	 */
5857c478bd9Sstevel@tonic-gate 	krb5_max_duration = KRB5_KDB_EXPIRATION - now - 60*60;
5867c478bd9Sstevel@tonic-gate 	lifetime = krb5_max_duration;
5877c478bd9Sstevel@tonic-gate 	rlife = krb5_max_duration;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/*
5907c478bd9Sstevel@tonic-gate 	 * Let us get the values for various options
5917c478bd9Sstevel@tonic-gate 	 * from Kerberos configuration file
5927c478bd9Sstevel@tonic-gate 	 */
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	krb_realm = krb5_princ_realm(kmd->kcontext, me)->data;
5957c478bd9Sstevel@tonic-gate 	profile_get_options_boolean(kmd->kcontext->profile,
5967c478bd9Sstevel@tonic-gate 				    realmdef, config_option);
5977c478bd9Sstevel@tonic-gate 	profile_get_options_boolean(kmd->kcontext->profile,
5987c478bd9Sstevel@tonic-gate 				    appdef, config_option);
5997c478bd9Sstevel@tonic-gate 	profile_get_options_string(kmd->kcontext->profile,
6007c478bd9Sstevel@tonic-gate 				realmdef, config_times);
6017c478bd9Sstevel@tonic-gate 	profile_get_options_string(kmd->kcontext->profile,
6027c478bd9Sstevel@tonic-gate 				appdef, config_times);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	if (renew_timeval) {
6057c478bd9Sstevel@tonic-gate 		code = krb5_string_to_deltat(renew_timeval, &rlife);
6067c478bd9Sstevel@tonic-gate 		if (code != 0 || rlife == 0 || rlife > krb5_max_duration) {
6073bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
6087c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (auth): Bad max_renewable_life "
6093bfb48feSsemery 				    " value '%s' in Kerberos config file",
6107c478bd9Sstevel@tonic-gate 			    renew_timeval);
6117c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
6127c478bd9Sstevel@tonic-gate 			goto out;
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 	if (life_timeval) {
6167c478bd9Sstevel@tonic-gate 		code = krb5_string_to_deltat(life_timeval, &lifetime);
6177c478bd9Sstevel@tonic-gate 		if (code != 0 || lifetime == 0 ||
6187c478bd9Sstevel@tonic-gate 		    lifetime > krb5_max_duration) {
6193bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
6203bfb48feSsemery 				"lifetime value '%s' in Kerberos config file",
6217c478bd9Sstevel@tonic-gate 			    life_timeval);
6227c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
6237c478bd9Sstevel@tonic-gate 			goto out;
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 	/*  start timer when request gets to KDC */
6277c478bd9Sstevel@tonic-gate 	my_creds->times.starttime = 0;
6287c478bd9Sstevel@tonic-gate 	my_creds->times.endtime = now + lifetime;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (options & KDC_OPT_RENEWABLE) {
6317c478bd9Sstevel@tonic-gate 		my_creds->times.renew_till = now + rlife;
6327c478bd9Sstevel@tonic-gate 	} else
6337c478bd9Sstevel@tonic-gate 		my_creds->times.renew_till = 0;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (proxiable_flag) { 		/* Set in config file */
6387c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6393bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
6407c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Proxiable tickets "
6413bfb48feSsemery 				"requested");
6427c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_proxiable(&opts, TRUE);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 	if (forwardable_flag) {
6457c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6463bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
6477c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Forwardable tickets "
6483bfb48feSsemery 				"requested");
6497c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_forwardable(&opts, TRUE);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	if (renewable_flag) {
6527c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6533bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
6547c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Renewable tickets "
6553bfb48feSsemery 				"requested");
6567c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 	if (no_address_flag) {
6597c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6603bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
6617c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Addressless tickets "
6623bfb48feSsemery 				"requested");
6637c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_address_list(&opts, NULL);
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	/*
667*70f41fc1SWill Fiveash 	 * mech_krb5 interprets empty passwords as NULL passwords and tries to
668*70f41fc1SWill Fiveash 	 * read a password from stdin. Since we are in pam this is bad and
669*70f41fc1SWill Fiveash 	 * should not be allowed.
670*70f41fc1SWill Fiveash 	 *
671*70f41fc1SWill Fiveash 	 * Note, the logic now is that if the preauth_type is PKINIT then
672*70f41fc1SWill Fiveash 	 * provide a proper PAMcentric prompt function that the underlying
673*70f41fc1SWill Fiveash 	 * PKINIT preauth plugin will use to prompt for the PIN.
6747c478bd9Sstevel@tonic-gate 	 */
675*70f41fc1SWill Fiveash 	if (kmd->preauth_type == KRB_PKINIT) {
676*70f41fc1SWill Fiveash 		/*
677*70f41fc1SWill Fiveash 		 * Do PKINIT preauth
678*70f41fc1SWill Fiveash 		 *
679*70f41fc1SWill Fiveash 		 * Note: we want to limit preauth types to just those for PKINIT
680*70f41fc1SWill Fiveash 		 * but krb5_get_init_creds() doesn't support that at this point.
681*70f41fc1SWill Fiveash 		 * Instead we rely on pam_krb5_prompter() to limit prompts to
682*70f41fc1SWill Fiveash 		 * non-password types.  So all we can do here is set the preauth
683*70f41fc1SWill Fiveash 		 * list so krb5_get_init_creds() will try that first.
684*70f41fc1SWill Fiveash 		 */
685*70f41fc1SWill Fiveash 		krb5_preauthtype pk_pa_list[] = {
686*70f41fc1SWill Fiveash 			KRB5_PADATA_PK_AS_REQ,
687*70f41fc1SWill Fiveash 			KRB5_PADATA_PK_AS_REQ_OLD
688*70f41fc1SWill Fiveash 		};
689*70f41fc1SWill Fiveash 		krb5_get_init_creds_opt_set_preauth_list(&opts, pk_pa_list, 2);
690*70f41fc1SWill Fiveash 
691*70f41fc1SWill Fiveash 		if (*krb5_pass == NULL) {
692*70f41fc1SWill Fiveash 			/* let preauth plugin prompt for PIN */
693*70f41fc1SWill Fiveash 			code = __krb5_get_init_creds_password(kmd->kcontext,
694*70f41fc1SWill Fiveash 			    my_creds,
695*70f41fc1SWill Fiveash 			    me,
696*70f41fc1SWill Fiveash 			    NULL, /* clear text passwd */
697*70f41fc1SWill Fiveash 			    pam_krb5_prompter, /* prompter */
698*70f41fc1SWill Fiveash 			    pamh, /* prompter data */
699*70f41fc1SWill Fiveash 			    0, /* start time */
700*70f41fc1SWill Fiveash 			    NULL, /* defaults to krbtgt@REALM */
701*70f41fc1SWill Fiveash 			    &opts,
702*70f41fc1SWill Fiveash 			    &as_reply);
703*70f41fc1SWill Fiveash 		} else {
704*70f41fc1SWill Fiveash 			/*
705*70f41fc1SWill Fiveash 			 * krb pkinit does not support setting the PIN so we
706*70f41fc1SWill Fiveash 			 * punt on trying to use krb5_pass as the PIN for now.
707*70f41fc1SWill Fiveash 			 * Note that once this is supported by pkinit the code
708*70f41fc1SWill Fiveash 			 * should make sure krb5_pass isn't empty and if it is
709*70f41fc1SWill Fiveash 			 * then that's an error.
710*70f41fc1SWill Fiveash 			 */
711*70f41fc1SWill Fiveash 			code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
712*70f41fc1SWill Fiveash 		}
7137c478bd9Sstevel@tonic-gate 	} else {
7143125ebfcSsemery 		/*
715*70f41fc1SWill Fiveash 		 * Do password based preauths
716*70f41fc1SWill Fiveash 		 *
717*70f41fc1SWill Fiveash 		 * See earlier PKINIT comment.  We are doing something similar
718*70f41fc1SWill Fiveash 		 * here but we do not pass in a prompter (we assume
719*70f41fc1SWill Fiveash 		 * pam_authtok_get has already prompted for that).
7203125ebfcSsemery 		 */
721*70f41fc1SWill Fiveash 		if (*krb5_pass == NULL || strlen(*krb5_pass) == 0) {
722*70f41fc1SWill Fiveash 			code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
723*70f41fc1SWill Fiveash 		} else {
724*70f41fc1SWill Fiveash 			krb5_preauthtype pk_pa_list[] = {
725*70f41fc1SWill Fiveash 				KRB5_PADATA_ENC_TIMESTAMP
726*70f41fc1SWill Fiveash 			};
727*70f41fc1SWill Fiveash 
728*70f41fc1SWill Fiveash 			krb5_get_init_creds_opt_set_preauth_list(&opts,
729*70f41fc1SWill Fiveash 			    pk_pa_list, 1);
730*70f41fc1SWill Fiveash 
731*70f41fc1SWill Fiveash 			/*
732*70f41fc1SWill Fiveash 			 * We call our own private version of gic_pwd, because
733*70f41fc1SWill Fiveash 			 * we need more information, such as password/account
734*70f41fc1SWill Fiveash 			 * expiration, that is found in the as_reply.  The
735*70f41fc1SWill Fiveash 			 * "prompter" interface is not granular enough for PAM
736*70f41fc1SWill Fiveash 			 * to make use of.
737*70f41fc1SWill Fiveash 			 */
738*70f41fc1SWill Fiveash 			code = __krb5_get_init_creds_password(kmd->kcontext,
739*70f41fc1SWill Fiveash 			    my_creds,
740*70f41fc1SWill Fiveash 			    me,
741*70f41fc1SWill Fiveash 			    *krb5_pass,	/* clear text passwd */
742*70f41fc1SWill Fiveash 			    NULL,	/* prompter */
743*70f41fc1SWill Fiveash 			    NULL,	/* data */
744*70f41fc1SWill Fiveash 			    0,		/* start time */
745*70f41fc1SWill Fiveash 			    NULL,	/* defaults to krbtgt@REALM */
746*70f41fc1SWill Fiveash 			    &opts,
747*70f41fc1SWill Fiveash 			    &as_reply);
748*70f41fc1SWill Fiveash 		}
7497c478bd9Sstevel@tonic-gate 	}
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	if (kmd->debug)
7523bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
7537c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth: "
7547c478bd9Sstevel@tonic-gate 		    "krb5_get_init_creds_password returns: %s",
7557c478bd9Sstevel@tonic-gate 		    code == 0 ? "SUCCESS" : error_message(code));
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	switch (code) {
7587c478bd9Sstevel@tonic-gate 	case 0:
7597c478bd9Sstevel@tonic-gate 		/* got a tgt, let's verify it */
7607c478bd9Sstevel@tonic-gate 		if (verify_tik) {
7617c478bd9Sstevel@tonic-gate 			krb5_verify_init_creds_opt vopts;
7627c478bd9Sstevel@tonic-gate 
763a0709436Smp 			krb5_principal sp = NULL;
764a0709436Smp 			char kt_name[MAX_KEYTAB_NAME_LEN];
765a0709436Smp 			char *fqdn;
766a0709436Smp 
7677c478bd9Sstevel@tonic-gate 			krb5_verify_init_creds_opt_init(&vopts);
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 			code = krb5_verify_init_creds(kmd->kcontext,
7707c478bd9Sstevel@tonic-gate 				my_creds,
7717c478bd9Sstevel@tonic-gate 				NULL,	/* defaults to host/localhost@REALM */
7727c478bd9Sstevel@tonic-gate 				NULL,
7737c478bd9Sstevel@tonic-gate 				NULL,
7747c478bd9Sstevel@tonic-gate 				&vopts);
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 			if (code) {
7777c478bd9Sstevel@tonic-gate 				result = PAM_SYSTEM_ERR;
7787c478bd9Sstevel@tonic-gate 
7790be37caaSsemery 				/*
7800be37caaSsemery 				 * Give a better error message when the
7810be37caaSsemery 				 * keytable entry isn't found or the keytab
7820be37caaSsemery 				 * file cannot be found.
7830be37caaSsemery 				 */
784a0709436Smp 				if (krb5_sname_to_principal(kmd->kcontext, NULL,
785a0709436Smp 						NULL, KRB5_NT_SRV_HST, &sp))
786a0709436Smp 					fqdn = "<fqdn>";
787a0709436Smp 				else
788a0709436Smp 					fqdn = sp->data[1].data;
789a0709436Smp 
790a0709436Smp 				if (krb5_kt_default_name(kmd->kcontext, kt_name,
791a0709436Smp 							sizeof (kt_name)))
792a0709436Smp 					(void) strncpy(kt_name,
793a0709436Smp 						"default keytab",
794a0709436Smp 						sizeof (kt_name));
795a0709436Smp 
796a0709436Smp 				switch (code) {
797a0709436Smp 				case KRB5_KT_NOTFOUND:
7983bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
799a0709436Smp 						"PAM-KRB5 (auth): "
800a0709436Smp 						"krb5_verify_init_creds failed:"
801a0709436Smp 						" Key table entry \"host/%s\""
8023bfb48feSsemery 						" not found in %s",
803a0709436Smp 						fqdn, kt_name);
804a0709436Smp 					break;
805a0709436Smp 				case ENOENT:
8063bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
807a0709436Smp 						"PAM-KRB5 (auth): "
808a0709436Smp 						"krb5_verify_init_creds failed:"
809a0709436Smp 						" Keytab file \"%s\""
8103bfb48feSsemery 						" does not exist.\n",
811a0709436Smp 						kt_name);
812a0709436Smp 					break;
813a0709436Smp 				default:
8143bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
815a0709436Smp 						"PAM-KRB5 (auth): "
816a0709436Smp 						"krb5_verify_init_creds failed:"
8173bfb48feSsemery 						" %s",
818a0709436Smp 						error_message(code));
819a0709436Smp 					break;
820a0709436Smp 				}
821a0709436Smp 
822a0709436Smp 				if (sp)
823a0709436Smp 					krb5_free_principal(kmd->kcontext, sp);
8247c478bd9Sstevel@tonic-gate 			}
8257c478bd9Sstevel@tonic-gate 		}
8263125ebfcSsemery 
8273125ebfcSsemery 		if (code == 0)
8283125ebfcSsemery 			kmd->expiration = as_reply->enc_part2->key_exp;
8293125ebfcSsemery 
8307c478bd9Sstevel@tonic-gate 		break;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
8337c478bd9Sstevel@tonic-gate 		/*
8347c478bd9Sstevel@tonic-gate 		 * Since this principal is not part of the local
8357c478bd9Sstevel@tonic-gate 		 * Kerberos realm, we just return PAM_USER_UNKNOWN.
8367c478bd9Sstevel@tonic-gate 		 */
8377c478bd9Sstevel@tonic-gate 		result = PAM_USER_UNKNOWN;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 		if (kmd->debug)
8403bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
8413bfb48feSsemery 				"PAM-KRB5 (auth): attempt_krb5_auth:"
8427c478bd9Sstevel@tonic-gate 				" User is not part of the local Kerberos"
8437c478bd9Sstevel@tonic-gate 				" realm: %s", error_message(code));
8447c478bd9Sstevel@tonic-gate 		break;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_PREAUTH_FAILED:
8477c478bd9Sstevel@tonic-gate 	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
8487c478bd9Sstevel@tonic-gate 		/*
8497c478bd9Sstevel@tonic-gate 		 * We could be trying the password from a previous
8507c478bd9Sstevel@tonic-gate 		 * pam authentication module, but we don't want to
8517c478bd9Sstevel@tonic-gate 		 * generate an error if the unix password is different
8527c478bd9Sstevel@tonic-gate 		 * than the Kerberos password...
8537c478bd9Sstevel@tonic-gate 		 */
8547c478bd9Sstevel@tonic-gate 		break;
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_KEY_EXP:
8577c478bd9Sstevel@tonic-gate 		if (!kmd->err_on_exp) {
8587c478bd9Sstevel@tonic-gate 			/*
859*70f41fc1SWill Fiveash 			 * Request a tik for changepw service and it will tell
860*70f41fc1SWill Fiveash 			 * us if pw is good or not. If PKINIT is being done it
861*70f41fc1SWill Fiveash 			 * is possible that *krb5_pass may be NULL so check for
862*70f41fc1SWill Fiveash 			 * that.  If that is the case this function will return
863*70f41fc1SWill Fiveash 			 * an error.
8647c478bd9Sstevel@tonic-gate 			 */
865*70f41fc1SWill Fiveash 			if (*krb5_pass != NULL) {
866*70f41fc1SWill Fiveash 				code = krb5_verifypw(kuser, *krb5_pass,
867*70f41fc1SWill Fiveash 				    kmd->debug);
868*70f41fc1SWill Fiveash 				if (kmd->debug) {
869*70f41fc1SWill Fiveash 					__pam_log(LOG_AUTH | LOG_DEBUG,
870*70f41fc1SWill Fiveash 					    "PAM-KRB5 (auth): "
871*70f41fc1SWill Fiveash 					    "attempt_krb5_auth: "
872*70f41fc1SWill Fiveash 					    "verifypw %d", code);
873*70f41fc1SWill Fiveash 				}
874*70f41fc1SWill Fiveash 				if (code == 0) {
875*70f41fc1SWill Fiveash 					/*
876*70f41fc1SWill Fiveash 					 * pw is good, set age status for
877*70f41fc1SWill Fiveash 					 * acct_mgmt.
878*70f41fc1SWill Fiveash 					 */
879*70f41fc1SWill Fiveash 					kmd->age_status = PAM_NEW_AUTHTOK_REQD;
880*70f41fc1SWill Fiveash 				}
8817c478bd9Sstevel@tonic-gate 			}
882*70f41fc1SWill Fiveash 
8837c478bd9Sstevel@tonic-gate 		}
8847c478bd9Sstevel@tonic-gate 		break;
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	default:
8877c478bd9Sstevel@tonic-gate 		result = PAM_SYSTEM_ERR;
8887c478bd9Sstevel@tonic-gate 		if (kmd->debug)
8893bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
8903bfb48feSsemery 				"PAM-KRB5 (auth): error %d - %s",
8917c478bd9Sstevel@tonic-gate 				code, error_message(code));
8927c478bd9Sstevel@tonic-gate 		break;
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	if (code == 0) {
8967c478bd9Sstevel@tonic-gate 		/*
897*70f41fc1SWill Fiveash 		 * success for the entered pw or PKINIT succeeded.
8987c478bd9Sstevel@tonic-gate 		 *
8997c478bd9Sstevel@tonic-gate 		 * we can't rely on the pw in PAM_AUTHTOK
9007c478bd9Sstevel@tonic-gate 		 * to be the (correct) krb5 one so
9017c478bd9Sstevel@tonic-gate 		 * store krb5 pw in module data for
902*70f41fc1SWill Fiveash 		 * use in acct_mgmt.  Note that *krb5_pass may be NULL if we're
903*70f41fc1SWill Fiveash 		 * doing PKINIT.
9047c478bd9Sstevel@tonic-gate 		 */
905*70f41fc1SWill Fiveash 		if (*krb5_pass != NULL &&
906*70f41fc1SWill Fiveash 		    !(kmd->password = strdup(*krb5_pass))) {
907*70f41fc1SWill Fiveash 			__pam_log(LOG_AUTH | LOG_ERR,
908*70f41fc1SWill Fiveash 				  "Cannot strdup password");
9097c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
9107c478bd9Sstevel@tonic-gate 			goto out_err;
9117c478bd9Sstevel@tonic-gate 		}
912*70f41fc1SWill Fiveash 
9137c478bd9Sstevel@tonic-gate 		result = PAM_SUCCESS;
9147c478bd9Sstevel@tonic-gate 		goto out;
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate out_err:
9187c478bd9Sstevel@tonic-gate 	/* jump (or reach) here if error and cred cache has been init */
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if (kmd->debug)
9213bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
9227c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): clearing initcreds in "
9237c478bd9Sstevel@tonic-gate 		    "pam_authenticate()");
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
9267c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate out:
9297c478bd9Sstevel@tonic-gate 	if (server)
9307c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, server);
9317c478bd9Sstevel@tonic-gate 	if (me)
9327c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, me);
9333125ebfcSsemery 	if (as_reply)
9343125ebfcSsemery 		krb5_free_kdc_rep(kmd->kcontext, as_reply);
93567c90040Ssemery 
93667c90040Ssemery 	/*
93767c90040Ssemery 	 * clientp or serverp could be NULL in certain error cases in this
93867c90040Ssemery 	 * function.  mycreds->[client|server] could also be NULL in case
93967c90040Ssemery 	 * of error in this function, see out_err above.  The pointers clientp
94067c90040Ssemery 	 * and serverp reference the input argument in my_creds for
94167c90040Ssemery 	 * get_init_creds and must be freed if the input argument does not
94267c90040Ssemery 	 * match the output argument, which occurs during a successful call
94367c90040Ssemery 	 * to get_init_creds.
94467c90040Ssemery 	 */
94567c90040Ssemery 	if (clientp && my_creds->client && clientp != my_creds->client)
94667c90040Ssemery 		krb5_free_principal(kmd->kcontext, clientp);
94767c90040Ssemery 	if (serverp && my_creds->server && serverp != my_creds->server)
94867c90040Ssemery 		krb5_free_principal(kmd->kcontext, serverp);
94967c90040Ssemery 
9507c478bd9Sstevel@tonic-gate 	if (kmd->kcontext) {
9517c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
9527c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	if (kmd->debug)
9563bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
9577c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth returning %d",
9587c478bd9Sstevel@tonic-gate 		    result);
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	return (kmd->auth_status = result);
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9647c478bd9Sstevel@tonic-gate void
9657c478bd9Sstevel@tonic-gate krb5_cleanup(pam_handle_t *pamh, void *data, int pam_status)
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd = (krb5_module_data_t *)data;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	if (kmd == NULL)
9707c478bd9Sstevel@tonic-gate 		return;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	if (kmd->debug) {
9733bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
9743bfb48feSsemery 			    "PAM-KRB5 (auth): krb5_cleanup auth_status = %d",
9757c478bd9Sstevel@tonic-gate 		    kmd->auth_status);
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	/*
97967c90040Ssemery 	 * Apps could be calling pam_end here, so we should always clean
98067c90040Ssemery 	 * up regardless of success or failure here.
9817c478bd9Sstevel@tonic-gate 	 */
98267c90040Ssemery 	if (kmd->ccache)
9835ad42b1bSSurya Prakki 		(void) krb5_cc_close(kmd->kcontext, kmd->ccache);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	if (kmd->password) {
9867c478bd9Sstevel@tonic-gate 		(void) memset(kmd->password, 0, strlen(kmd->password));
9877c478bd9Sstevel@tonic-gate 		free(kmd->password);
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 
99067c90040Ssemery 	if (kmd->user)
9913bfb48feSsemery 		free(kmd->user);
9923bfb48feSsemery 
99367c90040Ssemery 	if (kmd->env)
99467c90040Ssemery 		free(kmd->env);
99567c90040Ssemery 
99667c90040Ssemery 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
99767c90040Ssemery 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	free(kmd);
10007c478bd9Sstevel@tonic-gate }
1001