xref: /onnv-gate/usr/src/lib/pam_modules/krb5/krb5_setcred.c (revision 11780:26d2e4a6a702)
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  */
2111411SSurya.Prakki@Sun.COM 
220Sstevel@tonic-gate /*
23*11780SWill.Fiveash@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <libintl.h>
280Sstevel@tonic-gate #include <security/pam_appl.h>
290Sstevel@tonic-gate #include <security/pam_modules.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <pwd.h>
350Sstevel@tonic-gate #include <syslog.h>
360Sstevel@tonic-gate #include <libintl.h>
376924Sps57422 #include <k5-int.h>
380Sstevel@tonic-gate #include <netdb.h>
390Sstevel@tonic-gate #include <unistd.h>
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <fcntl.h>
42781Sgtb #include <errno.h>
430Sstevel@tonic-gate #include <com_err.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include "utils.h"
460Sstevel@tonic-gate #include "krb5_repository.h"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	PAMTXD			"SUNW_OST_SYSOSPAM"
490Sstevel@tonic-gate #define	KRB5_DEFAULT_LIFE	60*60*10  /* 10 hours */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate extern void krb5_cleanup(pam_handle_t *, void *, int);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int attempt_refresh_cred(krb5_module_data_t *, char *, int);
540Sstevel@tonic-gate static int attempt_delete_initcred(krb5_module_data_t *);
550Sstevel@tonic-gate static krb5_error_code krb5_renew_tgt(krb5_module_data_t *, krb5_principal,
560Sstevel@tonic-gate 		krb5_principal, int);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate extern uint_t kwarn_add_warning(char *, int);
590Sstevel@tonic-gate extern uint_t kwarn_del_warning(char *);
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * pam_sm_setcred
630Sstevel@tonic-gate  */
640Sstevel@tonic-gate int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)650Sstevel@tonic-gate pam_sm_setcred(
660Sstevel@tonic-gate 	pam_handle_t *pamh,
670Sstevel@tonic-gate 	int	flags,
680Sstevel@tonic-gate 	int	argc,
690Sstevel@tonic-gate 	const char **argv)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	int	i;
720Sstevel@tonic-gate 	int	err = 0;
730Sstevel@tonic-gate 	int	debug = 0;
740Sstevel@tonic-gate 	krb5_module_data_t	*kmd = NULL;
753391Ssemery 	char			*user = NULL;
760Sstevel@tonic-gate 	krb5_repository_data_t	*krb5_data = NULL;
770Sstevel@tonic-gate 	pam_repository_t	*rep_data = NULL;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
800Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
810Sstevel@tonic-gate 			debug = 1;
820Sstevel@tonic-gate 		else if (strcasecmp(argv[i], "nowarn") == 0)
830Sstevel@tonic-gate 			flags = flags | PAM_SILENT;
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if (debug)
873391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
880Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): start: nowarn = %d, flags = 0x%x",
890Sstevel@tonic-gate 		    flags & PAM_SILENT ? 1 : 0, flags);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	/* make sure flags are valid */
920Sstevel@tonic-gate 	if (flags &&
930Sstevel@tonic-gate 	    !(flags & PAM_ESTABLISH_CRED) &&
940Sstevel@tonic-gate 	    !(flags & PAM_REINITIALIZE_CRED) &&
950Sstevel@tonic-gate 	    !(flags & PAM_REFRESH_CRED) &&
960Sstevel@tonic-gate 	    !(flags & PAM_DELETE_CRED) &&
970Sstevel@tonic-gate 	    !(flags & PAM_SILENT)) {
983391Ssemery 		__pam_log(LOG_AUTH | LOG_ERR,
995890Sjjj 		    "PAM-KRB5 (setcred): illegal flag %d", flags);
1000Sstevel@tonic-gate 		err = PAM_SYSTEM_ERR;
1010Sstevel@tonic-gate 		goto out;
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1043391Ssemery 	(void) pam_get_item(pamh, PAM_USER, (void**) &user);
1050Sstevel@tonic-gate 
1063391Ssemery 	if (user == NULL || *user == '\0')
1073391Ssemery 		return (PAM_USER_UNKNOWN);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	if (pam_get_data(pamh, KRB5_DATA, (const void**)&kmd) != PAM_SUCCESS) {
1100Sstevel@tonic-gate 		if (debug) {
1113391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1120Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): kmd get failed, kmd=0x%p",
1130Sstevel@tonic-gate 			    kmd);
1140Sstevel@tonic-gate 		}
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 		/*
1170Sstevel@tonic-gate 		 * User  doesn't need to authenticate for PAM_REFRESH_CRED
1180Sstevel@tonic-gate 		 * or for PAM_DELETE_CRED
1190Sstevel@tonic-gate 		 */
1200Sstevel@tonic-gate 		if (flags & (PAM_REFRESH_CRED|PAM_DELETE_CRED)) {
1213391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1225890Sjjj 			    "PAM-KRB5 (setcred): inst kmd structure");
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 			kmd = calloc(1, sizeof (krb5_module_data_t));
1250Sstevel@tonic-gate 
1266488Ssemery 			if (kmd == NULL)
1276488Ssemery 				return (PAM_BUF_ERR);
1286488Ssemery 
1296488Ssemery 
1306488Ssemery 			/*
1316488Ssemery 			 * Need to initialize auth_status here to
1326488Ssemery 			 * PAM_AUTHINFO_UNAVAIL else there is a false positive
1336488Ssemery 			 * of PAM_SUCCESS.
1346488Ssemery 			 */
1356488Ssemery 			kmd->auth_status = PAM_AUTHINFO_UNAVAIL;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 			if ((err = pam_set_data(pamh, KRB5_DATA,
1385890Sjjj 			    kmd, &krb5_cleanup)) != PAM_SUCCESS) {
1390Sstevel@tonic-gate 				free(kmd);
1400Sstevel@tonic-gate 				return (PAM_SYSTEM_ERR);
1410Sstevel@tonic-gate 			}
1420Sstevel@tonic-gate 		} else {
1434621Ssemery 			/*
1444621Ssemery 			 * This could mean that we are not the account authority
1454621Ssemery 			 * for the authenticated user.  Therefore we should
1464621Ssemery 			 * return PAM_IGNORE in order to not affect the
1474621Ssemery 			 * login process of said user.
1484621Ssemery 			 */
1494621Ssemery 			err = PAM_IGNORE;
1504621Ssemery 			goto out;
1510Sstevel@tonic-gate 		}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	} else {  /* pam_get_data success */
1540Sstevel@tonic-gate 		if (kmd == NULL) {
1550Sstevel@tonic-gate 			if (debug) {
1563391Ssemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
1570Sstevel@tonic-gate 				    "PAM-KRB5 (setcred): kmd structure"
1580Sstevel@tonic-gate 				    " gotten but is NULL for user %s", user);
1590Sstevel@tonic-gate 			}
1606488Ssemery 			err = PAM_SYSTEM_ERR;
1610Sstevel@tonic-gate 			goto out;
1620Sstevel@tonic-gate 		}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		if (debug)
1653391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1660Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): kmd auth_status: %s",
1670Sstevel@tonic-gate 			    pam_strerror(pamh, kmd->auth_status));
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 		/*
1700Sstevel@tonic-gate 		 * pam_auth has set status to ignore, so we also return ignore
1710Sstevel@tonic-gate 		 */
1720Sstevel@tonic-gate 		if (kmd->auth_status == PAM_IGNORE) {
1730Sstevel@tonic-gate 			err = PAM_IGNORE;
1740Sstevel@tonic-gate 			goto out;
1750Sstevel@tonic-gate 		}
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	kmd->debug = debug;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/*
1810Sstevel@tonic-gate 	 * User must have passed pam_authenticate()
1820Sstevel@tonic-gate 	 * in order to use PAM_ESTABLISH_CRED or PAM_REINITIALIZE_CRED
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	if ((flags & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED)) &&
1850Sstevel@tonic-gate 	    (kmd->auth_status != PAM_SUCCESS)) {
1860Sstevel@tonic-gate 		if (kmd->debug)
1873391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1880Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
1890Sstevel@tonic-gate 			    "setcreds, not authenticated!");
1900Sstevel@tonic-gate 		return (PAM_CRED_UNAVAIL);
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/*
1940Sstevel@tonic-gate 	 * We cannot assume that kmd->kcontext being non-NULL
1950Sstevel@tonic-gate 	 * means it is valid.  Other pam_krb5 mods may have
1960Sstevel@tonic-gate 	 * freed it but not reset it to NULL.
1970Sstevel@tonic-gate 	 * Log a message when debugging to track down memory
1980Sstevel@tonic-gate 	 * leaks.
1990Sstevel@tonic-gate 	 */
2000Sstevel@tonic-gate 	if (kmd->kcontext != NULL && kmd->debug)
2013391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2025890Sjjj 		    "PAM-KRB5 (setcred): kcontext != NULL, "
2035890Sjjj 		    "possible memory leak.");
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/*
2063391Ssemery 	 * Use the authenticated and validated user, if applicable.
2073391Ssemery 	 */
2083391Ssemery 	if (kmd->user != NULL)
2093391Ssemery 		user = kmd->user;
2103391Ssemery 
2113391Ssemery 	/*
2120Sstevel@tonic-gate 	 * If auth was short-circuited we will not have anything to
2130Sstevel@tonic-gate 	 * renew, so just return here.
2140Sstevel@tonic-gate 	 */
2153391Ssemery 	(void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
2163391Ssemery 
2170Sstevel@tonic-gate 	if (rep_data != NULL) {
2180Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
2190Sstevel@tonic-gate 			if (debug)
2203391Ssemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
2215890Sjjj 				    "PAM-KRB5 (setcred): wrong"
2225890Sjjj 				    "repository found (%s), returning "
2235890Sjjj 				    "PAM_IGNORE", rep_data->type);
2240Sstevel@tonic-gate 			return (PAM_IGNORE);
2250Sstevel@tonic-gate 		}
2260Sstevel@tonic-gate 		if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
2270Sstevel@tonic-gate 			krb5_data = (krb5_repository_data_t *)rep_data->scope;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 			if (krb5_data->flags ==
2305890Sjjj 			    SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
2315890Sjjj 			    krb5_data->principal != NULL &&
2325890Sjjj 			    strlen(krb5_data->principal)) {
2330Sstevel@tonic-gate 				if (debug)
2343391Ssemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
2355890Sjjj 					    "PAM-KRB5 (setcred): "
2365890Sjjj 					    "Principal %s already "
2375890Sjjj 					    "authenticated, "
2385890Sjjj 					    "cannot setcred",
2395890Sjjj 					    krb5_data->principal);
2400Sstevel@tonic-gate 				return (PAM_SUCCESS);
2410Sstevel@tonic-gate 			}
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (flags & PAM_REINITIALIZE_CRED)
2460Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_REINITIALIZE_CRED);
2470Sstevel@tonic-gate 	else if (flags & PAM_REFRESH_CRED)
2480Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_REFRESH_CRED);
2490Sstevel@tonic-gate 	else if (flags & PAM_DELETE_CRED)
2500Sstevel@tonic-gate 		err = attempt_delete_initcred(kmd);
2510Sstevel@tonic-gate 	else {
2520Sstevel@tonic-gate 		/*
2530Sstevel@tonic-gate 		 * Default case:  PAM_ESTABLISH_CRED
2540Sstevel@tonic-gate 		 */
2550Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_ESTABLISH_CRED);
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2583391Ssemery 	if (err != PAM_SUCCESS)
2593391Ssemery 		__pam_log(LOG_AUTH | LOG_ERR,
2600Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): pam_setcred failed "
2610Sstevel@tonic-gate 		    "for %s (%s).", user, pam_strerror(pamh, err));
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate out:
2640Sstevel@tonic-gate 	if (kmd && kmd->kcontext) {
2650Sstevel@tonic-gate 		/*
2660Sstevel@tonic-gate 		 * free 'kcontext' field if it is allocated,
2670Sstevel@tonic-gate 		 * kcontext is local to the operation being performed
2680Sstevel@tonic-gate 		 * not considered global to the entire pam module.
2690Sstevel@tonic-gate 		 */
2700Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
2710Sstevel@tonic-gate 		kmd->kcontext = NULL;
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * 'kmd' is not freed here, it is handled in krb5_cleanup
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	if (debug)
2783391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2790Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): end: %s",
2800Sstevel@tonic-gate 		    pam_strerror(pamh, err));
2810Sstevel@tonic-gate 	return (err);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate static int
attempt_refresh_cred(krb5_module_data_t * kmd,char * user,int flag)2850Sstevel@tonic-gate attempt_refresh_cred(
2860Sstevel@tonic-gate 	krb5_module_data_t	*kmd,
2870Sstevel@tonic-gate 	char		*user,
2880Sstevel@tonic-gate 	int	flag)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	krb5_principal	me;
2910Sstevel@tonic-gate 	krb5_principal	server;
2920Sstevel@tonic-gate 	krb5_error_code	code;
2930Sstevel@tonic-gate 	char		kuser[2*MAXHOSTNAMELEN];
2940Sstevel@tonic-gate 	krb5_data tgtname = {
2950Sstevel@tonic-gate 		0,
2960Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
2970Sstevel@tonic-gate 		KRB5_TGS_NAME
2980Sstevel@tonic-gate 	};
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	/* Create a new context here. */
3018991SPeter.Shoults@Sun.COM 	if (krb5_init_secure_context(&kmd->kcontext) != 0) {
3020Sstevel@tonic-gate 		if (kmd->debug)
3033391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3040Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
3050Sstevel@tonic-gate 			    "initialize krb5 context");
3060Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if (krb5_cc_default(kmd->kcontext, &kmd->ccache) != 0) {
3103391Ssemery 		return (PAM_SYSTEM_ERR);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
3145890Sjjj 	    2*MAXHOSTNAMELEN)) != 0) {
3150Sstevel@tonic-gate 		return (code);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	if (krb5_parse_name(kmd->kcontext, kuser, &me) != 0) {
3193391Ssemery 		return (PAM_SYSTEM_ERR);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (code = krb5_build_principal_ext(kmd->kcontext, &server,
3235890Sjjj 	    krb5_princ_realm(kmd->kcontext, me)->length,
3245890Sjjj 	    krb5_princ_realm(kmd->kcontext, me)->data,
3255890Sjjj 	    tgtname.length, tgtname.data,
3265890Sjjj 	    krb5_princ_realm(kmd->kcontext, me)->length,
3275890Sjjj 	    krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
3283391Ssemery 		krb5_free_principal(kmd->kcontext, me);
3293391Ssemery 		return (PAM_SYSTEM_ERR);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	code = krb5_renew_tgt(kmd, me, server, flag);
3330Sstevel@tonic-gate 
3343391Ssemery 	krb5_free_principal(kmd->kcontext, server);
3353391Ssemery 	krb5_free_principal(kmd->kcontext, me);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	if (code) {
3383391Ssemery 		if (kmd->debug)
3393391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3405890Sjjj 			    "PAM-KRB5(setcred): krb5_renew_tgt() "
3415890Sjjj 			    "failed: %s", error_message((errcode_t)code));
3420Sstevel@tonic-gate 		return (PAM_CRED_ERR);
3430Sstevel@tonic-gate 	} else {
3440Sstevel@tonic-gate 		return (PAM_SUCCESS);
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate  * This code will update the credential matching "server" in the user's
3500Sstevel@tonic-gate  * credential cache.  The flag may be set to one of:
3518303SPeter.Shoults@Sun.COM  * PAM_REINITIALIZE_CRED/PAM_ESTABLISH_CRED - If we have new credentials then
3528303SPeter.Shoults@Sun.COM  *     create a new cred cache with these credentials else return failure.
3536488Ssemery  * PAM_REFRESH_CRED - If we have new credentials then create a new cred cache
3546488Ssemery  *  with these credentials else attempt to renew the credentials.
3556488Ssemery  *
3568303SPeter.Shoults@Sun.COM  * Note for any of the flags that if a new credential does exist from the
3578303SPeter.Shoults@Sun.COM  * previous auth pass then this will overwrite any existing credentials in the
3588303SPeter.Shoults@Sun.COM  * credential cache.
3590Sstevel@tonic-gate  */
3600Sstevel@tonic-gate static krb5_error_code
krb5_renew_tgt(krb5_module_data_t * kmd,krb5_principal me,krb5_principal server,int flag)3610Sstevel@tonic-gate krb5_renew_tgt(
3620Sstevel@tonic-gate 	krb5_module_data_t *kmd,
3630Sstevel@tonic-gate 	krb5_principal	me,
3640Sstevel@tonic-gate 	krb5_principal	server,
3650Sstevel@tonic-gate 	int	flag)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate 	krb5_error_code	retval;
3680Sstevel@tonic-gate 	krb5_creds	creds;
3693924Sgtb 	krb5_creds	*renewed_cred = NULL;
3700Sstevel@tonic-gate 	char		*client_name = NULL;
3718303SPeter.Shoults@Sun.COM 	char		*username = NULL;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate #define	my_creds	(kmd->initcreds)
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	if ((flag != PAM_REFRESH_CRED) &&
3765890Sjjj 	    (flag != PAM_REINITIALIZE_CRED) &&
3775890Sjjj 	    (flag != PAM_ESTABLISH_CRED))
3785890Sjjj 		return (KRB5KRB_ERR_GENERIC);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/* this is needed only for the ktkt_warnd */
3813391Ssemery 	if ((retval = krb5_unparse_name(kmd->kcontext, me, &client_name)) != 0)
3823391Ssemery 		return (retval);
3830Sstevel@tonic-gate 
3843924Sgtb 	(void) memset(&creds, 0, sizeof (krb5_creds));
3850Sstevel@tonic-gate 	if ((retval = krb5_copy_principal(kmd->kcontext,
3865890Sjjj 	    server, &creds.server))) {
3870Sstevel@tonic-gate 		if (kmd->debug)
3883391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3895890Sjjj 			    "PAM-KRB5 (setcred): krb5_copy_principal "
3905890Sjjj 			    "failed: %s",
3915890Sjjj 			    error_message((errcode_t)retval));
3920Sstevel@tonic-gate 		goto cleanup_creds;
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/* obtain ticket & session key */
3960Sstevel@tonic-gate 	retval = krb5_cc_get_principal(kmd->kcontext,
3975890Sjjj 	    kmd->ccache, &creds.client);
3980Sstevel@tonic-gate 	if (retval && (kmd->debug))
3993391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
4005890Sjjj 		    "PAM-KRB5 (setcred): User not in cred "
4015890Sjjj 		    "cache (%s)", error_message((errcode_t)retval));
4020Sstevel@tonic-gate 
4038303SPeter.Shoults@Sun.COM 	/*
4048303SPeter.Shoults@Sun.COM 	 * We got here either with the ESTABLISH | REINIT | REFRESH flag and
4058303SPeter.Shoults@Sun.COM 	 * auth_status returns SUCCESS or REFRESH and auth_status failure.
4068303SPeter.Shoults@Sun.COM 	 *
4078303SPeter.Shoults@Sun.COM 	 * Rules:
4088303SPeter.Shoults@Sun.COM 	 * - If the prior auth pass was successful then store the new
4098303SPeter.Shoults@Sun.COM 	 * credentials in the cache, regardless of which flag.
4108303SPeter.Shoults@Sun.COM 	 *
4118303SPeter.Shoults@Sun.COM 	 * - Else if REFRESH flag is used and there are no new
4128303SPeter.Shoults@Sun.COM 	 * credentials then attempt to refresh the existing credentials.
4138303SPeter.Shoults@Sun.COM 	 *
4148303SPeter.Shoults@Sun.COM 	 * - Note, refresh will not work if "R" flag is not set in
4158303SPeter.Shoults@Sun.COM 	 * original credential.  We don't want to 2nd guess the
4168303SPeter.Shoults@Sun.COM 	 * intention of the person who created the existing credential.
4178303SPeter.Shoults@Sun.COM 	 */
4188303SPeter.Shoults@Sun.COM 	if (kmd->auth_status == PAM_SUCCESS) {
4190Sstevel@tonic-gate 		/*
4200Sstevel@tonic-gate 		 * Create a fresh ccache, and store the credentials
4210Sstevel@tonic-gate 		 * we got from pam_authenticate()
4220Sstevel@tonic-gate 		 */
4230Sstevel@tonic-gate 		if ((retval = krb5_cc_initialize(kmd->kcontext,
4245890Sjjj 		    kmd->ccache, me)) != 0) {
4253391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4265890Sjjj 			    "PAM-KRB5 (setcred): krb5_cc_initialize "
4275890Sjjj 			    "failed: %s",
4285890Sjjj 			    error_message((errcode_t)retval));
4290Sstevel@tonic-gate 		} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
4305890Sjjj 		    kmd->ccache, &my_creds)) != 0) {
4313391Ssemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4325890Sjjj 			    "PAM-KRB5 (setcred): krb5_cc_store_cred "
4335890Sjjj 			    "failed: %s",
4345890Sjjj 			    error_message((errcode_t)retval));
4350Sstevel@tonic-gate 		}
4368303SPeter.Shoults@Sun.COM 	} else if ((retval == 0) && (flag & PAM_REFRESH_CRED)) {
4378303SPeter.Shoults@Sun.COM 		/*
4388303SPeter.Shoults@Sun.COM 		 * If we only wanted to refresh the creds but failed
4398303SPeter.Shoults@Sun.COM 		 * due to expiration, lack of "R" flag, or other
4408303SPeter.Shoults@Sun.COM 		 * problems, return an error.
4418303SPeter.Shoults@Sun.COM 		 */
4428303SPeter.Shoults@Sun.COM 		if (retval = krb5_get_credentials_renew(kmd->kcontext,
4438303SPeter.Shoults@Sun.COM 		    0, kmd->ccache, &creds, &renewed_cred)) {
4448303SPeter.Shoults@Sun.COM 			if (kmd->debug) {
4458303SPeter.Shoults@Sun.COM 				__pam_log(LOG_AUTH | LOG_DEBUG,
4468303SPeter.Shoults@Sun.COM 				    "PAM-KRB5 (setcred): "
4478303SPeter.Shoults@Sun.COM 				    "krb5_get_credentials"
4488303SPeter.Shoults@Sun.COM 				    "_renew(update) failed: %s",
4498303SPeter.Shoults@Sun.COM 				    error_message((errcode_t)retval));
4508303SPeter.Shoults@Sun.COM 			}
4518303SPeter.Shoults@Sun.COM 		}
4528303SPeter.Shoults@Sun.COM 	} else {
4530Sstevel@tonic-gate 		/*
4540Sstevel@tonic-gate 		 * We failed to get the user's credentials.
4550Sstevel@tonic-gate 		 * This might be due to permission error on the cache,
4560Sstevel@tonic-gate 		 * or maybe we are looking in the wrong cache file!
4570Sstevel@tonic-gate 		 */
4583391Ssemery 		__pam_log(LOG_AUTH | LOG_ERR,
4595890Sjjj 		    "PAM-KRB5 (setcred): Cannot find creds"
4605890Sjjj 		    " for %s (%s)",
4615890Sjjj 		    client_name ? client_name : "(unknown)",
4625890Sjjj 		    error_message((errcode_t)retval));
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate cleanup_creds:
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if ((retval == 0) && (client_name != NULL)) {
4680Sstevel@tonic-gate 		/*
4690Sstevel@tonic-gate 		 * Credential update was successful!
4700Sstevel@tonic-gate 		 *
4710Sstevel@tonic-gate 		 * We now chown the ccache to the appropriate uid/gid
4720Sstevel@tonic-gate 		 * combination, if its a FILE based ccache.
4730Sstevel@tonic-gate 		 */
4746924Sps57422 		if (!kmd->env || strstr(kmd->env, "FILE:")) {
4750Sstevel@tonic-gate 			uid_t uuid;
4760Sstevel@tonic-gate 			gid_t ugid;
4778303SPeter.Shoults@Sun.COM 			char *tmpname = NULL;
4780Sstevel@tonic-gate 			char *filepath = NULL;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 			username = strdup(client_name);
4815890Sjjj 			if (username == NULL) {
4825890Sjjj 				__pam_log(LOG_AUTH | LOG_ERR,
4835890Sjjj 				    "PAM-KRB5 (setcred): Out of memory");
4845890Sjjj 				retval = KRB5KRB_ERR_GENERIC;
4855890Sjjj 				goto error;
4865890Sjjj 			}
4870Sstevel@tonic-gate 			if ((tmpname = strchr(username, '@')))
4880Sstevel@tonic-gate 				*tmpname = '\0';
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 			if (get_pw_uid(username, &uuid) == 0 ||
4910Sstevel@tonic-gate 			    get_pw_gid(username, &ugid) == 0) {
4923391Ssemery 				__pam_log(LOG_AUTH | LOG_ERR,
4933391Ssemery 				    "PAM-KRB5 (setcred): Unable to "
4940Sstevel@tonic-gate 				    "find matching uid/gid pair for user `%s'",
4950Sstevel@tonic-gate 				    username);
4963924Sgtb 				retval = KRB5KRB_ERR_GENERIC;
4973924Sgtb 				goto error;
4980Sstevel@tonic-gate 			}
4996924Sps57422 
5006924Sps57422 			if (!kmd->env) {
5016924Sps57422 				char buffer[512];
5026924Sps57422 
5036924Sps57422 				if (snprintf(buffer, sizeof (buffer),
5046924Sps57422 				    "%s=FILE:/tmp/krb5cc_%d", KRB5_ENV_CCNAME,
5056924Sps57422 				    (int)uuid) >= sizeof (buffer)) {
5066924Sps57422 					retval = KRB5KRB_ERR_GENERIC;
5076924Sps57422 					goto error;
5086924Sps57422 				}
5096924Sps57422 
5106924Sps57422 				/*
5116924Sps57422 				 * We MUST copy this to the heap for the putenv
5126924Sps57422 				 * to work!
5136924Sps57422 				 */
5146924Sps57422 				kmd->env = strdup(buffer);
5156924Sps57422 				if (!kmd->env) {
5166924Sps57422 					retval = ENOMEM;
5176924Sps57422 					goto error;
5186924Sps57422 				} else {
5196924Sps57422 					if (putenv(kmd->env)) {
5206924Sps57422 						retval = ENOMEM;
5216924Sps57422 						goto error;
5226924Sps57422 					}
5236924Sps57422 				}
5246924Sps57422 			}
5256924Sps57422 
5268303SPeter.Shoults@Sun.COM 			/*
5278303SPeter.Shoults@Sun.COM 			 * We know at this point that kmd->env must start
5288303SPeter.Shoults@Sun.COM 			 * with the literal string "FILE:".  Set filepath
5298303SPeter.Shoults@Sun.COM 			 * character string to point to ":"
5308303SPeter.Shoults@Sun.COM 			 */
5318303SPeter.Shoults@Sun.COM 
5328303SPeter.Shoults@Sun.COM 			filepath = strchr(kmd->env, ':');
5338303SPeter.Shoults@Sun.COM 
5348303SPeter.Shoults@Sun.COM 			/*
5358303SPeter.Shoults@Sun.COM 			 * Now check if first char after ":" is null char
5368303SPeter.Shoults@Sun.COM 			 */
5378303SPeter.Shoults@Sun.COM 			if (filepath[1] == '\0') {
5383391Ssemery 				__pam_log(LOG_AUTH | LOG_ERR,
5395890Sjjj 				    "PAM-KRB5 (setcred): Invalid pathname "
5405890Sjjj 				    "for credential cache of user `%s'",
5415890Sjjj 				    username);
5423924Sgtb 				retval = KRB5KRB_ERR_GENERIC;
5433924Sgtb 				goto error;
5440Sstevel@tonic-gate 			}
5450Sstevel@tonic-gate 			if (chown(filepath+1, uuid, ugid)) {
5460Sstevel@tonic-gate 				if (kmd->debug)
5473391Ssemery 					__pam_log(LOG_AUTH | LOG_DEBUG,
5480Sstevel@tonic-gate 					    "PAM-KRB5 (setcred): chown to user "
5490Sstevel@tonic-gate 					    "`%s' failed for FILE=%s",
5500Sstevel@tonic-gate 					    username, filepath);
5510Sstevel@tonic-gate 			}
5520Sstevel@tonic-gate 		}
5533924Sgtb 	}
5540Sstevel@tonic-gate 
5553924Sgtb error:
5563924Sgtb 	if (retval == 0) {
5573924Sgtb 		krb5_timestamp endtime;
5583924Sgtb 
5593924Sgtb 		if (renewed_cred && renewed_cred->times.endtime != 0)
5603924Sgtb 			endtime = renewed_cred->times.endtime;
5613924Sgtb 		else
5623924Sgtb 			endtime = my_creds.times.endtime;
5633924Sgtb 
5643924Sgtb 		if (kmd->debug)
5653924Sgtb 			__pam_log(LOG_AUTH | LOG_DEBUG,
5665890Sjjj 			    "PAM-KRB5 (setcred): delete/add warning");
5673924Sgtb 
568*11780SWill.Fiveash@Sun.COM 		if (kwarn_del_warning(client_name) != 0) {
569*11780SWill.Fiveash@Sun.COM 			__pam_log(LOG_AUTH | LOG_NOTICE,
570*11780SWill.Fiveash@Sun.COM 			    "PAM-KRB5 (setcred): kwarn_del_warning"
571*11780SWill.Fiveash@Sun.COM 			    " failed: ktkt_warnd(1M) down?");
572*11780SWill.Fiveash@Sun.COM 		}
573*11780SWill.Fiveash@Sun.COM 
5743924Sgtb 		if (kwarn_add_warning(client_name, endtime) != 0) {
5753924Sgtb 			__pam_log(LOG_AUTH | LOG_NOTICE,
5765890Sjjj 			    "PAM-KRB5 (setcred): kwarn_add_warning"
5775890Sjjj 			    " failed: ktkt_warnd(1M) down?");
5780Sstevel@tonic-gate 		}
5790Sstevel@tonic-gate 	}
5803924Sgtb 
5813924Sgtb 	if (renewed_cred != NULL)
5823924Sgtb 		krb5_free_creds(kmd->kcontext, renewed_cred);
5833924Sgtb 
5840Sstevel@tonic-gate 	if (client_name != NULL)
5850Sstevel@tonic-gate 		free(client_name);
5860Sstevel@tonic-gate 
5878303SPeter.Shoults@Sun.COM 	if (username)
5888303SPeter.Shoults@Sun.COM 		free(username);
5898303SPeter.Shoults@Sun.COM 
5900Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &creds);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	return (retval);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate  * Delete the user's credentials for this session
5970Sstevel@tonic-gate  */
5980Sstevel@tonic-gate static int
attempt_delete_initcred(krb5_module_data_t * kmd)5990Sstevel@tonic-gate attempt_delete_initcred(krb5_module_data_t *kmd)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	if (kmd == NULL)
6023391Ssemery 		return (PAM_SUCCESS);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (kmd->debug) {
6053391Ssemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
6065890Sjjj 		    "PAM-KRB5 (setcred): deleting user's "
6075890Sjjj 		    "credentials (initcreds)");
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
6100Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
6110Sstevel@tonic-gate 	kmd->auth_status = PAM_AUTHINFO_UNAVAIL;
6123391Ssemery 	return (PAM_SUCCESS);
6130Sstevel@tonic-gate }
614