/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- _gsskrb5_register_acceptor_identity
- _gsskrb5i_is_cfx
- gsskrb5_acceptor_ready
- send_error_token
- gsskrb5_acceptor_start
- acceptor_wait_for_dcestyle
- _gsskrb5_accept_sec_context
1 /*
2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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.
32 */
33
34 #include "krb5/gsskrb5_locl.h"
35
36 RCSID("$Id$");
37
38 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
39 krb5_keytab _gsskrb5_keytab;
40
41 OM_uint32
42 _gsskrb5_register_acceptor_identity (const char *identity)
/* [<][>][^][v][top][bottom][index][help] */
43 {
44 krb5_context context;
45 krb5_error_code ret;
46
47 ret = _gsskrb5_init(&context);
48 if(ret)
49 return GSS_S_FAILURE;
50
51 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
52
53 if(_gsskrb5_keytab != NULL) {
54 krb5_kt_close(context, _gsskrb5_keytab);
55 _gsskrb5_keytab = NULL;
56 }
57 if (identity == NULL) {
58 ret = krb5_kt_default(context, &_gsskrb5_keytab);
59 } else {
60 char *p;
61
62 asprintf(&p, "FILE:%s", identity);
63 if(p == NULL) {
64 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
65 return GSS_S_FAILURE;
66 }
67 ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab);
68 free(p);
69 }
70 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
71 if(ret)
72 return GSS_S_FAILURE;
73 return GSS_S_COMPLETE;
74 }
75
76 void
77 _gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx)
/* [<][>][^][v][top][bottom][index][help] */
78 {
79 krb5_keyblock *key;
80 int acceptor = (ctx->more_flags & LOCAL) == 0;
81
82 *is_cfx = 0;
83
84 if (acceptor) {
85 if (ctx->auth_context->local_subkey)
86 key = ctx->auth_context->local_subkey;
87 else
88 key = ctx->auth_context->remote_subkey;
89 } else {
90 if (ctx->auth_context->remote_subkey)
91 key = ctx->auth_context->remote_subkey;
92 else
93 key = ctx->auth_context->local_subkey;
94 }
95 if (key == NULL)
96 key = ctx->auth_context->keyblock;
97
98 if (key == NULL)
99 return;
100
101 switch (key->keytype) {
102 case ETYPE_DES_CBC_CRC:
103 case ETYPE_DES_CBC_MD4:
104 case ETYPE_DES_CBC_MD5:
105 case ETYPE_DES3_CBC_MD5:
106 case ETYPE_DES3_CBC_SHA1:
107 case ETYPE_ARCFOUR_HMAC_MD5:
108 case ETYPE_ARCFOUR_HMAC_MD5_56:
109 break;
110 default :
111 *is_cfx = 1;
112 if ((acceptor && ctx->auth_context->local_subkey) ||
113 (!acceptor && ctx->auth_context->remote_subkey))
114 ctx->more_flags |= ACCEPTOR_SUBKEY;
115 break;
116 }
117 }
118
119
120 static OM_uint32
121 gsskrb5_accept_delegated_token
122 (OM_uint32 * minor_status,
123 gsskrb5_ctx ctx,
124 krb5_context context,
125 gss_cred_id_t * delegated_cred_handle
126 )
127 {
128 krb5_ccache ccache = NULL;
129 krb5_error_code kret;
130 int32_t ac_flags, ret = GSS_S_COMPLETE;
131
132 *minor_status = 0;
133
134 /* XXX Create a new delegated_cred_handle? */
135 if (delegated_cred_handle == NULL) {
136 kret = krb5_cc_default (context, &ccache);
137 } else {
138 *delegated_cred_handle = NULL;
139 kret = krb5_cc_gen_new (context, &krb5_mcc_ops, &ccache);
140 }
141 if (kret) {
142 ctx->flags &= ~GSS_C_DELEG_FLAG;
143 goto out;
144 }
145
146 kret = krb5_cc_initialize(context, ccache, ctx->source);
147 if (kret) {
148 ctx->flags &= ~GSS_C_DELEG_FLAG;
149 goto out;
150 }
151
152 krb5_auth_con_removeflags(context,
153 ctx->auth_context,
154 KRB5_AUTH_CONTEXT_DO_TIME,
155 &ac_flags);
156 kret = krb5_rd_cred2(context,
157 ctx->auth_context,
158 ccache,
159 &ctx->fwd_data);
160 krb5_auth_con_setflags(context,
161 ctx->auth_context,
162 ac_flags);
163 if (kret) {
164 ctx->flags &= ~GSS_C_DELEG_FLAG;
165 ret = GSS_S_FAILURE;
166 *minor_status = kret;
167 goto out;
168 }
169
170 if (delegated_cred_handle) {
171 gsskrb5_cred handle;
172
173 ret = _gsskrb5_import_cred(minor_status,
174 ccache,
175 NULL,
176 NULL,
177 delegated_cred_handle);
178 if (ret != GSS_S_COMPLETE)
179 goto out;
180
181 handle = (gsskrb5_cred) *delegated_cred_handle;
182
183 handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
184 krb5_cc_close(context, ccache);
185 ccache = NULL;
186 }
187
188 out:
189 if (ccache) {
190 /* Don't destroy the default cred cache */
191 if (delegated_cred_handle == NULL)
192 krb5_cc_close(context, ccache);
193 else
194 krb5_cc_destroy(context, ccache);
195 }
196 return ret;
197 }
198
199 static OM_uint32
200 gsskrb5_acceptor_ready(OM_uint32 * minor_status,
/* [<][>][^][v][top][bottom][index][help] */
201 gsskrb5_ctx ctx,
202 krb5_context context,
203 gss_cred_id_t *delegated_cred_handle)
204 {
205 OM_uint32 ret;
206 int32_t seq_number;
207 int is_cfx = 0;
208
209 krb5_auth_getremoteseqnumber (context,
210 ctx->auth_context,
211 &seq_number);
212
213 _gsskrb5i_is_cfx(ctx, &is_cfx);
214
215 ret = _gssapi_msg_order_create(minor_status,
216 &ctx->order,
217 _gssapi_msg_order_f(ctx->flags),
218 seq_number, 0, is_cfx);
219 if (ret)
220 return ret;
221
222 /*
223 * If requested, set local sequence num to remote sequence if this
224 * isn't a mutual authentication context
225 */
226 if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
227 krb5_auth_con_setlocalseqnumber(context,
228 ctx->auth_context,
229 seq_number);
230 }
231
232 /*
233 * We should handle the delegation ticket, in case it's there
234 */
235 if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
236 ret = gsskrb5_accept_delegated_token(minor_status,
237 ctx,
238 context,
239 delegated_cred_handle);
240 if (ret)
241 return ret;
242 } else {
243 /* Well, looks like it wasn't there after all */
244 ctx->flags &= ~GSS_C_DELEG_FLAG;
245 }
246
247 ctx->state = ACCEPTOR_READY;
248 ctx->more_flags |= OPEN;
249
250 return GSS_S_COMPLETE;
251 }
252
253 static OM_uint32
254 send_error_token(OM_uint32 *minor_status,
/* [<][>][^][v][top][bottom][index][help] */
255 krb5_context context,
256 krb5_error_code kret,
257 krb5_principal server,
258 krb5_data *indata,
259 gss_buffer_t output_token)
260 {
261 krb5_principal ap_req_server = NULL;
262 krb5_error_code ret;
263 krb5_data outbuf;
264
265 /* build server from request if the acceptor had not selected one */
266 if (server == NULL) {
267 AP_REQ ap_req;
268
269 ret = krb5_decode_ap_req(context, indata, &ap_req);
270 if (ret) {
271 *minor_status = ret;
272 return GSS_S_FAILURE;
273 }
274 ret = _krb5_principalname2krb5_principal(context,
275 &ap_req_server,
276 ap_req.ticket.sname,
277 ap_req.ticket.realm);
278 free_AP_REQ(&ap_req);
279 if (ret) {
280 *minor_status = ret;
281 return GSS_S_FAILURE;
282 }
283 server = ap_req_server;
284 }
285
286 ret = krb5_mk_error(context, kret, NULL, NULL, NULL,
287 server, NULL, NULL, &outbuf);
288 if (ap_req_server)
289 krb5_free_principal(context, ap_req_server);
290 if (ret) {
291 *minor_status = ret;
292 return GSS_S_FAILURE;
293 }
294
295 ret = _gsskrb5_encapsulate(minor_status,
296 &outbuf,
297 output_token,
298 "\x03\x00",
299 GSS_KRB5_MECHANISM);
300 krb5_data_free (&outbuf);
301 if (ret)
302 return ret;
303
304 *minor_status = 0;
305 return GSS_S_CONTINUE_NEEDED;
306 }
307
308
309 static OM_uint32
310 gsskrb5_acceptor_start(OM_uint32 * minor_status,
/* [<][>][^][v][top][bottom][index][help] */
311 gsskrb5_ctx ctx,
312 krb5_context context,
313 const gss_cred_id_t acceptor_cred_handle,
314 const gss_buffer_t input_token_buffer,
315 const gss_channel_bindings_t input_chan_bindings,
316 gss_name_t * src_name,
317 gss_OID * mech_type,
318 gss_buffer_t output_token,
319 OM_uint32 * ret_flags,
320 OM_uint32 * time_rec,
321 gss_cred_id_t * delegated_cred_handle)
322 {
323 krb5_error_code kret;
324 OM_uint32 ret = GSS_S_COMPLETE;
325 krb5_data indata;
326 krb5_flags ap_options;
327 krb5_keytab keytab = NULL;
328 int is_cfx = 0;
329 const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
330
331 /*
332 * We may, or may not, have an escapsulation.
333 */
334 ret = _gsskrb5_decapsulate (minor_status,
335 input_token_buffer,
336 &indata,
337 "\x01\x00",
338 GSS_KRB5_MECHANISM);
339
340 if (ret) {
341 /* Assume that there is no OID wrapping. */
342 indata.length = input_token_buffer->length;
343 indata.data = input_token_buffer->value;
344 }
345
346 /*
347 * We need to get our keytab
348 */
349 if (acceptor_cred == NULL) {
350 if (_gsskrb5_keytab != NULL)
351 keytab = _gsskrb5_keytab;
352 } else if (acceptor_cred->keytab != NULL) {
353 keytab = acceptor_cred->keytab;
354 }
355
356 /*
357 * We need to check the ticket and create the AP-REP packet
358 */
359
360 {
361 krb5_rd_req_in_ctx in = NULL;
362 krb5_rd_req_out_ctx out = NULL;
363 krb5_principal server = NULL;
364
365 if (acceptor_cred)
366 server = acceptor_cred->principal;
367
368 kret = krb5_rd_req_in_ctx_alloc(context, &in);
369 if (kret == 0)
370 kret = krb5_rd_req_in_set_keytab(context, in, keytab);
371 if (kret) {
372 if (in)
373 krb5_rd_req_in_ctx_free(context, in);
374 *minor_status = kret;
375 return GSS_S_FAILURE;
376 }
377
378 kret = krb5_rd_req_ctx(context,
379 &ctx->auth_context,
380 &indata,
381 server,
382 in, &out);
383 krb5_rd_req_in_ctx_free(context, in);
384 if (kret == KRB5KRB_AP_ERR_SKEW) {
385 /*
386 * No reply in non-MUTUAL mode, but we don't know that its
387 * non-MUTUAL mode yet, thats inside the 8003 checksum, so
388 * lets only send the error token on clock skew, that
389 * limit when send error token for non-MUTUAL.
390 */
391 return send_error_token(minor_status, context, kret,
392 server, &indata, output_token);
393 } else if (kret) {
394 *minor_status = kret;
395 return GSS_S_FAILURE;
396 }
397
398 /*
399 * we need to remember some data on the context_handle.
400 */
401 kret = krb5_rd_req_out_get_ap_req_options(context, out,
402 &ap_options);
403 if (kret == 0)
404 kret = krb5_rd_req_out_get_ticket(context, out,
405 &ctx->ticket);
406 if (kret == 0)
407 kret = krb5_rd_req_out_get_keyblock(context, out,
408 &ctx->service_keyblock);
409 ctx->lifetime = ctx->ticket->ticket.endtime;
410
411 krb5_rd_req_out_ctx_free(context, out);
412 if (kret) {
413 ret = GSS_S_FAILURE;
414 *minor_status = kret;
415 return ret;
416 }
417 }
418
419
420 /*
421 * We need to copy the principal names to the context and the
422 * calling layer.
423 */
424 kret = krb5_copy_principal(context,
425 ctx->ticket->client,
426 &ctx->source);
427 if (kret) {
428 ret = GSS_S_FAILURE;
429 *minor_status = kret;
430 }
431
432 kret = krb5_copy_principal(context,
433 ctx->ticket->server,
434 &ctx->target);
435 if (kret) {
436 ret = GSS_S_FAILURE;
437 *minor_status = kret;
438 return ret;
439 }
440
441 /*
442 * We need to setup some compat stuff, this assumes that
443 * context_handle->target is already set.
444 */
445 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
446 if (ret)
447 return ret;
448
449 if (src_name != NULL) {
450 kret = krb5_copy_principal (context,
451 ctx->ticket->client,
452 (gsskrb5_name*)src_name);
453 if (kret) {
454 ret = GSS_S_FAILURE;
455 *minor_status = kret;
456 return ret;
457 }
458 }
459
460 /*
461 * We need to get the flags out of the 8003 checksum.
462 */
463 {
464 krb5_authenticator authenticator;
465
466 kret = krb5_auth_con_getauthenticator(context,
467 ctx->auth_context,
468 &authenticator);
469 if(kret) {
470 ret = GSS_S_FAILURE;
471 *minor_status = kret;
472 return ret;
473 }
474
475 if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
476 ret = _gsskrb5_verify_8003_checksum(minor_status,
477 input_chan_bindings,
478 authenticator->cksum,
479 &ctx->flags,
480 &ctx->fwd_data);
481
482 krb5_free_authenticator(context, &authenticator);
483 if (ret) {
484 return ret;
485 }
486 } else {
487 krb5_crypto crypto;
488
489 kret = krb5_crypto_init(context,
490 ctx->auth_context->keyblock,
491 0, &crypto);
492 if(kret) {
493 krb5_free_authenticator(context, &authenticator);
494
495 ret = GSS_S_FAILURE;
496 *minor_status = kret;
497 return ret;
498 }
499
500 /*
501 * Windows accepts Samba3's use of a kerberos, rather than
502 * GSSAPI checksum here
503 */
504
505 kret = krb5_verify_checksum(context,
506 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
507 authenticator->cksum);
508 krb5_free_authenticator(context, &authenticator);
509 krb5_crypto_destroy(context, crypto);
510
511 if(kret) {
512 ret = GSS_S_BAD_SIG;
513 *minor_status = kret;
514 return ret;
515 }
516
517 /*
518 * Samba style get some flags (but not DCE-STYLE)
519 */
520 ctx->flags =
521 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
522 }
523 }
524
525 if(ctx->flags & GSS_C_MUTUAL_FLAG) {
526 krb5_data outbuf;
527 int use_subkey = 0;
528
529 _gsskrb5i_is_cfx(ctx, &is_cfx);
530
531 if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
532 use_subkey = 1;
533 } else {
534 krb5_keyblock *rkey;
535
536 /*
537 * If there is a initiator subkey, copy that to acceptor
538 * subkey to match Windows behavior
539 */
540 kret = krb5_auth_con_getremotesubkey(context,
541 ctx->auth_context,
542 &rkey);
543 if (kret == 0) {
544 kret = krb5_auth_con_setlocalsubkey(context,
545 ctx->auth_context,
546 rkey);
547 if (kret == 0)
548 use_subkey = 1;
549 krb5_free_keyblock(context, rkey);
550 }
551 }
552 if (use_subkey) {
553 ctx->more_flags |= ACCEPTOR_SUBKEY;
554 krb5_auth_con_addflags(context, ctx->auth_context,
555 KRB5_AUTH_CONTEXT_USE_SUBKEY,
556 NULL);
557 }
558
559 kret = krb5_mk_rep(context,
560 ctx->auth_context,
561 &outbuf);
562 if (kret) {
563 *minor_status = kret;
564 return GSS_S_FAILURE;
565 }
566
567 if (IS_DCE_STYLE(ctx)) {
568 output_token->length = outbuf.length;
569 output_token->value = outbuf.data;
570 } else {
571 ret = _gsskrb5_encapsulate(minor_status,
572 &outbuf,
573 output_token,
574 "\x02\x00",
575 GSS_KRB5_MECHANISM);
576 krb5_data_free (&outbuf);
577 if (ret)
578 return ret;
579 }
580 }
581
582 ctx->flags |= GSS_C_TRANS_FLAG;
583
584 /* Remember the flags */
585
586 ctx->lifetime = ctx->ticket->ticket.endtime;
587 ctx->more_flags |= OPEN;
588
589 if (mech_type)
590 *mech_type = GSS_KRB5_MECHANISM;
591
592 if (time_rec) {
593 ret = _gsskrb5_lifetime_left(minor_status,
594 context,
595 ctx->lifetime,
596 time_rec);
597 if (ret) {
598 return ret;
599 }
600 }
601
602 /*
603 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
604 * the client.
605 */
606 if (IS_DCE_STYLE(ctx)) {
607 /*
608 * Return flags to caller, but we haven't processed
609 * delgations yet
610 */
611 if (ret_flags)
612 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
613
614 ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
615 return GSS_S_CONTINUE_NEEDED;
616 }
617
618 ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
619 delegated_cred_handle);
620
621 if (ret_flags)
622 *ret_flags = ctx->flags;
623
624 return ret;
625 }
626
627 static OM_uint32
628 acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
/* [<][>][^][v][top][bottom][index][help] */
629 gsskrb5_ctx ctx,
630 krb5_context context,
631 const gss_cred_id_t acceptor_cred_handle,
632 const gss_buffer_t input_token_buffer,
633 const gss_channel_bindings_t input_chan_bindings,
634 gss_name_t * src_name,
635 gss_OID * mech_type,
636 gss_buffer_t output_token,
637 OM_uint32 * ret_flags,
638 OM_uint32 * time_rec,
639 gss_cred_id_t * delegated_cred_handle)
640 {
641 OM_uint32 ret;
642 krb5_error_code kret;
643 krb5_data inbuf;
644 int32_t r_seq_number, l_seq_number;
645
646 /*
647 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
648 */
649
650 inbuf.length = input_token_buffer->length;
651 inbuf.data = input_token_buffer->value;
652
653 /*
654 * We need to remeber the old remote seq_number, then check if the
655 * client has replied with our local seq_number, and then reset
656 * the remote seq_number to the old value
657 */
658 {
659 kret = krb5_auth_con_getlocalseqnumber(context,
660 ctx->auth_context,
661 &l_seq_number);
662 if (kret) {
663 *minor_status = kret;
664 return GSS_S_FAILURE;
665 }
666
667 kret = krb5_auth_getremoteseqnumber(context,
668 ctx->auth_context,
669 &r_seq_number);
670 if (kret) {
671 *minor_status = kret;
672 return GSS_S_FAILURE;
673 }
674
675 kret = krb5_auth_con_setremoteseqnumber(context,
676 ctx->auth_context,
677 l_seq_number);
678 if (kret) {
679 *minor_status = kret;
680 return GSS_S_FAILURE;
681 }
682 }
683
684 /*
685 * We need to verify the AP_REP, but we need to flag that this is
686 * DCE_STYLE, so don't check the timestamps this time, but put the
687 * flag DO_TIME back afterward.
688 */
689 {
690 krb5_ap_rep_enc_part *repl;
691 int32_t auth_flags;
692
693 krb5_auth_con_removeflags(context,
694 ctx->auth_context,
695 KRB5_AUTH_CONTEXT_DO_TIME,
696 &auth_flags);
697
698 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
699 if (kret) {
700 *minor_status = kret;
701 return GSS_S_FAILURE;
702 }
703 krb5_free_ap_rep_enc_part(context, repl);
704 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
705 }
706
707 /* We need to check the liftime */
708 {
709 OM_uint32 lifetime_rec;
710
711 ret = _gsskrb5_lifetime_left(minor_status,
712 context,
713 ctx->lifetime,
714 &lifetime_rec);
715 if (ret) {
716 return ret;
717 }
718 if (lifetime_rec == 0) {
719 return GSS_S_CONTEXT_EXPIRED;
720 }
721
722 if (time_rec) *time_rec = lifetime_rec;
723 }
724
725 /* We need to give the caller the flags which are in use */
726 if (ret_flags) *ret_flags = ctx->flags;
727
728 if (src_name) {
729 kret = krb5_copy_principal(context,
730 ctx->source,
731 (gsskrb5_name*)src_name);
732 if (kret) {
733 *minor_status = kret;
734 return GSS_S_FAILURE;
735 }
736 }
737
738 /*
739 * After the krb5_rd_rep() the remote and local seq_number should
740 * be the same, because the client just replies the seq_number
741 * from our AP-REP in its AP-REP, but then the client uses the
742 * seq_number from its AP-REQ for GSS_wrap()
743 */
744 {
745 int32_t tmp_r_seq_number, tmp_l_seq_number;
746
747 kret = krb5_auth_getremoteseqnumber(context,
748 ctx->auth_context,
749 &tmp_r_seq_number);
750 if (kret) {
751 *minor_status = kret;
752 return GSS_S_FAILURE;
753 }
754
755 kret = krb5_auth_con_getlocalseqnumber(context,
756 ctx->auth_context,
757 &tmp_l_seq_number);
758 if (kret) {
759
760 *minor_status = kret;
761 return GSS_S_FAILURE;
762 }
763
764 /*
765 * Here we check if the client has responsed with our local seq_number,
766 */
767 if (tmp_r_seq_number != tmp_l_seq_number) {
768 return GSS_S_UNSEQ_TOKEN;
769 }
770 }
771
772 /*
773 * We need to reset the remote seq_number, because the client will use,
774 * the old one for the GSS_wrap() calls
775 */
776 {
777 kret = krb5_auth_con_setremoteseqnumber(context,
778 ctx->auth_context,
779 r_seq_number);
780 if (kret) {
781 *minor_status = kret;
782 return GSS_S_FAILURE;
783 }
784 }
785
786 return gsskrb5_acceptor_ready(minor_status, ctx, context,
787 delegated_cred_handle);
788 }
789
790
791 OM_uint32
792 _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
/* [<][>][^][v][top][bottom][index][help] */
793 gss_ctx_id_t * context_handle,
794 const gss_cred_id_t acceptor_cred_handle,
795 const gss_buffer_t input_token_buffer,
796 const gss_channel_bindings_t input_chan_bindings,
797 gss_name_t * src_name,
798 gss_OID * mech_type,
799 gss_buffer_t output_token,
800 OM_uint32 * ret_flags,
801 OM_uint32 * time_rec,
802 gss_cred_id_t * delegated_cred_handle)
803 {
804 krb5_context context;
805 OM_uint32 ret;
806 gsskrb5_ctx ctx;
807
808 GSSAPI_KRB5_INIT(&context);
809
810 output_token->length = 0;
811 output_token->value = NULL;
812
813 if (src_name != NULL)
814 *src_name = NULL;
815 if (mech_type)
816 *mech_type = GSS_KRB5_MECHANISM;
817
818 if (*context_handle == GSS_C_NO_CONTEXT) {
819 ret = _gsskrb5_create_ctx(minor_status,
820 context_handle,
821 context,
822 input_chan_bindings,
823 ACCEPTOR_START);
824 if (ret)
825 return ret;
826 }
827
828 ctx = (gsskrb5_ctx)*context_handle;
829
830
831 /*
832 * TODO: check the channel_bindings
833 * (above just sets them to krb5 layer)
834 */
835
836 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
837
838 switch (ctx->state) {
839 case ACCEPTOR_START:
840 ret = gsskrb5_acceptor_start(minor_status,
841 ctx,
842 context,
843 acceptor_cred_handle,
844 input_token_buffer,
845 input_chan_bindings,
846 src_name,
847 mech_type,
848 output_token,
849 ret_flags,
850 time_rec,
851 delegated_cred_handle);
852 break;
853 case ACCEPTOR_WAIT_FOR_DCESTYLE:
854 ret = acceptor_wait_for_dcestyle(minor_status,
855 ctx,
856 context,
857 acceptor_cred_handle,
858 input_token_buffer,
859 input_chan_bindings,
860 src_name,
861 mech_type,
862 output_token,
863 ret_flags,
864 time_rec,
865 delegated_cred_handle);
866 break;
867 case ACCEPTOR_READY:
868 /*
869 * If we get there, the caller have called
870 * gss_accept_sec_context() one time too many.
871 */
872 ret = GSS_S_BAD_STATUS;
873 break;
874 default:
875 /* TODO: is this correct here? --metze */
876 ret = GSS_S_BAD_STATUS;
877 break;
878 }
879
880 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
881
882 if (GSS_ERROR(ret)) {
883 OM_uint32 min2;
884 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
885 }
886
887 return ret;
888 }