Rename str to oid in the function namespace to avoid -Wshadow warning
[heimdal.git] / kdc / krb5tgs.c
blob34ecabf56a64d450dc7d9b3222e924caab697975
1 /*
2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "kdc_locl.h"
36 RCSID("$Id$");
39 * return the realm of a krbtgt-ticket or NULL
42 static Realm
43 get_krbtgt_realm(const PrincipalName *p)
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;
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.
57 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
58 * entry of type KRB5SignedPath.
61 static krb5_error_code
62 find_KRB5SignedPath(krb5_context context,
63 const AuthorizationData *ad,
64 krb5_data *data)
66 AuthorizationData child;
67 krb5_error_code ret;
68 int pos;
70 if (ad == NULL || ad->len == 0)
71 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
73 pos = ad->len - 1;
75 if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
76 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
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;
88 if (child.len != 1) {
89 free_AuthorizationData(&child);
90 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
93 if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
94 free_AuthorizationData(&child);
95 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
98 if (data)
99 ret = der_copy_octet_string(&child.val[0].ad_data, data);
100 free_AuthorizationData(&child);
101 return ret;
104 krb5_error_code
105 _kdc_add_KRB5SignedPath(krb5_context context,
106 krb5_kdc_configuration *config,
107 hdb_entry_ex *krbtgt,
108 krb5_enctype enctype,
109 krb5_principal client,
110 krb5_const_principal server,
111 krb5_principals principals,
112 EncTicketPart *tkt)
114 krb5_error_code ret;
115 KRB5SignedPath sp;
116 krb5_data data;
117 krb5_crypto crypto = NULL;
118 size_t size;
120 if (server && principals) {
121 ret = add_Principals(principals, server);
122 if (ret)
123 return ret;
127 KRB5SignedPathData spd;
129 spd.client = client;
130 spd.authtime = tkt->authtime;
131 spd.delegated = principals;
132 spd.method_data = NULL;
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");
143 Key *key;
144 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
145 if (ret == 0)
146 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
147 if (ret) {
148 free(data.data);
149 return ret;
154 * Fill in KRB5SignedPath
157 sp.etype = enctype;
158 sp.delegated = principals;
159 sp.method_data = NULL;
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;
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");
177 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
178 * authorization data field.
181 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
182 KRB5_AUTHDATA_SIGNTICKET, &data);
183 krb5_data_free(&data);
185 return ret;
188 static krb5_error_code
189 check_KRB5SignedPath(krb5_context context,
190 krb5_kdc_configuration *config,
191 hdb_entry_ex *krbtgt,
192 krb5_principal cp,
193 EncTicketPart *tkt,
194 krb5_principals *delegated,
195 int *signedpath)
197 krb5_error_code ret;
198 krb5_data data;
199 krb5_crypto crypto = NULL;
201 if (delegated)
202 *delegated = NULL;
204 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
205 if (ret == 0) {
206 KRB5SignedPathData spd;
207 KRB5SignedPath sp;
208 size_t size;
210 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
211 krb5_data_free(&data);
212 if (ret)
213 return ret;
215 spd.client = cp;
216 spd.authtime = tkt->authtime;
217 spd.delegated = sp.delegated;
218 spd.method_data = sp.method_data;
220 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
221 &spd, &size, ret);
222 if (ret) {
223 free_KRB5SignedPath(&sp);
224 return ret;
226 if (data.length != size)
227 krb5_abortx(context, "internal asn.1 encoder error");
230 Key *key;
231 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
232 if (ret == 0)
233 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
234 if (ret) {
235 free(data.data);
236 free_KRB5SignedPath(&sp);
237 return ret;
240 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
241 data.data, data.length,
242 &sp.cksum);
243 krb5_crypto_destroy(context, crypto);
244 free(data.data);
245 if (ret) {
246 free_KRB5SignedPath(&sp);
247 kdc_log(context, config, 5,
248 "KRB5SignedPath not signed correctly, not marking as signed");
249 return 0;
252 if (delegated && sp.delegated) {
254 *delegated = malloc(sizeof(*sp.delegated));
255 if (*delegated == NULL) {
256 free_KRB5SignedPath(&sp);
257 return ENOMEM;
260 ret = copy_Principals(*delegated, sp.delegated);
261 if (ret) {
262 free_KRB5SignedPath(&sp);
263 free(*delegated);
264 *delegated = NULL;
265 return ret;
268 free_KRB5SignedPath(&sp);
270 *signedpath = 1;
273 return 0;
280 static krb5_error_code
281 check_PAC(krb5_context context,
282 krb5_kdc_configuration *config,
283 const krb5_principal client_principal,
284 hdb_entry_ex *client,
285 hdb_entry_ex *server,
286 const EncryptionKey *server_key,
287 const EncryptionKey *krbtgt_key,
288 EncTicketPart *tkt,
289 krb5_data *rspac,
290 int *signedpath)
292 AuthorizationData *ad = tkt->authorization_data;
293 unsigned i, j;
294 krb5_error_code ret;
296 if (ad == NULL || ad->len == 0)
297 return 0;
299 for (i = 0; i < ad->len; i++) {
300 AuthorizationData child;
302 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
303 continue;
305 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
306 ad->val[i].ad_data.length,
307 &child,
308 NULL);
309 if (ret) {
310 krb5_set_error_message(context, ret, "Failed to decode "
311 "IF_RELEVANT with %d", ret);
312 return ret;
314 for (j = 0; j < child.len; j++) {
316 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
317 krb5_pac pac;
319 /* Found PAC */
320 ret = krb5_pac_parse(context,
321 child.val[j].ad_data.data,
322 child.val[j].ad_data.length,
323 &pac);
324 free_AuthorizationData(&child);
325 if (ret)
326 return ret;
328 ret = krb5_pac_verify(context, pac, tkt->authtime,
329 client_principal,
330 krbtgt_key, NULL);
331 if (ret) {
332 krb5_pac_free(context, pac);
333 return ret;
336 ret = _kdc_pac_verify(context, client_principal,
337 client, server, &pac);
338 if (ret) {
339 krb5_pac_free(context, pac);
340 return ret;
342 *signedpath = 1;
344 ret = _krb5_pac_sign(context, pac, tkt->authtime,
345 client_principal,
346 server_key, krbtgt_key, rspac);
348 krb5_pac_free(context, pac);
350 return ret;
353 free_AuthorizationData(&child);
355 return 0;
362 static krb5_error_code
363 check_tgs_flags(krb5_context context,
364 krb5_kdc_configuration *config,
365 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
367 KDCOptions f = b->kdc_options;
369 if(f.validate){
370 if(!tgt->flags.invalid || tgt->starttime == NULL){
371 kdc_log(context, config, 0,
372 "Bad request to validate ticket");
373 return KRB5KDC_ERR_BADOPTION;
375 if(*tgt->starttime > kdc_time){
376 kdc_log(context, config, 0,
377 "Early request to validate ticket");
378 return KRB5KRB_AP_ERR_TKT_NYV;
380 /* XXX tkt = tgt */
381 et->flags.invalid = 0;
382 }else if(tgt->flags.invalid){
383 kdc_log(context, config, 0,
384 "Ticket-granting ticket has INVALID flag set");
385 return KRB5KRB_AP_ERR_TKT_INVALID;
388 if(f.forwardable){
389 if(!tgt->flags.forwardable){
390 kdc_log(context, config, 0,
391 "Bad request for forwardable ticket");
392 return KRB5KDC_ERR_BADOPTION;
394 et->flags.forwardable = 1;
396 if(f.forwarded){
397 if(!tgt->flags.forwardable){
398 kdc_log(context, config, 0,
399 "Request to forward non-forwardable ticket");
400 return KRB5KDC_ERR_BADOPTION;
402 et->flags.forwarded = 1;
403 et->caddr = b->addresses;
405 if(tgt->flags.forwarded)
406 et->flags.forwarded = 1;
408 if(f.proxiable){
409 if(!tgt->flags.proxiable){
410 kdc_log(context, config, 0,
411 "Bad request for proxiable ticket");
412 return KRB5KDC_ERR_BADOPTION;
414 et->flags.proxiable = 1;
416 if(f.proxy){
417 if(!tgt->flags.proxiable){
418 kdc_log(context, config, 0,
419 "Request to proxy non-proxiable ticket");
420 return KRB5KDC_ERR_BADOPTION;
422 et->flags.proxy = 1;
423 et->caddr = b->addresses;
425 if(tgt->flags.proxy)
426 et->flags.proxy = 1;
428 if(f.allow_postdate){
429 if(!tgt->flags.may_postdate){
430 kdc_log(context, config, 0,
431 "Bad request for post-datable ticket");
432 return KRB5KDC_ERR_BADOPTION;
434 et->flags.may_postdate = 1;
436 if(f.postdated){
437 if(!tgt->flags.may_postdate){
438 kdc_log(context, config, 0,
439 "Bad request for postdated ticket");
440 return KRB5KDC_ERR_BADOPTION;
442 if(b->from)
443 *et->starttime = *b->from;
444 et->flags.postdated = 1;
445 et->flags.invalid = 1;
446 }else if(b->from && *b->from > kdc_time + context->max_skew){
447 kdc_log(context, config, 0, "Ticket cannot be postdated");
448 return KRB5KDC_ERR_CANNOT_POSTDATE;
451 if(f.renewable){
452 if(!tgt->flags.renewable){
453 kdc_log(context, config, 0,
454 "Bad request for renewable ticket");
455 return KRB5KDC_ERR_BADOPTION;
457 et->flags.renewable = 1;
458 ALLOC(et->renew_till);
459 _kdc_fix_time(&b->rtime);
460 *et->renew_till = *b->rtime;
462 if(f.renew){
463 time_t old_life;
464 if(!tgt->flags.renewable || tgt->renew_till == NULL){
465 kdc_log(context, config, 0,
466 "Request to renew non-renewable ticket");
467 return KRB5KDC_ERR_BADOPTION;
469 old_life = tgt->endtime;
470 if(tgt->starttime)
471 old_life -= *tgt->starttime;
472 else
473 old_life -= tgt->authtime;
474 et->endtime = *et->starttime + old_life;
475 if (et->renew_till != NULL)
476 et->endtime = min(*et->renew_till, et->endtime);
479 #if 0
480 /* checks for excess flags */
481 if(f.request_anonymous && !config->allow_anonymous){
482 kdc_log(context, config, 0,
483 "Request for anonymous ticket");
484 return KRB5KDC_ERR_BADOPTION;
486 #endif
487 return 0;
494 static krb5_error_code
495 check_constrained_delegation(krb5_context context,
496 krb5_kdc_configuration *config,
497 HDB *clientdb,
498 hdb_entry_ex *client,
499 krb5_const_principal server)
501 const HDB_Ext_Constrained_delegation_acl *acl;
502 krb5_error_code ret;
503 int i;
505 /* if client delegates to itself, that ok */
506 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
507 return 0;
509 if (clientdb->hdb_check_constrained_delegation) {
510 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
511 if (ret == 0)
512 return 0;
513 } else {
514 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
515 if (ret) {
516 krb5_clear_error_message(context);
517 return ret;
520 if (acl) {
521 for (i = 0; i < acl->len; i++) {
522 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
523 return 0;
526 ret = KRB5KDC_ERR_BADOPTION;
528 kdc_log(context, config, 0,
529 "Bad request for constrained delegation");
530 return ret;
537 static krb5_error_code
538 verify_flags (krb5_context context,
539 krb5_kdc_configuration *config,
540 const EncTicketPart *et,
541 const char *pstr)
543 if(et->endtime < kdc_time){
544 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
545 return KRB5KRB_AP_ERR_TKT_EXPIRED;
547 if(et->flags.invalid){
548 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
549 return KRB5KRB_AP_ERR_TKT_NYV;
551 return 0;
558 static krb5_error_code
559 fix_transited_encoding(krb5_context context,
560 krb5_kdc_configuration *config,
561 krb5_boolean check_policy,
562 const TransitedEncoding *tr,
563 EncTicketPart *et,
564 const char *client_realm,
565 const char *server_realm,
566 const char *tgt_realm)
568 krb5_error_code ret = 0;
569 char **realms, **tmp;
570 unsigned int num_realms;
571 int i;
573 switch (tr->tr_type) {
574 case DOMAIN_X500_COMPRESS:
575 break;
576 case 0:
578 * Allow empty content of type 0 because that is was Microsoft
579 * generates in their TGT.
581 if (tr->contents.length == 0)
582 break;
583 kdc_log(context, config, 0,
584 "Transited type 0 with non empty content");
585 return KRB5KDC_ERR_TRTYPE_NOSUPP;
586 default:
587 kdc_log(context, config, 0,
588 "Unknown transited type: %u", tr->tr_type);
589 return KRB5KDC_ERR_TRTYPE_NOSUPP;
592 ret = krb5_domain_x500_decode(context,
593 tr->contents,
594 &realms,
595 &num_realms,
596 client_realm,
597 server_realm);
598 if(ret){
599 krb5_warn(context, ret,
600 "Decoding transited encoding");
601 return ret;
603 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
604 /* not us, so add the previous realm to transited set */
605 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
606 ret = ERANGE;
607 goto free_realms;
609 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
610 if(tmp == NULL){
611 ret = ENOMEM;
612 goto free_realms;
614 realms = tmp;
615 realms[num_realms] = strdup(tgt_realm);
616 if(realms[num_realms] == NULL){
617 ret = ENOMEM;
618 goto free_realms;
620 num_realms++;
622 if(num_realms == 0) {
623 if(strcmp(client_realm, server_realm))
624 kdc_log(context, config, 0,
625 "cross-realm %s -> %s", client_realm, server_realm);
626 } else {
627 size_t l = 0;
628 char *rs;
629 for(i = 0; i < num_realms; i++)
630 l += strlen(realms[i]) + 2;
631 rs = malloc(l);
632 if(rs != NULL) {
633 *rs = '\0';
634 for(i = 0; i < num_realms; i++) {
635 if(i > 0)
636 strlcat(rs, ", ", l);
637 strlcat(rs, realms[i], l);
639 kdc_log(context, config, 0,
640 "cross-realm %s -> %s via [%s]",
641 client_realm, server_realm, rs);
642 free(rs);
645 if(check_policy) {
646 ret = krb5_check_transited(context, client_realm,
647 server_realm,
648 realms, num_realms, NULL);
649 if(ret) {
650 krb5_warn(context, ret, "cross-realm %s -> %s",
651 client_realm, server_realm);
652 goto free_realms;
654 et->flags.transited_policy_checked = 1;
656 et->transited.tr_type = DOMAIN_X500_COMPRESS;
657 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
658 if(ret)
659 krb5_warn(context, ret, "Encoding transited encoding");
660 free_realms:
661 for(i = 0; i < num_realms; i++)
662 free(realms[i]);
663 free(realms);
664 return ret;
668 static krb5_error_code
669 tgs_make_reply(krb5_context context,
670 krb5_kdc_configuration *config,
671 KDC_REQ_BODY *b,
672 krb5_const_principal tgt_name,
673 const EncTicketPart *tgt,
674 const EncryptionKey *serverkey,
675 const krb5_keyblock *sessionkey,
676 krb5_kvno kvno,
677 AuthorizationData *auth_data,
678 hdb_entry_ex *server,
679 krb5_principal server_principal,
680 const char *server_name,
681 hdb_entry_ex *client,
682 krb5_principal client_principal,
683 hdb_entry_ex *krbtgt,
684 krb5_enctype krbtgt_etype,
685 krb5_principals spp,
686 const krb5_data *rspac,
687 const METHOD_DATA *enc_pa_data,
688 const char **e_text,
689 krb5_data *reply)
691 KDC_REP rep;
692 EncKDCRepPart ek;
693 EncTicketPart et;
694 KDCOptions f = b->kdc_options;
695 krb5_error_code ret;
696 int is_weak = 0;
698 memset(&rep, 0, sizeof(rep));
699 memset(&et, 0, sizeof(et));
700 memset(&ek, 0, sizeof(ek));
702 rep.pvno = 5;
703 rep.msg_type = krb_tgs_rep;
705 et.authtime = tgt->authtime;
706 _kdc_fix_time(&b->till);
707 et.endtime = min(tgt->endtime, *b->till);
708 ALLOC(et.starttime);
709 *et.starttime = kdc_time;
711 ret = check_tgs_flags(context, config, b, tgt, &et);
712 if(ret)
713 goto out;
715 /* We should check the transited encoding if:
716 1) the request doesn't ask not to be checked
717 2) globally enforcing a check
718 3) principal requires checking
719 4) we allow non-check per-principal, but principal isn't marked as allowing this
720 5) we don't globally allow this
723 #define GLOBAL_FORCE_TRANSITED_CHECK \
724 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
725 #define GLOBAL_ALLOW_PER_PRINCIPAL \
726 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
727 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
728 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
730 /* these will consult the database in future release */
731 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
732 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
734 ret = fix_transited_encoding(context, config,
735 !f.disable_transited_check ||
736 GLOBAL_FORCE_TRANSITED_CHECK ||
737 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
738 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
739 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
740 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
741 &tgt->transited, &et,
742 krb5_principal_get_realm(context, client_principal),
743 krb5_principal_get_realm(context, server->entry.principal),
744 krb5_principal_get_realm(context, krbtgt->entry.principal));
745 if(ret)
746 goto out;
748 copy_Realm(&server_principal->realm, &rep.ticket.realm);
749 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
750 copy_Realm(&tgt_name->realm, &rep.crealm);
752 if (f.request_anonymous)
753 _kdc_make_anonymous_principalname (&rep.cname);
754 else */
756 copy_PrincipalName(&tgt_name->name, &rep.cname);
757 rep.ticket.tkt_vno = 5;
759 ek.caddr = et.caddr;
760 if(et.caddr == NULL)
761 et.caddr = tgt->caddr;
764 time_t life;
765 life = et.endtime - *et.starttime;
766 if(client && client->entry.max_life)
767 life = min(life, *client->entry.max_life);
768 if(server->entry.max_life)
769 life = min(life, *server->entry.max_life);
770 et.endtime = *et.starttime + life;
772 if(f.renewable_ok && tgt->flags.renewable &&
773 et.renew_till == NULL && et.endtime < *b->till){
774 et.flags.renewable = 1;
775 ALLOC(et.renew_till);
776 *et.renew_till = *b->till;
778 if(et.renew_till){
779 time_t renew;
780 renew = *et.renew_till - et.authtime;
781 if(client && client->entry.max_renew)
782 renew = min(renew, *client->entry.max_renew);
783 if(server->entry.max_renew)
784 renew = min(renew, *server->entry.max_renew);
785 *et.renew_till = et.authtime + renew;
788 if(et.renew_till){
789 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
790 *et.starttime = min(*et.starttime, *et.renew_till);
791 et.endtime = min(et.endtime, *et.renew_till);
794 *et.starttime = min(*et.starttime, et.endtime);
796 if(*et.starttime == et.endtime){
797 ret = KRB5KDC_ERR_NEVER_VALID;
798 goto out;
800 if(et.renew_till && et.endtime == *et.renew_till){
801 free(et.renew_till);
802 et.renew_till = NULL;
803 et.flags.renewable = 0;
806 et.flags.pre_authent = tgt->flags.pre_authent;
807 et.flags.hw_authent = tgt->flags.hw_authent;
808 et.flags.anonymous = tgt->flags.anonymous;
809 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
811 if(rspac->length) {
813 * No not need to filter out the any PAC from the
814 * auth_data since it's signed by the KDC.
816 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
817 KRB5_AUTHDATA_WIN2K_PAC, rspac);
818 if (ret)
819 goto out;
822 if (auth_data) {
823 unsigned int i = 0;
825 /* XXX check authdata */
827 if (et.authorization_data == NULL) {
828 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
829 if (et.authorization_data == NULL) {
830 ret = ENOMEM;
831 krb5_set_error_message(context, ret, "malloc: out of memory");
832 goto out;
835 for(i = 0; i < auth_data->len ; i++) {
836 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
837 if (ret) {
838 krb5_set_error_message(context, ret, "malloc: out of memory");
839 goto out;
843 /* Filter out type KRB5SignedPath */
844 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
845 if (ret == 0) {
846 if (et.authorization_data->len == 1) {
847 free_AuthorizationData(et.authorization_data);
848 free(et.authorization_data);
849 et.authorization_data = NULL;
850 } else {
851 AuthorizationData *ad = et.authorization_data;
852 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
853 ad->len--;
858 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
859 if (ret)
860 goto out;
861 et.crealm = tgt->crealm;
862 et.cname = tgt_name->name;
864 ek.key = et.key;
865 /* MIT must have at least one last_req */
866 ek.last_req.len = 1;
867 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
868 if (ek.last_req.val == NULL) {
869 ret = ENOMEM;
870 goto out;
872 ek.nonce = b->nonce;
873 ek.flags = et.flags;
874 ek.authtime = et.authtime;
875 ek.starttime = et.starttime;
876 ek.endtime = et.endtime;
877 ek.renew_till = et.renew_till;
878 ek.srealm = rep.ticket.realm;
879 ek.sname = rep.ticket.sname;
881 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
882 et.endtime, et.renew_till);
884 /* Don't sign cross realm tickets, they can't be checked anyway */
886 char *r = get_krbtgt_realm(&ek.sname);
888 if (r == NULL || strcmp(r, ek.srealm) == 0) {
889 ret = _kdc_add_KRB5SignedPath(context,
890 config,
891 krbtgt,
892 krbtgt_etype,
893 client_principal,
894 NULL,
895 spp,
896 &et);
897 if (ret)
898 goto out;
902 if (enc_pa_data->len) {
903 rep.padata = calloc(1, sizeof(*rep.padata));
904 if (rep.padata == NULL) {
905 ret = ENOMEM;
906 goto out;
908 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
909 if (ret)
910 goto out;
913 if (krb5_enctype_valid(context, et.key.keytype) != 0
914 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
916 krb5_enctype_enable(context, et.key.keytype);
917 is_weak = 1;
921 /* It is somewhat unclear where the etype in the following
922 encryption should come from. What we have is a session
923 key in the passed tgt, and a list of preferred etypes
924 *for the new ticket*. Should we pick the best possible
925 etype, given the keytype in the tgt, or should we look
926 at the etype list here as well? What if the tgt
927 session key is DES3 and we want a ticket with a (say)
928 CAST session key. Should the DES3 etype be added to the
929 etype list, even if we don't want a session key with
930 DES3? */
931 ret = _kdc_encode_reply(context, config,
932 &rep, &et, &ek, et.key.keytype,
933 kvno,
934 serverkey, 0, &tgt->key, e_text, reply);
935 if (is_weak)
936 krb5_enctype_disable(context, et.key.keytype);
938 out:
939 free_TGS_REP(&rep);
940 free_TransitedEncoding(&et.transited);
941 if(et.starttime)
942 free(et.starttime);
943 if(et.renew_till)
944 free(et.renew_till);
945 if(et.authorization_data) {
946 free_AuthorizationData(et.authorization_data);
947 free(et.authorization_data);
949 free_LastReq(&ek.last_req);
950 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
951 free_EncryptionKey(&et.key);
952 return ret;
955 static krb5_error_code
956 tgs_check_authenticator(krb5_context context,
957 krb5_kdc_configuration *config,
958 krb5_auth_context ac,
959 KDC_REQ_BODY *b,
960 const char **e_text,
961 krb5_keyblock *key)
963 krb5_authenticator auth;
964 size_t len;
965 unsigned char *buf;
966 size_t buf_size;
967 krb5_error_code ret;
968 krb5_crypto crypto;
970 krb5_auth_con_getauthenticator(context, ac, &auth);
971 if(auth->cksum == NULL){
972 kdc_log(context, config, 0, "No authenticator in request");
973 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
974 goto out;
977 * according to RFC1510 it doesn't need to be keyed,
978 * but according to the latest draft it needs to.
980 if (
981 #if 0
982 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
984 #endif
985 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
986 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
987 auth->cksum->cksumtype);
988 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
989 goto out;
992 /* XXX should not re-encode this */
993 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
994 if(ret){
995 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
996 krb5_get_err_text(context, ret));
997 goto out;
999 if(buf_size != len) {
1000 free(buf);
1001 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1002 *e_text = "KDC internal error";
1003 ret = KRB5KRB_ERR_GENERIC;
1004 goto out;
1006 ret = krb5_crypto_init(context, key, 0, &crypto);
1007 if (ret) {
1008 free(buf);
1009 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1010 krb5_get_err_text(context, ret));
1011 goto out;
1013 ret = krb5_verify_checksum(context,
1014 crypto,
1015 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1016 buf,
1017 len,
1018 auth->cksum);
1019 free(buf);
1020 krb5_crypto_destroy(context, crypto);
1021 if(ret){
1022 kdc_log(context, config, 0,
1023 "Failed to verify authenticator checksum: %s",
1024 krb5_get_err_text(context, ret));
1026 out:
1027 free_Authenticator(auth);
1028 free(auth);
1029 return ret;
1036 static const char *
1037 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1039 const char *new_realm = krb5_config_get_string(context,
1040 NULL,
1041 "capaths",
1042 crealm,
1043 srealm,
1044 NULL);
1045 return new_realm;
1049 static krb5_boolean
1050 need_referral(krb5_context context, krb5_kdc_configuration *config,
1051 const KDCOptions * const options, krb5_principal server,
1052 krb5_realm **realms)
1054 const char *name;
1056 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1057 return FALSE;
1059 if (server->name.name_string.len == 1)
1060 name = server->name.name_string.val[0];
1061 else if (server->name.name_string.len > 1)
1062 name = server->name.name_string.val[1];
1063 else
1064 return FALSE;
1066 kdc_log(context, config, 0, "Searching referral for %s", name);
1068 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1071 static krb5_error_code
1072 tgs_parse_request(krb5_context context,
1073 krb5_kdc_configuration *config,
1074 KDC_REQ_BODY *b,
1075 const PA_DATA *tgs_req,
1076 hdb_entry_ex **krbtgt,
1077 krb5_enctype *krbtgt_etype,
1078 krb5_ticket **ticket,
1079 const char **e_text,
1080 const char *from,
1081 const struct sockaddr *from_addr,
1082 time_t **csec,
1083 int **cusec,
1084 AuthorizationData **auth_data)
1086 krb5_ap_req ap_req;
1087 krb5_error_code ret;
1088 krb5_principal princ;
1089 krb5_auth_context ac = NULL;
1090 krb5_flags ap_req_options;
1091 krb5_flags verify_ap_req_flags;
1092 krb5_crypto crypto;
1093 Key *tkey;
1095 *auth_data = NULL;
1096 *csec = NULL;
1097 *cusec = NULL;
1099 memset(&ap_req, 0, sizeof(ap_req));
1100 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1101 if(ret){
1102 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1103 krb5_get_err_text(context, ret));
1104 goto out;
1107 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1108 /* XXX check for ticket.sname == req.sname */
1109 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1110 ret = KRB5KDC_ERR_POLICY; /* ? */
1111 goto out;
1114 _krb5_principalname2krb5_principal(context,
1115 &princ,
1116 ap_req.ticket.sname,
1117 ap_req.ticket.realm);
1119 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1121 if(ret) {
1122 char *p;
1123 ret = krb5_unparse_name(context, princ, &p);
1124 if (ret != 0)
1125 p = "<unparse_name failed>";
1126 krb5_free_principal(context, princ);
1127 kdc_log(context, config, 0,
1128 "Ticket-granting ticket not found in database: %s: %s",
1129 p, krb5_get_err_text(context, ret));
1130 if (ret == 0)
1131 free(p);
1132 ret = KRB5KRB_AP_ERR_NOT_US;
1133 goto out;
1136 if(ap_req.ticket.enc_part.kvno &&
1137 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1138 char *p;
1140 ret = krb5_unparse_name (context, princ, &p);
1141 krb5_free_principal(context, princ);
1142 if (ret != 0)
1143 p = "<unparse_name failed>";
1144 kdc_log(context, config, 0,
1145 "Ticket kvno = %d, DB kvno = %d (%s)",
1146 *ap_req.ticket.enc_part.kvno,
1147 (*krbtgt)->entry.kvno,
1149 if (ret == 0)
1150 free (p);
1151 ret = KRB5KRB_AP_ERR_BADKEYVER;
1152 goto out;
1155 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1157 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1158 ap_req.ticket.enc_part.etype, &tkey);
1159 if(ret){
1160 char *str = NULL, *p = NULL;
1162 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1163 krb5_unparse_name(context, princ, &p);
1164 kdc_log(context, config, 0,
1165 "No server key with enctype %s found for %s",
1166 str ? str : "<unknown enctype>",
1167 p ? p : "<unparse_name failed>");
1168 free(str);
1169 free(p);
1170 ret = KRB5KRB_AP_ERR_BADKEYVER;
1171 goto out;
1174 if (b->kdc_options.validate)
1175 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1176 else
1177 verify_ap_req_flags = 0;
1179 ret = krb5_verify_ap_req2(context,
1180 &ac,
1181 &ap_req,
1182 princ,
1183 &tkey->key,
1184 verify_ap_req_flags,
1185 &ap_req_options,
1186 ticket,
1187 KRB5_KU_TGS_REQ_AUTH);
1189 krb5_free_principal(context, princ);
1190 if(ret) {
1191 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1192 krb5_get_err_text(context, ret));
1193 goto out;
1197 krb5_authenticator auth;
1199 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1200 if (ret == 0) {
1201 *csec = malloc(sizeof(**csec));
1202 if (*csec == NULL) {
1203 krb5_free_authenticator(context, &auth);
1204 kdc_log(context, config, 0, "malloc failed");
1205 goto out;
1207 **csec = auth->ctime;
1208 *cusec = malloc(sizeof(**cusec));
1209 if (*cusec == NULL) {
1210 krb5_free_authenticator(context, &auth);
1211 kdc_log(context, config, 0, "malloc failed");
1212 goto out;
1214 **cusec = auth->cusec;
1215 krb5_free_authenticator(context, &auth);
1219 ret = tgs_check_authenticator(context, config,
1220 ac, b, e_text, &(*ticket)->ticket.key);
1221 if (ret) {
1222 krb5_auth_con_free(context, ac);
1223 goto out;
1226 if (b->enc_authorization_data) {
1227 unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1228 krb5_keyblock *subkey;
1229 krb5_data ad;
1231 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1232 if(ret){
1233 krb5_auth_con_free(context, ac);
1234 kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1235 krb5_get_err_text(context, ret));
1236 goto out;
1238 if(subkey == NULL){
1239 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1240 ret = krb5_auth_con_getkey(context, ac, &subkey);
1241 if(ret) {
1242 krb5_auth_con_free(context, ac);
1243 kdc_log(context, config, 0, "Failed to get session key: %s",
1244 krb5_get_err_text(context, ret));
1245 goto out;
1248 if(subkey == NULL){
1249 krb5_auth_con_free(context, ac);
1250 kdc_log(context, config, 0,
1251 "Failed to get key for enc-authorization-data");
1252 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1253 goto out;
1255 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1256 krb5_free_keyblock(context, subkey);
1257 if (ret) {
1258 krb5_auth_con_free(context, ac);
1259 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1260 krb5_get_err_text(context, ret));
1261 goto out;
1263 ret = krb5_decrypt_EncryptedData (context,
1264 crypto,
1265 usage,
1266 b->enc_authorization_data,
1267 &ad);
1268 krb5_crypto_destroy(context, crypto);
1269 if(ret){
1270 krb5_auth_con_free(context, ac);
1271 kdc_log(context, config, 0,
1272 "Failed to decrypt enc-authorization-data");
1273 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1274 goto out;
1276 ALLOC(*auth_data);
1277 if (*auth_data == NULL) {
1278 krb5_auth_con_free(context, ac);
1279 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1280 goto out;
1282 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1283 if(ret){
1284 krb5_auth_con_free(context, ac);
1285 free(*auth_data);
1286 *auth_data = NULL;
1287 kdc_log(context, config, 0, "Failed to decode authorization data");
1288 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1289 goto out;
1293 krb5_auth_con_free(context, ac);
1295 out:
1296 free_AP_REQ(&ap_req);
1298 return ret;
1301 static krb5_error_code
1302 build_server_referral(krb5_context context,
1303 krb5_kdc_configuration *config,
1304 krb5_crypto session,
1305 krb5_const_realm referred_realm,
1306 const PrincipalName *true_principal_name,
1307 const PrincipalName *requested_principal,
1308 krb5_data *outdata)
1310 PA_ServerReferralData ref;
1311 krb5_error_code ret;
1312 EncryptedData ed;
1313 krb5_data data;
1314 size_t size;
1316 memset(&ref, 0, sizeof(ref));
1318 if (referred_realm) {
1319 ALLOC(ref.referred_realm);
1320 if (ref.referred_realm == NULL)
1321 goto eout;
1322 *ref.referred_realm = strdup(referred_realm);
1323 if (*ref.referred_realm == NULL)
1324 goto eout;
1326 if (true_principal_name) {
1327 ALLOC(ref.true_principal_name);
1328 if (ref.true_principal_name == NULL)
1329 goto eout;
1330 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1331 if (ret)
1332 goto eout;
1334 if (requested_principal) {
1335 ALLOC(ref.requested_principal_name);
1336 if (ref.requested_principal_name == NULL)
1337 goto eout;
1338 ret = copy_PrincipalName(requested_principal,
1339 ref.requested_principal_name);
1340 if (ret)
1341 goto eout;
1344 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1345 data.data, data.length,
1346 &ref, &size, ret);
1347 free_PA_ServerReferralData(&ref);
1348 if (ret)
1349 return ret;
1350 if (data.length != size)
1351 krb5_abortx(context, "internal asn.1 encoder error");
1353 ret = krb5_encrypt_EncryptedData(context, session,
1354 KRB5_KU_PA_SERVER_REFERRAL,
1355 data.data, data.length,
1356 0 /* kvno */, &ed);
1357 free(data.data);
1358 if (ret)
1359 return ret;
1361 ASN1_MALLOC_ENCODE(EncryptedData,
1362 outdata->data, outdata->length,
1363 &ed, &size, ret);
1364 free_EncryptedData(&ed);
1365 if (ret)
1366 return ret;
1367 if (outdata->length != size)
1368 krb5_abortx(context, "internal asn.1 encoder error");
1370 return 0;
1371 eout:
1372 free_PA_ServerReferralData(&ref);
1373 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1374 return ENOMEM;
1377 static krb5_error_code
1378 tgs_build_reply(krb5_context context,
1379 krb5_kdc_configuration *config,
1380 KDC_REQ *req,
1381 KDC_REQ_BODY *b,
1382 hdb_entry_ex *krbtgt,
1383 krb5_enctype krbtgt_etype,
1384 krb5_ticket *ticket,
1385 krb5_data *reply,
1386 const char *from,
1387 const char **e_text,
1388 AuthorizationData **auth_data,
1389 const struct sockaddr *from_addr)
1391 krb5_error_code ret;
1392 krb5_principal cp = NULL, sp = NULL;
1393 krb5_principal client_principal = NULL;
1394 char *spn = NULL, *cpn = NULL;
1395 hdb_entry_ex *server = NULL, *client = NULL;
1396 HDB *clientdb;
1397 krb5_realm ref_realm = NULL;
1398 EncTicketPart *tgt = &ticket->ticket;
1399 krb5_principals spp = NULL;
1400 const EncryptionKey *ekey;
1401 krb5_keyblock sessionkey;
1402 krb5_kvno kvno;
1403 krb5_data rspac;
1405 METHOD_DATA enc_pa_data;
1407 PrincipalName *s;
1408 Realm r;
1409 int nloop = 0;
1410 EncTicketPart adtkt;
1411 char opt_str[128];
1412 int signedpath = 0;
1414 Key *tkey;
1416 memset(&sessionkey, 0, sizeof(sessionkey));
1417 memset(&adtkt, 0, sizeof(adtkt));
1418 krb5_data_zero(&rspac);
1419 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1421 s = b->sname;
1422 r = b->realm;
1424 if(b->kdc_options.enc_tkt_in_skey){
1425 Ticket *t;
1426 hdb_entry_ex *uu;
1427 krb5_principal p;
1428 Key *uukey;
1430 if(b->additional_tickets == NULL ||
1431 b->additional_tickets->len == 0){
1432 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1433 kdc_log(context, config, 0,
1434 "No second ticket present in request");
1435 goto out;
1437 t = &b->additional_tickets->val[0];
1438 if(!get_krbtgt_realm(&t->sname)){
1439 kdc_log(context, config, 0,
1440 "Additional ticket is not a ticket-granting ticket");
1441 ret = KRB5KDC_ERR_POLICY;
1442 goto out;
1444 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1445 ret = _kdc_db_fetch(context, config, p,
1446 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1447 NULL, &uu);
1448 krb5_free_principal(context, p);
1449 if(ret){
1450 if (ret == HDB_ERR_NOENTRY)
1451 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1452 goto out;
1454 ret = hdb_enctype2key(context, &uu->entry,
1455 t->enc_part.etype, &uukey);
1456 if(ret){
1457 _kdc_free_ent(context, uu);
1458 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1459 goto out;
1461 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1462 _kdc_free_ent(context, uu);
1463 if(ret)
1464 goto out;
1466 ret = verify_flags(context, config, &adtkt, spn);
1467 if (ret)
1468 goto out;
1470 s = &adtkt.cname;
1471 r = adtkt.crealm;
1474 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1475 ret = krb5_unparse_name(context, sp, &spn);
1476 if (ret)
1477 goto out;
1478 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1479 ret = krb5_unparse_name(context, cp, &cpn);
1480 if (ret)
1481 goto out;
1482 unparse_flags (KDCOptions2int(b->kdc_options),
1483 asn1_KDCOptions_units(),
1484 opt_str, sizeof(opt_str));
1485 if(*opt_str)
1486 kdc_log(context, config, 0,
1487 "TGS-REQ %s from %s for %s [%s]",
1488 cpn, from, spn, opt_str);
1489 else
1490 kdc_log(context, config, 0,
1491 "TGS-REQ %s from %s for %s", cpn, from, spn);
1494 * Fetch server
1497 server_lookup:
1498 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1499 NULL, &server);
1501 if(ret){
1502 const char *new_rlm;
1503 Realm req_rlm;
1504 krb5_realm *realms;
1506 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1507 if(nloop++ < 2) {
1508 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1509 if(new_rlm) {
1510 kdc_log(context, config, 5, "krbtgt for realm %s "
1511 "not found, trying %s",
1512 req_rlm, new_rlm);
1513 krb5_free_principal(context, sp);
1514 free(spn);
1515 krb5_make_principal(context, &sp, r,
1516 KRB5_TGS_NAME, new_rlm, NULL);
1517 ret = krb5_unparse_name(context, sp, &spn);
1518 if (ret)
1519 goto out;
1521 if (ref_realm)
1522 free(ref_realm);
1523 ref_realm = strdup(new_rlm);
1524 goto server_lookup;
1527 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1528 if (strcmp(realms[0], sp->realm) != 0) {
1529 kdc_log(context, config, 5,
1530 "Returning a referral to realm %s for "
1531 "server %s that was not found",
1532 realms[0], spn);
1533 krb5_free_principal(context, sp);
1534 free(spn);
1535 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1536 realms[0], NULL);
1537 ret = krb5_unparse_name(context, sp, &spn);
1538 if (ret)
1539 goto out;
1541 if (ref_realm)
1542 free(ref_realm);
1543 ref_realm = strdup(realms[0]);
1545 krb5_free_host_realm(context, realms);
1546 goto server_lookup;
1548 krb5_free_host_realm(context, realms);
1550 kdc_log(context, config, 0,
1551 "Server not found in database: %s: %s", spn,
1552 krb5_get_err_text(context, ret));
1553 if (ret == HDB_ERR_NOENTRY)
1554 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1555 goto out;
1558 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1559 &clientdb, &client);
1560 if(ret) {
1561 const char *krbtgt_realm;
1564 * If the client belongs to the same realm as our krbtgt, it
1565 * should exist in the local database.
1569 krbtgt_realm =
1570 krb5_principal_get_comp_string(context,
1571 krbtgt->entry.principal, 1);
1573 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1574 if (ret == HDB_ERR_NOENTRY)
1575 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1576 kdc_log(context, config, 1, "Client no longer in database: %s",
1577 cpn);
1578 goto out;
1581 kdc_log(context, config, 1, "Client not found in database: %s: %s",
1582 cpn, krb5_get_err_text(context, ret));
1586 * Select enctype, return key and kvno.
1590 krb5_enctype etype;
1592 if(b->kdc_options.enc_tkt_in_skey) {
1593 int i;
1594 ekey = &adtkt.key;
1595 for(i = 0; i < b->etype.len; i++)
1596 if (b->etype.val[i] == adtkt.key.keytype)
1597 break;
1598 if(i == b->etype.len) {
1599 kdc_log(context, config, 0,
1600 "Addition ticket have not matching etypes");
1601 krb5_clear_error_message(context);
1602 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1603 goto out;
1605 etype = b->etype.val[i];
1606 kvno = 0;
1607 } else {
1608 Key *skey;
1610 ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1611 &skey, &etype);
1612 if(ret) {
1613 kdc_log(context, config, 0,
1614 "Server (%s) has no support for etypes", spn);
1615 goto out;
1617 ekey = &skey->key;
1618 kvno = server->entry.kvno;
1621 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1622 if (ret)
1623 goto out;
1627 * Check that service is in the same realm as the krbtgt. If it's
1628 * not the same, it's someone that is using a uni-directional trust
1629 * backward.
1632 if (strcmp(krb5_principal_get_realm(context, sp),
1633 krb5_principal_get_comp_string(context,
1634 krbtgt->entry.principal,
1635 1)) != 0) {
1636 char *tpn;
1637 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1638 kdc_log(context, config, 0,
1639 "Request with wrong krbtgt: %s",
1640 (ret == 0) ? tpn : "<unknown>");
1641 if(ret == 0)
1642 free(tpn);
1643 ret = KRB5KRB_AP_ERR_NOT_US;
1644 goto out;
1648 * Validate authoriation data
1651 ret = hdb_enctype2key(context, &krbtgt->entry,
1652 krbtgt_etype, &tkey);
1653 if(ret) {
1654 kdc_log(context, config, 0,
1655 "Failed to find key for krbtgt PAC check");
1656 goto out;
1659 ret = check_PAC(context, config, cp,
1660 client, server, ekey, &tkey->key,
1661 tgt, &rspac, &signedpath);
1662 if (ret) {
1663 kdc_log(context, config, 0,
1664 "Verify PAC failed for %s (%s) from %s with %s",
1665 spn, cpn, from, krb5_get_err_text(context, ret));
1666 goto out;
1669 /* also check the krbtgt for signature */
1670 ret = check_KRB5SignedPath(context,
1671 config,
1672 krbtgt,
1674 tgt,
1675 &spp,
1676 &signedpath);
1677 if (ret) {
1678 kdc_log(context, config, 0,
1679 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1680 spn, cpn, from, krb5_get_err_text(context, ret));
1681 goto out;
1685 * Process request
1688 client_principal = cp;
1690 if (client) {
1691 const PA_DATA *sdata;
1692 int i = 0;
1694 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1695 if (sdata) {
1696 krb5_crypto crypto;
1697 krb5_data datack;
1698 PA_S4U2Self self;
1699 char *selfcpn = NULL;
1700 const char *str;
1702 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1703 sdata->padata_value.length,
1704 &self, NULL);
1705 if (ret) {
1706 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1707 goto out;
1710 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1711 if (ret)
1712 goto out;
1714 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1715 if (ret) {
1716 free_PA_S4U2Self(&self);
1717 krb5_data_free(&datack);
1718 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1719 krb5_get_err_text(context, ret));
1720 goto out;
1723 ret = krb5_verify_checksum(context,
1724 crypto,
1725 KRB5_KU_OTHER_CKSUM,
1726 datack.data,
1727 datack.length,
1728 &self.cksum);
1729 krb5_data_free(&datack);
1730 krb5_crypto_destroy(context, crypto);
1731 if (ret) {
1732 free_PA_S4U2Self(&self);
1733 kdc_log(context, config, 0,
1734 "krb5_verify_checksum failed for S4U2Self: %s",
1735 krb5_get_err_text(context, ret));
1736 goto out;
1739 ret = _krb5_principalname2krb5_principal(context,
1740 &client_principal,
1741 self.name,
1742 self.realm);
1743 free_PA_S4U2Self(&self);
1744 if (ret)
1745 goto out;
1747 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1748 if (ret)
1749 goto out;
1752 * Check that service doing the impersonating is
1753 * requesting a ticket to it-self.
1755 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1756 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1757 "to impersonate some other user "
1758 "(tried for user %s to service %s)",
1759 cpn, selfcpn, spn);
1760 free(selfcpn);
1761 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1762 goto out;
1766 * If the service isn't trusted for authentication to
1767 * delegation, remove the forward flag.
1770 if (client->entry.flags.trusted_for_delegation) {
1771 str = "[forwardable]";
1772 } else {
1773 b->kdc_options.forwardable = 0;
1774 str = "";
1776 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1777 "service %s %s", cpn, selfcpn, spn, str);
1778 free(selfcpn);
1783 * Constrained delegation
1786 if (client != NULL
1787 && b->additional_tickets != NULL
1788 && b->additional_tickets->len != 0
1789 && b->kdc_options.enc_tkt_in_skey == 0)
1791 int ad_signedpath = 0;
1792 Key *clientkey;
1793 Ticket *t;
1794 char *str;
1797 * Require that the KDC have issued the service's krbtgt (not
1798 * self-issued ticket with kimpersonate(1).
1800 if (!signedpath) {
1801 ret = KRB5KDC_ERR_BADOPTION;
1802 kdc_log(context, config, 0,
1803 "Constrained delegation done on service ticket %s/%s",
1804 cpn, spn);
1805 goto out;
1808 t = &b->additional_tickets->val[0];
1810 ret = hdb_enctype2key(context, &client->entry,
1811 t->enc_part.etype, &clientkey);
1812 if(ret){
1813 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1814 goto out;
1817 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1818 if (ret) {
1819 kdc_log(context, config, 0,
1820 "failed to decrypt ticket for "
1821 "constrained delegation from %s to %s ", cpn, spn);
1822 goto out;
1825 /* check that ticket is valid */
1826 if (adtkt.flags.forwardable == 0) {
1827 kdc_log(context, config, 0,
1828 "Missing forwardable flag on ticket for "
1829 "constrained delegation from %s to %s ", cpn, spn);
1830 ret = KRB5KDC_ERR_BADOPTION;
1831 goto out;
1834 ret = check_constrained_delegation(context, config, clientdb,
1835 client, sp);
1836 if (ret) {
1837 kdc_log(context, config, 0,
1838 "constrained delegation from %s to %s not allowed",
1839 cpn, spn);
1840 goto out;
1843 ret = _krb5_principalname2krb5_principal(context,
1844 &client_principal,
1845 adtkt.cname,
1846 adtkt.crealm);
1847 if (ret)
1848 goto out;
1850 ret = krb5_unparse_name(context, client_principal, &str);
1851 if (ret)
1852 goto out;
1854 ret = verify_flags(context, config, &adtkt, str);
1855 if (ret) {
1856 free(str);
1857 goto out;
1861 * Check that the KDC issued the user's ticket.
1863 ret = check_KRB5SignedPath(context,
1864 config,
1865 krbtgt,
1867 &adtkt,
1868 NULL,
1869 &ad_signedpath);
1870 if (ret == 0 && !ad_signedpath)
1871 ret = KRB5KDC_ERR_BADOPTION;
1872 if (ret) {
1873 kdc_log(context, config, 0,
1874 "KRB5SignedPath check from service %s failed "
1875 "for delegation to %s for client %s "
1876 "from %s failed with %s",
1877 spn, str, cpn, from, krb5_get_err_text(context, ret));
1878 free(str);
1879 goto out;
1882 kdc_log(context, config, 0, "constrained delegation for %s "
1883 "from %s to %s", str, cpn, spn);
1884 free(str);
1888 * Check flags
1891 ret = kdc_check_flags(context, config,
1892 client, cpn,
1893 server, spn,
1894 FALSE);
1895 if(ret)
1896 goto out;
1898 if((b->kdc_options.validate || b->kdc_options.renew) &&
1899 !krb5_principal_compare(context,
1900 krbtgt->entry.principal,
1901 server->entry.principal)){
1902 kdc_log(context, config, 0, "Inconsistent request.");
1903 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1904 goto out;
1907 /* check for valid set of addresses */
1908 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1909 ret = KRB5KRB_AP_ERR_BADADDR;
1910 kdc_log(context, config, 0, "Request from wrong address");
1911 goto out;
1915 * If this is an referral, add server referral data to the
1916 * auth_data reply .
1918 if (ref_realm) {
1919 PA_DATA pa;
1920 krb5_crypto crypto;
1922 kdc_log(context, config, 0,
1923 "Adding server referral to %s", ref_realm);
1925 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1926 if (ret)
1927 goto out;
1929 ret = build_server_referral(context, config, crypto, ref_realm,
1930 NULL, s, &pa.padata_value);
1931 krb5_crypto_destroy(context, crypto);
1932 if (ret) {
1933 kdc_log(context, config, 0,
1934 "Failed building server referral");
1935 goto out;
1937 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1939 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1940 krb5_data_free(&pa.padata_value);
1941 if (ret) {
1942 kdc_log(context, config, 0,
1943 "Add server referral METHOD-DATA failed");
1944 goto out;
1952 ret = tgs_make_reply(context,
1953 config,
1955 client_principal,
1956 tgt,
1957 ekey,
1958 &sessionkey,
1959 kvno,
1960 *auth_data,
1961 server,
1963 spn,
1964 client,
1966 krbtgt,
1967 krbtgt_etype,
1968 spp,
1969 &rspac,
1970 &enc_pa_data,
1971 e_text,
1972 reply);
1974 out:
1975 free(spn);
1976 free(cpn);
1978 krb5_data_free(&rspac);
1979 krb5_free_keyblock_contents(context, &sessionkey);
1980 if(server)
1981 _kdc_free_ent(context, server);
1982 if(client)
1983 _kdc_free_ent(context, client);
1985 if (client_principal && client_principal != cp)
1986 krb5_free_principal(context, client_principal);
1987 if (cp)
1988 krb5_free_principal(context, cp);
1989 if (sp)
1990 krb5_free_principal(context, sp);
1991 if (ref_realm)
1992 free(ref_realm);
1993 free_METHOD_DATA(&enc_pa_data);
1995 free_EncTicketPart(&adtkt);
1997 return ret;
2004 krb5_error_code
2005 _kdc_tgs_rep(krb5_context context,
2006 krb5_kdc_configuration *config,
2007 KDC_REQ *req,
2008 krb5_data *data,
2009 const char *from,
2010 struct sockaddr *from_addr,
2011 int datagram_reply)
2013 AuthorizationData *auth_data = NULL;
2014 krb5_error_code ret;
2015 int i = 0;
2016 const PA_DATA *tgs_req;
2018 hdb_entry_ex *krbtgt = NULL;
2019 krb5_ticket *ticket = NULL;
2020 const char *e_text = NULL;
2021 krb5_enctype krbtgt_etype = ETYPE_NULL;
2023 time_t *csec = NULL;
2024 int *cusec = NULL;
2026 if(req->padata == NULL){
2027 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2028 kdc_log(context, config, 0,
2029 "TGS-REQ from %s without PA-DATA", from);
2030 goto out;
2033 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2035 if(tgs_req == NULL){
2036 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2038 kdc_log(context, config, 0,
2039 "TGS-REQ from %s without PA-TGS-REQ", from);
2040 goto out;
2042 ret = tgs_parse_request(context, config,
2043 &req->req_body, tgs_req,
2044 &krbtgt,
2045 &krbtgt_etype,
2046 &ticket,
2047 &e_text,
2048 from, from_addr,
2049 &csec, &cusec,
2050 &auth_data);
2051 if (ret) {
2052 kdc_log(context, config, 0,
2053 "Failed parsing TGS-REQ from %s", from);
2054 goto out;
2057 ret = tgs_build_reply(context,
2058 config,
2059 req,
2060 &req->req_body,
2061 krbtgt,
2062 krbtgt_etype,
2063 ticket,
2064 data,
2065 from,
2066 &e_text,
2067 &auth_data,
2068 from_addr);
2069 if (ret) {
2070 kdc_log(context, config, 0,
2071 "Failed building TGS-REP to %s", from);
2072 goto out;
2075 /* */
2076 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2077 krb5_data_free(data);
2078 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2079 e_text = "Reply packet too large";
2082 out:
2083 if(ret && data->data == NULL){
2084 krb5_mk_error(context,
2085 ret,
2086 NULL,
2087 NULL,
2088 NULL,
2089 NULL,
2090 csec,
2091 cusec,
2092 data);
2094 free(csec);
2095 free(cusec);
2096 if (ticket)
2097 krb5_free_ticket(context, ticket);
2098 if(krbtgt)
2099 _kdc_free_ent(context, krbtgt);
2101 if (auth_data) {
2102 free_AuthorizationData(auth_data);
2103 free(auth_data);
2106 return 0;