lib/gssapi/krb5: implement GSS_C_CHANNEL_BOUND_FLAG for gss_init_sec_context()
[heimdal.git] / lib / gssapi / krb5 / accept_sec_context.c
blob3f8e2740e2127615e4ddd29bdda47a8e95f5952b
1 /*
2 * Copyright (c) 1997 - 2006 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"
36 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
37 krb5_keytab _gsskrb5_keytab;
39 static krb5_error_code
40 validate_keytab(krb5_context context, const char *name, krb5_keytab *id)
42 krb5_error_code ret;
44 ret = krb5_kt_resolve(context, name, id);
45 if (ret)
46 return ret;
48 ret = krb5_kt_have_content(context, *id);
49 if (ret) {
50 krb5_kt_close(context, *id);
51 *id = NULL;
54 return ret;
57 OM_uint32
58 _gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity)
60 krb5_context context;
61 krb5_error_code ret;
63 *min_stat = 0;
65 ret = _gsskrb5_init(&context);
66 if(ret)
67 return GSS_S_FAILURE;
69 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
71 if(_gsskrb5_keytab != NULL) {
72 krb5_kt_close(context, _gsskrb5_keytab);
73 _gsskrb5_keytab = NULL;
75 if (identity == NULL) {
76 ret = krb5_kt_default(context, &_gsskrb5_keytab);
77 } else {
79 * First check if we can the keytab as is and if it has content...
81 ret = validate_keytab(context, identity, &_gsskrb5_keytab);
83 * if it doesn't, lets prepend FILE: and try again
85 if (ret) {
86 char *p = NULL;
87 ret = asprintf(&p, "FILE:%s", identity);
88 if(ret < 0 || p == NULL) {
89 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
90 return GSS_S_FAILURE;
92 ret = validate_keytab(context, p, &_gsskrb5_keytab);
93 free(p);
96 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
97 if(ret) {
98 *min_stat = ret;
99 return GSS_S_FAILURE;
101 return GSS_S_COMPLETE;
104 void
105 _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor)
107 krb5_keyblock *key;
109 if (acceptor) {
110 if (ctx->auth_context->local_subkey)
111 key = ctx->auth_context->local_subkey;
112 else
113 key = ctx->auth_context->remote_subkey;
114 } else {
115 if (ctx->auth_context->remote_subkey)
116 key = ctx->auth_context->remote_subkey;
117 else
118 key = ctx->auth_context->local_subkey;
120 if (key == NULL)
121 key = ctx->auth_context->keyblock;
123 if (key == NULL)
124 return;
126 switch (key->keytype) {
127 case ETYPE_DES_CBC_CRC:
128 case ETYPE_DES_CBC_MD4:
129 case ETYPE_DES_CBC_MD5:
130 case ETYPE_DES3_CBC_MD5:
131 case ETYPE_OLD_DES3_CBC_SHA1:
132 case ETYPE_DES3_CBC_SHA1:
133 case ETYPE_ARCFOUR_HMAC_MD5:
134 case ETYPE_ARCFOUR_HMAC_MD5_56:
135 break;
136 default :
137 ctx->more_flags |= IS_CFX;
139 if ((acceptor && ctx->auth_context->local_subkey) ||
140 (!acceptor && ctx->auth_context->remote_subkey))
141 ctx->more_flags |= ACCEPTOR_SUBKEY;
142 break;
144 if (ctx->crypto)
145 krb5_crypto_destroy(context, ctx->crypto);
146 /* XXX We really shouldn't ignore this; will come back to this */
147 (void) krb5_crypto_init(context, key, 0, &ctx->crypto);
151 static OM_uint32
152 gsskrb5_accept_delegated_token(OM_uint32 *minor_status,
153 gsskrb5_ctx ctx,
154 krb5_context context,
155 gss_cred_id_t *delegated_cred_handle)
157 krb5_ccache ccache = NULL;
158 krb5_error_code kret;
159 int32_t ac_flags, ret = GSS_S_COMPLETE;
160 gsskrb5_cred handle;
162 *minor_status = 0;
164 /* XXX Create a new delegated_cred_handle? */
165 if (delegated_cred_handle == NULL)
166 return GSS_S_COMPLETE;
168 *delegated_cred_handle = NULL;
169 kret = krb5_cc_resolve(context, "MEMORY:anonymous", &ccache);
170 if (kret == 0)
171 kret = krb5_cc_initialize(context, ccache, ctx->source);
172 if (kret == 0) {
173 (void) krb5_auth_con_removeflags(context,
174 ctx->auth_context,
175 KRB5_AUTH_CONTEXT_DO_TIME,
176 &ac_flags);
177 kret = krb5_rd_cred2(context,
178 ctx->auth_context,
179 ccache,
180 &ctx->fwd_data);
181 (void) krb5_auth_con_setflags(context,
182 ctx->auth_context,
183 ac_flags);
185 if (kret) {
186 ctx->flags &= ~GSS_C_DELEG_FLAG;
187 ret = GSS_S_FAILURE;
188 *minor_status = kret;
189 goto out;
192 ret = _gsskrb5_krb5_import_cred(minor_status,
193 &ccache,
194 NULL,
195 NULL,
196 delegated_cred_handle);
197 if (ret != GSS_S_COMPLETE)
198 goto out;
200 handle = (gsskrb5_cred) *delegated_cred_handle;
201 handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
204 * A root TGT is one of the form krbtgt/REALM@SAME-REALM.
206 * A destination TGT is a root TGT for the same realm as the acceptor
207 * service's realm.
209 * Normally clients delegate a root TGT for the client's realm.
211 * In some deployments clients may want to delegate destination TGTs as
212 * a form of constrained delegation: so that the destination service
213 * cannot use the delegated credential to impersonate the client
214 * principal to services in its home realm (due to KDC lineage/transit
215 * checks). In those deployments there may not even be a route back to
216 * the KDCs of the client's realm, and attempting to use a
217 * non-destination TGT might even lead to timeouts.
219 * We could simply pretend not to have obtained a credential, except
220 * that a) we don't (yet) have an app name here for the appdefault we
221 * need to check, b) the application really wants to be able to log a
222 * message about the delegated credential being no good.
224 * Thus we leave it to _gsskrb5_store_cred_into2() to decide what to do
225 * with non-destination TGTs. To do that, it needs the realm of the
226 * acceptor service, which we record here.
228 handle->destination_realm =
229 strdup(krb5_principal_get_realm(context, ctx->target));
230 if (handle->destination_realm == NULL) {
231 _gsskrb5_release_cred(minor_status, delegated_cred_handle);
232 *minor_status = krb5_enomem(context);
233 ret = GSS_S_FAILURE;
234 goto out;
237 out:
238 if (ccache) {
239 krb5_cc_close(context, ccache);
241 return ret;
244 static OM_uint32
245 gsskrb5_acceptor_ready(OM_uint32 * minor_status,
246 gsskrb5_ctx ctx,
247 krb5_context context,
248 gss_cred_id_t *delegated_cred_handle)
250 OM_uint32 ret;
251 int32_t seq_number;
252 int is_cfx = 0;
254 krb5_auth_con_getremoteseqnumber (context,
255 ctx->auth_context,
256 &seq_number);
258 _gsskrb5i_is_cfx(context, ctx, 1);
259 is_cfx = (ctx->more_flags & IS_CFX);
261 ret = _gssapi_msg_order_create(minor_status,
262 &ctx->order,
263 _gssapi_msg_order_f(ctx->flags),
264 seq_number, 0, is_cfx);
265 if (ret)
266 return ret;
269 * If requested, set local sequence num to remote sequence if this
270 * isn't a mutual authentication context
272 if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
273 krb5_auth_con_setlocalseqnumber(context,
274 ctx->auth_context,
275 seq_number);
279 * We should handle the delegation ticket, in case it's there
281 if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
282 ret = gsskrb5_accept_delegated_token(minor_status,
283 ctx,
284 context,
285 delegated_cred_handle);
286 if (ret != GSS_S_COMPLETE)
287 return ret;
288 } else {
289 /* Well, looks like it wasn't there after all */
290 ctx->flags &= ~GSS_C_DELEG_FLAG;
293 ctx->state = ACCEPTOR_READY;
294 ctx->more_flags |= OPEN;
296 return GSS_S_COMPLETE;
299 static OM_uint32
300 send_error_token(OM_uint32 *minor_status,
301 krb5_context context,
302 krb5_error_code kret,
303 krb5_principal server,
304 krb5_data *indata,
305 gss_buffer_t output_token)
307 krb5_principal ap_req_server = NULL;
308 krb5_error_code ret;
309 krb5_data outbuf;
310 /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which
311 tells windows to try again with the corrected timestamp. See
312 [MS-KILE] 2.2.1 KERB-ERROR-DATA */
313 krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") };
315 /* build server from request if the acceptor had not selected one */
316 if (server == NULL) {
317 AP_REQ ap_req;
319 ret = krb5_decode_ap_req(context, indata, &ap_req);
320 if (ret) {
321 *minor_status = ret;
322 return GSS_S_FAILURE;
324 ret = _krb5_principalname2krb5_principal(context,
325 &ap_req_server,
326 ap_req.ticket.sname,
327 ap_req.ticket.realm);
328 free_AP_REQ(&ap_req);
329 if (ret) {
330 *minor_status = ret;
331 return GSS_S_FAILURE;
333 server = ap_req_server;
336 ret = krb5_mk_error(context, kret, NULL, &e_data, NULL,
337 server, NULL, NULL, &outbuf);
338 if (ap_req_server)
339 krb5_free_principal(context, ap_req_server);
340 if (ret) {
341 *minor_status = ret;
342 return GSS_S_FAILURE;
345 ret = _gsskrb5_encapsulate(minor_status,
346 &outbuf,
347 output_token,
348 "\x03\x00",
349 GSS_KRB5_MECHANISM);
350 krb5_data_free (&outbuf);
351 if (ret)
352 return ret;
354 *minor_status = 0;
355 return GSS_S_CONTINUE_NEEDED;
359 static OM_uint32
360 gsskrb5_acceptor_start(OM_uint32 * minor_status,
361 gsskrb5_ctx ctx,
362 krb5_context context,
363 gss_const_cred_id_t acceptor_cred_handle,
364 const gss_buffer_t input_token_buffer,
365 const gss_channel_bindings_t input_chan_bindings,
366 gss_name_t * src_name,
367 gss_OID * mech_type,
368 gss_buffer_t output_token,
369 OM_uint32 * ret_flags,
370 OM_uint32 * time_rec,
371 gss_cred_id_t * delegated_cred_handle)
373 krb5_error_code kret;
374 OM_uint32 ret = GSS_S_COMPLETE;
375 krb5_data indata;
376 krb5_flags ap_options;
377 krb5_keytab keytab = NULL;
378 int is_cfx = 0;
379 int close_kt = 0;
380 const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
383 * We may, or may not, have an escapsulation.
385 ret = _gsskrb5_decapsulate (minor_status,
386 input_token_buffer,
387 &indata,
388 "\x01\x00",
389 GSS_KRB5_MECHANISM);
391 if (ret) {
392 /* Could be a raw AP-REQ (check for APPLICATION tag) */
393 if (input_token_buffer->length == 0 ||
394 ((const uint8_t *)input_token_buffer->value)[0] != 0x6E) {
395 *minor_status = ASN1_MISPLACED_FIELD;
396 return GSS_S_DEFECTIVE_TOKEN;
399 /* Assume that there is no OID wrapping. */
400 indata.length = input_token_buffer->length;
401 indata.data = input_token_buffer->value;
405 * We need to get our keytab
407 if (acceptor_cred == NULL) {
408 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
409 if (_gsskrb5_keytab != NULL) {
410 char *name = NULL;
411 kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);
412 if (kret == 0) {
413 kret = krb5_kt_resolve(context, name, &keytab);
414 krb5_xfree(name);
416 if (kret == 0)
417 close_kt = 1;
418 else
419 keytab = NULL;
421 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
422 } else if (acceptor_cred->keytab != NULL) {
423 keytab = acceptor_cred->keytab;
427 * We need to check the ticket and create the AP-REP packet
431 krb5_rd_req_in_ctx in = NULL;
432 krb5_rd_req_out_ctx out = NULL;
433 krb5_principal server = NULL;
435 if (acceptor_cred)
436 server = acceptor_cred->principal;
438 kret = krb5_rd_req_in_ctx_alloc(context, &in);
439 if (kret == 0)
440 kret = krb5_rd_req_in_set_keytab(context, in, keytab);
441 if (kret) {
442 if (in)
443 krb5_rd_req_in_ctx_free(context, in);
444 if (close_kt)
445 krb5_kt_close(context, keytab);
446 *minor_status = kret;
447 return GSS_S_FAILURE;
450 kret = krb5_rd_req_ctx(context,
451 &ctx->auth_context,
452 &indata,
453 server,
454 in, &out);
455 krb5_rd_req_in_ctx_free(context, in);
456 if (close_kt)
457 krb5_kt_close(context, keytab);
458 if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) {
460 * No reply in non-MUTUAL mode, but we don't know that its
461 * non-MUTUAL mode yet, thats inside the 8003 checksum, so
462 * lets only send the error token on clock skew, that
463 * limit when send error token for non-MUTUAL.
465 krb5_auth_con_free(context, ctx->auth_context);
466 krb5_auth_con_free(context, ctx->deleg_auth_context);
467 ctx->deleg_auth_context = NULL;
468 ctx->auth_context = NULL;
469 return send_error_token(minor_status, context, kret,
470 server, &indata, output_token);
471 } else if (kret) {
472 *minor_status = kret;
473 return GSS_S_FAILURE;
477 * we need to remember some data on the context_handle.
479 kret = krb5_rd_req_out_get_ap_req_options(context, out,
480 &ap_options);
481 if (kret == 0)
482 kret = krb5_rd_req_out_get_ticket(context, out,
483 &ctx->ticket);
484 if (kret == 0)
485 kret = krb5_rd_req_out_get_keyblock(context, out,
486 &ctx->service_keyblock);
487 ctx->endtime = ctx->ticket->ticket.endtime;
489 krb5_rd_req_out_ctx_free(context, out);
490 if (kret) {
491 ret = GSS_S_FAILURE;
492 *minor_status = kret;
493 return ret;
499 * We need to copy the principal names to the context and the
500 * calling layer.
502 kret = krb5_copy_principal(context,
503 ctx->ticket->client,
504 &ctx->source);
505 if (kret) {
506 ret = GSS_S_FAILURE;
507 *minor_status = kret;
508 return ret;
511 kret = krb5_copy_principal(context,
512 ctx->ticket->server,
513 &ctx->target);
514 if (kret) {
515 ret = GSS_S_FAILURE;
516 *minor_status = kret;
517 return ret;
521 * We need to setup some compat stuff, this assumes that
522 * context_handle->target is already set.
524 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
525 if (ret)
526 return ret;
528 if (src_name != NULL) {
529 kret = krb5_copy_principal (context,
530 ctx->ticket->client,
531 (gsskrb5_name*)src_name);
532 if (kret) {
533 ret = GSS_S_FAILURE;
534 *minor_status = kret;
535 return ret;
540 * We need to get the flags out of the 8003 checksum.
544 krb5_authenticator authenticator;
546 kret = krb5_auth_con_getauthenticator(context,
547 ctx->auth_context,
548 &authenticator);
549 if(kret) {
550 ret = GSS_S_FAILURE;
551 *minor_status = kret;
552 return ret;
555 if (authenticator->cksum != NULL
556 && authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
557 ret = _gsskrb5_verify_8003_checksum(context,
558 minor_status,
559 input_chan_bindings,
560 authenticator,
561 &ctx->flags,
562 &ctx->fwd_data);
564 if (ret) {
565 krb5_free_authenticator(context, &authenticator);
566 return ret;
568 } else {
569 if (authenticator->cksum != NULL) {
570 krb5_crypto crypto;
572 kret = krb5_crypto_init(context,
573 ctx->auth_context->keyblock,
574 0, &crypto);
575 if (kret) {
576 krb5_free_authenticator(context, &authenticator);
577 ret = GSS_S_FAILURE;
578 *minor_status = kret;
579 return ret;
583 * Windows accepts Samba3's use of a kerberos, rather than
584 * GSSAPI checksum here
587 _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
588 kret = krb5_verify_checksum(context,
589 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
590 authenticator->cksum);
591 krb5_crypto_destroy(context, crypto);
593 if (kret) {
594 krb5_free_authenticator(context, &authenticator);
595 ret = GSS_S_BAD_SIG;
596 *minor_status = kret;
597 return ret;
602 * If there is no checksum or a kerberos checksum (which Windows
603 * and Samba accept), we use the ap_options to guess the mutual
604 * flag.
607 ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
608 if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
609 ctx->flags |= GSS_C_MUTUAL_FLAG;
611 krb5_free_authenticator(context, &authenticator);
614 if(ctx->flags & GSS_C_MUTUAL_FLAG) {
615 krb5_data outbuf;
616 int use_subkey = 0;
618 _gsskrb5i_is_cfx(context, ctx, 1);
619 is_cfx = (ctx->more_flags & IS_CFX);
621 if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
622 use_subkey = 1;
623 } else {
624 krb5_keyblock *rkey;
627 * If there is a initiator subkey, copy that to acceptor
628 * subkey to match Windows behavior
630 kret = krb5_auth_con_getremotesubkey(context,
631 ctx->auth_context,
632 &rkey);
633 if (kret == 0) {
634 kret = krb5_auth_con_setlocalsubkey(context,
635 ctx->auth_context,
636 rkey);
637 if (kret == 0)
638 use_subkey = 1;
640 krb5_free_keyblock(context, rkey);
642 if (use_subkey) {
643 ctx->more_flags |= ACCEPTOR_SUBKEY;
644 krb5_auth_con_addflags(context, ctx->auth_context,
645 KRB5_AUTH_CONTEXT_USE_SUBKEY,
646 NULL);
649 kret = krb5_mk_rep(context,
650 ctx->auth_context,
651 &outbuf);
652 if (kret) {
653 *minor_status = kret;
654 return GSS_S_FAILURE;
657 if (IS_DCE_STYLE(ctx)) {
658 output_token->length = outbuf.length;
659 output_token->value = outbuf.data;
660 } else {
661 ret = _gsskrb5_encapsulate(minor_status,
662 &outbuf,
663 output_token,
664 "\x02\x00",
665 GSS_KRB5_MECHANISM);
666 krb5_data_free (&outbuf);
667 if (ret)
668 return ret;
672 ctx->flags |= GSS_C_TRANS_FLAG;
674 /* Remember the flags */
676 ctx->endtime = ctx->ticket->ticket.endtime;
677 ctx->more_flags |= OPEN;
679 if (mech_type)
680 *mech_type = GSS_KRB5_MECHANISM;
682 if (time_rec) {
683 ret = _gsskrb5_lifetime_left(minor_status,
684 context,
685 ctx->endtime,
686 time_rec);
687 if (ret) {
688 return ret;
693 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
694 * the client.
696 if (IS_DCE_STYLE(ctx)) {
698 * Return flags to caller, but we haven't processed
699 * delgations yet
701 if (ret_flags)
702 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
704 ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
705 return GSS_S_CONTINUE_NEEDED;
708 ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
709 delegated_cred_handle);
711 if (ret_flags)
712 *ret_flags = ctx->flags;
714 return ret;
717 static OM_uint32
718 acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
719 gsskrb5_ctx ctx,
720 krb5_context context,
721 gss_const_cred_id_t acceptor_cred_handle,
722 const gss_buffer_t input_token_buffer,
723 const gss_channel_bindings_t input_chan_bindings,
724 gss_name_t * src_name,
725 gss_OID * mech_type,
726 gss_buffer_t output_token,
727 OM_uint32 * ret_flags,
728 OM_uint32 * time_rec,
729 gss_cred_id_t * delegated_cred_handle)
731 OM_uint32 ret;
732 krb5_error_code kret;
733 krb5_data inbuf;
734 int32_t r_seq_number, l_seq_number;
737 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
740 inbuf.length = input_token_buffer->length;
741 inbuf.data = input_token_buffer->value;
744 * We need to remeber the old remote seq_number, then check if the
745 * client has replied with our local seq_number, and then reset
746 * the remote seq_number to the old value
749 kret = krb5_auth_con_getlocalseqnumber(context,
750 ctx->auth_context,
751 &l_seq_number);
752 if (kret) {
753 *minor_status = kret;
754 return GSS_S_FAILURE;
757 kret = krb5_auth_con_getremoteseqnumber(context,
758 ctx->auth_context,
759 &r_seq_number);
760 if (kret) {
761 *minor_status = kret;
762 return GSS_S_FAILURE;
765 kret = krb5_auth_con_setremoteseqnumber(context,
766 ctx->auth_context,
767 l_seq_number);
768 if (kret) {
769 *minor_status = kret;
770 return GSS_S_FAILURE;
775 * We need to verify the AP_REP, but we need to flag that this is
776 * DCE_STYLE, so don't check the timestamps this time, but put the
777 * flag DO_TIME back afterward.
780 krb5_ap_rep_enc_part *repl;
781 int32_t auth_flags;
783 krb5_auth_con_removeflags(context,
784 ctx->auth_context,
785 KRB5_AUTH_CONTEXT_DO_TIME,
786 &auth_flags);
788 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
789 if (kret) {
790 *minor_status = kret;
791 return GSS_S_FAILURE;
793 krb5_free_ap_rep_enc_part(context, repl);
794 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
797 /* We need to check the liftime */
799 OM_uint32 lifetime_rec;
801 ret = _gsskrb5_lifetime_left(minor_status,
802 context,
803 ctx->endtime,
804 &lifetime_rec);
805 if (ret) {
806 return ret;
808 if (lifetime_rec == 0) {
809 return GSS_S_CONTEXT_EXPIRED;
812 if (time_rec) *time_rec = lifetime_rec;
815 /* We need to give the caller the flags which are in use */
816 if (ret_flags) *ret_flags = ctx->flags;
818 if (src_name) {
819 kret = krb5_copy_principal(context,
820 ctx->source,
821 (gsskrb5_name*)src_name);
822 if (kret) {
823 *minor_status = kret;
824 return GSS_S_FAILURE;
829 * After the krb5_rd_rep() the remote and local seq_number should
830 * be the same, because the client just replies the seq_number
831 * from our AP-REP in its AP-REP, but then the client uses the
832 * seq_number from its AP-REQ for GSS_wrap()
835 int32_t tmp_r_seq_number, tmp_l_seq_number;
837 kret = krb5_auth_con_getremoteseqnumber(context,
838 ctx->auth_context,
839 &tmp_r_seq_number);
840 if (kret) {
841 *minor_status = kret;
842 return GSS_S_FAILURE;
845 kret = krb5_auth_con_getlocalseqnumber(context,
846 ctx->auth_context,
847 &tmp_l_seq_number);
848 if (kret) {
850 *minor_status = kret;
851 return GSS_S_FAILURE;
855 * Here we check if the client has responsed with our local seq_number,
857 if (tmp_r_seq_number != tmp_l_seq_number) {
858 return GSS_S_UNSEQ_TOKEN;
863 * We need to reset the remote seq_number, because the client will use,
864 * the old one for the GSS_wrap() calls
867 kret = krb5_auth_con_setremoteseqnumber(context,
868 ctx->auth_context,
869 r_seq_number);
870 if (kret) {
871 *minor_status = kret;
872 return GSS_S_FAILURE;
876 return gsskrb5_acceptor_ready(minor_status, ctx, context,
877 delegated_cred_handle);
881 OM_uint32 GSSAPI_CALLCONV
882 _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
883 gss_ctx_id_t * context_handle,
884 gss_const_cred_id_t acceptor_cred_handle,
885 const gss_buffer_t input_token_buffer,
886 const gss_channel_bindings_t input_chan_bindings,
887 gss_name_t * src_name,
888 gss_OID * mech_type,
889 gss_buffer_t output_token,
890 OM_uint32 * ret_flags,
891 OM_uint32 * time_rec,
892 gss_cred_id_t * delegated_cred_handle)
894 krb5_context context;
895 OM_uint32 ret;
896 gsskrb5_ctx ctx;
898 GSSAPI_KRB5_INIT(&context);
900 output_token->length = 0;
901 output_token->value = NULL;
903 if (src_name != NULL)
904 *src_name = NULL;
905 if (mech_type)
906 *mech_type = GSS_KRB5_MECHANISM;
908 if (*context_handle == GSS_C_NO_CONTEXT) {
909 ret = _gsskrb5_create_ctx(minor_status,
910 context_handle,
911 context,
912 input_chan_bindings,
913 ACCEPTOR_START);
914 if (ret)
915 return ret;
918 ctx = (gsskrb5_ctx)*context_handle;
922 * TODO: check the channel_bindings
923 * (above just sets them to krb5 layer)
926 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
928 switch (ctx->state) {
929 case ACCEPTOR_START:
930 ret = gsskrb5_acceptor_start(minor_status,
931 ctx,
932 context,
933 acceptor_cred_handle,
934 input_token_buffer,
935 input_chan_bindings,
936 src_name,
937 mech_type,
938 output_token,
939 ret_flags,
940 time_rec,
941 delegated_cred_handle);
942 break;
943 case ACCEPTOR_WAIT_FOR_DCESTYLE:
944 ret = acceptor_wait_for_dcestyle(minor_status,
945 ctx,
946 context,
947 acceptor_cred_handle,
948 input_token_buffer,
949 input_chan_bindings,
950 src_name,
951 mech_type,
952 output_token,
953 ret_flags,
954 time_rec,
955 delegated_cred_handle);
956 break;
957 case ACCEPTOR_READY:
959 * If we get there, the caller have called
960 * gss_accept_sec_context() one time too many.
962 ret = GSS_S_BAD_STATUS;
963 break;
964 default:
965 /* TODO: is this correct here? --metze */
966 ret = GSS_S_BAD_STATUS;
967 break;
970 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
972 if (GSS_ERROR(ret)) {
973 OM_uint32 min2;
974 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
977 return ret;