xref: /freebsd-src/crypto/heimdal/lib/gssapi/krb5/init_sec_context.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1c19800e8SDoug Rabson /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34*ae771770SStanislav Sedov #include "gsskrb5_locl.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson /*
37c19800e8SDoug Rabson  * copy the addresses from `input_chan_bindings' (if any) to
38c19800e8SDoug Rabson  * the auth context `ac'
39c19800e8SDoug Rabson  */
40c19800e8SDoug Rabson 
41c19800e8SDoug Rabson static OM_uint32
set_addresses(krb5_context context,krb5_auth_context ac,const gss_channel_bindings_t input_chan_bindings)42c19800e8SDoug Rabson set_addresses (krb5_context context,
43c19800e8SDoug Rabson 	       krb5_auth_context ac,
44c19800e8SDoug Rabson 	       const gss_channel_bindings_t input_chan_bindings)
45c19800e8SDoug Rabson {
46c19800e8SDoug Rabson     /* Port numbers are expected to be in application_data.value,
47c19800e8SDoug Rabson      * initator's port first */
48c19800e8SDoug Rabson 
49c19800e8SDoug Rabson     krb5_address initiator_addr, acceptor_addr;
50c19800e8SDoug Rabson     krb5_error_code kret;
51c19800e8SDoug Rabson 
52c19800e8SDoug Rabson     if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
53c19800e8SDoug Rabson 	|| input_chan_bindings->application_data.length !=
54c19800e8SDoug Rabson 	2 * sizeof(ac->local_port))
55c19800e8SDoug Rabson 	return 0;
56c19800e8SDoug Rabson 
57c19800e8SDoug Rabson     memset(&initiator_addr, 0, sizeof(initiator_addr));
58c19800e8SDoug Rabson     memset(&acceptor_addr, 0, sizeof(acceptor_addr));
59c19800e8SDoug Rabson 
60c19800e8SDoug Rabson     ac->local_port =
61c19800e8SDoug Rabson 	*(int16_t *) input_chan_bindings->application_data.value;
62c19800e8SDoug Rabson 
63c19800e8SDoug Rabson     ac->remote_port =
64c19800e8SDoug Rabson 	*((int16_t *) input_chan_bindings->application_data.value + 1);
65c19800e8SDoug Rabson 
66c19800e8SDoug Rabson     kret = _gsskrb5i_address_to_krb5addr(context,
67c19800e8SDoug Rabson 					 input_chan_bindings->acceptor_addrtype,
68c19800e8SDoug Rabson 					 &input_chan_bindings->acceptor_address,
69c19800e8SDoug Rabson 					 ac->remote_port,
70c19800e8SDoug Rabson 					 &acceptor_addr);
71c19800e8SDoug Rabson     if (kret)
72c19800e8SDoug Rabson 	return kret;
73c19800e8SDoug Rabson 
74c19800e8SDoug Rabson     kret = _gsskrb5i_address_to_krb5addr(context,
75c19800e8SDoug Rabson 					 input_chan_bindings->initiator_addrtype,
76c19800e8SDoug Rabson 					 &input_chan_bindings->initiator_address,
77c19800e8SDoug Rabson 					 ac->local_port,
78c19800e8SDoug Rabson 					 &initiator_addr);
79c19800e8SDoug Rabson     if (kret) {
80c19800e8SDoug Rabson 	krb5_free_address (context, &acceptor_addr);
81c19800e8SDoug Rabson 	return kret;
82c19800e8SDoug Rabson     }
83c19800e8SDoug Rabson 
84c19800e8SDoug Rabson     kret = krb5_auth_con_setaddrs(context,
85c19800e8SDoug Rabson 				  ac,
86c19800e8SDoug Rabson 				  &initiator_addr,  /* local address */
87c19800e8SDoug Rabson 				  &acceptor_addr);  /* remote address */
88c19800e8SDoug Rabson 
89c19800e8SDoug Rabson     krb5_free_address (context, &initiator_addr);
90c19800e8SDoug Rabson     krb5_free_address (context, &acceptor_addr);
91c19800e8SDoug Rabson 
92c19800e8SDoug Rabson #if 0
93c19800e8SDoug Rabson     free(input_chan_bindings->application_data.value);
94c19800e8SDoug Rabson     input_chan_bindings->application_data.value = NULL;
95c19800e8SDoug Rabson     input_chan_bindings->application_data.length = 0;
96c19800e8SDoug Rabson #endif
97c19800e8SDoug Rabson 
98c19800e8SDoug Rabson     return kret;
99c19800e8SDoug Rabson }
100c19800e8SDoug Rabson 
101c19800e8SDoug Rabson OM_uint32
_gsskrb5_create_ctx(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,krb5_context context,const gss_channel_bindings_t input_chan_bindings,enum gss_ctx_id_t_state state)102c19800e8SDoug Rabson _gsskrb5_create_ctx(
103c19800e8SDoug Rabson         OM_uint32 * minor_status,
104c19800e8SDoug Rabson 	gss_ctx_id_t * context_handle,
105c19800e8SDoug Rabson 	krb5_context context,
106c19800e8SDoug Rabson  	const gss_channel_bindings_t input_chan_bindings,
107c19800e8SDoug Rabson  	enum gss_ctx_id_t_state state)
108c19800e8SDoug Rabson {
109c19800e8SDoug Rabson     krb5_error_code kret;
110c19800e8SDoug Rabson     gsskrb5_ctx ctx;
111c19800e8SDoug Rabson 
112c19800e8SDoug Rabson     *context_handle = NULL;
113c19800e8SDoug Rabson 
114c19800e8SDoug Rabson     ctx = malloc(sizeof(*ctx));
115c19800e8SDoug Rabson     if (ctx == NULL) {
116c19800e8SDoug Rabson 	*minor_status = ENOMEM;
117c19800e8SDoug Rabson 	return GSS_S_FAILURE;
118c19800e8SDoug Rabson     }
119c19800e8SDoug Rabson     ctx->auth_context		= NULL;
120*ae771770SStanislav Sedov     ctx->deleg_auth_context	= NULL;
121c19800e8SDoug Rabson     ctx->source			= NULL;
122c19800e8SDoug Rabson     ctx->target			= NULL;
123*ae771770SStanislav Sedov     ctx->kcred			= NULL;
124*ae771770SStanislav Sedov     ctx->ccache			= NULL;
125c19800e8SDoug Rabson     ctx->state			= state;
126c19800e8SDoug Rabson     ctx->flags			= 0;
127c19800e8SDoug Rabson     ctx->more_flags		= 0;
128c19800e8SDoug Rabson     ctx->service_keyblock	= NULL;
129c19800e8SDoug Rabson     ctx->ticket			= NULL;
130c19800e8SDoug Rabson     krb5_data_zero(&ctx->fwd_data);
131c19800e8SDoug Rabson     ctx->lifetime		= GSS_C_INDEFINITE;
132c19800e8SDoug Rabson     ctx->order			= NULL;
133*ae771770SStanislav Sedov     ctx->crypto			= NULL;
134c19800e8SDoug Rabson     HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
135c19800e8SDoug Rabson 
136c19800e8SDoug Rabson     kret = krb5_auth_con_init (context, &ctx->auth_context);
137c19800e8SDoug Rabson     if (kret) {
138c19800e8SDoug Rabson 	*minor_status = kret;
139c19800e8SDoug Rabson 	HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
140*ae771770SStanislav Sedov 	return GSS_S_FAILURE;
141*ae771770SStanislav Sedov     }
142c19800e8SDoug Rabson 
143*ae771770SStanislav Sedov     kret = krb5_auth_con_init (context, &ctx->deleg_auth_context);
144*ae771770SStanislav Sedov     if (kret) {
145*ae771770SStanislav Sedov 	*minor_status = kret;
146*ae771770SStanislav Sedov 	krb5_auth_con_free(context, ctx->auth_context);
147*ae771770SStanislav Sedov 	HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
148c19800e8SDoug Rabson 	return GSS_S_FAILURE;
149c19800e8SDoug Rabson     }
150c19800e8SDoug Rabson 
151c19800e8SDoug Rabson     kret = set_addresses(context, ctx->auth_context, input_chan_bindings);
152c19800e8SDoug Rabson     if (kret) {
153c19800e8SDoug Rabson 	*minor_status = kret;
154c19800e8SDoug Rabson 
155*ae771770SStanislav Sedov 	krb5_auth_con_free(context, ctx->auth_context);
156*ae771770SStanislav Sedov 	krb5_auth_con_free(context, ctx->deleg_auth_context);
157*ae771770SStanislav Sedov 
158c19800e8SDoug Rabson 	HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
159c19800e8SDoug Rabson 
160*ae771770SStanislav Sedov 	return GSS_S_BAD_BINDINGS;
161*ae771770SStanislav Sedov     }
162*ae771770SStanislav Sedov 
163*ae771770SStanislav Sedov     kret = set_addresses(context, ctx->deleg_auth_context, input_chan_bindings);
164*ae771770SStanislav Sedov     if (kret) {
165*ae771770SStanislav Sedov 	*minor_status = kret;
166*ae771770SStanislav Sedov 
167c19800e8SDoug Rabson 	krb5_auth_con_free(context, ctx->auth_context);
168*ae771770SStanislav Sedov 	krb5_auth_con_free(context, ctx->deleg_auth_context);
169*ae771770SStanislav Sedov 
170*ae771770SStanislav Sedov 	HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
171c19800e8SDoug Rabson 
172c19800e8SDoug Rabson 	return GSS_S_BAD_BINDINGS;
173c19800e8SDoug Rabson     }
174c19800e8SDoug Rabson 
175c19800e8SDoug Rabson     /*
176c19800e8SDoug Rabson      * We need a sequence number
177c19800e8SDoug Rabson      */
178c19800e8SDoug Rabson 
179c19800e8SDoug Rabson     krb5_auth_con_addflags(context,
180c19800e8SDoug Rabson 			   ctx->auth_context,
181c19800e8SDoug Rabson 			   KRB5_AUTH_CONTEXT_DO_SEQUENCE |
182c19800e8SDoug Rabson 			   KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
183c19800e8SDoug Rabson 			   NULL);
184c19800e8SDoug Rabson 
185*ae771770SStanislav Sedov     /*
186*ae771770SStanislav Sedov      * We need a sequence number
187*ae771770SStanislav Sedov      */
188*ae771770SStanislav Sedov 
189*ae771770SStanislav Sedov     krb5_auth_con_addflags(context,
190*ae771770SStanislav Sedov 			   ctx->deleg_auth_context,
191*ae771770SStanislav Sedov 			   KRB5_AUTH_CONTEXT_DO_SEQUENCE |
192*ae771770SStanislav Sedov 			   KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
193*ae771770SStanislav Sedov 			   NULL);
194*ae771770SStanislav Sedov 
195c19800e8SDoug Rabson     *context_handle = (gss_ctx_id_t)ctx;
196c19800e8SDoug Rabson 
197c19800e8SDoug Rabson     return GSS_S_COMPLETE;
198c19800e8SDoug Rabson }
199c19800e8SDoug Rabson 
200c19800e8SDoug Rabson 
201c19800e8SDoug Rabson static OM_uint32
gsskrb5_get_creds(OM_uint32 * minor_status,krb5_context context,krb5_ccache ccache,gsskrb5_ctx ctx,const gss_name_t target_name,int use_dns,OM_uint32 time_req,OM_uint32 * time_rec)202c19800e8SDoug Rabson gsskrb5_get_creds(
203c19800e8SDoug Rabson         OM_uint32 * minor_status,
204c19800e8SDoug Rabson 	krb5_context context,
205c19800e8SDoug Rabson 	krb5_ccache ccache,
206c19800e8SDoug Rabson 	gsskrb5_ctx ctx,
207*ae771770SStanislav Sedov 	const gss_name_t target_name,
208*ae771770SStanislav Sedov 	int use_dns,
209c19800e8SDoug Rabson 	OM_uint32 time_req,
210*ae771770SStanislav Sedov 	OM_uint32 * time_rec)
211c19800e8SDoug Rabson {
212c19800e8SDoug Rabson     OM_uint32 ret;
213c19800e8SDoug Rabson     krb5_error_code kret;
214c19800e8SDoug Rabson     krb5_creds this_cred;
215c19800e8SDoug Rabson     OM_uint32 lifetime_rec;
216c19800e8SDoug Rabson 
217*ae771770SStanislav Sedov     if (ctx->target) {
218*ae771770SStanislav Sedov 	krb5_free_principal(context, ctx->target);
219*ae771770SStanislav Sedov 	ctx->target = NULL;
220*ae771770SStanislav Sedov     }
221*ae771770SStanislav Sedov     if (ctx->kcred) {
222*ae771770SStanislav Sedov 	krb5_free_creds(context, ctx->kcred);
223*ae771770SStanislav Sedov 	ctx->kcred = NULL;
224*ae771770SStanislav Sedov     }
225*ae771770SStanislav Sedov 
226*ae771770SStanislav Sedov     ret = _gsskrb5_canon_name(minor_status, context, use_dns,
227*ae771770SStanislav Sedov 			      ctx->source, target_name, &ctx->target);
228*ae771770SStanislav Sedov     if (ret)
229*ae771770SStanislav Sedov 	return ret;
230c19800e8SDoug Rabson 
231c19800e8SDoug Rabson     memset(&this_cred, 0, sizeof(this_cred));
232c19800e8SDoug Rabson     this_cred.client = ctx->source;
233c19800e8SDoug Rabson     this_cred.server = ctx->target;
234c19800e8SDoug Rabson 
235c19800e8SDoug Rabson     if (time_req && time_req != GSS_C_INDEFINITE) {
236c19800e8SDoug Rabson 	krb5_timestamp ts;
237c19800e8SDoug Rabson 
238c19800e8SDoug Rabson 	krb5_timeofday (context, &ts);
239c19800e8SDoug Rabson 	this_cred.times.endtime = ts + time_req;
240c19800e8SDoug Rabson     } else {
241c19800e8SDoug Rabson 	this_cred.times.endtime   = 0;
242c19800e8SDoug Rabson     }
243c19800e8SDoug Rabson 
244c19800e8SDoug Rabson     this_cred.session.keytype = KEYTYPE_NULL;
245c19800e8SDoug Rabson 
246c19800e8SDoug Rabson     kret = krb5_get_credentials(context,
247c19800e8SDoug Rabson 				0,
248c19800e8SDoug Rabson 				ccache,
249c19800e8SDoug Rabson 				&this_cred,
250*ae771770SStanislav Sedov 				&ctx->kcred);
251c19800e8SDoug Rabson     if (kret) {
252c19800e8SDoug Rabson 	*minor_status = kret;
253c19800e8SDoug Rabson 	return GSS_S_FAILURE;
254c19800e8SDoug Rabson     }
255c19800e8SDoug Rabson 
256*ae771770SStanislav Sedov     ctx->lifetime = ctx->kcred->times.endtime;
257c19800e8SDoug Rabson 
258c19800e8SDoug Rabson     ret = _gsskrb5_lifetime_left(minor_status, context,
259c19800e8SDoug Rabson 				 ctx->lifetime, &lifetime_rec);
260c19800e8SDoug Rabson     if (ret) return ret;
261c19800e8SDoug Rabson 
262c19800e8SDoug Rabson     if (lifetime_rec == 0) {
263c19800e8SDoug Rabson 	*minor_status = 0;
264c19800e8SDoug Rabson 	return GSS_S_CONTEXT_EXPIRED;
265c19800e8SDoug Rabson     }
266c19800e8SDoug Rabson 
267c19800e8SDoug Rabson     if (time_rec) *time_rec = lifetime_rec;
268c19800e8SDoug Rabson 
269c19800e8SDoug Rabson     return GSS_S_COMPLETE;
270c19800e8SDoug Rabson }
271c19800e8SDoug Rabson 
272c19800e8SDoug Rabson static OM_uint32
gsskrb5_initiator_ready(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context)273c19800e8SDoug Rabson gsskrb5_initiator_ready(
274c19800e8SDoug Rabson 	OM_uint32 * minor_status,
275c19800e8SDoug Rabson 	gsskrb5_ctx ctx,
276c19800e8SDoug Rabson 	krb5_context context)
277c19800e8SDoug Rabson {
278c19800e8SDoug Rabson     OM_uint32 ret;
279c19800e8SDoug Rabson     int32_t seq_number;
280c19800e8SDoug Rabson     int is_cfx = 0;
281c19800e8SDoug Rabson     OM_uint32 flags = ctx->flags;
282c19800e8SDoug Rabson 
283*ae771770SStanislav Sedov     krb5_free_creds(context, ctx->kcred);
284*ae771770SStanislav Sedov     ctx->kcred = NULL;
285c19800e8SDoug Rabson 
286*ae771770SStanislav Sedov     if (ctx->more_flags & CLOSE_CCACHE)
287*ae771770SStanislav Sedov 	krb5_cc_close(context, ctx->ccache);
288*ae771770SStanislav Sedov     ctx->ccache = NULL;
289*ae771770SStanislav Sedov 
290*ae771770SStanislav Sedov     krb5_auth_con_getremoteseqnumber (context, ctx->auth_context, &seq_number);
291*ae771770SStanislav Sedov 
292*ae771770SStanislav Sedov     _gsskrb5i_is_cfx(context, ctx, 0);
293*ae771770SStanislav Sedov     is_cfx = (ctx->more_flags & IS_CFX);
294c19800e8SDoug Rabson 
295c19800e8SDoug Rabson     ret = _gssapi_msg_order_create(minor_status,
296c19800e8SDoug Rabson 				   &ctx->order,
297c19800e8SDoug Rabson 				   _gssapi_msg_order_f(flags),
298c19800e8SDoug Rabson 				   seq_number, 0, is_cfx);
299c19800e8SDoug Rabson     if (ret) return ret;
300c19800e8SDoug Rabson 
301c19800e8SDoug Rabson     ctx->state	= INITIATOR_READY;
302c19800e8SDoug Rabson     ctx->more_flags	|= OPEN;
303c19800e8SDoug Rabson 
304c19800e8SDoug Rabson     return GSS_S_COMPLETE;
305c19800e8SDoug Rabson }
306c19800e8SDoug Rabson 
307c19800e8SDoug Rabson /*
308c19800e8SDoug Rabson  * handle delegated creds in init-sec-context
309c19800e8SDoug Rabson  */
310c19800e8SDoug Rabson 
311c19800e8SDoug Rabson static void
do_delegation(krb5_context context,krb5_auth_context ac,krb5_ccache ccache,krb5_creds * cred,krb5_const_principal name,krb5_data * fwd_data,uint32_t flagmask,uint32_t * flags)312c19800e8SDoug Rabson do_delegation (krb5_context context,
313c19800e8SDoug Rabson 	       krb5_auth_context ac,
314c19800e8SDoug Rabson 	       krb5_ccache ccache,
315c19800e8SDoug Rabson 	       krb5_creds *cred,
316c19800e8SDoug Rabson 	       krb5_const_principal name,
317c19800e8SDoug Rabson 	       krb5_data *fwd_data,
318*ae771770SStanislav Sedov 	       uint32_t flagmask,
319c19800e8SDoug Rabson 	       uint32_t *flags)
320c19800e8SDoug Rabson {
321c19800e8SDoug Rabson     krb5_creds creds;
322c19800e8SDoug Rabson     KDCOptions fwd_flags;
323c19800e8SDoug Rabson     krb5_error_code kret;
324c19800e8SDoug Rabson 
325c19800e8SDoug Rabson     memset (&creds, 0, sizeof(creds));
326c19800e8SDoug Rabson     krb5_data_zero (fwd_data);
327c19800e8SDoug Rabson 
328c19800e8SDoug Rabson     kret = krb5_cc_get_principal(context, ccache, &creds.client);
329c19800e8SDoug Rabson     if (kret)
330c19800e8SDoug Rabson 	goto out;
331c19800e8SDoug Rabson 
332*ae771770SStanislav Sedov     kret = krb5_make_principal(context,
333c19800e8SDoug Rabson 			       &creds.server,
334c19800e8SDoug Rabson 			       creds.client->realm,
335c19800e8SDoug Rabson 			       KRB5_TGS_NAME,
336c19800e8SDoug Rabson 			       creds.client->realm,
337c19800e8SDoug Rabson 			       NULL);
338c19800e8SDoug Rabson     if (kret)
339c19800e8SDoug Rabson 	goto out;
340c19800e8SDoug Rabson 
341c19800e8SDoug Rabson     creds.times.endtime = 0;
342c19800e8SDoug Rabson 
343c19800e8SDoug Rabson     memset(&fwd_flags, 0, sizeof(fwd_flags));
344c19800e8SDoug Rabson     fwd_flags.forwarded = 1;
345c19800e8SDoug Rabson     fwd_flags.forwardable = 1;
346c19800e8SDoug Rabson 
347c19800e8SDoug Rabson     if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
348c19800e8SDoug Rabson 	name->name.name_string.len < 2)
349c19800e8SDoug Rabson 	goto out;
350c19800e8SDoug Rabson 
351c19800e8SDoug Rabson     kret = krb5_get_forwarded_creds(context,
352c19800e8SDoug Rabson 				    ac,
353c19800e8SDoug Rabson 				    ccache,
354c19800e8SDoug Rabson 				    KDCOptions2int(fwd_flags),
355c19800e8SDoug Rabson 				    name->name.name_string.val[1],
356c19800e8SDoug Rabson 				    &creds,
357c19800e8SDoug Rabson 				    fwd_data);
358c19800e8SDoug Rabson 
359c19800e8SDoug Rabson  out:
360c19800e8SDoug Rabson     if (kret)
361*ae771770SStanislav Sedov 	*flags &= ~flagmask;
362c19800e8SDoug Rabson     else
363*ae771770SStanislav Sedov 	*flags |= flagmask;
364c19800e8SDoug Rabson 
365c19800e8SDoug Rabson     if (creds.client)
366c19800e8SDoug Rabson 	krb5_free_principal(context, creds.client);
367c19800e8SDoug Rabson     if (creds.server)
368c19800e8SDoug Rabson 	krb5_free_principal(context, creds.server);
369c19800e8SDoug Rabson }
370c19800e8SDoug Rabson 
371c19800e8SDoug Rabson /*
372c19800e8SDoug Rabson  * first stage of init-sec-context
373c19800e8SDoug Rabson  */
374c19800e8SDoug Rabson 
375c19800e8SDoug Rabson static OM_uint32
init_auth(OM_uint32 * minor_status,gsskrb5_cred cred,gsskrb5_ctx ctx,krb5_context context,gss_name_t name,const gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)376c19800e8SDoug Rabson init_auth
377c19800e8SDoug Rabson (OM_uint32 * minor_status,
378*ae771770SStanislav Sedov  gsskrb5_cred cred,
379c19800e8SDoug Rabson  gsskrb5_ctx ctx,
380c19800e8SDoug Rabson  krb5_context context,
381*ae771770SStanislav Sedov  gss_name_t name,
382c19800e8SDoug Rabson  const gss_OID mech_type,
383c19800e8SDoug Rabson  OM_uint32 req_flags,
384c19800e8SDoug Rabson  OM_uint32 time_req,
385*ae771770SStanislav Sedov  const gss_buffer_t input_token,
386*ae771770SStanislav Sedov  gss_OID * actual_mech_type,
387*ae771770SStanislav Sedov  gss_buffer_t output_token,
388*ae771770SStanislav Sedov  OM_uint32 * ret_flags,
389*ae771770SStanislav Sedov  OM_uint32 * time_rec
390*ae771770SStanislav Sedov     )
391*ae771770SStanislav Sedov {
392*ae771770SStanislav Sedov     OM_uint32 ret = GSS_S_FAILURE;
393*ae771770SStanislav Sedov     krb5_error_code kret;
394*ae771770SStanislav Sedov     krb5_data outbuf;
395*ae771770SStanislav Sedov     krb5_data fwd_data;
396*ae771770SStanislav Sedov     OM_uint32 lifetime_rec;
397*ae771770SStanislav Sedov     int allow_dns = 1;
398*ae771770SStanislav Sedov 
399*ae771770SStanislav Sedov     krb5_data_zero(&outbuf);
400*ae771770SStanislav Sedov     krb5_data_zero(&fwd_data);
401*ae771770SStanislav Sedov 
402*ae771770SStanislav Sedov     *minor_status = 0;
403*ae771770SStanislav Sedov 
404*ae771770SStanislav Sedov     if (actual_mech_type)
405*ae771770SStanislav Sedov 	*actual_mech_type = GSS_KRB5_MECHANISM;
406*ae771770SStanislav Sedov 
407*ae771770SStanislav Sedov     if (cred == NULL) {
408*ae771770SStanislav Sedov 	kret = krb5_cc_default (context, &ctx->ccache);
409*ae771770SStanislav Sedov 	if (kret) {
410*ae771770SStanislav Sedov 	    *minor_status = kret;
411*ae771770SStanislav Sedov 	    ret = GSS_S_FAILURE;
412*ae771770SStanislav Sedov 	    goto failure;
413*ae771770SStanislav Sedov 	}
414*ae771770SStanislav Sedov 	ctx->more_flags |= CLOSE_CCACHE;
415*ae771770SStanislav Sedov     } else
416*ae771770SStanislav Sedov 	ctx->ccache = cred->ccache;
417*ae771770SStanislav Sedov 
418*ae771770SStanislav Sedov     kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source);
419*ae771770SStanislav Sedov     if (kret) {
420*ae771770SStanislav Sedov 	*minor_status = kret;
421*ae771770SStanislav Sedov 	ret = GSS_S_FAILURE;
422*ae771770SStanislav Sedov 	goto failure;
423*ae771770SStanislav Sedov     }
424*ae771770SStanislav Sedov 
425*ae771770SStanislav Sedov     /*
426*ae771770SStanislav Sedov      * This is hideous glue for (NFS) clients that wants to limit the
427*ae771770SStanislav Sedov      * available enctypes to what it can support (encryption in
428*ae771770SStanislav Sedov      * kernel). If there is no enctypes selected for this credential,
429*ae771770SStanislav Sedov      * reset it to the default set of enctypes.
430*ae771770SStanislav Sedov      */
431*ae771770SStanislav Sedov     {
432*ae771770SStanislav Sedov 	krb5_enctype *enctypes = NULL;
433*ae771770SStanislav Sedov 
434*ae771770SStanislav Sedov 	if (cred && cred->enctypes)
435*ae771770SStanislav Sedov 	    enctypes = cred->enctypes;
436*ae771770SStanislav Sedov 	krb5_set_default_in_tkt_etypes(context, enctypes);
437*ae771770SStanislav Sedov     }
438*ae771770SStanislav Sedov 
439*ae771770SStanislav Sedov     /* canon name if needed for client + target realm */
440*ae771770SStanislav Sedov     kret = krb5_cc_get_config(context, ctx->ccache, NULL,
441*ae771770SStanislav Sedov 			      "realm-config", &outbuf);
442*ae771770SStanislav Sedov     if (kret == 0) {
443*ae771770SStanislav Sedov 	/* XXX 2 is no server canon */
444*ae771770SStanislav Sedov 	if (outbuf.length < 1 || ((((unsigned char *)outbuf.data)[0]) & 2))
445*ae771770SStanislav Sedov 	    allow_dns = 0;
446*ae771770SStanislav Sedov 	krb5_data_free(&outbuf);
447*ae771770SStanislav Sedov     }
448*ae771770SStanislav Sedov 
449*ae771770SStanislav Sedov     /*
450*ae771770SStanislav Sedov      * First we try w/o dns, hope that the KDC have register alias
451*ae771770SStanislav Sedov      * (and referrals if cross realm) for this principal. If that
452*ae771770SStanislav Sedov      * fails and if we are allowed to using this realm try again with
453*ae771770SStanislav Sedov      * DNS canonicalizion.
454*ae771770SStanislav Sedov      */
455*ae771770SStanislav Sedov     ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,
456*ae771770SStanislav Sedov 			    ctx, name, 0, time_req,
457*ae771770SStanislav Sedov 			    time_rec);
458*ae771770SStanislav Sedov     if (ret && allow_dns)
459*ae771770SStanislav Sedov 	ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,
460*ae771770SStanislav Sedov 				ctx, name, 1, time_req,
461*ae771770SStanislav Sedov 				time_rec);
462*ae771770SStanislav Sedov     if (ret)
463*ae771770SStanislav Sedov 	goto failure;
464*ae771770SStanislav Sedov 
465*ae771770SStanislav Sedov     ctx->lifetime = ctx->kcred->times.endtime;
466*ae771770SStanislav Sedov 
467*ae771770SStanislav Sedov     ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
468*ae771770SStanislav Sedov     if (ret)
469*ae771770SStanislav Sedov 	goto failure;
470*ae771770SStanislav Sedov 
471*ae771770SStanislav Sedov     ret = _gsskrb5_lifetime_left(minor_status,
472*ae771770SStanislav Sedov 				 context,
473*ae771770SStanislav Sedov 				 ctx->lifetime,
474*ae771770SStanislav Sedov 				 &lifetime_rec);
475*ae771770SStanislav Sedov     if (ret)
476*ae771770SStanislav Sedov 	goto failure;
477*ae771770SStanislav Sedov 
478*ae771770SStanislav Sedov     if (lifetime_rec == 0) {
479*ae771770SStanislav Sedov 	*minor_status = 0;
480*ae771770SStanislav Sedov 	ret = GSS_S_CONTEXT_EXPIRED;
481*ae771770SStanislav Sedov 	goto failure;
482*ae771770SStanislav Sedov     }
483*ae771770SStanislav Sedov 
484*ae771770SStanislav Sedov     krb5_auth_con_setkey(context,
485*ae771770SStanislav Sedov 			 ctx->auth_context,
486*ae771770SStanislav Sedov 			 &ctx->kcred->session);
487*ae771770SStanislav Sedov 
488*ae771770SStanislav Sedov     kret = krb5_auth_con_generatelocalsubkey(context,
489*ae771770SStanislav Sedov 					     ctx->auth_context,
490*ae771770SStanislav Sedov 					     &ctx->kcred->session);
491*ae771770SStanislav Sedov     if(kret) {
492*ae771770SStanislav Sedov 	*minor_status = kret;
493*ae771770SStanislav Sedov 	ret = GSS_S_FAILURE;
494*ae771770SStanislav Sedov 	goto failure;
495*ae771770SStanislav Sedov     }
496*ae771770SStanislav Sedov 
497*ae771770SStanislav Sedov     return GSS_S_COMPLETE;
498*ae771770SStanislav Sedov 
499*ae771770SStanislav Sedov failure:
500*ae771770SStanislav Sedov     if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
501*ae771770SStanislav Sedov 	krb5_cc_close(context, ctx->ccache);
502*ae771770SStanislav Sedov     ctx->ccache = NULL;
503*ae771770SStanislav Sedov 
504*ae771770SStanislav Sedov     return ret;
505*ae771770SStanislav Sedov 
506*ae771770SStanislav Sedov }
507*ae771770SStanislav Sedov 
508*ae771770SStanislav Sedov static OM_uint32
init_auth_restart(OM_uint32 * minor_status,gsskrb5_cred cred,gsskrb5_ctx ctx,krb5_context context,OM_uint32 req_flags,const gss_channel_bindings_t input_chan_bindings,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)509*ae771770SStanislav Sedov init_auth_restart
510*ae771770SStanislav Sedov (OM_uint32 * minor_status,
511*ae771770SStanislav Sedov  gsskrb5_cred cred,
512*ae771770SStanislav Sedov  gsskrb5_ctx ctx,
513*ae771770SStanislav Sedov  krb5_context context,
514*ae771770SStanislav Sedov  OM_uint32 req_flags,
515c19800e8SDoug Rabson  const gss_channel_bindings_t input_chan_bindings,
516c19800e8SDoug Rabson  const gss_buffer_t input_token,
517c19800e8SDoug Rabson  gss_OID * actual_mech_type,
518c19800e8SDoug Rabson  gss_buffer_t output_token,
519c19800e8SDoug Rabson  OM_uint32 * ret_flags,
520c19800e8SDoug Rabson  OM_uint32 * time_rec
521c19800e8SDoug Rabson     )
522c19800e8SDoug Rabson {
523c19800e8SDoug Rabson     OM_uint32 ret = GSS_S_FAILURE;
524c19800e8SDoug Rabson     krb5_error_code kret;
525c19800e8SDoug Rabson     krb5_flags ap_options;
526c19800e8SDoug Rabson     krb5_data outbuf;
527c19800e8SDoug Rabson     uint32_t flags;
528c19800e8SDoug Rabson     krb5_data authenticator;
529c19800e8SDoug Rabson     Checksum cksum;
530c19800e8SDoug Rabson     krb5_enctype enctype;
531*ae771770SStanislav Sedov     krb5_data fwd_data, timedata;
532*ae771770SStanislav Sedov     int32_t offset = 0, oldoffset = 0;
533*ae771770SStanislav Sedov     uint32_t flagmask;
534c19800e8SDoug Rabson 
535c19800e8SDoug Rabson     krb5_data_zero(&outbuf);
536c19800e8SDoug Rabson     krb5_data_zero(&fwd_data);
537c19800e8SDoug Rabson 
538c19800e8SDoug Rabson     *minor_status = 0;
539c19800e8SDoug Rabson 
540c19800e8SDoug Rabson     /*
541*ae771770SStanislav Sedov      * If the credential doesn't have ok-as-delegate, check if there
542*ae771770SStanislav Sedov      * is a realm setting and use that.
543c19800e8SDoug Rabson      */
544*ae771770SStanislav Sedov     if (!ctx->kcred->flags.b.ok_as_delegate) {
545*ae771770SStanislav Sedov 	krb5_data data;
546c19800e8SDoug Rabson 
547*ae771770SStanislav Sedov 	ret = krb5_cc_get_config(context, ctx->ccache, NULL,
548*ae771770SStanislav Sedov 				 "realm-config", &data);
549*ae771770SStanislav Sedov 	if (ret == 0) {
550*ae771770SStanislav Sedov 	    /* XXX 1 is use ok-as-delegate */
551*ae771770SStanislav Sedov 	    if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0)
552*ae771770SStanislav Sedov 		req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
553*ae771770SStanislav Sedov 	    krb5_data_free(&data);
554*ae771770SStanislav Sedov 	}
555c19800e8SDoug Rabson     }
556c19800e8SDoug Rabson 
557*ae771770SStanislav Sedov     flagmask = 0;
558c19800e8SDoug Rabson 
559*ae771770SStanislav Sedov     /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */
560*ae771770SStanislav Sedov     if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
561*ae771770SStanislav Sedov 	&& ctx->kcred->flags.b.ok_as_delegate)
562*ae771770SStanislav Sedov 	flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
563*ae771770SStanislav Sedov     /* if there still is a GSS_C_DELEG_FLAG, use that */
564*ae771770SStanislav Sedov     if (req_flags & GSS_C_DELEG_FLAG)
565*ae771770SStanislav Sedov 	flagmask |= GSS_C_DELEG_FLAG;
566c19800e8SDoug Rabson 
567c19800e8SDoug Rabson 
568c19800e8SDoug Rabson     flags = 0;
569c19800e8SDoug Rabson     ap_options = 0;
570*ae771770SStanislav Sedov     if (flagmask & GSS_C_DELEG_FLAG) {
571c19800e8SDoug Rabson 	do_delegation (context,
572*ae771770SStanislav Sedov 		       ctx->deleg_auth_context,
573*ae771770SStanislav Sedov 		       ctx->ccache, ctx->kcred, ctx->target,
574*ae771770SStanislav Sedov 		       &fwd_data, flagmask, &flags);
575*ae771770SStanislav Sedov     }
576c19800e8SDoug Rabson 
577c19800e8SDoug Rabson     if (req_flags & GSS_C_MUTUAL_FLAG) {
578c19800e8SDoug Rabson 	flags |= GSS_C_MUTUAL_FLAG;
579c19800e8SDoug Rabson 	ap_options |= AP_OPTS_MUTUAL_REQUIRED;
580c19800e8SDoug Rabson     }
581c19800e8SDoug Rabson 
582c19800e8SDoug Rabson     if (req_flags & GSS_C_REPLAY_FLAG)
583c19800e8SDoug Rabson 	flags |= GSS_C_REPLAY_FLAG;
584c19800e8SDoug Rabson     if (req_flags & GSS_C_SEQUENCE_FLAG)
585c19800e8SDoug Rabson 	flags |= GSS_C_SEQUENCE_FLAG;
586*ae771770SStanislav Sedov #if 0
587c19800e8SDoug Rabson     if (req_flags & GSS_C_ANON_FLAG)
588c19800e8SDoug Rabson 	;                               /* XXX */
589*ae771770SStanislav Sedov #endif
590c19800e8SDoug Rabson     if (req_flags & GSS_C_DCE_STYLE) {
591c19800e8SDoug Rabson 	/* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
592c19800e8SDoug Rabson 	flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;
593c19800e8SDoug Rabson 	ap_options |= AP_OPTS_MUTUAL_REQUIRED;
594c19800e8SDoug Rabson     }
595c19800e8SDoug Rabson     if (req_flags & GSS_C_IDENTIFY_FLAG)
596c19800e8SDoug Rabson 	flags |= GSS_C_IDENTIFY_FLAG;
597c19800e8SDoug Rabson     if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)
598c19800e8SDoug Rabson 	flags |= GSS_C_EXTENDED_ERROR_FLAG;
599c19800e8SDoug Rabson 
600*ae771770SStanislav Sedov     if (req_flags & GSS_C_CONF_FLAG) {
601*ae771770SStanislav Sedov 	flags |= GSS_C_CONF_FLAG;
602*ae771770SStanislav Sedov     }
603*ae771770SStanislav Sedov     if (req_flags & GSS_C_INTEG_FLAG) {
604*ae771770SStanislav Sedov 	flags |= GSS_C_INTEG_FLAG;
605*ae771770SStanislav Sedov     }
606*ae771770SStanislav Sedov     if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) {
607c19800e8SDoug Rabson 	flags |= GSS_C_CONF_FLAG;
608c19800e8SDoug Rabson 	flags |= GSS_C_INTEG_FLAG;
609*ae771770SStanislav Sedov     }
610c19800e8SDoug Rabson     flags |= GSS_C_TRANS_FLAG;
611c19800e8SDoug Rabson 
612c19800e8SDoug Rabson     if (ret_flags)
613c19800e8SDoug Rabson 	*ret_flags = flags;
614c19800e8SDoug Rabson     ctx->flags = flags;
615c19800e8SDoug Rabson     ctx->more_flags |= LOCAL;
616c19800e8SDoug Rabson 
617c19800e8SDoug Rabson     ret = _gsskrb5_create_8003_checksum (minor_status,
618c19800e8SDoug Rabson 					 input_chan_bindings,
619c19800e8SDoug Rabson 					 flags,
620c19800e8SDoug Rabson 					 &fwd_data,
621c19800e8SDoug Rabson 					 &cksum);
622c19800e8SDoug Rabson     krb5_data_free (&fwd_data);
623c19800e8SDoug Rabson     if (ret)
624c19800e8SDoug Rabson 	goto failure;
625c19800e8SDoug Rabson 
626c19800e8SDoug Rabson     enctype = ctx->auth_context->keyblock->keytype;
627c19800e8SDoug Rabson 
628*ae771770SStanislav Sedov     ret = krb5_cc_get_config(context, ctx->ccache, ctx->target,
629*ae771770SStanislav Sedov 			     "time-offset", &timedata);
630*ae771770SStanislav Sedov     if (ret == 0) {
631*ae771770SStanislav Sedov 	if (timedata.length == 4) {
632*ae771770SStanislav Sedov 	    const u_char *p = timedata.data;
633*ae771770SStanislav Sedov 	    offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
634*ae771770SStanislav Sedov 	}
635*ae771770SStanislav Sedov 	krb5_data_free(&timedata);
636*ae771770SStanislav Sedov     }
637*ae771770SStanislav Sedov 
638*ae771770SStanislav Sedov     if (offset) {
639*ae771770SStanislav Sedov 	krb5_get_kdc_sec_offset (context, &oldoffset, NULL);
640*ae771770SStanislav Sedov 	krb5_set_kdc_sec_offset (context, offset, -1);
641*ae771770SStanislav Sedov     }
642*ae771770SStanislav Sedov 
643*ae771770SStanislav Sedov     kret = _krb5_build_authenticator(context,
644c19800e8SDoug Rabson 				     ctx->auth_context,
645c19800e8SDoug Rabson 				     enctype,
646*ae771770SStanislav Sedov 				     ctx->kcred,
647c19800e8SDoug Rabson 				     &cksum,
648c19800e8SDoug Rabson 				     &authenticator,
649c19800e8SDoug Rabson 				     KRB5_KU_AP_REQ_AUTH);
650c19800e8SDoug Rabson 
651c19800e8SDoug Rabson     if (kret) {
652*ae771770SStanislav Sedov 	if (offset)
653*ae771770SStanislav Sedov 	    krb5_set_kdc_sec_offset (context, oldoffset, -1);
654c19800e8SDoug Rabson 	*minor_status = kret;
655c19800e8SDoug Rabson 	ret = GSS_S_FAILURE;
656c19800e8SDoug Rabson 	goto failure;
657c19800e8SDoug Rabson     }
658c19800e8SDoug Rabson 
659c19800e8SDoug Rabson     kret = krb5_build_ap_req (context,
660c19800e8SDoug Rabson 			      enctype,
661*ae771770SStanislav Sedov 			      ctx->kcred,
662c19800e8SDoug Rabson 			      ap_options,
663c19800e8SDoug Rabson 			      authenticator,
664c19800e8SDoug Rabson 			      &outbuf);
665*ae771770SStanislav Sedov     if (offset)
666*ae771770SStanislav Sedov 	krb5_set_kdc_sec_offset (context, oldoffset, -1);
667c19800e8SDoug Rabson     if (kret) {
668c19800e8SDoug Rabson 	*minor_status = kret;
669c19800e8SDoug Rabson 	ret = GSS_S_FAILURE;
670c19800e8SDoug Rabson 	goto failure;
671c19800e8SDoug Rabson     }
672c19800e8SDoug Rabson 
673*ae771770SStanislav Sedov     if (flags & GSS_C_DCE_STYLE) {
674*ae771770SStanislav Sedov 	output_token->value = outbuf.data;
675*ae771770SStanislav Sedov 	output_token->length = outbuf.length;
676*ae771770SStanislav Sedov     } else {
677c19800e8SDoug Rabson         ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
678*ae771770SStanislav Sedov 				    (u_char *)(intptr_t)"\x01\x00",
679*ae771770SStanislav Sedov 				    GSS_KRB5_MECHANISM);
680*ae771770SStanislav Sedov 	krb5_data_free (&outbuf);
681c19800e8SDoug Rabson 	if (ret)
682c19800e8SDoug Rabson 	    goto failure;
683*ae771770SStanislav Sedov     }
684c19800e8SDoug Rabson 
685c19800e8SDoug Rabson     free_Checksum(&cksum);
686c19800e8SDoug Rabson 
687c19800e8SDoug Rabson     if (flags & GSS_C_MUTUAL_FLAG) {
688c19800e8SDoug Rabson 	ctx->state = INITIATOR_WAIT_FOR_MUTAL;
689c19800e8SDoug Rabson 	return GSS_S_CONTINUE_NEEDED;
690c19800e8SDoug Rabson     }
691c19800e8SDoug Rabson 
692c19800e8SDoug Rabson     return gsskrb5_initiator_ready(minor_status, ctx, context);
693c19800e8SDoug Rabson failure:
694*ae771770SStanislav Sedov     if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
695*ae771770SStanislav Sedov 	krb5_cc_close(context, ctx->ccache);
696*ae771770SStanislav Sedov     ctx->ccache = NULL;
697c19800e8SDoug Rabson 
698c19800e8SDoug Rabson     return ret;
699c19800e8SDoug Rabson }
700c19800e8SDoug Rabson 
701*ae771770SStanislav Sedov static krb5_error_code
handle_error_packet(krb5_context context,gsskrb5_ctx ctx,krb5_data indata)702*ae771770SStanislav Sedov handle_error_packet(krb5_context context,
703*ae771770SStanislav Sedov 		    gsskrb5_ctx ctx,
704*ae771770SStanislav Sedov 		    krb5_data indata)
705*ae771770SStanislav Sedov {
706*ae771770SStanislav Sedov     krb5_error_code kret;
707*ae771770SStanislav Sedov     KRB_ERROR error;
708*ae771770SStanislav Sedov 
709*ae771770SStanislav Sedov     kret = krb5_rd_error(context, &indata, &error);
710*ae771770SStanislav Sedov     if (kret == 0) {
711*ae771770SStanislav Sedov 	kret = krb5_error_from_rd_error(context, &error, NULL);
712*ae771770SStanislav Sedov 
713*ae771770SStanislav Sedov 	/* save the time skrew for this host */
714*ae771770SStanislav Sedov 	if (kret == KRB5KRB_AP_ERR_SKEW) {
715*ae771770SStanislav Sedov 	    krb5_data timedata;
716*ae771770SStanislav Sedov 	    unsigned char p[4];
717*ae771770SStanislav Sedov 	    int32_t t = error.stime - time(NULL);
718*ae771770SStanislav Sedov 
719*ae771770SStanislav Sedov 	    p[0] = (t >> 24) & 0xFF;
720*ae771770SStanislav Sedov 	    p[1] = (t >> 16) & 0xFF;
721*ae771770SStanislav Sedov 	    p[2] = (t >> 8)  & 0xFF;
722*ae771770SStanislav Sedov 	    p[3] = (t >> 0)  & 0xFF;
723*ae771770SStanislav Sedov 
724*ae771770SStanislav Sedov 	    timedata.data = p;
725*ae771770SStanislav Sedov 	    timedata.length = sizeof(p);
726*ae771770SStanislav Sedov 
727*ae771770SStanislav Sedov 	    krb5_cc_set_config(context, ctx->ccache, ctx->target,
728*ae771770SStanislav Sedov 			       "time-offset", &timedata);
729*ae771770SStanislav Sedov 
730*ae771770SStanislav Sedov 	    if ((ctx->more_flags & RETRIED) == 0)
731*ae771770SStanislav Sedov 		 ctx->state = INITIATOR_RESTART;
732*ae771770SStanislav Sedov 	    ctx->more_flags |= RETRIED;
733*ae771770SStanislav Sedov 	}
734*ae771770SStanislav Sedov 	free_KRB_ERROR (&error);
735*ae771770SStanislav Sedov     }
736*ae771770SStanislav Sedov     return kret;
737*ae771770SStanislav Sedov }
738*ae771770SStanislav Sedov 
739*ae771770SStanislav Sedov 
740c19800e8SDoug Rabson static OM_uint32
repl_mutual(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,const gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,const gss_channel_bindings_t input_chan_bindings,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)741c19800e8SDoug Rabson repl_mutual
742c19800e8SDoug Rabson (OM_uint32 * minor_status,
743c19800e8SDoug Rabson  gsskrb5_ctx ctx,
744c19800e8SDoug Rabson  krb5_context context,
745c19800e8SDoug Rabson  const gss_OID mech_type,
746c19800e8SDoug Rabson  OM_uint32 req_flags,
747c19800e8SDoug Rabson  OM_uint32 time_req,
748c19800e8SDoug Rabson  const gss_channel_bindings_t input_chan_bindings,
749c19800e8SDoug Rabson  const gss_buffer_t input_token,
750c19800e8SDoug Rabson  gss_OID * actual_mech_type,
751c19800e8SDoug Rabson  gss_buffer_t output_token,
752c19800e8SDoug Rabson  OM_uint32 * ret_flags,
753c19800e8SDoug Rabson  OM_uint32 * time_rec
754c19800e8SDoug Rabson     )
755c19800e8SDoug Rabson {
756c19800e8SDoug Rabson     OM_uint32 ret;
757c19800e8SDoug Rabson     krb5_error_code kret;
758c19800e8SDoug Rabson     krb5_data indata;
759c19800e8SDoug Rabson     krb5_ap_rep_enc_part *repl;
760c19800e8SDoug Rabson 
761c19800e8SDoug Rabson     output_token->length = 0;
762c19800e8SDoug Rabson     output_token->value = NULL;
763c19800e8SDoug Rabson 
764c19800e8SDoug Rabson     if (actual_mech_type)
765c19800e8SDoug Rabson 	*actual_mech_type = GSS_KRB5_MECHANISM;
766c19800e8SDoug Rabson 
767*ae771770SStanislav Sedov     if (IS_DCE_STYLE(ctx)) {
768c19800e8SDoug Rabson 	/* There is no OID wrapping. */
769c19800e8SDoug Rabson 	indata.length	= input_token->length;
770c19800e8SDoug Rabson 	indata.data	= input_token->value;
771*ae771770SStanislav Sedov 	kret = krb5_rd_rep(context,
772*ae771770SStanislav Sedov 			   ctx->auth_context,
773*ae771770SStanislav Sedov 			   &indata,
774*ae771770SStanislav Sedov 			   &repl);
775*ae771770SStanislav Sedov 	if (kret) {
776*ae771770SStanislav Sedov 	    ret = _gsskrb5_decapsulate(minor_status,
777*ae771770SStanislav Sedov 				       input_token,
778*ae771770SStanislav Sedov 				       &indata,
779*ae771770SStanislav Sedov 				       "\x03\x00",
780*ae771770SStanislav Sedov 				       GSS_KRB5_MECHANISM);
781*ae771770SStanislav Sedov 	    if (ret == GSS_S_COMPLETE) {
782*ae771770SStanislav Sedov 		*minor_status = handle_error_packet(context, ctx, indata);
783*ae771770SStanislav Sedov 	    } else {
784*ae771770SStanislav Sedov 		*minor_status = kret;
785*ae771770SStanislav Sedov 	    }
786*ae771770SStanislav Sedov 	    return GSS_S_FAILURE;
787*ae771770SStanislav Sedov 	}
788c19800e8SDoug Rabson     } else {
789c19800e8SDoug Rabson 	ret = _gsskrb5_decapsulate (minor_status,
790c19800e8SDoug Rabson 				    input_token,
791c19800e8SDoug Rabson 				    &indata,
792c19800e8SDoug Rabson 				    "\x02\x00",
793c19800e8SDoug Rabson 				    GSS_KRB5_MECHANISM);
794*ae771770SStanislav Sedov 	if (ret == GSS_S_DEFECTIVE_TOKEN) {
795*ae771770SStanislav Sedov 	    /* check if there is an error token sent instead */
796*ae771770SStanislav Sedov 	    ret = _gsskrb5_decapsulate (minor_status,
797*ae771770SStanislav Sedov 					input_token,
798*ae771770SStanislav Sedov 					&indata,
799*ae771770SStanislav Sedov 					"\x03\x00",
800*ae771770SStanislav Sedov 					GSS_KRB5_MECHANISM);
801*ae771770SStanislav Sedov 	    if (ret == GSS_S_COMPLETE) {
802*ae771770SStanislav Sedov 		*minor_status = handle_error_packet(context, ctx, indata);
803*ae771770SStanislav Sedov 		return GSS_S_FAILURE;
804c19800e8SDoug Rabson 	    }
805c19800e8SDoug Rabson 	}
806c19800e8SDoug Rabson 	kret = krb5_rd_rep (context,
807c19800e8SDoug Rabson 			    ctx->auth_context,
808c19800e8SDoug Rabson 			    &indata,
809c19800e8SDoug Rabson 			    &repl);
810c19800e8SDoug Rabson 	if (kret) {
811c19800e8SDoug Rabson 	    *minor_status = kret;
812c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
813c19800e8SDoug Rabson 	}
814*ae771770SStanislav Sedov     }
815*ae771770SStanislav Sedov 
816c19800e8SDoug Rabson     krb5_free_ap_rep_enc_part (context,
817c19800e8SDoug Rabson 			       repl);
818c19800e8SDoug Rabson 
819c19800e8SDoug Rabson     *minor_status = 0;
820c19800e8SDoug Rabson     if (time_rec) {
821c19800e8SDoug Rabson 	ret = _gsskrb5_lifetime_left(minor_status,
822c19800e8SDoug Rabson 				     context,
823c19800e8SDoug Rabson 				     ctx->lifetime,
824c19800e8SDoug Rabson 				     time_rec);
825c19800e8SDoug Rabson     } else {
826c19800e8SDoug Rabson 	ret = GSS_S_COMPLETE;
827c19800e8SDoug Rabson     }
828c19800e8SDoug Rabson     if (ret_flags)
829c19800e8SDoug Rabson 	*ret_flags = ctx->flags;
830c19800e8SDoug Rabson 
831c19800e8SDoug Rabson     if (req_flags & GSS_C_DCE_STYLE) {
832*ae771770SStanislav Sedov 	int32_t local_seq, remote_seq;
833c19800e8SDoug Rabson 	krb5_data outbuf;
834c19800e8SDoug Rabson 
835*ae771770SStanislav Sedov 	/*
836*ae771770SStanislav Sedov 	 * So DCE_STYLE is strange. The client echos the seq number
837*ae771770SStanislav Sedov 	 * that the server used in the server's mk_rep in its own
838*ae771770SStanislav Sedov 	 * mk_rep(). After when done, it resets to it's own seq number
839*ae771770SStanislav Sedov 	 * for the gss_wrap calls.
840*ae771770SStanislav Sedov 	 */
841c19800e8SDoug Rabson 
842*ae771770SStanislav Sedov 	krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &remote_seq);
843*ae771770SStanislav Sedov 	krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq);
844*ae771770SStanislav Sedov 	krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq);
845*ae771770SStanislav Sedov 
846*ae771770SStanislav Sedov 	kret = krb5_mk_rep(context, ctx->auth_context, &outbuf);
847c19800e8SDoug Rabson 	if (kret) {
848c19800e8SDoug Rabson 	    *minor_status = kret;
849c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
850c19800e8SDoug Rabson 	}
851c19800e8SDoug Rabson 
852*ae771770SStanislav Sedov 	/* reset local seq number */
853*ae771770SStanislav Sedov 	krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq);
854*ae771770SStanislav Sedov 
855c19800e8SDoug Rabson 	output_token->length = outbuf.length;
856c19800e8SDoug Rabson 	output_token->value  = outbuf.data;
857c19800e8SDoug Rabson     }
858c19800e8SDoug Rabson 
859c19800e8SDoug Rabson     return gsskrb5_initiator_ready(minor_status, ctx, context);
860c19800e8SDoug Rabson }
861c19800e8SDoug Rabson 
862c19800e8SDoug Rabson /*
863c19800e8SDoug Rabson  * gss_init_sec_context
864c19800e8SDoug Rabson  */
865c19800e8SDoug Rabson 
_gsskrb5_init_sec_context(OM_uint32 * minor_status,const gss_cred_id_t cred_handle,gss_ctx_id_t * context_handle,const gss_name_t target_name,const gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,const gss_channel_bindings_t input_chan_bindings,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)866*ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context
867c19800e8SDoug Rabson (OM_uint32 * minor_status,
868*ae771770SStanislav Sedov  const gss_cred_id_t cred_handle,
869c19800e8SDoug Rabson  gss_ctx_id_t * context_handle,
870c19800e8SDoug Rabson  const gss_name_t target_name,
871c19800e8SDoug Rabson  const gss_OID mech_type,
872c19800e8SDoug Rabson  OM_uint32 req_flags,
873c19800e8SDoug Rabson  OM_uint32 time_req,
874c19800e8SDoug Rabson  const gss_channel_bindings_t input_chan_bindings,
875c19800e8SDoug Rabson  const gss_buffer_t input_token,
876c19800e8SDoug Rabson  gss_OID * actual_mech_type,
877c19800e8SDoug Rabson  gss_buffer_t output_token,
878c19800e8SDoug Rabson  OM_uint32 * ret_flags,
879c19800e8SDoug Rabson  OM_uint32 * time_rec
880c19800e8SDoug Rabson     )
881c19800e8SDoug Rabson {
882c19800e8SDoug Rabson     krb5_context context;
883*ae771770SStanislav Sedov     gsskrb5_cred cred = (gsskrb5_cred)cred_handle;
884c19800e8SDoug Rabson     gsskrb5_ctx ctx;
885c19800e8SDoug Rabson     OM_uint32 ret;
886c19800e8SDoug Rabson 
887c19800e8SDoug Rabson     GSSAPI_KRB5_INIT (&context);
888c19800e8SDoug Rabson 
889c19800e8SDoug Rabson     output_token->length = 0;
890c19800e8SDoug Rabson     output_token->value  = NULL;
891c19800e8SDoug Rabson 
892c19800e8SDoug Rabson     if (context_handle == NULL) {
893c19800e8SDoug Rabson 	*minor_status = 0;
894c19800e8SDoug Rabson 	return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
895c19800e8SDoug Rabson     }
896c19800e8SDoug Rabson 
897c19800e8SDoug Rabson     if (ret_flags)
898c19800e8SDoug Rabson 	*ret_flags = 0;
899c19800e8SDoug Rabson     if (time_rec)
900c19800e8SDoug Rabson 	*time_rec = 0;
901c19800e8SDoug Rabson 
902c19800e8SDoug Rabson     if (target_name == GSS_C_NO_NAME) {
903c19800e8SDoug Rabson 	if (actual_mech_type)
904c19800e8SDoug Rabson 	    *actual_mech_type = GSS_C_NO_OID;
905c19800e8SDoug Rabson 	*minor_status = 0;
906c19800e8SDoug Rabson 	return GSS_S_BAD_NAME;
907c19800e8SDoug Rabson     }
908c19800e8SDoug Rabson 
909c19800e8SDoug Rabson     if (mech_type != GSS_C_NO_OID &&
910c19800e8SDoug Rabson 	!gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
911c19800e8SDoug Rabson 	return GSS_S_BAD_MECH;
912c19800e8SDoug Rabson 
913c19800e8SDoug Rabson     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
914*ae771770SStanislav Sedov 	OM_uint32 ret1;
915c19800e8SDoug Rabson 
916c19800e8SDoug Rabson 	if (*context_handle != GSS_C_NO_CONTEXT) {
917c19800e8SDoug Rabson 	    *minor_status = 0;
918c19800e8SDoug Rabson 	    return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
919c19800e8SDoug Rabson 	}
920c19800e8SDoug Rabson 
921*ae771770SStanislav Sedov 	ret1 = _gsskrb5_create_ctx(minor_status,
922c19800e8SDoug Rabson 				  context_handle,
923c19800e8SDoug Rabson 				  context,
924c19800e8SDoug Rabson 				  input_chan_bindings,
925c19800e8SDoug Rabson 				  INITIATOR_START);
926*ae771770SStanislav Sedov 	if (ret1)
927*ae771770SStanislav Sedov 	    return ret1;
928c19800e8SDoug Rabson     }
929c19800e8SDoug Rabson 
930c19800e8SDoug Rabson     if (*context_handle == GSS_C_NO_CONTEXT) {
931c19800e8SDoug Rabson 	*minor_status = 0;
932c19800e8SDoug Rabson 	return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
933c19800e8SDoug Rabson     }
934c19800e8SDoug Rabson 
935c19800e8SDoug Rabson     ctx = (gsskrb5_ctx) *context_handle;
936c19800e8SDoug Rabson 
937c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
938c19800e8SDoug Rabson 
939*ae771770SStanislav Sedov  again:
940c19800e8SDoug Rabson     switch (ctx->state) {
941c19800e8SDoug Rabson     case INITIATOR_START:
942c19800e8SDoug Rabson 	ret = init_auth(minor_status,
943c19800e8SDoug Rabson 			cred,
944c19800e8SDoug Rabson 			ctx,
945c19800e8SDoug Rabson 			context,
946*ae771770SStanislav Sedov 			target_name,
947c19800e8SDoug Rabson 			mech_type,
948c19800e8SDoug Rabson 			req_flags,
949c19800e8SDoug Rabson 			time_req,
950*ae771770SStanislav Sedov 			input_token,
951*ae771770SStanislav Sedov 			actual_mech_type,
952*ae771770SStanislav Sedov 			output_token,
953*ae771770SStanislav Sedov 			ret_flags,
954*ae771770SStanislav Sedov 			time_rec);
955*ae771770SStanislav Sedov 	if (ret != GSS_S_COMPLETE)
956*ae771770SStanislav Sedov 	    break;
957*ae771770SStanislav Sedov 	/* FALL THOUGH */
958*ae771770SStanislav Sedov     case INITIATOR_RESTART:
959*ae771770SStanislav Sedov 	ret = init_auth_restart(minor_status,
960*ae771770SStanislav Sedov 				cred,
961*ae771770SStanislav Sedov 				ctx,
962*ae771770SStanislav Sedov 				context,
963*ae771770SStanislav Sedov 				req_flags,
964c19800e8SDoug Rabson 				input_chan_bindings,
965c19800e8SDoug Rabson 				input_token,
966c19800e8SDoug Rabson 				actual_mech_type,
967c19800e8SDoug Rabson 				output_token,
968c19800e8SDoug Rabson 				ret_flags,
969c19800e8SDoug Rabson 				time_rec);
970c19800e8SDoug Rabson 	break;
971c19800e8SDoug Rabson     case INITIATOR_WAIT_FOR_MUTAL:
972c19800e8SDoug Rabson 	ret = repl_mutual(minor_status,
973c19800e8SDoug Rabson 			  ctx,
974c19800e8SDoug Rabson 			  context,
975c19800e8SDoug Rabson 			  mech_type,
976c19800e8SDoug Rabson 			  req_flags,
977c19800e8SDoug Rabson 			  time_req,
978c19800e8SDoug Rabson 			  input_chan_bindings,
979c19800e8SDoug Rabson 			  input_token,
980c19800e8SDoug Rabson 			  actual_mech_type,
981c19800e8SDoug Rabson 			  output_token,
982c19800e8SDoug Rabson 			  ret_flags,
983c19800e8SDoug Rabson 			  time_rec);
984*ae771770SStanislav Sedov 	if (ctx->state == INITIATOR_RESTART)
985*ae771770SStanislav Sedov 	    goto again;
986c19800e8SDoug Rabson 	break;
987c19800e8SDoug Rabson     case INITIATOR_READY:
988c19800e8SDoug Rabson 	/*
989c19800e8SDoug Rabson 	 * If we get there, the caller have called
990c19800e8SDoug Rabson 	 * gss_init_sec_context() one time too many.
991c19800e8SDoug Rabson 	 */
992*ae771770SStanislav Sedov 	_gsskrb5_set_status(EINVAL, "init_sec_context "
993*ae771770SStanislav Sedov 			    "called one time too many");
994*ae771770SStanislav Sedov 	*minor_status = EINVAL;
995c19800e8SDoug Rabson 	ret = GSS_S_BAD_STATUS;
996c19800e8SDoug Rabson 	break;
997c19800e8SDoug Rabson     default:
998*ae771770SStanislav Sedov 	_gsskrb5_set_status(EINVAL, "init_sec_context "
999*ae771770SStanislav Sedov 			    "invalid state %d for client",
1000*ae771770SStanislav Sedov 			    (int)ctx->state);
1001*ae771770SStanislav Sedov 	*minor_status = EINVAL;
1002c19800e8SDoug Rabson 	ret = GSS_S_BAD_STATUS;
1003c19800e8SDoug Rabson 	break;
1004c19800e8SDoug Rabson     }
1005c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1006c19800e8SDoug Rabson 
1007c19800e8SDoug Rabson     /* destroy context in case of error */
1008c19800e8SDoug Rabson     if (GSS_ERROR(ret)) {
1009c19800e8SDoug Rabson 	OM_uint32 min2;
1010c19800e8SDoug Rabson 	_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
1011c19800e8SDoug Rabson     }
1012c19800e8SDoug Rabson 
1013c19800e8SDoug Rabson     return ret;
1014c19800e8SDoug Rabson 
1015c19800e8SDoug Rabson }
1016