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