1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <libintl.h>
30*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
31*7c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <pwd.h>
37*7c478bd9Sstevel@tonic-gate #include <syslog.h>
38*7c478bd9Sstevel@tonic-gate #include <libintl.h>
39*7c478bd9Sstevel@tonic-gate #include <krb5.h>
40*7c478bd9Sstevel@tonic-gate #include <netdb.h>
41*7c478bd9Sstevel@tonic-gate #include <unistd.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
43*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <com_err.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #include "utils.h"
47*7c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #define	PAMTXD			"SUNW_OST_SYSOSPAM"
50*7c478bd9Sstevel@tonic-gate #define	KRB5_DEFAULT_LIFE	60*60*10  /* 10 hours */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate extern void krb5_cleanup(pam_handle_t *, void *, int);
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static int attempt_refresh_cred(krb5_module_data_t *, char *, int);
55*7c478bd9Sstevel@tonic-gate static int attempt_delete_initcred(krb5_module_data_t *);
56*7c478bd9Sstevel@tonic-gate static krb5_error_code krb5_renew_tgt(krb5_module_data_t *, krb5_principal,
57*7c478bd9Sstevel@tonic-gate 		krb5_principal, int);
58*7c478bd9Sstevel@tonic-gate static krb5_boolean creds_match(krb5_context, const krb5_creds *,
59*7c478bd9Sstevel@tonic-gate 	const krb5_creds *);
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate extern uint_t kwarn_add_warning(char *, int);
62*7c478bd9Sstevel@tonic-gate extern uint_t kwarn_del_warning(char *);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * pam_sm_setcred
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate int
68*7c478bd9Sstevel@tonic-gate pam_sm_setcred(
69*7c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh,
70*7c478bd9Sstevel@tonic-gate 	int	flags,
71*7c478bd9Sstevel@tonic-gate 	int	argc,
72*7c478bd9Sstevel@tonic-gate 	const char **argv)
73*7c478bd9Sstevel@tonic-gate {
74*7c478bd9Sstevel@tonic-gate 	int	i;
75*7c478bd9Sstevel@tonic-gate 	int	err = 0;
76*7c478bd9Sstevel@tonic-gate 	int	debug = 0;
77*7c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd = NULL;
78*7c478bd9Sstevel@tonic-gate 	char			*user;
79*7c478bd9Sstevel@tonic-gate 	int			result;
80*7c478bd9Sstevel@tonic-gate 	krb5_repository_data_t	*krb5_data = NULL;
81*7c478bd9Sstevel@tonic-gate 	pam_repository_t	*rep_data = NULL;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
84*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
85*7c478bd9Sstevel@tonic-gate 			debug = 1;
86*7c478bd9Sstevel@tonic-gate 		else if (strcasecmp(argv[i], "nowarn") == 0)
87*7c478bd9Sstevel@tonic-gate 			flags = flags | PAM_SILENT;
88*7c478bd9Sstevel@tonic-gate 	}
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	if (debug)
91*7c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG,
92*7c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): start: nowarn = %d, flags = 0x%x",
93*7c478bd9Sstevel@tonic-gate 		    flags & PAM_SILENT ? 1 : 0, flags);
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	/* make sure flags are valid */
96*7c478bd9Sstevel@tonic-gate 	if (flags &&
97*7c478bd9Sstevel@tonic-gate 	    !(flags & PAM_ESTABLISH_CRED) &&
98*7c478bd9Sstevel@tonic-gate 	    !(flags & PAM_REINITIALIZE_CRED) &&
99*7c478bd9Sstevel@tonic-gate 	    !(flags & PAM_REFRESH_CRED) &&
100*7c478bd9Sstevel@tonic-gate 	    !(flags & PAM_DELETE_CRED) &&
101*7c478bd9Sstevel@tonic-gate 	    !(flags & PAM_SILENT)) {
102*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
103*7c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN,
104*7c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): illegal flag %d"), flags);
105*7c478bd9Sstevel@tonic-gate 		err = PAM_SYSTEM_ERR;
106*7c478bd9Sstevel@tonic-gate 		goto out;
107*7c478bd9Sstevel@tonic-gate 	}
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	err = pam_get_item(pamh, PAM_USER, (void**) &user);
110*7c478bd9Sstevel@tonic-gate 	if (err != PAM_SUCCESS)
111*7c478bd9Sstevel@tonic-gate 		return (err);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (user == NULL || !user[0])
114*7c478bd9Sstevel@tonic-gate 		return (PAM_AUTH_ERR);
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (pam_get_data(pamh, KRB5_DATA, (const void**)&kmd) != PAM_SUCCESS) {
117*7c478bd9Sstevel@tonic-gate 		if (debug) {
118*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
119*7c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): kmd get failed, kmd=0x%p",
120*7c478bd9Sstevel@tonic-gate 			    kmd);
121*7c478bd9Sstevel@tonic-gate 		}
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 		/*
124*7c478bd9Sstevel@tonic-gate 		 * User  doesn't need to authenticate for PAM_REFRESH_CRED
125*7c478bd9Sstevel@tonic-gate 		 * or for PAM_DELETE_CRED
126*7c478bd9Sstevel@tonic-gate 		 */
127*7c478bd9Sstevel@tonic-gate 		if (flags & (PAM_REFRESH_CRED|PAM_DELETE_CRED)) {
128*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
129*7c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): inst kmd structure");
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 			kmd = calloc(1, sizeof (krb5_module_data_t));
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 			if (kmd == NULL) {
134*7c478bd9Sstevel@tonic-gate 				result = PAM_BUF_ERR;
135*7c478bd9Sstevel@tonic-gate 				return (result);
136*7c478bd9Sstevel@tonic-gate 			}
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 			if ((err = pam_set_data(pamh, KRB5_DATA,
139*7c478bd9Sstevel@tonic-gate 				kmd, &krb5_cleanup)) != PAM_SUCCESS) {
140*7c478bd9Sstevel@tonic-gate 				free(kmd);
141*7c478bd9Sstevel@tonic-gate 				return (PAM_SYSTEM_ERR);
142*7c478bd9Sstevel@tonic-gate 			}
143*7c478bd9Sstevel@tonic-gate 		} else {
144*7c478bd9Sstevel@tonic-gate 				err = PAM_CRED_UNAVAIL;
145*7c478bd9Sstevel@tonic-gate 				goto out;
146*7c478bd9Sstevel@tonic-gate 		}
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	} else {  /* pam_get_data success */
149*7c478bd9Sstevel@tonic-gate 		if (kmd == NULL) {
150*7c478bd9Sstevel@tonic-gate 			if (debug) {
151*7c478bd9Sstevel@tonic-gate 				syslog(LOG_DEBUG,
152*7c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (setcred): kmd structure"
153*7c478bd9Sstevel@tonic-gate 				    " gotten but is NULL for user %s", user);
154*7c478bd9Sstevel@tonic-gate 			}
155*7c478bd9Sstevel@tonic-gate 			err = PAM_CRED_UNAVAIL;
156*7c478bd9Sstevel@tonic-gate 			goto out;
157*7c478bd9Sstevel@tonic-gate 		}
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 		if (debug)
160*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
161*7c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): kmd auth_status: %s",
162*7c478bd9Sstevel@tonic-gate 			    pam_strerror(pamh, kmd->auth_status));
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 		/*
165*7c478bd9Sstevel@tonic-gate 		 * pam_auth has set status to ignore, so we also return ignore
166*7c478bd9Sstevel@tonic-gate 		 */
167*7c478bd9Sstevel@tonic-gate 		if (kmd->auth_status == PAM_IGNORE) {
168*7c478bd9Sstevel@tonic-gate 			err = PAM_IGNORE;
169*7c478bd9Sstevel@tonic-gate 			goto out;
170*7c478bd9Sstevel@tonic-gate 		}
171*7c478bd9Sstevel@tonic-gate 	}
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	kmd->debug = debug;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	/*
177*7c478bd9Sstevel@tonic-gate 	 * User must have passed pam_authenticate()
178*7c478bd9Sstevel@tonic-gate 	 * in order to use PAM_ESTABLISH_CRED or PAM_REINITIALIZE_CRED
179*7c478bd9Sstevel@tonic-gate 	 */
180*7c478bd9Sstevel@tonic-gate 	if ((flags & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED)) &&
181*7c478bd9Sstevel@tonic-gate 	    (kmd->auth_status != PAM_SUCCESS)) {
182*7c478bd9Sstevel@tonic-gate 		if (kmd->debug)
183*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
184*7c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
185*7c478bd9Sstevel@tonic-gate 			    "setcreds, not authenticated!");
186*7c478bd9Sstevel@tonic-gate 		return (PAM_CRED_UNAVAIL);
187*7c478bd9Sstevel@tonic-gate 	}
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	/*
190*7c478bd9Sstevel@tonic-gate 	 * We cannot assume that kmd->kcontext being non-NULL
191*7c478bd9Sstevel@tonic-gate 	 * means it is valid.  Other pam_krb5 mods may have
192*7c478bd9Sstevel@tonic-gate 	 * freed it but not reset it to NULL.
193*7c478bd9Sstevel@tonic-gate 	 * Log a message when debugging to track down memory
194*7c478bd9Sstevel@tonic-gate 	 * leaks.
195*7c478bd9Sstevel@tonic-gate 	 */
196*7c478bd9Sstevel@tonic-gate 	if (kmd->kcontext != NULL && kmd->debug)
197*7c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG,
198*7c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): kcontext != NULL, "
199*7c478bd9Sstevel@tonic-gate 			"possible memory leak.");
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	/*
202*7c478bd9Sstevel@tonic-gate 	 * If auth was short-circuited we will not have anything to
203*7c478bd9Sstevel@tonic-gate 	 * renew, so just return here.
204*7c478bd9Sstevel@tonic-gate 	 */
205*7c478bd9Sstevel@tonic-gate 	err = pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
206*7c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
207*7c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
208*7c478bd9Sstevel@tonic-gate 			if (debug)
209*7c478bd9Sstevel@tonic-gate 				syslog(LOG_DEBUG, "PAM-KRB5 (setcred): wrong"
210*7c478bd9Sstevel@tonic-gate 					"repository found (%s), returning "
211*7c478bd9Sstevel@tonic-gate 					"PAM_IGNORE", rep_data->type);
212*7c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
213*7c478bd9Sstevel@tonic-gate 		}
214*7c478bd9Sstevel@tonic-gate 		if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
215*7c478bd9Sstevel@tonic-gate 			krb5_data = (krb5_repository_data_t *)rep_data->scope;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 			if (krb5_data->flags ==
218*7c478bd9Sstevel@tonic-gate 				SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
219*7c478bd9Sstevel@tonic-gate 				krb5_data->principal != NULL &&
220*7c478bd9Sstevel@tonic-gate 				strlen(krb5_data->principal)) {
221*7c478bd9Sstevel@tonic-gate 				if (debug)
222*7c478bd9Sstevel@tonic-gate 					syslog(LOG_DEBUG,
223*7c478bd9Sstevel@tonic-gate 						"PAM-KRB5 (setcred): "
224*7c478bd9Sstevel@tonic-gate 						"Principal %s already "
225*7c478bd9Sstevel@tonic-gate 						"authenticated, "
226*7c478bd9Sstevel@tonic-gate 						"cannot setcred",
227*7c478bd9Sstevel@tonic-gate 						krb5_data->principal);
228*7c478bd9Sstevel@tonic-gate 				return (PAM_SUCCESS);
229*7c478bd9Sstevel@tonic-gate 			}
230*7c478bd9Sstevel@tonic-gate 		}
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	if (flags & PAM_REINITIALIZE_CRED)
234*7c478bd9Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_REINITIALIZE_CRED);
235*7c478bd9Sstevel@tonic-gate 	else if (flags & PAM_REFRESH_CRED)
236*7c478bd9Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_REFRESH_CRED);
237*7c478bd9Sstevel@tonic-gate 	else if (flags & PAM_DELETE_CRED)
238*7c478bd9Sstevel@tonic-gate 		err = attempt_delete_initcred(kmd);
239*7c478bd9Sstevel@tonic-gate 	else {
240*7c478bd9Sstevel@tonic-gate 		/*
241*7c478bd9Sstevel@tonic-gate 		 * Default case:  PAM_ESTABLISH_CRED
242*7c478bd9Sstevel@tonic-gate 		 */
243*7c478bd9Sstevel@tonic-gate 		err = attempt_refresh_cred(kmd, user, PAM_ESTABLISH_CRED);
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	if (err)
247*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
248*7c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): pam_setcred failed "
249*7c478bd9Sstevel@tonic-gate 		    "for %s (%s).", user, pam_strerror(pamh, err));
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate out:
252*7c478bd9Sstevel@tonic-gate 	if (kmd && kmd->kcontext) {
253*7c478bd9Sstevel@tonic-gate 		/*
254*7c478bd9Sstevel@tonic-gate 		 * free 'kcontext' field if it is allocated,
255*7c478bd9Sstevel@tonic-gate 		 * kcontext is local to the operation being performed
256*7c478bd9Sstevel@tonic-gate 		 * not considered global to the entire pam module.
257*7c478bd9Sstevel@tonic-gate 		 */
258*7c478bd9Sstevel@tonic-gate 		krb5_free_context(kmd->kcontext);
259*7c478bd9Sstevel@tonic-gate 		kmd->kcontext = NULL;
260*7c478bd9Sstevel@tonic-gate 	}
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	/*
263*7c478bd9Sstevel@tonic-gate 	 * 'kmd' is not freed here, it is handled in krb5_cleanup
264*7c478bd9Sstevel@tonic-gate 	 */
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	if (debug)
268*7c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG,
269*7c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (setcred): end: %s",
270*7c478bd9Sstevel@tonic-gate 		    pam_strerror(pamh, err));
271*7c478bd9Sstevel@tonic-gate 	return (err);
272*7c478bd9Sstevel@tonic-gate }
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate static int
275*7c478bd9Sstevel@tonic-gate attempt_refresh_cred(
276*7c478bd9Sstevel@tonic-gate 	krb5_module_data_t	*kmd,
277*7c478bd9Sstevel@tonic-gate 	char		*user,
278*7c478bd9Sstevel@tonic-gate 	int	flag)
279*7c478bd9Sstevel@tonic-gate {
280*7c478bd9Sstevel@tonic-gate 	krb5_principal	me;
281*7c478bd9Sstevel@tonic-gate 	krb5_principal	server;
282*7c478bd9Sstevel@tonic-gate 	krb5_error_code	code;
283*7c478bd9Sstevel@tonic-gate 	char		kuser[2*MAXHOSTNAMELEN];
284*7c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
285*7c478bd9Sstevel@tonic-gate 		0,
286*7c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
287*7c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
288*7c478bd9Sstevel@tonic-gate 	};
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* User must have passed pam_authenticate() */
291*7c478bd9Sstevel@tonic-gate 	if (kmd->auth_status != PAM_SUCCESS) {
292*7c478bd9Sstevel@tonic-gate 		if (kmd->debug)
293*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
294*7c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
295*7c478bd9Sstevel@tonic-gate 			    "setcreds, not authenticated!");
296*7c478bd9Sstevel@tonic-gate 		return (PAM_CRED_UNAVAIL);
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	/* Create a new context here. */
300*7c478bd9Sstevel@tonic-gate 	if (krb5_init_context(&kmd->kcontext) != 0) {
301*7c478bd9Sstevel@tonic-gate 		if (kmd->debug)
302*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
303*7c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (setcred): unable to "
304*7c478bd9Sstevel@tonic-gate 			    "initialize krb5 context");
305*7c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	if (krb5_cc_default(kmd->kcontext, &kmd->ccache) != 0) {
309*7c478bd9Sstevel@tonic-gate 		return (PAM_CRED_ERR);
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
313*7c478bd9Sstevel@tonic-gate 		2*MAXHOSTNAMELEN)) != 0) {
314*7c478bd9Sstevel@tonic-gate 		return (code);
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	if (krb5_parse_name(kmd->kcontext, kuser, &me) != 0) {
318*7c478bd9Sstevel@tonic-gate 		return (PAM_CRED_ERR);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (code = krb5_build_principal_ext(kmd->kcontext, &server,
322*7c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
323*7c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data,
324*7c478bd9Sstevel@tonic-gate 			    tgtname.length, tgtname.data,
325*7c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->length,
326*7c478bd9Sstevel@tonic-gate 			    krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
327*7c478bd9Sstevel@tonic-gate 		code = PAM_CRED_ERR;
328*7c478bd9Sstevel@tonic-gate 		goto out;
329*7c478bd9Sstevel@tonic-gate 	}
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	code = krb5_renew_tgt(kmd, me, server, flag);
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate out:
334*7c478bd9Sstevel@tonic-gate 	if (server)
335*7c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, server);
336*7c478bd9Sstevel@tonic-gate 	if (me)
337*7c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, me);
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if (code) {
340*7c478bd9Sstevel@tonic-gate 		return (PAM_CRED_ERR);
341*7c478bd9Sstevel@tonic-gate 	} else {
342*7c478bd9Sstevel@tonic-gate 		return (PAM_SUCCESS);
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate /*
347*7c478bd9Sstevel@tonic-gate  * This code will update the credential matching "server" in the user's
348*7c478bd9Sstevel@tonic-gate  * credential cache.  The flag may be set to one of:
349*7c478bd9Sstevel@tonic-gate  * PAM_ESTABLISH_CRED -  Create a new cred cache if one doesnt exist,
350*7c478bd9Sstevel@tonic-gate  *                       else refresh the existing one.
351*7c478bd9Sstevel@tonic-gate  * PAM_REINITIALIZE_CRED  - destroy current cred cache and create a new one
352*7c478bd9Sstevel@tonic-gate  * PAM_REFRESH_CRED  - update the existing cred cache (default action)
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate static krb5_error_code
355*7c478bd9Sstevel@tonic-gate krb5_renew_tgt(
356*7c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd,
357*7c478bd9Sstevel@tonic-gate 	krb5_principal	me,
358*7c478bd9Sstevel@tonic-gate 	krb5_principal	server,
359*7c478bd9Sstevel@tonic-gate 	int	flag)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
362*7c478bd9Sstevel@tonic-gate 	krb5_creds	creds;
363*7c478bd9Sstevel@tonic-gate 	krb5_creds	*credsp = &creds;
364*7c478bd9Sstevel@tonic-gate 	char		*client_name = NULL;
365*7c478bd9Sstevel@tonic-gate 	typedef struct _cred_node {
366*7c478bd9Sstevel@tonic-gate 		krb5_creds		*creds;
367*7c478bd9Sstevel@tonic-gate 		struct _cred_node	*next;
368*7c478bd9Sstevel@tonic-gate 	} cred_node;
369*7c478bd9Sstevel@tonic-gate 	cred_node *cred_list_head = NULL;
370*7c478bd9Sstevel@tonic-gate 	cred_node *fetched = NULL;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate #define	my_creds	(kmd->initcreds)
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	if ((flag != PAM_REFRESH_CRED) &&
375*7c478bd9Sstevel@tonic-gate 		(flag != PAM_REINITIALIZE_CRED) &&
376*7c478bd9Sstevel@tonic-gate 		(flag != PAM_ESTABLISH_CRED))
377*7c478bd9Sstevel@tonic-gate 			return (PAM_SYSTEM_ERR);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/* this is needed only for the ktkt_warnd */
380*7c478bd9Sstevel@tonic-gate 	if (krb5_unparse_name(kmd->kcontext, me, &client_name) != 0) {
381*7c478bd9Sstevel@tonic-gate 		krb5_free_principal(kmd->kcontext, me);
382*7c478bd9Sstevel@tonic-gate 		return (PAM_CRED_ERR);
383*7c478bd9Sstevel@tonic-gate 	}
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)credsp, 0, sizeof (krb5_creds));
386*7c478bd9Sstevel@tonic-gate 	if ((retval = krb5_copy_principal(kmd->kcontext,
387*7c478bd9Sstevel@tonic-gate 				server, &credsp->server))) {
388*7c478bd9Sstevel@tonic-gate 		if (kmd->debug)
389*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
390*7c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_copy_principal "
391*7c478bd9Sstevel@tonic-gate 				"failed: %s",
392*7c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
393*7c478bd9Sstevel@tonic-gate 		goto cleanup_creds;
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	/* obtain ticket & session key */
397*7c478bd9Sstevel@tonic-gate 	retval = krb5_cc_get_principal(kmd->kcontext,
398*7c478bd9Sstevel@tonic-gate 				kmd->ccache, &credsp->client);
399*7c478bd9Sstevel@tonic-gate 	if (retval && (kmd->debug))
400*7c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG,
401*7c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
402*7c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): User not in cred "
403*7c478bd9Sstevel@tonic-gate 			"cache (%s)"), error_message((errcode_t)retval));
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	if ((retval == KRB5_FCC_NOFILE) &&
406*7c478bd9Sstevel@tonic-gate 		(flag & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED))) {
407*7c478bd9Sstevel@tonic-gate 		/*
408*7c478bd9Sstevel@tonic-gate 		 * Create a fresh ccache, and store the credentials
409*7c478bd9Sstevel@tonic-gate 		 * we got from pam_authenticate()
410*7c478bd9Sstevel@tonic-gate 		 */
411*7c478bd9Sstevel@tonic-gate 		if ((retval = krb5_cc_initialize(kmd->kcontext,
412*7c478bd9Sstevel@tonic-gate 				kmd->ccache, me)) != 0) {
413*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
414*7c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_cc_initialize "
415*7c478bd9Sstevel@tonic-gate 				"failed: %s",
416*7c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
417*7c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
418*7c478bd9Sstevel@tonic-gate 		} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
419*7c478bd9Sstevel@tonic-gate 				kmd->ccache, &my_creds)) != 0) {
420*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
421*7c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_cc_store_cred "
422*7c478bd9Sstevel@tonic-gate 				"failed: %s",
423*7c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
424*7c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
425*7c478bd9Sstevel@tonic-gate 		}
426*7c478bd9Sstevel@tonic-gate 	} else if (retval) {
427*7c478bd9Sstevel@tonic-gate 		/*
428*7c478bd9Sstevel@tonic-gate 		 * We failed to get the user's credentials.
429*7c478bd9Sstevel@tonic-gate 		 * This might be due to permission error on the cache,
430*7c478bd9Sstevel@tonic-gate 		 * or maybe we are looking in the wrong cache file!
431*7c478bd9Sstevel@tonic-gate 		 */
432*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
433*7c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
434*7c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): Cannot find creds"
435*7c478bd9Sstevel@tonic-gate 			" for %s (%s)"),
436*7c478bd9Sstevel@tonic-gate 			client_name ? client_name : "(unknown)",
437*7c478bd9Sstevel@tonic-gate 			error_message((errcode_t)retval));
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	} else if (flag & PAM_REINITIALIZE_CRED) {
440*7c478bd9Sstevel@tonic-gate 		/*
441*7c478bd9Sstevel@tonic-gate 		 * This destroys the credential cache, and stores a new
442*7c478bd9Sstevel@tonic-gate 		 * krbtgt with updated startime, endtime and renewable
443*7c478bd9Sstevel@tonic-gate 		 * lifetime.
444*7c478bd9Sstevel@tonic-gate 		 */
445*7c478bd9Sstevel@tonic-gate 		creds.times.starttime = my_creds.times.starttime;
446*7c478bd9Sstevel@tonic-gate 		creds.times.endtime = my_creds.times.endtime;
447*7c478bd9Sstevel@tonic-gate 		creds.times.renew_till = my_creds.times.renew_till;
448*7c478bd9Sstevel@tonic-gate 		if ((retval = krb5_get_credentials_renew(kmd->kcontext, 0,
449*7c478bd9Sstevel@tonic-gate 					kmd->ccache, &creds, &credsp))) {
450*7c478bd9Sstevel@tonic-gate 			if (kmd->debug)
451*7c478bd9Sstevel@tonic-gate 			    syslog(LOG_DEBUG,
452*7c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_get_credentials",
453*7c478bd9Sstevel@tonic-gate 				"_renew(reinitialize) failed: %s",
454*7c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
455*7c478bd9Sstevel@tonic-gate 			/* perhaps the tgt lifetime has expired */
456*7c478bd9Sstevel@tonic-gate 			if ((retval = krb5_cc_initialize(kmd->kcontext,
457*7c478bd9Sstevel@tonic-gate 					kmd->ccache, me)) != 0) {
458*7c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
459*7c478bd9Sstevel@tonic-gate 			} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
460*7c478bd9Sstevel@tonic-gate 					kmd->ccache, &my_creds)) != 0) {
461*7c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
462*7c478bd9Sstevel@tonic-gate 			}
463*7c478bd9Sstevel@tonic-gate 		}
464*7c478bd9Sstevel@tonic-gate 	} else {
465*7c478bd9Sstevel@tonic-gate 		/*
466*7c478bd9Sstevel@tonic-gate 		 * Creds already exist, update them if possible.
467*7c478bd9Sstevel@tonic-gate 		 * We got here either with the ESTABLISH or REFRESH flag.
468*7c478bd9Sstevel@tonic-gate 		 *
469*7c478bd9Sstevel@tonic-gate 		 * The credential cache does exist, and we are going to
470*7c478bd9Sstevel@tonic-gate 		 * read in each cred, looking for our own.  When we find
471*7c478bd9Sstevel@tonic-gate 		 * a matching credential, we will update it, and store it.
472*7c478bd9Sstevel@tonic-gate 		 * Any nonmatching credentials are stored as is.
473*7c478bd9Sstevel@tonic-gate 		 *
474*7c478bd9Sstevel@tonic-gate 		 * Rules:
475*7c478bd9Sstevel@tonic-gate 		 *    TGT must exist in cache to get to this point.
476*7c478bd9Sstevel@tonic-gate 		 *	if flag == ESTABLISH
477*7c478bd9Sstevel@tonic-gate 		 *		refresh it if possible, else overwrite
478*7c478bd9Sstevel@tonic-gate 		 *		with new TGT, other tickets in cache remain
479*7c478bd9Sstevel@tonic-gate 		 *		unchanged.
480*7c478bd9Sstevel@tonic-gate 		 *	else if flag == REFRESH
481*7c478bd9Sstevel@tonic-gate 		 *		refresh it if possible, else return error.
482*7c478bd9Sstevel@tonic-gate 		 *		- Will not work if "R" flag is not set in
483*7c478bd9Sstevel@tonic-gate 		 *		original cred, we dont want to 2nd guess the
484*7c478bd9Sstevel@tonic-gate 		 *		intention of the person who created the
485*7c478bd9Sstevel@tonic-gate 		 *		existing TGT.
486*7c478bd9Sstevel@tonic-gate 		 *
487*7c478bd9Sstevel@tonic-gate 		 */
488*7c478bd9Sstevel@tonic-gate 		krb5_cc_cursor	cursor;
489*7c478bd9Sstevel@tonic-gate 		krb5_creds	nextcred;
490*7c478bd9Sstevel@tonic-gate 		boolean_t	found = 0;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 		if ((retval = krb5_cc_start_seq_get(kmd->kcontext,
493*7c478bd9Sstevel@tonic-gate 				kmd->ccache, &cursor)) != 0)
494*7c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 		while ((krb5_cc_next_cred(kmd->kcontext, kmd->ccache,
497*7c478bd9Sstevel@tonic-gate 					&cursor, &nextcred) == 0)) {
498*7c478bd9Sstevel@tonic-gate 			/* if two creds match, we just update the first */
499*7c478bd9Sstevel@tonic-gate 			if ((!found) && (creds_match(kmd->kcontext,
500*7c478bd9Sstevel@tonic-gate 						&nextcred, &creds))) {
501*7c478bd9Sstevel@tonic-gate 				/*
502*7c478bd9Sstevel@tonic-gate 				 * Mark it as found, don't store it
503*7c478bd9Sstevel@tonic-gate 				 * in the list or else it will be
504*7c478bd9Sstevel@tonic-gate 				 * stored twice later.
505*7c478bd9Sstevel@tonic-gate 				 */
506*7c478bd9Sstevel@tonic-gate 				found = 1;
507*7c478bd9Sstevel@tonic-gate 			} else {
508*7c478bd9Sstevel@tonic-gate 				/*
509*7c478bd9Sstevel@tonic-gate 				 * Add a new node to the list
510*7c478bd9Sstevel@tonic-gate 				 * of creds that must be replaced
511*7c478bd9Sstevel@tonic-gate 				 * in the cache later.
512*7c478bd9Sstevel@tonic-gate 				 */
513*7c478bd9Sstevel@tonic-gate 				cred_node *newnode = (cred_node *)malloc(
514*7c478bd9Sstevel@tonic-gate 						sizeof (cred_node));
515*7c478bd9Sstevel@tonic-gate 				if (newnode == NULL) {
516*7c478bd9Sstevel@tonic-gate 					retval = ENOMEM;
517*7c478bd9Sstevel@tonic-gate 					goto cleanup_creds;
518*7c478bd9Sstevel@tonic-gate 				}
519*7c478bd9Sstevel@tonic-gate 				newnode->creds = NULL;
520*7c478bd9Sstevel@tonic-gate 				newnode->next = NULL;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 				if (cred_list_head == NULL) {
523*7c478bd9Sstevel@tonic-gate 					cred_list_head = newnode;
524*7c478bd9Sstevel@tonic-gate 					fetched = cred_list_head;
525*7c478bd9Sstevel@tonic-gate 				} else {
526*7c478bd9Sstevel@tonic-gate 					fetched->next = newnode;
527*7c478bd9Sstevel@tonic-gate 					fetched = fetched->next;
528*7c478bd9Sstevel@tonic-gate 				}
529*7c478bd9Sstevel@tonic-gate 				retval = krb5_copy_creds(kmd->kcontext,
530*7c478bd9Sstevel@tonic-gate 						&nextcred, &fetched->creds);
531*7c478bd9Sstevel@tonic-gate 				if (retval)
532*7c478bd9Sstevel@tonic-gate 					goto cleanup_creds;
533*7c478bd9Sstevel@tonic-gate 			}
534*7c478bd9Sstevel@tonic-gate 		}
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 		if ((retval = krb5_cc_end_seq_get(kmd->kcontext,
537*7c478bd9Sstevel@tonic-gate 					kmd->ccache, &cursor)) != 0)
538*7c478bd9Sstevel@tonic-gate 			goto cleanup_creds;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 		/*
541*7c478bd9Sstevel@tonic-gate 		 * If we found a matching cred, renew it.
542*7c478bd9Sstevel@tonic-gate 		 * This destroys the credential cache, if and only
543*7c478bd9Sstevel@tonic-gate 		 * if it passes.
544*7c478bd9Sstevel@tonic-gate 		 */
545*7c478bd9Sstevel@tonic-gate 		if (found &&
546*7c478bd9Sstevel@tonic-gate 		    (retval = krb5_get_credentials_renew(kmd->kcontext,
547*7c478bd9Sstevel@tonic-gate 				0, kmd->ccache, &creds, &credsp))) {
548*7c478bd9Sstevel@tonic-gate 			if (kmd->debug)
549*7c478bd9Sstevel@tonic-gate 			    syslog(LOG_DEBUG,
550*7c478bd9Sstevel@tonic-gate 				"PAM-KRB5 (setcred): krb5_get_credentials"
551*7c478bd9Sstevel@tonic-gate 				"_renew(update) failed: %s",
552*7c478bd9Sstevel@tonic-gate 				error_message((errcode_t)retval));
553*7c478bd9Sstevel@tonic-gate 			/*
554*7c478bd9Sstevel@tonic-gate 			 * If we only wanted to refresh the creds but failed
555*7c478bd9Sstevel@tonic-gate 			 * due to expiration, lack of "R" flag, or other
556*7c478bd9Sstevel@tonic-gate 			 * problems, return an error.  If we were trying to
557*7c478bd9Sstevel@tonic-gate 			 * establish new creds, add them to the cache.
558*7c478bd9Sstevel@tonic-gate 			 */
559*7c478bd9Sstevel@tonic-gate 			if ((retval = krb5_cc_initialize(kmd->kcontext,
560*7c478bd9Sstevel@tonic-gate 					kmd->ccache, me)) != 0) {
561*7c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
562*7c478bd9Sstevel@tonic-gate 			} else if ((retval = krb5_cc_store_cred(kmd->kcontext,
563*7c478bd9Sstevel@tonic-gate 					kmd->ccache, &my_creds)) != 0) {
564*7c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
565*7c478bd9Sstevel@tonic-gate 			}
566*7c478bd9Sstevel@tonic-gate 		}
567*7c478bd9Sstevel@tonic-gate 		/*
568*7c478bd9Sstevel@tonic-gate 		 * If no matching creds were found, we must
569*7c478bd9Sstevel@tonic-gate 		 * initialize the cache before we can store stuff
570*7c478bd9Sstevel@tonic-gate 		 * in it.
571*7c478bd9Sstevel@tonic-gate 		 */
572*7c478bd9Sstevel@tonic-gate 		if (!found) {
573*7c478bd9Sstevel@tonic-gate 			if ((retval = krb5_cc_initialize(kmd->kcontext,
574*7c478bd9Sstevel@tonic-gate 					kmd->ccache, me)) != 0) {
575*7c478bd9Sstevel@tonic-gate 				goto cleanup_creds;
576*7c478bd9Sstevel@tonic-gate 			}
577*7c478bd9Sstevel@tonic-gate 		}
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 		/* now store all the other tickets */
580*7c478bd9Sstevel@tonic-gate 		fetched = cred_list_head;
581*7c478bd9Sstevel@tonic-gate 		while (fetched != NULL) {
582*7c478bd9Sstevel@tonic-gate 			retval = krb5_cc_store_cred(kmd->kcontext,
583*7c478bd9Sstevel@tonic-gate 					kmd->ccache, fetched->creds);
584*7c478bd9Sstevel@tonic-gate 			fetched = fetched->next;
585*7c478bd9Sstevel@tonic-gate 			if (retval) {
586*7c478bd9Sstevel@tonic-gate 			    if (kmd->debug)
587*7c478bd9Sstevel@tonic-gate 				syslog(LOG_DEBUG,
588*7c478bd9Sstevel@tonic-gate 				    "PAM-KRB5(setcred): krb5_cc_store_cred() "
589*7c478bd9Sstevel@tonic-gate 				    "failed: %s",
590*7c478bd9Sstevel@tonic-gate 				    error_message((errcode_t)retval));
591*7c478bd9Sstevel@tonic-gate 			    goto cleanup_creds;
592*7c478bd9Sstevel@tonic-gate 			}
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 	}
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate cleanup_creds:
597*7c478bd9Sstevel@tonic-gate 	/* Cleanup the list of creds read from the cache if necessary */
598*7c478bd9Sstevel@tonic-gate 	fetched = cred_list_head;
599*7c478bd9Sstevel@tonic-gate 	while (fetched != NULL) {
600*7c478bd9Sstevel@tonic-gate 		cred_node *old = fetched;
601*7c478bd9Sstevel@tonic-gate 		/* Free the contents and the cred structure itself */
602*7c478bd9Sstevel@tonic-gate 		krb5_free_creds(kmd->kcontext, fetched->creds);
603*7c478bd9Sstevel@tonic-gate 		fetched = fetched->next;
604*7c478bd9Sstevel@tonic-gate 		free(old);
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if ((retval == 0) && (client_name != NULL)) {
608*7c478bd9Sstevel@tonic-gate 		/*
609*7c478bd9Sstevel@tonic-gate 		 * Credential update was successful!
610*7c478bd9Sstevel@tonic-gate 		 *
611*7c478bd9Sstevel@tonic-gate 		 * We now chown the ccache to the appropriate uid/gid
612*7c478bd9Sstevel@tonic-gate 		 * combination, if its a FILE based ccache.
613*7c478bd9Sstevel@tonic-gate 		 */
614*7c478bd9Sstevel@tonic-gate 		if (strstr(kmd->env, "FILE:")) {
615*7c478bd9Sstevel@tonic-gate 			uid_t uuid;
616*7c478bd9Sstevel@tonic-gate 			gid_t ugid;
617*7c478bd9Sstevel@tonic-gate 			char *username = NULL, *tmpname = NULL;
618*7c478bd9Sstevel@tonic-gate 			char *filepath = NULL;
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 			username = strdup(client_name);
621*7c478bd9Sstevel@tonic-gate 			if ((tmpname = strchr(username, '@')))
622*7c478bd9Sstevel@tonic-gate 				*tmpname = '\0';
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 			if (get_pw_uid(username, &uuid) == 0 ||
625*7c478bd9Sstevel@tonic-gate 			    get_pw_gid(username, &ugid) == 0) {
626*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "PAM-KRB5 (setcred): Unable to "
627*7c478bd9Sstevel@tonic-gate 				    "find matching uid/gid pair for user `%s'",
628*7c478bd9Sstevel@tonic-gate 				    username);
629*7c478bd9Sstevel@tonic-gate 				return (PAM_SYSTEM_ERR);
630*7c478bd9Sstevel@tonic-gate 			}
631*7c478bd9Sstevel@tonic-gate 			if (!(filepath = strchr(kmd->env, ':')) ||
632*7c478bd9Sstevel@tonic-gate 			    !(filepath+1)) {
633*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
634*7c478bd9Sstevel@tonic-gate 					"PAM-KRB5 (setcred): Invalid pathname "
635*7c478bd9Sstevel@tonic-gate 					"for credential cache of user `%s'",
636*7c478bd9Sstevel@tonic-gate 					username);
637*7c478bd9Sstevel@tonic-gate 				return (PAM_SYSTEM_ERR);
638*7c478bd9Sstevel@tonic-gate 			}
639*7c478bd9Sstevel@tonic-gate 			if (chown(filepath+1, uuid, ugid)) {
640*7c478bd9Sstevel@tonic-gate 				if (kmd->debug)
641*7c478bd9Sstevel@tonic-gate 					syslog(LOG_DEBUG,
642*7c478bd9Sstevel@tonic-gate 					    "PAM-KRB5 (setcred): chown to user "
643*7c478bd9Sstevel@tonic-gate 					    "`%s' failed for FILE=%s",
644*7c478bd9Sstevel@tonic-gate 					    username, filepath);
645*7c478bd9Sstevel@tonic-gate 			}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 			free(username);
648*7c478bd9Sstevel@tonic-gate 		}
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 		if (creds.times.endtime != 0) {
651*7c478bd9Sstevel@tonic-gate 			kwarn_del_warning(client_name);
652*7c478bd9Sstevel@tonic-gate 			if (kwarn_add_warning(client_name,
653*7c478bd9Sstevel@tonic-gate 			    creds.times.endtime) != 0) {
654*7c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE, dgettext(TEXT_DOMAIN,
655*7c478bd9Sstevel@tonic-gate 					"PAM-KRB5 (auth): kwarn_add_warning"
656*7c478bd9Sstevel@tonic-gate 					" failed: ktkt_warnd(1M) down?"));
657*7c478bd9Sstevel@tonic-gate 			}
658*7c478bd9Sstevel@tonic-gate 		}
659*7c478bd9Sstevel@tonic-gate 	}
660*7c478bd9Sstevel@tonic-gate 	if (client_name != NULL)
661*7c478bd9Sstevel@tonic-gate 		free(client_name);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &creds);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	return (retval);
666*7c478bd9Sstevel@tonic-gate }
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate static krb5_boolean
669*7c478bd9Sstevel@tonic-gate creds_match(krb5_context ctx, const krb5_creds *mcreds,
670*7c478bd9Sstevel@tonic-gate 	const krb5_creds *creds)
671*7c478bd9Sstevel@tonic-gate {
672*7c478bd9Sstevel@tonic-gate 	char *s1, *s2, *c1, *c2;
673*7c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, mcreds->client, &c1);
674*7c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, mcreds->server, &s1);
675*7c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, creds->client, &c2);
676*7c478bd9Sstevel@tonic-gate 	krb5_unparse_name(ctx, creds->server, &s2);
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	return (krb5_principal_compare(ctx, mcreds->client, creds->client) &&
679*7c478bd9Sstevel@tonic-gate 		krb5_principal_compare(ctx, mcreds->server, creds->server));
680*7c478bd9Sstevel@tonic-gate }
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate /*
683*7c478bd9Sstevel@tonic-gate  * Delete the user's credentials for this session
684*7c478bd9Sstevel@tonic-gate  */
685*7c478bd9Sstevel@tonic-gate static int
686*7c478bd9Sstevel@tonic-gate attempt_delete_initcred(krb5_module_data_t *kmd)
687*7c478bd9Sstevel@tonic-gate {
688*7c478bd9Sstevel@tonic-gate 	if (kmd == NULL)
689*7c478bd9Sstevel@tonic-gate 		return (0);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	if (kmd->debug) {
692*7c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG,
693*7c478bd9Sstevel@tonic-gate 			"PAM-KRB5 (setcred): deleting user's "
694*7c478bd9Sstevel@tonic-gate 			"credentials (initcreds)");
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
697*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
698*7c478bd9Sstevel@tonic-gate 	kmd->auth_status = PAM_AUTHINFO_UNAVAIL;
699*7c478bd9Sstevel@tonic-gate 	return (0);
700*7c478bd9Sstevel@tonic-gate }
701