krb5: implement draft-ietf-kitten-aes-cts-hmac-sha2-07
[heimdal.git] / lib / gssapi / krb5 / init_sec_context.c
blobaee797a77c9fb670aca3a72ca64a9fe6ad381416
1 /*
2 * Copyright (c) 1997 - 2008 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 "gsskrb5_locl.h"
37 * copy the addresses from `input_chan_bindings' (if any) to
38 * the auth context `ac'
41 static OM_uint32
42 set_addresses (krb5_context context,
43 krb5_auth_context ac,
44 const gss_channel_bindings_t input_chan_bindings)
46 /* Port numbers are expected to be in application_data.value,
47 * initator's port first */
49 krb5_address initiator_addr, acceptor_addr;
50 krb5_error_code kret;
52 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
53 || input_chan_bindings->application_data.length !=
54 2 * sizeof(ac->local_port))
55 return 0;
57 memset(&initiator_addr, 0, sizeof(initiator_addr));
58 memset(&acceptor_addr, 0, sizeof(acceptor_addr));
60 ac->local_port =
61 *(int16_t *) input_chan_bindings->application_data.value;
63 ac->remote_port =
64 *((int16_t *) input_chan_bindings->application_data.value + 1);
66 kret = _gsskrb5i_address_to_krb5addr(context,
67 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 = _gsskrb5i_address_to_krb5addr(context,
75 input_chan_bindings->initiator_addrtype,
76 &input_chan_bindings->initiator_address,
77 ac->local_port,
78 &initiator_addr);
79 if (kret) {
80 krb5_free_address (context, &acceptor_addr);
81 return kret;
84 kret = krb5_auth_con_setaddrs(context,
85 ac,
86 &initiator_addr, /* local address */
87 &acceptor_addr); /* remote address */
89 krb5_free_address (context, &initiator_addr);
90 krb5_free_address (context, &acceptor_addr);
92 #if 0
93 free(input_chan_bindings->application_data.value);
94 input_chan_bindings->application_data.value = NULL;
95 input_chan_bindings->application_data.length = 0;
96 #endif
98 return kret;
101 OM_uint32
102 _gsskrb5_create_ctx(
103 OM_uint32 * minor_status,
104 gss_ctx_id_t * context_handle,
105 krb5_context context,
106 const gss_channel_bindings_t input_chan_bindings,
107 enum gss_ctx_id_t_state state)
109 krb5_error_code kret;
110 gsskrb5_ctx ctx;
112 *context_handle = NULL;
114 ctx = malloc(sizeof(*ctx));
115 if (ctx == NULL) {
116 *minor_status = ENOMEM;
117 return GSS_S_FAILURE;
119 ctx->auth_context = NULL;
120 ctx->deleg_auth_context = NULL;
121 ctx->source = NULL;
122 ctx->target = NULL;
123 ctx->kcred = NULL;
124 ctx->ccache = NULL;
125 ctx->state = state;
126 ctx->flags = 0;
127 ctx->more_flags = 0;
128 ctx->service_keyblock = NULL;
129 ctx->ticket = NULL;
130 krb5_data_zero(&ctx->fwd_data);
131 ctx->endtime = 0;
132 ctx->order = NULL;
133 ctx->crypto = NULL;
134 HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
136 kret = krb5_auth_con_init (context, &ctx->auth_context);
137 if (kret) {
138 *minor_status = kret;
139 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
140 free(ctx);
141 return GSS_S_FAILURE;
144 kret = krb5_auth_con_init (context, &ctx->deleg_auth_context);
145 if (kret) {
146 *minor_status = kret;
147 krb5_auth_con_free(context, ctx->auth_context);
148 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
149 free(ctx);
150 return GSS_S_FAILURE;
153 kret = set_addresses(context, ctx->auth_context, input_chan_bindings);
154 if (kret) {
155 *minor_status = kret;
157 krb5_auth_con_free(context, ctx->auth_context);
158 krb5_auth_con_free(context, ctx->deleg_auth_context);
160 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
161 free(ctx);
162 return GSS_S_BAD_BINDINGS;
165 kret = set_addresses(context, ctx->deleg_auth_context, input_chan_bindings);
166 if (kret) {
167 *minor_status = kret;
169 krb5_auth_con_free(context, ctx->auth_context);
170 krb5_auth_con_free(context, ctx->deleg_auth_context);
172 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
173 free(ctx);
174 return GSS_S_BAD_BINDINGS;
178 * We need a sequence number
181 krb5_auth_con_addflags(context,
182 ctx->auth_context,
183 KRB5_AUTH_CONTEXT_DO_SEQUENCE |
184 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
185 NULL);
188 * We need a sequence number
191 krb5_auth_con_addflags(context,
192 ctx->deleg_auth_context,
193 KRB5_AUTH_CONTEXT_DO_SEQUENCE |
194 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
195 NULL);
197 *context_handle = (gss_ctx_id_t)ctx;
199 return GSS_S_COMPLETE;
203 static OM_uint32
204 gsskrb5_get_creds(
205 OM_uint32 * minor_status,
206 krb5_context context,
207 krb5_ccache ccache,
208 gsskrb5_ctx ctx,
209 gss_const_name_t target_name,
210 OM_uint32 time_req,
211 OM_uint32 * time_rec)
213 OM_uint32 ret;
214 krb5_error_code kret;
215 krb5_creds this_cred;
216 OM_uint32 lifetime_rec;
218 if (ctx->target) {
219 krb5_free_principal(context, ctx->target);
220 ctx->target = NULL;
222 if (ctx->kcred) {
223 krb5_free_creds(context, ctx->kcred);
224 ctx->kcred = NULL;
227 ret = _gsskrb5_canon_name(minor_status, context, target_name,
228 &ctx->target);
229 if (ret)
230 return ret;
232 memset(&this_cred, 0, sizeof(this_cred));
233 this_cred.client = ctx->source;
234 this_cred.server = ctx->target;
236 if (time_req && time_req != GSS_C_INDEFINITE) {
237 krb5_timestamp ts;
239 krb5_timeofday (context, &ts);
240 this_cred.times.endtime = ts + time_req;
241 } else {
242 this_cred.times.endtime = 0;
245 this_cred.session.keytype = KEYTYPE_NULL;
247 kret = krb5_get_credentials(context,
249 ccache,
250 &this_cred,
251 &ctx->kcred);
252 if (kret) {
253 *minor_status = kret;
254 return GSS_S_FAILURE;
257 ctx->endtime = ctx->kcred->times.endtime;
259 ret = _gsskrb5_lifetime_left(minor_status, context,
260 ctx->endtime, &lifetime_rec);
261 if (ret) return ret;
263 if (lifetime_rec == 0) {
264 *minor_status = 0;
265 return GSS_S_CONTEXT_EXPIRED;
268 if (time_rec) *time_rec = lifetime_rec;
270 return GSS_S_COMPLETE;
273 static OM_uint32
274 gsskrb5_initiator_ready(
275 OM_uint32 * minor_status,
276 gsskrb5_ctx ctx,
277 krb5_context context)
279 OM_uint32 ret;
280 int32_t seq_number;
281 int is_cfx = 0;
282 OM_uint32 flags = ctx->flags;
284 krb5_free_creds(context, ctx->kcred);
285 ctx->kcred = NULL;
287 if (ctx->more_flags & CLOSE_CCACHE)
288 krb5_cc_close(context, ctx->ccache);
289 ctx->ccache = NULL;
291 krb5_auth_con_getremoteseqnumber (context, ctx->auth_context, &seq_number);
293 _gsskrb5i_is_cfx(context, ctx, 0);
294 is_cfx = (ctx->more_flags & IS_CFX);
296 ret = _gssapi_msg_order_create(minor_status,
297 &ctx->order,
298 _gssapi_msg_order_f(flags),
299 seq_number, 0, is_cfx);
300 if (ret) return ret;
302 ctx->state = INITIATOR_READY;
303 ctx->more_flags |= OPEN;
305 return GSS_S_COMPLETE;
309 * handle delegated creds in init-sec-context
312 static void
313 do_delegation (krb5_context context,
314 krb5_auth_context ac,
315 krb5_ccache ccache,
316 krb5_creds *cred,
317 krb5_const_principal name,
318 krb5_data *fwd_data,
319 uint32_t flagmask,
320 uint32_t *flags)
322 krb5_creds creds;
323 KDCOptions fwd_flags;
324 krb5_error_code kret;
326 memset (&creds, 0, sizeof(creds));
327 krb5_data_zero (fwd_data);
329 kret = krb5_cc_get_principal(context, ccache, &creds.client);
330 if (kret)
331 goto out;
333 kret = krb5_make_principal(context,
334 &creds.server,
335 creds.client->realm,
336 KRB5_TGS_NAME,
337 creds.client->realm,
338 NULL);
339 if (kret)
340 goto out;
342 creds.times.endtime = 0;
344 memset(&fwd_flags, 0, sizeof(fwd_flags));
345 fwd_flags.forwarded = 1;
346 fwd_flags.forwardable = 1;
348 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
349 name->name.name_string.len < 2)
350 goto out;
352 kret = krb5_get_forwarded_creds(context,
354 ccache,
355 KDCOptions2int(fwd_flags),
356 name->name.name_string.val[1],
357 &creds,
358 fwd_data);
360 out:
361 if (kret)
362 *flags &= ~flagmask;
363 else
364 *flags |= flagmask;
366 if (creds.client)
367 krb5_free_principal(context, creds.client);
368 if (creds.server)
369 krb5_free_principal(context, creds.server);
373 * first stage of init-sec-context
376 static OM_uint32
377 init_auth
378 (OM_uint32 * minor_status,
379 gsskrb5_cred cred,
380 gsskrb5_ctx ctx,
381 krb5_context context,
382 gss_const_name_t name,
383 const gss_OID mech_type,
384 OM_uint32 req_flags,
385 OM_uint32 time_req,
386 const gss_buffer_t input_token,
387 gss_OID * actual_mech_type,
388 gss_buffer_t output_token,
389 OM_uint32 * ret_flags,
390 OM_uint32 * time_rec
393 OM_uint32 ret = GSS_S_FAILURE;
394 krb5_error_code kret;
395 krb5_data fwd_data;
396 OM_uint32 lifetime_rec;
398 krb5_data_zero(&fwd_data);
400 *minor_status = 0;
402 if (actual_mech_type)
403 *actual_mech_type = GSS_KRB5_MECHANISM;
405 if (cred == NULL) {
406 kret = krb5_cc_default (context, &ctx->ccache);
407 if (kret) {
408 *minor_status = kret;
409 ret = GSS_S_FAILURE;
410 goto failure;
412 ctx->more_flags |= CLOSE_CCACHE;
413 } else
414 ctx->ccache = cred->ccache;
416 kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source);
417 if (kret) {
418 *minor_status = kret;
419 ret = GSS_S_FAILURE;
420 goto failure;
424 * This is hideous glue for (NFS) clients that wants to limit the
425 * available enctypes to what it can support (encryption in
426 * kernel).
428 if (cred && cred->enctypes)
429 krb5_set_default_in_tkt_etypes(context, cred->enctypes);
431 ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,
432 ctx, name, time_req, time_rec);
433 if (ret)
434 goto failure;
436 ctx->endtime = ctx->kcred->times.endtime;
438 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
439 if (ret)
440 goto failure;
442 ret = _gsskrb5_lifetime_left(minor_status,
443 context,
444 ctx->endtime,
445 &lifetime_rec);
446 if (ret)
447 goto failure;
449 if (lifetime_rec == 0) {
450 *minor_status = 0;
451 ret = GSS_S_CONTEXT_EXPIRED;
452 goto failure;
455 krb5_auth_con_setkey(context,
456 ctx->auth_context,
457 &ctx->kcred->session);
459 kret = krb5_auth_con_generatelocalsubkey(context,
460 ctx->auth_context,
461 &ctx->kcred->session);
462 if(kret) {
463 *minor_status = kret;
464 ret = GSS_S_FAILURE;
465 goto failure;
468 return GSS_S_COMPLETE;
470 failure:
471 if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
472 krb5_cc_close(context, ctx->ccache);
473 ctx->ccache = NULL;
475 return ret;
479 static OM_uint32
480 init_auth_restart
481 (OM_uint32 * minor_status,
482 gsskrb5_cred cred,
483 gsskrb5_ctx ctx,
484 krb5_context context,
485 OM_uint32 req_flags,
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 = GSS_S_FAILURE;
495 krb5_error_code kret;
496 krb5_flags ap_options;
497 krb5_data outbuf;
498 uint32_t flags;
499 krb5_data authenticator;
500 Checksum cksum;
501 krb5_enctype enctype;
502 krb5_data fwd_data, timedata;
503 int32_t offset = 0, oldoffset = 0;
504 uint32_t flagmask;
506 krb5_data_zero(&outbuf);
507 krb5_data_zero(&fwd_data);
509 *minor_status = 0;
512 * If the credential doesn't have ok-as-delegate, check if there
513 * is a realm setting and use that.
515 if (!ctx->kcred->flags.b.ok_as_delegate) {
516 krb5_data data;
518 ret = krb5_cc_get_config(context, ctx->ccache, NULL,
519 "realm-config", &data);
520 if (ret == 0) {
521 /* XXX 1 is use ok-as-delegate */
522 if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0)
523 req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
524 krb5_data_free(&data);
528 flagmask = 0;
530 /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */
531 if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
532 && ctx->kcred->flags.b.ok_as_delegate)
533 flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
534 /* if there still is a GSS_C_DELEG_FLAG, use that */
535 if (req_flags & GSS_C_DELEG_FLAG)
536 flagmask |= GSS_C_DELEG_FLAG;
539 flags = 0;
540 ap_options = 0;
541 if (flagmask & GSS_C_DELEG_FLAG) {
542 do_delegation (context,
543 ctx->deleg_auth_context,
544 ctx->ccache, ctx->kcred, ctx->target,
545 &fwd_data, flagmask, &flags);
548 if (req_flags & GSS_C_MUTUAL_FLAG) {
549 flags |= GSS_C_MUTUAL_FLAG;
550 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
553 if (req_flags & GSS_C_REPLAY_FLAG)
554 flags |= GSS_C_REPLAY_FLAG;
555 if (req_flags & GSS_C_SEQUENCE_FLAG)
556 flags |= GSS_C_SEQUENCE_FLAG;
557 #if 0
558 if (req_flags & GSS_C_ANON_FLAG)
559 ; /* XXX */
560 #endif
561 if (req_flags & GSS_C_DCE_STYLE) {
562 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
563 flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;
564 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
566 if (req_flags & GSS_C_IDENTIFY_FLAG)
567 flags |= GSS_C_IDENTIFY_FLAG;
568 if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)
569 flags |= GSS_C_EXTENDED_ERROR_FLAG;
571 if (req_flags & GSS_C_CONF_FLAG) {
572 flags |= GSS_C_CONF_FLAG;
574 if (req_flags & GSS_C_INTEG_FLAG) {
575 flags |= GSS_C_INTEG_FLAG;
577 if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) {
578 flags |= GSS_C_CONF_FLAG;
579 flags |= GSS_C_INTEG_FLAG;
581 flags |= GSS_C_TRANS_FLAG;
583 if (ret_flags)
584 *ret_flags = flags;
585 ctx->flags = flags;
586 ctx->more_flags |= LOCAL;
588 ret = _gsskrb5_create_8003_checksum (minor_status,
589 input_chan_bindings,
590 flags,
591 &fwd_data,
592 &cksum);
593 krb5_data_free (&fwd_data);
594 if (ret)
595 goto failure;
597 enctype = ctx->auth_context->keyblock->keytype;
599 ret = krb5_cc_get_config(context, ctx->ccache, ctx->target,
600 "time-offset", &timedata);
601 if (ret == 0) {
602 if (timedata.length == 4) {
603 const u_char *p = timedata.data;
604 offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
606 krb5_data_free(&timedata);
609 if (offset) {
610 krb5_get_kdc_sec_offset (context, &oldoffset, NULL);
611 krb5_set_kdc_sec_offset (context, offset, -1);
614 kret = _krb5_build_authenticator(context,
615 ctx->auth_context,
616 enctype,
617 ctx->kcred,
618 &cksum,
619 &authenticator,
620 KRB5_KU_AP_REQ_AUTH);
622 if (kret) {
623 if (offset)
624 krb5_set_kdc_sec_offset (context, oldoffset, -1);
625 *minor_status = kret;
626 ret = GSS_S_FAILURE;
627 goto failure;
630 kret = krb5_build_ap_req (context,
631 enctype,
632 ctx->kcred,
633 ap_options,
634 authenticator,
635 &outbuf);
636 if (offset)
637 krb5_set_kdc_sec_offset (context, oldoffset, -1);
638 if (kret) {
639 *minor_status = kret;
640 ret = GSS_S_FAILURE;
641 goto failure;
644 if (flags & GSS_C_DCE_STYLE) {
645 output_token->value = outbuf.data;
646 output_token->length = outbuf.length;
647 } else {
648 ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
649 (u_char *)(intptr_t)"\x01\x00",
650 GSS_KRB5_MECHANISM);
651 krb5_data_free (&outbuf);
652 if (ret)
653 goto failure;
656 free_Checksum(&cksum);
658 if (flags & GSS_C_MUTUAL_FLAG) {
659 ctx->state = INITIATOR_WAIT_FOR_MUTAL;
660 return GSS_S_CONTINUE_NEEDED;
663 return gsskrb5_initiator_ready(minor_status, ctx, context);
664 failure:
665 if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
666 krb5_cc_close(context, ctx->ccache);
667 ctx->ccache = NULL;
669 return ret;
672 static krb5_error_code
673 handle_error_packet(krb5_context context,
674 gsskrb5_ctx ctx,
675 krb5_data indata)
677 krb5_error_code kret;
678 KRB_ERROR error;
680 kret = krb5_rd_error(context, &indata, &error);
681 if (kret == 0) {
682 kret = krb5_error_from_rd_error(context, &error, NULL);
684 /* save the time skrew for this host */
685 if (kret == KRB5KRB_AP_ERR_SKEW) {
686 krb5_data timedata;
687 unsigned char p[4];
688 int32_t t = error.stime - time(NULL);
690 p[0] = (t >> 24) & 0xFF;
691 p[1] = (t >> 16) & 0xFF;
692 p[2] = (t >> 8) & 0xFF;
693 p[3] = (t >> 0) & 0xFF;
695 timedata.data = p;
696 timedata.length = sizeof(p);
698 krb5_cc_set_config(context, ctx->ccache, ctx->target,
699 "time-offset", &timedata);
701 if ((ctx->more_flags & RETRIED) == 0)
702 ctx->state = INITIATOR_RESTART;
703 ctx->more_flags |= RETRIED;
705 free_KRB_ERROR (&error);
707 return kret;
711 static OM_uint32
712 repl_mutual
713 (OM_uint32 * minor_status,
714 gsskrb5_ctx ctx,
715 krb5_context context,
716 const gss_OID mech_type,
717 OM_uint32 req_flags,
718 OM_uint32 time_req,
719 const gss_channel_bindings_t input_chan_bindings,
720 const gss_buffer_t input_token,
721 gss_OID * actual_mech_type,
722 gss_buffer_t output_token,
723 OM_uint32 * ret_flags,
724 OM_uint32 * time_rec
727 OM_uint32 ret;
728 krb5_error_code kret;
729 krb5_data indata;
730 krb5_ap_rep_enc_part *repl;
732 output_token->length = 0;
733 output_token->value = NULL;
735 if (actual_mech_type)
736 *actual_mech_type = GSS_KRB5_MECHANISM;
738 if (IS_DCE_STYLE(ctx)) {
739 /* There is no OID wrapping. */
740 indata.length = input_token->length;
741 indata.data = input_token->value;
742 kret = krb5_rd_rep(context,
743 ctx->auth_context,
744 &indata,
745 &repl);
746 if (kret) {
747 ret = _gsskrb5_decapsulate(minor_status,
748 input_token,
749 &indata,
750 "\x03\x00",
751 GSS_KRB5_MECHANISM);
752 if (ret == GSS_S_COMPLETE) {
753 *minor_status = handle_error_packet(context, ctx, indata);
754 } else {
755 *minor_status = kret;
757 return GSS_S_FAILURE;
759 } else {
760 ret = _gsskrb5_decapsulate (minor_status,
761 input_token,
762 &indata,
763 "\x02\x00",
764 GSS_KRB5_MECHANISM);
765 if (ret == GSS_S_DEFECTIVE_TOKEN) {
766 /* check if there is an error token sent instead */
767 ret = _gsskrb5_decapsulate (minor_status,
768 input_token,
769 &indata,
770 "\x03\x00",
771 GSS_KRB5_MECHANISM);
772 if (ret == GSS_S_COMPLETE) {
773 *minor_status = handle_error_packet(context, ctx, indata);
774 return GSS_S_FAILURE;
777 kret = krb5_rd_rep (context,
778 ctx->auth_context,
779 &indata,
780 &repl);
781 if (kret) {
782 *minor_status = kret;
783 return GSS_S_FAILURE;
787 krb5_free_ap_rep_enc_part (context,
788 repl);
790 *minor_status = 0;
791 if (time_rec) {
792 ret = _gsskrb5_lifetime_left(minor_status,
793 context,
794 ctx->endtime,
795 time_rec);
796 } else {
797 ret = GSS_S_COMPLETE;
799 if (ret_flags)
800 *ret_flags = ctx->flags;
802 if (req_flags & GSS_C_DCE_STYLE) {
803 int32_t local_seq, remote_seq;
804 krb5_data outbuf;
807 * So DCE_STYLE is strange. The client echos the seq number
808 * that the server used in the server's mk_rep in its own
809 * mk_rep(). After when done, it resets to it's own seq number
810 * for the gss_wrap calls.
813 krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &remote_seq);
814 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq);
815 krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq);
817 kret = krb5_mk_rep(context, ctx->auth_context, &outbuf);
818 if (kret) {
819 *minor_status = kret;
820 return GSS_S_FAILURE;
823 /* reset local seq number */
824 krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq);
826 output_token->length = outbuf.length;
827 output_token->value = outbuf.data;
830 return gsskrb5_initiator_ready(minor_status, ctx, context);
834 * gss_init_sec_context
837 OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context
838 (OM_uint32 * minor_status,
839 gss_const_cred_id_t cred_handle,
840 gss_ctx_id_t * context_handle,
841 gss_const_name_t target_name,
842 const gss_OID mech_type,
843 OM_uint32 req_flags,
844 OM_uint32 time_req,
845 const gss_channel_bindings_t input_chan_bindings,
846 const gss_buffer_t input_token,
847 gss_OID * actual_mech_type,
848 gss_buffer_t output_token,
849 OM_uint32 * ret_flags,
850 OM_uint32 * time_rec
853 krb5_context context;
854 gsskrb5_cred cred = (gsskrb5_cred)cred_handle;
855 gsskrb5_ctx ctx;
856 OM_uint32 ret;
858 GSSAPI_KRB5_INIT (&context);
860 output_token->length = 0;
861 output_token->value = NULL;
863 if (context_handle == NULL) {
864 *minor_status = 0;
865 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
868 if (ret_flags)
869 *ret_flags = 0;
870 if (time_rec)
871 *time_rec = 0;
873 if (target_name == GSS_C_NO_NAME) {
874 if (actual_mech_type)
875 *actual_mech_type = GSS_C_NO_OID;
876 *minor_status = 0;
877 return GSS_S_BAD_NAME;
880 if (mech_type != GSS_C_NO_OID &&
881 !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
882 return GSS_S_BAD_MECH;
884 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
885 OM_uint32 ret1;
887 if (*context_handle != GSS_C_NO_CONTEXT) {
888 *minor_status = 0;
889 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
892 ret1 = _gsskrb5_create_ctx(minor_status,
893 context_handle,
894 context,
895 input_chan_bindings,
896 INITIATOR_START);
897 if (ret1)
898 return ret1;
901 if (*context_handle == GSS_C_NO_CONTEXT) {
902 *minor_status = 0;
903 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
906 ctx = (gsskrb5_ctx) *context_handle;
908 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
910 again:
911 switch (ctx->state) {
912 case INITIATOR_START:
913 ret = init_auth(minor_status,
914 cred,
915 ctx,
916 context,
917 target_name,
918 mech_type,
919 req_flags,
920 time_req,
921 input_token,
922 actual_mech_type,
923 output_token,
924 ret_flags,
925 time_rec);
926 if (ret != GSS_S_COMPLETE)
927 break;
928 /* FALL THOUGH */
929 case INITIATOR_RESTART:
930 ret = init_auth_restart(minor_status,
931 cred,
932 ctx,
933 context,
934 req_flags,
935 input_chan_bindings,
936 input_token,
937 actual_mech_type,
938 output_token,
939 ret_flags,
940 time_rec);
941 break;
942 case INITIATOR_WAIT_FOR_MUTAL:
943 ret = repl_mutual(minor_status,
944 ctx,
945 context,
946 mech_type,
947 req_flags,
948 time_req,
949 input_chan_bindings,
950 input_token,
951 actual_mech_type,
952 output_token,
953 ret_flags,
954 time_rec);
955 if (ctx->state == INITIATOR_RESTART)
956 goto again;
957 break;
958 case INITIATOR_READY:
960 * If we get there, the caller have called
961 * gss_init_sec_context() one time too many.
963 _gsskrb5_set_status(EINVAL, "init_sec_context "
964 "called one time too many");
965 *minor_status = EINVAL;
966 ret = GSS_S_BAD_STATUS;
967 break;
968 default:
969 _gsskrb5_set_status(EINVAL, "init_sec_context "
970 "invalid state %d for client",
971 (int)ctx->state);
972 *minor_status = EINVAL;
973 ret = GSS_S_BAD_STATUS;
974 break;
976 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
978 /* destroy context in case of error */
979 if (GSS_ERROR(ret)) {
980 OM_uint32 min2;
981 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
984 return ret;