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