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