Ensure data structures allocated by hprop are initialized
[heimdal.git] / kdc / krb5tgs.c
blobb6f9c865bbd772806aa02c853b907a98960bee73
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 krb5_keyblock *replykey,
675 int rk_is_subkey,
676 const EncryptionKey *serverkey,
677 const krb5_keyblock *sessionkey,
678 krb5_kvno kvno,
679 AuthorizationData *auth_data,
680 hdb_entry_ex *server,
681 krb5_principal server_principal,
682 const char *server_name,
683 hdb_entry_ex *client,
684 krb5_principal client_principal,
685 hdb_entry_ex *krbtgt,
686 krb5_enctype krbtgt_etype,
687 krb5_principals spp,
688 const krb5_data *rspac,
689 const METHOD_DATA *enc_pa_data,
690 const char **e_text,
691 krb5_data *reply)
693 KDC_REP rep;
694 EncKDCRepPart ek;
695 EncTicketPart et;
696 KDCOptions f = b->kdc_options;
697 krb5_error_code ret;
698 int is_weak = 0;
700 memset(&rep, 0, sizeof(rep));
701 memset(&et, 0, sizeof(et));
702 memset(&ek, 0, sizeof(ek));
704 rep.pvno = 5;
705 rep.msg_type = krb_tgs_rep;
707 et.authtime = tgt->authtime;
708 _kdc_fix_time(&b->till);
709 et.endtime = min(tgt->endtime, *b->till);
710 ALLOC(et.starttime);
711 *et.starttime = kdc_time;
713 ret = check_tgs_flags(context, config, b, tgt, &et);
714 if(ret)
715 goto out;
717 /* We should check the transited encoding if:
718 1) the request doesn't ask not to be checked
719 2) globally enforcing a check
720 3) principal requires checking
721 4) we allow non-check per-principal, but principal isn't marked as allowing this
722 5) we don't globally allow this
725 #define GLOBAL_FORCE_TRANSITED_CHECK \
726 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
727 #define GLOBAL_ALLOW_PER_PRINCIPAL \
728 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
729 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
730 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
732 /* these will consult the database in future release */
733 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
734 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
736 ret = fix_transited_encoding(context, config,
737 !f.disable_transited_check ||
738 GLOBAL_FORCE_TRANSITED_CHECK ||
739 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
740 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
741 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
742 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
743 &tgt->transited, &et,
744 krb5_principal_get_realm(context, client_principal),
745 krb5_principal_get_realm(context, server->entry.principal),
746 krb5_principal_get_realm(context, krbtgt->entry.principal));
747 if(ret)
748 goto out;
750 copy_Realm(&server_principal->realm, &rep.ticket.realm);
751 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
752 copy_Realm(&tgt_name->realm, &rep.crealm);
754 if (f.request_anonymous)
755 _kdc_make_anonymous_principalname (&rep.cname);
756 else */
758 copy_PrincipalName(&tgt_name->name, &rep.cname);
759 rep.ticket.tkt_vno = 5;
761 ek.caddr = et.caddr;
762 if(et.caddr == NULL)
763 et.caddr = tgt->caddr;
766 time_t life;
767 life = et.endtime - *et.starttime;
768 if(client && client->entry.max_life)
769 life = min(life, *client->entry.max_life);
770 if(server->entry.max_life)
771 life = min(life, *server->entry.max_life);
772 et.endtime = *et.starttime + life;
774 if(f.renewable_ok && tgt->flags.renewable &&
775 et.renew_till == NULL && et.endtime < *b->till){
776 et.flags.renewable = 1;
777 ALLOC(et.renew_till);
778 *et.renew_till = *b->till;
780 if(et.renew_till){
781 time_t renew;
782 renew = *et.renew_till - et.authtime;
783 if(client && client->entry.max_renew)
784 renew = min(renew, *client->entry.max_renew);
785 if(server->entry.max_renew)
786 renew = min(renew, *server->entry.max_renew);
787 *et.renew_till = et.authtime + renew;
790 if(et.renew_till){
791 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
792 *et.starttime = min(*et.starttime, *et.renew_till);
793 et.endtime = min(et.endtime, *et.renew_till);
796 *et.starttime = min(*et.starttime, et.endtime);
798 if(*et.starttime == et.endtime){
799 ret = KRB5KDC_ERR_NEVER_VALID;
800 goto out;
802 if(et.renew_till && et.endtime == *et.renew_till){
803 free(et.renew_till);
804 et.renew_till = NULL;
805 et.flags.renewable = 0;
808 et.flags.pre_authent = tgt->flags.pre_authent;
809 et.flags.hw_authent = tgt->flags.hw_authent;
810 et.flags.anonymous = tgt->flags.anonymous;
811 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
813 if(rspac->length) {
815 * No not need to filter out the any PAC from the
816 * auth_data since it's signed by the KDC.
818 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
819 KRB5_AUTHDATA_WIN2K_PAC, rspac);
820 if (ret)
821 goto out;
824 if (auth_data) {
825 unsigned int i = 0;
827 /* XXX check authdata */
829 if (et.authorization_data == NULL) {
830 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
831 if (et.authorization_data == NULL) {
832 ret = ENOMEM;
833 krb5_set_error_message(context, ret, "malloc: out of memory");
834 goto out;
837 for(i = 0; i < auth_data->len ; i++) {
838 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
839 if (ret) {
840 krb5_set_error_message(context, ret, "malloc: out of memory");
841 goto out;
845 /* Filter out type KRB5SignedPath */
846 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
847 if (ret == 0) {
848 if (et.authorization_data->len == 1) {
849 free_AuthorizationData(et.authorization_data);
850 free(et.authorization_data);
851 et.authorization_data = NULL;
852 } else {
853 AuthorizationData *ad = et.authorization_data;
854 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
855 ad->len--;
860 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
861 if (ret)
862 goto out;
863 et.crealm = tgt->crealm;
864 et.cname = tgt_name->name;
866 ek.key = et.key;
867 /* MIT must have at least one last_req */
868 ek.last_req.len = 1;
869 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
870 if (ek.last_req.val == NULL) {
871 ret = ENOMEM;
872 goto out;
874 ek.nonce = b->nonce;
875 ek.flags = et.flags;
876 ek.authtime = et.authtime;
877 ek.starttime = et.starttime;
878 ek.endtime = et.endtime;
879 ek.renew_till = et.renew_till;
880 ek.srealm = rep.ticket.realm;
881 ek.sname = rep.ticket.sname;
883 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
884 et.endtime, et.renew_till);
886 /* Don't sign cross realm tickets, they can't be checked anyway */
888 char *r = get_krbtgt_realm(&ek.sname);
890 if (r == NULL || strcmp(r, ek.srealm) == 0) {
891 ret = _kdc_add_KRB5SignedPath(context,
892 config,
893 krbtgt,
894 krbtgt_etype,
895 client_principal,
896 NULL,
897 spp,
898 &et);
899 if (ret)
900 goto out;
904 if (enc_pa_data->len) {
905 rep.padata = calloc(1, sizeof(*rep.padata));
906 if (rep.padata == NULL) {
907 ret = ENOMEM;
908 goto out;
910 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
911 if (ret)
912 goto out;
915 if (krb5_enctype_valid(context, et.key.keytype) != 0
916 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
918 krb5_enctype_enable(context, et.key.keytype);
919 is_weak = 1;
923 /* It is somewhat unclear where the etype in the following
924 encryption should come from. What we have is a session
925 key in the passed tgt, and a list of preferred etypes
926 *for the new ticket*. Should we pick the best possible
927 etype, given the keytype in the tgt, or should we look
928 at the etype list here as well? What if the tgt
929 session key is DES3 and we want a ticket with a (say)
930 CAST session key. Should the DES3 etype be added to the
931 etype list, even if we don't want a session key with
932 DES3? */
933 ret = _kdc_encode_reply(context, config,
934 &rep, &et, &ek, et.key.keytype,
935 kvno,
936 serverkey, 0, replykey, rk_is_subkey,
937 e_text, reply);
938 if (is_weak)
939 krb5_enctype_disable(context, et.key.keytype);
941 out:
942 free_TGS_REP(&rep);
943 free_TransitedEncoding(&et.transited);
944 if(et.starttime)
945 free(et.starttime);
946 if(et.renew_till)
947 free(et.renew_till);
948 if(et.authorization_data) {
949 free_AuthorizationData(et.authorization_data);
950 free(et.authorization_data);
952 free_LastReq(&ek.last_req);
953 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
954 free_EncryptionKey(&et.key);
955 return ret;
958 static krb5_error_code
959 tgs_check_authenticator(krb5_context context,
960 krb5_kdc_configuration *config,
961 krb5_auth_context ac,
962 KDC_REQ_BODY *b,
963 const char **e_text,
964 krb5_keyblock *key)
966 krb5_authenticator auth;
967 size_t len;
968 unsigned char *buf;
969 size_t buf_size;
970 krb5_error_code ret;
971 krb5_crypto crypto;
973 krb5_auth_con_getauthenticator(context, ac, &auth);
974 if(auth->cksum == NULL){
975 kdc_log(context, config, 0, "No authenticator in request");
976 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
977 goto out;
980 * according to RFC1510 it doesn't need to be keyed,
981 * but according to the latest draft it needs to.
983 if (
984 #if 0
985 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
987 #endif
988 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
989 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
990 auth->cksum->cksumtype);
991 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
992 goto out;
995 /* XXX should not re-encode this */
996 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
997 if(ret){
998 const char *msg = krb5_get_error_message(context, ret);
999 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1000 krb5_free_error_message(context, msg);
1001 goto out;
1003 if(buf_size != len) {
1004 free(buf);
1005 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1006 *e_text = "KDC internal error";
1007 ret = KRB5KRB_ERR_GENERIC;
1008 goto out;
1010 ret = krb5_crypto_init(context, key, 0, &crypto);
1011 if (ret) {
1012 const char *msg = krb5_get_error_message(context, ret);
1013 free(buf);
1014 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1015 krb5_free_error_message(context, msg);
1016 goto out;
1018 ret = krb5_verify_checksum(context,
1019 crypto,
1020 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1021 buf,
1022 len,
1023 auth->cksum);
1024 free(buf);
1025 krb5_crypto_destroy(context, crypto);
1026 if(ret){
1027 const char *msg = krb5_get_error_message(context, ret);
1028 kdc_log(context, config, 0,
1029 "Failed to verify authenticator checksum: %s", msg);
1030 krb5_free_error_message(context, msg);
1032 out:
1033 free_Authenticator(auth);
1034 free(auth);
1035 return ret;
1042 static const char *
1043 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1045 const char *new_realm = krb5_config_get_string(context,
1046 NULL,
1047 "capaths",
1048 crealm,
1049 srealm,
1050 NULL);
1051 return new_realm;
1055 static krb5_boolean
1056 need_referral(krb5_context context, krb5_kdc_configuration *config,
1057 const KDCOptions * const options, krb5_principal server,
1058 krb5_realm **realms)
1060 const char *name;
1062 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1063 return FALSE;
1065 if (server->name.name_string.len == 1)
1066 name = server->name.name_string.val[0];
1067 else if (server->name.name_string.len > 1)
1068 name = server->name.name_string.val[1];
1069 else
1070 return FALSE;
1072 kdc_log(context, config, 0, "Searching referral for %s", name);
1074 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1077 static krb5_error_code
1078 tgs_parse_request(krb5_context context,
1079 krb5_kdc_configuration *config,
1080 KDC_REQ_BODY *b,
1081 const PA_DATA *tgs_req,
1082 hdb_entry_ex **krbtgt,
1083 krb5_enctype *krbtgt_etype,
1084 krb5_ticket **ticket,
1085 const char **e_text,
1086 const char *from,
1087 const struct sockaddr *from_addr,
1088 time_t **csec,
1089 int **cusec,
1090 AuthorizationData **auth_data,
1091 krb5_keyblock **replykey,
1092 int *rk_is_subkey)
1094 krb5_ap_req ap_req;
1095 krb5_error_code ret;
1096 krb5_principal princ;
1097 krb5_auth_context ac = NULL;
1098 krb5_flags ap_req_options;
1099 krb5_flags verify_ap_req_flags;
1100 krb5_crypto crypto;
1101 Key *tkey;
1102 krb5_keyblock *subkey = NULL;
1103 unsigned usage;
1105 *auth_data = NULL;
1106 *csec = NULL;
1107 *cusec = NULL;
1108 *replykey = NULL;
1110 memset(&ap_req, 0, sizeof(ap_req));
1111 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1112 if(ret){
1113 const char *msg = krb5_get_error_message(context, ret);
1114 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1115 krb5_free_error_message(context, msg);
1116 goto out;
1119 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1120 /* XXX check for ticket.sname == req.sname */
1121 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1122 ret = KRB5KDC_ERR_POLICY; /* ? */
1123 goto out;
1126 _krb5_principalname2krb5_principal(context,
1127 &princ,
1128 ap_req.ticket.sname,
1129 ap_req.ticket.realm);
1131 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1133 if(ret) {
1134 const char *msg = krb5_get_error_message(context, ret);
1135 char *p;
1136 ret = krb5_unparse_name(context, princ, &p);
1137 if (ret != 0)
1138 p = "<unparse_name failed>";
1139 krb5_free_principal(context, princ);
1140 kdc_log(context, config, 0,
1141 "Ticket-granting ticket not found in database: %s", msg);
1142 krb5_free_error_message(context, msg);
1143 if (ret == 0)
1144 free(p);
1145 ret = KRB5KRB_AP_ERR_NOT_US;
1146 goto out;
1149 if(ap_req.ticket.enc_part.kvno &&
1150 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1151 char *p;
1153 ret = krb5_unparse_name (context, princ, &p);
1154 krb5_free_principal(context, princ);
1155 if (ret != 0)
1156 p = "<unparse_name failed>";
1157 kdc_log(context, config, 0,
1158 "Ticket kvno = %d, DB kvno = %d (%s)",
1159 *ap_req.ticket.enc_part.kvno,
1160 (*krbtgt)->entry.kvno,
1162 if (ret == 0)
1163 free (p);
1164 ret = KRB5KRB_AP_ERR_BADKEYVER;
1165 goto out;
1168 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1170 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1171 ap_req.ticket.enc_part.etype, &tkey);
1172 if(ret){
1173 char *str = NULL, *p = NULL;
1175 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1176 krb5_unparse_name(context, princ, &p);
1177 kdc_log(context, config, 0,
1178 "No server key with enctype %s found for %s",
1179 str ? str : "<unknown enctype>",
1180 p ? p : "<unparse_name failed>");
1181 free(str);
1182 free(p);
1183 ret = KRB5KRB_AP_ERR_BADKEYVER;
1184 goto out;
1187 if (b->kdc_options.validate)
1188 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1189 else
1190 verify_ap_req_flags = 0;
1192 ret = krb5_verify_ap_req2(context,
1193 &ac,
1194 &ap_req,
1195 princ,
1196 &tkey->key,
1197 verify_ap_req_flags,
1198 &ap_req_options,
1199 ticket,
1200 KRB5_KU_TGS_REQ_AUTH);
1202 krb5_free_principal(context, princ);
1203 if(ret) {
1204 const char *msg = krb5_get_error_message(context, ret);
1205 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1206 krb5_free_error_message(context, msg);
1207 goto out;
1211 krb5_authenticator auth;
1213 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1214 if (ret == 0) {
1215 *csec = malloc(sizeof(**csec));
1216 if (*csec == NULL) {
1217 krb5_free_authenticator(context, &auth);
1218 kdc_log(context, config, 0, "malloc failed");
1219 goto out;
1221 **csec = auth->ctime;
1222 *cusec = malloc(sizeof(**cusec));
1223 if (*cusec == NULL) {
1224 krb5_free_authenticator(context, &auth);
1225 kdc_log(context, config, 0, "malloc failed");
1226 goto out;
1228 **cusec = auth->cusec;
1229 krb5_free_authenticator(context, &auth);
1233 ret = tgs_check_authenticator(context, config,
1234 ac, b, e_text, &(*ticket)->ticket.key);
1235 if (ret) {
1236 krb5_auth_con_free(context, ac);
1237 goto out;
1240 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1241 *rk_is_subkey = 1;
1243 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1244 if(ret){
1245 const char *msg = krb5_get_error_message(context, ret);
1246 krb5_auth_con_free(context, ac);
1247 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1248 krb5_free_error_message(context, msg);
1249 goto out;
1251 if(subkey == NULL){
1252 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1253 *rk_is_subkey = 0;
1255 ret = krb5_auth_con_getkey(context, ac, &subkey);
1256 if(ret) {
1257 const char *msg = krb5_get_error_message(context, ret);
1258 krb5_auth_con_free(context, ac);
1259 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1260 krb5_free_error_message(context, msg);
1261 goto out;
1264 if(subkey == NULL){
1265 krb5_auth_con_free(context, ac);
1266 kdc_log(context, config, 0,
1267 "Failed to get key for enc-authorization-data");
1268 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1269 goto out;
1272 *replykey = subkey;
1274 if (b->enc_authorization_data) {
1275 krb5_data ad;
1277 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1278 if (ret) {
1279 const char *msg = krb5_get_error_message(context, ret);
1280 krb5_auth_con_free(context, ac);
1281 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1282 krb5_free_error_message(context, msg);
1283 goto out;
1285 ret = krb5_decrypt_EncryptedData (context,
1286 crypto,
1287 usage,
1288 b->enc_authorization_data,
1289 &ad);
1290 krb5_crypto_destroy(context, crypto);
1291 if(ret){
1292 krb5_auth_con_free(context, ac);
1293 kdc_log(context, config, 0,
1294 "Failed to decrypt enc-authorization-data");
1295 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1296 goto out;
1298 ALLOC(*auth_data);
1299 if (*auth_data == NULL) {
1300 krb5_auth_con_free(context, ac);
1301 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1302 goto out;
1304 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1305 if(ret){
1306 krb5_auth_con_free(context, ac);
1307 free(*auth_data);
1308 *auth_data = NULL;
1309 kdc_log(context, config, 0, "Failed to decode authorization data");
1310 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1311 goto out;
1315 krb5_auth_con_free(context, ac);
1317 out:
1318 free_AP_REQ(&ap_req);
1320 return ret;
1323 static krb5_error_code
1324 build_server_referral(krb5_context context,
1325 krb5_kdc_configuration *config,
1326 krb5_crypto session,
1327 krb5_const_realm referred_realm,
1328 const PrincipalName *true_principal_name,
1329 const PrincipalName *requested_principal,
1330 krb5_data *outdata)
1332 PA_ServerReferralData ref;
1333 krb5_error_code ret;
1334 EncryptedData ed;
1335 krb5_data data;
1336 size_t size;
1338 memset(&ref, 0, sizeof(ref));
1340 if (referred_realm) {
1341 ALLOC(ref.referred_realm);
1342 if (ref.referred_realm == NULL)
1343 goto eout;
1344 *ref.referred_realm = strdup(referred_realm);
1345 if (*ref.referred_realm == NULL)
1346 goto eout;
1348 if (true_principal_name) {
1349 ALLOC(ref.true_principal_name);
1350 if (ref.true_principal_name == NULL)
1351 goto eout;
1352 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1353 if (ret)
1354 goto eout;
1356 if (requested_principal) {
1357 ALLOC(ref.requested_principal_name);
1358 if (ref.requested_principal_name == NULL)
1359 goto eout;
1360 ret = copy_PrincipalName(requested_principal,
1361 ref.requested_principal_name);
1362 if (ret)
1363 goto eout;
1366 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1367 data.data, data.length,
1368 &ref, &size, ret);
1369 free_PA_ServerReferralData(&ref);
1370 if (ret)
1371 return ret;
1372 if (data.length != size)
1373 krb5_abortx(context, "internal asn.1 encoder error");
1375 ret = krb5_encrypt_EncryptedData(context, session,
1376 KRB5_KU_PA_SERVER_REFERRAL,
1377 data.data, data.length,
1378 0 /* kvno */, &ed);
1379 free(data.data);
1380 if (ret)
1381 return ret;
1383 ASN1_MALLOC_ENCODE(EncryptedData,
1384 outdata->data, outdata->length,
1385 &ed, &size, ret);
1386 free_EncryptedData(&ed);
1387 if (ret)
1388 return ret;
1389 if (outdata->length != size)
1390 krb5_abortx(context, "internal asn.1 encoder error");
1392 return 0;
1393 eout:
1394 free_PA_ServerReferralData(&ref);
1395 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1396 return ENOMEM;
1399 static krb5_error_code
1400 tgs_build_reply(krb5_context context,
1401 krb5_kdc_configuration *config,
1402 KDC_REQ *req,
1403 KDC_REQ_BODY *b,
1404 hdb_entry_ex *krbtgt,
1405 krb5_enctype krbtgt_etype,
1406 const krb5_keyblock *replykey,
1407 int rk_is_subkey,
1408 krb5_ticket *ticket,
1409 krb5_data *reply,
1410 const char *from,
1411 const char **e_text,
1412 AuthorizationData **auth_data,
1413 const struct sockaddr *from_addr)
1415 krb5_error_code ret;
1416 krb5_principal cp = NULL, sp = NULL;
1417 krb5_principal client_principal = NULL;
1418 char *spn = NULL, *cpn = NULL;
1419 hdb_entry_ex *server = NULL, *client = NULL;
1420 HDB *clientdb;
1421 krb5_realm ref_realm = NULL;
1422 EncTicketPart *tgt = &ticket->ticket;
1423 krb5_principals spp = NULL;
1424 const EncryptionKey *ekey;
1425 krb5_keyblock sessionkey;
1426 krb5_kvno kvno;
1427 krb5_data rspac;
1429 METHOD_DATA enc_pa_data;
1431 PrincipalName *s;
1432 Realm r;
1433 int nloop = 0;
1434 EncTicketPart adtkt;
1435 char opt_str[128];
1436 int signedpath = 0;
1438 Key *tkey;
1440 memset(&sessionkey, 0, sizeof(sessionkey));
1441 memset(&adtkt, 0, sizeof(adtkt));
1442 krb5_data_zero(&rspac);
1443 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1445 s = b->sname;
1446 r = b->realm;
1448 if(b->kdc_options.enc_tkt_in_skey){
1449 Ticket *t;
1450 hdb_entry_ex *uu;
1451 krb5_principal p;
1452 Key *uukey;
1454 if(b->additional_tickets == NULL ||
1455 b->additional_tickets->len == 0){
1456 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1457 kdc_log(context, config, 0,
1458 "No second ticket present in request");
1459 goto out;
1461 t = &b->additional_tickets->val[0];
1462 if(!get_krbtgt_realm(&t->sname)){
1463 kdc_log(context, config, 0,
1464 "Additional ticket is not a ticket-granting ticket");
1465 ret = KRB5KDC_ERR_POLICY;
1466 goto out;
1468 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1469 ret = _kdc_db_fetch(context, config, p,
1470 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1471 NULL, &uu);
1472 krb5_free_principal(context, p);
1473 if(ret){
1474 if (ret == HDB_ERR_NOENTRY)
1475 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1476 goto out;
1478 ret = hdb_enctype2key(context, &uu->entry,
1479 t->enc_part.etype, &uukey);
1480 if(ret){
1481 _kdc_free_ent(context, uu);
1482 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1483 goto out;
1485 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1486 _kdc_free_ent(context, uu);
1487 if(ret)
1488 goto out;
1490 ret = verify_flags(context, config, &adtkt, spn);
1491 if (ret)
1492 goto out;
1494 s = &adtkt.cname;
1495 r = adtkt.crealm;
1498 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1499 ret = krb5_unparse_name(context, sp, &spn);
1500 if (ret)
1501 goto out;
1502 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1503 ret = krb5_unparse_name(context, cp, &cpn);
1504 if (ret)
1505 goto out;
1506 unparse_flags (KDCOptions2int(b->kdc_options),
1507 asn1_KDCOptions_units(),
1508 opt_str, sizeof(opt_str));
1509 if(*opt_str)
1510 kdc_log(context, config, 0,
1511 "TGS-REQ %s from %s for %s [%s]",
1512 cpn, from, spn, opt_str);
1513 else
1514 kdc_log(context, config, 0,
1515 "TGS-REQ %s from %s for %s", cpn, from, spn);
1518 * Fetch server
1521 server_lookup:
1522 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1523 NULL, &server);
1525 if(ret){
1526 const char *new_rlm, *msg;
1527 Realm req_rlm;
1528 krb5_realm *realms;
1530 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1531 if(nloop++ < 2) {
1532 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1533 if(new_rlm) {
1534 kdc_log(context, config, 5, "krbtgt for realm %s "
1535 "not found, trying %s",
1536 req_rlm, new_rlm);
1537 krb5_free_principal(context, sp);
1538 free(spn);
1539 krb5_make_principal(context, &sp, r,
1540 KRB5_TGS_NAME, new_rlm, NULL);
1541 ret = krb5_unparse_name(context, sp, &spn);
1542 if (ret)
1543 goto out;
1545 if (ref_realm)
1546 free(ref_realm);
1547 ref_realm = strdup(new_rlm);
1548 goto server_lookup;
1551 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1552 if (strcmp(realms[0], sp->realm) != 0) {
1553 kdc_log(context, config, 5,
1554 "Returning a referral to realm %s for "
1555 "server %s that was not found",
1556 realms[0], spn);
1557 krb5_free_principal(context, sp);
1558 free(spn);
1559 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1560 realms[0], NULL);
1561 ret = krb5_unparse_name(context, sp, &spn);
1562 if (ret)
1563 goto out;
1565 if (ref_realm)
1566 free(ref_realm);
1567 ref_realm = strdup(realms[0]);
1569 krb5_free_host_realm(context, realms);
1570 goto server_lookup;
1572 krb5_free_host_realm(context, realms);
1574 msg = krb5_get_error_message(context, ret);
1575 kdc_log(context, config, 0,
1576 "Server not found in database: %s: %s", spn, msg);
1577 krb5_free_error_message(context, msg);
1578 if (ret == HDB_ERR_NOENTRY)
1579 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1580 goto out;
1583 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1584 &clientdb, &client);
1585 if(ret) {
1586 const char *krbtgt_realm, *msg;
1589 * If the client belongs to the same realm as our krbtgt, it
1590 * should exist in the local database.
1594 krbtgt_realm =
1595 krb5_principal_get_comp_string(context,
1596 krbtgt->entry.principal, 1);
1598 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1599 if (ret == HDB_ERR_NOENTRY)
1600 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1601 kdc_log(context, config, 1, "Client no longer in database: %s",
1602 cpn);
1603 goto out;
1606 msg = krb5_get_error_message(context, ret);
1607 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1608 krb5_free_error_message(context, msg);
1612 * Select enctype, return key and kvno.
1616 krb5_enctype etype;
1618 if(b->kdc_options.enc_tkt_in_skey) {
1619 int i;
1620 ekey = &adtkt.key;
1621 for(i = 0; i < b->etype.len; i++)
1622 if (b->etype.val[i] == adtkt.key.keytype)
1623 break;
1624 if(i == b->etype.len) {
1625 kdc_log(context, config, 0,
1626 "Addition ticket have not matching etypes");
1627 krb5_clear_error_message(context);
1628 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1629 goto out;
1631 etype = b->etype.val[i];
1632 kvno = 0;
1633 } else {
1634 Key *skey;
1636 ret = _kdc_find_etype(context, server,
1637 b->etype.val, b->etype.len, &skey);
1638 if(ret) {
1639 kdc_log(context, config, 0,
1640 "Server (%s) has no support for etypes", spn);
1641 goto out;
1643 ekey = &skey->key;
1644 etype = skey->key.keytype;
1645 kvno = server->entry.kvno;
1648 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1649 if (ret)
1650 goto out;
1654 * Check that service is in the same realm as the krbtgt. If it's
1655 * not the same, it's someone that is using a uni-directional trust
1656 * backward.
1659 if (strcmp(krb5_principal_get_realm(context, sp),
1660 krb5_principal_get_comp_string(context,
1661 krbtgt->entry.principal,
1662 1)) != 0) {
1663 char *tpn;
1664 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1665 kdc_log(context, config, 0,
1666 "Request with wrong krbtgt: %s",
1667 (ret == 0) ? tpn : "<unknown>");
1668 if(ret == 0)
1669 free(tpn);
1670 ret = KRB5KRB_AP_ERR_NOT_US;
1671 goto out;
1675 * Validate authoriation data
1678 ret = hdb_enctype2key(context, &krbtgt->entry,
1679 krbtgt_etype, &tkey);
1680 if(ret) {
1681 kdc_log(context, config, 0,
1682 "Failed to find key for krbtgt PAC check");
1683 goto out;
1686 ret = check_PAC(context, config, cp,
1687 client, server, ekey, &tkey->key,
1688 tgt, &rspac, &signedpath);
1689 if (ret) {
1690 const char *msg = krb5_get_error_message(context, ret);
1691 kdc_log(context, config, 0,
1692 "Verify PAC failed for %s (%s) from %s with %s",
1693 spn, cpn, from, msg);
1694 krb5_free_error_message(context, msg);
1695 goto out;
1698 /* also check the krbtgt for signature */
1699 ret = check_KRB5SignedPath(context,
1700 config,
1701 krbtgt,
1703 tgt,
1704 &spp,
1705 &signedpath);
1706 if (ret) {
1707 const char *msg = krb5_get_error_message(context, ret);
1708 kdc_log(context, config, 0,
1709 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1710 spn, cpn, from, msg);
1711 krb5_free_error_message(context, msg);
1712 goto out;
1716 * Process request
1719 client_principal = cp;
1721 if (client) {
1722 const PA_DATA *sdata;
1723 int i = 0;
1725 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1726 if (sdata) {
1727 krb5_crypto crypto;
1728 krb5_data datack;
1729 PA_S4U2Self self;
1730 char *selfcpn = NULL;
1731 const char *str;
1733 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1734 sdata->padata_value.length,
1735 &self, NULL);
1736 if (ret) {
1737 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1738 goto out;
1741 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1742 if (ret)
1743 goto out;
1745 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1746 if (ret) {
1747 const char *msg = krb5_get_error_message(context, ret);
1748 free_PA_S4U2Self(&self);
1749 krb5_data_free(&datack);
1750 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1751 krb5_free_error_message(context, msg);
1752 goto out;
1755 ret = krb5_verify_checksum(context,
1756 crypto,
1757 KRB5_KU_OTHER_CKSUM,
1758 datack.data,
1759 datack.length,
1760 &self.cksum);
1761 krb5_data_free(&datack);
1762 krb5_crypto_destroy(context, crypto);
1763 if (ret) {
1764 const char *msg = krb5_get_error_message(context, ret);
1765 free_PA_S4U2Self(&self);
1766 kdc_log(context, config, 0,
1767 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1768 krb5_free_error_message(context, msg);
1769 goto out;
1772 ret = _krb5_principalname2krb5_principal(context,
1773 &client_principal,
1774 self.name,
1775 self.realm);
1776 free_PA_S4U2Self(&self);
1777 if (ret)
1778 goto out;
1780 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1781 if (ret)
1782 goto out;
1785 * Check that service doing the impersonating is
1786 * requesting a ticket to it-self.
1788 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1789 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1790 "to impersonate some other user "
1791 "(tried for user %s to service %s)",
1792 cpn, selfcpn, spn);
1793 free(selfcpn);
1794 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1795 goto out;
1799 * If the service isn't trusted for authentication to
1800 * delegation, remove the forward flag.
1803 if (client->entry.flags.trusted_for_delegation) {
1804 str = "[forwardable]";
1805 } else {
1806 b->kdc_options.forwardable = 0;
1807 str = "";
1809 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1810 "service %s %s", cpn, selfcpn, spn, str);
1811 free(selfcpn);
1816 * Constrained delegation
1819 if (client != NULL
1820 && b->additional_tickets != NULL
1821 && b->additional_tickets->len != 0
1822 && b->kdc_options.enc_tkt_in_skey == 0)
1824 int ad_signedpath = 0;
1825 Key *clientkey;
1826 Ticket *t;
1827 char *str;
1830 * Require that the KDC have issued the service's krbtgt (not
1831 * self-issued ticket with kimpersonate(1).
1833 if (!signedpath) {
1834 ret = KRB5KDC_ERR_BADOPTION;
1835 kdc_log(context, config, 0,
1836 "Constrained delegation done on service ticket %s/%s",
1837 cpn, spn);
1838 goto out;
1841 t = &b->additional_tickets->val[0];
1843 ret = hdb_enctype2key(context, &client->entry,
1844 t->enc_part.etype, &clientkey);
1845 if(ret){
1846 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1847 goto out;
1850 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1851 if (ret) {
1852 kdc_log(context, config, 0,
1853 "failed to decrypt ticket for "
1854 "constrained delegation from %s to %s ", cpn, spn);
1855 goto out;
1858 /* check that ticket is valid */
1859 if (adtkt.flags.forwardable == 0) {
1860 kdc_log(context, config, 0,
1861 "Missing forwardable flag on ticket for "
1862 "constrained delegation from %s to %s ", cpn, spn);
1863 ret = KRB5KDC_ERR_BADOPTION;
1864 goto out;
1867 ret = check_constrained_delegation(context, config, clientdb,
1868 client, sp);
1869 if (ret) {
1870 kdc_log(context, config, 0,
1871 "constrained delegation from %s to %s not allowed",
1872 cpn, spn);
1873 goto out;
1876 ret = _krb5_principalname2krb5_principal(context,
1877 &client_principal,
1878 adtkt.cname,
1879 adtkt.crealm);
1880 if (ret)
1881 goto out;
1883 ret = krb5_unparse_name(context, client_principal, &str);
1884 if (ret)
1885 goto out;
1887 ret = verify_flags(context, config, &adtkt, str);
1888 if (ret) {
1889 free(str);
1890 goto out;
1894 * Check that the KDC issued the user's ticket.
1896 ret = check_KRB5SignedPath(context,
1897 config,
1898 krbtgt,
1900 &adtkt,
1901 NULL,
1902 &ad_signedpath);
1903 if (ret == 0 && !ad_signedpath)
1904 ret = KRB5KDC_ERR_BADOPTION;
1905 if (ret) {
1906 const char *msg = krb5_get_error_message(context, ret);
1907 kdc_log(context, config, 0,
1908 "KRB5SignedPath check from service %s failed "
1909 "for delegation to %s for client %s "
1910 "from %s failed with %s",
1911 spn, str, cpn, from, msg);
1912 krb5_free_error_message(context, msg);
1913 free(str);
1914 goto out;
1917 kdc_log(context, config, 0, "constrained delegation for %s "
1918 "from %s to %s", str, cpn, spn);
1919 free(str);
1923 * Check flags
1926 ret = kdc_check_flags(context, config,
1927 client, cpn,
1928 server, spn,
1929 FALSE);
1930 if(ret)
1931 goto out;
1933 if((b->kdc_options.validate || b->kdc_options.renew) &&
1934 !krb5_principal_compare(context,
1935 krbtgt->entry.principal,
1936 server->entry.principal)){
1937 kdc_log(context, config, 0, "Inconsistent request.");
1938 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1939 goto out;
1942 /* check for valid set of addresses */
1943 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1944 ret = KRB5KRB_AP_ERR_BADADDR;
1945 kdc_log(context, config, 0, "Request from wrong address");
1946 goto out;
1950 * If this is an referral, add server referral data to the
1951 * auth_data reply .
1953 if (ref_realm) {
1954 PA_DATA pa;
1955 krb5_crypto crypto;
1957 kdc_log(context, config, 0,
1958 "Adding server referral to %s", ref_realm);
1960 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1961 if (ret)
1962 goto out;
1964 ret = build_server_referral(context, config, crypto, ref_realm,
1965 NULL, s, &pa.padata_value);
1966 krb5_crypto_destroy(context, crypto);
1967 if (ret) {
1968 kdc_log(context, config, 0,
1969 "Failed building server referral");
1970 goto out;
1972 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1974 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1975 krb5_data_free(&pa.padata_value);
1976 if (ret) {
1977 kdc_log(context, config, 0,
1978 "Add server referral METHOD-DATA failed");
1979 goto out;
1987 ret = tgs_make_reply(context,
1988 config,
1990 client_principal,
1991 tgt,
1992 replykey,
1993 rk_is_subkey,
1994 ekey,
1995 &sessionkey,
1996 kvno,
1997 *auth_data,
1998 server,
2000 spn,
2001 client,
2003 krbtgt,
2004 krbtgt_etype,
2005 spp,
2006 &rspac,
2007 &enc_pa_data,
2008 e_text,
2009 reply);
2011 out:
2012 free(spn);
2013 free(cpn);
2015 krb5_data_free(&rspac);
2016 krb5_free_keyblock_contents(context, &sessionkey);
2017 if(server)
2018 _kdc_free_ent(context, server);
2019 if(client)
2020 _kdc_free_ent(context, client);
2022 if (client_principal && client_principal != cp)
2023 krb5_free_principal(context, client_principal);
2024 if (cp)
2025 krb5_free_principal(context, cp);
2026 if (sp)
2027 krb5_free_principal(context, sp);
2028 if (ref_realm)
2029 free(ref_realm);
2030 free_METHOD_DATA(&enc_pa_data);
2032 free_EncTicketPart(&adtkt);
2034 return ret;
2041 krb5_error_code
2042 _kdc_tgs_rep(krb5_context context,
2043 krb5_kdc_configuration *config,
2044 KDC_REQ *req,
2045 krb5_data *data,
2046 const char *from,
2047 struct sockaddr *from_addr,
2048 int datagram_reply)
2050 AuthorizationData *auth_data = NULL;
2051 krb5_error_code ret;
2052 int i = 0;
2053 const PA_DATA *tgs_req;
2055 hdb_entry_ex *krbtgt = NULL;
2056 krb5_ticket *ticket = NULL;
2057 const char *e_text = NULL;
2058 krb5_enctype krbtgt_etype = ETYPE_NULL;
2060 krb5_keyblock *replykey = NULL;
2061 int rk_is_subkey = 0;
2062 time_t *csec = NULL;
2063 int *cusec = NULL;
2065 if(req->padata == NULL){
2066 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2067 kdc_log(context, config, 0,
2068 "TGS-REQ from %s without PA-DATA", from);
2069 goto out;
2072 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2074 if(tgs_req == NULL){
2075 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2077 kdc_log(context, config, 0,
2078 "TGS-REQ from %s without PA-TGS-REQ", from);
2079 goto out;
2081 ret = tgs_parse_request(context, config,
2082 &req->req_body, tgs_req,
2083 &krbtgt,
2084 &krbtgt_etype,
2085 &ticket,
2086 &e_text,
2087 from, from_addr,
2088 &csec, &cusec,
2089 &auth_data,
2090 &replykey,
2091 &rk_is_subkey);
2092 if (ret) {
2093 kdc_log(context, config, 0,
2094 "Failed parsing TGS-REQ from %s", from);
2095 goto out;
2098 ret = tgs_build_reply(context,
2099 config,
2100 req,
2101 &req->req_body,
2102 krbtgt,
2103 krbtgt_etype,
2104 replykey,
2105 rk_is_subkey,
2106 ticket,
2107 data,
2108 from,
2109 &e_text,
2110 &auth_data,
2111 from_addr);
2112 if (ret) {
2113 kdc_log(context, config, 0,
2114 "Failed building TGS-REP to %s", from);
2115 goto out;
2118 /* */
2119 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2120 krb5_data_free(data);
2121 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2122 e_text = "Reply packet too large";
2125 out:
2126 if (replykey)
2127 krb5_free_keyblock(context, replykey);
2128 if(ret && data->data == NULL){
2129 krb5_mk_error(context,
2130 ret,
2131 NULL,
2132 NULL,
2133 NULL,
2134 NULL,
2135 csec,
2136 cusec,
2137 data);
2139 free(csec);
2140 free(cusec);
2141 if (ticket)
2142 krb5_free_ticket(context, ticket);
2143 if(krbtgt)
2144 _kdc_free_ent(context, krbtgt);
2146 if (auth_data) {
2147 free_AuthorizationData(auth_data);
2148 free(auth_data);
2151 return 0;