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