1 /*
2 * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "kdc_locl.h"
35
36 RCSID("$Id: krb5tgs.c,v 1.16 2006/10/22 15:54:37 lha Exp $");
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_string(context, "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 server,KRB5SignedPathPrincipals * 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 server,
110 KRB5SignedPathPrincipals *principals,
111 EncTicketPart *tkt)
112 {
113 krb5_error_code ret;
114 KRB5SignedPath sp;
115 krb5_data data;
116 krb5_crypto crypto = NULL;
117 size_t size;
118
119 if (server && principals) {
120 ret = add_KRB5SignedPathPrincipals(principals, server);
121 if (ret)
122 goto out;
123 }
124
125 {
126 KRB5SignedPathData spd;
127
128 spd.encticket = *tkt;
129 spd.delegated = principals;
130
131 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
132 &spd, &size, ret);
133 if (ret)
134 goto out;
135 if (data.length != size)
136 krb5_abortx(context, "internal asn.1 encoder error");
137 }
138
139 {
140 Key *key;
141 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
142 if (ret == 0)
143 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
144 if (ret) {
145 free(data.data);
146 return ret;
147 }
148 }
149
150 /*
151 * Fill in KRB5SignedPath
152 */
153
154 sp.etype = enctype;
155 sp.delegated = principals;
156
157 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
158 data.data, data.length, &sp.cksum);
159 krb5_crypto_destroy(context, crypto);
160 free(data.data);
161 if (ret)
162 goto out;
163
164 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
165 free_Checksum(&sp.cksum);
166 if (ret)
167 goto out;
168 if (data.length != size)
169 krb5_abortx(context, "internal asn.1 encoder error");
170
171
172 /*
173 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
174 * authorization data field.
175 */
176
177 if (tkt->authorization_data == NULL) {
178 tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
179 if (tkt->authorization_data == NULL) {
180 ret = ENOMEM;
181 goto out;
182 }
183 }
184
185 /* add the entry to the last element */
186 {
187 AuthorizationData ad = { 0, NULL };
188 AuthorizationDataElement ade;
189
190 ade.ad_type = KRB5_AUTHDATA_SIGNTICKET;
191 ade.ad_data = data;
192
193 ret = add_AuthorizationData(&ad, &ade);
194 krb5_data_free(&data);
195 if (ret)
196 return ret;
197
198 ASN1_MALLOC_ENCODE(AuthorizationData, data.data, data.length,
199 &ad, &size, ret);
200 free_AuthorizationData(&ad);
201 if (ret)
202 return ret;
203 if (data.length != size)
204 krb5_abortx(context, "internal asn.1 encoder error");
205
206 ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
207 ade.ad_data = data;
208
209 ret = add_AuthorizationData(tkt->authorization_data, &ade);
210 krb5_data_free(&data);
211 if (ret)
212 return ret;
213 }
214
215 out:
216 return 0;
217 }
218
219 static krb5_error_code
check_KRB5SignedPath(krb5_context context,krb5_kdc_configuration * config,hdb_entry_ex * krbtgt,EncTicketPart * tkt,KRB5SignedPathPrincipals ** delegated,int require_signedpath)220 check_KRB5SignedPath(krb5_context context,
221 krb5_kdc_configuration *config,
222 hdb_entry_ex *krbtgt,
223 EncTicketPart *tkt,
224 KRB5SignedPathPrincipals **delegated,
225 int require_signedpath)
226 {
227 krb5_error_code ret;
228 krb5_data data;
229 krb5_crypto crypto = NULL;
230
231 *delegated = NULL;
232
233 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
234 if (ret == 0) {
235 KRB5SignedPathData spd;
236 KRB5SignedPath sp;
237 AuthorizationData *ad;
238 size_t size;
239
240 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
241 krb5_data_free(&data);
242 if (ret)
243 return ret;
244
245 spd.encticket = *tkt;
246 /* the KRB5SignedPath is the last entry */
247 ad = spd.encticket.authorization_data;
248 if (--ad->len == 0)
249 spd.encticket.authorization_data = NULL;
250 spd.delegated = sp.delegated;
251
252 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
253 &spd, &size, ret);
254 ad->len++;
255 spd.encticket.authorization_data = ad;
256 if (ret) {
257 free_KRB5SignedPath(&sp);
258 return ret;
259 }
260 if (data.length != size)
261 krb5_abortx(context, "internal asn.1 encoder error");
262
263 {
264 Key *key;
265 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
266 if (ret == 0)
267 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
268 if (ret) {
269 free(data.data);
270 free_KRB5SignedPath(&sp);
271 return ret;
272 }
273 }
274 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
275 data.data, data.length,
276 &sp.cksum);
277 krb5_crypto_destroy(context, crypto);
278 free(data.data);
279 if (ret) {
280 free_KRB5SignedPath(&sp);
281 return ret;
282 }
283
284 if (sp.delegated) {
285
286 *delegated = malloc(sizeof(*sp.delegated));
287 if (*delegated == NULL) {
288 free_KRB5SignedPath(&sp);
289 return ENOMEM;
290 }
291
292 ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated);
293 if (ret) {
294 free_KRB5SignedPath(&sp);
295 free(*delegated);
296 *delegated = NULL;
297 return ret;
298 }
299 }
300 free_KRB5SignedPath(&sp);
301
302 } else {
303 if (require_signedpath)
304 return KRB5KDC_ERR_BADOPTION;
305 }
306
307 return 0;
308 }
309
310
311 /*
312 *
313 */
314
315 static krb5_error_code
check_tgs_flags(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,const EncTicketPart * tgt,EncTicketPart * et)316 check_tgs_flags(krb5_context context,
317 krb5_kdc_configuration *config,
318 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
319 {
320 KDCOptions f = b->kdc_options;
321
322 if(f.validate){
323 if(!tgt->flags.invalid || tgt->starttime == NULL){
324 kdc_log(context, config, 0,
325 "Bad request to validate ticket");
326 return KRB5KDC_ERR_BADOPTION;
327 }
328 if(*tgt->starttime > kdc_time){
329 kdc_log(context, config, 0,
330 "Early request to validate ticket");
331 return KRB5KRB_AP_ERR_TKT_NYV;
332 }
333 /* XXX tkt = tgt */
334 et->flags.invalid = 0;
335 }else if(tgt->flags.invalid){
336 kdc_log(context, config, 0,
337 "Ticket-granting ticket has INVALID flag set");
338 return KRB5KRB_AP_ERR_TKT_INVALID;
339 }
340
341 if(f.forwardable){
342 if(!tgt->flags.forwardable){
343 kdc_log(context, config, 0,
344 "Bad request for forwardable ticket");
345 return KRB5KDC_ERR_BADOPTION;
346 }
347 et->flags.forwardable = 1;
348 }
349 if(f.forwarded){
350 if(!tgt->flags.forwardable){
351 kdc_log(context, config, 0,
352 "Request to forward non-forwardable ticket");
353 return KRB5KDC_ERR_BADOPTION;
354 }
355 et->flags.forwarded = 1;
356 et->caddr = b->addresses;
357 }
358 if(tgt->flags.forwarded)
359 et->flags.forwarded = 1;
360
361 if(f.proxiable){
362 if(!tgt->flags.proxiable){
363 kdc_log(context, config, 0,
364 "Bad request for proxiable ticket");
365 return KRB5KDC_ERR_BADOPTION;
366 }
367 et->flags.proxiable = 1;
368 }
369 if(f.proxy){
370 if(!tgt->flags.proxiable){
371 kdc_log(context, config, 0,
372 "Request to proxy non-proxiable ticket");
373 return KRB5KDC_ERR_BADOPTION;
374 }
375 et->flags.proxy = 1;
376 et->caddr = b->addresses;
377 }
378 if(tgt->flags.proxy)
379 et->flags.proxy = 1;
380
381 if(f.allow_postdate){
382 if(!tgt->flags.may_postdate){
383 kdc_log(context, config, 0,
384 "Bad request for post-datable ticket");
385 return KRB5KDC_ERR_BADOPTION;
386 }
387 et->flags.may_postdate = 1;
388 }
389 if(f.postdated){
390 if(!tgt->flags.may_postdate){
391 kdc_log(context, config, 0,
392 "Bad request for postdated ticket");
393 return KRB5KDC_ERR_BADOPTION;
394 }
395 if(b->from)
396 *et->starttime = *b->from;
397 et->flags.postdated = 1;
398 et->flags.invalid = 1;
399 }else if(b->from && *b->from > kdc_time + context->max_skew){
400 kdc_log(context, config, 0, "Ticket cannot be postdated");
401 return KRB5KDC_ERR_CANNOT_POSTDATE;
402 }
403
404 if(f.renewable){
405 if(!tgt->flags.renewable){
406 kdc_log(context, config, 0,
407 "Bad request for renewable ticket");
408 return KRB5KDC_ERR_BADOPTION;
409 }
410 et->flags.renewable = 1;
411 ALLOC(et->renew_till);
412 _kdc_fix_time(&b->rtime);
413 *et->renew_till = *b->rtime;
414 }
415 if(f.renew){
416 time_t old_life;
417 if(!tgt->flags.renewable || tgt->renew_till == NULL){
418 kdc_log(context, config, 0,
419 "Request to renew non-renewable ticket");
420 return KRB5KDC_ERR_BADOPTION;
421 }
422 old_life = tgt->endtime;
423 if(tgt->starttime)
424 old_life -= *tgt->starttime;
425 else
426 old_life -= tgt->authtime;
427 et->endtime = *et->starttime + old_life;
428 if (et->renew_till != NULL)
429 et->endtime = min(*et->renew_till, et->endtime);
430 }
431
432 /* checks for excess flags */
433 if(f.request_anonymous && !config->allow_anonymous){
434 kdc_log(context, config, 0,
435 "Request for anonymous ticket");
436 return KRB5KDC_ERR_BADOPTION;
437 }
438 return 0;
439 }
440
441 /*
442 *
443 */
444
445 static krb5_error_code
check_constrained_delegation(krb5_context context,krb5_kdc_configuration * config,hdb_entry_ex * client,krb5_const_principal server)446 check_constrained_delegation(krb5_context context,
447 krb5_kdc_configuration *config,
448 hdb_entry_ex *client,
449 krb5_const_principal server)
450 {
451 const HDB_Ext_Constrained_delegation_acl *acl;
452 krb5_error_code ret;
453 int i;
454
455 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
456 if (ret) {
457 krb5_clear_error_string(context);
458 return ret;
459 }
460
461 if (acl) {
462 for (i = 0; i < acl->len; i++) {
463 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
464 return 0;
465 }
466 }
467 kdc_log(context, config, 0,
468 "Bad request for constrained delegation");
469 return KRB5KDC_ERR_BADOPTION;
470 }
471
472 /*
473 *
474 */
475
476 static krb5_error_code
verify_flags(krb5_context context,krb5_kdc_configuration * config,const EncTicketPart * et,const char * pstr)477 verify_flags (krb5_context context,
478 krb5_kdc_configuration *config,
479 const EncTicketPart *et,
480 const char *pstr)
481 {
482 if(et->endtime < kdc_time){
483 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
484 return KRB5KRB_AP_ERR_TKT_EXPIRED;
485 }
486 if(et->flags.invalid){
487 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
488 return KRB5KRB_AP_ERR_TKT_NYV;
489 }
490 return 0;
491 }
492
493 /*
494 *
495 */
496
497 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)498 fix_transited_encoding(krb5_context context,
499 krb5_kdc_configuration *config,
500 krb5_boolean check_policy,
501 const TransitedEncoding *tr,
502 EncTicketPart *et,
503 const char *client_realm,
504 const char *server_realm,
505 const char *tgt_realm)
506 {
507 krb5_error_code ret = 0;
508 char **realms, **tmp;
509 int num_realms;
510 int i;
511
512 switch (tr->tr_type) {
513 case DOMAIN_X500_COMPRESS:
514 break;
515 case 0:
516 /*
517 * Allow empty content of type 0 because that is was Microsoft
518 * generates in their TGT.
519 */
520 if (tr->contents.length == 0)
521 break;
522 kdc_log(context, config, 0,
523 "Transited type 0 with non empty content");
524 return KRB5KDC_ERR_TRTYPE_NOSUPP;
525 default:
526 kdc_log(context, config, 0,
527 "Unknown transited type: %u", tr->tr_type);
528 return KRB5KDC_ERR_TRTYPE_NOSUPP;
529 }
530
531 ret = krb5_domain_x500_decode(context,
532 tr->contents,
533 &realms,
534 &num_realms,
535 client_realm,
536 server_realm);
537 if(ret){
538 krb5_warn(context, ret,
539 "Decoding transited encoding");
540 return ret;
541 }
542 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
543 /* not us, so add the previous realm to transited set */
544 if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
545 ret = ERANGE;
546 goto free_realms;
547 }
548 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
549 if(tmp == NULL){
550 ret = ENOMEM;
551 goto free_realms;
552 }
553 realms = tmp;
554 realms[num_realms] = strdup(tgt_realm);
555 if(realms[num_realms] == NULL){
556 ret = ENOMEM;
557 goto free_realms;
558 }
559 num_realms++;
560 }
561 if(num_realms == 0) {
562 if(strcmp(client_realm, server_realm))
563 kdc_log(context, config, 0,
564 "cross-realm %s -> %s", client_realm, server_realm);
565 } else {
566 size_t l = 0;
567 char *rs;
568 for(i = 0; i < num_realms; i++)
569 l += strlen(realms[i]) + 2;
570 rs = malloc(l);
571 if(rs != NULL) {
572 *rs = '\0';
573 for(i = 0; i < num_realms; i++) {
574 if(i > 0)
575 strlcat(rs, ", ", l);
576 strlcat(rs, realms[i], l);
577 }
578 kdc_log(context, config, 0,
579 "cross-realm %s -> %s via [%s]",
580 client_realm, server_realm, rs);
581 free(rs);
582 }
583 }
584 if(check_policy) {
585 ret = krb5_check_transited(context, client_realm,
586 server_realm,
587 realms, num_realms, NULL);
588 if(ret) {
589 krb5_warn(context, ret, "cross-realm %s -> %s",
590 client_realm, server_realm);
591 goto free_realms;
592 }
593 et->flags.transited_policy_checked = 1;
594 }
595 et->transited.tr_type = DOMAIN_X500_COMPRESS;
596 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
597 if(ret)
598 krb5_warn(context, ret, "Encoding transited encoding");
599 free_realms:
600 for(i = 0; i < num_realms; i++)
601 free(realms[i]);
602 free(realms);
603 return ret;
604 }
605
606
607 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 EncTicketPart * adtkt,AuthorizationData * auth_data,krb5_ticket * tgs_ticket,hdb_entry_ex * server,const char * server_name,hdb_entry_ex * client,krb5_principal client_principal,hdb_entry_ex * krbtgt,krb5_enctype krbtgt_etype,KRB5SignedPathPrincipals * spp,EncryptionKey * tgtkey,const char ** e_text,krb5_data * reply)608 tgs_make_reply(krb5_context context,
609 krb5_kdc_configuration *config,
610 KDC_REQ_BODY *b,
611 krb5_const_principal tgt_name,
612 const EncTicketPart *tgt,
613 const EncTicketPart *adtkt,
614 AuthorizationData *auth_data,
615 krb5_ticket *tgs_ticket,
616 hdb_entry_ex *server,
617 const char *server_name,
618 hdb_entry_ex *client,
619 krb5_principal client_principal,
620 hdb_entry_ex *krbtgt,
621 krb5_enctype krbtgt_etype,
622 KRB5SignedPathPrincipals *spp,
623 EncryptionKey *tgtkey,
624 const char **e_text,
625 krb5_data *reply)
626 {
627 KDC_REP rep;
628 EncKDCRepPart ek;
629 EncTicketPart et;
630 KDCOptions f = b->kdc_options;
631 krb5_error_code ret;
632 krb5_enctype etype;
633 Key *skey;
634 const EncryptionKey *ekey;
635 AuthorizationData *new_auth_data = NULL;
636
637 if(adtkt) {
638 int i;
639 ekey = &adtkt->key;
640 for(i = 0; i < b->etype.len; i++)
641 if (b->etype.val[i] == adtkt->key.keytype)
642 break;
643 if(i == b->etype.len) {
644 krb5_clear_error_string(context);
645 return KRB5KDC_ERR_ETYPE_NOSUPP;
646 }
647 etype = b->etype.val[i];
648 }else{
649 ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
650 &skey, &etype);
651 if(ret) {
652 kdc_log(context, config, 0,
653 "Server (%s) has no support for etypes", server_name);
654 return ret;
655 }
656 ekey = &skey->key;
657 }
658
659 memset(&rep, 0, sizeof(rep));
660 memset(&et, 0, sizeof(et));
661 memset(&ek, 0, sizeof(ek));
662
663 rep.pvno = 5;
664 rep.msg_type = krb_tgs_rep;
665
666 et.authtime = tgt->authtime;
667 _kdc_fix_time(&b->till);
668 et.endtime = min(tgt->endtime, *b->till);
669 ALLOC(et.starttime);
670 *et.starttime = kdc_time;
671
672 ret = check_tgs_flags(context, config, b, tgt, &et);
673 if(ret)
674 goto out;
675
676 /* We should check the transited encoding if:
677 1) the request doesn't ask not to be checked
678 2) globally enforcing a check
679 3) principal requires checking
680 4) we allow non-check per-principal, but principal isn't marked as allowing this
681 5) we don't globally allow this
682 */
683
684 #define GLOBAL_FORCE_TRANSITED_CHECK \
685 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
686 #define GLOBAL_ALLOW_PER_PRINCIPAL \
687 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
688 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
689 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
690
691 /* these will consult the database in future release */
692 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
693 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
694
695 ret = fix_transited_encoding(context, config,
696 !f.disable_transited_check ||
697 GLOBAL_FORCE_TRANSITED_CHECK ||
698 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
699 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
700 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
701 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
702 &tgt->transited, &et,
703 *krb5_princ_realm(context, client_principal),
704 *krb5_princ_realm(context, server->entry.principal),
705 *krb5_princ_realm(context, krbtgt->entry.principal));
706 if(ret)
707 goto out;
708
709 copy_Realm(krb5_princ_realm(context, server->entry.principal),
710 &rep.ticket.realm);
711 _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
712 copy_Realm(&tgt_name->realm, &rep.crealm);
713 if (f.request_anonymous)
714 _kdc_make_anonymous_principalname (&rep.cname);
715 else
716 copy_PrincipalName(&tgt_name->name, &rep.cname);
717 rep.ticket.tkt_vno = 5;
718
719 ek.caddr = et.caddr;
720 if(et.caddr == NULL)
721 et.caddr = tgt->caddr;
722
723 {
724 time_t life;
725 life = et.endtime - *et.starttime;
726 if(client && client->entry.max_life)
727 life = min(life, *client->entry.max_life);
728 if(server->entry.max_life)
729 life = min(life, *server->entry.max_life);
730 et.endtime = *et.starttime + life;
731 }
732 if(f.renewable_ok && tgt->flags.renewable &&
733 et.renew_till == NULL && et.endtime < *b->till){
734 et.flags.renewable = 1;
735 ALLOC(et.renew_till);
736 *et.renew_till = *b->till;
737 }
738 if(et.renew_till){
739 time_t renew;
740 renew = *et.renew_till - et.authtime;
741 if(client && client->entry.max_renew)
742 renew = min(renew, *client->entry.max_renew);
743 if(server->entry.max_renew)
744 renew = min(renew, *server->entry.max_renew);
745 *et.renew_till = et.authtime + renew;
746 }
747
748 if(et.renew_till){
749 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
750 *et.starttime = min(*et.starttime, *et.renew_till);
751 et.endtime = min(et.endtime, *et.renew_till);
752 }
753
754 *et.starttime = min(*et.starttime, et.endtime);
755
756 if(*et.starttime == et.endtime){
757 ret = KRB5KDC_ERR_NEVER_VALID;
758 goto out;
759 }
760 if(et.renew_till && et.endtime == *et.renew_till){
761 free(et.renew_till);
762 et.renew_till = NULL;
763 et.flags.renewable = 0;
764 }
765
766 et.flags.pre_authent = tgt->flags.pre_authent;
767 et.flags.hw_authent = tgt->flags.hw_authent;
768 et.flags.anonymous = tgt->flags.anonymous;
769 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
770
771
772 krb5_generate_random_keyblock(context, etype, &et.key);
773
774 if (server->authz_data_tgs_req) {
775 ret = server->authz_data_tgs_req(context, server,
776 client_principal,
777 tgs_ticket->ticket.authorization_data,
778 tgs_ticket->ticket.authtime,
779 tgtkey,
780 ekey,
781 &et.key,
782 &new_auth_data);
783 if (ret) {
784 new_auth_data = NULL;
785 }
786 }
787
788 /* XXX Check enc-authorization-data */
789 et.authorization_data = new_auth_data;
790
791 et.crealm = tgt->crealm;
792 et.cname = tgt_name->name;
793
794 ek.key = et.key;
795 /* MIT must have at least one last_req */
796 ek.last_req.len = 1;
797 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
798 ek.nonce = b->nonce;
799 ek.flags = et.flags;
800 ek.authtime = et.authtime;
801 ek.starttime = et.starttime;
802 ek.endtime = et.endtime;
803 ek.renew_till = et.renew_till;
804 ek.srealm = rep.ticket.realm;
805 ek.sname = rep.ticket.sname;
806
807 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
808 et.endtime, et.renew_till);
809
810 /* Don't sign cross realm tickets, they can't be checked anyway */
811 {
812 char *r = get_krbtgt_realm(&ek.sname);
813
814 if (r == NULL || strcmp(r, ek.srealm) == 0) {
815 ret = _kdc_add_KRB5SignedPath(context,
816 config,
817 krbtgt,
818 krbtgt_etype,
819 NULL,
820 NULL,
821 &et);
822 if (ret)
823 goto out;
824 }
825 }
826
827 /* It is somewhat unclear where the etype in the following
828 encryption should come from. What we have is a session
829 key in the passed tgt, and a list of preferred etypes
830 *for the new ticket*. Should we pick the best possible
831 etype, given the keytype in the tgt, or should we look
832 at the etype list here as well? What if the tgt
833 session key is DES3 and we want a ticket with a (say)
834 CAST session key. Should the DES3 etype be added to the
835 etype list, even if we don't want a session key with
836 DES3? */
837 ret = _kdc_encode_reply(context, config,
838 &rep, &et, &ek, etype,
839 adtkt ? 0 : server->entry.kvno,
840 ekey, 0, &tgt->key, e_text, reply);
841 out:
842 free_TGS_REP(&rep);
843 free_TransitedEncoding(&et.transited);
844 if(et.starttime)
845 free(et.starttime);
846 if(et.renew_till)
847 free(et.renew_till);
848 if(et.authorization_data) {
849 free_AuthorizationData(et.authorization_data);
850 free(et.authorization_data);
851 }
852 free_LastReq(&ek.last_req);
853 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
854 free_EncryptionKey(&et.key);
855 return ret;
856 }
857
858 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)859 tgs_check_authenticator(krb5_context context,
860 krb5_kdc_configuration *config,
861 krb5_auth_context ac,
862 KDC_REQ_BODY *b,
863 const char **e_text,
864 krb5_keyblock *key)
865 {
866 krb5_authenticator auth;
867 size_t len;
868 unsigned char *buf;
869 size_t buf_size;
870 krb5_error_code ret;
871 krb5_crypto crypto;
872
873 krb5_auth_con_getauthenticator(context, ac, &auth);
874 if(auth->cksum == NULL){
875 kdc_log(context, config, 0, "No authenticator in request");
876 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
877 goto out;
878 }
879 /*
880 * according to RFC1510 it doesn't need to be keyed,
881 * but according to the latest draft it needs to.
882 */
883 if (
884 #if 0
885 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
886 ||
887 #endif
888 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
889 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
890 auth->cksum->cksumtype);
891 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
892 goto out;
893 }
894
895 /* XXX should not re-encode this */
896 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
897 if(ret){
898 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
899 krb5_get_err_text(context, ret));
900 goto out;
901 }
902 if(buf_size != len) {
903 free(buf);
904 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
905 *e_text = "KDC internal error";
906 ret = KRB5KRB_ERR_GENERIC;
907 goto out;
908 }
909 ret = krb5_crypto_init(context, key, 0, &crypto);
910 if (ret) {
911 free(buf);
912 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
913 krb5_get_err_text(context, ret));
914 goto out;
915 }
916 ret = krb5_verify_checksum(context,
917 crypto,
918 KRB5_KU_TGS_REQ_AUTH_CKSUM,
919 buf,
920 len,
921 auth->cksum);
922 free(buf);
923 krb5_crypto_destroy(context, crypto);
924 if(ret){
925 kdc_log(context, config, 0,
926 "Failed to verify authenticator checksum: %s",
927 krb5_get_err_text(context, ret));
928 }
929 out:
930 free_Authenticator(auth);
931 free(auth);
932 return ret;
933 }
934
935 /*
936 *
937 */
938
939 static const char *
find_rpath(krb5_context context,Realm crealm,Realm srealm)940 find_rpath(krb5_context context, Realm crealm, Realm srealm)
941 {
942 const char *new_realm = krb5_config_get_string(context,
943 NULL,
944 "capaths",
945 crealm,
946 srealm,
947 NULL);
948 return new_realm;
949 }
950
951
952 static krb5_boolean
need_referral(krb5_context context,krb5_principal server,krb5_realm ** realms)953 need_referral(krb5_context context, krb5_principal server, krb5_realm **realms)
954 {
955 if(server->name.name_type != KRB5_NT_SRV_INST ||
956 server->name.name_string.len != 2)
957 return FALSE;
958
959 return _krb5_get_host_realm_int(context, server->name.name_string.val[1],
960 FALSE, realms) == 0;
961 }
962
963 static krb5_error_code
tgs_parse_request(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,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,EncryptionKey ** tgtkey)964 tgs_parse_request(krb5_context context,
965 krb5_kdc_configuration *config,
966 KDC_REQ_BODY *b,
967 PA_DATA *tgs_req,
968 hdb_entry_ex **krbtgt,
969 krb5_enctype *krbtgt_etype,
970 krb5_ticket **ticket,
971 const char **e_text,
972 const char *from,
973 const struct sockaddr *from_addr,
974 time_t **csec,
975 int **cusec,
976 AuthorizationData **auth_data,
977 EncryptionKey **tgtkey)
978 {
979 krb5_ap_req ap_req;
980 krb5_error_code ret;
981 krb5_principal princ;
982 krb5_auth_context ac = NULL;
983 krb5_flags ap_req_options;
984 krb5_flags verify_ap_req_flags;
985 krb5_crypto crypto;
986 Key *tkey;
987
988 *auth_data = NULL;
989 *csec = NULL;
990 *cusec = NULL;
991
992 memset(&ap_req, 0, sizeof(ap_req));
993 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
994 if(ret){
995 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
996 krb5_get_err_text(context, ret));
997 goto out;
998 }
999
1000 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1001 /* XXX check for ticket.sname == req.sname */
1002 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1003 ret = KRB5KDC_ERR_POLICY; /* ? */
1004 goto out;
1005 }
1006
1007 _krb5_principalname2krb5_principal(context,
1008 &princ,
1009 ap_req.ticket.sname,
1010 ap_req.ticket.realm);
1011
1012 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1013
1014 if(ret) {
1015 char *p;
1016 ret = krb5_unparse_name(context, princ, &p);
1017 if (ret != 0)
1018 p = "<unparse_name failed>";
1019 krb5_free_principal(context, princ);
1020 kdc_log(context, config, 0,
1021 "Ticket-granting ticket not found in database: %s: %s",
1022 p, krb5_get_err_text(context, ret));
1023 if (ret == 0)
1024 free(p);
1025 ret = KRB5KRB_AP_ERR_NOT_US;
1026 goto out;
1027 }
1028
1029 if(ap_req.ticket.enc_part.kvno &&
1030 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1031 char *p;
1032
1033 ret = krb5_unparse_name (context, princ, &p);
1034 krb5_free_principal(context, princ);
1035 if (ret != 0)
1036 p = "<unparse_name failed>";
1037 kdc_log(context, config, 0,
1038 "Ticket kvno = %d, DB kvno = %d (%s)",
1039 *ap_req.ticket.enc_part.kvno,
1040 (*krbtgt)->entry.kvno,
1041 p);
1042 if (ret == 0)
1043 free (p);
1044 ret = KRB5KRB_AP_ERR_BADKEYVER;
1045 goto out;
1046 }
1047
1048 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1049
1050 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1051 ap_req.ticket.enc_part.etype, &tkey);
1052 if(ret){
1053 char *str, *p;
1054 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1055 krb5_unparse_name(context, princ, &p);
1056 kdc_log(context, config, 0,
1057 "No server key with enctype %s found for %s", str, p);
1058 free(str);
1059 free(p);
1060 ret = KRB5KRB_AP_ERR_BADKEYVER;
1061 goto out;
1062 }
1063
1064 *tgtkey = &tkey->key;
1065
1066 if (b->kdc_options.validate)
1067 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1068 else
1069 verify_ap_req_flags = 0;
1070
1071 ret = krb5_verify_ap_req2(context,
1072 &ac,
1073 &ap_req,
1074 princ,
1075 &tkey->key,
1076 verify_ap_req_flags,
1077 &ap_req_options,
1078 ticket,
1079 KRB5_KU_TGS_REQ_AUTH);
1080
1081 krb5_free_principal(context, princ);
1082 if(ret) {
1083 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1084 krb5_get_err_text(context, ret));
1085 goto out;
1086 }
1087
1088 {
1089 krb5_authenticator auth;
1090
1091 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1092 if (ret == 0) {
1093 *csec = malloc(sizeof(**csec));
1094 if (*csec == NULL) {
1095 krb5_free_authenticator(context, &auth);
1096 kdc_log(context, config, 0, "malloc failed");
1097 goto out;
1098 }
1099 **csec = auth->ctime;
1100 *cusec = malloc(sizeof(**cusec));
1101 if (*cusec == NULL) {
1102 krb5_free_authenticator(context, &auth);
1103 kdc_log(context, config, 0, "malloc failed");
1104 goto out;
1105 }
1106 **cusec = auth->cusec;
1107 krb5_free_authenticator(context, &auth);
1108 }
1109 }
1110
1111 ret = tgs_check_authenticator(context, config,
1112 ac, b, e_text, &(*ticket)->ticket.key);
1113 if (ret) {
1114 krb5_auth_con_free(context, ac);
1115 goto out;
1116 }
1117
1118 if (b->enc_authorization_data) {
1119 krb5_keyblock *subkey;
1120 krb5_data ad;
1121 ret = krb5_auth_con_getremotesubkey(context,
1122 ac,
1123 &subkey);
1124 if(ret){
1125 krb5_auth_con_free(context, ac);
1126 kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1127 krb5_get_err_text(context, ret));
1128 goto out;
1129 }
1130 if(subkey == NULL){
1131 ret = krb5_auth_con_getkey(context, ac, &subkey);
1132 if(ret) {
1133 krb5_auth_con_free(context, ac);
1134 kdc_log(context, config, 0, "Failed to get session key: %s",
1135 krb5_get_err_text(context, ret));
1136 goto out;
1137 }
1138 }
1139 if(subkey == NULL){
1140 krb5_auth_con_free(context, ac);
1141 kdc_log(context, config, 0,
1142 "Failed to get key for enc-authorization-data");
1143 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1144 goto out;
1145 }
1146 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1147 if (ret) {
1148 krb5_auth_con_free(context, ac);
1149 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1150 krb5_get_err_text(context, ret));
1151 goto out;
1152 }
1153 ret = krb5_decrypt_EncryptedData (context,
1154 crypto,
1155 KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
1156 b->enc_authorization_data,
1157 &ad);
1158 krb5_crypto_destroy(context, crypto);
1159 if(ret){
1160 krb5_auth_con_free(context, ac);
1161 kdc_log(context, config, 0,
1162 "Failed to decrypt enc-authorization-data");
1163 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1164 goto out;
1165 }
1166 krb5_free_keyblock(context, subkey);
1167 ALLOC(*auth_data);
1168 if (*auth_data == NULL) {
1169 krb5_auth_con_free(context, ac);
1170 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1171 goto out;
1172 }
1173 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1174 if(ret){
1175 krb5_auth_con_free(context, ac);
1176 free(*auth_data);
1177 *auth_data = NULL;
1178 kdc_log(context, config, 0, "Failed to decode authorization data");
1179 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1180 goto out;
1181 }
1182 }
1183
1184 krb5_auth_con_free(context, ac);
1185
1186 out:
1187 free_AP_REQ(&ap_req);
1188
1189 return ret;
1190 }
1191
1192 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,krb5_ticket * ticket,krb5_data * reply,const char * from,const char ** e_text,AuthorizationData * auth_data,EncryptionKey * tgtkey,const struct sockaddr * from_addr)1193 tgs_build_reply(krb5_context context,
1194 krb5_kdc_configuration *config,
1195 KDC_REQ *req,
1196 KDC_REQ_BODY *b,
1197 hdb_entry_ex *krbtgt,
1198 krb5_enctype krbtgt_etype,
1199 krb5_ticket *ticket,
1200 krb5_data *reply,
1201 const char *from,
1202 const char **e_text,
1203 AuthorizationData *auth_data,
1204 EncryptionKey *tgtkey,
1205 const struct sockaddr *from_addr)
1206 {
1207 krb5_error_code ret;
1208 krb5_principal cp = NULL, sp = NULL;
1209 krb5_principal client_principal = NULL;
1210 char *spn = NULL, *cpn = NULL;
1211 hdb_entry_ex *server = NULL, *client = NULL;
1212 EncTicketPart *tgt = &ticket->ticket;
1213 KRB5SignedPathPrincipals *spp = NULL;
1214
1215 PrincipalName *s;
1216 Realm r;
1217 int nloop = 0;
1218 EncTicketPart adtkt;
1219 char opt_str[128];
1220 int require_signedpath = 0;
1221
1222 memset(&adtkt, 0, sizeof(adtkt));
1223
1224 s = b->sname;
1225 r = b->realm;
1226
1227 if(b->kdc_options.enc_tkt_in_skey){
1228 Ticket *t;
1229 hdb_entry_ex *uu;
1230 krb5_principal p;
1231 Key *uukey;
1232
1233 if(b->additional_tickets == NULL ||
1234 b->additional_tickets->len == 0){
1235 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1236 kdc_log(context, config, 0,
1237 "No second ticket present in request");
1238 goto out;
1239 }
1240 t = &b->additional_tickets->val[0];
1241 if(!get_krbtgt_realm(&t->sname)){
1242 kdc_log(context, config, 0,
1243 "Additional ticket is not a ticket-granting ticket");
1244 ret = KRB5KDC_ERR_POLICY;
1245 goto out;
1246 }
1247 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1248 ret = _kdc_db_fetch(context, config, p,
1249 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1250 NULL, &uu);
1251 krb5_free_principal(context, p);
1252 if(ret){
1253 if (ret == HDB_ERR_NOENTRY)
1254 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1255 goto out;
1256 }
1257 ret = hdb_enctype2key(context, &uu->entry,
1258 t->enc_part.etype, &uukey);
1259 if(ret){
1260 _kdc_free_ent(context, uu);
1261 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1262 goto out;
1263 }
1264 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1265 _kdc_free_ent(context, uu);
1266 if(ret)
1267 goto out;
1268
1269 ret = verify_flags(context, config, &adtkt, spn);
1270 if (ret)
1271 goto out;
1272
1273 s = &adtkt.cname;
1274 r = adtkt.crealm;
1275 }
1276
1277 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1278 ret = krb5_unparse_name(context, sp, &spn);
1279 if (ret)
1280 goto out;
1281 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1282 ret = krb5_unparse_name(context, cp, &cpn);
1283 if (ret)
1284 goto out;
1285 unparse_flags (KDCOptions2int(b->kdc_options),
1286 asn1_KDCOptions_units(),
1287 opt_str, sizeof(opt_str));
1288 if(*opt_str)
1289 kdc_log(context, config, 0,
1290 "TGS-REQ %s from %s for %s [%s]",
1291 cpn, from, spn, opt_str);
1292 else
1293 kdc_log(context, config, 0,
1294 "TGS-REQ %s from %s for %s", cpn, from, spn);
1295
1296 /*
1297 * Fetch server
1298 */
1299
1300 server_lookup:
1301 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server);
1302
1303 if(ret){
1304 const char *new_rlm;
1305 Realm req_rlm;
1306 krb5_realm *realms;
1307
1308 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1309 if(nloop++ < 2) {
1310 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1311 if(new_rlm) {
1312 kdc_log(context, config, 5, "krbtgt for realm %s "
1313 "not found, trying %s",
1314 req_rlm, new_rlm);
1315 krb5_free_principal(context, sp);
1316 free(spn);
1317 krb5_make_principal(context, &sp, r,
1318 KRB5_TGS_NAME, new_rlm, NULL);
1319 ret = krb5_unparse_name(context, sp, &spn);
1320 if (ret)
1321 goto out;
1322 goto server_lookup;
1323 }
1324 }
1325 } else if(need_referral(context, sp, &realms)) {
1326 if (strcmp(realms[0], sp->realm) != 0) {
1327 kdc_log(context, config, 5,
1328 "Returning a referral to realm %s for "
1329 "server %s that was not found",
1330 realms[0], spn);
1331 krb5_free_principal(context, sp);
1332 free(spn);
1333 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1334 realms[0], NULL);
1335 ret = krb5_unparse_name(context, sp, &spn);
1336 if (ret)
1337 goto out;
1338 krb5_free_host_realm(context, realms);
1339 goto server_lookup;
1340 }
1341 krb5_free_host_realm(context, realms);
1342 }
1343 kdc_log(context, config, 0,
1344 "Server not found in database: %s: %s", spn,
1345 krb5_get_err_text(context, ret));
1346 if (ret == HDB_ERR_NOENTRY)
1347 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1348 goto out;
1349 }
1350
1351 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client);
1352 if(ret) {
1353 const char *krbtgt_realm;
1354
1355 /*
1356 * If the client belongs to the same realm as our krbtgt, it
1357 * should exist in the local database.
1358 *
1359 */
1360
1361 krbtgt_realm =
1362 krb5_principal_get_comp_string(context,
1363 krbtgt->entry.principal, 1);
1364
1365 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1366 if (ret == HDB_ERR_NOENTRY)
1367 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1368 kdc_log(context, config, 1, "Client no longer in database: %s",
1369 cpn);
1370 goto out;
1371 }
1372
1373 kdc_log(context, config, 1, "Client not found in database: %s: %s",
1374 cpn, krb5_get_err_text(context, ret));
1375 }
1376
1377 /*
1378 * Check that service is in the same realm as the krbtgt. If its
1379 * not the same, its someone that is using a uni-directional trust
1380 * backward.
1381 */
1382
1383 if (strcmp(krb5_principal_get_realm(context, sp),
1384 krb5_principal_get_comp_string(context,
1385 krbtgt->entry.principal,
1386 1)) != 0) {
1387 char *tpn;
1388 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1389 kdc_log(context, config, 0,
1390 "Request with wrong krbtgt: %s",
1391 (ret == 0) ? tpn : "<unknown>");
1392 if(ret == 0)
1393 free(tpn);
1394 ret = KRB5KRB_AP_ERR_NOT_US;
1395 goto out;
1396 }
1397
1398 /*
1399 *
1400 */
1401
1402 client_principal = cp;
1403
1404 if (client) {
1405 const PA_DATA *sdata;
1406 int i = 0;
1407
1408 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
1409 if (sdata) {
1410 krb5_crypto crypto;
1411 krb5_data datack;
1412 PA_S4U2Self self;
1413 char *selfcpn = NULL;
1414 const char *str;
1415
1416 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1417 sdata->padata_value.length,
1418 &self, NULL);
1419 if (ret) {
1420 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1421 goto out;
1422 }
1423
1424 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1425 if (ret)
1426 goto out;
1427
1428 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1429 if (ret) {
1430 free_PA_S4U2Self(&self);
1431 krb5_data_free(&datack);
1432 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1433 krb5_get_err_text(context, ret));
1434 goto out;
1435 }
1436
1437 ret = krb5_verify_checksum(context,
1438 crypto,
1439 KRB5_KU_TGS_IMPERSONATE,
1440 datack.data,
1441 datack.length,
1442 &self.cksum);
1443 krb5_data_free(&datack);
1444 krb5_crypto_destroy(context, crypto);
1445 if (ret) {
1446 free_PA_S4U2Self(&self);
1447 kdc_log(context, config, 0,
1448 "krb5_verify_checksum failed for S4U2Self: %s",
1449 krb5_get_err_text(context, ret));
1450 goto out;
1451 }
1452
1453 ret = _krb5_principalname2krb5_principal(context,
1454 &client_principal,
1455 self.name,
1456 self.realm);
1457 free_PA_S4U2Self(&self);
1458 if (ret)
1459 goto out;
1460
1461 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1462 if (ret)
1463 goto out;
1464
1465 /*
1466 * Check that service doing the impersonating is
1467 * requesting a ticket to it-self.
1468 */
1469 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1470 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1471 "to impersonate some other user "
1472 "(tried for user %s to service %s)",
1473 cpn, selfcpn, spn);
1474 free(selfcpn);
1475 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1476 goto out;
1477 }
1478
1479 /*
1480 * If the service isn't trusted for authentication to
1481 * delegation, remove the forward flag.
1482 */
1483
1484 if (client->entry.flags.trusted_for_delegation) {
1485 str = "[forwardable]";
1486 } else {
1487 b->kdc_options.forwardable = 0;
1488 str = "";
1489 }
1490 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1491 "service %s %s", cpn, selfcpn, spn, str);
1492 free(selfcpn);
1493 }
1494 }
1495
1496 /*
1497 * Constrained delegation
1498 */
1499
1500 if (client != NULL
1501 && b->additional_tickets != NULL
1502 && b->additional_tickets->len != 0
1503 && b->kdc_options.enc_tkt_in_skey == 0)
1504 {
1505 Key *clientkey;
1506 Ticket *t;
1507 char *str;
1508
1509 t = &b->additional_tickets->val[0];
1510
1511 ret = hdb_enctype2key(context, &client->entry,
1512 t->enc_part.etype, &clientkey);
1513 if(ret){
1514 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1515 goto out;
1516 }
1517
1518 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1519 if (ret) {
1520 kdc_log(context, config, 0,
1521 "failed to decrypt ticket for "
1522 "constrained delegation from %s to %s ", spn, cpn);
1523 goto out;
1524 }
1525
1526 /* check that ticket is valid */
1527
1528 if (adtkt.flags.forwardable == 0) {
1529 kdc_log(context, config, 0,
1530 "Missing forwardable flag on ticket for "
1531 "constrained delegation from %s to %s ", spn, cpn);
1532 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1533 goto out;
1534 }
1535
1536 ret = check_constrained_delegation(context, config, client, sp);
1537 if (ret) {
1538 kdc_log(context, config, 0,
1539 "constrained delegation from %s to %s not allowed",
1540 spn, cpn);
1541 goto out;
1542 }
1543
1544 ret = _krb5_principalname2krb5_principal(context,
1545 &client_principal,
1546 adtkt.cname,
1547 adtkt.crealm);
1548 if (ret)
1549 goto out;
1550
1551 ret = krb5_unparse_name(context, client_principal, &str);
1552 if (ret)
1553 goto out;
1554
1555 ret = verify_flags(context, config, &adtkt, str);
1556 if (ret) {
1557 free(str);
1558 goto out;
1559 }
1560
1561 /*
1562 * Check KRB5SignedPath in authorization data and add new entry to
1563 * make sure servers can't fake a ticket to us.
1564 */
1565
1566 ret = check_KRB5SignedPath(context,
1567 config,
1568 krbtgt,
1569 &adtkt,
1570 &spp,
1571 1);
1572 if (ret) {
1573 kdc_log(context, config, 0,
1574 "KRB5SignedPath check from service %s failed "
1575 "for delegation to %s for client %s "
1576 "from %s failed with %s",
1577 spn, str, cpn, from, krb5_get_err_text(context, ret));
1578 free(str);
1579 goto out;
1580 }
1581
1582 kdc_log(context, config, 0, "constrained delegation for %s "
1583 "from %s to %s", str, cpn, spn);
1584 free(str);
1585
1586 /*
1587 * Also require that the KDC have issue the service's krbtgt
1588 * used to do the request.
1589 */
1590 require_signedpath = 1;
1591 }
1592
1593 /*
1594 * Check flags
1595 */
1596
1597 ret = _kdc_check_flags(context, config,
1598 client, cpn,
1599 server, spn,
1600 FALSE);
1601 if(ret)
1602 goto out;
1603
1604 if((b->kdc_options.validate || b->kdc_options.renew) &&
1605 !krb5_principal_compare(context,
1606 krbtgt->entry.principal,
1607 server->entry.principal)){
1608 kdc_log(context, config, 0, "Inconsistent request.");
1609 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1610 goto out;
1611 }
1612
1613 /* check for valid set of addresses */
1614 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1615 ret = KRB5KRB_AP_ERR_BADADDR;
1616 kdc_log(context, config, 0, "Request from wrong address");
1617 goto out;
1618 }
1619
1620 /* also check the krbtgt for signature */
1621 ret = check_KRB5SignedPath(context,
1622 config,
1623 krbtgt,
1624 tgt,
1625 &spp,
1626 require_signedpath);
1627 if (ret) {
1628 kdc_log(context, config, 0,
1629 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1630 spn, cpn, from, krb5_get_err_text(context, ret));
1631 goto out;
1632 }
1633
1634 /*
1635 *
1636 */
1637
1638 ret = tgs_make_reply(context,
1639 config,
1640 b,
1641 client_principal,
1642 tgt,
1643 b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
1644 auth_data,
1645 ticket,
1646 server,
1647 spn,
1648 client,
1649 cp,
1650 krbtgt,
1651 krbtgt_etype,
1652 spp,
1653 tgtkey,
1654 e_text,
1655 reply);
1656
1657 out:
1658 free(spn);
1659 free(cpn);
1660
1661 if(server)
1662 _kdc_free_ent(context, server);
1663 if(client)
1664 _kdc_free_ent(context, client);
1665
1666 if (client_principal && client_principal != cp)
1667 krb5_free_principal(context, client_principal);
1668 if (cp)
1669 krb5_free_principal(context, cp);
1670 if (sp)
1671 krb5_free_principal(context, sp);
1672
1673 free_EncTicketPart(&adtkt);
1674
1675 return ret;
1676 }
1677
1678 /*
1679 *
1680 */
1681
1682 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)1683 _kdc_tgs_rep(krb5_context context,
1684 krb5_kdc_configuration *config,
1685 KDC_REQ *req,
1686 krb5_data *data,
1687 const char *from,
1688 struct sockaddr *from_addr)
1689 {
1690 AuthorizationData *auth_data = NULL;
1691 krb5_error_code ret;
1692 int i = 0;
1693 PA_DATA *tgs_req = NULL;
1694
1695 hdb_entry_ex *krbtgt = NULL;
1696 krb5_ticket *ticket = NULL;
1697 const char *e_text = NULL;
1698 krb5_enctype krbtgt_etype = ETYPE_NULL;
1699 EncryptionKey *tgtkey = NULL;
1700
1701
1702 time_t *csec = NULL;
1703 int *cusec = NULL;
1704
1705 if(req->padata == NULL){
1706 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1707 kdc_log(context, config, 0,
1708 "TGS-REQ from %s without PA-DATA", from);
1709 goto out;
1710 }
1711
1712 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1713
1714 if(tgs_req == NULL){
1715 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1716
1717 kdc_log(context, config, 0,
1718 "TGS-REQ from %s without PA-TGS-REQ", from);
1719 goto out;
1720 }
1721 ret = tgs_parse_request(context, config,
1722 &req->req_body, tgs_req,
1723 &krbtgt,
1724 &krbtgt_etype,
1725 &ticket,
1726 &e_text,
1727 from, from_addr,
1728 &csec, &cusec,
1729 &auth_data,
1730 &tgtkey);
1731 if (ret) {
1732 kdc_log(context, config, 0,
1733 "Failed parsing TGS-REQ from %s", from);
1734 goto out;
1735 }
1736
1737 ret = tgs_build_reply(context,
1738 config,
1739 req,
1740 &req->req_body,
1741 krbtgt,
1742 krbtgt_etype,
1743 ticket,
1744 data,
1745 from,
1746 &e_text,
1747 auth_data,
1748 tgtkey,
1749 from_addr);
1750 if (ret) {
1751 kdc_log(context, config, 0,
1752 "Failed building TGS-REP to %s", from);
1753 goto out;
1754 }
1755
1756 out:
1757 if(ret && data->data == NULL){
1758 krb5_mk_error(context,
1759 ret,
1760 NULL,
1761 NULL,
1762 NULL,
1763 NULL,
1764 csec,
1765 cusec,
1766 data);
1767 }
1768 free(csec);
1769 free(cusec);
1770 if (ticket)
1771 krb5_free_ticket(context, ticket);
1772 if(krbtgt)
1773 _kdc_free_ent(context, krbtgt);
1774
1775 if (auth_data) {
1776 free_AuthorizationData(auth_data);
1777 free(auth_data);
1778 }
1779
1780 return 0;
1781 }
1782