1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate /*
9*7c478bd9Sstevel@tonic-gate  * Copyright 2000 by the Massachusetts Institute of Technology.
10*7c478bd9Sstevel@tonic-gate  * All Rights Reserved.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
13*7c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
14*7c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
15*7c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
16*7c478bd9Sstevel@tonic-gate  *
17*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
19*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
20*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
21*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
22*7c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
23*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
24*7c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
25*7c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
26*7c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
27*7c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
28*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
29*7c478bd9Sstevel@tonic-gate  * or implied warranty.
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
36*7c478bd9Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
37*7c478bd9Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
38*7c478bd9Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
39*7c478bd9Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
40*7c478bd9Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
41*7c478bd9Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
42*7c478bd9Sstevel@tonic-gate  * representations about the suitability of this software for any
43*7c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
46*7c478bd9Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
47*7c478bd9Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
48*7c478bd9Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
49*7c478bd9Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
50*7c478bd9Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
51*7c478bd9Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
52*7c478bd9Sstevel@tonic-gate  */
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate /*
55*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
56*7c478bd9Sstevel@tonic-gate  *
57*7c478bd9Sstevel@tonic-gate  * All rights reserved.
58*7c478bd9Sstevel@tonic-gate  *
59*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
60*7c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
61*7c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
62*7c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
63*7c478bd9Sstevel@tonic-gate  *
64*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
65*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
66*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
67*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
68*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
69*7c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
70*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
71*7c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
72*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
73*7c478bd9Sstevel@tonic-gate  * or implied warranty.
74*7c478bd9Sstevel@tonic-gate  *
75*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
76*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
77*7c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate #include <gssapiP_krb5.h>
81*7c478bd9Sstevel@tonic-gate #include <k5-int.h>
82*7c478bd9Sstevel@tonic-gate #include <memory.h>
83*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
84*7c478bd9Sstevel@tonic-gate #include <syslog.h>
85*7c478bd9Sstevel@tonic-gate #include <assert.h>
86*7c478bd9Sstevel@tonic-gate #define ROOT_UID 0
87*7c478bd9Sstevel@tonic-gate #define KRB5_DEFAULT_LIFE 60*60*10
88*7c478bd9Sstevel@tonic-gate #define CACHE_FILENAME_LEN 35
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /*
91*7c478bd9Sstevel@tonic-gate  * $Id: init_sec_context.c,v 1.51.2.7 2000/06/28 02:48:22 tlyu Exp $
92*7c478bd9Sstevel@tonic-gate  */
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate extern int
95*7c478bd9Sstevel@tonic-gate safechown(const char *src, uid_t uid, gid_t gid, int mode);
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /*
98*7c478bd9Sstevel@tonic-gate  * XXX This is for debugging only!!!  Should become a real bitfield
99*7c478bd9Sstevel@tonic-gate  * at some point
100*7c478bd9Sstevel@tonic-gate  */
101*7c478bd9Sstevel@tonic-gate int krb5_gss_dbg_client_expcreds = 0;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate  * Common code which fetches the correct krb5 credentials from the
105*7c478bd9Sstevel@tonic-gate  * ccache.
106*7c478bd9Sstevel@tonic-gate  */
107*7c478bd9Sstevel@tonic-gate static krb5_error_code get_credentials(context, cred, server, now,
108*7c478bd9Sstevel@tonic-gate 				       endtime, out_creds)
109*7c478bd9Sstevel@tonic-gate     krb5_context context;
110*7c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
111*7c478bd9Sstevel@tonic-gate     krb5_principal server;
112*7c478bd9Sstevel@tonic-gate     krb5_timestamp now;
113*7c478bd9Sstevel@tonic-gate     krb5_timestamp endtime;
114*7c478bd9Sstevel@tonic-gate     krb5_creds **out_creds;
115*7c478bd9Sstevel@tonic-gate {
116*7c478bd9Sstevel@tonic-gate     krb5_error_code	code;
117*7c478bd9Sstevel@tonic-gate     krb5_creds 		in_creds;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "get_credentials() start\n");
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate     memset((char *) &in_creds, 0, sizeof(krb5_creds));
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate     if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
124*7c478bd9Sstevel@tonic-gate 	goto cleanup;
125*7c478bd9Sstevel@tonic-gate     if ((code = krb5_copy_principal(context, server, &in_creds.server)))
126*7c478bd9Sstevel@tonic-gate 	goto cleanup;
127*7c478bd9Sstevel@tonic-gate     in_creds.times.endtime = endtime;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate     in_creds.keyblock.enctype = 0;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate     code = krb5_get_credentials(context, 0, cred->ccache,
132*7c478bd9Sstevel@tonic-gate 				&in_creds, out_creds);
133*7c478bd9Sstevel@tonic-gate     if (code)
134*7c478bd9Sstevel@tonic-gate 	goto cleanup;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate     /*
137*7c478bd9Sstevel@tonic-gate      * Enforce a stricter limit (without timeskew forgiveness at the
138*7c478bd9Sstevel@tonic-gate      * boundaries) because accept_sec_context code is also similarly
139*7c478bd9Sstevel@tonic-gate      * non-forgiving.
140*7c478bd9Sstevel@tonic-gate      */
141*7c478bd9Sstevel@tonic-gate     if (!krb5_gss_dbg_client_expcreds && *out_creds != NULL &&
142*7c478bd9Sstevel@tonic-gate 	(*out_creds)->times.endtime < now) {
143*7c478bd9Sstevel@tonic-gate 	code = KRB5KRB_AP_ERR_TKT_EXPIRED;
144*7c478bd9Sstevel@tonic-gate 	goto cleanup;
145*7c478bd9Sstevel@tonic-gate     }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate cleanup:
148*7c478bd9Sstevel@tonic-gate     if (in_creds.client)
149*7c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, in_creds.client);
150*7c478bd9Sstevel@tonic-gate     if (in_creds.server)
151*7c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, in_creds.server);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate     KRB5_LOG(KRB5_INFO, "get_credentials() end, code = %d\n", code);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate     return code;
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate struct gss_checksum_data {
159*7c478bd9Sstevel@tonic-gate     krb5_gss_ctx_id_rec *ctx;
160*7c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
161*7c478bd9Sstevel@tonic-gate     krb5_checksum md5;
162*7c478bd9Sstevel@tonic-gate     krb5_data checksum_data;
163*7c478bd9Sstevel@tonic-gate };
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate static krb5_error_code KRB5_CALLCONV
166*7c478bd9Sstevel@tonic-gate make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
167*7c478bd9Sstevel@tonic-gate                    void *cksum_data, krb5_data **out)
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate     krb5_error_code code;
170*7c478bd9Sstevel@tonic-gate     krb5_int32 con_flags;
171*7c478bd9Sstevel@tonic-gate     unsigned char *ptr;
172*7c478bd9Sstevel@tonic-gate     struct gss_checksum_data *data = cksum_data;
173*7c478bd9Sstevel@tonic-gate     krb5_data credmsg;
174*7c478bd9Sstevel@tonic-gate     int junk;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate     data->checksum_data.data = 0;
177*7c478bd9Sstevel@tonic-gate     credmsg.data = 0;
178*7c478bd9Sstevel@tonic-gate     /* build the checksum field */
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate     if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
181*7c478bd9Sstevel@tonic-gate 	/* first get KRB_CRED message, so we know its length */
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	/* clear the time check flag that was set in krb5_auth_con_init() */
184*7c478bd9Sstevel@tonic-gate 	krb5_auth_con_getflags(context, auth_context, &con_flags);
185*7c478bd9Sstevel@tonic-gate 	krb5_auth_con_setflags(context, auth_context,
186*7c478bd9Sstevel@tonic-gate 		con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	code = krb5_fwd_tgt_creds(context, auth_context, 0,
189*7c478bd9Sstevel@tonic-gate 		data->cred->princ, data->ctx->there,
190*7c478bd9Sstevel@tonic-gate 		data->cred->ccache, 1,
191*7c478bd9Sstevel@tonic-gate 		&credmsg);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	/* turn KRB5_AUTH_CONTEXT_DO_TIME back on */
194*7c478bd9Sstevel@tonic-gate 	krb5_auth_con_setflags(context, auth_context, con_flags);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	if (code) {
197*7c478bd9Sstevel@tonic-gate 	    /* don't fail here; just don't accept/do the delegation
198*7c478bd9Sstevel@tonic-gate 		request */
199*7c478bd9Sstevel@tonic-gate 	    data->ctx->gss_flags &= ~GSS_C_DELEG_FLAG;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	    data->checksum_data.length = 24;
202*7c478bd9Sstevel@tonic-gate 	} else {
203*7c478bd9Sstevel@tonic-gate 	    if (credmsg.length+28 > KRB5_INT16_MAX) {
204*7c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, &credmsg);
205*7c478bd9Sstevel@tonic-gate 		return(KRB5KRB_ERR_FIELD_TOOLONG);
206*7c478bd9Sstevel@tonic-gate             }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate             data->checksum_data.length = 28+credmsg.length;
209*7c478bd9Sstevel@tonic-gate 	}
210*7c478bd9Sstevel@tonic-gate     } else {
211*7c478bd9Sstevel@tonic-gate 	data->checksum_data.length = 24;
212*7c478bd9Sstevel@tonic-gate     }
213*7c478bd9Sstevel@tonic-gate #ifdef CFX_EXERCISE
214*7c478bd9Sstevel@tonic-gate     if (data->ctx->auth_context->keyblock->enctype == 18) {
215*7c478bd9Sstevel@tonic-gate 	srand(time(0) ^ getpid());
216*7c478bd9Sstevel@tonic-gate 	/* Our ftp client code stupidly assumes a base64-encoded
217*7c478bd9Sstevel@tonic-gate 	   version of the token will fit in 10K, so don't make this
218*7c478bd9Sstevel@tonic-gate 	   too big.  */
219*7c478bd9Sstevel@tonic-gate 	junk = rand() & 0xff;
220*7c478bd9Sstevel@tonic-gate     } else
221*7c478bd9Sstevel@tonic-gate         junk = 0;
222*7c478bd9Sstevel@tonic-gate #else
223*7c478bd9Sstevel@tonic-gate     junk = 0;
224*7c478bd9Sstevel@tonic-gate #endif
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate     data->checksum_data.length += junk;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate     /* now allocate a buffer to hold the checksum data and
229*7c478bd9Sstevel@tonic-gate 	(maybe) KRB_CRED msg */
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate     if ((data->checksum_data.data =
232*7c478bd9Sstevel@tonic-gate 	 (char *) xmalloc(data->checksum_data.length)) == NULL) {
233*7c478bd9Sstevel@tonic-gate 	if (credmsg.data)
234*7c478bd9Sstevel@tonic-gate             krb5_free_data_contents(context, &credmsg);
235*7c478bd9Sstevel@tonic-gate 	return(ENOMEM);
236*7c478bd9Sstevel@tonic-gate     }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate     ptr = (uchar_t *)data->checksum_data.data;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate     TWRITE_INT(ptr, data->md5.length, 0);
241*7c478bd9Sstevel@tonic-gate     TWRITE_STR(ptr, (unsigned char *) data->md5.contents, data->md5.length);
242*7c478bd9Sstevel@tonic-gate     TWRITE_INT(ptr, data->ctx->gss_flags, 0);
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate     /* done with this, free it */
245*7c478bd9Sstevel@tonic-gate     xfree(data->md5.contents);
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate     if (credmsg.data) {
248*7c478bd9Sstevel@tonic-gate 	TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
249*7c478bd9Sstevel@tonic-gate 	TWRITE_INT16(ptr, credmsg.length, 0);
250*7c478bd9Sstevel@tonic-gate 	TWRITE_STR(ptr, (unsigned char *) credmsg.data, credmsg.length);
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	/* free credmsg data */
253*7c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &credmsg);
254*7c478bd9Sstevel@tonic-gate     }
255*7c478bd9Sstevel@tonic-gate     if (junk)
256*7c478bd9Sstevel@tonic-gate 	memset(ptr, 'i', junk);
257*7c478bd9Sstevel@tonic-gate     *out = &data->checksum_data;
258*7c478bd9Sstevel@tonic-gate     return 0;
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate static krb5_error_code
262*7c478bd9Sstevel@tonic-gate make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token)
263*7c478bd9Sstevel@tonic-gate     krb5_context context;
264*7c478bd9Sstevel@tonic-gate     krb5_gss_ctx_id_rec *ctx;
265*7c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
266*7c478bd9Sstevel@tonic-gate     krb5_creds *k_cred;
267*7c478bd9Sstevel@tonic-gate     gss_channel_bindings_t chan_bindings;
268*7c478bd9Sstevel@tonic-gate     gss_OID mech_type;
269*7c478bd9Sstevel@tonic-gate     gss_buffer_t token;
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate     krb5_flags mk_req_flags = 0;
272*7c478bd9Sstevel@tonic-gate     krb5_error_code code;
273*7c478bd9Sstevel@tonic-gate     struct gss_checksum_data cksum_struct;
274*7c478bd9Sstevel@tonic-gate     krb5_checksum md5;
275*7c478bd9Sstevel@tonic-gate     krb5_data ap_req;
276*7c478bd9Sstevel@tonic-gate     krb5_data *checksum_data = NULL;
277*7c478bd9Sstevel@tonic-gate     unsigned char *ptr;
278*7c478bd9Sstevel@tonic-gate     unsigned char *t;
279*7c478bd9Sstevel@tonic-gate     int tlen;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate     ap_req.data = 0;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate     /* build the checksum buffer */
284*7c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "make_ap_req_v1() start\n");
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate     /* compute the hash of the channel bindings */
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate     if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0)))
289*7c478bd9Sstevel@tonic-gate         return(code);
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate     krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
292*7c478bd9Sstevel@tonic-gate 				    CKSUMTYPE_KG_CB);
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate     cksum_struct.md5 = md5;
295*7c478bd9Sstevel@tonic-gate     cksum_struct.ctx = ctx;
296*7c478bd9Sstevel@tonic-gate     cksum_struct.cred = cred;
297*7c478bd9Sstevel@tonic-gate     cksum_struct.checksum_data.data = NULL;
298*7c478bd9Sstevel@tonic-gate     switch (k_cred->keyblock.enctype) {
299*7c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_CRC:
300*7c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_MD4:
301*7c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_MD5:
302*7c478bd9Sstevel@tonic-gate     case ENCTYPE_DES3_CBC_SHA1:
303*7c478bd9Sstevel@tonic-gate 	code = make_gss_checksum(context, ctx->auth_context, &cksum_struct,
304*7c478bd9Sstevel@tonic-gate 		&checksum_data);
305*7c478bd9Sstevel@tonic-gate 	if (code)
306*7c478bd9Sstevel@tonic-gate 		goto cleanup;
307*7c478bd9Sstevel@tonic-gate         break;
308*7c478bd9Sstevel@tonic-gate     default:
309*7c478bd9Sstevel@tonic-gate 	krb5_auth_con_set_checksum_func(context, ctx->auth_context,
310*7c478bd9Sstevel@tonic-gate 		make_gss_checksum, &cksum_struct);
311*7c478bd9Sstevel@tonic-gate 	break;
312*7c478bd9Sstevel@tonic-gate     }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate     /* call mk_req.  subkey and ap_req need to be used or destroyed */
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate     mk_req_flags = AP_OPTS_USE_SUBKEY;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
319*7c478bd9Sstevel@tonic-gate 	mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate     if ((code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
322*7c478bd9Sstevel@tonic-gate 				     checksum_data, k_cred, &ap_req)))
323*7c478bd9Sstevel@tonic-gate 	goto cleanup;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate    /* store the interesting stuff from creds and authent */
326*7c478bd9Sstevel@tonic-gate    ctx->endtime = k_cred->times.endtime;
327*7c478bd9Sstevel@tonic-gate    ctx->krb_flags = k_cred->ticket_flags;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate    /* build up the token */
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate    /* allocate space for the token */
332*7c478bd9Sstevel@tonic-gate    tlen = g_token_size((gss_OID) mech_type, ap_req.length);
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate    if ((t = (unsigned char *) xmalloc(tlen)) == NULL) {
335*7c478bd9Sstevel@tonic-gate       code = ENOMEM;
336*7c478bd9Sstevel@tonic-gate       goto cleanup;
337*7c478bd9Sstevel@tonic-gate    }
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate    /* fill in the buffer */
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate    ptr = t;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate    g_make_token_header((gss_OID) mech_type, ap_req.length,
344*7c478bd9Sstevel@tonic-gate 		       &ptr, KG_TOK_CTX_AP_REQ);
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate    TWRITE_STR(ptr, (unsigned char *) ap_req.data, ap_req.length);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate    /* pass it back */
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate    token->length = tlen;
351*7c478bd9Sstevel@tonic-gate    token->value = (void *) t;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate    code = 0;
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate cleanup:
356*7c478bd9Sstevel@tonic-gate    /*
357*7c478bd9Sstevel@tonic-gate     * We only free cksum_struct.checksum_data here, because checksum_data
358*7c478bd9Sstevel@tonic-gate     * could point to cksum_struct.checksum_data or NULL.
359*7c478bd9Sstevel@tonic-gate     */
360*7c478bd9Sstevel@tonic-gate    if (cksum_struct.checksum_data.data)
361*7c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &cksum_struct.checksum_data);
362*7c478bd9Sstevel@tonic-gate    if (ap_req.data)
363*7c478bd9Sstevel@tonic-gate        xfree(ap_req.data);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate    KRB5_LOG(KRB5_INFO, "make_ap_req_v1() end, code = %d\n", code);
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate    return (code);
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate static krb5_boolean
373*7c478bd9Sstevel@tonic-gate principal_ignore_inst_compare(context, princ1, princ2)
374*7c478bd9Sstevel@tonic-gate     krb5_context context;
375*7c478bd9Sstevel@tonic-gate     krb5_const_principal princ1;
376*7c478bd9Sstevel@tonic-gate     krb5_const_principal princ2;
377*7c478bd9Sstevel@tonic-gate {
378*7c478bd9Sstevel@tonic-gate     krb5_int32 nelem;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate     nelem = krb5_princ_size(context, princ1);
381*7c478bd9Sstevel@tonic-gate     if (nelem != krb5_princ_size(context, princ2))
382*7c478bd9Sstevel@tonic-gate 	return FALSE;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate     if (! krb5_realm_compare(context, princ1, princ2))
385*7c478bd9Sstevel@tonic-gate 	return FALSE;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate     /*
388*7c478bd9Sstevel@tonic-gate      * Solaris Kerberos
389*7c478bd9Sstevel@tonic-gate      * If princ1 is elem1/metachar@REALM, compare just elem1 (and REALM).
390*7c478bd9Sstevel@tonic-gate      */
391*7c478bd9Sstevel@tonic-gate     if (nelem == 2) {
392*7c478bd9Sstevel@tonic-gate         const krb5_data *p = krb5_princ_component(context, princ1, 1);
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if (p->length == 1) {
395*7c478bd9Sstevel@tonic-gate 	    const char *s = p->data;
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	    if (s[0] == '*') {
398*7c478bd9Sstevel@tonic-gate 		const krb5_data *p1 = krb5_princ_component(context, princ1, 0);
399*7c478bd9Sstevel@tonic-gate 		const krb5_data *p2 = krb5_princ_component(context, princ2, 0);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 		if (p1->length != p2->length ||
402*7c478bd9Sstevel@tonic-gate 		        memcmp(p1->data, p2->data, p1->length))
403*7c478bd9Sstevel@tonic-gate 		    return FALSE;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		return TRUE;
406*7c478bd9Sstevel@tonic-gate 	    }
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate     }
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate     return FALSE;
411*7c478bd9Sstevel@tonic-gate }
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate /*
414*7c478bd9Sstevel@tonic-gate  * Solaris Kerberos
415*7c478bd9Sstevel@tonic-gate  * This is a dup of krb5_ktfile_get_entry (sigh) but is necessary to
416*7c478bd9Sstevel@tonic-gate  * to get a custom princ compare above (principal_ignore_inst_compare)
417*7c478bd9Sstevel@tonic-gate  * and thus avoid mucking w/important krb5 internal
418*7c478bd9Sstevel@tonic-gate  * api (krb5_principal_compare)
419*7c478bd9Sstevel@tonic-gate  */
420*7c478bd9Sstevel@tonic-gate #include "../krb5/keytab/file/ktfile.h"
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate static krb5_error_code KRB5_CALLCONV
423*7c478bd9Sstevel@tonic-gate ktfile_get_entry(context, id, principal, kvno, enctype, entry)
424*7c478bd9Sstevel@tonic-gate    krb5_context context;
425*7c478bd9Sstevel@tonic-gate    krb5_keytab id;
426*7c478bd9Sstevel@tonic-gate    krb5_const_principal principal;
427*7c478bd9Sstevel@tonic-gate    krb5_kvno kvno;
428*7c478bd9Sstevel@tonic-gate    krb5_enctype enctype;
429*7c478bd9Sstevel@tonic-gate    krb5_keytab_entry * entry;
430*7c478bd9Sstevel@tonic-gate {
431*7c478bd9Sstevel@tonic-gate     krb5_keytab_entry cur_entry, new_entry;
432*7c478bd9Sstevel@tonic-gate     krb5_error_code kerror = 0;
433*7c478bd9Sstevel@tonic-gate     int found_wrong_kvno = 0;
434*7c478bd9Sstevel@tonic-gate     krb5_boolean similar;
435*7c478bd9Sstevel@tonic-gate     int kvno_offset = 0;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() start\n");
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate     /* Open the keyfile for reading */
440*7c478bd9Sstevel@tonic-gate     if ((kerror = krb5_ktfileint_openr(context, id))){
441*7c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "ktfile_get_entry() end, ktfileint_openr() "
442*7c478bd9Sstevel@tonic-gate 		"kerror= %d\n", kerror);
443*7c478bd9Sstevel@tonic-gate 	return(kerror);
444*7c478bd9Sstevel@tonic-gate     }
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate     /*
447*7c478bd9Sstevel@tonic-gate      * For efficiency and simplicity, we'll use a while true that
448*7c478bd9Sstevel@tonic-gate      * is exited with a break statement.
449*7c478bd9Sstevel@tonic-gate      */
450*7c478bd9Sstevel@tonic-gate     cur_entry.principal = 0;
451*7c478bd9Sstevel@tonic-gate     cur_entry.vno = 0;
452*7c478bd9Sstevel@tonic-gate     cur_entry.key.contents = 0;
453*7c478bd9Sstevel@tonic-gate     /*CONSTCOND*/
454*7c478bd9Sstevel@tonic-gate     while (TRUE) {
455*7c478bd9Sstevel@tonic-gate 	if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry)))
456*7c478bd9Sstevel@tonic-gate 	    break;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	/*
459*7c478bd9Sstevel@tonic-gate 	 * by the time this loop exits, it must either free cur_entry,
460*7c478bd9Sstevel@tonic-gate 	 * and copy new_entry there, or free new_entry.  Otherwise, it
461*7c478bd9Sstevel@tonic-gate 	 * leaks.
462*7c478bd9Sstevel@tonic-gate 	 */
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	/*
465*7c478bd9Sstevel@tonic-gate 	 * if the principal isn't the one requested, free new_entry
466*7c478bd9Sstevel@tonic-gate 	 * and continue to the next.
467*7c478bd9Sstevel@tonic-gate 	 */
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	if (!principal_ignore_inst_compare(context, principal,
470*7c478bd9Sstevel@tonic-gate 					new_entry.principal)) {
471*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &new_entry);
472*7c478bd9Sstevel@tonic-gate 	    continue;
473*7c478bd9Sstevel@tonic-gate 	}
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	/*
476*7c478bd9Sstevel@tonic-gate 	 * if the enctype is not ignored and doesn't match, free new_entry
477*7c478bd9Sstevel@tonic-gate 	 * and continue to the next
478*7c478bd9Sstevel@tonic-gate 	 */
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	if (enctype != IGNORE_ENCTYPE) {
481*7c478bd9Sstevel@tonic-gate 	    if ((kerror = krb5_c_enctype_compare(context, enctype,
482*7c478bd9Sstevel@tonic-gate 						 new_entry.key.enctype,
483*7c478bd9Sstevel@tonic-gate 						 &similar))) {
484*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &new_entry);
485*7c478bd9Sstevel@tonic-gate 		break;
486*7c478bd9Sstevel@tonic-gate 	    }
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	    if (!similar) {
489*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &new_entry);
490*7c478bd9Sstevel@tonic-gate 		continue;
491*7c478bd9Sstevel@tonic-gate 	    }
492*7c478bd9Sstevel@tonic-gate 	    /*
493*7c478bd9Sstevel@tonic-gate 	     * Coerce the enctype of the output keyblock in case we
494*7c478bd9Sstevel@tonic-gate 	     * got an inexact match on the enctype.
495*7c478bd9Sstevel@tonic-gate 	     */
496*7c478bd9Sstevel@tonic-gate 	    new_entry.key.enctype = enctype;
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (kvno == IGNORE_VNO) {
500*7c478bd9Sstevel@tonic-gate 	    /*
501*7c478bd9Sstevel@tonic-gate 	     * if this is the first match, or if the new vno is
502*7c478bd9Sstevel@tonic-gate 	     * bigger, free the current and keep the new.  Otherwise,
503*7c478bd9Sstevel@tonic-gate 	     * free the new.
504*7c478bd9Sstevel@tonic-gate 	     */
505*7c478bd9Sstevel@tonic-gate 	    /*
506*7c478bd9Sstevel@tonic-gate 	     * A 1.2.x keytab contains only the low 8 bits of the key
507*7c478bd9Sstevel@tonic-gate 	     * version number.  Since it can be much bigger, and thus
508*7c478bd9Sstevel@tonic-gate 	     * the 8-bit value can wrap, we need some heuristics to
509*7c478bd9Sstevel@tonic-gate 	     * figure out the "highest" numbered key if some numbers
510*7c478bd9Sstevel@tonic-gate 	     * close to 255 and some near 0 are used.
511*7c478bd9Sstevel@tonic-gate 	     *
512*7c478bd9Sstevel@tonic-gate 	     * The heuristic here:
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	     * If we have any keys with versions over 240, then assume
515*7c478bd9Sstevel@tonic-gate 	     * that all version numbers 0-127 refer to 256+N instead.
516*7c478bd9Sstevel@tonic-gate 	     * Not perfect, but maybe good enough?
517*7c478bd9Sstevel@tonic-gate 	     */
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate #define M(VNO) (((VNO) - kvno_offset + 256) % 256)
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	    if (new_entry.vno > 240)
522*7c478bd9Sstevel@tonic-gate 		kvno_offset = 128;
523*7c478bd9Sstevel@tonic-gate 	    if (! cur_entry.principal ||
524*7c478bd9Sstevel@tonic-gate 		M(new_entry.vno) > M(cur_entry.vno)) {
525*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &cur_entry);
526*7c478bd9Sstevel@tonic-gate 		cur_entry = new_entry;
527*7c478bd9Sstevel@tonic-gate 	    } else {
528*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &new_entry);
529*7c478bd9Sstevel@tonic-gate 	    }
530*7c478bd9Sstevel@tonic-gate 	} else {
531*7c478bd9Sstevel@tonic-gate 	    /*
532*7c478bd9Sstevel@tonic-gate 	     * if this kvno matches, free the current (will there ever
533*7c478bd9Sstevel@tonic-gate 	     * be one?), keep the new, and break out.  Otherwise, remember
534*7c478bd9Sstevel@tonic-gate 	     * that we were here so we can return the right error, and
535*7c478bd9Sstevel@tonic-gate 	     * free the new
536*7c478bd9Sstevel@tonic-gate 	     */
537*7c478bd9Sstevel@tonic-gate 	    /*
538*7c478bd9Sstevel@tonic-gate 	     * Yuck.  The krb5-1.2.x keytab format only stores one byte
539*7c478bd9Sstevel@tonic-gate 	     * for the kvno, so we're toast if the kvno requested is
540*7c478bd9Sstevel@tonic-gate 	     * higher than that.  Short-term workaround: only compare
541*7c478bd9Sstevel@tonic-gate 	     * the low 8 bits.
542*7c478bd9Sstevel@tonic-gate 	     */
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	    if (new_entry.vno == (kvno & 0xff)) {
545*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &cur_entry);
546*7c478bd9Sstevel@tonic-gate 		cur_entry = new_entry;
547*7c478bd9Sstevel@tonic-gate 		break;
548*7c478bd9Sstevel@tonic-gate 	    } else {
549*7c478bd9Sstevel@tonic-gate 		found_wrong_kvno++;
550*7c478bd9Sstevel@tonic-gate 		krb5_kt_free_entry(context, &new_entry);
551*7c478bd9Sstevel@tonic-gate 	    }
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate     }
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate     if (kerror == KRB5_KT_END) {
556*7c478bd9Sstevel@tonic-gate 	 if (cur_entry.principal)
557*7c478bd9Sstevel@tonic-gate 	      kerror = 0;
558*7c478bd9Sstevel@tonic-gate 	 else if (found_wrong_kvno)
559*7c478bd9Sstevel@tonic-gate 	      kerror = KRB5_KT_KVNONOTFOUND;
560*7c478bd9Sstevel@tonic-gate 	 else
561*7c478bd9Sstevel@tonic-gate 	      kerror = KRB5_KT_NOTFOUND;
562*7c478bd9Sstevel@tonic-gate     }
563*7c478bd9Sstevel@tonic-gate     if (kerror) {
564*7c478bd9Sstevel@tonic-gate 	(void) krb5_ktfileint_close(context, id);
565*7c478bd9Sstevel@tonic-gate 	krb5_kt_free_entry(context, &cur_entry);
566*7c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, kerror="
567*7c478bd9Sstevel@tonic-gate 		    "%d\n", kerror);
568*7c478bd9Sstevel@tonic-gate 	return kerror;
569*7c478bd9Sstevel@tonic-gate     }
570*7c478bd9Sstevel@tonic-gate     if ((kerror = krb5_ktfileint_close(context, id)) != 0) {
571*7c478bd9Sstevel@tonic-gate 	krb5_kt_free_entry(context, &cur_entry);
572*7c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, ktfileint_close() "
573*7c478bd9Sstevel@tonic-gate 	       "kerror= %d\n", kerror);
574*7c478bd9Sstevel@tonic-gate 	return kerror;
575*7c478bd9Sstevel@tonic-gate     }
576*7c478bd9Sstevel@tonic-gate     *entry = cur_entry;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate     /* Let us close the file before we leave */
579*7c478bd9Sstevel@tonic-gate     (void) krb5_ktfileint_close(context, id);
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() end");
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate     return 0;
584*7c478bd9Sstevel@tonic-gate }
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate /*
588*7c478bd9Sstevel@tonic-gate  * Solaris Kerberos
589*7c478bd9Sstevel@tonic-gate  * Given a princ of name/instance@LOCALREALM, search the keytab
590*7c478bd9Sstevel@tonic-gate  * for a match of name and LOCALREALM and if found, return instance
591*7c478bd9Sstevel@tonic-gate  * as a string.
592*7c478bd9Sstevel@tonic-gate  *
593*7c478bd9Sstevel@tonic-gate  * Caller must free returned string.
594*7c478bd9Sstevel@tonic-gate  */
595*7c478bd9Sstevel@tonic-gate static krb5_error_code
596*7c478bd9Sstevel@tonic-gate get_instance_keytab(
597*7c478bd9Sstevel@tonic-gate 	krb5_context context,
598*7c478bd9Sstevel@tonic-gate 	const char *sname,
599*7c478bd9Sstevel@tonic-gate 	krb5_keytab keytab,
600*7c478bd9Sstevel@tonic-gate 	char  **instance)  /* out */
601*7c478bd9Sstevel@tonic-gate {
602*7c478bd9Sstevel@tonic-gate 	krb5_error_code ret=0;
603*7c478bd9Sstevel@tonic-gate 	krb5_keytab_entry kt_ent;
604*7c478bd9Sstevel@tonic-gate 	krb5_int32 nelem, free_kt_ent=0;
605*7c478bd9Sstevel@tonic-gate 	register const krb5_data *p;
606*7c478bd9Sstevel@tonic-gate 	char *realm=NULL, *s=NULL;
607*7c478bd9Sstevel@tonic-gate 	krb5_principal client=NULL, princ=NULL;
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	if (!keytab)
610*7c478bd9Sstevel@tonic-gate 		return EINVAL;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	if (ret = krb5_get_default_realm(context, &realm))
613*7c478bd9Sstevel@tonic-gate 		return ret;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	ret = krb5_build_principal(context, &client, strlen(realm),
616*7c478bd9Sstevel@tonic-gate 				      realm, sname, "*",
617*7c478bd9Sstevel@tonic-gate 				      (char *)0);
618*7c478bd9Sstevel@tonic-gate 	if (ret)
619*7c478bd9Sstevel@tonic-gate 		goto out;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	ret = ktfile_get_entry(context, keytab, client,
622*7c478bd9Sstevel@tonic-gate 				0, /* don't have vno available */
623*7c478bd9Sstevel@tonic-gate 				0, &kt_ent);
624*7c478bd9Sstevel@tonic-gate 	if (ret)
625*7c478bd9Sstevel@tonic-gate 		goto out;
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	free_kt_ent++;  /* kt_ent is not a ptr */
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	princ = kt_ent.principal;
630*7c478bd9Sstevel@tonic-gate 	nelem = krb5_princ_size(context, princ);
631*7c478bd9Sstevel@tonic-gate 	if (nelem != 2) {
632*7c478bd9Sstevel@tonic-gate 		ret = KRB5_PRINC_NOMATCH;
633*7c478bd9Sstevel@tonic-gate 		goto out;
634*7c478bd9Sstevel@tonic-gate 	}
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	p = krb5_princ_component(context, princ, 1);
637*7c478bd9Sstevel@tonic-gate 	s = calloc(p->length + sizeof(char), sizeof(char));
638*7c478bd9Sstevel@tonic-gate 	if (!s) {
639*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
640*7c478bd9Sstevel@tonic-gate 		goto out;
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	(void) memcpy(s, p->data, p->length);
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate out:
647*7c478bd9Sstevel@tonic-gate 	free(realm);
648*7c478bd9Sstevel@tonic-gate 	if (client)
649*7c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, client);
650*7c478bd9Sstevel@tonic-gate 	if (free_kt_ent)
651*7c478bd9Sstevel@tonic-gate 		(void) krb5_kt_free_entry(context, &kt_ent);
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	if (ret == 0)
654*7c478bd9Sstevel@tonic-gate 		*instance = s;
655*7c478bd9Sstevel@tonic-gate 	return ret;
656*7c478bd9Sstevel@tonic-gate }
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate static OM_uint32
659*7c478bd9Sstevel@tonic-gate load_root_cred_using_keytab(
660*7c478bd9Sstevel@tonic-gate 	OM_uint32 *minor_status,
661*7c478bd9Sstevel@tonic-gate 	krb5_context context,
662*7c478bd9Sstevel@tonic-gate 	const char *sname,
663*7c478bd9Sstevel@tonic-gate 	int use_nodename)
664*7c478bd9Sstevel@tonic-gate {
665*7c478bd9Sstevel@tonic-gate 	krb5_creds my_creds;
666*7c478bd9Sstevel@tonic-gate 	krb5_principal me;
667*7c478bd9Sstevel@tonic-gate 	krb5_principal server;
668*7c478bd9Sstevel@tonic-gate 	krb5_error_code code;
669*7c478bd9Sstevel@tonic-gate 	krb5_ccache ccache = NULL;
670*7c478bd9Sstevel@tonic-gate 	krb5_keytab keytab = NULL;
671*7c478bd9Sstevel@tonic-gate 	krb5_timestamp now;
672*7c478bd9Sstevel@tonic-gate 	krb5_deltat lifetime = KRB5_DEFAULT_LIFE;   /* -l option */
673*7c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt opt;
674*7c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
675*7c478bd9Sstevel@tonic-gate 		0,
676*7c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
677*7c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
678*7c478bd9Sstevel@tonic-gate 	};
679*7c478bd9Sstevel@tonic-gate 	char *svcname = NULL;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() start \n");
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	if (!sname)
684*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	memset((char *)&my_creds, 0, sizeof(my_creds));
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	if (code = krb5_kt_default(context, &keytab)) {
689*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
690*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
691*7c478bd9Sstevel@tonic-gate 	}
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 	if (!use_nodename) {
694*7c478bd9Sstevel@tonic-gate 		char *instance = NULL;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 		code = get_instance_keytab(context, sname, keytab, &instance);
697*7c478bd9Sstevel@tonic-gate 		if (code == 0) {
698*7c478bd9Sstevel@tonic-gate 			code = krb5_sname_to_principal(context,
699*7c478bd9Sstevel@tonic-gate 						    instance, sname,
700*7c478bd9Sstevel@tonic-gate 						    KRB5_NT_UNKNOWN, &me);
701*7c478bd9Sstevel@tonic-gate 			free(instance);
702*7c478bd9Sstevel@tonic-gate 		}
703*7c478bd9Sstevel@tonic-gate 	} else {
704*7c478bd9Sstevel@tonic-gate 		code = krb5_sname_to_principal(context, NULL, sname,
705*7c478bd9Sstevel@tonic-gate 					    KRB5_NT_SRV_HST, &me);
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 	if (code) {
708*7c478bd9Sstevel@tonic-gate 		(void) krb5_kt_close(context, keytab);
709*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
710*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
711*7c478bd9Sstevel@tonic-gate 	}
712*7c478bd9Sstevel@tonic-gate 	my_creds.client = me;
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	if((code = krb5_build_principal_ext(context, &server,
715*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->length,
716*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->data,
717*7c478bd9Sstevel@tonic-gate 					tgtname.length, tgtname.data,
718*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->length,
719*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->data,
720*7c478bd9Sstevel@tonic-gate 					0))) {
721*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
722*7c478bd9Sstevel@tonic-gate 		krb5_free_cred_contents(context, &my_creds);
723*7c478bd9Sstevel@tonic-gate 		(void) krb5_kt_close(context, keytab);
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
726*7c478bd9Sstevel@tonic-gate 	}
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	my_creds.server = server;
729*7c478bd9Sstevel@tonic-gate 	my_creds.times.starttime = 0;     /* start timer
730*7c478bd9Sstevel@tonic-gate 					   * when request
731*7c478bd9Sstevel@tonic-gate 					   * gets to KDC
732*7c478bd9Sstevel@tonic-gate 					   */
733*7c478bd9Sstevel@tonic-gate 	if ((code = krb5_timeofday(context, &now))) {
734*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
735*7c478bd9Sstevel@tonic-gate 		krb5_free_cred_contents(context, &my_creds);
736*7c478bd9Sstevel@tonic-gate 		(void) krb5_kt_close(context, keytab);
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
739*7c478bd9Sstevel@tonic-gate 	}
740*7c478bd9Sstevel@tonic-gate 	my_creds.times.endtime = now + lifetime;
741*7c478bd9Sstevel@tonic-gate 	my_creds.times.renew_till = 0;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	memset(&opt, 0, sizeof (opt));
744*7c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_init(&opt);
745*7c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_set_tkt_life(&opt, lifetime);
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	code = krb5_unparse_name(context, server, &svcname);
748*7c478bd9Sstevel@tonic-gate 	if (code != 0) {
749*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
750*7c478bd9Sstevel@tonic-gate 		krb5_free_cred_contents(context, &my_creds);
751*7c478bd9Sstevel@tonic-gate 		(void) krb5_kt_close(context, keytab);
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
754*7c478bd9Sstevel@tonic-gate 	}
755*7c478bd9Sstevel@tonic-gate 	code = krb5_get_init_creds_keytab(context,
756*7c478bd9Sstevel@tonic-gate                                 &my_creds, me, keytab,
757*7c478bd9Sstevel@tonic-gate                                 0, svcname, &opt);
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	(void) krb5_kt_close(context, keytab);
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	if (svcname != NULL)
762*7c478bd9Sstevel@tonic-gate 		free(svcname);
763*7c478bd9Sstevel@tonic-gate 	if (code) {
764*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
765*7c478bd9Sstevel@tonic-gate 		krb5_free_cred_contents(context, &my_creds);
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 	code = krb5_cc_resolve (context,
770*7c478bd9Sstevel@tonic-gate 				krb5_cc_default_name(context),
771*7c478bd9Sstevel@tonic-gate 				&ccache);
772*7c478bd9Sstevel@tonic-gate 	if (code != 0) {
773*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
774*7c478bd9Sstevel@tonic-gate 		krb5_free_cred_contents(context, &my_creds);
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
777*7c478bd9Sstevel@tonic-gate 	}
778*7c478bd9Sstevel@tonic-gate 	code = krb5_cc_initialize (context, ccache, me);
779*7c478bd9Sstevel@tonic-gate 	if (code != 0) {
780*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
781*7c478bd9Sstevel@tonic-gate 		krb5_free_cred_contents(context, &my_creds);
782*7c478bd9Sstevel@tonic-gate 		(void) krb5_cc_close(context, ccache);
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
785*7c478bd9Sstevel@tonic-gate 	}
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	code = krb5_cc_store_cred(context, ccache,
788*7c478bd9Sstevel@tonic-gate 				  &my_creds);
789*7c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(context, &my_creds);
790*7c478bd9Sstevel@tonic-gate 	(void) krb5_cc_close(context, ccache);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	if (code) {
793*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 		KRB5_LOG(KRB5_ERR, "load_root_cred_using_keytab() end, error "
796*7c478bd9Sstevel@tonic-gate 			"code = %d\n", code);
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
799*7c478bd9Sstevel@tonic-gate 	}
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() end \n");
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
804*7c478bd9Sstevel@tonic-gate }
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate static OM_uint32
807*7c478bd9Sstevel@tonic-gate renew_ccache(OM_uint32 *minor_status, krb5_context context, uid_t uid)
808*7c478bd9Sstevel@tonic-gate {
809*7c478bd9Sstevel@tonic-gate 	krb5_principal me;
810*7c478bd9Sstevel@tonic-gate 	krb5_principal server;
811*7c478bd9Sstevel@tonic-gate 	krb5_creds	creds;
812*7c478bd9Sstevel@tonic-gate 	krb5_creds	tmpcreds;
813*7c478bd9Sstevel@tonic-gate 	krb5_creds	*out_creds;
814*7c478bd9Sstevel@tonic-gate 	krb5_error_code code;
815*7c478bd9Sstevel@tonic-gate 	krb5_ccache ccache = NULL;
816*7c478bd9Sstevel@tonic-gate 	static char ccache_name_buf[CACHE_FILENAME_LEN];
817*7c478bd9Sstevel@tonic-gate 	int options = 0;
818*7c478bd9Sstevel@tonic-gate 	krb5_data tgtname = {
819*7c478bd9Sstevel@tonic-gate 		0,
820*7c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME_SIZE,
821*7c478bd9Sstevel@tonic-gate 		KRB5_TGS_NAME
822*7c478bd9Sstevel@tonic-gate 	};
823*7c478bd9Sstevel@tonic-gate 	gid_t gid = getgid();
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	memset((char *)&creds, 0, sizeof(creds));
826*7c478bd9Sstevel@tonic-gate 	memset((char *)&tmpcreds, 0, sizeof(creds));
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	if ((code = krb5_cc_default(context, &ccache))) {
829*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
830*7c478bd9Sstevel@tonic-gate 		(void) krb5_cc_close(context, ccache);
831*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
832*7c478bd9Sstevel@tonic-gate 	}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	if ((code = krb5_cc_get_principal(context, ccache, &me)) != 0) {
835*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
836*7c478bd9Sstevel@tonic-gate 		(void) krb5_cc_close(context, ccache);
837*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	creds.client = me;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	if((code = krb5_build_principal_ext(context, &server,
843*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->length,
844*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->data,
845*7c478bd9Sstevel@tonic-gate 					tgtname.length, tgtname.data,
846*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->length,
847*7c478bd9Sstevel@tonic-gate 					krb5_princ_realm(context, me)->data,
848*7c478bd9Sstevel@tonic-gate 					0))) {
849*7c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, me);
850*7c478bd9Sstevel@tonic-gate 		(void) krb5_cc_close(context, ccache);
851*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
852*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
853*7c478bd9Sstevel@tonic-gate 	}
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	creds.server = server;
856*7c478bd9Sstevel@tonic-gate 	creds.ticket_flags = TKT_FLG_RENEWABLE;
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 	if ((krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_FLAGS,
859*7c478bd9Sstevel@tonic-gate 			&creds, &tmpcreds))) {
860*7c478bd9Sstevel@tonic-gate 		(void) krb5_cc_close(context, ccache);
861*7c478bd9Sstevel@tonic-gate 		return (KDC_ERR_BADOPTION);
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	creds.ticket_flags = 0;
865*7c478bd9Sstevel@tonic-gate         code = krb5_get_credentials_renew(context, options, ccache,
866*7c478bd9Sstevel@tonic-gate 						&creds, &out_creds);
867*7c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(context, &creds);
868*7c478bd9Sstevel@tonic-gate 	krb5_free_cred_contents(context, &tmpcreds);
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 	if (code) {
871*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
872*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
873*7c478bd9Sstevel@tonic-gate 	}
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	krb5_free_creds(context, out_creds);
876*7c478bd9Sstevel@tonic-gate 	snprintf(ccache_name_buf, CACHE_FILENAME_LEN, "/tmp/krb5cc_%d",
877*7c478bd9Sstevel@tonic-gate 		uid, -1);
878*7c478bd9Sstevel@tonic-gate 	code = safechown(ccache_name_buf, uid, gid, -1);
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	if (code == -1) {
881*7c478bd9Sstevel@tonic-gate 		(void) krb5_cc_destroy(context, ccache);
882*7c478bd9Sstevel@tonic-gate 		*minor_status = code;
883*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
884*7c478bd9Sstevel@tonic-gate 	}
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	(void) krb5_cc_close(context, ccache);
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate }
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate /*
893*7c478bd9Sstevel@tonic-gate  * Solaris Kerberos:
894*7c478bd9Sstevel@tonic-gate  * We enforce a minimum refresh time on the root cred. This avoids problems for
895*7c478bd9Sstevel@tonic-gate  * the higher level communication protocol for having valid creds and
896*7c478bd9Sstevel@tonic-gate  * setting up a valid context, only to have it expire before or while
897*7c478bd9Sstevel@tonic-gate  * it is being used. For non root users we don't care since we do not refresh
898*7c478bd9Sstevel@tonic-gate  * there creds, they get what they can get.
899*7c478bd9Sstevel@tonic-gate  */
900*7c478bd9Sstevel@tonic-gate #define MIN_REFRESH_TIME 300
901*7c478bd9Sstevel@tonic-gate #define MIN_RENEW_TIME 1500
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate /* get_default_cred() must be called with the krb5_mutex lock held */
904*7c478bd9Sstevel@tonic-gate static OM_uint32
905*7c478bd9Sstevel@tonic-gate get_default_cred(OM_uint32 *minor_status, void *ct, gss_cred_id_t *cred_handle)
906*7c478bd9Sstevel@tonic-gate {
907*7c478bd9Sstevel@tonic-gate 	krb5_timestamp now;
908*7c478bd9Sstevel@tonic-gate 	krb5_gss_cred_id_t cred;
909*7c478bd9Sstevel@tonic-gate 	OM_uint32 major;
910*7c478bd9Sstevel@tonic-gate 	OM_uint32 mntmp;
911*7c478bd9Sstevel@tonic-gate 	uid_t uid = getuid();
912*7c478bd9Sstevel@tonic-gate 	krb5_context context = (krb5_context)ct;
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_INFO, "get_default_cred() start\n");
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	/* Get the default cred for user */
917*7c478bd9Sstevel@tonic-gate 	if (((major = kg_get_defcred(minor_status, cred_handle)) != NULL) &&
918*7c478bd9Sstevel@tonic-gate 	    GSS_ERROR(major)) {
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 		/* If we're not root we're done */
921*7c478bd9Sstevel@tonic-gate    		if (uid != ROOT_UID)
922*7c478bd9Sstevel@tonic-gate 	 		return (major);
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 		/*
925*7c478bd9Sstevel@tonic-gate 		 * Try and get root's cred in the cache using keytab.
926*7c478bd9Sstevel@tonic-gate 		 *
927*7c478bd9Sstevel@tonic-gate 		 * First try "root" and then try "host" - this allows
928*7c478bd9Sstevel@tonic-gate 		 * Secure NFS to use the host principal for mounting if
929*7c478bd9Sstevel@tonic-gate 		 * there is no root principal.
930*7c478bd9Sstevel@tonic-gate 		 *
931*7c478bd9Sstevel@tonic-gate 		 * Then try "host/<anything>" to match any instance (needed
932*7c478bd9Sstevel@tonic-gate 		 * for DHCP clients).
933*7c478bd9Sstevel@tonic-gate 		 */
934*7c478bd9Sstevel@tonic-gate 		major = load_root_cred_using_keytab(minor_status,
935*7c478bd9Sstevel@tonic-gate 						    context, "root", 1);
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
938*7c478bd9Sstevel@tonic-gate 			major = load_root_cred_using_keytab(minor_status,
939*7c478bd9Sstevel@tonic-gate 							    context, "host", 1);
940*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
941*7c478bd9Sstevel@tonic-gate 			major = load_root_cred_using_keytab(minor_status,
942*7c478bd9Sstevel@tonic-gate 							    context, "host", 0);
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
945*7c478bd9Sstevel@tonic-gate 			return (major);
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 		/* We should have valid tgt now in the cache, so get it. */
948*7c478bd9Sstevel@tonic-gate 		major = kg_get_defcred(minor_status, cred_handle);
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 		return (major);
951*7c478bd9Sstevel@tonic-gate       	}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	/* We've got a gss cred handle that is a kerberos cred handle. */
954*7c478bd9Sstevel@tonic-gate 	cred = (krb5_gss_cred_id_t)*cred_handle;
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	/* If we can't get the time, assume the worst. */
957*7c478bd9Sstevel@tonic-gate 	if (krb5_timeofday(context, &now)) {
958*7c478bd9Sstevel@tonic-gate 		(void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle);
959*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CREDENTIALS_EXPIRED);
960*7c478bd9Sstevel@tonic-gate 	}
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	/* If root's cred has expired re-get it */
963*7c478bd9Sstevel@tonic-gate 	if (cred->tgt_expire < now + MIN_REFRESH_TIME && uid == ROOT_UID) {
964*7c478bd9Sstevel@tonic-gate 		(void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle);
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 		major = load_root_cred_using_keytab(minor_status,
967*7c478bd9Sstevel@tonic-gate 						    context, "root", 1);
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
970*7c478bd9Sstevel@tonic-gate 			major = load_root_cred_using_keytab(minor_status,
971*7c478bd9Sstevel@tonic-gate 							    context, "host", 1);
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
974*7c478bd9Sstevel@tonic-gate 			major = load_root_cred_using_keytab(minor_status,
975*7c478bd9Sstevel@tonic-gate 							    context, "host", 0);
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
978*7c478bd9Sstevel@tonic-gate 			return (major);
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 		major = kg_get_defcred(minor_status, cred_handle);
981*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
982*7c478bd9Sstevel@tonic-gate 			return (major);
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	/* Any body else is SOL unless we can renew their credential cache */
985*7c478bd9Sstevel@tonic-gate 	} else if ((cred->tgt_expire < now + MIN_RENEW_TIME) &&
986*7c478bd9Sstevel@tonic-gate 			(cred->tgt_expire > now)) {
987*7c478bd9Sstevel@tonic-gate 		(void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle);
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 		major = renew_ccache(minor_status, context, uid);
990*7c478bd9Sstevel@tonic-gate 		if ((major != GSS_S_COMPLETE) &&
991*7c478bd9Sstevel@tonic-gate 			(major != KDC_ERR_BADOPTION))
992*7c478bd9Sstevel@tonic-gate 			return (major);
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 		major = kg_get_defcred(minor_status, cred_handle);
995*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
996*7c478bd9Sstevel@tonic-gate 			return (major);
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	}
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	/* Otherwise we got non expired creds */
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_INFO, "get_default_cred() end\n");
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
1005*7c478bd9Sstevel@tonic-gate }
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate /*
1008*7c478bd9Sstevel@tonic-gate  * setup_enc
1009*7c478bd9Sstevel@tonic-gate  *
1010*7c478bd9Sstevel@tonic-gate  * Fill in the encryption descriptors.	Called after AP-REQ is made.
1011*7c478bd9Sstevel@tonic-gate  */
1012*7c478bd9Sstevel@tonic-gate static OM_uint32
1013*7c478bd9Sstevel@tonic-gate setup_enc(
1014*7c478bd9Sstevel@tonic-gate    OM_uint32 *minor_status,
1015*7c478bd9Sstevel@tonic-gate    krb5_gss_ctx_id_rec *ctx,
1016*7c478bd9Sstevel@tonic-gate    krb5_context context)
1017*7c478bd9Sstevel@tonic-gate {
1018*7c478bd9Sstevel@tonic-gate    krb5_error_code code;
1019*7c478bd9Sstevel@tonic-gate    OM_uint32 ret = GSS_S_COMPLETE;
1020*7c478bd9Sstevel@tonic-gate    int i;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate    ctx->have_acceptor_subkey = 0;
1023*7c478bd9Sstevel@tonic-gate    ctx->proto = 0;
1024*7c478bd9Sstevel@tonic-gate    ctx->cksumtype = 0;
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate    KRB5_LOG(KRB5_ERR, "setup_enc() enctype = %d\n",
1027*7c478bd9Sstevel@tonic-gate 	ctx->subkey->enctype);
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate    switch(ctx->subkey->enctype) {
1030*7c478bd9Sstevel@tonic-gate    case ENCTYPE_DES_CBC_MD5:
1031*7c478bd9Sstevel@tonic-gate    case ENCTYPE_DES_CBC_MD4:
1032*7c478bd9Sstevel@tonic-gate    case ENCTYPE_DES_CBC_CRC:
1033*7c478bd9Sstevel@tonic-gate 	ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
1034*7c478bd9Sstevel@tonic-gate 	ctx->signalg = SGN_ALG_DES_MAC_MD5;
1035*7c478bd9Sstevel@tonic-gate 	ctx->cksum_size = 8;
1036*7c478bd9Sstevel@tonic-gate 	ctx->sealalg = SEAL_ALG_DES;
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	/* The encryption key is the session key XOR
1039*7c478bd9Sstevel@tonic-gate 	 0xf0f0f0f0f0f0f0f0.  */
1040*7c478bd9Sstevel@tonic-gate 	if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc)))
1041*7c478bd9Sstevel@tonic-gate 	    goto fail;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	for (i=0; i<ctx->enc->length; i++)
1044*7c478bd9Sstevel@tonic-gate 	    ctx->enc->contents[i] ^= 0xf0;
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	goto copy_subkey_to_seq;
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate    case ENCTYPE_DES3_CBC_SHA1:
1049*7c478bd9Sstevel@tonic-gate 	/* MIT extension */
1050*7c478bd9Sstevel@tonic-gate 	ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
1051*7c478bd9Sstevel@tonic-gate 	ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
1052*7c478bd9Sstevel@tonic-gate 	ctx->cksum_size = 20;
1053*7c478bd9Sstevel@tonic-gate 	ctx->sealalg = SEAL_ALG_DES3KD;
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate    copy_subkey:
1056*7c478bd9Sstevel@tonic-gate 	code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
1057*7c478bd9Sstevel@tonic-gate 	if (code)
1058*7c478bd9Sstevel@tonic-gate 	    goto fail;
1059*7c478bd9Sstevel@tonic-gate    copy_subkey_to_seq:
1060*7c478bd9Sstevel@tonic-gate 	code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
1061*7c478bd9Sstevel@tonic-gate 	if (code) {
1062*7c478bd9Sstevel@tonic-gate 	    krb5_free_keyblock (context, ctx->enc);
1063*7c478bd9Sstevel@tonic-gate 	    goto fail;
1064*7c478bd9Sstevel@tonic-gate 	}
1065*7c478bd9Sstevel@tonic-gate 	break;
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate    case ENCTYPE_ARCFOUR_HMAC:
1068*7c478bd9Sstevel@tonic-gate 	/* Microsoft extension */
1069*7c478bd9Sstevel@tonic-gate 	ctx->signalg = SGN_ALG_HMAC_MD5 ;
1070*7c478bd9Sstevel@tonic-gate 	ctx->cksum_size = 8;
1071*7c478bd9Sstevel@tonic-gate 	ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	goto copy_subkey;
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate    default:
1076*7c478bd9Sstevel@tonic-gate        /* Fill some fields we shouldn't be using on this path
1077*7c478bd9Sstevel@tonic-gate 	  with garbage.	 */
1078*7c478bd9Sstevel@tonic-gate 	ctx->signalg = -10;
1079*7c478bd9Sstevel@tonic-gate 	ctx->sealalg = -10;
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	ctx->proto = 1;
1082*7c478bd9Sstevel@tonic-gate 	code = krb5int_c_mandatory_cksumtype(context, ctx->subkey->enctype,
1083*7c478bd9Sstevel@tonic-gate 		&ctx->cksumtype);
1084*7c478bd9Sstevel@tonic-gate 	if (code)
1085*7c478bd9Sstevel@tonic-gate 	    goto fail;
1086*7c478bd9Sstevel@tonic-gate 	code = krb5_c_checksum_length(context, ctx->cksumtype,
1087*7c478bd9Sstevel@tonic-gate 				(size_t *)&ctx->cksum_size);
1088*7c478bd9Sstevel@tonic-gate 	if (code)
1089*7c478bd9Sstevel@tonic-gate 	    goto fail;
1090*7c478bd9Sstevel@tonic-gate 	goto copy_subkey;
1091*7c478bd9Sstevel@tonic-gate    }
1092*7c478bd9Sstevel@tonic-gate fail:
1093*7c478bd9Sstevel@tonic-gate    if (code) {
1094*7c478bd9Sstevel@tonic-gate 	*minor_status = code;
1095*7c478bd9Sstevel@tonic-gate 	ret = GSS_S_FAILURE;
1096*7c478bd9Sstevel@tonic-gate    }
1097*7c478bd9Sstevel@tonic-gate success:
1098*7c478bd9Sstevel@tonic-gate    return (ret);
1099*7c478bd9Sstevel@tonic-gate }
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate /*
1102*7c478bd9Sstevel@tonic-gate  * new_connection
1103*7c478bd9Sstevel@tonic-gate  *
1104*7c478bd9Sstevel@tonic-gate  * Do the grunt work of setting up a new context.
1105*7c478bd9Sstevel@tonic-gate  */
1106*7c478bd9Sstevel@tonic-gate static OM_uint32
1107*7c478bd9Sstevel@tonic-gate new_connection(
1108*7c478bd9Sstevel@tonic-gate    OM_uint32 *minor_status,
1109*7c478bd9Sstevel@tonic-gate    krb5_gss_cred_id_t cred,
1110*7c478bd9Sstevel@tonic-gate    gss_ctx_id_t *context_handle,
1111*7c478bd9Sstevel@tonic-gate    gss_name_t target_name,
1112*7c478bd9Sstevel@tonic-gate    gss_OID mech_type,
1113*7c478bd9Sstevel@tonic-gate    OM_uint32 req_flags,
1114*7c478bd9Sstevel@tonic-gate    OM_uint32 time_req,
1115*7c478bd9Sstevel@tonic-gate    gss_channel_bindings_t input_chan_bindings,
1116*7c478bd9Sstevel@tonic-gate    gss_buffer_t input_token,
1117*7c478bd9Sstevel@tonic-gate    gss_OID *actual_mech_type,
1118*7c478bd9Sstevel@tonic-gate    gss_buffer_t output_token,
1119*7c478bd9Sstevel@tonic-gate    OM_uint32 *ret_flags,
1120*7c478bd9Sstevel@tonic-gate    OM_uint32 *time_rec,
1121*7c478bd9Sstevel@tonic-gate    krb5_context context,
1122*7c478bd9Sstevel@tonic-gate    int default_mech)
1123*7c478bd9Sstevel@tonic-gate {
1124*7c478bd9Sstevel@tonic-gate    OM_uint32 major_status;
1125*7c478bd9Sstevel@tonic-gate    krb5_error_code code;
1126*7c478bd9Sstevel@tonic-gate    krb5_creds *k_cred;
1127*7c478bd9Sstevel@tonic-gate    krb5_gss_ctx_id_rec *ctx, *ctx_free;
1128*7c478bd9Sstevel@tonic-gate    krb5_timestamp now;
1129*7c478bd9Sstevel@tonic-gate    gss_buffer_desc token;
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate    major_status = GSS_S_FAILURE;
1132*7c478bd9Sstevel@tonic-gate    token.length = 0;
1133*7c478bd9Sstevel@tonic-gate    token.value = NULL;
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate    /* make sure the cred is usable for init */
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate    if ((cred->usage != GSS_C_INITIATE) &&
1138*7c478bd9Sstevel@tonic-gate 	(cred->usage != GSS_C_BOTH)) {
1139*7c478bd9Sstevel@tonic-gate 	*minor_status = 0;
1140*7c478bd9Sstevel@tonic-gate 	return(GSS_S_NO_CRED);
1141*7c478bd9Sstevel@tonic-gate    }
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate    /* complain if the input token is non-null */
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate    if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
1146*7c478bd9Sstevel@tonic-gate        *minor_status = 0;
1147*7c478bd9Sstevel@tonic-gate 	return(GSS_S_DEFECTIVE_TOKEN);
1148*7c478bd9Sstevel@tonic-gate    }
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate    /* create the ctx */
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate    if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
1153*7c478bd9Sstevel@tonic-gate 	== NULL) {
1154*7c478bd9Sstevel@tonic-gate 	*minor_status = ENOMEM;
1155*7c478bd9Sstevel@tonic-gate 	return(GSS_S_FAILURE);
1156*7c478bd9Sstevel@tonic-gate    }
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate    /* fill in the ctx */
1159*7c478bd9Sstevel@tonic-gate    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
1160*7c478bd9Sstevel@tonic-gate    ctx_free = ctx;
1161*7c478bd9Sstevel@tonic-gate    if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
1162*7c478bd9Sstevel@tonic-gate 	goto fail;
1163*7c478bd9Sstevel@tonic-gate    krb5_auth_con_setflags(context, ctx->auth_context,
1164*7c478bd9Sstevel@tonic-gate                           KRB5_AUTH_CONTEXT_DO_SEQUENCE);
1165*7c478bd9Sstevel@tonic-gate    ctx->initiate = 1;
1166*7c478bd9Sstevel@tonic-gate    ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
1167*7c478bd9Sstevel@tonic-gate                       GSS_C_TRANS_FLAG |  GSS_C_PROT_READY_FLAG |
1168*7c478bd9Sstevel@tonic-gate                       ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
1169*7c478bd9Sstevel@tonic-gate                                       GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
1170*7c478bd9Sstevel@tonic-gate    ctx->seed_init = 0;
1171*7c478bd9Sstevel@tonic-gate    ctx->big_endian = 0;	 /* all initiators do little-endian, as per spec */
1172*7c478bd9Sstevel@tonic-gate    ctx->seqstate = 0;
1173*7c478bd9Sstevel@tonic-gate    if ((code = krb5_timeofday(context, &now)))
1174*7c478bd9Sstevel@tonic-gate 	goto fail;
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate    if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
1177*7c478bd9Sstevel@tonic-gate 	ctx->endtime = 0;
1178*7c478bd9Sstevel@tonic-gate    } else {
1179*7c478bd9Sstevel@tonic-gate       ctx->endtime = now + time_req;
1180*7c478bd9Sstevel@tonic-gate    }
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here)))
1183*7c478bd9Sstevel@tonic-gate 	goto fail;
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate    if ((code = krb5_copy_principal(context, (krb5_principal) target_name,
1186*7c478bd9Sstevel@tonic-gate                                    &ctx->there)))
1187*7c478bd9Sstevel@tonic-gate 	goto fail;
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate    code = get_credentials(context, cred, ctx->there, now,
1190*7c478bd9Sstevel@tonic-gate                           ctx->endtime, &k_cred);
1191*7c478bd9Sstevel@tonic-gate    if (code)
1192*7c478bd9Sstevel@tonic-gate       goto fail;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate    if (default_mech) {
1195*7c478bd9Sstevel@tonic-gate 	mech_type = (gss_OID) gss_mech_krb5;
1196*7c478bd9Sstevel@tonic-gate    }
1197*7c478bd9Sstevel@tonic-gate       /* Solaris Kerberos:  we allocate the memory for mech_used here
1198*7c478bd9Sstevel@tonic-gate        * because we store mech_used as a gss_OID and not a (gss_OID *)
1199*7c478bd9Sstevel@tonic-gate        */
1200*7c478bd9Sstevel@tonic-gate    ctx->mech_used.elements = malloc(mech_type->length);
1201*7c478bd9Sstevel@tonic-gate    if ( (ctx->mech_used.elements) == NULL ) {
1202*7c478bd9Sstevel@tonic-gate 	code = ENOMEM;
1203*7c478bd9Sstevel@tonic-gate 	major_status = GSS_S_FAILURE;
1204*7c478bd9Sstevel@tonic-gate 	goto fail;
1205*7c478bd9Sstevel@tonic-gate    }
1206*7c478bd9Sstevel@tonic-gate    ctx->mech_used.length = mech_type->length;
1207*7c478bd9Sstevel@tonic-gate    memcpy(ctx->mech_used.elements, mech_type->elements, mech_type->length);
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate    /*
1210*7c478bd9Sstevel@tonic-gate     * Now try to make it static if at all possible....
1211*7c478bd9Sstevel@tonic-gate     */
1212*7c478bd9Sstevel@tonic-gate    /* Solaris Kerberos:  our mech_used is part of the ctx structure */
1213*7c478bd9Sstevel@tonic-gate    /* ctx->mech_used = krb5_gss_convert_static_mech_oid(&(ctx->mech_used)); */
1214*7c478bd9Sstevel@tonic-gate    {
1215*7c478bd9Sstevel@tonic-gate       /* gsskrb5 v1 */
1216*7c478bd9Sstevel@tonic-gate 	krb5_ui_4 seq_temp;
1217*7c478bd9Sstevel@tonic-gate 	if ((code = make_ap_req_v1(context, ctx,
1218*7c478bd9Sstevel@tonic-gate                                  cred, k_cred, input_chan_bindings,
1219*7c478bd9Sstevel@tonic-gate                                  mech_type, &token))) {
1220*7c478bd9Sstevel@tonic-gate 	 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
1221*7c478bd9Sstevel@tonic-gate              (code == KG_EMPTY_CCACHE))
1222*7c478bd9Sstevel@tonic-gate             major_status = GSS_S_NO_CRED;
1223*7c478bd9Sstevel@tonic-gate 	 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
1224*7c478bd9Sstevel@tonic-gate             major_status = GSS_S_CREDENTIALS_EXPIRED;
1225*7c478bd9Sstevel@tonic-gate 	 goto fail;
1226*7c478bd9Sstevel@tonic-gate 	}
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	krb5_auth_con_getlocalseqnumber(context, ctx->auth_context,
1229*7c478bd9Sstevel@tonic-gate 		(krb5_int32 *)&seq_temp);
1230*7c478bd9Sstevel@tonic-gate 	ctx->seq_send = seq_temp;
1231*7c478bd9Sstevel@tonic-gate 	krb5_auth_con_getsendsubkey(context, ctx->auth_context,
1232*7c478bd9Sstevel@tonic-gate                                   &ctx->subkey);
1233*7c478bd9Sstevel@tonic-gate    }
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate    major_status = setup_enc(minor_status, ctx, context);
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate    if (k_cred) {
1238*7c478bd9Sstevel@tonic-gate 	krb5_free_creds(context, k_cred);
1239*7c478bd9Sstevel@tonic-gate 	k_cred = 0;
1240*7c478bd9Sstevel@tonic-gate    }
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate    /* at this point, the context is constructed and valid,
1243*7c478bd9Sstevel@tonic-gate 	hence, releaseable */
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate    /* intern the context handle */
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
1248*7c478bd9Sstevel@tonic-gate 	code = G_VALIDATE_FAILED;
1249*7c478bd9Sstevel@tonic-gate 	goto fail;
1250*7c478bd9Sstevel@tonic-gate    }
1251*7c478bd9Sstevel@tonic-gate    *context_handle = (gss_ctx_id_t) ctx;
1252*7c478bd9Sstevel@tonic-gate    ctx_free = 0;
1253*7c478bd9Sstevel@tonic-gate    /* compute time_rec */
1254*7c478bd9Sstevel@tonic-gate    if (time_rec) {
1255*7c478bd9Sstevel@tonic-gate 	if ((code = krb5_timeofday(context, &now)))
1256*7c478bd9Sstevel@tonic-gate 	    goto fail;
1257*7c478bd9Sstevel@tonic-gate 	*time_rec = ctx->endtime - now;
1258*7c478bd9Sstevel@tonic-gate    }
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate    /* set the other returns */
1261*7c478bd9Sstevel@tonic-gate    *output_token = token;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate    if (ret_flags)
1264*7c478bd9Sstevel@tonic-gate 	*ret_flags = ctx->gss_flags;
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate    if (actual_mech_type)
1267*7c478bd9Sstevel@tonic-gate 	*actual_mech_type = mech_type;
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate    /* return successfully */
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate    *minor_status = 0;
1272*7c478bd9Sstevel@tonic-gate    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1273*7c478bd9Sstevel@tonic-gate 	ctx->established = 0;
1274*7c478bd9Sstevel@tonic-gate 	return(GSS_S_CONTINUE_NEEDED);
1275*7c478bd9Sstevel@tonic-gate    } else {
1276*7c478bd9Sstevel@tonic-gate       ctx->seq_recv = ctx->seq_send;
1277*7c478bd9Sstevel@tonic-gate 	g_order_init(&(ctx->seqstate), ctx->seq_recv,
1278*7c478bd9Sstevel@tonic-gate                    (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
1279*7c478bd9Sstevel@tonic-gate                    (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
1280*7c478bd9Sstevel@tonic-gate 	ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1281*7c478bd9Sstevel@tonic-gate 	ctx->established = 1;
1282*7c478bd9Sstevel@tonic-gate 	return(GSS_S_COMPLETE);
1283*7c478bd9Sstevel@tonic-gate    }
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate fail:
1286*7c478bd9Sstevel@tonic-gate    if (ctx_free) {
1287*7c478bd9Sstevel@tonic-gate 	if (ctx_free->auth_context)
1288*7c478bd9Sstevel@tonic-gate 	   krb5_auth_con_free(context, ctx_free->auth_context);
1289*7c478bd9Sstevel@tonic-gate 	if (ctx_free->here)
1290*7c478bd9Sstevel@tonic-gate 	   krb5_free_principal(context, ctx_free->here);
1291*7c478bd9Sstevel@tonic-gate 	if (ctx_free->there)
1292*7c478bd9Sstevel@tonic-gate 	   krb5_free_principal(context, ctx_free->there);
1293*7c478bd9Sstevel@tonic-gate 	if (ctx_free->subkey)
1294*7c478bd9Sstevel@tonic-gate 	   krb5_free_keyblock(context, ctx_free->subkey);
1295*7c478bd9Sstevel@tonic-gate 	xfree(ctx_free);
1296*7c478bd9Sstevel@tonic-gate    } else
1297*7c478bd9Sstevel@tonic-gate         (void)krb5_gss_delete_sec_context(context, minor_status, context_handle, NULL);
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate    *minor_status = code;
1300*7c478bd9Sstevel@tonic-gate    return (major_status);
1301*7c478bd9Sstevel@tonic-gate }
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate /*
1304*7c478bd9Sstevel@tonic-gate  * mutual_auth
1305*7c478bd9Sstevel@tonic-gate  *
1306*7c478bd9Sstevel@tonic-gate  * Handle the reply from the acceptor, if we're doing mutual auth.
1307*7c478bd9Sstevel@tonic-gate  */
1308*7c478bd9Sstevel@tonic-gate static OM_uint32
1309*7c478bd9Sstevel@tonic-gate mutual_auth(
1310*7c478bd9Sstevel@tonic-gate    OM_uint32 *minor_status,
1311*7c478bd9Sstevel@tonic-gate    krb5_gss_cred_id_t cred,
1312*7c478bd9Sstevel@tonic-gate    gss_ctx_id_t *context_handle,
1313*7c478bd9Sstevel@tonic-gate    gss_name_t target_name,
1314*7c478bd9Sstevel@tonic-gate    gss_OID mech_type,
1315*7c478bd9Sstevel@tonic-gate    OM_uint32 req_flags,
1316*7c478bd9Sstevel@tonic-gate    OM_uint32 time_req,
1317*7c478bd9Sstevel@tonic-gate    gss_channel_bindings_t input_chan_bindings,
1318*7c478bd9Sstevel@tonic-gate    gss_buffer_t input_token,
1319*7c478bd9Sstevel@tonic-gate    gss_OID *actual_mech_type,
1320*7c478bd9Sstevel@tonic-gate    gss_buffer_t output_token,
1321*7c478bd9Sstevel@tonic-gate    OM_uint32 *ret_flags,
1322*7c478bd9Sstevel@tonic-gate    OM_uint32 *time_rec,
1323*7c478bd9Sstevel@tonic-gate    krb5_context context)
1324*7c478bd9Sstevel@tonic-gate {
1325*7c478bd9Sstevel@tonic-gate    OM_uint32 major_status;
1326*7c478bd9Sstevel@tonic-gate    unsigned char *ptr;
1327*7c478bd9Sstevel@tonic-gate    char *sptr;
1328*7c478bd9Sstevel@tonic-gate    krb5_data ap_rep;
1329*7c478bd9Sstevel@tonic-gate    krb5_ap_rep_enc_part *ap_rep_data;
1330*7c478bd9Sstevel@tonic-gate    krb5_timestamp now;
1331*7c478bd9Sstevel@tonic-gate    krb5_gss_ctx_id_rec *ctx;
1332*7c478bd9Sstevel@tonic-gate    krb5_error *krb_error;
1333*7c478bd9Sstevel@tonic-gate    krb5_error_code code;
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate    major_status = GSS_S_FAILURE;
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate    /* validate the context handle */
1338*7c478bd9Sstevel@tonic-gate    /*SUPPRESS 29*/
1339*7c478bd9Sstevel@tonic-gate    if (! kg_validate_ctx_id(*context_handle)) {
1340*7c478bd9Sstevel@tonic-gate 	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
1341*7c478bd9Sstevel@tonic-gate 	return(GSS_S_NO_CONTEXT);
1342*7c478bd9Sstevel@tonic-gate    }
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate    ctx = (krb5_gss_ctx_id_rec *) *context_handle;
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate    /* make sure the context is non-established, and that certain
1347*7c478bd9Sstevel@tonic-gate 	arguments are unchanged */
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate    if ((ctx->established) ||
1350*7c478bd9Sstevel@tonic-gate 	((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
1351*7c478bd9Sstevel@tonic-gate 	code = KG_CONTEXT_ESTABLISHED;
1352*7c478bd9Sstevel@tonic-gate 	goto fail;
1353*7c478bd9Sstevel@tonic-gate    }
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate    if (! krb5_principal_compare(context, ctx->there,
1356*7c478bd9Sstevel@tonic-gate 				(krb5_principal) target_name)) {
1357*7c478bd9Sstevel@tonic-gate 	(void)krb5_gss_delete_sec_context(context, minor_status,
1358*7c478bd9Sstevel@tonic-gate                                         context_handle, NULL);
1359*7c478bd9Sstevel@tonic-gate 	code = 0;
1360*7c478bd9Sstevel@tonic-gate 	major_status = GSS_S_BAD_NAME;
1361*7c478bd9Sstevel@tonic-gate 	goto fail;
1362*7c478bd9Sstevel@tonic-gate    }
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate    /* verify the token and leave the AP_REP message in ap_rep */
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate    if (input_token == GSS_C_NO_BUFFER) {
1367*7c478bd9Sstevel@tonic-gate 	(void)krb5_gss_delete_sec_context(context, minor_status,
1368*7c478bd9Sstevel@tonic-gate                                         context_handle, NULL);
1369*7c478bd9Sstevel@tonic-gate 	code = 0;
1370*7c478bd9Sstevel@tonic-gate 	major_status = GSS_S_DEFECTIVE_TOKEN;
1371*7c478bd9Sstevel@tonic-gate 	goto fail;
1372*7c478bd9Sstevel@tonic-gate    }
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate    ptr = (unsigned char *) input_token->value;
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate    if (g_verify_token_header(&ctx->mech_used,
1377*7c478bd9Sstevel@tonic-gate                              (uint32_t *)&(ap_rep.length),
1378*7c478bd9Sstevel@tonic-gate                              &ptr, KG_TOK_CTX_AP_REP,
1379*7c478bd9Sstevel@tonic-gate                              input_token->length, 1)) {
1380*7c478bd9Sstevel@tonic-gate 	if (g_verify_token_header(&ctx->mech_used,
1381*7c478bd9Sstevel@tonic-gate 				(uint32_t *)&(ap_rep.length),
1382*7c478bd9Sstevel@tonic-gate 				&ptr, KG_TOK_CTX_ERROR,
1383*7c478bd9Sstevel@tonic-gate 				input_token->length, 1) == 0) {
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 	 /* Handle a KRB_ERROR message from the server */
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	 sptr = (char *) ptr;		/* PC compiler bug */
1388*7c478bd9Sstevel@tonic-gate 	 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate 	 code = krb5_rd_error(context, &ap_rep, &krb_error);
1391*7c478bd9Sstevel@tonic-gate 	 if (code)
1392*7c478bd9Sstevel@tonic-gate             goto fail;
1393*7c478bd9Sstevel@tonic-gate 	 if (krb_error->error)
1394*7c478bd9Sstevel@tonic-gate             code = krb_error->error + ERROR_TABLE_BASE_krb5;
1395*7c478bd9Sstevel@tonic-gate 	 else
1396*7c478bd9Sstevel@tonic-gate             code = 0;
1397*7c478bd9Sstevel@tonic-gate 	 krb5_free_error(context, krb_error);
1398*7c478bd9Sstevel@tonic-gate 	 goto fail;
1399*7c478bd9Sstevel@tonic-gate 	} else {
1400*7c478bd9Sstevel@tonic-gate 	 *minor_status = 0;
1401*7c478bd9Sstevel@tonic-gate 	 return(GSS_S_DEFECTIVE_TOKEN);
1402*7c478bd9Sstevel@tonic-gate 	}
1403*7c478bd9Sstevel@tonic-gate    }
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate    sptr = (char *) ptr;                      /* PC compiler bug */
1406*7c478bd9Sstevel@tonic-gate    TREAD_STR(sptr, ap_rep.data, ap_rep.length);
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate    /* decode the ap_rep */
1409*7c478bd9Sstevel@tonic-gate    if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
1410*7c478bd9Sstevel@tonic-gate                            &ap_rep_data))) {
1411*7c478bd9Sstevel@tonic-gate 	/*
1412*7c478bd9Sstevel@tonic-gate        * XXX A hack for backwards compatiblity.
1413*7c478bd9Sstevel@tonic-gate 	* To be removed in 1999 -- proven
1414*7c478bd9Sstevel@tonic-gate 	*/
1415*7c478bd9Sstevel@tonic-gate       krb5_auth_con_setuseruserkey(context, ctx->auth_context,
1416*7c478bd9Sstevel@tonic-gate                                    ctx->subkey);
1417*7c478bd9Sstevel@tonic-gate 	if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
1418*7c478bd9Sstevel@tonic-gate 			&ap_rep_data)))
1419*7c478bd9Sstevel@tonic-gate 	 goto fail;
1420*7c478bd9Sstevel@tonic-gate    }
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate    /* store away the sequence number */
1423*7c478bd9Sstevel@tonic-gate    ctx->seq_recv = ap_rep_data->seq_number;
1424*7c478bd9Sstevel@tonic-gate    g_order_init(&(ctx->seqstate), ctx->seq_recv,
1425*7c478bd9Sstevel@tonic-gate 		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
1426*7c478bd9Sstevel@tonic-gate 		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto);
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate    if (ctx->proto == 1 && ap_rep_data->subkey) {
1429*7c478bd9Sstevel@tonic-gate 	/* Keep acceptor's subkey.  */
1430*7c478bd9Sstevel@tonic-gate 	ctx->have_acceptor_subkey = 1;
1431*7c478bd9Sstevel@tonic-gate 	code = krb5_copy_keyblock(context, ap_rep_data->subkey,
1432*7c478bd9Sstevel@tonic-gate                                  &ctx->acceptor_subkey);
1433*7c478bd9Sstevel@tonic-gate 	if (code)
1434*7c478bd9Sstevel@tonic-gate            goto fail;
1435*7c478bd9Sstevel@tonic-gate 	code = krb5int_c_mandatory_cksumtype(context,
1436*7c478bd9Sstevel@tonic-gate 		ctx->acceptor_subkey->enctype,
1437*7c478bd9Sstevel@tonic-gate 		&ctx->acceptor_subkey_cksumtype);
1438*7c478bd9Sstevel@tonic-gate 	if (code)
1439*7c478bd9Sstevel@tonic-gate            goto fail;
1440*7c478bd9Sstevel@tonic-gate    }
1441*7c478bd9Sstevel@tonic-gate 
1442*7c478bd9Sstevel@tonic-gate    /* free the ap_rep_data */
1443*7c478bd9Sstevel@tonic-gate    krb5_free_ap_rep_enc_part(context, ap_rep_data);
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate    /* set established */
1446*7c478bd9Sstevel@tonic-gate    ctx->established = 1;
1447*7c478bd9Sstevel@tonic-gate 
1448*7c478bd9Sstevel@tonic-gate    /* set returns */
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate    if (time_rec) {
1451*7c478bd9Sstevel@tonic-gate 	if ((code = krb5_timeofday(context, &now)))
1452*7c478bd9Sstevel@tonic-gate 	 goto fail;
1453*7c478bd9Sstevel@tonic-gate 	*time_rec = ctx->endtime - now;
1454*7c478bd9Sstevel@tonic-gate    }
1455*7c478bd9Sstevel@tonic-gate    if (ret_flags)
1456*7c478bd9Sstevel@tonic-gate 	*ret_flags = ctx->gss_flags;
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate    if (actual_mech_type)
1459*7c478bd9Sstevel@tonic-gate 	*actual_mech_type = mech_type;
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate    /* success */
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate    *minor_status = 0;
1464*7c478bd9Sstevel@tonic-gate    return GSS_S_COMPLETE;
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate fail:
1467*7c478bd9Sstevel@tonic-gate    (void)krb5_gss_delete_sec_context(context, minor_status, context_handle, NULL);
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate    *minor_status = code;
1470*7c478bd9Sstevel@tonic-gate    return (major_status);
1471*7c478bd9Sstevel@tonic-gate }
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate /*
1474*7c478bd9Sstevel@tonic-gate  * krb5_gss_init_sec_context
1475*7c478bd9Sstevel@tonic-gate  * This has been broken up into smaller chunks for CFX support.
1476*7c478bd9Sstevel@tonic-gate  * MIT KRB5 1.3.2
1477*7c478bd9Sstevel@tonic-gate  */
1478*7c478bd9Sstevel@tonic-gate OM_uint32
1479*7c478bd9Sstevel@tonic-gate krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
1480*7c478bd9Sstevel@tonic-gate 			  context_handle, target_name, mech_type,
1481*7c478bd9Sstevel@tonic-gate 			  req_flags, time_req, input_chan_bindings,
1482*7c478bd9Sstevel@tonic-gate 			  input_token, actual_mech_type, output_token,
1483*7c478bd9Sstevel@tonic-gate 			  ret_flags, time_rec)
1484*7c478bd9Sstevel@tonic-gate     void      *ct;
1485*7c478bd9Sstevel@tonic-gate     OM_uint32 *minor_status;
1486*7c478bd9Sstevel@tonic-gate     gss_cred_id_t claimant_cred_handle;
1487*7c478bd9Sstevel@tonic-gate     gss_ctx_id_t *context_handle;
1488*7c478bd9Sstevel@tonic-gate     gss_name_t target_name;
1489*7c478bd9Sstevel@tonic-gate     gss_OID mech_type;
1490*7c478bd9Sstevel@tonic-gate     OM_uint32 req_flags;
1491*7c478bd9Sstevel@tonic-gate     OM_uint32 time_req;
1492*7c478bd9Sstevel@tonic-gate     gss_channel_bindings_t input_chan_bindings;
1493*7c478bd9Sstevel@tonic-gate     gss_buffer_t input_token;
1494*7c478bd9Sstevel@tonic-gate     gss_OID *actual_mech_type;
1495*7c478bd9Sstevel@tonic-gate     gss_buffer_t output_token;
1496*7c478bd9Sstevel@tonic-gate     OM_uint32 *ret_flags;
1497*7c478bd9Sstevel@tonic-gate     OM_uint32 *time_rec;
1498*7c478bd9Sstevel@tonic-gate {
1499*7c478bd9Sstevel@tonic-gate    krb5_context context;
1500*7c478bd9Sstevel@tonic-gate    krb5_gss_cred_id_t cred = NULL;
1501*7c478bd9Sstevel@tonic-gate    int err;
1502*7c478bd9Sstevel@tonic-gate    int default_mech = 0;
1503*7c478bd9Sstevel@tonic-gate    OM_uint32 major_status;
1504*7c478bd9Sstevel@tonic-gate    OM_uint32 tmp_min_stat;
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate    /* Solaris Kerberos:  for MT safety, we avoid the use of a default
1507*7c478bd9Sstevel@tonic-gate     * context via kg_get_context() */
1508*7c478bd9Sstevel@tonic-gate #if 0
1509*7c478bd9Sstevel@tonic-gate    if (GSS_ERROR(kg_get_context(minor_status, &context)))
1510*7c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
1511*7c478bd9Sstevel@tonic-gate #endif
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate    KRB5_LOG0(KRB5_INFO, "krb5_gss_init_sec_context() start\n");
1514*7c478bd9Sstevel@tonic-gate 
1515*7c478bd9Sstevel@tonic-gate    mutex_lock(&krb5_mutex);
1516*7c478bd9Sstevel@tonic-gate    context = ct;
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate    /* set up return values so they can be "freed" successfully */
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate    major_status = GSS_S_FAILURE; /* Default major code */
1521*7c478bd9Sstevel@tonic-gate    output_token->length = 0;
1522*7c478bd9Sstevel@tonic-gate    output_token->value = NULL;
1523*7c478bd9Sstevel@tonic-gate    if (actual_mech_type)
1524*7c478bd9Sstevel@tonic-gate       *actual_mech_type = NULL;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate    /* verify that the target_name is valid and usable */
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate    if (! kg_validate_name(target_name)) {
1529*7c478bd9Sstevel@tonic-gate       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
1530*7c478bd9Sstevel@tonic-gate       major_status = (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
1531*7c478bd9Sstevel@tonic-gate       goto unlock;
1532*7c478bd9Sstevel@tonic-gate    }
1533*7c478bd9Sstevel@tonic-gate 
1534*7c478bd9Sstevel@tonic-gate    /* verify the credential, or use the default */
1535*7c478bd9Sstevel@tonic-gate    /*SUPPRESS 29*/
1536*7c478bd9Sstevel@tonic-gate    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
1537*7c478bd9Sstevel@tonic-gate       /*
1538*7c478bd9Sstevel@tonic-gate        * Solaris Kerberos: here we are using the Solaris specific
1539*7c478bd9Sstevel@tonic-gate        * function get_default_cred() to handle the special case of a
1540*7c478bd9Sstevel@tonic-gate        * root principal
1541*7c478bd9Sstevel@tonic-gate        */
1542*7c478bd9Sstevel@tonic-gate       major_status = get_default_cred(minor_status, ct, (gss_cred_id_t *)&cred);
1543*7c478bd9Sstevel@tonic-gate       if (major_status && GSS_ERROR(major_status)) {
1544*7c478bd9Sstevel@tonic-gate 	    KRB5_LOG(KRB5_ERR, "krb5_gss_init_sec_context() end, error "
1545*7c478bd9Sstevel@tonic-gate 		   "major_status = %d\n", major_status);
1546*7c478bd9Sstevel@tonic-gate 	    goto unlock;
1547*7c478bd9Sstevel@tonic-gate       }
1548*7c478bd9Sstevel@tonic-gate    } else {
1549*7c478bd9Sstevel@tonic-gate       major_status = krb5_gss_validate_cred_no_lock(ct, minor_status,
1550*7c478bd9Sstevel@tonic-gate 					     claimant_cred_handle);
1551*7c478bd9Sstevel@tonic-gate       if (GSS_ERROR(major_status)) {
1552*7c478bd9Sstevel@tonic-gate 	  KRB5_LOG(KRB5_ERR, "krb5_gss_init_sec_context() end, error "
1553*7c478bd9Sstevel@tonic-gate 		   "major_status = %d\n", major_status);
1554*7c478bd9Sstevel@tonic-gate 	  goto unlock;
1555*7c478bd9Sstevel@tonic-gate       }
1556*7c478bd9Sstevel@tonic-gate       cred = (krb5_gss_cred_id_t) claimant_cred_handle;
1557*7c478bd9Sstevel@tonic-gate    }
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate    /* verify the mech_type */
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate    err = 0;
1562*7c478bd9Sstevel@tonic-gate    if (mech_type == GSS_C_NULL_OID) {
1563*7c478bd9Sstevel@tonic-gate        default_mech = 1;
1564*7c478bd9Sstevel@tonic-gate        if (cred->rfc_mech) {
1565*7c478bd9Sstevel@tonic-gate 	   mech_type = (gss_OID) gss_mech_krb5;
1566*7c478bd9Sstevel@tonic-gate        } else if (cred->prerfc_mech) {
1567*7c478bd9Sstevel@tonic-gate 	   mech_type = (gss_OID) gss_mech_krb5_old;
1568*7c478bd9Sstevel@tonic-gate        } else {
1569*7c478bd9Sstevel@tonic-gate 	   err = 1;
1570*7c478bd9Sstevel@tonic-gate        }
1571*7c478bd9Sstevel@tonic-gate    } else if (g_OID_equal(mech_type, gss_mech_krb5)) {
1572*7c478bd9Sstevel@tonic-gate        if (!cred->rfc_mech)
1573*7c478bd9Sstevel@tonic-gate 	   err = 1;
1574*7c478bd9Sstevel@tonic-gate    } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
1575*7c478bd9Sstevel@tonic-gate        if (!cred->prerfc_mech)
1576*7c478bd9Sstevel@tonic-gate 	   err = 1;
1577*7c478bd9Sstevel@tonic-gate    } else {
1578*7c478bd9Sstevel@tonic-gate        err = 1;
1579*7c478bd9Sstevel@tonic-gate    }
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate    if (err) {
1582*7c478bd9Sstevel@tonic-gate       *minor_status = 0;
1583*7c478bd9Sstevel@tonic-gate       major_status = GSS_S_BAD_MECH;
1584*7c478bd9Sstevel@tonic-gate       goto unlock;
1585*7c478bd9Sstevel@tonic-gate    }
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate    /* is this a new connection or not? */
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate    /*SUPPRESS 29*/
1590*7c478bd9Sstevel@tonic-gate    if (*context_handle == GSS_C_NO_CONTEXT) {
1591*7c478bd9Sstevel@tonic-gate       major_status = new_connection(minor_status, cred, context_handle,
1592*7c478bd9Sstevel@tonic-gate                                     target_name, mech_type, req_flags,
1593*7c478bd9Sstevel@tonic-gate                                     time_req, input_chan_bindings,
1594*7c478bd9Sstevel@tonic-gate                                     input_token, actual_mech_type,
1595*7c478bd9Sstevel@tonic-gate                                     output_token, ret_flags, time_rec,
1596*7c478bd9Sstevel@tonic-gate                                     context, default_mech);
1597*7c478bd9Sstevel@tonic-gate    } else {
1598*7c478bd9Sstevel@tonic-gate       major_status = mutual_auth(minor_status, cred, context_handle,
1599*7c478bd9Sstevel@tonic-gate                                  target_name, mech_type, req_flags,
1600*7c478bd9Sstevel@tonic-gate                                  time_req, input_chan_bindings,
1601*7c478bd9Sstevel@tonic-gate                                  input_token, actual_mech_type,
1602*7c478bd9Sstevel@tonic-gate                                  output_token, ret_flags, time_rec,
1603*7c478bd9Sstevel@tonic-gate                                  context);
1604*7c478bd9Sstevel@tonic-gate    }
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate unlock:
1607*7c478bd9Sstevel@tonic-gate    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL && cred != NULL)
1608*7c478bd9Sstevel@tonic-gate 	krb5_gss_release_cred_no_lock(context, &tmp_min_stat, (gss_cred_id_t *)cred);
1609*7c478bd9Sstevel@tonic-gate 
1610*7c478bd9Sstevel@tonic-gate    mutex_unlock(&krb5_mutex);
1611*7c478bd9Sstevel@tonic-gate 
1612*7c478bd9Sstevel@tonic-gate    KRB5_LOG1(KRB5_ERR, "krb5_gss_init_sec_context() end, error "
1613*7c478bd9Sstevel@tonic-gate 	   "major_status = %d, minor_status = %d\n",
1614*7c478bd9Sstevel@tonic-gate 	   major_status, *minor_status);
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate    return (major_status);
1617*7c478bd9Sstevel@tonic-gate }
1618