xref: /onnv-gate/usr/src/lib/pam_modules/krb5/krb5_acct_mgmt.c (revision 8991:5ab80299f68b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53391Ssemery  * Common Development and Distribution License (the "License").
63391Ssemery  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*8991SPeter.Shoults@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <kadm5/admin.h>
270Sstevel@tonic-gate #include <krb5.h>
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <security/pam_appl.h>
300Sstevel@tonic-gate #include <security/pam_modules.h>
310Sstevel@tonic-gate #include <security/pam_impl.h>
320Sstevel@tonic-gate #include <syslog.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <pwd.h>
380Sstevel@tonic-gate #include <libintl.h>
390Sstevel@tonic-gate #include <netdb.h>
400Sstevel@tonic-gate #include "utils.h"
410Sstevel@tonic-gate #include <shadow.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "krb5_repository.h"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #define	KRB5_AUTOMIGRATE_DATA	"SUNW-KRB5-AUTOMIGRATE-DATA"
460Sstevel@tonic-gate 
473641Ssemery #define	min(a, b) ((a) < (b) ? (a) : (b))
483641Ssemery 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * pam_sm_acct_mgmt	  main account managment routine.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int
fetch_princ_entry(krb5_module_data_t * kmd,char * princ_str,kadm5_principal_ent_rec * prent,int debug)540Sstevel@tonic-gate fetch_princ_entry(
553641Ssemery 	krb5_module_data_t *kmd,
560Sstevel@tonic-gate 	char *princ_str,
570Sstevel@tonic-gate 	kadm5_principal_ent_rec *prent,	/* out */
580Sstevel@tonic-gate 	int debug)
590Sstevel@tonic-gate 
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	kadm5_ret_t		code;
620Sstevel@tonic-gate 	krb5_principal 		princ = 0;
630Sstevel@tonic-gate 	char 			admin_realm[1024];
640Sstevel@tonic-gate 	char			kprinc[2*MAXHOSTNAMELEN];
653641Ssemery 	char			*cpw_service, *password;
660Sstevel@tonic-gate 	void 			*server_handle;
670Sstevel@tonic-gate 	krb5_context		context;
680Sstevel@tonic-gate 	kadm5_config_params	params;
690Sstevel@tonic-gate 
703641Ssemery 	password = kmd->password;
713641Ssemery 	context = kmd->kcontext;
720Sstevel@tonic-gate 
733641Ssemery 	if ((code = get_kmd_kuser(context, (const char *)princ_str,
743641Ssemery 	    kprinc, 2*MAXHOSTNAMELEN)) != 0) {
750Sstevel@tonic-gate 		return (code);
760Sstevel@tonic-gate 	}
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	code = krb5_parse_name(context, kprinc, &princ);
790Sstevel@tonic-gate 	if (code != 0) {
800Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	if (strlen(password) == 0) {
840Sstevel@tonic-gate 		krb5_free_principal(context, princ);
850Sstevel@tonic-gate 		if (debug)
863391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
870Sstevel@tonic-gate 			    "PAM-KRB5 (acct): fetch_princ_entry: pwlen=0");
880Sstevel@tonic-gate 		return (PAM_AUTH_ERR);
890Sstevel@tonic-gate 	}
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	(void) strlcpy(admin_realm,
920Sstevel@tonic-gate 		    krb5_princ_realm(context, princ)->data,
930Sstevel@tonic-gate 		    sizeof (admin_realm));
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	(void) memset((char *)&params, 0, sizeof (params));
960Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
970Sstevel@tonic-gate 	params.realm = admin_realm;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
1003391Ssemery 		__pam_log(LOG_AUTH | LOG_ERR,
1010Sstevel@tonic-gate 			"PAM-KRB5 (acct):  unable to get host based "
1023391Ssemery 			"service name for realm '%s'",
1030Sstevel@tonic-gate 			admin_realm);
1040Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1050Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	code = kadm5_init_with_password(kprinc, password, cpw_service,
1090Sstevel@tonic-gate 					&params, KADM5_STRUCT_VERSION,
1104960Swillf 					KADM5_API_VERSION_2, NULL,
1114960Swillf 					&server_handle);
1120Sstevel@tonic-gate 	if (code != 0) {
1130Sstevel@tonic-gate 		if (debug)
1143391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1150Sstevel@tonic-gate 			    "PAM-KRB5 (acct): fetch_princ_entry: "
1160Sstevel@tonic-gate 			    "init_with_pw failed: code = %d", code);
1170Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1180Sstevel@tonic-gate 		return ((code == KADM5_BAD_PASSWORD) ?
1190Sstevel@tonic-gate 			PAM_AUTH_ERR : PAM_SYSTEM_ERR);
1200Sstevel@tonic-gate 	}
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (_kadm5_get_kpasswd_protocol(server_handle) != KRB5_CHGPWD_RPCSEC) {
1230Sstevel@tonic-gate 		if (debug)
1243391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1250Sstevel@tonic-gate 			    "PAM-KRB5 (acct): fetch_princ_entry: "
1260Sstevel@tonic-gate 			    "non-RPCSEC_GSS chpw server, can't get "
1270Sstevel@tonic-gate 			    "princ entry");
1280Sstevel@tonic-gate 		(void) kadm5_destroy(server_handle);
1290Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1300Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	code = kadm5_get_principal(server_handle, princ, prent,
1340Sstevel@tonic-gate 				KADM5_PRINCIPAL_NORMAL_MASK);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	if (code != 0) {
1370Sstevel@tonic-gate 		(void) kadm5_destroy(server_handle);
1380Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1390Sstevel@tonic-gate 		return ((code == KADM5_UNK_PRINC) ?
1400Sstevel@tonic-gate 			PAM_USER_UNKNOWN : PAM_SYSTEM_ERR);
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	(void) kadm5_destroy(server_handle);
1440Sstevel@tonic-gate 	krb5_free_principal(context, princ);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	return (PAM_SUCCESS);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate  * exp_warn
1510Sstevel@tonic-gate  *
1523641Ssemery  * Warn the user if their pw is set to expire.
1530Sstevel@tonic-gate  *
1543641Ssemery  * We first check to see if the KDC had set any account or password
1553641Ssemery  * expiration information in the key expiration field.  If this was
1563641Ssemery  * not set then we must assume that the KDC could be broken and revert
1573641Ssemery  * to fetching pw/account expiration information from kadm.  We can not
1583641Ssemery  * determine the difference between broken KDCs that do not send key-exp
1593641Ssemery  * vs. principals that do not have an expiration policy.  The up-shot
1603641Ssemery  * is that pam_krb5 will probably not be stacked for acct mgmt if the
1613641Ssemery  * environment does not have an exp policy, avoiding the second exchange
1623641Ssemery  * using the kadm protocol.
1630Sstevel@tonic-gate  */
1640Sstevel@tonic-gate static int
exp_warn(pam_handle_t * pamh,char * user,krb5_module_data_t * kmd,int debug)1650Sstevel@tonic-gate exp_warn(
1660Sstevel@tonic-gate 	pam_handle_t *pamh,
1670Sstevel@tonic-gate 	char *user,
1683641Ssemery 	krb5_module_data_t *kmd,
1690Sstevel@tonic-gate 	int debug)
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	int err;
1730Sstevel@tonic-gate 	kadm5_principal_ent_rec prent;
1743641Ssemery 	krb5_timestamp  now, days, expiration;
1753641Ssemery 	char    messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], *password;
1763641Ssemery 	krb5_error_code code;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (debug)
1793391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1800Sstevel@tonic-gate 		    "PAM-KRB5 (acct): exp_warn start: user = '%s'",
1810Sstevel@tonic-gate 		    user ? user : "<null>");
1820Sstevel@tonic-gate 
1833641Ssemery 	password = kmd->password;
1843641Ssemery 
1850Sstevel@tonic-gate 	if (!pamh || !user || !password) {
1860Sstevel@tonic-gate 		err = PAM_SERVICE_ERR;
1874252Sps57422 		goto exit;
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1904252Sps57422 	/*
191*8991SPeter.Shoults@Sun.COM 	 * If we error out from krb5_init_secure_context, then just set error
192*8991SPeter.Shoults@Sun.COM 	 * code, check to see about debug message and exit out of routine as the
1934252Sps57422 	 * context could not possibly have been setup.
1944252Sps57422 	 */
1954252Sps57422 
196*8991SPeter.Shoults@Sun.COM 	if (code = krb5_init_secure_context(&kmd->kcontext)) {
1973641Ssemery 		err = PAM_SYSTEM_ERR;
1983641Ssemery 		if (debug)
1993641Ssemery 			__pam_log(LOG_AUTH | LOG_ERR, "PAM-KRB5 (acct): "
200*8991SPeter.Shoults@Sun.COM 			    "krb5_init_secure_context failed: code=%d",
2013641Ssemery 			    code);
2024252Sps57422 		goto exit;
2033641Ssemery 	}
2043641Ssemery 	if (code = krb5_timeofday(kmd->kcontext, &now)) {
2053641Ssemery 		err = PAM_SYSTEM_ERR;
2060Sstevel@tonic-gate 		if (debug)
2073641Ssemery 			__pam_log(LOG_AUTH | LOG_ERR,
2083641Ssemery 			    "PAM-KRB5 (acct): krb5_timeofday failed: code=%d",
2093641Ssemery 			    code);
2100Sstevel@tonic-gate 		goto out;
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2133641Ssemery 	if (kmd->expiration != 0) {
2143641Ssemery 		expiration = kmd->expiration;
2153641Ssemery 	} else {
2163641Ssemery 		(void) memset(&prent, 0, sizeof (prent));
2173641Ssemery 		if ((err = fetch_princ_entry(kmd, user, &prent, debug))
2183641Ssemery 		    != PAM_SUCCESS) {
2193641Ssemery 			if (debug)
2203641Ssemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
2213641Ssemery 				"PAM-KRB5 (acct): exp_warn: fetch_pr failed %d",
2223641Ssemery 				err);
2233641Ssemery 			goto out;
2243641Ssemery 		}
2253641Ssemery 		if (prent.princ_expire_time != 0 && prent.pw_expiration != 0)
2263641Ssemery 			expiration = min(prent.princ_expire_time,
2273641Ssemery 				prent.pw_expiration);
2283641Ssemery 		else
2293641Ssemery 			expiration = prent.princ_expire_time ?
2303641Ssemery 				prent.princ_expire_time : prent.pw_expiration;
2313641Ssemery 	}
2323641Ssemery 
2330Sstevel@tonic-gate 	if (debug)
2343391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2353641Ssemery 		    "PAM-KRB5 (acct): exp_warn: "
2363641Ssemery 		    "princ/pw_exp exp=%ld, now =%ld, days=%ld",
2373641Ssemery 		    expiration,
2383641Ssemery 		    now,
2393641Ssemery 		    expiration > 0
2403641Ssemery 		    ? ((expiration - now) / DAY)
2410Sstevel@tonic-gate 		    : 0);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/* warn user if principal's pw is set to expire */
2443641Ssemery 	if (expiration > 0) {
2453641Ssemery 		days = (expiration - now) / DAY;
2460Sstevel@tonic-gate 		if (days <= 0)
2470Sstevel@tonic-gate 			(void) snprintf(messages[0],
2480Sstevel@tonic-gate 				sizeof (messages[0]),
2490Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
2503641Ssemery 				"Your Kerberos account/password will expire "
2513641Ssemery 				"within 24 hours.\n"));
2520Sstevel@tonic-gate 		else if (days == 1)
2530Sstevel@tonic-gate 			(void) snprintf(messages[0],
2540Sstevel@tonic-gate 				sizeof (messages[0]),
2550Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
2563641Ssemery 				"Your Kerberos account/password will expire "
2573641Ssemery 				"in 1 day.\n"));
2580Sstevel@tonic-gate 		else
2590Sstevel@tonic-gate 			(void) snprintf(messages[0],
2600Sstevel@tonic-gate 				sizeof (messages[0]),
2610Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
2623641Ssemery 				"Your Kerberos account/password will expire in "
2633641Ssemery 				"%d days.\n"),
2640Sstevel@tonic-gate 				(int)days);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1,
2670Sstevel@tonic-gate 					messages, NULL);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	/* things went smooth */
2710Sstevel@tonic-gate 	err = PAM_SUCCESS;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate out:
2744252Sps57422 
2754252Sps57422 	if (kmd->kcontext) {
2764252Sps57422 		krb5_free_context(kmd->kcontext);
2774252Sps57422 		kmd->kcontext = NULL;
2784252Sps57422 	}
2794252Sps57422 
2804252Sps57422 exit:
2814252Sps57422 
2820Sstevel@tonic-gate 	if (debug)
2833391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2840Sstevel@tonic-gate 		    "PAM-KRB5 (acct): exp_warn end: err = %d", err);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	return (err);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate  * pam_krb5 acct_mgmt
2910Sstevel@tonic-gate  *
2920Sstevel@tonic-gate  * we do
2930Sstevel@tonic-gate  *    - check if pw expired (flag set in auth)
2940Sstevel@tonic-gate  *    - warn user if pw is set to expire
2950Sstevel@tonic-gate  *
2960Sstevel@tonic-gate  * notes
2970Sstevel@tonic-gate  *    - we require the auth module to have already run (sets module data)
2980Sstevel@tonic-gate  *    - we don't worry about an expired princ cuz if that's the case,
2990Sstevel@tonic-gate  *      auth would have failed
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char ** argv)3020Sstevel@tonic-gate pam_sm_acct_mgmt(
3030Sstevel@tonic-gate 	pam_handle_t *pamh,
3040Sstevel@tonic-gate 	int	flags,
3050Sstevel@tonic-gate 	int	argc,
3060Sstevel@tonic-gate 	const char **argv)
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	char *user = NULL;
3100Sstevel@tonic-gate 	char *userdata = NULL;
3110Sstevel@tonic-gate 	int err;
3120Sstevel@tonic-gate 	int i;
3130Sstevel@tonic-gate 	krb5_module_data_t *kmd = NULL;
3140Sstevel@tonic-gate 	char    messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
3150Sstevel@tonic-gate 	int debug = 0;  /* pam.conf entry option */
3160Sstevel@tonic-gate 	int nowarn = 0; /* pam.conf entry option, no expire warnings */
3170Sstevel@tonic-gate 	pam_repository_t	*rep_data = NULL;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
3200Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
3210Sstevel@tonic-gate 			debug = 1;
3220Sstevel@tonic-gate 		else if (strcasecmp(argv[i], "nowarn") == 0) {
3230Sstevel@tonic-gate 			nowarn = 1;
3240Sstevel@tonic-gate 			flags = flags | PAM_SILENT;
3250Sstevel@tonic-gate 		} else {
3263391Ssemery 			__pam_log(LOG_AUTH | LOG_ERR,
3270Sstevel@tonic-gate 			    "PAM-KRB5 (acct): illegal option %s",
3280Sstevel@tonic-gate 			    argv[i]);
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (debug)
3333391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3340Sstevel@tonic-gate 		    "PAM-KRB5 (acct): debug=%d, nowarn=%d",
3350Sstevel@tonic-gate 		    debug, nowarn);
3360Sstevel@tonic-gate 
3373391Ssemery 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
3383391Ssemery 
3390Sstevel@tonic-gate 	if (rep_data != NULL) {
3400Sstevel@tonic-gate 		/*
3410Sstevel@tonic-gate 		 * If the repository is not ours,
3420Sstevel@tonic-gate 		 * return PAM_IGNORE.
3430Sstevel@tonic-gate 		 */
3440Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
3450Sstevel@tonic-gate 			if (debug)
3463391Ssemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
3473391Ssemery 					"PAM-KRB5 (acct): wrong"
3480Sstevel@tonic-gate 					"repository found (%s), returning "
3490Sstevel@tonic-gate 					"PAM_IGNORE", rep_data->type);
3500Sstevel@tonic-gate 			return (PAM_IGNORE);
3510Sstevel@tonic-gate 		}
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/* get user name */
3563391Ssemery 	(void) pam_get_item(pamh, PAM_USER, (void **) &user);
3570Sstevel@tonic-gate 
3583391Ssemery 	if (user == NULL || *user == '\0') {
3590Sstevel@tonic-gate 		err = PAM_USER_UNKNOWN;
3600Sstevel@tonic-gate 		goto out;
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/* get pam_krb5_migrate specific data */
3640Sstevel@tonic-gate 	err = pam_get_data(pamh, KRB5_AUTOMIGRATE_DATA,
3650Sstevel@tonic-gate 					(const void **)&userdata);
3660Sstevel@tonic-gate 	if (err != PAM_SUCCESS) {
3670Sstevel@tonic-gate 		if (debug)
3683391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): "
3693391Ssemery 				"no module data for KRB5_AUTOMIGRATE_DATA");
3700Sstevel@tonic-gate 	} else {
3710Sstevel@tonic-gate 		/*
3720Sstevel@tonic-gate 		 * We try and reauthenticate, since this user has a
3730Sstevel@tonic-gate 		 * newly created krb5 principal via the pam_krb5_migrate
3740Sstevel@tonic-gate 		 * auth module. That way, this new user will have fresh
3750Sstevel@tonic-gate 		 * creds (assuming pam_sm_authenticate() succeeds).
3760Sstevel@tonic-gate 		 */
3770Sstevel@tonic-gate 		if (strcmp(user, userdata) == 0)
3780Sstevel@tonic-gate 			(void) pam_sm_authenticate(pamh, flags, argc,
3790Sstevel@tonic-gate 					(const char **)argv);
3800Sstevel@tonic-gate 		else
3810Sstevel@tonic-gate 			if (debug)
3823391Ssemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
3830Sstevel@tonic-gate 				"PAM-KRB5 (acct): PAM_USER %s"
3843391Ssemery 				"does not match user %s from pam_get_data()",
3850Sstevel@tonic-gate 				user, (char *)userdata);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	/* get krb5 module data  */
3890Sstevel@tonic-gate 	if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd))
3900Sstevel@tonic-gate 	    != PAM_SUCCESS) {
3910Sstevel@tonic-gate 		if (err == PAM_NO_MODULE_DATA) {
3920Sstevel@tonic-gate 			/*
3930Sstevel@tonic-gate 			 * pam_auth never called (possible config
3943740Ssemery 			 * error; no pam_krb5 auth entry in pam.conf),
3950Sstevel@tonic-gate 			 */
3963740Ssemery 			if (debug) {
3973391Ssemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
3980Sstevel@tonic-gate 				    "PAM-KRB5 (acct): no module data");
3993740Ssemery 			}
4000Sstevel@tonic-gate 			err = PAM_IGNORE;
4010Sstevel@tonic-gate 			goto out;
4020Sstevel@tonic-gate 		} else {
4033391Ssemery 			__pam_log(LOG_AUTH | LOG_ERR,
4040Sstevel@tonic-gate 				    "PAM-KRB5 (acct): get module"
4053391Ssemery 				    " data failed: err=%d",
4060Sstevel@tonic-gate 			    err);
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 		goto out;
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	debug = debug || kmd->debug;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * auth mod set status to ignore, most likely cuz root key is
4150Sstevel@tonic-gate 	 * in keytab, so skip other checks and return ignore
4160Sstevel@tonic-gate 	 */
4170Sstevel@tonic-gate 	if (kmd->auth_status == PAM_IGNORE) {
4180Sstevel@tonic-gate 		if (debug)
4193391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4200Sstevel@tonic-gate 			    "PAM-KRB5 (acct): kmd auth_status is IGNORE");
4210Sstevel@tonic-gate 		err = PAM_IGNORE;
4220Sstevel@tonic-gate 		goto out;
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/*
4263740Ssemery 	 * If there is no Kerberos related user and there is authentication
4273740Ssemery 	 * data, this means that while the user has successfully passed
4283740Ssemery 	 * authentication, Kerberos is not the account authority because there
4293740Ssemery 	 * is no valid Kerberos principal.  PAM_IGNORE is returned since
4303740Ssemery 	 * Kerberos is not authoritative for this user.  Other modules in the
4313740Ssemery 	 * account stack will need to determine the success or failure for this
4323740Ssemery 	 * user.
4333391Ssemery 	 */
4343391Ssemery 	if (kmd->auth_status == PAM_USER_UNKNOWN) {
4353391Ssemery 		if (debug)
4363391Ssemery 			syslog(LOG_DEBUG,
4373391Ssemery 			    "PAM-KRB5 (acct): kmd auth_status is USER UNKNOWN");
4383740Ssemery 		err = PAM_IGNORE;
4393391Ssemery 		goto out;
4403391Ssemery 	}
4413391Ssemery 
4423391Ssemery 	/*
4430Sstevel@tonic-gate 	 * age_status will be set to PAM_NEW_AUTHTOK_REQD in pam_krb5's
4440Sstevel@tonic-gate 	 * 'auth' if the user's key/pw has expired and needs to be changed
4450Sstevel@tonic-gate 	 */
4460Sstevel@tonic-gate 	if (kmd->age_status == PAM_NEW_AUTHTOK_REQD) {
4470Sstevel@tonic-gate 		if (!nowarn) {
4480Sstevel@tonic-gate 			(void) snprintf(messages[0], sizeof (messages[0]),
4490Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
4500Sstevel@tonic-gate 				"Your Kerberos password has expired.\n"));
4510Sstevel@tonic-gate 			(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
4520Sstevel@tonic-gate 					1, messages, NULL);
4530Sstevel@tonic-gate 		}
4540Sstevel@tonic-gate 		err = PAM_NEW_AUTHTOK_REQD;
4550Sstevel@tonic-gate 		goto out;
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 
4583740Ssemery 	if (kmd->auth_status == PAM_SUCCESS && !(flags & PAM_SILENT) &&
4593740Ssemery 	    !nowarn && kmd->password) {
4600Sstevel@tonic-gate 		/* if we fail, let it slide, it's only a warning brah */
4613641Ssemery 		(void) exp_warn(pamh, user, kmd, debug);
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate 
4643391Ssemery 	/*
4653740Ssemery 	 * If Kerberos is treated as optional in the PAM stack, it is possible
4663740Ssemery 	 * that there is a KRB5_DATA item and a non-Kerberos account authority.
4673740Ssemery 	 * In that case, PAM_IGNORE is returned.
4683391Ssemery 	 */
4693740Ssemery 	err = kmd->auth_status != PAM_SUCCESS ? PAM_IGNORE : kmd->auth_status;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate out:
4720Sstevel@tonic-gate 	if (debug)
4733391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
4740Sstevel@tonic-gate 		    "PAM-KRB5 (acct): end: %s", pam_strerror(pamh, err));
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	return (err);
4770Sstevel@tonic-gate }
478