x
[heimdal.git] / lib / gssapi / krb5 / init_sec_context.c
blobf3b7cc59505b652d1d5d005048b368ac92c2bc89
1 /*
2 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "gssapi_locl.h"
36 RCSID("$Id$");
39 * copy the addresses from `input_chan_bindings' (if any) to
40 * the auth context `ac'
43 static OM_uint32
44 set_addresses (krb5_auth_context ac,
45 const gss_channel_bindings_t input_chan_bindings)
47 /* Port numbers are expected to be in application_data.value,
48 * initator's port first */
50 krb5_address initiator_addr, acceptor_addr;
51 krb5_error_code kret;
53 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
54 || input_chan_bindings->application_data.length !=
55 2 * sizeof(ac->local_port))
56 return 0;
58 memset(&initiator_addr, 0, sizeof(initiator_addr));
59 memset(&acceptor_addr, 0, sizeof(acceptor_addr));
61 ac->local_port =
62 *(int16_t *) input_chan_bindings->application_data.value;
64 ac->remote_port =
65 *((int16_t *) input_chan_bindings->application_data.value + 1);
67 kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
68 &input_chan_bindings->acceptor_address,
69 ac->remote_port,
70 &acceptor_addr);
71 if (kret)
72 return kret;
74 kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
75 &input_chan_bindings->initiator_address,
76 ac->local_port,
77 &initiator_addr);
78 if (kret) {
79 krb5_free_address (gssapi_krb5_context, &acceptor_addr);
80 return kret;
83 kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
84 ac,
85 &initiator_addr, /* local address */
86 &acceptor_addr); /* remote address */
88 krb5_free_address (gssapi_krb5_context, &initiator_addr);
89 krb5_free_address (gssapi_krb5_context, &acceptor_addr);
91 #if 0
92 free(input_chan_bindings->application_data.value);
93 input_chan_bindings->application_data.value = NULL;
94 input_chan_bindings->application_data.length = 0;
95 #endif
97 return kret;
101 * handle delegated creds in init-sec-context
104 static void
105 do_delegation (krb5_auth_context ac,
106 krb5_ccache ccache,
107 krb5_creds *cred,
108 const gss_name_t target_name,
109 krb5_data *fwd_data,
110 int *flags)
112 krb5_creds creds;
113 krb5_kdc_flags fwd_flags;
114 krb5_keyblock *subkey;
115 krb5_error_code kret;
117 memset (&creds, 0, sizeof(creds));
118 krb5_data_zero (fwd_data);
120 kret = krb5_generate_subkey (gssapi_krb5_context, &cred->session, &subkey);
121 if (kret)
122 goto out;
124 kret = krb5_auth_con_setlocalsubkey(gssapi_krb5_context, ac, subkey);
125 krb5_free_keyblock (gssapi_krb5_context, subkey);
126 if (kret)
127 goto out;
129 kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
130 if (kret)
131 goto out;
133 kret = krb5_build_principal(gssapi_krb5_context,
134 &creds.server,
135 strlen(creds.client->realm),
136 creds.client->realm,
137 KRB5_TGS_NAME,
138 creds.client->realm,
139 NULL);
140 if (kret)
141 goto out;
143 creds.times.endtime = 0;
145 fwd_flags.i = 0;
146 fwd_flags.b.forwarded = 1;
147 fwd_flags.b.forwardable = 1;
149 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
150 target_name->name.name_string.len < 2)
151 goto out;
153 kret = krb5_get_forwarded_creds(gssapi_krb5_context,
155 ccache,
156 fwd_flags.i,
157 target_name->name.name_string.val[1],
158 &creds,
159 fwd_data);
161 out:
162 if (kret)
163 *flags &= ~GSS_C_DELEG_FLAG;
164 else
165 *flags |= GSS_C_DELEG_FLAG;
167 if (creds.client)
168 krb5_free_principal(gssapi_krb5_context, creds.client);
169 if (creds.server)
170 krb5_free_principal(gssapi_krb5_context, creds.server);
174 * first stage of init-sec-context
177 static OM_uint32
178 init_auth
179 (OM_uint32 * minor_status,
180 const gss_cred_id_t initiator_cred_handle,
181 gss_ctx_id_t * context_handle,
182 const gss_name_t target_name,
183 const gss_OID mech_type,
184 OM_uint32 req_flags,
185 OM_uint32 time_req,
186 const gss_channel_bindings_t input_chan_bindings,
187 const gss_buffer_t input_token,
188 gss_OID * actual_mech_type,
189 gss_buffer_t output_token,
190 OM_uint32 * ret_flags,
191 OM_uint32 * time_rec
194 OM_uint32 ret = GSS_S_FAILURE;
195 krb5_error_code kret;
196 krb5_flags ap_options;
197 krb5_creds this_cred, *cred;
198 krb5_data outbuf;
199 krb5_ccache ccache;
200 u_int32_t flags;
201 Authenticator *auth;
202 krb5_data authenticator;
203 Checksum cksum;
204 krb5_enctype enctype;
205 krb5_data fwd_data;
207 output_token->length = 0;
208 output_token->value = NULL;
210 krb5_data_zero(&outbuf);
211 krb5_data_zero(&fwd_data);
213 *minor_status = 0;
215 *context_handle = malloc(sizeof(**context_handle));
216 if (*context_handle == NULL) {
217 *minor_status = ENOMEM;
218 return GSS_S_FAILURE;
221 (*context_handle)->auth_context = NULL;
222 (*context_handle)->source = NULL;
223 (*context_handle)->target = NULL;
224 (*context_handle)->flags = 0;
225 (*context_handle)->more_flags = 0;
226 (*context_handle)->ticket = NULL;
228 kret = krb5_auth_con_init (gssapi_krb5_context,
229 &(*context_handle)->auth_context);
230 if (kret) {
231 gssapi_krb5_set_error_string ();
232 *minor_status = kret;
233 ret = GSS_S_FAILURE;
234 goto failure;
237 kret = set_addresses ((*context_handle)->auth_context,
238 input_chan_bindings);
239 if (kret) {
240 *minor_status = kret;
241 ret = GSS_S_BAD_BINDINGS;
242 goto failure;
246 int32_t tmp;
248 krb5_auth_con_getflags(gssapi_krb5_context,
249 (*context_handle)->auth_context,
250 &tmp);
251 tmp |= KRB5_AUTH_CONTEXT_DO_SEQUENCE;
252 krb5_auth_con_setflags(gssapi_krb5_context,
253 (*context_handle)->auth_context,
254 tmp);
257 if (actual_mech_type)
258 *actual_mech_type = GSS_KRB5_MECHANISM;
260 if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
261 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
262 if (kret) {
263 gssapi_krb5_set_error_string ();
264 *minor_status = kret;
265 ret = GSS_S_FAILURE;
266 goto failure;
268 } else
269 ccache = initiator_cred_handle->ccache;
271 kret = krb5_cc_get_principal (gssapi_krb5_context,
272 ccache,
273 &(*context_handle)->source);
274 if (kret) {
275 gssapi_krb5_set_error_string ();
276 *minor_status = kret;
277 ret = GSS_S_FAILURE;
278 goto failure;
281 kret = krb5_copy_principal (gssapi_krb5_context,
282 target_name,
283 &(*context_handle)->target);
284 if (kret) {
285 gssapi_krb5_set_error_string ();
286 *minor_status = kret;
287 ret = GSS_S_FAILURE;
288 goto failure;
291 memset(&this_cred, 0, sizeof(this_cred));
292 this_cred.client = (*context_handle)->source;
293 this_cred.server = (*context_handle)->target;
294 if (time_req) {
295 krb5_timestamp ts;
297 krb5_timeofday (gssapi_krb5_context, &ts);
298 this_cred.times.endtime = ts + time_req;
299 } else
300 this_cred.times.endtime = 0;
301 this_cred.session.keytype = 0;
303 kret = krb5_get_credentials (gssapi_krb5_context,
304 KRB5_TC_MATCH_KEYTYPE,
305 ccache,
306 &this_cred,
307 &cred);
309 if (kret) {
310 gssapi_krb5_set_error_string ();
311 *minor_status = kret;
312 ret = GSS_S_FAILURE;
313 goto failure;
316 krb5_auth_con_setkey(gssapi_krb5_context,
317 (*context_handle)->auth_context,
318 &cred->session);
320 flags = 0;
321 ap_options = 0;
322 if (req_flags & GSS_C_DELEG_FLAG)
323 do_delegation ((*context_handle)->auth_context,
324 ccache, cred, target_name, &fwd_data, &flags);
326 if (req_flags & GSS_C_MUTUAL_FLAG) {
327 flags |= GSS_C_MUTUAL_FLAG;
328 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
331 if (req_flags & GSS_C_REPLAY_FLAG)
332 ; /* XXX */
333 if (req_flags & GSS_C_SEQUENCE_FLAG)
334 ; /* XXX */
335 if (req_flags & GSS_C_ANON_FLAG)
336 ; /* XXX */
337 flags |= GSS_C_CONF_FLAG;
338 flags |= GSS_C_INTEG_FLAG;
339 flags |= GSS_C_SEQUENCE_FLAG;
340 flags |= GSS_C_TRANS_FLAG;
342 if (ret_flags)
343 *ret_flags = flags;
344 (*context_handle)->flags = flags;
345 (*context_handle)->more_flags = LOCAL;
347 ret = gssapi_krb5_create_8003_checksum (minor_status,
348 input_chan_bindings,
349 flags,
350 &fwd_data,
351 &cksum);
352 krb5_data_free (&fwd_data);
353 if (ret)
354 goto failure;
356 #if 1
357 enctype = (*context_handle)->auth_context->keyblock->keytype;
358 #else
359 if ((*context_handle)->auth_context->enctype)
360 enctype = (*context_handle)->auth_context->enctype;
361 else {
362 kret = krb5_keytype_to_enctype(gssapi_krb5_context,
363 (*context_handle)->auth_context->keyblock->keytype,
364 &enctype);
365 if (kret)
366 return kret;
368 #endif
370 kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context,
371 (*context_handle)->auth_context,
372 &cred->session);
373 if(kret) {
374 gssapi_krb5_set_error_string ();
375 *minor_status = kret;
376 ret = GSS_S_FAILURE;
377 goto failure;
380 kret = krb5_build_authenticator (gssapi_krb5_context,
381 (*context_handle)->auth_context,
382 enctype,
383 cred,
384 &cksum,
385 &auth,
386 &authenticator,
387 KRB5_KU_AP_REQ_AUTH);
389 if (kret) {
390 gssapi_krb5_set_error_string ();
391 *minor_status = kret;
392 ret = GSS_S_FAILURE;
393 goto failure;
396 kret = krb5_build_ap_req (gssapi_krb5_context,
397 enctype,
398 cred,
399 ap_options,
400 authenticator,
401 &outbuf);
403 if (kret) {
404 gssapi_krb5_set_error_string ();
405 *minor_status = kret;
406 ret = GSS_S_FAILURE;
407 goto failure;
410 ret = gssapi_krb5_encapsulate (minor_status, &outbuf, output_token,
411 "\x01\x00");
412 if (ret)
413 goto failure;
415 krb5_data_free (&outbuf);
417 if (flags & GSS_C_MUTUAL_FLAG) {
418 return GSS_S_CONTINUE_NEEDED;
419 } else {
420 (*context_handle)->more_flags |= OPEN;
421 return GSS_S_COMPLETE;
424 failure:
425 krb5_auth_con_free (gssapi_krb5_context,
426 (*context_handle)->auth_context);
427 if((*context_handle)->source)
428 krb5_free_principal (gssapi_krb5_context,
429 (*context_handle)->source);
430 if((*context_handle)->target)
431 krb5_free_principal (gssapi_krb5_context,
432 (*context_handle)->target);
433 free (*context_handle);
434 krb5_data_free (&outbuf);
435 *context_handle = GSS_C_NO_CONTEXT;
436 return ret;
439 static OM_uint32
440 repl_mutual
441 (OM_uint32 * minor_status,
442 const gss_cred_id_t initiator_cred_handle,
443 gss_ctx_id_t * context_handle,
444 const gss_name_t target_name,
445 const gss_OID mech_type,
446 OM_uint32 req_flags,
447 OM_uint32 time_req,
448 const gss_channel_bindings_t input_chan_bindings,
449 const gss_buffer_t input_token,
450 gss_OID * actual_mech_type,
451 gss_buffer_t output_token,
452 OM_uint32 * ret_flags,
453 OM_uint32 * time_rec
456 OM_uint32 ret;
457 krb5_error_code kret;
458 krb5_data indata;
459 krb5_ap_rep_enc_part *repl;
461 ret = gssapi_krb5_decapsulate (minor_status, input_token, &indata,
462 "\x02\x00");
463 if (ret)
464 /* XXX - Handle AP_ERROR */
465 return ret;
467 kret = krb5_rd_rep (gssapi_krb5_context,
468 (*context_handle)->auth_context,
469 &indata,
470 &repl);
471 if (kret) {
472 gssapi_krb5_set_error_string ();
473 *minor_status = kret;
474 return GSS_S_FAILURE;
476 krb5_free_ap_rep_enc_part (gssapi_krb5_context,
477 repl);
479 output_token->length = 0;
481 (*context_handle)->more_flags |= OPEN;
483 return GSS_S_COMPLETE;
487 * gss_init_sec_context
490 OM_uint32 gss_init_sec_context
491 (OM_uint32 * minor_status,
492 const gss_cred_id_t initiator_cred_handle,
493 gss_ctx_id_t * context_handle,
494 const gss_name_t target_name,
495 const gss_OID mech_type,
496 OM_uint32 req_flags,
497 OM_uint32 time_req,
498 const gss_channel_bindings_t input_chan_bindings,
499 const gss_buffer_t input_token,
500 gss_OID * actual_mech_type,
501 gss_buffer_t output_token,
502 OM_uint32 * ret_flags,
503 OM_uint32 * time_rec
506 gssapi_krb5_init ();
508 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
509 return init_auth (minor_status,
510 initiator_cred_handle,
511 context_handle,
512 target_name,
513 mech_type,
514 req_flags,
515 time_req,
516 input_chan_bindings,
517 input_token,
518 actual_mech_type,
519 output_token,
520 ret_flags,
521 time_rec);
522 else
523 return repl_mutual(minor_status,
524 initiator_cred_handle,
525 context_handle,
526 target_name,
527 mech_type,
528 req_flags,
529 time_req,
530 input_chan_bindings,
531 input_token,
532 actual_mech_type,
533 output_token,
534 ret_flags,
535 time_rec);