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