krb5tgs.c revision 1.1.1.1 1 /* $NetBSD: krb5tgs.c,v 1.1.1.1 2011/04/13 18:14:37 elric Exp $ */
2
3 /*
4 * Copyright (c) 1997-2008 Kungliga Tekniska Hgskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "kdc_locl.h"
37
38 /*
39 * return the realm of a krbtgt-ticket or NULL
40 */
41
42 static Realm
43 get_krbtgt_realm(const PrincipalName *p)
44 {
45 if(p->name_string.len == 2
46 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
47 return p->name_string.val[1];
48 else
49 return NULL;
50 }
51
52 /*
53 * The KDC might add a signed path to the ticket authorization data
54 * field. This is to avoid server impersonating clients and the
55 * request constrained delegation.
56 *
57 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
58 * entry of type KRB5SignedPath.
59 */
60
61 static krb5_error_code
62 find_KRB5SignedPath(krb5_context context,
63 const AuthorizationData *ad,
64 krb5_data *data)
65 {
66 AuthorizationData child;
67 krb5_error_code ret;
68 int pos;
69
70 if (ad == NULL || ad->len == 0)
71 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
72
73 pos = ad->len - 1;
74
75 if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
76 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
77
78 ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
79 ad->val[pos].ad_data.length,
80 &child,
81 NULL);
82 if (ret) {
83 krb5_set_error_message(context, ret, "Failed to decode "
84 "IF_RELEVANT with %d", ret);
85 return ret;
86 }
87
88 if (child.len != 1) {
89 free_AuthorizationData(&child);
90 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
91 }
92
93 if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
94 free_AuthorizationData(&child);
95 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
96 }
97
98 if (data)
99 ret = der_copy_octet_string(&child.val[0].ad_data, data);
100 free_AuthorizationData(&child);
101 return ret;
102 }
103
104 krb5_error_code
105 _kdc_add_KRB5SignedPath(krb5_context context,
106 krb5_kdc_configuration *config,
107 hdb_entry_ex *krbtgt,
108 krb5_enctype enctype,
109 krb5_principal client,
110 krb5_const_principal server,
111 krb5_principals principals,
112 EncTicketPart *tkt)
113 {
114 krb5_error_code ret;
115 KRB5SignedPath sp;
116 krb5_data data;
117 krb5_crypto crypto = NULL;
118 size_t size;
119
120 if (server && principals) {
121 ret = add_Principals(principals, server);
122 if (ret)
123 return ret;
124 }
125
126 {
127 KRB5SignedPathData spd;
128
129 spd.client = client;
130 spd.authtime = tkt->authtime;
131 spd.delegated = principals;
132 spd.method_data = NULL;
133
134 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
135 &spd, &size, ret);
136 if (ret)
137 return ret;
138 if (data.length != size)
139 krb5_abortx(context, "internal asn.1 encoder error");
140 }
141
142 {
143 Key *key;
144 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
145 if (ret == 0)
146 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
147 if (ret) {
148 free(data.data);
149 return ret;
150 }
151 }
152
153 /*
154 * Fill in KRB5SignedPath
155 */
156
157 sp.etype = enctype;
158 sp.delegated = principals;
159 sp.method_data = NULL;
160
161 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
162 data.data, data.length, &sp.cksum);
163 krb5_crypto_destroy(context, crypto);
164 free(data.data);
165 if (ret)
166 return ret;
167
168 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
169 free_Checksum(&sp.cksum);
170 if (ret)
171 return ret;
172 if (data.length != size)
173 krb5_abortx(context, "internal asn.1 encoder error");
174
175
176 /*
177 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
178 * authorization data field.
179 */
180
181 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
182 KRB5_AUTHDATA_SIGNTICKET, &data);
183 krb5_data_free(&data);
184
185 return ret;
186 }
187
188 static krb5_error_code
189 check_KRB5SignedPath(krb5_context context,
190 krb5_kdc_configuration *config,
191 hdb_entry_ex *krbtgt,
192 krb5_principal cp,
193 EncTicketPart *tkt,
194 krb5_principals *delegated,
195 int *signedpath)
196 {
197 krb5_error_code ret;
198 krb5_data data;
199 krb5_crypto crypto = NULL;
200
201 if (delegated)
202 *delegated = NULL;
203
204 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
205 if (ret == 0) {
206 KRB5SignedPathData spd;
207 KRB5SignedPath sp;
208 size_t size;
209
210 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
211 krb5_data_free(&data);
212 if (ret)
213 return ret;
214
215 spd.client = cp;
216 spd.authtime = tkt->authtime;
217 spd.delegated = sp.delegated;
218 spd.method_data = sp.method_data;
219
220 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
221 &spd, &size, ret);
222 if (ret) {
223 free_KRB5SignedPath(&sp);
224 return ret;
225 }
226 if (data.length != size)
227 krb5_abortx(context, "internal asn.1 encoder error");
228
229 {
230 Key *key;
231 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
232 if (ret == 0)
233 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
234 if (ret) {
235 free(data.data);
236 free_KRB5SignedPath(&sp);
237 return ret;
238 }
239 }
240 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
241 data.data, data.length,
242 &sp.cksum);
243 krb5_crypto_destroy(context, crypto);
244 free(data.data);
245 if (ret) {
246 free_KRB5SignedPath(&sp);
247 kdc_log(context, config, 5,
248 "KRB5SignedPath not signed correctly, not marking as signed");
249 return 0;
250 }
251
252 if (delegated && sp.delegated) {
253
254 *delegated = malloc(sizeof(*sp.delegated));
255 if (*delegated == NULL) {
256 free_KRB5SignedPath(&sp);
257 return ENOMEM;
258 }
259
260 ret = copy_Principals(*delegated, sp.delegated);
261 if (ret) {
262 free_KRB5SignedPath(&sp);
263 free(*delegated);
264 *delegated = NULL;
265 return ret;
266 }
267 }
268 free_KRB5SignedPath(&sp);
269
270 *signedpath = 1;
271 }
272
273 return 0;
274 }
275
276 /*
277 *
278 */
279
280 static krb5_error_code
281 check_PAC(krb5_context context,
282 krb5_kdc_configuration *config,
283 const krb5_principal client_principal,
284 hdb_entry_ex *client,
285 hdb_entry_ex *server,
286 hdb_entry_ex *krbtgt,
287 const EncryptionKey *server_key,
288 const EncryptionKey *krbtgt_check_key,
289 const EncryptionKey *krbtgt_sign_key,
290 EncTicketPart *tkt,
291 krb5_data *rspac,
292 int *signedpath)
293 {
294 AuthorizationData *ad = tkt->authorization_data;
295 unsigned i, j;
296 krb5_error_code ret;
297
298 if (ad == NULL || ad->len == 0)
299 return 0;
300
301 for (i = 0; i < ad->len; i++) {
302 AuthorizationData child;
303
304 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
305 continue;
306
307 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
308 ad->val[i].ad_data.length,
309 &child,
310 NULL);
311 if (ret) {
312 krb5_set_error_message(context, ret, "Failed to decode "
313 "IF_RELEVANT with %d", ret);
314 return ret;
315 }
316 for (j = 0; j < child.len; j++) {
317
318 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
319 int signed_pac = 0;
320 krb5_pac pac;
321
322 /* Found PAC */
323 ret = krb5_pac_parse(context,
324 child.val[j].ad_data.data,
325 child.val[j].ad_data.length,
326 &pac);
327 free_AuthorizationData(&child);
328 if (ret)
329 return ret;
330
331 ret = krb5_pac_verify(context, pac, tkt->authtime,
332 client_principal,
333 krbtgt_check_key, NULL);
334 if (ret) {
335 krb5_pac_free(context, pac);
336 return ret;
337 }
338
339 ret = _kdc_pac_verify(context, client_principal,
340 client, server, krbtgt, &pac, &signed_pac);
341 if (ret) {
342 krb5_pac_free(context, pac);
343 return ret;
344 }
345
346 /*
347 * Only re-sign PAC if we could verify it with the PAC
348 * function. The no-verify case happens when we get in
349 * a PAC from cross realm from a Windows domain and
350 * that there is no PAC verification function.
351 */
352 if (signed_pac) {
353 *signedpath = 1;
354 ret = _krb5_pac_sign(context, pac, tkt->authtime,
355 client_principal,
356 server_key, krbtgt_sign_key, rspac);
357 }
358 krb5_pac_free(context, pac);
359
360 return ret;
361 }
362 }
363 free_AuthorizationData(&child);
364 }
365 return 0;
366 }
367
368 /*
369 *
370 */
371
372 static krb5_error_code
373 check_tgs_flags(krb5_context context,
374 krb5_kdc_configuration *config,
375 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
376 {
377 KDCOptions f = b->kdc_options;
378
379 if(f.validate){
380 if(!tgt->flags.invalid || tgt->starttime == NULL){
381 kdc_log(context, config, 0,
382 "Bad request to validate ticket");
383 return KRB5KDC_ERR_BADOPTION;
384 }
385 if(*tgt->starttime > kdc_time){
386 kdc_log(context, config, 0,
387 "Early request to validate ticket");
388 return KRB5KRB_AP_ERR_TKT_NYV;
389 }
390 /* XXX tkt = tgt */
391 et->flags.invalid = 0;
392 }else if(tgt->flags.invalid){
393 kdc_log(context, config, 0,
394 "Ticket-granting ticket has INVALID flag set");
395 return KRB5KRB_AP_ERR_TKT_INVALID;
396 }
397
398 if(f.forwardable){
399 if(!tgt->flags.forwardable){
400 kdc_log(context, config, 0,
401 "Bad request for forwardable ticket");
402 return KRB5KDC_ERR_BADOPTION;
403 }
404 et->flags.forwardable = 1;
405 }
406 if(f.forwarded){
407 if(!tgt->flags.forwardable){
408 kdc_log(context, config, 0,
409 "Request to forward non-forwardable ticket");
410 return KRB5KDC_ERR_BADOPTION;
411 }
412 et->flags.forwarded = 1;
413 et->caddr = b->addresses;
414 }
415 if(tgt->flags.forwarded)
416 et->flags.forwarded = 1;
417
418 if(f.proxiable){
419 if(!tgt->flags.proxiable){
420 kdc_log(context, config, 0,
421 "Bad request for proxiable ticket");
422 return KRB5KDC_ERR_BADOPTION;
423 }
424 et->flags.proxiable = 1;
425 }
426 if(f.proxy){
427 if(!tgt->flags.proxiable){
428 kdc_log(context, config, 0,
429 "Request to proxy non-proxiable ticket");
430 return KRB5KDC_ERR_BADOPTION;
431 }
432 et->flags.proxy = 1;
433 et->caddr = b->addresses;
434 }
435 if(tgt->flags.proxy)
436 et->flags.proxy = 1;
437
438 if(f.allow_postdate){
439 if(!tgt->flags.may_postdate){
440 kdc_log(context, config, 0,
441 "Bad request for post-datable ticket");
442 return KRB5KDC_ERR_BADOPTION;
443 }
444 et->flags.may_postdate = 1;
445 }
446 if(f.postdated){
447 if(!tgt->flags.may_postdate){
448 kdc_log(context, config, 0,
449 "Bad request for postdated ticket");
450 return KRB5KDC_ERR_BADOPTION;
451 }
452 if(b->from)
453 *et->starttime = *b->from;
454 et->flags.postdated = 1;
455 et->flags.invalid = 1;
456 }else if(b->from && *b->from > kdc_time + context->max_skew){
457 kdc_log(context, config, 0, "Ticket cannot be postdated");
458 return KRB5KDC_ERR_CANNOT_POSTDATE;
459 }
460
461 if(f.renewable){
462 if(!tgt->flags.renewable || tgt->renew_till == NULL){
463 kdc_log(context, config, 0,
464 "Bad request for renewable ticket");
465 return KRB5KDC_ERR_BADOPTION;
466 }
467 et->flags.renewable = 1;
468 ALLOC(et->renew_till);
469 _kdc_fix_time(&b->rtime);
470 *et->renew_till = *b->rtime;
471 }
472 if(f.renew){
473 time_t old_life;
474 if(!tgt->flags.renewable || tgt->renew_till == NULL){
475 kdc_log(context, config, 0,
476 "Request to renew non-renewable ticket");
477 return KRB5KDC_ERR_BADOPTION;
478 }
479 old_life = tgt->endtime;
480 if(tgt->starttime)
481 old_life -= *tgt->starttime;
482 else
483 old_life -= tgt->authtime;
484 et->endtime = *et->starttime + old_life;
485 if (et->renew_till != NULL)
486 et->endtime = min(*et->renew_till, et->endtime);
487 }
488
489 #if 0
490 /* checks for excess flags */
491 if(f.request_anonymous && !config->allow_anonymous){
492 kdc_log(context, config, 0,
493 "Request for anonymous ticket");
494 return KRB5KDC_ERR_BADOPTION;
495 }
496 #endif
497 return 0;
498 }
499
500 /*
501 * Determine if constrained delegation is allowed from this client to this server
502 */
503
504 static krb5_error_code
505 check_constrained_delegation(krb5_context context,
506 krb5_kdc_configuration *config,
507 HDB *clientdb,
508 hdb_entry_ex *client,
509 krb5_const_principal server)
510 {
511 const HDB_Ext_Constrained_delegation_acl *acl;
512 krb5_error_code ret;
513 int i;
514
515 /* if client delegates to itself, that ok */
516 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
517 return 0;
518
519 if (clientdb->hdb_check_constrained_delegation) {
520 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
521 if (ret == 0)
522 return 0;
523 } else {
524 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
525 if (ret) {
526 krb5_clear_error_message(context);
527 return ret;
528 }
529
530 if (acl) {
531 for (i = 0; i < acl->len; i++) {
532 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
533 return 0;
534 }
535 }
536 ret = KRB5KDC_ERR_BADOPTION;
537 }
538 kdc_log(context, config, 0,
539 "Bad request for constrained delegation");
540 return ret;
541 }
542
543 /*
544 * Determine if s4u2self is allowed from this client to this server
545 *
546 * For example, regardless of the principal being impersonated, if the
547 * 'client' and 'server' are the same, then it's safe.
548 */
549
550 static krb5_error_code
551 check_s4u2self(krb5_context context,
552 krb5_kdc_configuration *config,
553 HDB *clientdb,
554 hdb_entry_ex *client,
555 krb5_const_principal server)
556 {
557 krb5_error_code ret;
558
559 /* if client does a s4u2self to itself, that ok */
560 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
561 return 0;
562
563 if (clientdb->hdb_check_s4u2self) {
564 ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
565 if (ret == 0)
566 return 0;
567 } else {
568 ret = KRB5KDC_ERR_BADOPTION;
569 }
570 return ret;
571 }
572
573 /*
574 *
575 */
576
577 static krb5_error_code
578 verify_flags (krb5_context context,
579 krb5_kdc_configuration *config,
580 const EncTicketPart *et,
581 const char *pstr)
582 {
583 if(et->endtime < kdc_time){
584 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
585 return KRB5KRB_AP_ERR_TKT_EXPIRED;
586 }
587 if(et->flags.invalid){
588 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
589 return KRB5KRB_AP_ERR_TKT_NYV;
590 }
591 return 0;
592 }
593
594 /*
595 *
596 */
597
598 static krb5_error_code
599 fix_transited_encoding(krb5_context context,
600 krb5_kdc_configuration *config,
601 krb5_boolean check_policy,
602 const TransitedEncoding *tr,
603 EncTicketPart *et,
604 const char *client_realm,
605 const char *server_realm,
606 const char *tgt_realm)
607 {
608 krb5_error_code ret = 0;
609 char **realms, **tmp;
610 unsigned int num_realms;
611 int i;
612
613 switch (tr->tr_type) {
614 case DOMAIN_X500_COMPRESS:
615 break;
616 case 0:
617 /*
618 * Allow empty content of type 0 because that is was Microsoft
619 * generates in their TGT.
620 */
621 if (tr->contents.length == 0)
622 break;
623 kdc_log(context, config, 0,
624 "Transited type 0 with non empty content");
625 return KRB5KDC_ERR_TRTYPE_NOSUPP;
626 default:
627 kdc_log(context, config, 0,
628 "Unknown transited type: %u", tr->tr_type);
629 return KRB5KDC_ERR_TRTYPE_NOSUPP;
630 }
631
632 ret = krb5_domain_x500_decode(context,
633 tr->contents,
634 &realms,
635 &num_realms,
636 client_realm,
637 server_realm);
638 if(ret){
639 krb5_warn(context, ret,
640 "Decoding transited encoding");
641 return ret;
642 }
643 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
644 /* not us, so add the previous realm to transited set */
645 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
646 ret = ERANGE;
647 goto free_realms;
648 }
649 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
650 if(tmp == NULL){
651 ret = ENOMEM;
652 goto free_realms;
653 }
654 realms = tmp;
655 realms[num_realms] = strdup(tgt_realm);
656 if(realms[num_realms] == NULL){
657 ret = ENOMEM;
658 goto free_realms;
659 }
660 num_realms++;
661 }
662 if(num_realms == 0) {
663 if(strcmp(client_realm, server_realm))
664 kdc_log(context, config, 0,
665 "cross-realm %s -> %s", client_realm, server_realm);
666 } else {
667 size_t l = 0;
668 char *rs;
669 for(i = 0; i < num_realms; i++)
670 l += strlen(realms[i]) + 2;
671 rs = malloc(l);
672 if(rs != NULL) {
673 *rs = '\0';
674 for(i = 0; i < num_realms; i++) {
675 if(i > 0)
676 strlcat(rs, ", ", l);
677 strlcat(rs, realms[i], l);
678 }
679 kdc_log(context, config, 0,
680 "cross-realm %s -> %s via [%s]",
681 client_realm, server_realm, rs);
682 free(rs);
683 }
684 }
685 if(check_policy) {
686 ret = krb5_check_transited(context, client_realm,
687 server_realm,
688 realms, num_realms, NULL);
689 if(ret) {
690 krb5_warn(context, ret, "cross-realm %s -> %s",
691 client_realm, server_realm);
692 goto free_realms;
693 }
694 et->flags.transited_policy_checked = 1;
695 }
696 et->transited.tr_type = DOMAIN_X500_COMPRESS;
697 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
698 if(ret)
699 krb5_warn(context, ret, "Encoding transited encoding");
700 free_realms:
701 for(i = 0; i < num_realms; i++)
702 free(realms[i]);
703 free(realms);
704 return ret;
705 }
706
707
708 static krb5_error_code
709 tgs_make_reply(krb5_context context,
710 krb5_kdc_configuration *config,
711 KDC_REQ_BODY *b,
712 krb5_const_principal tgt_name,
713 const EncTicketPart *tgt,
714 const krb5_keyblock *replykey,
715 int rk_is_subkey,
716 const EncryptionKey *serverkey,
717 const krb5_keyblock *sessionkey,
718 krb5_kvno kvno,
719 AuthorizationData *auth_data,
720 hdb_entry_ex *server,
721 krb5_principal server_principal,
722 const char *server_name,
723 hdb_entry_ex *client,
724 krb5_principal client_principal,
725 hdb_entry_ex *krbtgt,
726 krb5_enctype krbtgt_etype,
727 krb5_principals spp,
728 const krb5_data *rspac,
729 const METHOD_DATA *enc_pa_data,
730 const char **e_text,
731 krb5_data *reply)
732 {
733 KDC_REP rep;
734 EncKDCRepPart ek;
735 EncTicketPart et;
736 KDCOptions f = b->kdc_options;
737 krb5_error_code ret;
738 int is_weak = 0;
739
740 memset(&rep, 0, sizeof(rep));
741 memset(&et, 0, sizeof(et));
742 memset(&ek, 0, sizeof(ek));
743
744 rep.pvno = 5;
745 rep.msg_type = krb_tgs_rep;
746
747 et.authtime = tgt->authtime;
748 _kdc_fix_time(&b->till);
749 et.endtime = min(tgt->endtime, *b->till);
750 ALLOC(et.starttime);
751 *et.starttime = kdc_time;
752
753 ret = check_tgs_flags(context, config, b, tgt, &et);
754 if(ret)
755 goto out;
756
757 /* We should check the transited encoding if:
758 1) the request doesn't ask not to be checked
759 2) globally enforcing a check
760 3) principal requires checking
761 4) we allow non-check per-principal, but principal isn't marked as allowing this
762 5) we don't globally allow this
763 */
764
765 #define GLOBAL_FORCE_TRANSITED_CHECK \
766 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
767 #define GLOBAL_ALLOW_PER_PRINCIPAL \
768 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
769 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
770 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
771
772 /* these will consult the database in future release */
773 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
774 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
775
776 ret = fix_transited_encoding(context, config,
777 !f.disable_transited_check ||
778 GLOBAL_FORCE_TRANSITED_CHECK ||
779 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
780 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
781 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
782 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
783 &tgt->transited, &et,
784 krb5_principal_get_realm(context, client_principal),
785 krb5_principal_get_realm(context, server->entry.principal),
786 krb5_principal_get_realm(context, krbtgt->entry.principal));
787 if(ret)
788 goto out;
789
790 copy_Realm(&server_principal->realm, &rep.ticket.realm);
791 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
792 copy_Realm(&tgt_name->realm, &rep.crealm);
793 /*
794 if (f.request_anonymous)
795 _kdc_make_anonymous_principalname (&rep.cname);
796 else */
797
798 copy_PrincipalName(&tgt_name->name, &rep.cname);
799 rep.ticket.tkt_vno = 5;
800
801 ek.caddr = et.caddr;
802 if(et.caddr == NULL)
803 et.caddr = tgt->caddr;
804
805 {
806 time_t life;
807 life = et.endtime - *et.starttime;
808 if(client && client->entry.max_life)
809 life = min(life, *client->entry.max_life);
810 if(server->entry.max_life)
811 life = min(life, *server->entry.max_life);
812 et.endtime = *et.starttime + life;
813 }
814 if(f.renewable_ok && tgt->flags.renewable &&
815 et.renew_till == NULL && et.endtime < *b->till &&
816 tgt->renew_till != NULL)
817 {
818 et.flags.renewable = 1;
819 ALLOC(et.renew_till);
820 *et.renew_till = *b->till;
821 }
822 if(et.renew_till){
823 time_t renew;
824 renew = *et.renew_till - et.authtime;
825 if(client && client->entry.max_renew)
826 renew = min(renew, *client->entry.max_renew);
827 if(server->entry.max_renew)
828 renew = min(renew, *server->entry.max_renew);
829 *et.renew_till = et.authtime + renew;
830 }
831
832 if(et.renew_till){
833 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
834 *et.starttime = min(*et.starttime, *et.renew_till);
835 et.endtime = min(et.endtime, *et.renew_till);
836 }
837
838 *et.starttime = min(*et.starttime, et.endtime);
839
840 if(*et.starttime == et.endtime){
841 ret = KRB5KDC_ERR_NEVER_VALID;
842 goto out;
843 }
844 if(et.renew_till && et.endtime == *et.renew_till){
845 free(et.renew_till);
846 et.renew_till = NULL;
847 et.flags.renewable = 0;
848 }
849
850 et.flags.pre_authent = tgt->flags.pre_authent;
851 et.flags.hw_authent = tgt->flags.hw_authent;
852 et.flags.anonymous = tgt->flags.anonymous;
853 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
854
855 if(rspac->length) {
856 /*
857 * No not need to filter out the any PAC from the
858 * auth_data since it's signed by the KDC.
859 */
860 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
861 KRB5_AUTHDATA_WIN2K_PAC, rspac);
862 if (ret)
863 goto out;
864 }
865
866 if (auth_data) {
867 unsigned int i = 0;
868
869 /* XXX check authdata */
870
871 if (et.authorization_data == NULL) {
872 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
873 if (et.authorization_data == NULL) {
874 ret = ENOMEM;
875 krb5_set_error_message(context, ret, "malloc: out of memory");
876 goto out;
877 }
878 }
879 for(i = 0; i < auth_data->len ; i++) {
880 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
881 if (ret) {
882 krb5_set_error_message(context, ret, "malloc: out of memory");
883 goto out;
884 }
885 }
886
887 /* Filter out type KRB5SignedPath */
888 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
889 if (ret == 0) {
890 if (et.authorization_data->len == 1) {
891 free_AuthorizationData(et.authorization_data);
892 free(et.authorization_data);
893 et.authorization_data = NULL;
894 } else {
895 AuthorizationData *ad = et.authorization_data;
896 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
897 ad->len--;
898 }
899 }
900 }
901
902 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
903 if (ret)
904 goto out;
905 et.crealm = tgt->crealm;
906 et.cname = tgt_name->name;
907
908 ek.key = et.key;
909 /* MIT must have at least one last_req */
910 ek.last_req.len = 1;
911 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
912 if (ek.last_req.val == NULL) {
913 ret = ENOMEM;
914 goto out;
915 }
916 ek.nonce = b->nonce;
917 ek.flags = et.flags;
918 ek.authtime = et.authtime;
919 ek.starttime = et.starttime;
920 ek.endtime = et.endtime;
921 ek.renew_till = et.renew_till;
922 ek.srealm = rep.ticket.realm;
923 ek.sname = rep.ticket.sname;
924
925 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
926 et.endtime, et.renew_till);
927
928 /* Don't sign cross realm tickets, they can't be checked anyway */
929 {
930 char *r = get_krbtgt_realm(&ek.sname);
931
932 if (r == NULL || strcmp(r, ek.srealm) == 0) {
933 ret = _kdc_add_KRB5SignedPath(context,
934 config,
935 krbtgt,
936 krbtgt_etype,
937 client_principal,
938 NULL,
939 spp,
940 &et);
941 if (ret)
942 goto out;
943 }
944 }
945
946 if (enc_pa_data->len) {
947 rep.padata = calloc(1, sizeof(*rep.padata));
948 if (rep.padata == NULL) {
949 ret = ENOMEM;
950 goto out;
951 }
952 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
953 if (ret)
954 goto out;
955 }
956
957 if (krb5_enctype_valid(context, et.key.keytype) != 0
958 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
959 {
960 krb5_enctype_enable(context, et.key.keytype);
961 is_weak = 1;
962 }
963
964
965 /* It is somewhat unclear where the etype in the following
966 encryption should come from. What we have is a session
967 key in the passed tgt, and a list of preferred etypes
968 *for the new ticket*. Should we pick the best possible
969 etype, given the keytype in the tgt, or should we look
970 at the etype list here as well? What if the tgt
971 session key is DES3 and we want a ticket with a (say)
972 CAST session key. Should the DES3 etype be added to the
973 etype list, even if we don't want a session key with
974 DES3? */
975 ret = _kdc_encode_reply(context, config,
976 &rep, &et, &ek, et.key.keytype,
977 kvno,
978 serverkey, 0, replykey, rk_is_subkey,
979 e_text, reply);
980 if (is_weak)
981 krb5_enctype_disable(context, et.key.keytype);
982
983 out:
984 free_TGS_REP(&rep);
985 free_TransitedEncoding(&et.transited);
986 if(et.starttime)
987 free(et.starttime);
988 if(et.renew_till)
989 free(et.renew_till);
990 if(et.authorization_data) {
991 free_AuthorizationData(et.authorization_data);
992 free(et.authorization_data);
993 }
994 free_LastReq(&ek.last_req);
995 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
996 free_EncryptionKey(&et.key);
997 return ret;
998 }
999
1000 static krb5_error_code
1001 tgs_check_authenticator(krb5_context context,
1002 krb5_kdc_configuration *config,
1003 krb5_auth_context ac,
1004 KDC_REQ_BODY *b,
1005 const char **e_text,
1006 krb5_keyblock *key)
1007 {
1008 krb5_authenticator auth;
1009 size_t len;
1010 unsigned char *buf;
1011 size_t buf_size;
1012 krb5_error_code ret;
1013 krb5_crypto crypto;
1014
1015 krb5_auth_con_getauthenticator(context, ac, &auth);
1016 if(auth->cksum == NULL){
1017 kdc_log(context, config, 0, "No authenticator in request");
1018 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1019 goto out;
1020 }
1021 /*
1022 * according to RFC1510 it doesn't need to be keyed,
1023 * but according to the latest draft it needs to.
1024 */
1025 if (
1026 #if 0
1027 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1028 ||
1029 #endif
1030 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1031 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1032 auth->cksum->cksumtype);
1033 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1034 goto out;
1035 }
1036
1037 /* XXX should not re-encode this */
1038 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1039 if(ret){
1040 const char *msg = krb5_get_error_message(context, ret);
1041 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1042 krb5_free_error_message(context, msg);
1043 goto out;
1044 }
1045 if(buf_size != len) {
1046 free(buf);
1047 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1048 *e_text = "KDC internal error";
1049 ret = KRB5KRB_ERR_GENERIC;
1050 goto out;
1051 }
1052 ret = krb5_crypto_init(context, key, 0, &crypto);
1053 if (ret) {
1054 const char *msg = krb5_get_error_message(context, ret);
1055 free(buf);
1056 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1057 krb5_free_error_message(context, msg);
1058 goto out;
1059 }
1060 ret = krb5_verify_checksum(context,
1061 crypto,
1062 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1063 buf,
1064 len,
1065 auth->cksum);
1066 free(buf);
1067 krb5_crypto_destroy(context, crypto);
1068 if(ret){
1069 const char *msg = krb5_get_error_message(context, ret);
1070 kdc_log(context, config, 0,
1071 "Failed to verify authenticator checksum: %s", msg);
1072 krb5_free_error_message(context, msg);
1073 }
1074 out:
1075 free_Authenticator(auth);
1076 free(auth);
1077 return ret;
1078 }
1079
1080 /*
1081 *
1082 */
1083
1084 static const char *
1085 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1086 {
1087 const char *new_realm = krb5_config_get_string(context,
1088 NULL,
1089 "capaths",
1090 crealm,
1091 srealm,
1092 NULL);
1093 return new_realm;
1094 }
1095
1096
1097 static krb5_boolean
1098 need_referral(krb5_context context, krb5_kdc_configuration *config,
1099 const KDCOptions * const options, krb5_principal server,
1100 krb5_realm **realms)
1101 {
1102 const char *name;
1103
1104 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1105 return FALSE;
1106
1107 if (server->name.name_string.len == 1)
1108 name = server->name.name_string.val[0];
1109 else if (server->name.name_string.len > 1)
1110 name = server->name.name_string.val[1];
1111 else
1112 return FALSE;
1113
1114 kdc_log(context, config, 0, "Searching referral for %s", name);
1115
1116 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1117 }
1118
1119 static krb5_error_code
1120 tgs_parse_request(krb5_context context,
1121 krb5_kdc_configuration *config,
1122 KDC_REQ_BODY *b,
1123 const PA_DATA *tgs_req,
1124 hdb_entry_ex **krbtgt,
1125 krb5_enctype *krbtgt_etype,
1126 krb5_ticket **ticket,
1127 const char **e_text,
1128 const char *from,
1129 const struct sockaddr *from_addr,
1130 time_t **csec,
1131 int **cusec,
1132 AuthorizationData **auth_data,
1133 krb5_keyblock **replykey,
1134 int *rk_is_subkey)
1135 {
1136 krb5_ap_req ap_req;
1137 krb5_error_code ret;
1138 krb5_principal princ;
1139 krb5_auth_context ac = NULL;
1140 krb5_flags ap_req_options;
1141 krb5_flags verify_ap_req_flags;
1142 krb5_crypto crypto;
1143 Key *tkey;
1144 krb5_keyblock *subkey = NULL;
1145 unsigned usage;
1146
1147 *auth_data = NULL;
1148 *csec = NULL;
1149 *cusec = NULL;
1150 *replykey = NULL;
1151
1152 memset(&ap_req, 0, sizeof(ap_req));
1153 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1154 if(ret){
1155 const char *msg = krb5_get_error_message(context, ret);
1156 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1157 krb5_free_error_message(context, msg);
1158 goto out;
1159 }
1160
1161 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1162 /* XXX check for ticket.sname == req.sname */
1163 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1164 ret = KRB5KDC_ERR_POLICY; /* ? */
1165 goto out;
1166 }
1167
1168 _krb5_principalname2krb5_principal(context,
1169 &princ,
1170 ap_req.ticket.sname,
1171 ap_req.ticket.realm);
1172
1173 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
1174
1175 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1176 char *p;
1177 ret = krb5_unparse_name(context, princ, &p);
1178 if (ret != 0)
1179 p = "<unparse_name failed>";
1180 krb5_free_principal(context, princ);
1181 kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
1182 if (ret == 0)
1183 free(p);
1184 ret = HDB_ERR_NOT_FOUND_HERE;
1185 goto out;
1186 } else if(ret){
1187 const char *msg = krb5_get_error_message(context, ret);
1188 char *p;
1189 ret = krb5_unparse_name(context, princ, &p);
1190 if (ret != 0)
1191 p = "<unparse_name failed>";
1192 krb5_free_principal(context, princ);
1193 kdc_log(context, config, 0,
1194 "Ticket-granting ticket not found in database: %s", msg);
1195 krb5_free_error_message(context, msg);
1196 if (ret == 0)
1197 free(p);
1198 ret = KRB5KRB_AP_ERR_NOT_US;
1199 goto out;
1200 }
1201
1202 if(ap_req.ticket.enc_part.kvno &&
1203 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1204 char *p;
1205
1206 ret = krb5_unparse_name (context, princ, &p);
1207 krb5_free_principal(context, princ);
1208 if (ret != 0)
1209 p = "<unparse_name failed>";
1210 kdc_log(context, config, 0,
1211 "Ticket kvno = %d, DB kvno = %d (%s)",
1212 *ap_req.ticket.enc_part.kvno,
1213 (*krbtgt)->entry.kvno,
1214 p);
1215 if (ret == 0)
1216 free (p);
1217 ret = KRB5KRB_AP_ERR_BADKEYVER;
1218 goto out;
1219 }
1220
1221 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1222
1223 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1224 ap_req.ticket.enc_part.etype, &tkey);
1225 if(ret){
1226 char *str = NULL, *p = NULL;
1227
1228 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1229 krb5_unparse_name(context, princ, &p);
1230 kdc_log(context, config, 0,
1231 "No server key with enctype %s found for %s",
1232 str ? str : "<unknown enctype>",
1233 p ? p : "<unparse_name failed>");
1234 free(str);
1235 free(p);
1236 ret = KRB5KRB_AP_ERR_BADKEYVER;
1237 goto out;
1238 }
1239
1240 if (b->kdc_options.validate)
1241 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1242 else
1243 verify_ap_req_flags = 0;
1244
1245 ret = krb5_verify_ap_req2(context,
1246 &ac,
1247 &ap_req,
1248 princ,
1249 &tkey->key,
1250 verify_ap_req_flags,
1251 &ap_req_options,
1252 ticket,
1253 KRB5_KU_TGS_REQ_AUTH);
1254
1255 krb5_free_principal(context, princ);
1256 if(ret) {
1257 const char *msg = krb5_get_error_message(context, ret);
1258 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1259 krb5_free_error_message(context, msg);
1260 goto out;
1261 }
1262
1263 {
1264 krb5_authenticator auth;
1265
1266 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1267 if (ret == 0) {
1268 *csec = malloc(sizeof(**csec));
1269 if (*csec == NULL) {
1270 krb5_free_authenticator(context, &auth);
1271 kdc_log(context, config, 0, "malloc failed");
1272 goto out;
1273 }
1274 **csec = auth->ctime;
1275 *cusec = malloc(sizeof(**cusec));
1276 if (*cusec == NULL) {
1277 krb5_free_authenticator(context, &auth);
1278 kdc_log(context, config, 0, "malloc failed");
1279 goto out;
1280 }
1281 **cusec = auth->cusec;
1282 krb5_free_authenticator(context, &auth);
1283 }
1284 }
1285
1286 ret = tgs_check_authenticator(context, config,
1287 ac, b, e_text, &(*ticket)->ticket.key);
1288 if (ret) {
1289 krb5_auth_con_free(context, ac);
1290 goto out;
1291 }
1292
1293 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1294 *rk_is_subkey = 1;
1295
1296 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1297 if(ret){
1298 const char *msg = krb5_get_error_message(context, ret);
1299 krb5_auth_con_free(context, ac);
1300 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1301 krb5_free_error_message(context, msg);
1302 goto out;
1303 }
1304 if(subkey == NULL){
1305 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1306 *rk_is_subkey = 0;
1307
1308 ret = krb5_auth_con_getkey(context, ac, &subkey);
1309 if(ret) {
1310 const char *msg = krb5_get_error_message(context, ret);
1311 krb5_auth_con_free(context, ac);
1312 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1313 krb5_free_error_message(context, msg);
1314 goto out;
1315 }
1316 }
1317 if(subkey == NULL){
1318 krb5_auth_con_free(context, ac);
1319 kdc_log(context, config, 0,
1320 "Failed to get key for enc-authorization-data");
1321 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1322 goto out;
1323 }
1324
1325 *replykey = subkey;
1326
1327 if (b->enc_authorization_data) {
1328 krb5_data ad;
1329
1330 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1331 if (ret) {
1332 const char *msg = krb5_get_error_message(context, ret);
1333 krb5_auth_con_free(context, ac);
1334 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1335 krb5_free_error_message(context, msg);
1336 goto out;
1337 }
1338 ret = krb5_decrypt_EncryptedData (context,
1339 crypto,
1340 usage,
1341 b->enc_authorization_data,
1342 &ad);
1343 krb5_crypto_destroy(context, crypto);
1344 if(ret){
1345 krb5_auth_con_free(context, ac);
1346 kdc_log(context, config, 0,
1347 "Failed to decrypt enc-authorization-data");
1348 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1349 goto out;
1350 }
1351 ALLOC(*auth_data);
1352 if (*auth_data == NULL) {
1353 krb5_auth_con_free(context, ac);
1354 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1355 goto out;
1356 }
1357 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1358 if(ret){
1359 krb5_auth_con_free(context, ac);
1360 free(*auth_data);
1361 *auth_data = NULL;
1362 kdc_log(context, config, 0, "Failed to decode authorization data");
1363 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1364 goto out;
1365 }
1366 }
1367
1368 krb5_auth_con_free(context, ac);
1369
1370 out:
1371 free_AP_REQ(&ap_req);
1372
1373 return ret;
1374 }
1375
1376 static krb5_error_code
1377 build_server_referral(krb5_context context,
1378 krb5_kdc_configuration *config,
1379 krb5_crypto session,
1380 krb5_const_realm referred_realm,
1381 const PrincipalName *true_principal_name,
1382 const PrincipalName *requested_principal,
1383 krb5_data *outdata)
1384 {
1385 PA_ServerReferralData ref;
1386 krb5_error_code ret;
1387 EncryptedData ed;
1388 krb5_data data;
1389 size_t size;
1390
1391 memset(&ref, 0, sizeof(ref));
1392
1393 if (referred_realm) {
1394 ALLOC(ref.referred_realm);
1395 if (ref.referred_realm == NULL)
1396 goto eout;
1397 *ref.referred_realm = strdup(referred_realm);
1398 if (*ref.referred_realm == NULL)
1399 goto eout;
1400 }
1401 if (true_principal_name) {
1402 ALLOC(ref.true_principal_name);
1403 if (ref.true_principal_name == NULL)
1404 goto eout;
1405 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1406 if (ret)
1407 goto eout;
1408 }
1409 if (requested_principal) {
1410 ALLOC(ref.requested_principal_name);
1411 if (ref.requested_principal_name == NULL)
1412 goto eout;
1413 ret = copy_PrincipalName(requested_principal,
1414 ref.requested_principal_name);
1415 if (ret)
1416 goto eout;
1417 }
1418
1419 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1420 data.data, data.length,
1421 &ref, &size, ret);
1422 free_PA_ServerReferralData(&ref);
1423 if (ret)
1424 return ret;
1425 if (data.length != size)
1426 krb5_abortx(context, "internal asn.1 encoder error");
1427
1428 ret = krb5_encrypt_EncryptedData(context, session,
1429 KRB5_KU_PA_SERVER_REFERRAL,
1430 data.data, data.length,
1431 0 /* kvno */, &ed);
1432 free(data.data);
1433 if (ret)
1434 return ret;
1435
1436 ASN1_MALLOC_ENCODE(EncryptedData,
1437 outdata->data, outdata->length,
1438 &ed, &size, ret);
1439 free_EncryptedData(&ed);
1440 if (ret)
1441 return ret;
1442 if (outdata->length != size)
1443 krb5_abortx(context, "internal asn.1 encoder error");
1444
1445 return 0;
1446 eout:
1447 free_PA_ServerReferralData(&ref);
1448 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1449 return ENOMEM;
1450 }
1451
1452 static krb5_error_code
1453 tgs_build_reply(krb5_context context,
1454 krb5_kdc_configuration *config,
1455 KDC_REQ *req,
1456 KDC_REQ_BODY *b,
1457 hdb_entry_ex *krbtgt,
1458 krb5_enctype krbtgt_etype,
1459 const krb5_keyblock *replykey,
1460 int rk_is_subkey,
1461 krb5_ticket *ticket,
1462 krb5_data *reply,
1463 const char *from,
1464 const char **e_text,
1465 AuthorizationData **auth_data,
1466 const struct sockaddr *from_addr)
1467 {
1468 krb5_error_code ret;
1469 krb5_principal cp = NULL, sp = NULL;
1470 krb5_principal client_principal = NULL;
1471 krb5_principal krbtgt_principal = NULL;
1472 char *spn = NULL, *cpn = NULL;
1473 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1474 HDB *clientdb, *s4u2self_impersonated_clientdb;
1475 krb5_realm ref_realm = NULL;
1476 EncTicketPart *tgt = &ticket->ticket;
1477 krb5_principals spp = NULL;
1478 const EncryptionKey *ekey;
1479 krb5_keyblock sessionkey;
1480 krb5_kvno kvno;
1481 krb5_data rspac;
1482
1483 hdb_entry_ex *krbtgt_out = NULL;
1484
1485 METHOD_DATA enc_pa_data;
1486
1487 PrincipalName *s;
1488 Realm r;
1489 int nloop = 0;
1490 EncTicketPart adtkt;
1491 char opt_str[128];
1492 int signedpath = 0;
1493
1494 Key *tkey_check;
1495 Key *tkey_sign;
1496
1497 memset(&sessionkey, 0, sizeof(sessionkey));
1498 memset(&adtkt, 0, sizeof(adtkt));
1499 krb5_data_zero(&rspac);
1500 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1501
1502 s = b->sname;
1503 r = b->realm;
1504
1505 if(b->kdc_options.enc_tkt_in_skey){
1506 Ticket *t;
1507 hdb_entry_ex *uu;
1508 krb5_principal p;
1509 Key *uukey;
1510
1511 if(b->additional_tickets == NULL ||
1512 b->additional_tickets->len == 0){
1513 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1514 kdc_log(context, config, 0,
1515 "No second ticket present in request");
1516 goto out;
1517 }
1518 t = &b->additional_tickets->val[0];
1519 if(!get_krbtgt_realm(&t->sname)){
1520 kdc_log(context, config, 0,
1521 "Additional ticket is not a ticket-granting ticket");
1522 ret = KRB5KDC_ERR_POLICY;
1523 goto out;
1524 }
1525 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1526 ret = _kdc_db_fetch(context, config, p,
1527 HDB_F_GET_KRBTGT, t->enc_part.kvno,
1528 NULL, &uu);
1529 krb5_free_principal(context, p);
1530 if(ret){
1531 if (ret == HDB_ERR_NOENTRY)
1532 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1533 goto out;
1534 }
1535 ret = hdb_enctype2key(context, &uu->entry,
1536 t->enc_part.etype, &uukey);
1537 if(ret){
1538 _kdc_free_ent(context, uu);
1539 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1540 goto out;
1541 }
1542 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1543 _kdc_free_ent(context, uu);
1544 if(ret)
1545 goto out;
1546
1547 ret = verify_flags(context, config, &adtkt, spn);
1548 if (ret)
1549 goto out;
1550
1551 s = &adtkt.cname;
1552 r = adtkt.crealm;
1553 }
1554
1555 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1556 ret = krb5_unparse_name(context, sp, &spn);
1557 if (ret)
1558 goto out;
1559 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1560 ret = krb5_unparse_name(context, cp, &cpn);
1561 if (ret)
1562 goto out;
1563 unparse_flags (KDCOptions2int(b->kdc_options),
1564 asn1_KDCOptions_units(),
1565 opt_str, sizeof(opt_str));
1566 if(*opt_str)
1567 kdc_log(context, config, 0,
1568 "TGS-REQ %s from %s for %s [%s]",
1569 cpn, from, spn, opt_str);
1570 else
1571 kdc_log(context, config, 0,
1572 "TGS-REQ %s from %s for %s", cpn, from, spn);
1573
1574 /*
1575 * Fetch server
1576 */
1577
1578 server_lookup:
1579 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1580 NULL, NULL, &server);
1581
1582 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1583 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1584 goto out;
1585 } else if(ret){
1586 const char *new_rlm, *msg;
1587 Realm req_rlm;
1588 krb5_realm *realms;
1589
1590 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1591 if(nloop++ < 2) {
1592 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1593 if(new_rlm) {
1594 kdc_log(context, config, 5, "krbtgt for realm %s "
1595 "not found, trying %s",
1596 req_rlm, new_rlm);
1597 krb5_free_principal(context, sp);
1598 free(spn);
1599 krb5_make_principal(context, &sp, r,
1600 KRB5_TGS_NAME, new_rlm, NULL);
1601 ret = krb5_unparse_name(context, sp, &spn);
1602 if (ret)
1603 goto out;
1604
1605 if (ref_realm)
1606 free(ref_realm);
1607 ref_realm = strdup(new_rlm);
1608 goto server_lookup;
1609 }
1610 }
1611 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1612 if (strcmp(realms[0], sp->realm) != 0) {
1613 kdc_log(context, config, 5,
1614 "Returning a referral to realm %s for "
1615 "server %s that was not found",
1616 realms[0], spn);
1617 krb5_free_principal(context, sp);
1618 free(spn);
1619 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1620 realms[0], NULL);
1621 ret = krb5_unparse_name(context, sp, &spn);
1622 if (ret)
1623 goto out;
1624
1625 if (ref_realm)
1626 free(ref_realm);
1627 ref_realm = strdup(realms[0]);
1628
1629 krb5_free_host_realm(context, realms);
1630 goto server_lookup;
1631 }
1632 krb5_free_host_realm(context, realms);
1633 }
1634 msg = krb5_get_error_message(context, ret);
1635 kdc_log(context, config, 0,
1636 "Server not found in database: %s: %s", spn, msg);
1637 krb5_free_error_message(context, msg);
1638 if (ret == HDB_ERR_NOENTRY)
1639 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1640 goto out;
1641 }
1642
1643 /*
1644 * Select enctype, return key and kvno.
1645 */
1646
1647 {
1648 krb5_enctype etype;
1649
1650 if(b->kdc_options.enc_tkt_in_skey) {
1651 int i;
1652 ekey = &adtkt.key;
1653 for(i = 0; i < b->etype.len; i++)
1654 if (b->etype.val[i] == adtkt.key.keytype)
1655 break;
1656 if(i == b->etype.len) {
1657 kdc_log(context, config, 0,
1658 "Addition ticket have not matching etypes");
1659 krb5_clear_error_message(context);
1660 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1661 goto out;
1662 }
1663 etype = b->etype.val[i];
1664 kvno = 0;
1665 } else {
1666 Key *skey;
1667
1668 ret = _kdc_find_etype(context, server,
1669 b->etype.val, b->etype.len, &skey);
1670 if(ret) {
1671 kdc_log(context, config, 0,
1672 "Server (%s) has no support for etypes", spn);
1673 goto out;
1674 }
1675 ekey = &skey->key;
1676 etype = skey->key.keytype;
1677 kvno = server->entry.kvno;
1678 }
1679
1680 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1681 if (ret)
1682 goto out;
1683 }
1684
1685 /*
1686 * Check that service is in the same realm as the krbtgt. If it's
1687 * not the same, it's someone that is using a uni-directional trust
1688 * backward.
1689 */
1690
1691 /*
1692 * Validate authoriation data
1693 */
1694
1695 ret = hdb_enctype2key(context, &krbtgt->entry,
1696 krbtgt_etype, &tkey_check);
1697 if(ret) {
1698 kdc_log(context, config, 0,
1699 "Failed to find key for krbtgt PAC check");
1700 goto out;
1701 }
1702
1703 /* Now refetch the primary krbtgt, and get the current kvno (the
1704 * sign check may have been on an old kvno, and the server may
1705 * have been an incoming trust) */
1706 ret = krb5_make_principal(context, &krbtgt_principal,
1707 krb5_principal_get_comp_string(context,
1708 krbtgt->entry.principal,
1709 1),
1710 KRB5_TGS_NAME,
1711 krb5_principal_get_comp_string(context,
1712 krbtgt->entry.principal,
1713 1), NULL);
1714 if(ret) {
1715 kdc_log(context, config, 0,
1716 "Failed to generate krbtgt principal");
1717 goto out;
1718 }
1719
1720 ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1721 krb5_free_principal(context, krbtgt_principal);
1722 if (ret) {
1723 krb5_error_code ret2;
1724 char *tpn, *tpn2;
1725 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1726 ret2 = krb5_unparse_name(context, krbtgt->entry.principal, &tpn2);
1727 kdc_log(context, config, 0,
1728 "Request with wrong krbtgt: %s, %s not found in our database",
1729 (ret == 0) ? tpn : "<unknown>", (ret2 == 0) ? tpn2 : "<unknown>");
1730 if(ret == 0)
1731 free(tpn);
1732 if(ret2 == 0)
1733 free(tpn2);
1734 ret = KRB5KRB_AP_ERR_NOT_US;
1735 goto out;
1736 }
1737
1738 /* The first realm is the realm of the service, the second is
1739 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1740 * encrypted to. The redirection via the krbtgt_out entry allows
1741 * the DB to possibly correct the case of the realm (Samba4 does
1742 * this) before the strcmp() */
1743 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1744 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1745 char *tpn;
1746 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &tpn);
1747 kdc_log(context, config, 0,
1748 "Request with wrong krbtgt: %s",
1749 (ret == 0) ? tpn : "<unknown>");
1750 if(ret == 0)
1751 free(tpn);
1752 ret = KRB5KRB_AP_ERR_NOT_US;
1753 }
1754
1755 ret = hdb_enctype2key(context, &krbtgt_out->entry,
1756 krbtgt_etype, &tkey_sign);
1757 if(ret) {
1758 kdc_log(context, config, 0,
1759 "Failed to find key for krbtgt PAC signature");
1760 goto out;
1761 }
1762
1763 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1764 NULL, &clientdb, &client);
1765 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1766 /* This is OK, we are just trying to find out if they have
1767 * been disabled or deleted in the meantime, missing secrets
1768 * is OK */
1769 } else if(ret){
1770 const char *krbtgt_realm, *msg;
1771
1772 /*
1773 * If the client belongs to the same realm as our krbtgt, it
1774 * should exist in the local database.
1775 *
1776 */
1777
1778 krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1779
1780 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1781 if (ret == HDB_ERR_NOENTRY)
1782 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1783 kdc_log(context, config, 1, "Client no longer in database: %s",
1784 cpn);
1785 goto out;
1786 }
1787
1788 msg = krb5_get_error_message(context, ret);
1789 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1790 krb5_free_error_message(context, msg);
1791 }
1792
1793 ret = check_PAC(context, config, cp,
1794 client, server, krbtgt, ekey, &tkey_check->key, &tkey_sign->key,
1795 tgt, &rspac, &signedpath);
1796 if (ret) {
1797 const char *msg = krb5_get_error_message(context, ret);
1798 kdc_log(context, config, 0,
1799 "Verify PAC failed for %s (%s) from %s with %s",
1800 spn, cpn, from, msg);
1801 krb5_free_error_message(context, msg);
1802 goto out;
1803 }
1804
1805 /* also check the krbtgt for signature */
1806 ret = check_KRB5SignedPath(context,
1807 config,
1808 krbtgt,
1809 cp,
1810 tgt,
1811 &spp,
1812 &signedpath);
1813 if (ret) {
1814 const char *msg = krb5_get_error_message(context, ret);
1815 kdc_log(context, config, 0,
1816 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1817 spn, cpn, from, msg);
1818 krb5_free_error_message(context, msg);
1819 goto out;
1820 }
1821
1822 /*
1823 * Process request
1824 */
1825
1826 client_principal = cp;
1827
1828 if (client) {
1829 const PA_DATA *sdata;
1830 int i = 0;
1831
1832 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1833 if (sdata) {
1834 krb5_crypto crypto;
1835 krb5_data datack;
1836 PA_S4U2Self self;
1837 char *selfcpn = NULL;
1838 const char *str;
1839
1840 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1841 sdata->padata_value.length,
1842 &self, NULL);
1843 if (ret) {
1844 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1845 goto out;
1846 }
1847
1848 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1849 if (ret)
1850 goto out;
1851
1852 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1853 if (ret) {
1854 const char *msg = krb5_get_error_message(context, ret);
1855 free_PA_S4U2Self(&self);
1856 krb5_data_free(&datack);
1857 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1858 krb5_free_error_message(context, msg);
1859 goto out;
1860 }
1861
1862 ret = krb5_verify_checksum(context,
1863 crypto,
1864 KRB5_KU_OTHER_CKSUM,
1865 datack.data,
1866 datack.length,
1867 &self.cksum);
1868 krb5_data_free(&datack);
1869 krb5_crypto_destroy(context, crypto);
1870 if (ret) {
1871 const char *msg = krb5_get_error_message(context, ret);
1872 free_PA_S4U2Self(&self);
1873 kdc_log(context, config, 0,
1874 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1875 krb5_free_error_message(context, msg);
1876 goto out;
1877 }
1878
1879 ret = _krb5_principalname2krb5_principal(context,
1880 &client_principal,
1881 self.name,
1882 self.realm);
1883 free_PA_S4U2Self(&self);
1884 if (ret)
1885 goto out;
1886
1887 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1888 if (ret)
1889 goto out;
1890
1891 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1892 if(rspac.data) {
1893 krb5_pac p = NULL;
1894 krb5_data_free(&rspac);
1895 ret = _kdc_db_fetch(context, config, client_principal, HDB_F_GET_CLIENT | HDB_F_CANON,
1896 NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
1897 if (ret) {
1898 const char *msg;
1899
1900 /*
1901 * If the client belongs to the same realm as our krbtgt, it
1902 * should exist in the local database.
1903 *
1904 */
1905
1906 if (ret == HDB_ERR_NOENTRY)
1907 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1908 msg = krb5_get_error_message(context, ret);
1909 kdc_log(context, config, 1, "S2U4Self principal to impersonate %s not found in database: %s", cpn, msg);
1910 krb5_free_error_message(context, msg);
1911 goto out;
1912 }
1913 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1914 if (ret) {
1915 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1916 selfcpn);
1917 goto out;
1918 }
1919 if (p != NULL) {
1920 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1921 s4u2self_impersonated_client->entry.principal,
1922 ekey, &tkey_sign->key,
1923 &rspac);
1924 krb5_pac_free(context, p);
1925 if (ret) {
1926 kdc_log(context, config, 0, "PAC signing failed for -- %s",
1927 selfcpn);
1928 goto out;
1929 }
1930 }
1931 }
1932
1933 /*
1934 * Check that service doing the impersonating is
1935 * requesting a ticket to it-self.
1936 */
1937 ret = check_s4u2self(context, config, clientdb, client, sp);
1938 if (ret) {
1939 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1940 "to impersonate to service "
1941 "(tried for user %s to service %s)",
1942 cpn, selfcpn, spn);
1943 free(selfcpn);
1944 goto out;
1945 }
1946
1947 /*
1948 * If the service isn't trusted for authentication to
1949 * delegation, remove the forward flag.
1950 */
1951
1952 if (client->entry.flags.trusted_for_delegation) {
1953 str = "[forwardable]";
1954 } else {
1955 b->kdc_options.forwardable = 0;
1956 str = "";
1957 }
1958 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1959 "service %s %s", cpn, selfcpn, spn, str);
1960 free(selfcpn);
1961 }
1962 }
1963
1964 /*
1965 * Constrained delegation
1966 */
1967
1968 if (client != NULL
1969 && b->additional_tickets != NULL
1970 && b->additional_tickets->len != 0
1971 && b->kdc_options.enc_tkt_in_skey == 0)
1972 {
1973 int ad_signedpath = 0;
1974 Key *clientkey;
1975 Ticket *t;
1976 char *str;
1977
1978 /*
1979 * Require that the KDC have issued the service's krbtgt (not
1980 * self-issued ticket with kimpersonate(1).
1981 */
1982 if (!signedpath) {
1983 ret = KRB5KDC_ERR_BADOPTION;
1984 kdc_log(context, config, 0,
1985 "Constrained delegation done on service ticket %s/%s",
1986 cpn, spn);
1987 goto out;
1988 }
1989
1990 t = &b->additional_tickets->val[0];
1991
1992 ret = hdb_enctype2key(context, &client->entry,
1993 t->enc_part.etype, &clientkey);
1994 if(ret){
1995 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1996 goto out;
1997 }
1998
1999 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2000 if (ret) {
2001 kdc_log(context, config, 0,
2002 "failed to decrypt ticket for "
2003 "constrained delegation from %s to %s ", cpn, spn);
2004 goto out;
2005 }
2006
2007 /* check that ticket is valid */
2008 if (adtkt.flags.forwardable == 0) {
2009 kdc_log(context, config, 0,
2010 "Missing forwardable flag on ticket for "
2011 "constrained delegation from %s to %s ", cpn, spn);
2012 ret = KRB5KDC_ERR_BADOPTION;
2013 goto out;
2014 }
2015
2016 ret = check_constrained_delegation(context, config, clientdb,
2017 client, sp);
2018 if (ret) {
2019 kdc_log(context, config, 0,
2020 "constrained delegation from %s to %s not allowed",
2021 cpn, spn);
2022 goto out;
2023 }
2024
2025 ret = _krb5_principalname2krb5_principal(context,
2026 &client_principal,
2027 adtkt.cname,
2028 adtkt.crealm);
2029 if (ret)
2030 goto out;
2031
2032 ret = krb5_unparse_name(context, client_principal, &str);
2033 if (ret)
2034 goto out;
2035
2036 ret = verify_flags(context, config, &adtkt, str);
2037 if (ret) {
2038 free(str);
2039 goto out;
2040 }
2041
2042 /*
2043 * Check that the KDC issued the user's ticket.
2044 */
2045 ret = check_KRB5SignedPath(context,
2046 config,
2047 krbtgt,
2048 cp,
2049 &adtkt,
2050 NULL,
2051 &ad_signedpath);
2052 if (ret == 0 && !ad_signedpath)
2053 ret = KRB5KDC_ERR_BADOPTION;
2054 if (ret) {
2055 const char *msg = krb5_get_error_message(context, ret);
2056 kdc_log(context, config, 0,
2057 "KRB5SignedPath check from service %s failed "
2058 "for delegation to %s for client %s "
2059 "from %s failed with %s",
2060 spn, str, cpn, from, msg);
2061 krb5_free_error_message(context, msg);
2062 free(str);
2063 goto out;
2064 }
2065
2066 kdc_log(context, config, 0, "constrained delegation for %s "
2067 "from %s to %s", str, cpn, spn);
2068 free(str);
2069 }
2070
2071 /*
2072 * Check flags
2073 */
2074
2075 ret = kdc_check_flags(context, config,
2076 client, cpn,
2077 server, spn,
2078 FALSE);
2079 if(ret)
2080 goto out;
2081
2082 if((b->kdc_options.validate || b->kdc_options.renew) &&
2083 !krb5_principal_compare(context,
2084 krbtgt->entry.principal,
2085 server->entry.principal)){
2086 kdc_log(context, config, 0, "Inconsistent request.");
2087 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2088 goto out;
2089 }
2090
2091 /* check for valid set of addresses */
2092 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2093 ret = KRB5KRB_AP_ERR_BADADDR;
2094 kdc_log(context, config, 0, "Request from wrong address");
2095 goto out;
2096 }
2097
2098 /*
2099 * If this is an referral, add server referral data to the
2100 * auth_data reply .
2101 */
2102 if (ref_realm) {
2103 PA_DATA pa;
2104 krb5_crypto crypto;
2105
2106 kdc_log(context, config, 0,
2107 "Adding server referral to %s", ref_realm);
2108
2109 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2110 if (ret)
2111 goto out;
2112
2113 ret = build_server_referral(context, config, crypto, ref_realm,
2114 NULL, s, &pa.padata_value);
2115 krb5_crypto_destroy(context, crypto);
2116 if (ret) {
2117 kdc_log(context, config, 0,
2118 "Failed building server referral");
2119 goto out;
2120 }
2121 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2122
2123 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2124 krb5_data_free(&pa.padata_value);
2125 if (ret) {
2126 kdc_log(context, config, 0,
2127 "Add server referral METHOD-DATA failed");
2128 goto out;
2129 }
2130 }
2131
2132 /*
2133 *
2134 */
2135
2136 ret = tgs_make_reply(context,
2137 config,
2138 b,
2139 client_principal,
2140 tgt,
2141 replykey,
2142 rk_is_subkey,
2143 ekey,
2144 &sessionkey,
2145 kvno,
2146 *auth_data,
2147 server,
2148 sp,
2149 spn,
2150 client,
2151 cp,
2152 krbtgt_out,
2153 krbtgt_etype,
2154 spp,
2155 &rspac,
2156 &enc_pa_data,
2157 e_text,
2158 reply);
2159
2160 out:
2161 free(spn);
2162 free(cpn);
2163
2164 krb5_data_free(&rspac);
2165 krb5_free_keyblock_contents(context, &sessionkey);
2166 if(krbtgt_out)
2167 _kdc_free_ent(context, krbtgt_out);
2168 if(server)
2169 _kdc_free_ent(context, server);
2170 if(client)
2171 _kdc_free_ent(context, client);
2172 if(s4u2self_impersonated_client)
2173 _kdc_free_ent(context, s4u2self_impersonated_client);
2174
2175 if (client_principal && client_principal != cp)
2176 krb5_free_principal(context, client_principal);
2177 if (cp)
2178 krb5_free_principal(context, cp);
2179 if (sp)
2180 krb5_free_principal(context, sp);
2181 if (ref_realm)
2182 free(ref_realm);
2183 free_METHOD_DATA(&enc_pa_data);
2184
2185 free_EncTicketPart(&adtkt);
2186
2187 return ret;
2188 }
2189
2190 /*
2191 *
2192 */
2193
2194 krb5_error_code
2195 _kdc_tgs_rep(krb5_context context,
2196 krb5_kdc_configuration *config,
2197 KDC_REQ *req,
2198 krb5_data *data,
2199 const char *from,
2200 struct sockaddr *from_addr,
2201 int datagram_reply)
2202 {
2203 AuthorizationData *auth_data = NULL;
2204 krb5_error_code ret;
2205 int i = 0;
2206 const PA_DATA *tgs_req;
2207
2208 hdb_entry_ex *krbtgt = NULL;
2209 krb5_ticket *ticket = NULL;
2210 const char *e_text = NULL;
2211 krb5_enctype krbtgt_etype = ETYPE_NULL;
2212
2213 krb5_keyblock *replykey = NULL;
2214 int rk_is_subkey = 0;
2215 time_t *csec = NULL;
2216 int *cusec = NULL;
2217
2218 if(req->padata == NULL){
2219 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2220 kdc_log(context, config, 0,
2221 "TGS-REQ from %s without PA-DATA", from);
2222 goto out;
2223 }
2224
2225 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2226
2227 if(tgs_req == NULL){
2228 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2229
2230 kdc_log(context, config, 0,
2231 "TGS-REQ from %s without PA-TGS-REQ", from);
2232 goto out;
2233 }
2234 ret = tgs_parse_request(context, config,
2235 &req->req_body, tgs_req,
2236 &krbtgt,
2237 &krbtgt_etype,
2238 &ticket,
2239 &e_text,
2240 from, from_addr,
2241 &csec, &cusec,
2242 &auth_data,
2243 &replykey,
2244 &rk_is_subkey);
2245 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2246 /* kdc_log() is called in tgs_parse_request() */
2247 goto out;
2248 }
2249 if (ret) {
2250 kdc_log(context, config, 0,
2251 "Failed parsing TGS-REQ from %s", from);
2252 goto out;
2253 }
2254
2255 ret = tgs_build_reply(context,
2256 config,
2257 req,
2258 &req->req_body,
2259 krbtgt,
2260 krbtgt_etype,
2261 replykey,
2262 rk_is_subkey,
2263 ticket,
2264 data,
2265 from,
2266 &e_text,
2267 &auth_data,
2268 from_addr);
2269 if (ret) {
2270 kdc_log(context, config, 0,
2271 "Failed building TGS-REP to %s", from);
2272 goto out;
2273 }
2274
2275 /* */
2276 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2277 krb5_data_free(data);
2278 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2279 e_text = "Reply packet too large";
2280 }
2281
2282 out:
2283 if (replykey)
2284 krb5_free_keyblock(context, replykey);
2285 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2286 krb5_mk_error(context,
2287 ret,
2288 NULL,
2289 NULL,
2290 NULL,
2291 NULL,
2292 csec,
2293 cusec,
2294 data);
2295 ret = 0;
2296 }
2297 free(csec);
2298 free(cusec);
2299 if (ticket)
2300 krb5_free_ticket(context, ticket);
2301 if(krbtgt)
2302 _kdc_free_ent(context, krbtgt);
2303
2304 if (auth_data) {
2305 free_AuthorizationData(auth_data);
2306 free(auth_data);
2307 }
2308
2309 return ret;
2310 }
2311