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  */
217c478bd9Sstevel@tonic-gate /*
223bfb48feSsemery  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
297c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
307c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <pwd.h>
377c478bd9Sstevel@tonic-gate #include <syslog.h>
387c478bd9Sstevel@tonic-gate #include <libintl.h>
397c478bd9Sstevel@tonic-gate #include <k5-int.h>
407c478bd9Sstevel@tonic-gate #include "profile/prof_int.h"
417c478bd9Sstevel@tonic-gate #include <netdb.h>
427c478bd9Sstevel@tonic-gate #include <ctype.h>
437c478bd9Sstevel@tonic-gate #include "utils.h"
447c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	KRB5_DEFAULT_OPTIONS 0
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate int forwardable_flag = 0;
497c478bd9Sstevel@tonic-gate int renewable_flag = 0;
507c478bd9Sstevel@tonic-gate int proxiable_flag = 0;
517c478bd9Sstevel@tonic-gate int no_address_flag = 0;
527c478bd9Sstevel@tonic-gate profile_options_boolean config_option[] = {
537c478bd9Sstevel@tonic-gate 	{ "forwardable", &forwardable_flag, 0 },
547c478bd9Sstevel@tonic-gate 	{ "renewable",  &renewable_flag, 0 },
557c478bd9Sstevel@tonic-gate 	{ "proxiable", &proxiable_flag, 0 },
567c478bd9Sstevel@tonic-gate 	{ "no_addresses", &no_address_flag, 0 },
577c478bd9Sstevel@tonic-gate 	{ NULL, NULL, 0 }
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate char *renew_timeval;
607c478bd9Sstevel@tonic-gate char *life_timeval;
617c478bd9Sstevel@tonic-gate profile_option_strings config_times[] = {
627c478bd9Sstevel@tonic-gate 	{ "max_life", &life_timeval, 0 },
637c478bd9Sstevel@tonic-gate 	{ "max_renewable_life",  &renew_timeval, 0 },
647c478bd9Sstevel@tonic-gate 	{ NULL, NULL, 0 }
657c478bd9Sstevel@tonic-gate };
667c478bd9Sstevel@tonic-gate char *realmdef[] = { "realms", NULL, NULL, NULL };
677c478bd9Sstevel@tonic-gate char *appdef[] = { "appdefaults", "kinit", NULL };
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	krb_realm (*(realmdef + 1))
707c478bd9Sstevel@tonic-gate 
712278144aSsemery int	attempt_krb5_auth(krb5_module_data_t *, char *, 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;
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;
1177c478bd9Sstevel@tonic-gate 		} else {
1183bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
1193bfb48feSsemery 				"PAM-KRB5 (auth) unrecognized option %s",
1207c478bd9Sstevel@tonic-gate 				argv[i]);
1217c478bd9Sstevel@tonic-gate 		}
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 	if (flags & PAM_SILENT) warn = 0;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (debug)
1263bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1277c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): pam_sm_authenticate flags=%d",
1287c478bd9Sstevel@tonic-gate 		    flags);
1297c478bd9Sstevel@tonic-gate 
1300be37caaSsemery 	(void) pam_get_item(pamh, PAM_USER, (void**) &user);
1317c478bd9Sstevel@tonic-gate 
132a0e56b0eSsemery 	if (user == NULL || *user == '\0') {
1337c478bd9Sstevel@tonic-gate 		if (debug)
1343bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1353bfb48feSsemery 				"PAM-KRB5 (auth): user empty or null");
136a0e56b0eSsemery 		return (PAM_USER_UNKNOWN);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/* make sure a password entry exists for this user */
1400be37caaSsemery 	if (!get_pw_uid(user, &pw_uid))
1410be37caaSsemery 		return (PAM_USER_UNKNOWN);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * pam_get_data could fail if we are being called for the first time
1457c478bd9Sstevel@tonic-gate 	 * or if the module is not found, PAM_NO_MODULE_DATA is not an error
1467c478bd9Sstevel@tonic-gate 	 */
1477c478bd9Sstevel@tonic-gate 	err = pam_get_data(pamh, KRB5_DATA, (const void**)&kmd);
1487c478bd9Sstevel@tonic-gate 	if (!(err == PAM_SUCCESS || err == PAM_NO_MODULE_DATA))
1493bfb48feSsemery 		return (PAM_SYSTEM_ERR);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if (kmd == NULL) {
1527c478bd9Sstevel@tonic-gate 		kmd = calloc(1, sizeof (krb5_module_data_t));
1537c478bd9Sstevel@tonic-gate 		if (kmd == NULL) {
1547c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
1557c478bd9Sstevel@tonic-gate 			goto out;
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		err = pam_set_data(pamh, KRB5_DATA, kmd, &krb5_cleanup);
1597c478bd9Sstevel@tonic-gate 		if (err != PAM_SUCCESS) {
1607c478bd9Sstevel@tonic-gate 			free(kmd);
1617c478bd9Sstevel@tonic-gate 			result = err;
1627c478bd9Sstevel@tonic-gate 			goto out;
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (!kmd->env) {
1677c478bd9Sstevel@tonic-gate 		char buffer[512];
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 		if (snprintf(buffer, sizeof (buffer),
1707c478bd9Sstevel@tonic-gate 			    "%s=FILE:/tmp/krb5cc_%d",
1717c478bd9Sstevel@tonic-gate 			    KRB5_ENV_CCNAME, (int)pw_uid) >= sizeof (buffer)) {
1727c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
1737c478bd9Sstevel@tonic-gate 			goto out;
1747c478bd9Sstevel@tonic-gate 		}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		/* we MUST copy this to the heap for the putenv to work! */
1777c478bd9Sstevel@tonic-gate 		kmd->env = strdup(buffer);
1787c478bd9Sstevel@tonic-gate 		if (!kmd->env) {
1797c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
1807c478bd9Sstevel@tonic-gate 			goto out;
1817c478bd9Sstevel@tonic-gate 		} else {
1827c478bd9Sstevel@tonic-gate 			if (putenv(kmd->env)) {
1837c478bd9Sstevel@tonic-gate 				result = PAM_SYSTEM_ERR;
1847c478bd9Sstevel@tonic-gate 				goto out;
1857c478bd9Sstevel@tonic-gate 			}
1867c478bd9Sstevel@tonic-gate 		}
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 
189*67c90040Ssemery 	if (kmd->user != NULL)
190*67c90040Ssemery 		free(kmd->user);
1913bfb48feSsemery 	if ((kmd->user = strdup(user)) == NULL) {
1923bfb48feSsemery 		result = PAM_BUF_ERR;
1933bfb48feSsemery 		goto out;
1943bfb48feSsemery 	}
1953bfb48feSsemery 
1967c478bd9Sstevel@tonic-gate 	kmd->auth_status = PAM_AUTH_ERR;
1977c478bd9Sstevel@tonic-gate 	kmd->debug = debug;
1987c478bd9Sstevel@tonic-gate 	kmd->warn = warn;
1997c478bd9Sstevel@tonic-gate 	kmd->err_on_exp = err_on_exp;
2007c478bd9Sstevel@tonic-gate 	kmd->ccache = NULL;
2017c478bd9Sstevel@tonic-gate 	kmd->kcontext = NULL;
2027c478bd9Sstevel@tonic-gate 	kmd->password = NULL;
2037c478bd9Sstevel@tonic-gate 	kmd->age_status = PAM_SUCCESS;
2047c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/*
2077c478bd9Sstevel@tonic-gate 	 * For apps that already did krb5 auth exchange...
2087c478bd9Sstevel@tonic-gate 	 * Now that we've created the kmd structure, we can
2097c478bd9Sstevel@tonic-gate 	 * return SUCCESS.  'kmd' may be needed later by other
2107c478bd9Sstevel@tonic-gate 	 * PAM functions, thats why we wait until this point to
2117c478bd9Sstevel@tonic-gate 	 * return.
2127c478bd9Sstevel@tonic-gate 	 */
2130be37caaSsemery 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
2167c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
2177c478bd9Sstevel@tonic-gate 			if (debug)
2183bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
2193bfb48feSsemery 					"PAM-KRB5 (auth): wrong"
2207c478bd9Sstevel@tonic-gate 					"repository found (%s), returning "
2217c478bd9Sstevel@tonic-gate 					"PAM_IGNORE", rep_data->type);
2227c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 		if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
2257c478bd9Sstevel@tonic-gate 			krb5_data = (krb5_repository_data_t *)rep_data->scope;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			if (krb5_data->flags ==
2287c478bd9Sstevel@tonic-gate 				SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
2297c478bd9Sstevel@tonic-gate 				krb5_data->principal != NULL &&
2307c478bd9Sstevel@tonic-gate 				strlen(krb5_data->principal)) {
2317c478bd9Sstevel@tonic-gate 				if (debug)
2323bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
2337c478bd9Sstevel@tonic-gate 						"PAM-KRB5 (auth): Principal "
2347c478bd9Sstevel@tonic-gate 						"%s already authenticated",
2357c478bd9Sstevel@tonic-gate 						krb5_data->principal);
2367c478bd9Sstevel@tonic-gate 				kmd->auth_status = PAM_SUCCESS;
2377c478bd9Sstevel@tonic-gate 				return (PAM_SUCCESS);
2387c478bd9Sstevel@tonic-gate 			}
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	/*
2437c478bd9Sstevel@tonic-gate 	 * if root key exists in the keytab, it's a random key so no
2447c478bd9Sstevel@tonic-gate 	 * need to prompt for pw and we just return IGNORE.
2457c478bd9Sstevel@tonic-gate 	 *
2467c478bd9Sstevel@tonic-gate 	 * note we don't need to force a prompt for pw as authtok_get
2477c478bd9Sstevel@tonic-gate 	 * is required to be stacked above this module.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if ((strcmp(user, ROOT_UNAME) == 0) &&
2507c478bd9Sstevel@tonic-gate 	    key_in_keytab(user, debug)) {
2517c478bd9Sstevel@tonic-gate 		if (debug)
2523bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
2537c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (auth): "
2547c478bd9Sstevel@tonic-gate 			    "key for '%s' in keytab, returning IGNORE", user);
2557c478bd9Sstevel@tonic-gate 		result = PAM_IGNORE;
2567c478bd9Sstevel@tonic-gate 		goto out;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2590be37caaSsemery 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&password);
2607c478bd9Sstevel@tonic-gate 
2612278144aSsemery 	result = attempt_krb5_auth(kmd, user, &password, 1);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate out:
2647c478bd9Sstevel@tonic-gate 	if (kmd) {
2657c478bd9Sstevel@tonic-gate 		if (debug)
2663bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
2677c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (auth): pam_sm_auth finalize"
2687c478bd9Sstevel@tonic-gate 			    " ccname env, result =%d, env ='%s',"
2697c478bd9Sstevel@tonic-gate 			    " age = %d, status = %d",
2707c478bd9Sstevel@tonic-gate 			    result, kmd->env ? kmd->env : "<null>",
2717c478bd9Sstevel@tonic-gate 			    kmd->age_status, kmd->auth_status);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		if (kmd->env &&
2747c478bd9Sstevel@tonic-gate 		    !(kmd->age_status == PAM_NEW_AUTHTOK_REQD &&
2757c478bd9Sstevel@tonic-gate 			    kmd->auth_status == PAM_SUCCESS)) {
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 			if (result == PAM_SUCCESS) {
2797c478bd9Sstevel@tonic-gate 				/*
2807c478bd9Sstevel@tonic-gate 				 * Put ccname into the pamh so that login
2817c478bd9Sstevel@tonic-gate 				 * apps can pick this up when they run
2827c478bd9Sstevel@tonic-gate 				 * pam_getenvlist().
2837c478bd9Sstevel@tonic-gate 				 */
2847c478bd9Sstevel@tonic-gate 				if ((result = pam_putenv(pamh, kmd->env))
2857c478bd9Sstevel@tonic-gate 				    != PAM_SUCCESS) {
2867c478bd9Sstevel@tonic-gate 					/* should not happen but... */
2873bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
2887c478bd9Sstevel@tonic-gate 					    "PAM-KRB5 (auth):"
2893bfb48feSsemery 					    " pam_putenv failed: result: %d",
2907c478bd9Sstevel@tonic-gate 					    result);
2917c478bd9Sstevel@tonic-gate 					goto cleanupccname;
2927c478bd9Sstevel@tonic-gate 				}
2937c478bd9Sstevel@tonic-gate 			} else {
2947c478bd9Sstevel@tonic-gate 			cleanupccname:
2957c478bd9Sstevel@tonic-gate 				/* for lack of a Solaris unputenv() */
2967c478bd9Sstevel@tonic-gate 				krb5_unsetenv(KRB5_ENV_CCNAME);
2977c478bd9Sstevel@tonic-gate 				free(kmd->env);
2987c478bd9Sstevel@tonic-gate 				kmd->env = NULL;
2997c478bd9Sstevel@tonic-gate 			}
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 		kmd->auth_status = result;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (debug)
3053bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3067c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): end: %s", pam_strerror(pamh, result));
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	return (result);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate int
3127c478bd9Sstevel@tonic-gate attempt_krb5_auth(
3137c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd,
3147c478bd9Sstevel@tonic-gate 	char		*user,
3157c478bd9Sstevel@tonic-gate 	char		**krb5_pass,
3160be37caaSsemery 	boolean_t	verify_tik)
3177c478bd9Sstevel@tonic-gate {
318*67c90040Ssemery 	krb5_principal	me = NULL, clientp = NULL;
319*67c90040Ssemery 	krb5_principal	server = NULL, serverp = NULL;
3207c478bd9Sstevel@tonic-gate 	krb5_creds	*my_creds;
3217c478bd9Sstevel@tonic-gate 	krb5_timestamp	now;
3227c478bd9Sstevel@tonic-gate 	krb5_error_code	code = 0;
3237c478bd9Sstevel@tonic-gate 	char		kuser[2*MAXHOSTNAMELEN];
3247c478bd9Sstevel@tonic-gate 	krb5_deltat	lifetime;
3257c478bd9Sstevel@tonic-gate 	krb5_deltat	rlife;
3267c478bd9Sstevel@tonic-gate 	krb5_deltat	krb5_max_duration;
3277c478bd9Sstevel@tonic-gate 	int		options = KRB5_DEFAULT_OPTIONS;
3287c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
3297c478bd9Sstevel@tonic-gate 		0,
3307c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
3317c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
3327c478bd9Sstevel@tonic-gate 	};
3337c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt opts;
3343125ebfcSsemery 	krb5_kdc_rep *as_reply = NULL;
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * "result" should not be assigned PAM_SUCCESS unless
3377c478bd9Sstevel@tonic-gate 	 * authentication has succeeded and there are no other errors.
3387c478bd9Sstevel@tonic-gate 	 *
3397c478bd9Sstevel@tonic-gate 	 * "code" is sometimes used for PAM codes, sometimes for krb5
3407c478bd9Sstevel@tonic-gate 	 * codes.  Be careful.
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	int result = PAM_AUTH_ERR;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	if (kmd->debug)
3453bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3467c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth: start: user='%s'",
3477c478bd9Sstevel@tonic-gate 		    user ? user : "<null>");
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_init(&opts);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/* need to free context with krb5_free_context */
3527c478bd9Sstevel@tonic-gate 	if (code = krb5_init_context(&kmd->kcontext)) {
3533bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
3547c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (auth): Error initializing "
3553bfb48feSsemery 			"krb5: %s",
3567c478bd9Sstevel@tonic-gate 			error_message(code));
3577c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
3617c478bd9Sstevel@tonic-gate 		2*MAXHOSTNAMELEN)) != 0) {
3627c478bd9Sstevel@tonic-gate 		/* get_kmd_kuser returns proper PAM error statuses */
3637c478bd9Sstevel@tonic-gate 		return (code);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if ((code = krb5_parse_name(kmd->kcontext, kuser, &me)) != 0) {
3677c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
3687c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
3693bfb48feSsemery 		return (PAM_SYSTEM_ERR);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	/* call krb5_free_cred_contents() on error */
3737c478bd9Sstevel@tonic-gate 	my_creds = &kmd->initcreds;
3747c478bd9Sstevel@tonic-gate 
3753bfb48feSsemery 	if ((code =
3763bfb48feSsemery 	    krb5_copy_principal(kmd->kcontext, me, &my_creds->client))) {
3773bfb48feSsemery 		result = PAM_SYSTEM_ERR;
3783bfb48feSsemery 		goto out_err;
3793bfb48feSsemery 	}
380*67c90040Ssemery 	clientp = my_creds->client;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (code = krb5_build_principal_ext(kmd->kcontext, &server,
3837c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
3847c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data,
3857c478bd9Sstevel@tonic-gate 			    tgtname.length, tgtname.data,
3867c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
3877c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
3883bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
3893bfb48feSsemery 			"PAM-KRB5 (auth): attempt_krb5_auth: "
3903bfb48feSsemery 			"krb5_build_princ_ext failed: %s",
3913bfb48feSsemery 			error_message(code));
3923bfb48feSsemery 		result = PAM_SYSTEM_ERR;
3937c478bd9Sstevel@tonic-gate 		goto out;
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (code = krb5_copy_principal(kmd->kcontext, server,
3977c478bd9Sstevel@tonic-gate 				&my_creds->server)) {
3983bfb48feSsemery 		result = PAM_SYSTEM_ERR;
3997c478bd9Sstevel@tonic-gate 		goto out_err;
4007c478bd9Sstevel@tonic-gate 	}
401*67c90040Ssemery 	serverp = my_creds->server;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if (code = krb5_timeofday(kmd->kcontext, &now)) {
4043bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
4053bfb48feSsemery 			"PAM-KRB5 (auth): attempt_krb5_auth: "
4063bfb48feSsemery 			"krb5_timeofday failed: %s",
4073bfb48feSsemery 			error_message(code));
4083bfb48feSsemery 		result = PAM_SYSTEM_ERR;
4097c478bd9Sstevel@tonic-gate 		goto out;
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/*
4137c478bd9Sstevel@tonic-gate 	 * set the values for lifetime and rlife to be the maximum
4147c478bd9Sstevel@tonic-gate 	 * possible
4157c478bd9Sstevel@tonic-gate 	 */
4167c478bd9Sstevel@tonic-gate 	krb5_max_duration = KRB5_KDB_EXPIRATION - now - 60*60;
4177c478bd9Sstevel@tonic-gate 	lifetime = krb5_max_duration;
4187c478bd9Sstevel@tonic-gate 	rlife = krb5_max_duration;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/*
4217c478bd9Sstevel@tonic-gate 	 * Let us get the values for various options
4227c478bd9Sstevel@tonic-gate 	 * from Kerberos configuration file
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	krb_realm = krb5_princ_realm(kmd->kcontext, me)->data;
4267c478bd9Sstevel@tonic-gate 	profile_get_options_boolean(kmd->kcontext->profile,
4277c478bd9Sstevel@tonic-gate 				    realmdef, config_option);
4287c478bd9Sstevel@tonic-gate 	profile_get_options_boolean(kmd->kcontext->profile,
4297c478bd9Sstevel@tonic-gate 				    appdef, config_option);
4307c478bd9Sstevel@tonic-gate 	profile_get_options_string(kmd->kcontext->profile,
4317c478bd9Sstevel@tonic-gate 				realmdef, config_times);
4327c478bd9Sstevel@tonic-gate 	profile_get_options_string(kmd->kcontext->profile,
4337c478bd9Sstevel@tonic-gate 				appdef, config_times);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (renew_timeval) {
4367c478bd9Sstevel@tonic-gate 		code = krb5_string_to_deltat(renew_timeval, &rlife);
4377c478bd9Sstevel@tonic-gate 		if (code != 0 || rlife == 0 || rlife > krb5_max_duration) {
4383bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
4397c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (auth): Bad max_renewable_life "
4403bfb48feSsemery 				    " value '%s' in Kerberos config file",
4417c478bd9Sstevel@tonic-gate 			    renew_timeval);
4427c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
4437c478bd9Sstevel@tonic-gate 			goto out;
4447c478bd9Sstevel@tonic-gate 		}
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 	if (life_timeval) {
4477c478bd9Sstevel@tonic-gate 		code = krb5_string_to_deltat(life_timeval, &lifetime);
4487c478bd9Sstevel@tonic-gate 		if (code != 0 || lifetime == 0 ||
4497c478bd9Sstevel@tonic-gate 		    lifetime > krb5_max_duration) {
4503bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
4513bfb48feSsemery 				"lifetime value '%s' in Kerberos config file",
4527c478bd9Sstevel@tonic-gate 			    life_timeval);
4537c478bd9Sstevel@tonic-gate 			result = PAM_SYSTEM_ERR;
4547c478bd9Sstevel@tonic-gate 			goto out;
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	/*  start timer when request gets to KDC */
4587c478bd9Sstevel@tonic-gate 	my_creds->times.starttime = 0;
4597c478bd9Sstevel@tonic-gate 	my_creds->times.endtime = now + lifetime;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	if (options & KDC_OPT_RENEWABLE) {
4627c478bd9Sstevel@tonic-gate 		my_creds->times.renew_till = now + rlife;
4637c478bd9Sstevel@tonic-gate 	} else
4647c478bd9Sstevel@tonic-gate 		my_creds->times.renew_till = 0;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	if (proxiable_flag) { 		/* Set in config file */
4697c478bd9Sstevel@tonic-gate 		if (kmd->debug)
4703bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4717c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Proxiable tickets "
4723bfb48feSsemery 				"requested");
4737c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_proxiable(&opts, TRUE);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	if (forwardable_flag) {
4767c478bd9Sstevel@tonic-gate 		if (kmd->debug)
4773bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4787c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Forwardable tickets "
4793bfb48feSsemery 				"requested");
4807c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_forwardable(&opts, TRUE);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 	if (renewable_flag) {
4837c478bd9Sstevel@tonic-gate 		if (kmd->debug)
4843bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4857c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Renewable tickets "
4863bfb48feSsemery 				"requested");
4877c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 	if (no_address_flag) {
4907c478bd9Sstevel@tonic-gate 		if (kmd->debug)
4913bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4927c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (auth): Addressless tickets "
4933bfb48feSsemery 				"requested");
4947c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_address_list(&opts, NULL);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * mech_krb5 interprets empty passwords as NULL passwords
4997c478bd9Sstevel@tonic-gate 	 * and tries to read a password from stdin. Since we are in
5007c478bd9Sstevel@tonic-gate 	 * pam this is bad and should not be allowed.
5017c478bd9Sstevel@tonic-gate 	 */
5027c478bd9Sstevel@tonic-gate 	if (*krb5_pass == NULL || strlen(*krb5_pass) == 0) {
5037c478bd9Sstevel@tonic-gate 		code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
5047c478bd9Sstevel@tonic-gate 	} else {
5053125ebfcSsemery 
5063125ebfcSsemery 		/*
5073125ebfcSsemery 		 * We call our own private version of gic_pwd, because we need
5083125ebfcSsemery 		 * more information, such as password/account expiration, that
5093125ebfcSsemery 		 * is found in the as_reply.  The "prompter" interface is not
5103125ebfcSsemery 		 * granular enough for PAM to make use of.
5113125ebfcSsemery 		 */
5123125ebfcSsemery 		code = __krb5_get_init_creds_password(kmd->kcontext,
5137c478bd9Sstevel@tonic-gate 				my_creds,
5147c478bd9Sstevel@tonic-gate 				me,
5157c478bd9Sstevel@tonic-gate 				*krb5_pass,	/* clear text passwd */
5167c478bd9Sstevel@tonic-gate 				NULL,		/* prompter */
5177c478bd9Sstevel@tonic-gate 				NULL,		/* data */
5187c478bd9Sstevel@tonic-gate 				0,		/* start time */
5197c478bd9Sstevel@tonic-gate 				NULL,		/* defaults to krbtgt@REALM */
5203125ebfcSsemery 				&opts,
5213125ebfcSsemery 				&as_reply);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (kmd->debug)
5253bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
5267c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth: "
5277c478bd9Sstevel@tonic-gate 		    "krb5_get_init_creds_password returns: %s",
5287c478bd9Sstevel@tonic-gate 		    code == 0 ? "SUCCESS" : error_message(code));
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	switch (code) {
5317c478bd9Sstevel@tonic-gate 	case 0:
5327c478bd9Sstevel@tonic-gate 		/* got a tgt, let's verify it */
5337c478bd9Sstevel@tonic-gate 		if (verify_tik) {
5347c478bd9Sstevel@tonic-gate 			krb5_verify_init_creds_opt vopts;
5357c478bd9Sstevel@tonic-gate 
536a0709436Smp 			krb5_principal sp = NULL;
537a0709436Smp 			char kt_name[MAX_KEYTAB_NAME_LEN];
538a0709436Smp 			char *fqdn;
539a0709436Smp 
5407c478bd9Sstevel@tonic-gate 			krb5_verify_init_creds_opt_init(&vopts);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 			code = krb5_verify_init_creds(kmd->kcontext,
5437c478bd9Sstevel@tonic-gate 				my_creds,
5447c478bd9Sstevel@tonic-gate 				NULL,	/* defaults to host/localhost@REALM */
5457c478bd9Sstevel@tonic-gate 				NULL,
5467c478bd9Sstevel@tonic-gate 				NULL,
5477c478bd9Sstevel@tonic-gate 				&vopts);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 			if (code) {
5507c478bd9Sstevel@tonic-gate 				result = PAM_SYSTEM_ERR;
5517c478bd9Sstevel@tonic-gate 
5520be37caaSsemery 				/*
5530be37caaSsemery 				 * Give a better error message when the
5540be37caaSsemery 				 * keytable entry isn't found or the keytab
5550be37caaSsemery 				 * file cannot be found.
5560be37caaSsemery 				 */
557a0709436Smp 				if (krb5_sname_to_principal(kmd->kcontext, NULL,
558a0709436Smp 						NULL, KRB5_NT_SRV_HST, &sp))
559a0709436Smp 					fqdn = "<fqdn>";
560a0709436Smp 				else
561a0709436Smp 					fqdn = sp->data[1].data;
562a0709436Smp 
563a0709436Smp 				if (krb5_kt_default_name(kmd->kcontext, kt_name,
564a0709436Smp 							sizeof (kt_name)))
565a0709436Smp 					(void) strncpy(kt_name,
566a0709436Smp 						"default keytab",
567a0709436Smp 						sizeof (kt_name));
568a0709436Smp 
569a0709436Smp 				switch (code) {
570a0709436Smp 				case KRB5_KT_NOTFOUND:
5713bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
572a0709436Smp 						"PAM-KRB5 (auth): "
573a0709436Smp 						"krb5_verify_init_creds failed:"
574a0709436Smp 						" Key table entry \"host/%s\""
5753bfb48feSsemery 						" not found in %s",
576a0709436Smp 						fqdn, kt_name);
577a0709436Smp 					break;
578a0709436Smp 				case ENOENT:
5793bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
580a0709436Smp 						"PAM-KRB5 (auth): "
581a0709436Smp 						"krb5_verify_init_creds failed:"
582a0709436Smp 						" Keytab file \"%s\""
5833bfb48feSsemery 						" does not exist.\n",
584a0709436Smp 						kt_name);
585a0709436Smp 					break;
586a0709436Smp 				default:
5873bfb48feSsemery 					__pam_log(LOG_AUTH | LOG_ERR,
588a0709436Smp 						"PAM-KRB5 (auth): "
589a0709436Smp 						"krb5_verify_init_creds failed:"
5903bfb48feSsemery 						" %s",
591a0709436Smp 						error_message(code));
592a0709436Smp 					break;
593a0709436Smp 				}
594a0709436Smp 
595a0709436Smp 				if (sp)
596a0709436Smp 					krb5_free_principal(kmd->kcontext, sp);
5977c478bd9Sstevel@tonic-gate 			}
5987c478bd9Sstevel@tonic-gate 		}
5993125ebfcSsemery 
6003125ebfcSsemery 		if (code == 0)
6013125ebfcSsemery 			kmd->expiration = as_reply->enc_part2->key_exp;
6023125ebfcSsemery 
6037c478bd9Sstevel@tonic-gate 		break;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
6067c478bd9Sstevel@tonic-gate 		/*
6077c478bd9Sstevel@tonic-gate 		 * Since this principal is not part of the local
6087c478bd9Sstevel@tonic-gate 		 * Kerberos realm, we just return PAM_USER_UNKNOWN.
6097c478bd9Sstevel@tonic-gate 		 */
6107c478bd9Sstevel@tonic-gate 		result = PAM_USER_UNKNOWN;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6133bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
6143bfb48feSsemery 				"PAM-KRB5 (auth): attempt_krb5_auth:"
6157c478bd9Sstevel@tonic-gate 				" User is not part of the local Kerberos"
6167c478bd9Sstevel@tonic-gate 				" realm: %s", error_message(code));
6177c478bd9Sstevel@tonic-gate 		break;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_PREAUTH_FAILED:
6207c478bd9Sstevel@tonic-gate 	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
6217c478bd9Sstevel@tonic-gate 		/*
6227c478bd9Sstevel@tonic-gate 		 * We could be trying the password from a previous
6237c478bd9Sstevel@tonic-gate 		 * pam authentication module, but we don't want to
6247c478bd9Sstevel@tonic-gate 		 * generate an error if the unix password is different
6257c478bd9Sstevel@tonic-gate 		 * than the Kerberos password...
6267c478bd9Sstevel@tonic-gate 		 */
6277c478bd9Sstevel@tonic-gate 		break;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	case KRB5KDC_ERR_KEY_EXP:
6307c478bd9Sstevel@tonic-gate 		if (!kmd->err_on_exp) {
6317c478bd9Sstevel@tonic-gate 			/*
6327c478bd9Sstevel@tonic-gate 			 * Request a tik for changepw service
6337c478bd9Sstevel@tonic-gate 			 * and it will tell us if pw is good or not.
6347c478bd9Sstevel@tonic-gate 			 */
6352278144aSsemery 			code = krb5_verifypw(kuser, *krb5_pass, kmd->debug);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 			if (kmd->debug)
6383bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
6397c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (auth): attempt_krb5_auth: "
6402278144aSsemery 				    "verifypw %d", code);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 			if (code == 0) {
6437c478bd9Sstevel@tonic-gate 				/* pw is good, set age status for acct_mgmt */
6447c478bd9Sstevel@tonic-gate 				kmd->age_status = PAM_NEW_AUTHTOK_REQD;
6457c478bd9Sstevel@tonic-gate 			}
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 		break;
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	default:
6507c478bd9Sstevel@tonic-gate 		result = PAM_SYSTEM_ERR;
6517c478bd9Sstevel@tonic-gate 		if (kmd->debug)
6523bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
6533bfb48feSsemery 				"PAM-KRB5 (auth): error %d - %s",
6547c478bd9Sstevel@tonic-gate 				code, error_message(code));
6557c478bd9Sstevel@tonic-gate 		break;
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	if (code == 0) {
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * success for the entered pw
6617c478bd9Sstevel@tonic-gate 		 *
6627c478bd9Sstevel@tonic-gate 		 * we can't rely on the pw in PAM_AUTHTOK
6637c478bd9Sstevel@tonic-gate 		 * to be the (correct) krb5 one so
6647c478bd9Sstevel@tonic-gate 		 * store krb5 pw in module data for
6657c478bd9Sstevel@tonic-gate 		 * use in acct_mgmt
6667c478bd9Sstevel@tonic-gate 		 */
6677c478bd9Sstevel@tonic-gate 		if (!(kmd->password = strdup(*krb5_pass))) {
6683bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR, "Cannot strdup password");
6697c478bd9Sstevel@tonic-gate 			result = PAM_BUF_ERR;
6707c478bd9Sstevel@tonic-gate 			goto out_err;
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate 		result = PAM_SUCCESS;
6737c478bd9Sstevel@tonic-gate 		goto out;
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate out_err:
6777c478bd9Sstevel@tonic-gate 	/* jump (or reach) here if error and cred cache has been init */
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	if (kmd->debug)
6803bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
6817c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): clearing initcreds in "
6827c478bd9Sstevel@tonic-gate 		    "pam_authenticate()");
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
6857c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate out:
6887c478bd9Sstevel@tonic-gate 	if (server)
6897c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, server);
6907c478bd9Sstevel@tonic-gate 	if (me)
6917c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, me);
6923125ebfcSsemery 	if (as_reply)
6933125ebfcSsemery 		krb5_free_kdc_rep(kmd->kcontext, as_reply);
694*67c90040Ssemery 
695*67c90040Ssemery 	/*
696*67c90040Ssemery 	 * clientp or serverp could be NULL in certain error cases in this
697*67c90040Ssemery 	 * function.  mycreds->[client|server] could also be NULL in case
698*67c90040Ssemery 	 * of error in this function, see out_err above.  The pointers clientp
699*67c90040Ssemery 	 * and serverp reference the input argument in my_creds for
700*67c90040Ssemery 	 * get_init_creds and must be freed if the input argument does not
701*67c90040Ssemery 	 * match the output argument, which occurs during a successful call
702*67c90040Ssemery 	 * to get_init_creds.
703*67c90040Ssemery 	 */
704*67c90040Ssemery 	if (clientp && my_creds->client && clientp != my_creds->client)
705*67c90040Ssemery 		krb5_free_principal(kmd->kcontext, clientp);
706*67c90040Ssemery 	if (serverp && my_creds->server && serverp != my_creds->server)
707*67c90040Ssemery 		krb5_free_principal(kmd->kcontext, serverp);
708*67c90040Ssemery 
7097c478bd9Sstevel@tonic-gate 	if (kmd->kcontext) {
7107c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
7117c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	if (kmd->debug)
7153bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
7167c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (auth): attempt_krb5_auth returning %d",
7177c478bd9Sstevel@tonic-gate 		    result);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	return (kmd->auth_status = result);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7237c478bd9Sstevel@tonic-gate void
7247c478bd9Sstevel@tonic-gate krb5_cleanup(pam_handle_t *pamh, void *data, int pam_status)
7257c478bd9Sstevel@tonic-gate {
7267c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd = (krb5_module_data_t *)data;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	if (kmd == NULL)
7297c478bd9Sstevel@tonic-gate 		return;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	if (kmd->debug) {
7323bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
7333bfb48feSsemery 			    "PAM-KRB5 (auth): krb5_cleanup auth_status = %d",
7347c478bd9Sstevel@tonic-gate 		    kmd->auth_status);
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/*
738*67c90040Ssemery 	 * Apps could be calling pam_end here, so we should always clean
739*67c90040Ssemery 	 * up regardless of success or failure here.
7407c478bd9Sstevel@tonic-gate 	 */
741*67c90040Ssemery 	if (kmd->ccache)
7427c478bd9Sstevel@tonic-gate 		krb5_cc_close(kmd->kcontext, kmd->ccache);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	if (kmd->password) {
7457c478bd9Sstevel@tonic-gate 		(void) memset(kmd->password, 0, strlen(kmd->password));
7467c478bd9Sstevel@tonic-gate 		free(kmd->password);
7477c478bd9Sstevel@tonic-gate 	}
7487c478bd9Sstevel@tonic-gate 
749*67c90040Ssemery 	if (kmd->user)
7503bfb48feSsemery 		free(kmd->user);
7513bfb48feSsemery 
752*67c90040Ssemery 	if (kmd->env)
753*67c90040Ssemery 		free(kmd->env);
754*67c90040Ssemery 
755*67c90040Ssemery 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
756*67c90040Ssemery 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	free(kmd);
7597c478bd9Sstevel@tonic-gate }
760