xref: /illumos-gate/usr/src/lib/pam_modules/krb5/krb5_acct_mgmt.c (revision cbea7aca3fd7787405cbdbd93752998f03dfc25f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53bfb48feSsemery  * Common Development and Distribution License (the "License").
63bfb48feSsemery  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
228ce3ffdfSPeter Shoults  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*cbea7acaSDominik Hassler  *
25*cbea7acaSDominik Hassler  * Copyright 2023 OmniOS Community Edition (OmniOSce) Association.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
297c478bd9Sstevel@tonic-gate #include <krb5.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
327c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
337c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
347c478bd9Sstevel@tonic-gate #include <syslog.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <pwd.h>
407c478bd9Sstevel@tonic-gate #include <libintl.h>
417c478bd9Sstevel@tonic-gate #include <netdb.h>
427c478bd9Sstevel@tonic-gate #include "utils.h"
437c478bd9Sstevel@tonic-gate #include <shadow.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	KRB5_AUTOMIGRATE_DATA	"SUNW-KRB5-AUTOMIGRATE-DATA"
487c478bd9Sstevel@tonic-gate 
493125ebfcSsemery #define	min(a, b) ((a) < (b) ? (a) : (b))
503125ebfcSsemery 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * pam_sm_acct_mgmt	  main account managment routine.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static int
fetch_princ_entry(krb5_module_data_t * kmd,const char * princ_str,kadm5_principal_ent_rec * prent,int debug)567c478bd9Sstevel@tonic-gate fetch_princ_entry(
573125ebfcSsemery 	krb5_module_data_t *kmd,
58*cbea7acaSDominik Hassler 	const char *princ_str,
597c478bd9Sstevel@tonic-gate 	kadm5_principal_ent_rec *prent,	/* out */
607c478bd9Sstevel@tonic-gate 	int debug)
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	kadm5_ret_t		code;
647c478bd9Sstevel@tonic-gate 	krb5_principal 		princ = 0;
657c478bd9Sstevel@tonic-gate 	char 			admin_realm[1024];
667c478bd9Sstevel@tonic-gate 	char			kprinc[2*MAXHOSTNAMELEN];
673125ebfcSsemery 	char			*cpw_service, *password;
687c478bd9Sstevel@tonic-gate 	void 			*server_handle;
697c478bd9Sstevel@tonic-gate 	krb5_context		context;
707c478bd9Sstevel@tonic-gate 	kadm5_config_params	params;
717c478bd9Sstevel@tonic-gate 
723125ebfcSsemery 	password = kmd->password;
733125ebfcSsemery 	context = kmd->kcontext;
747c478bd9Sstevel@tonic-gate 
75*cbea7acaSDominik Hassler 	if ((code = get_kmd_kuser(context, princ_str,
763125ebfcSsemery 	    kprinc, 2 * MAXHOSTNAMELEN)) != 0) {
777c478bd9Sstevel@tonic-gate 		return (code);
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	code = krb5_parse_name(context, kprinc, &princ);
817c478bd9Sstevel@tonic-gate 	if (code != 0) {
827c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	if (strlen(password) == 0) {
867c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
877c478bd9Sstevel@tonic-gate 		if (debug)
883bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
897c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (acct): fetch_princ_entry: pwlen=0");
907c478bd9Sstevel@tonic-gate 		return (PAM_AUTH_ERR);
917c478bd9Sstevel@tonic-gate 	}
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	(void) strlcpy(admin_realm,
947c478bd9Sstevel@tonic-gate 		    krb5_princ_realm(context, princ)->data,
957c478bd9Sstevel@tonic-gate 		    sizeof (admin_realm));
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	(void) memset((char *)&params, 0, sizeof (params));
987c478bd9Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
997c478bd9Sstevel@tonic-gate 	params.realm = admin_realm;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
1023bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
1037c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (acct):  unable to get host based "
1043bfb48feSsemery 			"service name for realm '%s'",
1057c478bd9Sstevel@tonic-gate 			admin_realm);
1067c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1077c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	code = kadm5_init_with_password(kprinc, password, cpw_service,
1117c478bd9Sstevel@tonic-gate 					&params, KADM5_STRUCT_VERSION,
11254925bf6Swillf 					KADM5_API_VERSION_2, NULL,
11354925bf6Swillf 					&server_handle);
1147c478bd9Sstevel@tonic-gate 	if (code != 0) {
1157c478bd9Sstevel@tonic-gate 		if (debug)
1163bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1177c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (acct): fetch_princ_entry: "
1187c478bd9Sstevel@tonic-gate 			    "init_with_pw failed: code = %d", code);
1197c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1207c478bd9Sstevel@tonic-gate 		return ((code == KADM5_BAD_PASSWORD) ?
1217c478bd9Sstevel@tonic-gate 			PAM_AUTH_ERR : PAM_SYSTEM_ERR);
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	if (_kadm5_get_kpasswd_protocol(server_handle) != KRB5_CHGPWD_RPCSEC) {
1257c478bd9Sstevel@tonic-gate 		if (debug)
1263bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1277c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (acct): fetch_princ_entry: "
1287c478bd9Sstevel@tonic-gate 			    "non-RPCSEC_GSS chpw server, can't get "
1297c478bd9Sstevel@tonic-gate 			    "princ entry");
1307c478bd9Sstevel@tonic-gate 		(void) kadm5_destroy(server_handle);
1317c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1327c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	code = kadm5_get_principal(server_handle, princ, prent,
1367c478bd9Sstevel@tonic-gate 				KADM5_PRINCIPAL_NORMAL_MASK);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (code != 0) {
1397c478bd9Sstevel@tonic-gate 		(void) kadm5_destroy(server_handle);
1407c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
1417c478bd9Sstevel@tonic-gate 		return ((code == KADM5_UNK_PRINC) ?
1427c478bd9Sstevel@tonic-gate 			PAM_USER_UNKNOWN : PAM_SYSTEM_ERR);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	(void) kadm5_destroy(server_handle);
1467c478bd9Sstevel@tonic-gate 	krb5_free_principal(context, princ);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (PAM_SUCCESS);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * exp_warn
1537c478bd9Sstevel@tonic-gate  *
1543125ebfcSsemery  * Warn the user if their pw is set to expire.
1557c478bd9Sstevel@tonic-gate  *
1563125ebfcSsemery  * We first check to see if the KDC had set any account or password
1573125ebfcSsemery  * expiration information in the key expiration field.  If this was
1583125ebfcSsemery  * not set then we must assume that the KDC could be broken and revert
1593125ebfcSsemery  * to fetching pw/account expiration information from kadm.  We can not
1603125ebfcSsemery  * determine the difference between broken KDCs that do not send key-exp
1613125ebfcSsemery  * vs. principals that do not have an expiration policy.  The up-shot
1623125ebfcSsemery  * is that pam_krb5 will probably not be stacked for acct mgmt if the
1633125ebfcSsemery  * environment does not have an exp policy, avoiding the second exchange
1643125ebfcSsemery  * using the kadm protocol.
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate static int
exp_warn(pam_handle_t * pamh,const char * user,krb5_module_data_t * kmd,int debug)1677c478bd9Sstevel@tonic-gate exp_warn(
1687c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh,
169*cbea7acaSDominik Hassler 	const char *user,
1703125ebfcSsemery 	krb5_module_data_t *kmd,
1717c478bd9Sstevel@tonic-gate 	int debug)
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	int err;
1757c478bd9Sstevel@tonic-gate 	kadm5_principal_ent_rec prent;
1763125ebfcSsemery 	krb5_timestamp  now, days, expiration;
1773125ebfcSsemery 	char    messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], *password;
1783125ebfcSsemery 	krb5_error_code code;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (debug)
1813bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1827c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (acct): exp_warn start: user = '%s'",
1837c478bd9Sstevel@tonic-gate 		    user ? user : "<null>");
1847c478bd9Sstevel@tonic-gate 
1853125ebfcSsemery 	password = kmd->password;
1863125ebfcSsemery 
1877c478bd9Sstevel@tonic-gate 	if (!pamh || !user || !password) {
1887c478bd9Sstevel@tonic-gate 		err = PAM_SERVICE_ERR;
189f12178a9Sps57422 		goto exit;
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
192f12178a9Sps57422 	/*
1938ce3ffdfSPeter Shoults 	 * If we error out from krb5_init_secure_context, then just set error
1948ce3ffdfSPeter Shoults 	 * code, check to see about debug message and exit out of routine as the
195f12178a9Sps57422 	 * context could not possibly have been setup.
196f12178a9Sps57422 	 */
197f12178a9Sps57422 
1988ce3ffdfSPeter Shoults 	if (code = krb5_init_secure_context(&kmd->kcontext)) {
1993125ebfcSsemery 		err = PAM_SYSTEM_ERR;
2003125ebfcSsemery 		if (debug)
2013125ebfcSsemery 			__pam_log(LOG_AUTH | LOG_ERR, "PAM-KRB5 (acct): "
2028ce3ffdfSPeter Shoults 			    "krb5_init_secure_context failed: code=%d",
2033125ebfcSsemery 			    code);
204f12178a9Sps57422 		goto exit;
2053125ebfcSsemery 	}
2063125ebfcSsemery 	if (code = krb5_timeofday(kmd->kcontext, &now)) {
2073125ebfcSsemery 		err = PAM_SYSTEM_ERR;
2083125ebfcSsemery 		if (debug)
2093125ebfcSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
2103125ebfcSsemery 			    "PAM-KRB5 (acct): krb5_timeofday failed: code=%d",
2113125ebfcSsemery 			    code);
2123125ebfcSsemery 		goto out;
2133125ebfcSsemery 	}
2143125ebfcSsemery 
2153125ebfcSsemery 	if (kmd->expiration != 0) {
2163125ebfcSsemery 		expiration = kmd->expiration;
2173125ebfcSsemery 	} else {
2187c478bd9Sstevel@tonic-gate 		(void) memset(&prent, 0, sizeof (prent));
2193125ebfcSsemery 		if ((err = fetch_princ_entry(kmd, user, &prent, debug))
2203125ebfcSsemery 		    != PAM_SUCCESS) {
2217c478bd9Sstevel@tonic-gate 			if (debug)
2223bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
2237c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (acct): exp_warn: fetch_pr failed %d",
2247c478bd9Sstevel@tonic-gate 				err);
2257c478bd9Sstevel@tonic-gate 			goto out;
2267c478bd9Sstevel@tonic-gate 		}
2273125ebfcSsemery 		if (prent.princ_expire_time != 0 && prent.pw_expiration != 0)
2283125ebfcSsemery 			expiration = min(prent.princ_expire_time,
2293125ebfcSsemery 				prent.pw_expiration);
2303125ebfcSsemery 		else
2313125ebfcSsemery 			expiration = prent.princ_expire_time ?
2323125ebfcSsemery 				prent.princ_expire_time : prent.pw_expiration;
2333125ebfcSsemery 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if (debug)
2363bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2373125ebfcSsemery 		    "PAM-KRB5 (acct): exp_warn: "
2383125ebfcSsemery 		    "princ/pw_exp exp=%ld, now =%ld, days=%ld",
2393125ebfcSsemery 		    expiration,
2403125ebfcSsemery 		    now,
2413125ebfcSsemery 		    expiration > 0
2423125ebfcSsemery 		    ? ((expiration - now) / DAY)
2437c478bd9Sstevel@tonic-gate 		    : 0);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/* warn user if principal's pw is set to expire */
2463125ebfcSsemery 	if (expiration > 0) {
2473125ebfcSsemery 		days = (expiration - now) / DAY;
2487c478bd9Sstevel@tonic-gate 		if (days <= 0)
2497c478bd9Sstevel@tonic-gate 			(void) snprintf(messages[0],
2507c478bd9Sstevel@tonic-gate 				sizeof (messages[0]),
2517c478bd9Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
2523125ebfcSsemery 				"Your Kerberos account/password will expire "
2533125ebfcSsemery 				"within 24 hours.\n"));
2547c478bd9Sstevel@tonic-gate 		else if (days == 1)
2557c478bd9Sstevel@tonic-gate 			(void) snprintf(messages[0],
2567c478bd9Sstevel@tonic-gate 				sizeof (messages[0]),
2577c478bd9Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
2583125ebfcSsemery 				"Your Kerberos account/password will expire "
2593125ebfcSsemery 				"in 1 day.\n"));
2607c478bd9Sstevel@tonic-gate 		else
2617c478bd9Sstevel@tonic-gate 			(void) snprintf(messages[0],
2627c478bd9Sstevel@tonic-gate 				sizeof (messages[0]),
2637c478bd9Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
2643125ebfcSsemery 				"Your Kerberos account/password will expire in "
2653125ebfcSsemery 				"%d days.\n"),
2667c478bd9Sstevel@tonic-gate 				(int)days);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		(void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1,
2697c478bd9Sstevel@tonic-gate 					messages, NULL);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/* things went smooth */
2737c478bd9Sstevel@tonic-gate 	err = PAM_SUCCESS;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate out:
276f12178a9Sps57422 
277f12178a9Sps57422 	if (kmd->kcontext) {
278f12178a9Sps57422 		krb5_free_context(kmd->kcontext);
279f12178a9Sps57422 		kmd->kcontext = NULL;
280f12178a9Sps57422 	}
281f12178a9Sps57422 
282f12178a9Sps57422 exit:
283f12178a9Sps57422 
2847c478bd9Sstevel@tonic-gate 	if (debug)
2853bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2867c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (acct): exp_warn end: err = %d", err);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	return (err);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate  * pam_krb5 acct_mgmt
2937c478bd9Sstevel@tonic-gate  *
2947c478bd9Sstevel@tonic-gate  * we do
2957c478bd9Sstevel@tonic-gate  *    - check if pw expired (flag set in auth)
2967c478bd9Sstevel@tonic-gate  *    - warn user if pw is set to expire
2977c478bd9Sstevel@tonic-gate  *
2987c478bd9Sstevel@tonic-gate  * notes
2997c478bd9Sstevel@tonic-gate  *    - we require the auth module to have already run (sets module data)
3007c478bd9Sstevel@tonic-gate  *    - we don't worry about an expired princ cuz if that's the case,
3017c478bd9Sstevel@tonic-gate  *      auth would have failed
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char ** argv)304*cbea7acaSDominik Hassler pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
3057c478bd9Sstevel@tonic-gate {
306*cbea7acaSDominik Hassler 	const char *user = NULL;
3077c478bd9Sstevel@tonic-gate 	char *userdata = NULL;
3087c478bd9Sstevel@tonic-gate 	int err;
3097c478bd9Sstevel@tonic-gate 	int i;
3107c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd = NULL;
3117c478bd9Sstevel@tonic-gate 	char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
3127c478bd9Sstevel@tonic-gate 	int debug = 0;  /* pam.conf entry option */
3137c478bd9Sstevel@tonic-gate 	int nowarn = 0; /* pam.conf entry option, no expire warnings */
314*cbea7acaSDominik Hassler 	const pam_repository_t *rep_data = NULL;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
3177c478bd9Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
3187c478bd9Sstevel@tonic-gate 			debug = 1;
3197c478bd9Sstevel@tonic-gate 		else if (strcasecmp(argv[i], "nowarn") == 0) {
3207c478bd9Sstevel@tonic-gate 			nowarn = 1;
3217c478bd9Sstevel@tonic-gate 			flags = flags | PAM_SILENT;
3227c478bd9Sstevel@tonic-gate 		} else {
3233bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
3247c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (acct): illegal option %s",
3257c478bd9Sstevel@tonic-gate 			    argv[i]);
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if (debug)
3303bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3317c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (acct): debug=%d, nowarn=%d",
3327c478bd9Sstevel@tonic-gate 		    debug, nowarn);
3337c478bd9Sstevel@tonic-gate 
334*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_REPOSITORY, (const void **)&rep_data);
3353bfb48feSsemery 
3367c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
3377c478bd9Sstevel@tonic-gate 		/*
3387c478bd9Sstevel@tonic-gate 		 * If the repository is not ours,
3397c478bd9Sstevel@tonic-gate 		 * return PAM_IGNORE.
3407c478bd9Sstevel@tonic-gate 		 */
3417c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
3427c478bd9Sstevel@tonic-gate 			if (debug)
3433bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
3443bfb48feSsemery 					"PAM-KRB5 (acct): wrong"
3457c478bd9Sstevel@tonic-gate 					"repository found (%s), returning "
3467c478bd9Sstevel@tonic-gate 					"PAM_IGNORE", rep_data->type);
3477c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* get user name */
353*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_USER, (const void **)&user);
3547c478bd9Sstevel@tonic-gate 
3553bfb48feSsemery 	if (user == NULL || *user == '\0') {
3567c478bd9Sstevel@tonic-gate 		err = PAM_USER_UNKNOWN;
3577c478bd9Sstevel@tonic-gate 		goto out;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* get pam_krb5_migrate specific data */
3617c478bd9Sstevel@tonic-gate 	err = pam_get_data(pamh, KRB5_AUTOMIGRATE_DATA,
3627c478bd9Sstevel@tonic-gate 					(const void **)&userdata);
3637c478bd9Sstevel@tonic-gate 	if (err != PAM_SUCCESS) {
3647c478bd9Sstevel@tonic-gate 		if (debug)
3653bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): "
3663bfb48feSsemery 				"no module data for KRB5_AUTOMIGRATE_DATA");
3677c478bd9Sstevel@tonic-gate 	} else {
3687c478bd9Sstevel@tonic-gate 		/*
3697c478bd9Sstevel@tonic-gate 		 * We try and reauthenticate, since this user has a
3707c478bd9Sstevel@tonic-gate 		 * newly created krb5 principal via the pam_krb5_migrate
3717c478bd9Sstevel@tonic-gate 		 * auth module. That way, this new user will have fresh
3727c478bd9Sstevel@tonic-gate 		 * creds (assuming pam_sm_authenticate() succeeds).
3737c478bd9Sstevel@tonic-gate 		 */
3747c478bd9Sstevel@tonic-gate 		if (strcmp(user, userdata) == 0)
375*cbea7acaSDominik Hassler 			(void) pam_sm_authenticate(pamh, flags, argc, argv);
3767c478bd9Sstevel@tonic-gate 		else
3777c478bd9Sstevel@tonic-gate 			if (debug)
3783bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
3797c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (acct): PAM_USER %s"
3803bfb48feSsemery 				"does not match user %s from pam_get_data()",
3817c478bd9Sstevel@tonic-gate 				user, (char *)userdata);
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	/* get krb5 module data  */
3857c478bd9Sstevel@tonic-gate 	if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd))
3867c478bd9Sstevel@tonic-gate 	    != PAM_SUCCESS) {
3877c478bd9Sstevel@tonic-gate 		if (err == PAM_NO_MODULE_DATA) {
3887c478bd9Sstevel@tonic-gate 			/*
3897c478bd9Sstevel@tonic-gate 			 * pam_auth never called (possible config
390ed19839eSsemery 			 * error; no pam_krb5 auth entry in pam.conf),
3917c478bd9Sstevel@tonic-gate 			 */
392ed19839eSsemery 			if (debug) {
3933bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
3947c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (acct): no module data");
395ed19839eSsemery 			}
3967c478bd9Sstevel@tonic-gate 			err = PAM_IGNORE;
3977c478bd9Sstevel@tonic-gate 			goto out;
3987c478bd9Sstevel@tonic-gate 		} else {
3993bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
4007c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (acct): get module"
4013bfb48feSsemery 				    " data failed: err=%d",
4027c478bd9Sstevel@tonic-gate 			    err);
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		goto out;
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	debug = debug || kmd->debug;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * auth mod set status to ignore, most likely cuz root key is
4117c478bd9Sstevel@tonic-gate 	 * in keytab, so skip other checks and return ignore
4127c478bd9Sstevel@tonic-gate 	 */
4137c478bd9Sstevel@tonic-gate 	if (kmd->auth_status == PAM_IGNORE) {
4147c478bd9Sstevel@tonic-gate 		if (debug)
4153bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4167c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (acct): kmd auth_status is IGNORE");
4177c478bd9Sstevel@tonic-gate 		err = PAM_IGNORE;
4187c478bd9Sstevel@tonic-gate 		goto out;
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/*
422ed19839eSsemery 	 * If there is no Kerberos related user and there is authentication
423ed19839eSsemery 	 * data, this means that while the user has successfully passed
424ed19839eSsemery 	 * authentication, Kerberos is not the account authority because there
425ed19839eSsemery 	 * is no valid Kerberos principal.  PAM_IGNORE is returned since
426ed19839eSsemery 	 * Kerberos is not authoritative for this user.  Other modules in the
427ed19839eSsemery 	 * account stack will need to determine the success or failure for this
428ed19839eSsemery 	 * user.
4293bfb48feSsemery 	 */
4303bfb48feSsemery 	if (kmd->auth_status == PAM_USER_UNKNOWN) {
4313bfb48feSsemery 		if (debug)
4323bfb48feSsemery 			syslog(LOG_DEBUG,
4333bfb48feSsemery 			    "PAM-KRB5 (acct): kmd auth_status is USER UNKNOWN");
434ed19839eSsemery 		err = PAM_IGNORE;
4353bfb48feSsemery 		goto out;
4363bfb48feSsemery 	}
4373bfb48feSsemery 
4383bfb48feSsemery 	/*
4397c478bd9Sstevel@tonic-gate 	 * age_status will be set to PAM_NEW_AUTHTOK_REQD in pam_krb5's
4407c478bd9Sstevel@tonic-gate 	 * 'auth' if the user's key/pw has expired and needs to be changed
4417c478bd9Sstevel@tonic-gate 	 */
4427c478bd9Sstevel@tonic-gate 	if (kmd->age_status == PAM_NEW_AUTHTOK_REQD) {
4437c478bd9Sstevel@tonic-gate 		if (!nowarn) {
4447c478bd9Sstevel@tonic-gate 			(void) snprintf(messages[0], sizeof (messages[0]),
4457c478bd9Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN,
4467c478bd9Sstevel@tonic-gate 				"Your Kerberos password has expired.\n"));
4477c478bd9Sstevel@tonic-gate 			(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
4487c478bd9Sstevel@tonic-gate 					1, messages, NULL);
4497c478bd9Sstevel@tonic-gate 		}
4507c478bd9Sstevel@tonic-gate 		err = PAM_NEW_AUTHTOK_REQD;
4517c478bd9Sstevel@tonic-gate 		goto out;
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
454ed19839eSsemery 	if (kmd->auth_status == PAM_SUCCESS && !(flags & PAM_SILENT) &&
455ed19839eSsemery 	    !nowarn && kmd->password) {
4567c478bd9Sstevel@tonic-gate 		/* if we fail, let it slide, it's only a warning brah */
4573125ebfcSsemery 		(void) exp_warn(pamh, user, kmd, debug);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4603bfb48feSsemery 	/*
461ed19839eSsemery 	 * If Kerberos is treated as optional in the PAM stack, it is possible
462ed19839eSsemery 	 * that there is a KRB5_DATA item and a non-Kerberos account authority.
463ed19839eSsemery 	 * In that case, PAM_IGNORE is returned.
4643bfb48feSsemery 	 */
465ed19839eSsemery 	err = kmd->auth_status != PAM_SUCCESS ? PAM_IGNORE : kmd->auth_status;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate out:
4687c478bd9Sstevel@tonic-gate 	if (debug)
4693bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
4707c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (acct): end: %s", pam_strerror(pamh, err));
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	return (err);
4737c478bd9Sstevel@tonic-gate }
474