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