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 /*
23488060a6SWill Fiveash  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
277c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
287c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <pwd.h>
357c478bd9Sstevel@tonic-gate #include <syslog.h>
367c478bd9Sstevel@tonic-gate #include <libintl.h>
377c478bd9Sstevel@tonic-gate #include <k5-int.h>
387c478bd9Sstevel@tonic-gate #include "profile/prof_int.h"
397c478bd9Sstevel@tonic-gate #include <netdb.h>
407c478bd9Sstevel@tonic-gate #include <ctype.h>
417c478bd9Sstevel@tonic-gate #include "utils.h"
427c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define	KRB5_DEFAULT_OPTIONS 0
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate int forwardable_flag = 0;
477c478bd9Sstevel@tonic-gate int renewable_flag = 0;
487c478bd9Sstevel@tonic-gate int proxiable_flag = 0;
497c478bd9Sstevel@tonic-gate int no_address_flag = 0;
507c478bd9Sstevel@tonic-gate profile_options_boolean config_option[] = {
517c478bd9Sstevel@tonic-gate 	{ "forwardable", &forwardable_flag, 0 },
527c478bd9Sstevel@tonic-gate 	{ "renewable",  &renewable_flag, 0 },
537c478bd9Sstevel@tonic-gate 	{ "proxiable", &proxiable_flag, 0 },
547c478bd9Sstevel@tonic-gate 	{ "no_addresses", &no_address_flag, 0 },
557c478bd9Sstevel@tonic-gate 	{ NULL, NULL, 0 }
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate char *renew_timeval;
587c478bd9Sstevel@tonic-gate char *life_timeval;
597c478bd9Sstevel@tonic-gate profile_option_strings config_times[] = {
607c478bd9Sstevel@tonic-gate 	{ "max_life", &life_timeval, 0 },
617c478bd9Sstevel@tonic-gate 	{ "max_renewable_life",  &renew_timeval, 0 },
627c478bd9Sstevel@tonic-gate 	{ NULL, NULL, 0 }
637c478bd9Sstevel@tonic-gate };
647c478bd9Sstevel@tonic-gate char *realmdef[] = { "realms", NULL, NULL, NULL };
657c478bd9Sstevel@tonic-gate char *appdef[] = { "appdefaults", "kinit", NULL };
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	krb_realm (*(realmdef + 1))
687c478bd9Sstevel@tonic-gate 
6970f41fc1SWill Fiveash int	attempt_krb5_auth(pam_handle_t *, krb5_module_data_t *, char *,
7070f41fc1SWill Fiveash 	char **, boolean_t);
717c478bd9Sstevel@tonic-gate void	krb5_cleanup(pam_handle_t *, void *, int);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_boolean();
747c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_string();
752278144aSsemery extern int krb5_verifypw(char *, char *, int);
767c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_verify_init_creds(krb5_context,
777c478bd9Sstevel@tonic-gate 		krb5_creds *, krb5_principal, krb5_keytab, krb5_ccache *,
787c478bd9Sstevel@tonic-gate 		krb5_verify_init_creds_opt *);
793125ebfcSsemery extern krb5_error_code __krb5_get_init_creds_password(krb5_context,
803125ebfcSsemery 		krb5_creds *, krb5_principal, char *, krb5_prompter_fct, void *,
813125ebfcSsemery 		krb5_deltat, char *, krb5_get_init_creds_opt *,
823125ebfcSsemery 		krb5_kdc_rep **);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * pam_sm_authenticate		- Authenticate user
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate int
887c478bd9Sstevel@tonic-gate pam_sm_authenticate(
897c478bd9Sstevel@tonic-gate 	pam_handle_t		*pamh,
907c478bd9Sstevel@tonic-gate 	int 			flags,
917c478bd9Sstevel@tonic-gate 	int			argc,
927c478bd9Sstevel@tonic-gate 	const char		**argv)
937c478bd9Sstevel@tonic-gate {
940be37caaSsemery 	char			*user = NULL;
957c478bd9Sstevel@tonic-gate 	int			err;
967c478bd9Sstevel@tonic-gate 	int			result = PAM_AUTH_ERR;
977c478bd9Sstevel@tonic-gate 	/* pam.conf options */
987c478bd9Sstevel@tonic-gate 	int			debug = 0;
997c478bd9Sstevel@tonic-gate 	int			warn = 1;
1007c478bd9Sstevel@tonic-gate 	/* return an error on password expire */
1017c478bd9Sstevel@tonic-gate 	int			err_on_exp = 0;
1027c478bd9Sstevel@tonic-gate 	int			i;
1037c478bd9Sstevel@tonic-gate 	char			*password = NULL;
1047c478bd9Sstevel@tonic-gate 	uid_t			pw_uid;
1057c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd = NULL;
1067c478bd9Sstevel@tonic-gate 	krb5_repository_data_t  *krb5_data = NULL;
1077c478bd9Sstevel@tonic-gate 	pam_repository_t	*rep_data = NULL;
10870f41fc1SWill Fiveash 	boolean_t		do_pkinit = FALSE;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
1117c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0) {
1127c478bd9Sstevel@tonic-gate 			debug = 1;
1137c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[i], "nowarn") == 0) {
1147c478bd9Sstevel@tonic-gate 			warn = 0;
1157c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[i], "err_on_exp") == 0) {
1167c478bd9Sstevel@tonic-gate 			err_on_exp = 1;
11770f41fc1SWill Fiveash 		} else if (strcmp(argv[i], "pkinit") == 0) {
11870f41fc1SWill Fiveash 			do_pkinit = TRUE;
1197c478bd9Sstevel@tonic-gate 		} else {
1203bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
12170f41fc1SWill Fiveash 			    "PAM-KRB5 (auth) unrecognized option %s", argv[i]);
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 	if (flags & PAM_SILENT) warn = 0;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (debug)
1273bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1287c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): pam_sm_authenticate flags=%d",
1297c478bd9Sstevel@tonic-gate 		    flags);
1307c478bd9Sstevel@tonic-gate 
13170f41fc1SWill Fiveash 	/*
13270f41fc1SWill Fiveash 	 * pam_get_data could fail if we are being called for the first time
13370f41fc1SWill Fiveash 	 * or if the module is not found, PAM_NO_MODULE_DATA is not an error
13470f41fc1SWill Fiveash 	 */
13570f41fc1SWill Fiveash 	err = pam_get_data(pamh, KRB5_DATA, (const void**)&kmd);
13670f41fc1SWill Fiveash 	if (!(err == PAM_SUCCESS || err == PAM_NO_MODULE_DATA))
13770f41fc1SWill Fiveash 		return (PAM_SYSTEM_ERR);
13870f41fc1SWill Fiveash 
13970f41fc1SWill Fiveash 	/*
14070f41fc1SWill Fiveash 	 * If pam_krb5 was stacked higher in the auth stack and did PKINIT
14170f41fc1SWill Fiveash 	 * preauth sucessfully then this instance is a fallback to password
14270f41fc1SWill Fiveash 	 * based preauth and should just return PAM_IGNORE.
14370f41fc1SWill Fiveash 	 *
14470f41fc1SWill Fiveash 	 * The else clause is handled further down.
14570f41fc1SWill Fiveash 	 */
14670f41fc1SWill Fiveash 	if (kmd != NULL) {
14770f41fc1SWill Fiveash 		if (++(kmd->auth_calls) > 2) {
14870f41fc1SWill Fiveash 			/*
14970f41fc1SWill Fiveash 			 * pam_krb5 has been stacked > 2 times in the auth
15070f41fc1SWill Fiveash 			 * stack.  Clear out the current kmd and proceed as if
15170f41fc1SWill Fiveash 			 * this is the first time pam_krb5 auth has been called.
15270f41fc1SWill Fiveash 			 */
15370f41fc1SWill Fiveash 			if (debug) {
15470f41fc1SWill Fiveash 				__pam_log(LOG_AUTH | LOG_DEBUG,
15570f41fc1SWill Fiveash 				    "PAM-KRB5 (auth): stacked more than"
15670f41fc1SWill Fiveash 				    " two times, clearing kmd");
15770f41fc1SWill Fiveash 			}
15870f41fc1SWill Fiveash 			/* clear out/free current kmd */
15970f41fc1SWill Fiveash 			err = pam_set_data(pamh, KRB5_DATA, NULL, NULL);
16070f41fc1SWill Fiveash 			if (err != PAM_SUCCESS) {
16170f41fc1SWill Fiveash 				krb5_cleanup(pamh, kmd, err);
16270f41fc1SWill Fiveash 				result = err;
16370f41fc1SWill Fiveash 				goto out;
16470f41fc1SWill Fiveash 			}
16570f41fc1SWill Fiveash 			kmd = NULL;
16670f41fc1SWill Fiveash 		} else if (kmd->auth_calls == 2 &&
16770f41fc1SWill Fiveash 		    kmd->auth_status == PAM_SUCCESS) {
16870f41fc1SWill Fiveash 			/*
16970f41fc1SWill Fiveash 			 * The previous instance of pam_krb5 succeeded and this
17070f41fc1SWill Fiveash 			 * instance was a fall back in case it didn't succeed so
17170f41fc1SWill Fiveash 			 * return ignore.
17270f41fc1SWill Fiveash 			 */
17370f41fc1SWill Fiveash 			if (debug) {
17470f41fc1SWill Fiveash 				__pam_log(LOG_AUTH | LOG_DEBUG,
17570f41fc1SWill Fiveash 				    "PAM-KRB5 (auth): PKINIT succeeded "
17670f41fc1SWill Fiveash 				    "earlier so returning PAM_IGNORE");
17770f41fc1SWill Fiveash 			}
17870f41fc1SWill Fiveash 			return (PAM_IGNORE);
17970f41fc1SWill Fiveash 		}
18070f41fc1SWill Fiveash 	}
18170f41fc1SWill Fiveash 
1820be37caaSsemery 	(void) pam_get_item(pamh, PAM_USER, (void**) &user);
1837c478bd9Sstevel@tonic-gate 
184a0e56b0eSsemery 	if (user == NULL || *user == '\0') {
18570f41fc1SWill Fiveash 		if (do_pkinit) {
18670f41fc1SWill Fiveash 			/*
18770f41fc1SWill Fiveash 			 * If doing PKINIT it is okay to prompt for the user
18870f41fc1SWill Fiveash 			 * name.
18970f41fc1SWill Fiveash 			 */
19070f41fc1SWill Fiveash 			if ((err = pam_get_user(pamh, &user, NULL)) !=
19170f41fc1SWill Fiveash 			    PAM_SUCCESS) {
19270f41fc1SWill Fiveash 				if (debug) {
19370f41fc1SWill Fiveash 					__pam_log(LOG_AUTH | LOG_DEBUG,
19470f41fc1SWill Fiveash 					    "PAM-KRB5 (auth): get user failed: "
19570f41fc1SWill Fiveash 					    "%s", pam_strerror(pamh, err));
19670f41fc1SWill Fiveash 				}
19770f41fc1SWill Fiveash 				return (err);
19870f41fc1SWill Fiveash 			}
19970f41fc1SWill Fiveash 		} else {
20070f41fc1SWill Fiveash 			if (debug)
20170f41fc1SWill Fiveash 				__pam_log(LOG_AUTH | LOG_DEBUG,
20270f41fc1SWill Fiveash 				    "PAM-KRB5 (auth): user empty or null");
20370f41fc1SWill Fiveash 			return (PAM_USER_UNKNOWN);
20470f41fc1SWill Fiveash 		}
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	/* make sure a password entry exists for this user */
2080be37caaSsemery 	if (!get_pw_uid(user, &pw_uid))
2090be37caaSsemery 		return (PAM_USER_UNKNOWN);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if (kmd == NULL) {
2127c478bd9Sstevel@tonic-gate 		kmd = calloc(1, sizeof (krb5_module_data_t));
2137c478bd9Sstevel@tonic-gate 		if (kmd == NULL) {
2147c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
2157c478bd9Sstevel@tonic-gate 			goto out;
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 		err = pam_set_data(pamh, KRB5_DATA, kmd, &krb5_cleanup);
2197c478bd9Sstevel@tonic-gate 		if (err != PAM_SUCCESS) {
2207c478bd9Sstevel@tonic-gate 			free(kmd);
2217c478bd9Sstevel@tonic-gate 			result = err;
2227c478bd9Sstevel@tonic-gate 			goto out;
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	if (!kmd->env) {
2277c478bd9Sstevel@tonic-gate 		char buffer[512];
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		if (snprintf(buffer, sizeof (buffer),
230b0c1f5b7SWill Fiveash 		    "%s=FILE:/tmp/krb5cc_%d",
231b0c1f5b7SWill Fiveash 		    KRB5_ENV_CCNAME, (int)pw_uid) >= sizeof (buffer)) {
2327c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
2337c478bd9Sstevel@tonic-gate 			goto out;
2347c478bd9Sstevel@tonic-gate 		}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		/* we MUST copy this to the heap for the putenv to work! */
2377c478bd9Sstevel@tonic-gate 		kmd->env = strdup(buffer);
2387c478bd9Sstevel@tonic-gate 		if (!kmd->env) {
2397c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
2407c478bd9Sstevel@tonic-gate 			goto out;
2417c478bd9Sstevel@tonic-gate 		} else {
2427c478bd9Sstevel@tonic-gate 			if (putenv(kmd->env)) {
2437c478bd9Sstevel@tonic-gate 				result = PAM_SYSTEM_ERR;
2447c478bd9Sstevel@tonic-gate 				goto out;
2457c478bd9Sstevel@tonic-gate 			}
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
24967c90040Ssemery 	if (kmd->user != NULL)
25067c90040Ssemery 		free(kmd->user);
2513bfb48feSsemery 	if ((kmd->user = strdup(user)) == NULL) {
2523bfb48feSsemery 		result = PAM_BUF_ERR;
2533bfb48feSsemery 		goto out;
2543bfb48feSsemery 	}
2553bfb48feSsemery 
2567c478bd9Sstevel@tonic-gate 	kmd->auth_status = PAM_AUTH_ERR;
2577c478bd9Sstevel@tonic-gate 	kmd->debug = debug;
2587c478bd9Sstevel@tonic-gate 	kmd->warn = warn;
2597c478bd9Sstevel@tonic-gate 	kmd->err_on_exp = err_on_exp;
2607c478bd9Sstevel@tonic-gate 	kmd->ccache = NULL;
2617c478bd9Sstevel@tonic-gate 	kmd->kcontext = NULL;
2627c478bd9Sstevel@tonic-gate 	kmd->password = NULL;
2637c478bd9Sstevel@tonic-gate 	kmd->age_status = PAM_SUCCESS;
2647c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
26570f41fc1SWill Fiveash 	kmd->auth_calls = 1;
26670f41fc1SWill Fiveash 	kmd->preauth_type = do_pkinit ? KRB_PKINIT : KRB_PASSWD;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	/*
2697c478bd9Sstevel@tonic-gate 	 * For apps that already did krb5 auth exchange...
2707c478bd9Sstevel@tonic-gate 	 * Now that we've created the kmd structure, we can
2717c478bd9Sstevel@tonic-gate 	 * return SUCCESS.  'kmd' may be needed later by other
2727c478bd9Sstevel@tonic-gate 	 * PAM functions, thats why we wait until this point to
2737c478bd9Sstevel@tonic-gate 	 * return.
2747c478bd9Sstevel@tonic-gate 	 */
2750be37caaSsemery 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
2787c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
2797c478bd9Sstevel@tonic-gate 			if (debug)
2803bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
281b0c1f5b7SWill Fiveash 				    "PAM-KRB5 (auth): wrong"
282b0c1f5b7SWill Fiveash 				    "repository found (%s), returning "
283b0c1f5b7SWill Fiveash 				    "PAM_IGNORE", rep_data->type);
2847c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
2877c478bd9Sstevel@tonic-gate 			krb5_data = (krb5_repository_data_t *)rep_data->scope;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 			if (krb5_data->flags ==
290b0c1f5b7SWill Fiveash 			    SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
291b0c1f5b7SWill Fiveash 			    krb5_data->principal != NULL &&
292b0c1f5b7SWill Fiveash 			    strlen(krb5_data->principal)) {
2937c478bd9Sstevel@tonic-gate 				if (debug)
2943bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
295b0c1f5b7SWill Fiveash 					    "PAM-KRB5 (auth): Principal "
296b0c1f5b7SWill Fiveash 					    "%s already authenticated",
297b0c1f5b7SWill Fiveash 					    krb5_data->principal);
2987c478bd9Sstevel@tonic-gate 				kmd->auth_status = PAM_SUCCESS;
2997c478bd9Sstevel@tonic-gate 				return (PAM_SUCCESS);
3007c478bd9Sstevel@tonic-gate 			}
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * if root key exists in the keytab, it's a random key so no
3067c478bd9Sstevel@tonic-gate 	 * need to prompt for pw and we just return IGNORE.
3077c478bd9Sstevel@tonic-gate 	 *
3087c478bd9Sstevel@tonic-gate 	 * note we don't need to force a prompt for pw as authtok_get
3097c478bd9Sstevel@tonic-gate 	 * is required to be stacked above this module.
3107c478bd9Sstevel@tonic-gate 	 */
3117c478bd9Sstevel@tonic-gate 	if ((strcmp(user, ROOT_UNAME) == 0) &&
3127c478bd9Sstevel@tonic-gate 	    key_in_keytab(user, debug)) {
3137c478bd9Sstevel@tonic-gate 		if (debug)
3143bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3157c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (auth): "
3167c478bd9Sstevel@tonic-gate 			    "key for '%s' in keytab, returning IGNORE", user);
3177c478bd9Sstevel@tonic-gate 		result = PAM_IGNORE;
3187c478bd9Sstevel@tonic-gate 		goto out;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3210be37caaSsemery 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&password);
3227c478bd9Sstevel@tonic-gate 
32370f41fc1SWill Fiveash 	result = attempt_krb5_auth(pamh, kmd, user, &password, 1);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate out:
3267c478bd9Sstevel@tonic-gate 	if (kmd) {
3277c478bd9Sstevel@tonic-gate 		if (debug)
3283bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3297c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (auth): pam_sm_auth finalize"
3307c478bd9Sstevel@tonic-gate 			    " ccname env, result =%d, env ='%s',"
3317c478bd9Sstevel@tonic-gate 			    " age = %d, status = %d",
3327c478bd9Sstevel@tonic-gate 			    result, kmd->env ? kmd->env : "<null>",
3337c478bd9Sstevel@tonic-gate 			    kmd->age_status, kmd->auth_status);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 		if (kmd->env &&
3367c478bd9Sstevel@tonic-gate 		    !(kmd->age_status == PAM_NEW_AUTHTOK_REQD &&
337b0c1f5b7SWill Fiveash 		    kmd->auth_status == PAM_SUCCESS)) {
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 			if (result == PAM_SUCCESS) {
3417c478bd9Sstevel@tonic-gate 				/*
3427c478bd9Sstevel@tonic-gate 				 * Put ccname into the pamh so that login
3437c478bd9Sstevel@tonic-gate 				 * apps can pick this up when they run
3447c478bd9Sstevel@tonic-gate 				 * pam_getenvlist().
3457c478bd9Sstevel@tonic-gate 				 */
3467c478bd9Sstevel@tonic-gate 				if ((result = pam_putenv(pamh, kmd->env))
3477c478bd9Sstevel@tonic-gate 				    != PAM_SUCCESS) {
3487c478bd9Sstevel@tonic-gate 					/* should not happen but... */
3493bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
3507c478bd9Sstevel@tonic-gate 					    "PAM-KRB5 (auth):"
3513bfb48feSsemery 					    " pam_putenv failed: result: %d",
3527c478bd9Sstevel@tonic-gate 					    result);
3537c478bd9Sstevel@tonic-gate 					goto cleanupccname;
3547c478bd9Sstevel@tonic-gate 				}
3557c478bd9Sstevel@tonic-gate 			} else {
3567c478bd9Sstevel@tonic-gate 			cleanupccname:
3577c478bd9Sstevel@tonic-gate 				/* for lack of a Solaris unputenv() */
3587c478bd9Sstevel@tonic-gate 				krb5_unsetenv(KRB5_ENV_CCNAME);
3597c478bd9Sstevel@tonic-gate 				free(kmd->env);
3607c478bd9Sstevel@tonic-gate 				kmd->env = NULL;
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate 		kmd->auth_status = result;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (debug)
3673bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3687c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): end: %s", pam_strerror(pamh, result));
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	return (result);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
37370f41fc1SWill Fiveash static krb5_error_code
37470f41fc1SWill Fiveash pam_krb5_prompter(
37570f41fc1SWill Fiveash 	krb5_context ctx,
37670f41fc1SWill Fiveash 	void *data,
37770f41fc1SWill Fiveash 	/* ARGSUSED1 */
37870f41fc1SWill Fiveash 	const char *name,
37970f41fc1SWill Fiveash 	const char *banner,
38070f41fc1SWill Fiveash 	int num_prompts,
38170f41fc1SWill Fiveash 	krb5_prompt prompts[])
38270f41fc1SWill Fiveash {
38370f41fc1SWill Fiveash 	krb5_error_code rc;
38470f41fc1SWill Fiveash 	pam_handle_t *pamh = (pam_handle_t *)data;
38570f41fc1SWill Fiveash 	struct pam_conv	*pam_convp;
38670f41fc1SWill Fiveash 	struct pam_message *msgs;
38770f41fc1SWill Fiveash 	struct pam_response *ret_respp;
38870f41fc1SWill Fiveash 	int i;
38970f41fc1SWill Fiveash 	krb5_prompt_type *prompt_type = krb5_get_prompt_types(ctx);
39070f41fc1SWill Fiveash 	char tmpbuf[PAM_MAX_MSG_SIZE];
39170f41fc1SWill Fiveash 
39270f41fc1SWill Fiveash 	/*
39370f41fc1SWill Fiveash 	 * Because this function should never be used for password prompts,
39470f41fc1SWill Fiveash 	 * disallow password prompts.
39570f41fc1SWill Fiveash 	 */
39670f41fc1SWill Fiveash 	for (i = 0; i < num_prompts; i++) {
397*a1219d13SWill Fiveash 		switch (prompt_type[i]) {
398*a1219d13SWill Fiveash 		case KRB5_PROMPT_TYPE_PASSWORD:
399*a1219d13SWill Fiveash 		case KRB5_PROMPT_TYPE_NEW_PASSWORD:
400*a1219d13SWill Fiveash 		case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN:
40170f41fc1SWill Fiveash 			return (KRB5_LIBOS_CANTREADPWD);
402*a1219d13SWill Fiveash 		}
40370f41fc1SWill Fiveash 	}
40470f41fc1SWill Fiveash 
40570f41fc1SWill Fiveash 	if (num_prompts == 0) {
40670f41fc1SWill Fiveash 		if (prompts) {
40770f41fc1SWill Fiveash 			/* This shouldn't happen */
40870f41fc1SWill Fiveash 			return (PAM_SYSTEM_ERR);
40970f41fc1SWill Fiveash 		} else {
41070f41fc1SWill Fiveash 			/* no prompts so return */
41170f41fc1SWill Fiveash 			return (0);
41270f41fc1SWill Fiveash 		}
41370f41fc1SWill Fiveash 	}
41470f41fc1SWill Fiveash 	if ((rc = pam_get_item(pamh, PAM_CONV, (void **)&pam_convp))
41570f41fc1SWill Fiveash 	    != PAM_SUCCESS) {
41670f41fc1SWill Fiveash 		return (rc);
41770f41fc1SWill Fiveash 	}
41870f41fc1SWill Fiveash 	if (pam_convp == NULL) {
41970f41fc1SWill Fiveash 		return (PAM_SYSTEM_ERR);
42070f41fc1SWill Fiveash 	}
42170f41fc1SWill Fiveash 
42270f41fc1SWill Fiveash 	msgs = (struct pam_message *)calloc(num_prompts,
42370f41fc1SWill Fiveash 	    sizeof (struct pam_message));
42470f41fc1SWill Fiveash 	if (msgs == NULL) {
42570f41fc1SWill Fiveash 		return (PAM_BUF_ERR);
42670f41fc1SWill Fiveash 	}
42770f41fc1SWill Fiveash 	(void) memset(msgs, 0, sizeof (struct pam_message) * num_prompts);
42870f41fc1SWill Fiveash 
42970f41fc1SWill Fiveash 	for (i = 0; i < num_prompts; i++) {
43070f41fc1SWill Fiveash 		/* convert krb prompt style to PAM style */
43170f41fc1SWill Fiveash 		if (prompts[i].hidden) {
43270f41fc1SWill Fiveash 			msgs[i].msg_style = PAM_PROMPT_ECHO_OFF;
43370f41fc1SWill Fiveash 		} else {
43470f41fc1SWill Fiveash 			msgs[i].msg_style = PAM_PROMPT_ECHO_ON;
43570f41fc1SWill Fiveash 		}
43670f41fc1SWill Fiveash 		/*
43770f41fc1SWill Fiveash 		 * krb expects the prompting function to append ": " to the
43870f41fc1SWill Fiveash 		 * prompt string.
43970f41fc1SWill Fiveash 		 */
44070f41fc1SWill Fiveash 		if (snprintf(tmpbuf, sizeof (tmpbuf), "%s: ",
44170f41fc1SWill Fiveash 		    prompts[i].prompt) < 0) {
44270f41fc1SWill Fiveash 			rc = PAM_BUF_ERR;
44370f41fc1SWill Fiveash 			goto cleanup;
44470f41fc1SWill Fiveash 		}
44570f41fc1SWill Fiveash 		msgs[i].msg = strdup(tmpbuf);
44670f41fc1SWill Fiveash 		if (msgs[i].msg == NULL) {
44770f41fc1SWill Fiveash 			rc = PAM_BUF_ERR;
44870f41fc1SWill Fiveash 			goto cleanup;
44970f41fc1SWill Fiveash 		}
45070f41fc1SWill Fiveash 	}
45170f41fc1SWill Fiveash 
45270f41fc1SWill Fiveash 	/*
45370f41fc1SWill Fiveash 	 * Call PAM conv function to display the prompt.
45470f41fc1SWill Fiveash 	 */
45570f41fc1SWill Fiveash 	rc = (pam_convp->conv)(num_prompts, &msgs, &ret_respp,
45670f41fc1SWill Fiveash 	    pam_convp->appdata_ptr);
45770f41fc1SWill Fiveash 
45870f41fc1SWill Fiveash 	if (rc == PAM_SUCCESS) {
45970f41fc1SWill Fiveash 		for (i = 0; i < num_prompts; i++) {
46070f41fc1SWill Fiveash 			/* convert PAM response to krb prompt reply format */
46170f41fc1SWill Fiveash 			prompts[i].reply->length = strlen(ret_respp[i].resp) +
46270f41fc1SWill Fiveash 			    1; /* adding 1 for NULL terminator */
46370f41fc1SWill Fiveash 			prompts[i].reply->data = ret_respp[i].resp;
46470f41fc1SWill Fiveash 		}
46570f41fc1SWill Fiveash 		/*
46670f41fc1SWill Fiveash 		 * Note, just free ret_respp, not the resp data since that is
46770f41fc1SWill Fiveash 		 * being referenced by the krb prompt reply data pointer.
46870f41fc1SWill Fiveash 		 */
46970f41fc1SWill Fiveash 		free(ret_respp);
47070f41fc1SWill Fiveash 	}
47170f41fc1SWill Fiveash 
47270f41fc1SWill Fiveash cleanup:
47370f41fc1SWill Fiveash 	for (i = 0; i < num_prompts; i++) {
47470f41fc1SWill Fiveash 		if (msgs[i].msg) {
47570f41fc1SWill Fiveash 			free(msgs[i].msg);
47670f41fc1SWill Fiveash 		}
47770f41fc1SWill Fiveash 	}
47870f41fc1SWill Fiveash 	free(msgs);
47970f41fc1SWill Fiveash 	return (rc);
48070f41fc1SWill Fiveash }
48170f41fc1SWill Fiveash 
4827c478bd9Sstevel@tonic-gate int
4837c478bd9Sstevel@tonic-gate attempt_krb5_auth(
48470f41fc1SWill Fiveash 	pam_handle_t *pamh,
4857c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd,
4867c478bd9Sstevel@tonic-gate 	char		*user,
4877c478bd9Sstevel@tonic-gate 	char		**krb5_pass,
4880be37caaSsemery 	boolean_t	verify_tik)
4897c478bd9Sstevel@tonic-gate {
49067c90040Ssemery 	krb5_principal	me = NULL, clientp = NULL;
49167c90040Ssemery 	krb5_principal	server = NULL, serverp = NULL;
4927c478bd9Sstevel@tonic-gate 	krb5_creds	*my_creds;
4937c478bd9Sstevel@tonic-gate 	krb5_timestamp	now;
4947c478bd9Sstevel@tonic-gate 	krb5_error_code	code = 0;
4957c478bd9Sstevel@tonic-gate 	char		kuser[2*MAXHOSTNAMELEN];
4967c478bd9Sstevel@tonic-gate 	krb5_deltat	lifetime;
4977c478bd9Sstevel@tonic-gate 	krb5_deltat	rlife;
4987c478bd9Sstevel@tonic-gate 	krb5_deltat	krb5_max_duration;
4997c478bd9Sstevel@tonic-gate 	int		options = KRB5_DEFAULT_OPTIONS;
5007c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
5017c478bd9Sstevel@tonic-gate 		0,
5027c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
5037c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
5047c478bd9Sstevel@tonic-gate 	};
505488060a6SWill Fiveash 	krb5_get_init_creds_opt *opts = NULL;
5063125ebfcSsemery 	krb5_kdc_rep *as_reply = NULL;
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * "result" should not be assigned PAM_SUCCESS unless
5097c478bd9Sstevel@tonic-gate 	 * authentication has succeeded and there are no other errors.
5107c478bd9Sstevel@tonic-gate 	 *
5117c478bd9Sstevel@tonic-gate 	 * "code" is sometimes used for PAM codes, sometimes for krb5
5127c478bd9Sstevel@tonic-gate 	 * codes.  Be careful.
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	int result = PAM_AUTH_ERR;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	if (kmd->debug)
5173bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
5187c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth: start: user='%s'",
5197c478bd9Sstevel@tonic-gate 		    user ? user : "<null>");
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/* need to free context with krb5_free_context */
5228ce3ffdfSPeter Shoults 	if (code = krb5_init_secure_context(&kmd->kcontext)) {
5233bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
524b0c1f5b7SWill Fiveash 		    "PAM-KRB5 (auth): Error initializing "
525b0c1f5b7SWill Fiveash 		    "krb5: %s",
526b0c1f5b7SWill Fiveash 		    error_message(code));
5277c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
531b0c1f5b7SWill Fiveash 	    2*MAXHOSTNAMELEN)) != 0) {
5327c478bd9Sstevel@tonic-gate 		/* get_kmd_kuser returns proper PAM error statuses */
5337c478bd9Sstevel@tonic-gate 		return (code);
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if ((code = krb5_parse_name(kmd->kcontext, kuser, &me)) != 0) {
5377c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
5387c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
5393bfb48feSsemery 		return (PAM_SYSTEM_ERR);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/* call krb5_free_cred_contents() on error */
5437c478bd9Sstevel@tonic-gate 	my_creds = &kmd->initcreds;
5447c478bd9Sstevel@tonic-gate 
5453bfb48feSsemery 	if ((code =
5463bfb48feSsemery 	    krb5_copy_principal(kmd->kcontext, me, &my_creds->client))) {
5473bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5483bfb48feSsemery 		goto out_err;
5493bfb48feSsemery 	}
55067c90040Ssemery 	clientp = my_creds->client;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	if (code = krb5_build_principal_ext(kmd->kcontext, &server,
553b0c1f5b7SWill Fiveash 	    krb5_princ_realm(kmd->kcontext, me)->length,
554b0c1f5b7SWill Fiveash 	    krb5_princ_realm(kmd->kcontext, me)->data,
555b0c1f5b7SWill Fiveash 	    tgtname.length, tgtname.data,
556b0c1f5b7SWill Fiveash 	    krb5_princ_realm(kmd->kcontext, me)->length,
557b0c1f5b7SWill Fiveash 	    krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
5583bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
559b0c1f5b7SWill Fiveash 		    "PAM-KRB5 (auth): attempt_krb5_auth: "
560b0c1f5b7SWill Fiveash 		    "krb5_build_princ_ext failed: %s",
561b0c1f5b7SWill Fiveash 		    error_message(code));
5623bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5637c478bd9Sstevel@tonic-gate 		goto out;
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if (code = krb5_copy_principal(kmd->kcontext, server,
567b0c1f5b7SWill Fiveash 	    &my_creds->server)) {
5683bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5697c478bd9Sstevel@tonic-gate 		goto out_err;
5707c478bd9Sstevel@tonic-gate 	}
57167c90040Ssemery 	serverp = my_creds->server;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (code = krb5_timeofday(kmd->kcontext, &now)) {
5743bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
575b0c1f5b7SWill Fiveash 		    "PAM-KRB5 (auth): attempt_krb5_auth: "
576b0c1f5b7SWill Fiveash 		    "krb5_timeofday failed: %s",
577b0c1f5b7SWill Fiveash 		    error_message(code));
5783bfb48feSsemery 		result = PAM_SYSTEM_ERR;
5797c478bd9Sstevel@tonic-gate 		goto out;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	/*
5837c478bd9Sstevel@tonic-gate 	 * set the values for lifetime and rlife to be the maximum
5847c478bd9Sstevel@tonic-gate 	 * possible
5857c478bd9Sstevel@tonic-gate 	 */
5867c478bd9Sstevel@tonic-gate 	krb5_max_duration = KRB5_KDB_EXPIRATION - now - 60*60;
5877c478bd9Sstevel@tonic-gate 	lifetime = krb5_max_duration;
5887c478bd9Sstevel@tonic-gate 	rlife = krb5_max_duration;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	/*
5917c478bd9Sstevel@tonic-gate 	 * Let us get the values for various options
5927c478bd9Sstevel@tonic-gate 	 * from Kerberos configuration file
5937c478bd9Sstevel@tonic-gate 	 */
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	krb_realm = krb5_princ_realm(kmd->kcontext, me)->data;
5967c478bd9Sstevel@tonic-gate 	profile_get_options_boolean(kmd->kcontext->profile,
597b0c1f5b7SWill Fiveash 	    realmdef, config_option);
5987c478bd9Sstevel@tonic-gate 	profile_get_options_boolean(kmd->kcontext->profile,
599b0c1f5b7SWill Fiveash 	    appdef, config_option);
6007c478bd9Sstevel@tonic-gate 	profile_get_options_string(kmd->kcontext->profile,
601b0c1f5b7SWill Fiveash 	    realmdef, config_times);
6027c478bd9Sstevel@tonic-gate 	profile_get_options_string(kmd->kcontext->profile,
603b0c1f5b7SWill Fiveash 	    appdef, config_times);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (renew_timeval) {
6067c478bd9Sstevel@tonic-gate 		code = krb5_string_to_deltat(renew_timeval, &rlife);
6077c478bd9Sstevel@tonic-gate 		if (code != 0 || rlife == 0 || rlife > krb5_max_duration) {
6083bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
609b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): Bad max_renewable_life "
610b0c1f5b7SWill Fiveash 			    " value '%s' in Kerberos config file",
6117c478bd9Sstevel@tonic-gate 			    renew_timeval);
6127c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
6137c478bd9Sstevel@tonic-gate 			goto out;
6147c478bd9Sstevel@tonic-gate 		}
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	if (life_timeval) {
6177c478bd9Sstevel@tonic-gate 		code = krb5_string_to_deltat(life_timeval, &lifetime);
6187c478bd9Sstevel@tonic-gate 		if (code != 0 || lifetime == 0 ||
6197c478bd9Sstevel@tonic-gate 		    lifetime > krb5_max_duration) {
6203bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
621b0c1f5b7SWill Fiveash 			    "lifetime value '%s' in Kerberos config file",
6227c478bd9Sstevel@tonic-gate 			    life_timeval);
6237c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
6247c478bd9Sstevel@tonic-gate 			goto out;
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 	/*  start timer when request gets to KDC */
6287c478bd9Sstevel@tonic-gate 	my_creds->times.starttime = 0;
6297c478bd9Sstevel@tonic-gate 	my_creds->times.endtime = now + lifetime;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (options & KDC_OPT_RENEWABLE) {
6327c478bd9Sstevel@tonic-gate 		my_creds->times.renew_till = now + rlife;
6337c478bd9Sstevel@tonic-gate 	} else
6347c478bd9Sstevel@tonic-gate 		my_creds->times.renew_till = 0;
6357c478bd9Sstevel@tonic-gate 
636488060a6SWill Fiveash 	code = krb5_get_init_creds_opt_alloc(kmd->kcontext, &opts);
637488060a6SWill Fiveash 	if (code != 0) {
638488060a6SWill Fiveash 		__pam_log(LOG_AUTH | LOG_ERR,
639488060a6SWill Fiveash 		    "Error allocating gic opts: %s",
640488060a6SWill Fiveash 		    error_message(code));
641488060a6SWill Fiveash 		result = PAM_SYSTEM_ERR;
642488060a6SWill Fiveash 		goto out;
643488060a6SWill Fiveash 	}
644488060a6SWill Fiveash 
645488060a6SWill Fiveash 	krb5_get_init_creds_opt_set_tkt_life(opts, lifetime);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (proxiable_flag) { 		/* Set in config file */
6487c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6493bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
650b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): Proxiable tickets "
651b0c1f5b7SWill Fiveash 			    "requested");
652488060a6SWill Fiveash 		krb5_get_init_creds_opt_set_proxiable(opts, TRUE);
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	if (forwardable_flag) {
6557c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6563bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
657b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): Forwardable tickets "
658b0c1f5b7SWill Fiveash 			    "requested");
659488060a6SWill Fiveash 		krb5_get_init_creds_opt_set_forwardable(opts, TRUE);
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 	if (renewable_flag) {
6627c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6633bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
664b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): Renewable tickets "
665b0c1f5b7SWill Fiveash 			    "requested");
666488060a6SWill Fiveash 		krb5_get_init_creds_opt_set_renew_life(opts, rlife);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 	if (no_address_flag) {
6697c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6703bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
671b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): Addressless tickets "
672b0c1f5b7SWill Fiveash 			    "requested");
673488060a6SWill Fiveash 		krb5_get_init_creds_opt_set_address_list(opts, NULL);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	/*
67770f41fc1SWill Fiveash 	 * mech_krb5 interprets empty passwords as NULL passwords and tries to
67870f41fc1SWill Fiveash 	 * read a password from stdin. Since we are in pam this is bad and
67970f41fc1SWill Fiveash 	 * should not be allowed.
68070f41fc1SWill Fiveash 	 *
68170f41fc1SWill Fiveash 	 * Note, the logic now is that if the preauth_type is PKINIT then
68270f41fc1SWill Fiveash 	 * provide a proper PAMcentric prompt function that the underlying
68370f41fc1SWill Fiveash 	 * PKINIT preauth plugin will use to prompt for the PIN.
6847c478bd9Sstevel@tonic-gate 	 */
68570f41fc1SWill Fiveash 	if (kmd->preauth_type == KRB_PKINIT) {
68670f41fc1SWill Fiveash 		/*
68770f41fc1SWill Fiveash 		 * Do PKINIT preauth
68870f41fc1SWill Fiveash 		 *
68970f41fc1SWill Fiveash 		 * Note: we want to limit preauth types to just those for PKINIT
69070f41fc1SWill Fiveash 		 * but krb5_get_init_creds() doesn't support that at this point.
69170f41fc1SWill Fiveash 		 * Instead we rely on pam_krb5_prompter() to limit prompts to
69270f41fc1SWill Fiveash 		 * non-password types.  So all we can do here is set the preauth
69370f41fc1SWill Fiveash 		 * list so krb5_get_init_creds() will try that first.
69470f41fc1SWill Fiveash 		 */
69570f41fc1SWill Fiveash 		krb5_preauthtype pk_pa_list[] = {
69670f41fc1SWill Fiveash 			KRB5_PADATA_PK_AS_REQ,
69770f41fc1SWill Fiveash 			KRB5_PADATA_PK_AS_REQ_OLD
69870f41fc1SWill Fiveash 		};
699488060a6SWill Fiveash 		krb5_get_init_creds_opt_set_preauth_list(opts, pk_pa_list, 2);
70070f41fc1SWill Fiveash 
701488060a6SWill Fiveash 		if (*krb5_pass == NULL || strlen(*krb5_pass) != 0) {
702488060a6SWill Fiveash 			if (*krb5_pass != NULL) {
703488060a6SWill Fiveash 				/* treat the krb5_pass as a PIN */
704488060a6SWill Fiveash 				code = krb5_get_init_creds_opt_set_pa(
705488060a6SWill Fiveash 				    kmd->kcontext, opts, "PIN", *krb5_pass);
706488060a6SWill Fiveash 			}
707488060a6SWill Fiveash 
708488060a6SWill Fiveash 			if (!code) {
709488060a6SWill Fiveash 				code = __krb5_get_init_creds_password(
710488060a6SWill Fiveash 				    kmd->kcontext,
711488060a6SWill Fiveash 				    my_creds,
712488060a6SWill Fiveash 				    me,
713488060a6SWill Fiveash 				    NULL, /* clear text passwd */
714488060a6SWill Fiveash 				    pam_krb5_prompter, /* prompter */
715488060a6SWill Fiveash 				    pamh, /* prompter data */
716488060a6SWill Fiveash 				    0, /* start time */
717488060a6SWill Fiveash 				    NULL, /* defaults to krbtgt@REALM */
718488060a6SWill Fiveash 				    opts,
719488060a6SWill Fiveash 				    &as_reply);
720488060a6SWill Fiveash 			}
72170f41fc1SWill Fiveash 		} else {
722488060a6SWill Fiveash 			/* invalid PIN */
72370f41fc1SWill Fiveash 			code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
72470f41fc1SWill Fiveash 		}
7257c478bd9Sstevel@tonic-gate 	} else {
7263125ebfcSsemery 		/*
72770f41fc1SWill Fiveash 		 * Do password based preauths
72870f41fc1SWill Fiveash 		 *
72970f41fc1SWill Fiveash 		 * See earlier PKINIT comment.  We are doing something similar
73070f41fc1SWill Fiveash 		 * here but we do not pass in a prompter (we assume
73170f41fc1SWill Fiveash 		 * pam_authtok_get has already prompted for that).
7323125ebfcSsemery 		 */
73370f41fc1SWill Fiveash 		if (*krb5_pass == NULL || strlen(*krb5_pass) == 0) {
73470f41fc1SWill Fiveash 			code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
73570f41fc1SWill Fiveash 		} else {
73670f41fc1SWill Fiveash 			krb5_preauthtype pk_pa_list[] = {
73770f41fc1SWill Fiveash 				KRB5_PADATA_ENC_TIMESTAMP
73870f41fc1SWill Fiveash 			};
73970f41fc1SWill Fiveash 
740488060a6SWill Fiveash 			krb5_get_init_creds_opt_set_preauth_list(opts,
74170f41fc1SWill Fiveash 			    pk_pa_list, 1);
74270f41fc1SWill Fiveash 
74370f41fc1SWill Fiveash 			/*
74470f41fc1SWill Fiveash 			 * We call our own private version of gic_pwd, because
74570f41fc1SWill Fiveash 			 * we need more information, such as password/account
74670f41fc1SWill Fiveash 			 * expiration, that is found in the as_reply.  The
74770f41fc1SWill Fiveash 			 * "prompter" interface is not granular enough for PAM
74870f41fc1SWill Fiveash 			 * to make use of.
74970f41fc1SWill Fiveash 			 */
75070f41fc1SWill Fiveash 			code = __krb5_get_init_creds_password(kmd->kcontext,
75170f41fc1SWill Fiveash 			    my_creds,
75270f41fc1SWill Fiveash 			    me,
75370f41fc1SWill Fiveash 			    *krb5_pass,	/* clear text passwd */
75470f41fc1SWill Fiveash 			    NULL,	/* prompter */
75570f41fc1SWill Fiveash 			    NULL,	/* data */
75670f41fc1SWill Fiveash 			    0,		/* start time */
75770f41fc1SWill Fiveash 			    NULL,	/* defaults to krbtgt@REALM */
758488060a6SWill Fiveash 			    opts,
75970f41fc1SWill Fiveash 			    &as_reply);
76070f41fc1SWill Fiveash 		}
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	if (kmd->debug)
7643bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
7657c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth: "
7667c478bd9Sstevel@tonic-gate 		    "krb5_get_init_creds_password returns: %s",
7677c478bd9Sstevel@tonic-gate 		    code == 0 ? "SUCCESS" : error_message(code));
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	switch (code) {
7707c478bd9Sstevel@tonic-gate 	case 0:
7717c478bd9Sstevel@tonic-gate 		/* got a tgt, let's verify it */
7727c478bd9Sstevel@tonic-gate 		if (verify_tik) {
7737c478bd9Sstevel@tonic-gate 			krb5_verify_init_creds_opt vopts;
7747c478bd9Sstevel@tonic-gate 
775a0709436Smp 			krb5_principal sp = NULL;
776a0709436Smp 			char kt_name[MAX_KEYTAB_NAME_LEN];
777a0709436Smp 			char *fqdn;
778a0709436Smp 
7797c478bd9Sstevel@tonic-gate 			krb5_verify_init_creds_opt_init(&vopts);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 			code = krb5_verify_init_creds(kmd->kcontext,
782b0c1f5b7SWill Fiveash 			    my_creds,
783b0c1f5b7SWill Fiveash 			    NULL,	/* defaults to host/localhost@REALM */
784b0c1f5b7SWill Fiveash 			    NULL,
785b0c1f5b7SWill Fiveash 			    NULL,
786b0c1f5b7SWill Fiveash 			    &vopts);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 			if (code) {
7897c478bd9Sstevel@tonic-gate 				result = PAM_SYSTEM_ERR;
7907c478bd9Sstevel@tonic-gate 
7910be37caaSsemery 				/*
7920be37caaSsemery 				 * Give a better error message when the
7930be37caaSsemery 				 * keytable entry isn't found or the keytab
7940be37caaSsemery 				 * file cannot be found.
7950be37caaSsemery 				 */
796a0709436Smp 				if (krb5_sname_to_principal(kmd->kcontext, NULL,
797b0c1f5b7SWill Fiveash 				    NULL, KRB5_NT_SRV_HST, &sp))
798a0709436Smp 					fqdn = "<fqdn>";
799a0709436Smp 				else
800a0709436Smp 					fqdn = sp->data[1].data;
801a0709436Smp 
802a0709436Smp 				if (krb5_kt_default_name(kmd->kcontext, kt_name,
803b0c1f5b7SWill Fiveash 				    sizeof (kt_name)))
804b0c1f5b7SWill Fiveash 					(void) strlcpy(kt_name,
805b0c1f5b7SWill Fiveash 					    "default keytab",
806b0c1f5b7SWill Fiveash 					    sizeof (kt_name));
807a0709436Smp 
808a0709436Smp 				switch (code) {
809a0709436Smp 				case KRB5_KT_NOTFOUND:
8103bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
811b0c1f5b7SWill Fiveash 					    "PAM-KRB5 (auth): "
812b0c1f5b7SWill Fiveash 					    "krb5_verify_init_creds failed:"
813b0c1f5b7SWill Fiveash 					    " Key table entry \"host/%s\""
814b0c1f5b7SWill Fiveash 					    " not found in %s",
815b0c1f5b7SWill Fiveash 					    fqdn, kt_name);
816a0709436Smp 					break;
817a0709436Smp 				case ENOENT:
8183bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
819b0c1f5b7SWill Fiveash 					    "PAM-KRB5 (auth): "
820b0c1f5b7SWill Fiveash 					    "krb5_verify_init_creds failed:"
821b0c1f5b7SWill Fiveash 					    " Keytab file \"%s\""
822b0c1f5b7SWill Fiveash 					    " does not exist.\n",
823b0c1f5b7SWill Fiveash 					    kt_name);
824a0709436Smp 					break;
825a0709436Smp 				default:
8263bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
827b0c1f5b7SWill Fiveash 					    "PAM-KRB5 (auth): "
828b0c1f5b7SWill Fiveash 					    "krb5_verify_init_creds failed:"
829b0c1f5b7SWill Fiveash 					    " %s",
830b0c1f5b7SWill Fiveash 					    error_message(code));
831a0709436Smp 					break;
832a0709436Smp 				}
833a0709436Smp 
834a0709436Smp 				if (sp)
835a0709436Smp 					krb5_free_principal(kmd->kcontext, sp);
8367c478bd9Sstevel@tonic-gate 			}
8377c478bd9Sstevel@tonic-gate 		}
8383125ebfcSsemery 
8393125ebfcSsemery 		if (code == 0)
8403125ebfcSsemery 			kmd->expiration = as_reply->enc_part2->key_exp;
8413125ebfcSsemery 
8427c478bd9Sstevel@tonic-gate 		break;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
8457c478bd9Sstevel@tonic-gate 		/*
8467c478bd9Sstevel@tonic-gate 		 * Since this principal is not part of the local
8477c478bd9Sstevel@tonic-gate 		 * Kerberos realm, we just return PAM_USER_UNKNOWN.
8487c478bd9Sstevel@tonic-gate 		 */
8497c478bd9Sstevel@tonic-gate 		result = PAM_USER_UNKNOWN;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 		if (kmd->debug)
8523bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
853b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): attempt_krb5_auth:"
854b0c1f5b7SWill Fiveash 			    " User is not part of the local Kerberos"
855b0c1f5b7SWill Fiveash 			    " realm: %s", error_message(code));
8567c478bd9Sstevel@tonic-gate 		break;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_PREAUTH_FAILED:
8597c478bd9Sstevel@tonic-gate 	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
8607c478bd9Sstevel@tonic-gate 		/*
8617c478bd9Sstevel@tonic-gate 		 * We could be trying the password from a previous
8627c478bd9Sstevel@tonic-gate 		 * pam authentication module, but we don't want to
8637c478bd9Sstevel@tonic-gate 		 * generate an error if the unix password is different
8647c478bd9Sstevel@tonic-gate 		 * than the Kerberos password...
8657c478bd9Sstevel@tonic-gate 		 */
8667c478bd9Sstevel@tonic-gate 		break;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_KEY_EXP:
8697c478bd9Sstevel@tonic-gate 		if (!kmd->err_on_exp) {
8707c478bd9Sstevel@tonic-gate 			/*
87170f41fc1SWill Fiveash 			 * Request a tik for changepw service and it will tell
87270f41fc1SWill Fiveash 			 * us if pw is good or not. If PKINIT is being done it
87370f41fc1SWill Fiveash 			 * is possible that *krb5_pass may be NULL so check for
87470f41fc1SWill Fiveash 			 * that.  If that is the case this function will return
87570f41fc1SWill Fiveash 			 * an error.
8767c478bd9Sstevel@tonic-gate 			 */
87770f41fc1SWill Fiveash 			if (*krb5_pass != NULL) {
87870f41fc1SWill Fiveash 				code = krb5_verifypw(kuser, *krb5_pass,
87970f41fc1SWill Fiveash 				    kmd->debug);
88070f41fc1SWill Fiveash 				if (kmd->debug) {
88170f41fc1SWill Fiveash 					__pam_log(LOG_AUTH | LOG_DEBUG,
88270f41fc1SWill Fiveash 					    "PAM-KRB5 (auth): "
88370f41fc1SWill Fiveash 					    "attempt_krb5_auth: "
88470f41fc1SWill Fiveash 					    "verifypw %d", code);
88570f41fc1SWill Fiveash 				}
88670f41fc1SWill Fiveash 				if (code == 0) {
88770f41fc1SWill Fiveash 					/*
88870f41fc1SWill Fiveash 					 * pw is good, set age status for
88970f41fc1SWill Fiveash 					 * acct_mgmt.
89070f41fc1SWill Fiveash 					 */
89170f41fc1SWill Fiveash 					kmd->age_status = PAM_NEW_AUTHTOK_REQD;
89270f41fc1SWill Fiveash 				}
8937c478bd9Sstevel@tonic-gate 			}
89470f41fc1SWill Fiveash 
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 		break;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	default:
8997c478bd9Sstevel@tonic-gate 		result = PAM_SYSTEM_ERR;
9007c478bd9Sstevel@tonic-gate 		if (kmd->debug)
9013bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
902b0c1f5b7SWill Fiveash 			    "PAM-KRB5 (auth): error %d - %s",
903b0c1f5b7SWill Fiveash 			    code, error_message(code));
9047c478bd9Sstevel@tonic-gate 		break;
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	if (code == 0) {
9087c478bd9Sstevel@tonic-gate 		/*
90970f41fc1SWill Fiveash 		 * success for the entered pw or PKINIT succeeded.
9107c478bd9Sstevel@tonic-gate 		 *
9117c478bd9Sstevel@tonic-gate 		 * we can't rely on the pw in PAM_AUTHTOK
9127c478bd9Sstevel@tonic-gate 		 * to be the (correct) krb5 one so
9137c478bd9Sstevel@tonic-gate 		 * store krb5 pw in module data for
91470f41fc1SWill Fiveash 		 * use in acct_mgmt.  Note that *krb5_pass may be NULL if we're
91570f41fc1SWill Fiveash 		 * doing PKINIT.
9167c478bd9Sstevel@tonic-gate 		 */
91770f41fc1SWill Fiveash 		if (*krb5_pass != NULL &&
91870f41fc1SWill Fiveash 		    !(kmd->password = strdup(*krb5_pass))) {
91970f41fc1SWill Fiveash 			__pam_log(LOG_AUTH | LOG_ERR,
920b0c1f5b7SWill Fiveash 			    "Cannot strdup password");
9217c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
9227c478bd9Sstevel@tonic-gate 			goto out_err;
9237c478bd9Sstevel@tonic-gate 		}
92470f41fc1SWill Fiveash 
9257c478bd9Sstevel@tonic-gate 		result = PAM_SUCCESS;
9267c478bd9Sstevel@tonic-gate 		goto out;
9277c478bd9Sstevel@tonic-gate 	}
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate out_err:
9307c478bd9Sstevel@tonic-gate 	/* jump (or reach) here if error and cred cache has been init */
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	if (kmd->debug)
9333bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
9347c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): clearing initcreds in "
9357c478bd9Sstevel@tonic-gate 		    "pam_authenticate()");
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
9387c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate out:
9417c478bd9Sstevel@tonic-gate 	if (server)
9427c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, server);
9437c478bd9Sstevel@tonic-gate 	if (me)
9447c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, me);
9453125ebfcSsemery 	if (as_reply)
9463125ebfcSsemery 		krb5_free_kdc_rep(kmd->kcontext, as_reply);
94767c90040Ssemery 
94867c90040Ssemery 	/*
94967c90040Ssemery 	 * clientp or serverp could be NULL in certain error cases in this
95067c90040Ssemery 	 * function.  mycreds->[client|server] could also be NULL in case
95167c90040Ssemery 	 * of error in this function, see out_err above.  The pointers clientp
95267c90040Ssemery 	 * and serverp reference the input argument in my_creds for
95367c90040Ssemery 	 * get_init_creds and must be freed if the input argument does not
95467c90040Ssemery 	 * match the output argument, which occurs during a successful call
95567c90040Ssemery 	 * to get_init_creds.
95667c90040Ssemery 	 */
95767c90040Ssemery 	if (clientp && my_creds->client && clientp != my_creds->client)
95867c90040Ssemery 		krb5_free_principal(kmd->kcontext, clientp);
95967c90040Ssemery 	if (serverp && my_creds->server && serverp != my_creds->server)
96067c90040Ssemery 		krb5_free_principal(kmd->kcontext, serverp);
96167c90040Ssemery 
9627c478bd9Sstevel@tonic-gate 	if (kmd->kcontext) {
9637c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
9647c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
9657c478bd9Sstevel@tonic-gate 	}
966488060a6SWill Fiveash 	if (opts)
967488060a6SWill Fiveash 		krb5_get_init_creds_opt_free(kmd->kcontext, opts);
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	if (kmd->debug)
9703bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
9717c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth returning %d",
9727c478bd9Sstevel@tonic-gate 		    result);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	return (kmd->auth_status = result);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9787c478bd9Sstevel@tonic-gate void
9797c478bd9Sstevel@tonic-gate krb5_cleanup(pam_handle_t *pamh, void *data, int pam_status)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd = (krb5_module_data_t *)data;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	if (kmd == NULL)
9847c478bd9Sstevel@tonic-gate 		return;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if (kmd->debug) {
9873bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
988b0c1f5b7SWill Fiveash 		    "PAM-KRB5 (auth): krb5_cleanup auth_status = %d",
9897c478bd9Sstevel@tonic-gate 		    kmd->auth_status);
9907c478bd9Sstevel@tonic-gate 	}
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	/*
99367c90040Ssemery 	 * Apps could be calling pam_end here, so we should always clean
99467c90040Ssemery 	 * up regardless of success or failure here.
9957c478bd9Sstevel@tonic-gate 	 */
99667c90040Ssemery 	if (kmd->ccache)
9975ad42b1bSSurya Prakki 		(void) krb5_cc_close(kmd->kcontext, kmd->ccache);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	if (kmd->password) {
10007c478bd9Sstevel@tonic-gate 		(void) memset(kmd->password, 0, strlen(kmd->password));
10017c478bd9Sstevel@tonic-gate 		free(kmd->password);
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
100467c90040Ssemery 	if (kmd->user)
10053bfb48feSsemery 		free(kmd->user);
10063bfb48feSsemery 
100767c90040Ssemery 	if (kmd->env)
100867c90040Ssemery 		free(kmd->env);
100967c90040Ssemery 
101067c90040Ssemery 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
101167c90040Ssemery 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	free(kmd);
10147c478bd9Sstevel@tonic-gate }
1015