x
[heimdal.git] / lib / gssapi / krb5 / init_sec_context.c
blobee242f51f25d74704ee28963622163edd5cb1aec
1 /*
2 * Copyright (c) 1997 - 2003 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_error_code kret;
116 memset (&creds, 0, sizeof(creds));
117 krb5_data_zero (fwd_data);
119 kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
120 if (kret)
121 goto out;
123 kret = krb5_build_principal(gssapi_krb5_context,
124 &creds.server,
125 strlen(creds.client->realm),
126 creds.client->realm,
127 KRB5_TGS_NAME,
128 creds.client->realm,
129 NULL);
130 if (kret)
131 goto out;
133 creds.times.endtime = 0;
135 fwd_flags.i = 0;
136 fwd_flags.b.forwarded = 1;
137 fwd_flags.b.forwardable = 1;
139 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
140 target_name->name.name_string.len < 2)
141 goto out;
143 kret = krb5_get_forwarded_creds(gssapi_krb5_context,
145 ccache,
146 fwd_flags.i,
147 target_name->name.name_string.val[1],
148 &creds,
149 fwd_data);
151 out:
152 if (kret)
153 *flags &= ~GSS_C_DELEG_FLAG;
154 else
155 *flags |= GSS_C_DELEG_FLAG;
157 if (creds.client)
158 krb5_free_principal(gssapi_krb5_context, creds.client);
159 if (creds.server)
160 krb5_free_principal(gssapi_krb5_context, creds.server);
164 * first stage of init-sec-context
167 static OM_uint32
168 init_auth
169 (OM_uint32 * minor_status,
170 const gss_cred_id_t initiator_cred_handle,
171 gss_ctx_id_t * context_handle,
172 const gss_name_t target_name,
173 const gss_OID mech_type,
174 OM_uint32 req_flags,
175 OM_uint32 time_req,
176 const gss_channel_bindings_t input_chan_bindings,
177 const gss_buffer_t input_token,
178 gss_OID * actual_mech_type,
179 gss_buffer_t output_token,
180 OM_uint32 * ret_flags,
181 OM_uint32 * time_rec
184 OM_uint32 ret = GSS_S_FAILURE;
185 krb5_error_code kret;
186 krb5_flags ap_options;
187 krb5_creds this_cred, *cred = NULL;
188 krb5_data outbuf;
189 krb5_ccache ccache = NULL;
190 u_int32_t flags;
191 krb5_data authenticator;
192 Checksum cksum;
193 krb5_enctype enctype;
194 krb5_data fwd_data;
195 OM_uint32 lifetime_rec;
197 krb5_data_zero(&outbuf);
198 krb5_data_zero(&fwd_data);
200 *minor_status = 0;
202 *context_handle = malloc(sizeof(**context_handle));
203 if (*context_handle == NULL) {
204 *minor_status = ENOMEM;
205 return GSS_S_FAILURE;
208 (*context_handle)->auth_context = NULL;
209 (*context_handle)->source = NULL;
210 (*context_handle)->target = NULL;
211 (*context_handle)->flags = 0;
212 (*context_handle)->more_flags = 0;
213 (*context_handle)->ticket = NULL;
214 (*context_handle)->lifetime = GSS_C_INDEFINITE;
215 (*context_handle)->order = NULL;
216 HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex);
218 kret = krb5_auth_con_init (gssapi_krb5_context,
219 &(*context_handle)->auth_context);
220 if (kret) {
221 gssapi_krb5_set_error_string ();
222 *minor_status = kret;
223 ret = GSS_S_FAILURE;
224 goto failure;
227 kret = set_addresses ((*context_handle)->auth_context,
228 input_chan_bindings);
229 if (kret) {
230 *minor_status = kret;
231 ret = GSS_S_BAD_BINDINGS;
232 goto failure;
235 krb5_auth_con_addflags(gssapi_krb5_context,
236 (*context_handle)->auth_context,
237 KRB5_AUTH_CONTEXT_DO_SEQUENCE |
238 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
239 NULL);
241 if (actual_mech_type)
242 *actual_mech_type = GSS_KRB5_MECHANISM;
244 if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) {
245 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
246 if (kret) {
247 gssapi_krb5_set_error_string ();
248 *minor_status = kret;
249 ret = GSS_S_FAILURE;
250 goto failure;
252 } else
253 ccache = initiator_cred_handle->ccache;
255 kret = krb5_cc_get_principal (gssapi_krb5_context,
256 ccache,
257 &(*context_handle)->source);
258 if (kret) {
259 gssapi_krb5_set_error_string ();
260 *minor_status = kret;
261 ret = GSS_S_FAILURE;
262 goto failure;
265 kret = krb5_copy_principal (gssapi_krb5_context,
266 target_name,
267 &(*context_handle)->target);
268 if (kret) {
269 gssapi_krb5_set_error_string ();
270 *minor_status = kret;
271 ret = GSS_S_FAILURE;
272 goto failure;
275 ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
276 if (ret)
277 goto failure;
280 memset(&this_cred, 0, sizeof(this_cred));
281 this_cred.client = (*context_handle)->source;
282 this_cred.server = (*context_handle)->target;
283 if (time_req && time_req != GSS_C_INDEFINITE) {
284 krb5_timestamp ts;
286 krb5_timeofday (gssapi_krb5_context, &ts);
287 this_cred.times.endtime = ts + time_req;
288 } else
289 this_cred.times.endtime = 0;
290 this_cred.session.keytype = KEYTYPE_NULL;
292 kret = krb5_get_credentials (gssapi_krb5_context,
294 ccache,
295 &this_cred,
296 &cred);
298 if (kret) {
299 gssapi_krb5_set_error_string ();
300 *minor_status = kret;
301 ret = GSS_S_FAILURE;
302 goto failure;
305 (*context_handle)->lifetime = cred->times.endtime;
307 ret = gssapi_lifetime_left(minor_status,
308 (*context_handle)->lifetime,
309 &lifetime_rec);
310 if (ret) {
311 goto failure;
314 if (lifetime_rec == 0) {
315 *minor_status = 0;
316 ret = GSS_S_CONTEXT_EXPIRED;
317 goto failure;
320 krb5_auth_con_setkey(gssapi_krb5_context,
321 (*context_handle)->auth_context,
322 &cred->session);
324 kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context,
325 (*context_handle)->auth_context,
326 &cred->session);
327 if(kret) {
328 gssapi_krb5_set_error_string ();
329 *minor_status = kret;
330 ret = GSS_S_FAILURE;
331 goto failure;
335 * If the realm policy approves a delegation, lets check local
336 * policy if the credentials should be delegated, defafult to
337 * false.
339 if (cred->flags.b.ok_as_delegate) {
340 krb5_boolean delegate = FALSE;
342 _gss_check_compat(NULL, target_name, "ok-as-delegate",
343 &delegate, TRUE);
344 krb5_appdefault_boolean(gssapi_krb5_context,
345 "gssapi", target_name->realm,
346 "ok-as-delegate", delegate, &delegate);
347 if (delegate)
348 req_flags |= GSS_C_DELEG_FLAG;
351 flags = 0;
352 ap_options = 0;
353 if (req_flags & GSS_C_DELEG_FLAG)
354 do_delegation ((*context_handle)->auth_context,
355 ccache, cred, target_name, &fwd_data, &flags);
357 if (req_flags & GSS_C_MUTUAL_FLAG) {
358 flags |= GSS_C_MUTUAL_FLAG;
359 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
362 if (req_flags & GSS_C_REPLAY_FLAG)
363 flags |= GSS_C_REPLAY_FLAG;
364 if (req_flags & GSS_C_SEQUENCE_FLAG)
365 flags |= GSS_C_SEQUENCE_FLAG;
366 if (req_flags & GSS_C_ANON_FLAG)
367 ; /* XXX */
368 flags |= GSS_C_CONF_FLAG;
369 flags |= GSS_C_INTEG_FLAG;
370 flags |= GSS_C_TRANS_FLAG;
372 if (ret_flags)
373 *ret_flags = flags;
374 (*context_handle)->flags = flags;
375 (*context_handle)->more_flags |= LOCAL;
377 ret = gssapi_krb5_create_8003_checksum (minor_status,
378 input_chan_bindings,
379 flags,
380 &fwd_data,
381 &cksum);
382 krb5_data_free (&fwd_data);
383 if (ret)
384 goto failure;
386 enctype = (*context_handle)->auth_context->keyblock->keytype;
388 kret = krb5_build_authenticator (gssapi_krb5_context,
389 (*context_handle)->auth_context,
390 enctype,
391 cred,
392 &cksum,
393 NULL,
394 &authenticator,
395 KRB5_KU_AP_REQ_AUTH);
397 if (kret) {
398 gssapi_krb5_set_error_string ();
399 *minor_status = kret;
400 ret = GSS_S_FAILURE;
401 goto failure;
404 kret = krb5_build_ap_req (gssapi_krb5_context,
405 enctype,
406 cred,
407 ap_options,
408 authenticator,
409 &outbuf);
411 if (kret) {
412 gssapi_krb5_set_error_string ();
413 *minor_status = kret;
414 ret = GSS_S_FAILURE;
415 goto failure;
418 ret = gssapi_krb5_encapsulate (minor_status, &outbuf, output_token,
419 "\x01\x00", GSS_KRB5_MECHANISM);
420 if (ret)
421 goto failure;
423 krb5_data_free (&outbuf);
424 krb5_free_creds(gssapi_krb5_context, cred);
425 free_Checksum(&cksum);
426 if (initiator_cred_handle == GSS_C_NO_CREDENTIAL)
427 krb5_cc_close(gssapi_krb5_context, ccache);
429 if (flags & GSS_C_MUTUAL_FLAG) {
430 return GSS_S_CONTINUE_NEEDED;
431 } else {
432 int32_t seq_number;
433 int is_cfx = 0;
435 krb5_auth_getremoteseqnumber (gssapi_krb5_context,
436 (*context_handle)->auth_context,
437 &seq_number);
439 gsskrb5_is_cfx(*context_handle, &is_cfx);
441 ret = _gssapi_msg_order_create(minor_status,
442 &(*context_handle)->order,
443 _gssapi_msg_order_f(flags),
444 seq_number, 0, is_cfx);
445 if (ret)
446 goto failure;
448 if (time_rec)
449 *time_rec = lifetime_rec;
451 (*context_handle)->more_flags |= OPEN;
452 return GSS_S_COMPLETE;
455 failure:
456 krb5_auth_con_free (gssapi_krb5_context,
457 (*context_handle)->auth_context);
458 krb5_data_free (&outbuf);
459 if(cred)
460 krb5_free_creds(gssapi_krb5_context, cred);
461 if (ccache && initiator_cred_handle == GSS_C_NO_CREDENTIAL)
462 krb5_cc_close(gssapi_krb5_context, ccache);
463 if((*context_handle)->source)
464 krb5_free_principal (gssapi_krb5_context,
465 (*context_handle)->source);
466 if((*context_handle)->target)
467 krb5_free_principal (gssapi_krb5_context,
468 (*context_handle)->target);
469 if((*context_handle)->order)
470 _gssapi_msg_order_destroy(&(*context_handle)->order);
471 HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
472 free (*context_handle);
473 *context_handle = GSS_C_NO_CONTEXT;
474 return ret;
477 static OM_uint32
478 repl_mutual
479 (OM_uint32 * minor_status,
480 const gss_cred_id_t initiator_cred_handle,
481 gss_ctx_id_t * context_handle,
482 const gss_name_t target_name,
483 const gss_OID mech_type,
484 OM_uint32 req_flags,
485 OM_uint32 time_req,
486 const gss_channel_bindings_t input_chan_bindings,
487 const gss_buffer_t input_token,
488 gss_OID * actual_mech_type,
489 gss_buffer_t output_token,
490 OM_uint32 * ret_flags,
491 OM_uint32 * time_rec
494 OM_uint32 ret, seq_number;
495 krb5_error_code kret;
496 krb5_data indata;
497 krb5_ap_rep_enc_part *repl;
498 int is_cfx = 0;
500 output_token->length = 0;
501 output_token->value = NULL;
503 HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
505 if (actual_mech_type)
506 *actual_mech_type = GSS_KRB5_MECHANISM;
508 ret = gssapi_krb5_decapsulate (minor_status, input_token, &indata,
509 "\x02\x00", GSS_KRB5_MECHANISM);
510 if (ret) {
511 HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
512 /* XXX - Handle AP_ERROR */
513 return ret;
516 kret = krb5_rd_rep (gssapi_krb5_context,
517 (*context_handle)->auth_context,
518 &indata,
519 &repl);
520 if (kret) {
521 HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
522 gssapi_krb5_set_error_string ();
523 *minor_status = kret;
524 return GSS_S_FAILURE;
526 krb5_free_ap_rep_enc_part (gssapi_krb5_context,
527 repl);
529 krb5_auth_getremoteseqnumber (gssapi_krb5_context,
530 (*context_handle)->auth_context,
531 &seq_number);
533 gsskrb5_is_cfx(*context_handle, &is_cfx);
535 ret = _gssapi_msg_order_create(minor_status,
536 &(*context_handle)->order,
537 _gssapi_msg_order_f((*context_handle)->flags),
538 seq_number, 0, is_cfx);
539 if (ret) {
540 HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
541 return ret;
544 (*context_handle)->more_flags |= OPEN;
546 *minor_status = 0;
547 if (time_rec) {
548 ret = gssapi_lifetime_left(minor_status,
549 (*context_handle)->lifetime,
550 time_rec);
551 } else {
552 ret = GSS_S_COMPLETE;
554 if (ret_flags)
555 *ret_flags = (*context_handle)->flags;
556 HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
558 return ret;
561 static OM_uint32
562 gsskrb5_init_sec_context
563 (OM_uint32 * minor_status,
564 const gss_cred_id_t initiator_cred_handle,
565 gss_ctx_id_t * context_handle,
566 const gss_name_t target_name,
567 const gss_OID mech_type,
568 OM_uint32 req_flags,
569 OM_uint32 time_req,
570 const gss_channel_bindings_t input_chan_bindings,
571 const gss_buffer_t input_token,
572 gss_OID * actual_mech_type,
573 gss_buffer_t output_token,
574 OM_uint32 * ret_flags,
575 OM_uint32 * time_rec
578 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
579 return init_auth (minor_status,
580 initiator_cred_handle,
581 context_handle,
582 target_name,
583 mech_type,
584 req_flags,
585 time_req,
586 input_chan_bindings,
587 input_token,
588 actual_mech_type,
589 output_token,
590 ret_flags,
591 time_rec);
592 else
593 return repl_mutual(minor_status,
594 initiator_cred_handle,
595 context_handle,
596 target_name,
597 mech_type,
598 req_flags,
599 time_req,
600 input_chan_bindings,
601 input_token,
602 actual_mech_type,
603 output_token,
604 ret_flags,
605 time_rec);
608 static OM_uint32
609 spnego_reply
610 (OM_uint32 * minor_status,
611 const gss_cred_id_t initiator_cred_handle,
612 gss_ctx_id_t * context_handle,
613 const gss_name_t target_name,
614 const gss_OID mech_type,
615 OM_uint32 req_flags,
616 OM_uint32 time_req,
617 const gss_channel_bindings_t input_chan_bindings,
618 const gss_buffer_t input_token,
619 gss_OID * actual_mech_type,
620 gss_buffer_t output_token,
621 OM_uint32 * ret_flags,
622 OM_uint32 * time_rec
625 OM_uint32 ret;
626 krb5_data indata;
627 NegTokenTarg targ;
628 u_char oidbuf[17];
629 size_t oidlen;
630 gss_buffer_desc sub_token;
631 ssize_t mech_len;
632 const u_char *p;
633 size_t len, taglen;
634 krb5_boolean require_mic;
636 output_token->length = 0;
637 output_token->value = NULL;
640 * SPNEGO doesn't include gss wrapping on SubsequentContextToken
641 * like the Kerberos 5 mech does. But lets check for it anyway.
644 mech_len = gssapi_krb5_get_mech (input_token->value,
645 input_token->length,
646 &p);
648 if (mech_len < 0) {
649 indata.data = input_token->value;
650 indata.length = input_token->length;
651 } else if (mech_len == GSS_KRB5_MECHANISM->length
652 && memcmp(GSS_KRB5_MECHANISM->elements, p, mech_len) == 0)
653 return gsskrb5_init_sec_context (minor_status,
654 initiator_cred_handle,
655 context_handle,
656 target_name,
657 GSS_KRB5_MECHANISM,
658 req_flags,
659 time_req,
660 input_chan_bindings,
661 input_token,
662 actual_mech_type,
663 output_token,
664 ret_flags,
665 time_rec);
666 else if (mech_len == GSS_SPNEGO_MECHANISM->length
667 && memcmp(GSS_SPNEGO_MECHANISM->elements, p, mech_len) == 0){
668 ret = _gssapi_decapsulate (minor_status,
669 input_token,
670 &indata,
671 GSS_SPNEGO_MECHANISM);
672 if (ret)
673 return ret;
674 } else
675 return GSS_S_BAD_MECH;
677 ret = der_match_tag_and_length((const char *)indata.data,
678 indata.length,
679 ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
680 if (ret)
681 return ret;
683 if(len > indata.length - taglen)
684 return ASN1_OVERRUN;
686 ret = decode_NegTokenTarg((const char *)indata.data + taglen,
687 len, &targ, NULL);
688 if (ret) {
689 *minor_status = ENOMEM;
690 return GSS_S_FAILURE;
693 if (targ.negResult == NULL
694 || *(targ.negResult) == reject
695 || targ.supportedMech == NULL) {
696 free_NegTokenTarg(&targ);
697 return GSS_S_BAD_MECH;
700 ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
701 sizeof(oidbuf),
702 targ.supportedMech,
703 &oidlen);
704 if (ret || oidlen != GSS_KRB5_MECHANISM->length
705 || memcmp(oidbuf + sizeof(oidbuf) - oidlen,
706 GSS_KRB5_MECHANISM->elements,
707 oidlen) != 0) {
708 free_NegTokenTarg(&targ);
709 return GSS_S_BAD_MECH;
712 if (targ.responseToken != NULL) {
713 sub_token.length = targ.responseToken->length;
714 sub_token.value = targ.responseToken->data;
715 } else {
716 sub_token.length = 0;
717 sub_token.value = NULL;
720 ret = gsskrb5_init_sec_context(minor_status,
721 initiator_cred_handle,
722 context_handle,
723 target_name,
724 GSS_KRB5_MECHANISM,
725 req_flags,
726 time_req,
727 input_chan_bindings,
728 &sub_token,
729 actual_mech_type,
730 output_token,
731 ret_flags,
732 time_rec);
733 if (ret) {
734 free_NegTokenTarg(&targ);
735 return ret;
739 * Verify the mechListMIC if CFX was used; or if local policy
740 * dictated so.
742 ret = _gss_spnego_require_mechlist_mic(minor_status, *context_handle,
743 &require_mic);
744 if (ret) {
745 free_NegTokenTarg(&targ);
746 return ret;
749 if (require_mic) {
750 MechTypeList mechlist;
751 MechType m0;
752 size_t buf_len;
753 gss_buffer_desc mic_buf, mech_buf;
755 if (targ.mechListMIC == NULL) {
756 free_NegTokenTarg(&targ);
757 *minor_status = 0;
758 return GSS_S_BAD_MIC;
761 mechlist.len = 1;
762 mechlist.val = &m0;
764 ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
765 GSS_KRB5_MECHANISM->length,
766 &m0,
767 NULL);
768 if (ret) {
769 free_NegTokenTarg(&targ);
770 *minor_status = ENOMEM;
771 return GSS_S_FAILURE;
774 ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
775 &mechlist, &buf_len, ret);
776 if (ret) {
777 free_NegTokenTarg(&targ);
778 free_oid(&m0);
779 *minor_status = ENOMEM;
780 return GSS_S_FAILURE;
782 if (mech_buf.length != buf_len)
783 abort();
785 mic_buf.length = targ.mechListMIC->length;
786 mic_buf.value = targ.mechListMIC->data;
788 ret = gss_verify_mic(minor_status, *context_handle,
789 &mech_buf, &mic_buf, NULL);
790 free(mech_buf.value);
791 free_oid(&m0);
793 free_NegTokenTarg(&targ);
794 return ret;
797 static OM_uint32
798 spnego_initial
799 (OM_uint32 * minor_status,
800 const gss_cred_id_t initiator_cred_handle,
801 gss_ctx_id_t * context_handle,
802 const gss_name_t target_name,
803 const gss_OID mech_type,
804 OM_uint32 req_flags,
805 OM_uint32 time_req,
806 const gss_channel_bindings_t input_chan_bindings,
807 const gss_buffer_t input_token,
808 gss_OID * actual_mech_type,
809 gss_buffer_t output_token,
810 OM_uint32 * ret_flags,
811 OM_uint32 * time_rec
814 NegTokenInit ni;
815 int ret;
816 OM_uint32 sub, minor;
817 gss_buffer_desc mech_token;
818 u_char *buf;
819 size_t buf_size, buf_len;
820 krb5_data data;
821 #if 1
822 size_t ni_len;
823 #endif
825 memset (&ni, 0, sizeof(ni));
827 ALLOC(ni.mechTypes, 1);
828 if (ni.mechTypes == NULL) {
829 *minor_status = ENOMEM;
830 return GSS_S_FAILURE;
832 ALLOC_SEQ(ni.mechTypes, 1);
833 if (ni.mechTypes->val == NULL) {
834 free_NegTokenInit(&ni);
835 *minor_status = ENOMEM;
836 return GSS_S_FAILURE;
838 ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
839 GSS_KRB5_MECHANISM->length,
840 &ni.mechTypes->val[0],
841 NULL);
842 if (ret) {
843 free_NegTokenInit(&ni);
844 *minor_status = ENOMEM;
845 return GSS_S_FAILURE;
848 #if 0
849 ALLOC(ni.reqFlags, 1);
850 if (ni.reqFlags == NULL) {
851 free_NegTokenInit(&ni);
852 *minor_status = ENOMEM;
853 return GSS_S_FAILURE;
855 ni.reqFlags->delegFlag = req_flags & GSS_C_DELEG_FLAG;
856 ni.reqFlags->mutualFlag = req_flags & GSS_C_MUTUAL_FLAG;
857 ni.reqFlags->replayFlag = req_flags & GSS_C_REPLAY_FLAG;
858 ni.reqFlags->sequenceFlag = req_flags & GSS_C_SEQUENCE_FLAG;
859 ni.reqFlags->anonFlag = req_flags & GSS_C_ANON_FLAG;
860 ni.reqFlags->confFlag = req_flags & GSS_C_CONF_FLAG;
861 ni.reqFlags->integFlag = req_flags & GSS_C_INTEG_FLAG;
862 #else
863 ni.reqFlags = NULL;
864 #endif
866 sub = gsskrb5_init_sec_context(&minor,
867 initiator_cred_handle,
868 context_handle,
869 target_name,
870 GSS_KRB5_MECHANISM,
871 req_flags,
872 time_req,
873 input_chan_bindings,
874 GSS_C_NO_BUFFER,
875 actual_mech_type,
876 &mech_token,
877 ret_flags,
878 time_rec);
879 if (GSS_ERROR(sub)) {
880 free_NegTokenInit(&ni);
881 return sub;
883 if (mech_token.length != 0) {
884 ALLOC(ni.mechToken, 1);
885 if (ni.mechToken == NULL) {
886 free_NegTokenInit(&ni);
887 gss_release_buffer(&minor, &mech_token);
888 *minor_status = ENOMEM;
889 return GSS_S_FAILURE;
891 ni.mechToken->length = mech_token.length;
892 ni.mechToken->data = malloc(mech_token.length);
893 if (ni.mechToken->data == NULL && mech_token.length != 0) {
894 free_NegTokenInit(&ni);
895 gss_release_buffer(&minor, &mech_token);
896 *minor_status = ENOMEM;
897 return GSS_S_FAILURE;
899 memcpy(ni.mechToken->data, mech_token.value, mech_token.length);
900 gss_release_buffer(&minor, &mech_token);
901 } else
902 ni.mechToken = NULL;
904 /* XXX ignore mech list mic for now */
905 ni.mechListMIC = NULL;
908 #if 0
910 int ret;
911 NegotiationToken nt;
913 nt.element = choice_NegotiationToken_negTokenInit;
914 nt.u.negTokenInit = ni;
916 ASN1_MALLOC_ENCODE(NegotiationToken, buf, buf_size,
917 &nt, &buf_len, ret);
918 if (buf_size != buf_len)
919 abort();
921 #else
922 ni_len = length_NegTokenInit(&ni);
923 buf_size = 1 + length_len(ni_len) + ni_len;
925 buf = malloc(buf_size);
926 if (buf == NULL) {
927 free_NegTokenInit(&ni);
928 *minor_status = ENOMEM;
929 return GSS_S_FAILURE;
932 ret = encode_NegTokenInit(buf + buf_size - 1,
933 ni_len,
934 &ni, &buf_len);
935 if (ret == 0 && ni_len != buf_len)
936 abort();
938 if (ret == 0) {
939 size_t tmp;
941 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
942 buf_size - buf_len,
943 buf_len,
944 ASN1_C_CONTEXT,
945 CONS,
947 &tmp);
948 if (ret == 0 && tmp + buf_len != buf_size)
949 abort();
951 if (ret) {
952 *minor_status = ret;
953 free(buf);
954 free_NegTokenInit(&ni);
955 return GSS_S_FAILURE;
958 #endif
959 data.data = buf;
960 data.length = buf_size;
962 free_NegTokenInit(&ni);
963 if (ret)
964 return ret;
966 sub = _gssapi_encapsulate(minor_status,
967 &data,
968 output_token,
969 GSS_SPNEGO_MECHANISM);
970 free (buf);
972 if (sub)
973 return sub;
975 return GSS_S_CONTINUE_NEEDED;
978 static OM_uint32
979 spnego_init_sec_context
980 (OM_uint32 * minor_status,
981 const gss_cred_id_t initiator_cred_handle,
982 gss_ctx_id_t * context_handle,
983 const gss_name_t target_name,
984 const gss_OID mech_type,
985 OM_uint32 req_flags,
986 OM_uint32 time_req,
987 const gss_channel_bindings_t input_chan_bindings,
988 const gss_buffer_t input_token,
989 gss_OID * actual_mech_type,
990 gss_buffer_t output_token,
991 OM_uint32 * ret_flags,
992 OM_uint32 * time_rec
995 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
996 return spnego_initial (minor_status,
997 initiator_cred_handle,
998 context_handle,
999 target_name,
1000 mech_type,
1001 req_flags,
1002 time_req,
1003 input_chan_bindings,
1004 input_token,
1005 actual_mech_type,
1006 output_token,
1007 ret_flags,
1008 time_rec);
1009 else
1010 return spnego_reply (minor_status,
1011 initiator_cred_handle,
1012 context_handle,
1013 target_name,
1014 mech_type,
1015 req_flags,
1016 time_req,
1017 input_chan_bindings,
1018 input_token,
1019 actual_mech_type,
1020 output_token,
1021 ret_flags,
1022 time_rec);
1026 * gss_init_sec_context
1029 OM_uint32 gss_init_sec_context
1030 (OM_uint32 * minor_status,
1031 const gss_cred_id_t initiator_cred_handle,
1032 gss_ctx_id_t * context_handle,
1033 const gss_name_t target_name,
1034 const gss_OID mech_type,
1035 OM_uint32 req_flags,
1036 OM_uint32 time_req,
1037 const gss_channel_bindings_t input_chan_bindings,
1038 const gss_buffer_t input_token,
1039 gss_OID * actual_mech_type,
1040 gss_buffer_t output_token,
1041 OM_uint32 * ret_flags,
1042 OM_uint32 * time_rec
1045 GSSAPI_KRB5_INIT ();
1047 output_token->length = 0;
1048 output_token->value = NULL;
1050 if (ret_flags)
1051 *ret_flags = 0;
1052 if (time_rec)
1053 *time_rec = 0;
1055 if (target_name == GSS_C_NO_NAME) {
1056 if (actual_mech_type)
1057 *actual_mech_type = GSS_C_NO_OID;
1058 *minor_status = 0;
1059 return GSS_S_BAD_NAME;
1062 if (mech_type == GSS_C_NO_OID ||
1063 gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
1064 return gsskrb5_init_sec_context(minor_status,
1065 initiator_cred_handle,
1066 context_handle,
1067 target_name,
1068 mech_type,
1069 req_flags,
1070 time_req,
1071 input_chan_bindings,
1072 input_token,
1073 actual_mech_type,
1074 output_token,
1075 ret_flags,
1076 time_rec);
1077 else if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM))
1078 return spnego_init_sec_context (minor_status,
1079 initiator_cred_handle,
1080 context_handle,
1081 target_name,
1082 mech_type,
1083 req_flags,
1084 time_req,
1085 input_chan_bindings,
1086 input_token,
1087 actual_mech_type,
1088 output_token,
1089 ret_flags,
1090 time_rec);
1091 else
1092 return GSS_S_BAD_MECH;