If backend implements ->hdb_check_constrained_delegation, use it for processing.
[Samba.git] / kdc / krb5tgs.c
blob53a4784e402991ffaa00fd4acde4944089ff6921
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_const_principal server,
110 krb5_principals principals,
111 EncTicketPart *tkt)
113 krb5_error_code ret;
114 KRB5SignedPath sp;
115 krb5_data data;
116 krb5_crypto crypto = NULL;
117 size_t size;
119 if (server && principals) {
120 ret = add_Principals(principals, server);
121 if (ret)
122 return ret;
126 KRB5SignedPathData spd;
128 spd.encticket = *tkt;
129 spd.delegated = principals;
131 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
132 &spd, &size, ret);
133 if (ret)
134 return ret;
135 if (data.length != size)
136 krb5_abortx(context, "internal asn.1 encoder error");
140 Key *key;
141 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
142 if (ret == 0)
143 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
144 if (ret) {
145 free(data.data);
146 return ret;
151 * Fill in KRB5SignedPath
154 sp.etype = enctype;
155 sp.delegated = principals;
157 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
158 data.data, data.length, &sp.cksum);
159 krb5_crypto_destroy(context, crypto);
160 free(data.data);
161 if (ret)
162 return ret;
164 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
165 free_Checksum(&sp.cksum);
166 if (ret)
167 return ret;
168 if (data.length != size)
169 krb5_abortx(context, "internal asn.1 encoder error");
173 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
174 * authorization data field.
177 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
178 KRB5_AUTHDATA_SIGNTICKET, &data);
179 krb5_data_free(&data);
181 return ret;
184 static krb5_error_code
185 check_KRB5SignedPath(krb5_context context,
186 krb5_kdc_configuration *config,
187 hdb_entry_ex *krbtgt,
188 EncTicketPart *tkt,
189 krb5_principals *delegated,
190 int *signedpath)
192 krb5_error_code ret;
193 krb5_data data;
194 krb5_crypto crypto = NULL;
196 if (delegated)
197 *delegated = NULL;
199 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
200 if (ret == 0) {
201 KRB5SignedPathData spd;
202 KRB5SignedPath sp;
203 AuthorizationData *ad;
204 size_t size;
206 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
207 krb5_data_free(&data);
208 if (ret)
209 return ret;
211 spd.encticket = *tkt;
212 /* the KRB5SignedPath is the last entry */
213 ad = spd.encticket.authorization_data;
214 if (--ad->len == 0)
215 spd.encticket.authorization_data = NULL;
216 spd.delegated = sp.delegated;
218 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
219 &spd, &size, ret);
220 ad->len++;
221 spd.encticket.authorization_data = ad;
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 return ret;
250 if (delegated && sp.delegated) {
252 *delegated = malloc(sizeof(*sp.delegated));
253 if (*delegated == NULL) {
254 free_KRB5SignedPath(&sp);
255 return ENOMEM;
258 ret = copy_Principals(*delegated, sp.delegated);
259 if (ret) {
260 free_KRB5SignedPath(&sp);
261 free(*delegated);
262 *delegated = NULL;
263 return ret;
266 free_KRB5SignedPath(&sp);
268 *signedpath = 1;
271 return 0;
278 static krb5_error_code
279 check_PAC(krb5_context context,
280 krb5_kdc_configuration *config,
281 const krb5_principal client_principal,
282 hdb_entry_ex *client,
283 hdb_entry_ex *server,
284 const EncryptionKey *server_key,
285 const EncryptionKey *krbtgt_key,
286 EncTicketPart *tkt,
287 krb5_data *rspac,
288 int *signedpath)
290 AuthorizationData *ad = tkt->authorization_data;
291 unsigned i, j;
292 krb5_error_code ret;
294 if (ad == NULL || ad->len == 0)
295 return 0;
297 for (i = 0; i < ad->len; i++) {
298 AuthorizationData child;
300 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
301 continue;
303 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
304 ad->val[i].ad_data.length,
305 &child,
306 NULL);
307 if (ret) {
308 krb5_set_error_message(context, ret, "Failed to decode "
309 "IF_RELEVANT with %d", ret);
310 return ret;
312 for (j = 0; j < child.len; j++) {
314 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
315 krb5_pac pac;
317 /* Found PAC */
318 ret = krb5_pac_parse(context,
319 child.val[j].ad_data.data,
320 child.val[j].ad_data.length,
321 &pac);
322 free_AuthorizationData(&child);
323 if (ret)
324 return ret;
326 ret = krb5_pac_verify(context, pac, tkt->authtime,
327 client_principal,
328 krbtgt_key, NULL);
329 if (ret) {
330 krb5_pac_free(context, pac);
331 return ret;
334 ret = _kdc_pac_verify(context, client_principal,
335 client, server, &pac);
336 if (ret) {
337 krb5_pac_free(context, pac);
338 return ret;
340 *signedpath = 1;
342 ret = _krb5_pac_sign(context, pac, tkt->authtime,
343 client_principal,
344 server_key, krbtgt_key, rspac);
346 krb5_pac_free(context, pac);
348 return ret;
351 free_AuthorizationData(&child);
353 return 0;
360 static krb5_error_code
361 check_tgs_flags(krb5_context context,
362 krb5_kdc_configuration *config,
363 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
365 KDCOptions f = b->kdc_options;
367 if(f.validate){
368 if(!tgt->flags.invalid || tgt->starttime == NULL){
369 kdc_log(context, config, 0,
370 "Bad request to validate ticket");
371 return KRB5KDC_ERR_BADOPTION;
373 if(*tgt->starttime > kdc_time){
374 kdc_log(context, config, 0,
375 "Early request to validate ticket");
376 return KRB5KRB_AP_ERR_TKT_NYV;
378 /* XXX tkt = tgt */
379 et->flags.invalid = 0;
380 }else if(tgt->flags.invalid){
381 kdc_log(context, config, 0,
382 "Ticket-granting ticket has INVALID flag set");
383 return KRB5KRB_AP_ERR_TKT_INVALID;
386 if(f.forwardable){
387 if(!tgt->flags.forwardable){
388 kdc_log(context, config, 0,
389 "Bad request for forwardable ticket");
390 return KRB5KDC_ERR_BADOPTION;
392 et->flags.forwardable = 1;
394 if(f.forwarded){
395 if(!tgt->flags.forwardable){
396 kdc_log(context, config, 0,
397 "Request to forward non-forwardable ticket");
398 return KRB5KDC_ERR_BADOPTION;
400 et->flags.forwarded = 1;
401 et->caddr = b->addresses;
403 if(tgt->flags.forwarded)
404 et->flags.forwarded = 1;
406 if(f.proxiable){
407 if(!tgt->flags.proxiable){
408 kdc_log(context, config, 0,
409 "Bad request for proxiable ticket");
410 return KRB5KDC_ERR_BADOPTION;
412 et->flags.proxiable = 1;
414 if(f.proxy){
415 if(!tgt->flags.proxiable){
416 kdc_log(context, config, 0,
417 "Request to proxy non-proxiable ticket");
418 return KRB5KDC_ERR_BADOPTION;
420 et->flags.proxy = 1;
421 et->caddr = b->addresses;
423 if(tgt->flags.proxy)
424 et->flags.proxy = 1;
426 if(f.allow_postdate){
427 if(!tgt->flags.may_postdate){
428 kdc_log(context, config, 0,
429 "Bad request for post-datable ticket");
430 return KRB5KDC_ERR_BADOPTION;
432 et->flags.may_postdate = 1;
434 if(f.postdated){
435 if(!tgt->flags.may_postdate){
436 kdc_log(context, config, 0,
437 "Bad request for postdated ticket");
438 return KRB5KDC_ERR_BADOPTION;
440 if(b->from)
441 *et->starttime = *b->from;
442 et->flags.postdated = 1;
443 et->flags.invalid = 1;
444 }else if(b->from && *b->from > kdc_time + context->max_skew){
445 kdc_log(context, config, 0, "Ticket cannot be postdated");
446 return KRB5KDC_ERR_CANNOT_POSTDATE;
449 if(f.renewable){
450 if(!tgt->flags.renewable){
451 kdc_log(context, config, 0,
452 "Bad request for renewable ticket");
453 return KRB5KDC_ERR_BADOPTION;
455 et->flags.renewable = 1;
456 ALLOC(et->renew_till);
457 _kdc_fix_time(&b->rtime);
458 *et->renew_till = *b->rtime;
460 if(f.renew){
461 time_t old_life;
462 if(!tgt->flags.renewable || tgt->renew_till == NULL){
463 kdc_log(context, config, 0,
464 "Request to renew non-renewable ticket");
465 return KRB5KDC_ERR_BADOPTION;
467 old_life = tgt->endtime;
468 if(tgt->starttime)
469 old_life -= *tgt->starttime;
470 else
471 old_life -= tgt->authtime;
472 et->endtime = *et->starttime + old_life;
473 if (et->renew_till != NULL)
474 et->endtime = min(*et->renew_till, et->endtime);
477 #if 0
478 /* checks for excess flags */
479 if(f.request_anonymous && !config->allow_anonymous){
480 kdc_log(context, config, 0,
481 "Request for anonymous ticket");
482 return KRB5KDC_ERR_BADOPTION;
484 #endif
485 return 0;
492 static krb5_error_code
493 check_constrained_delegation(krb5_context context,
494 krb5_kdc_configuration *config,
495 HDB *clientdb,
496 hdb_entry_ex *client,
497 krb5_const_principal server)
499 const HDB_Ext_Constrained_delegation_acl *acl;
500 krb5_error_code ret;
501 int i;
503 if (clientdb->hdb_check_constrained_delegation) {
504 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
505 if (ret == 0)
506 return 0;
507 } else {
508 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
509 if (ret) {
510 krb5_clear_error_message(context);
511 return ret;
514 if (acl) {
515 for (i = 0; i < acl->len; i++) {
516 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
517 return 0;
520 ret = KRB5KDC_ERR_BADOPTION;
522 kdc_log(context, config, 0,
523 "Bad request for constrained delegation");
524 return ret;
531 static krb5_error_code
532 verify_flags (krb5_context context,
533 krb5_kdc_configuration *config,
534 const EncTicketPart *et,
535 const char *pstr)
537 if(et->endtime < kdc_time){
538 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
539 return KRB5KRB_AP_ERR_TKT_EXPIRED;
541 if(et->flags.invalid){
542 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
543 return KRB5KRB_AP_ERR_TKT_NYV;
545 return 0;
552 static krb5_error_code
553 fix_transited_encoding(krb5_context context,
554 krb5_kdc_configuration *config,
555 krb5_boolean check_policy,
556 const TransitedEncoding *tr,
557 EncTicketPart *et,
558 const char *client_realm,
559 const char *server_realm,
560 const char *tgt_realm)
562 krb5_error_code ret = 0;
563 char **realms, **tmp;
564 unsigned int num_realms;
565 int i;
567 switch (tr->tr_type) {
568 case DOMAIN_X500_COMPRESS:
569 break;
570 case 0:
572 * Allow empty content of type 0 because that is was Microsoft
573 * generates in their TGT.
575 if (tr->contents.length == 0)
576 break;
577 kdc_log(context, config, 0,
578 "Transited type 0 with non empty content");
579 return KRB5KDC_ERR_TRTYPE_NOSUPP;
580 default:
581 kdc_log(context, config, 0,
582 "Unknown transited type: %u", tr->tr_type);
583 return KRB5KDC_ERR_TRTYPE_NOSUPP;
586 ret = krb5_domain_x500_decode(context,
587 tr->contents,
588 &realms,
589 &num_realms,
590 client_realm,
591 server_realm);
592 if(ret){
593 krb5_warn(context, ret,
594 "Decoding transited encoding");
595 return ret;
597 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
598 /* not us, so add the previous realm to transited set */
599 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
600 ret = ERANGE;
601 goto free_realms;
603 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
604 if(tmp == NULL){
605 ret = ENOMEM;
606 goto free_realms;
608 realms = tmp;
609 realms[num_realms] = strdup(tgt_realm);
610 if(realms[num_realms] == NULL){
611 ret = ENOMEM;
612 goto free_realms;
614 num_realms++;
616 if(num_realms == 0) {
617 if(strcmp(client_realm, server_realm))
618 kdc_log(context, config, 0,
619 "cross-realm %s -> %s", client_realm, server_realm);
620 } else {
621 size_t l = 0;
622 char *rs;
623 for(i = 0; i < num_realms; i++)
624 l += strlen(realms[i]) + 2;
625 rs = malloc(l);
626 if(rs != NULL) {
627 *rs = '\0';
628 for(i = 0; i < num_realms; i++) {
629 if(i > 0)
630 strlcat(rs, ", ", l);
631 strlcat(rs, realms[i], l);
633 kdc_log(context, config, 0,
634 "cross-realm %s -> %s via [%s]",
635 client_realm, server_realm, rs);
636 free(rs);
639 if(check_policy) {
640 ret = krb5_check_transited(context, client_realm,
641 server_realm,
642 realms, num_realms, NULL);
643 if(ret) {
644 krb5_warn(context, ret, "cross-realm %s -> %s",
645 client_realm, server_realm);
646 goto free_realms;
648 et->flags.transited_policy_checked = 1;
650 et->transited.tr_type = DOMAIN_X500_COMPRESS;
651 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
652 if(ret)
653 krb5_warn(context, ret, "Encoding transited encoding");
654 free_realms:
655 for(i = 0; i < num_realms; i++)
656 free(realms[i]);
657 free(realms);
658 return ret;
662 static krb5_error_code
663 tgs_make_reply(krb5_context context,
664 krb5_kdc_configuration *config,
665 KDC_REQ_BODY *b,
666 krb5_const_principal tgt_name,
667 const EncTicketPart *tgt,
668 const EncryptionKey *serverkey,
669 const krb5_keyblock *sessionkey,
670 krb5_kvno kvno,
671 AuthorizationData *auth_data,
672 hdb_entry_ex *server,
673 krb5_principal server_principal,
674 const char *server_name,
675 hdb_entry_ex *client,
676 krb5_principal client_principal,
677 hdb_entry_ex *krbtgt,
678 krb5_enctype krbtgt_etype,
679 krb5_principals spp,
680 const krb5_data *rspac,
681 const METHOD_DATA *enc_pa_data,
682 const char **e_text,
683 krb5_data *reply)
685 KDC_REP rep;
686 EncKDCRepPart ek;
687 EncTicketPart et;
688 KDCOptions f = b->kdc_options;
689 krb5_error_code ret;
690 int is_weak = 0;
692 memset(&rep, 0, sizeof(rep));
693 memset(&et, 0, sizeof(et));
694 memset(&ek, 0, sizeof(ek));
696 rep.pvno = 5;
697 rep.msg_type = krb_tgs_rep;
699 et.authtime = tgt->authtime;
700 _kdc_fix_time(&b->till);
701 et.endtime = min(tgt->endtime, *b->till);
702 ALLOC(et.starttime);
703 *et.starttime = kdc_time;
705 ret = check_tgs_flags(context, config, b, tgt, &et);
706 if(ret)
707 goto out;
709 /* We should check the transited encoding if:
710 1) the request doesn't ask not to be checked
711 2) globally enforcing a check
712 3) principal requires checking
713 4) we allow non-check per-principal, but principal isn't marked as allowing this
714 5) we don't globally allow this
717 #define GLOBAL_FORCE_TRANSITED_CHECK \
718 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
719 #define GLOBAL_ALLOW_PER_PRINCIPAL \
720 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
721 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
722 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
724 /* these will consult the database in future release */
725 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
726 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
728 ret = fix_transited_encoding(context, config,
729 !f.disable_transited_check ||
730 GLOBAL_FORCE_TRANSITED_CHECK ||
731 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
732 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
733 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
734 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
735 &tgt->transited, &et,
736 krb5_principal_get_realm(context, client_principal),
737 krb5_principal_get_realm(context, server->entry.principal),
738 krb5_principal_get_realm(context, krbtgt->entry.principal));
739 if(ret)
740 goto out;
742 copy_Realm(&server_principal->realm, &rep.ticket.realm);
743 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
744 copy_Realm(&tgt_name->realm, &rep.crealm);
746 if (f.request_anonymous)
747 _kdc_make_anonymous_principalname (&rep.cname);
748 else */
750 copy_PrincipalName(&tgt_name->name, &rep.cname);
751 rep.ticket.tkt_vno = 5;
753 ek.caddr = et.caddr;
754 if(et.caddr == NULL)
755 et.caddr = tgt->caddr;
758 time_t life;
759 life = et.endtime - *et.starttime;
760 if(client && client->entry.max_life)
761 life = min(life, *client->entry.max_life);
762 if(server->entry.max_life)
763 life = min(life, *server->entry.max_life);
764 et.endtime = *et.starttime + life;
766 if(f.renewable_ok && tgt->flags.renewable &&
767 et.renew_till == NULL && et.endtime < *b->till){
768 et.flags.renewable = 1;
769 ALLOC(et.renew_till);
770 *et.renew_till = *b->till;
772 if(et.renew_till){
773 time_t renew;
774 renew = *et.renew_till - et.authtime;
775 if(client && client->entry.max_renew)
776 renew = min(renew, *client->entry.max_renew);
777 if(server->entry.max_renew)
778 renew = min(renew, *server->entry.max_renew);
779 *et.renew_till = et.authtime + renew;
782 if(et.renew_till){
783 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
784 *et.starttime = min(*et.starttime, *et.renew_till);
785 et.endtime = min(et.endtime, *et.renew_till);
788 *et.starttime = min(*et.starttime, et.endtime);
790 if(*et.starttime == et.endtime){
791 ret = KRB5KDC_ERR_NEVER_VALID;
792 goto out;
794 if(et.renew_till && et.endtime == *et.renew_till){
795 free(et.renew_till);
796 et.renew_till = NULL;
797 et.flags.renewable = 0;
800 et.flags.pre_authent = tgt->flags.pre_authent;
801 et.flags.hw_authent = tgt->flags.hw_authent;
802 et.flags.anonymous = tgt->flags.anonymous;
803 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
805 if (auth_data) {
806 /* XXX Check enc-authorization-data */
807 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
808 if (et.authorization_data == NULL) {
809 ret = ENOMEM;
810 goto out;
812 ret = copy_AuthorizationData(auth_data, et.authorization_data);
813 if (ret)
814 goto out;
816 /* Filter out type KRB5SignedPath */
817 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
818 if (ret == 0) {
819 if (et.authorization_data->len == 1) {
820 free_AuthorizationData(et.authorization_data);
821 free(et.authorization_data);
822 et.authorization_data = NULL;
823 } else {
824 AuthorizationData *ad = et.authorization_data;
825 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
826 ad->len--;
831 if(rspac->length) {
833 * No not need to filter out the any PAC from the
834 * auth_data since it's signed by the KDC.
836 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
837 KRB5_AUTHDATA_WIN2K_PAC,
838 rspac);
839 if (ret)
840 goto out;
843 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
844 if (ret)
845 goto out;
846 et.crealm = tgt->crealm;
847 et.cname = tgt_name->name;
849 ek.key = et.key;
850 /* MIT must have at least one last_req */
851 ek.last_req.len = 1;
852 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
853 if (ek.last_req.val == NULL) {
854 ret = ENOMEM;
855 goto out;
857 ek.nonce = b->nonce;
858 ek.flags = et.flags;
859 ek.authtime = et.authtime;
860 ek.starttime = et.starttime;
861 ek.endtime = et.endtime;
862 ek.renew_till = et.renew_till;
863 ek.srealm = rep.ticket.realm;
864 ek.sname = rep.ticket.sname;
866 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
867 et.endtime, et.renew_till);
869 /* Don't sign cross realm tickets, they can't be checked anyway */
871 char *r = get_krbtgt_realm(&ek.sname);
873 if (r == NULL || strcmp(r, ek.srealm) == 0) {
874 ret = _kdc_add_KRB5SignedPath(context,
875 config,
876 krbtgt,
877 krbtgt_etype,
878 NULL,
879 spp,
880 &et);
881 if (ret)
882 goto out;
886 if (enc_pa_data->len) {
887 rep.padata = calloc(1, sizeof(*rep.padata));
888 if (rep.padata == NULL) {
889 ret = ENOMEM;
890 goto out;
892 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
893 if (ret)
894 goto out;
897 if (krb5_enctype_valid(context, et.key.keytype) != 0
898 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
900 krb5_enctype_enable(context, et.key.keytype);
901 is_weak = 1;
905 /* It is somewhat unclear where the etype in the following
906 encryption should come from. What we have is a session
907 key in the passed tgt, and a list of preferred etypes
908 *for the new ticket*. Should we pick the best possible
909 etype, given the keytype in the tgt, or should we look
910 at the etype list here as well? What if the tgt
911 session key is DES3 and we want a ticket with a (say)
912 CAST session key. Should the DES3 etype be added to the
913 etype list, even if we don't want a session key with
914 DES3? */
915 ret = _kdc_encode_reply(context, config,
916 &rep, &et, &ek, et.key.keytype,
917 kvno,
918 serverkey, 0, &tgt->key, e_text, reply);
919 if (is_weak)
920 krb5_enctype_disable(context, et.key.keytype);
922 out:
923 free_TGS_REP(&rep);
924 free_TransitedEncoding(&et.transited);
925 if(et.starttime)
926 free(et.starttime);
927 if(et.renew_till)
928 free(et.renew_till);
929 if(et.authorization_data) {
930 free_AuthorizationData(et.authorization_data);
931 free(et.authorization_data);
933 free_LastReq(&ek.last_req);
934 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
935 free_EncryptionKey(&et.key);
936 return ret;
939 static krb5_error_code
940 tgs_check_authenticator(krb5_context context,
941 krb5_kdc_configuration *config,
942 krb5_auth_context ac,
943 KDC_REQ_BODY *b,
944 const char **e_text,
945 krb5_keyblock *key)
947 krb5_authenticator auth;
948 size_t len;
949 unsigned char *buf;
950 size_t buf_size;
951 krb5_error_code ret;
952 krb5_crypto crypto;
954 krb5_auth_con_getauthenticator(context, ac, &auth);
955 if(auth->cksum == NULL){
956 kdc_log(context, config, 0, "No authenticator in request");
957 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
958 goto out;
961 * according to RFC1510 it doesn't need to be keyed,
962 * but according to the latest draft it needs to.
964 if (
965 #if 0
966 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
968 #endif
969 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
970 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
971 auth->cksum->cksumtype);
972 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
973 goto out;
976 /* XXX should not re-encode this */
977 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
978 if(ret){
979 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
980 krb5_get_err_text(context, ret));
981 goto out;
983 if(buf_size != len) {
984 free(buf);
985 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
986 *e_text = "KDC internal error";
987 ret = KRB5KRB_ERR_GENERIC;
988 goto out;
990 ret = krb5_crypto_init(context, key, 0, &crypto);
991 if (ret) {
992 free(buf);
993 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
994 krb5_get_err_text(context, ret));
995 goto out;
997 ret = krb5_verify_checksum(context,
998 crypto,
999 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1000 buf,
1001 len,
1002 auth->cksum);
1003 free(buf);
1004 krb5_crypto_destroy(context, crypto);
1005 if(ret){
1006 kdc_log(context, config, 0,
1007 "Failed to verify authenticator checksum: %s",
1008 krb5_get_err_text(context, ret));
1010 out:
1011 free_Authenticator(auth);
1012 free(auth);
1013 return ret;
1020 static const char *
1021 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1023 const char *new_realm = krb5_config_get_string(context,
1024 NULL,
1025 "capaths",
1026 crealm,
1027 srealm,
1028 NULL);
1029 return new_realm;
1033 static krb5_boolean
1034 need_referral(krb5_context context, krb5_kdc_configuration *config,
1035 const KDCOptions * const options, krb5_principal server,
1036 krb5_realm **realms)
1038 const char *name;
1040 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1041 return FALSE;
1043 if (server->name.name_string.len == 1)
1044 name = server->name.name_string.val[0];
1045 else if (server->name.name_string.len > 1)
1046 name = server->name.name_string.val[1];
1047 else
1048 return FALSE;
1050 kdc_log(context, config, 0, "Searching referral for %s", name);
1052 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1055 static krb5_error_code
1056 tgs_parse_request(krb5_context context,
1057 krb5_kdc_configuration *config,
1058 KDC_REQ_BODY *b,
1059 const PA_DATA *tgs_req,
1060 hdb_entry_ex **krbtgt,
1061 krb5_enctype *krbtgt_etype,
1062 krb5_ticket **ticket,
1063 const char **e_text,
1064 const char *from,
1065 const struct sockaddr *from_addr,
1066 time_t **csec,
1067 int **cusec,
1068 AuthorizationData **auth_data)
1070 krb5_ap_req ap_req;
1071 krb5_error_code ret;
1072 krb5_principal princ;
1073 krb5_auth_context ac = NULL;
1074 krb5_flags ap_req_options;
1075 krb5_flags verify_ap_req_flags;
1076 krb5_crypto crypto;
1077 Key *tkey;
1079 *auth_data = NULL;
1080 *csec = NULL;
1081 *cusec = NULL;
1083 memset(&ap_req, 0, sizeof(ap_req));
1084 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1085 if(ret){
1086 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1087 krb5_get_err_text(context, ret));
1088 goto out;
1091 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1092 /* XXX check for ticket.sname == req.sname */
1093 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1094 ret = KRB5KDC_ERR_POLICY; /* ? */
1095 goto out;
1098 _krb5_principalname2krb5_principal(context,
1099 &princ,
1100 ap_req.ticket.sname,
1101 ap_req.ticket.realm);
1103 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1105 if(ret) {
1106 char *p;
1107 ret = krb5_unparse_name(context, princ, &p);
1108 if (ret != 0)
1109 p = "<unparse_name failed>";
1110 krb5_free_principal(context, princ);
1111 kdc_log(context, config, 0,
1112 "Ticket-granting ticket not found in database: %s: %s",
1113 p, krb5_get_err_text(context, ret));
1114 if (ret == 0)
1115 free(p);
1116 ret = KRB5KRB_AP_ERR_NOT_US;
1117 goto out;
1120 if(ap_req.ticket.enc_part.kvno &&
1121 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1122 char *p;
1124 ret = krb5_unparse_name (context, princ, &p);
1125 krb5_free_principal(context, princ);
1126 if (ret != 0)
1127 p = "<unparse_name failed>";
1128 kdc_log(context, config, 0,
1129 "Ticket kvno = %d, DB kvno = %d (%s)",
1130 *ap_req.ticket.enc_part.kvno,
1131 (*krbtgt)->entry.kvno,
1133 if (ret == 0)
1134 free (p);
1135 ret = KRB5KRB_AP_ERR_BADKEYVER;
1136 goto out;
1139 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1141 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1142 ap_req.ticket.enc_part.etype, &tkey);
1143 if(ret){
1144 char *str = NULL, *p = NULL;
1146 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1147 krb5_unparse_name(context, princ, &p);
1148 kdc_log(context, config, 0,
1149 "No server key with enctype %s found for %s",
1150 str ? str : "<unknown enctype>",
1151 p ? p : "<unparse_name failed>");
1152 free(str);
1153 free(p);
1154 ret = KRB5KRB_AP_ERR_BADKEYVER;
1155 goto out;
1158 if (b->kdc_options.validate)
1159 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1160 else
1161 verify_ap_req_flags = 0;
1163 ret = krb5_verify_ap_req2(context,
1164 &ac,
1165 &ap_req,
1166 princ,
1167 &tkey->key,
1168 verify_ap_req_flags,
1169 &ap_req_options,
1170 ticket,
1171 KRB5_KU_TGS_REQ_AUTH);
1173 krb5_free_principal(context, princ);
1174 if(ret) {
1175 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1176 krb5_get_err_text(context, ret));
1177 goto out;
1181 krb5_authenticator auth;
1183 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1184 if (ret == 0) {
1185 *csec = malloc(sizeof(**csec));
1186 if (*csec == NULL) {
1187 krb5_free_authenticator(context, &auth);
1188 kdc_log(context, config, 0, "malloc failed");
1189 goto out;
1191 **csec = auth->ctime;
1192 *cusec = malloc(sizeof(**cusec));
1193 if (*cusec == NULL) {
1194 krb5_free_authenticator(context, &auth);
1195 kdc_log(context, config, 0, "malloc failed");
1196 goto out;
1198 **cusec = auth->cusec;
1199 krb5_free_authenticator(context, &auth);
1203 ret = tgs_check_authenticator(context, config,
1204 ac, b, e_text, &(*ticket)->ticket.key);
1205 if (ret) {
1206 krb5_auth_con_free(context, ac);
1207 goto out;
1210 if (b->enc_authorization_data) {
1211 unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1212 krb5_keyblock *subkey;
1213 krb5_data ad;
1215 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1216 if(ret){
1217 krb5_auth_con_free(context, ac);
1218 kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1219 krb5_get_err_text(context, ret));
1220 goto out;
1222 if(subkey == NULL){
1223 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1224 ret = krb5_auth_con_getkey(context, ac, &subkey);
1225 if(ret) {
1226 krb5_auth_con_free(context, ac);
1227 kdc_log(context, config, 0, "Failed to get session key: %s",
1228 krb5_get_err_text(context, ret));
1229 goto out;
1232 if(subkey == NULL){
1233 krb5_auth_con_free(context, ac);
1234 kdc_log(context, config, 0,
1235 "Failed to get key for enc-authorization-data");
1236 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1237 goto out;
1239 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1240 krb5_free_keyblock(context, subkey);
1241 if (ret) {
1242 krb5_auth_con_free(context, ac);
1243 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1244 krb5_get_err_text(context, ret));
1245 goto out;
1247 ret = krb5_decrypt_EncryptedData (context,
1248 crypto,
1249 usage,
1250 b->enc_authorization_data,
1251 &ad);
1252 krb5_crypto_destroy(context, crypto);
1253 if(ret){
1254 krb5_auth_con_free(context, ac);
1255 kdc_log(context, config, 0,
1256 "Failed to decrypt enc-authorization-data");
1257 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1258 goto out;
1260 ALLOC(*auth_data);
1261 if (*auth_data == NULL) {
1262 krb5_auth_con_free(context, ac);
1263 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1264 goto out;
1266 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1267 if(ret){
1268 krb5_auth_con_free(context, ac);
1269 free(*auth_data);
1270 *auth_data = NULL;
1271 kdc_log(context, config, 0, "Failed to decode authorization data");
1272 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1273 goto out;
1277 krb5_auth_con_free(context, ac);
1279 out:
1280 free_AP_REQ(&ap_req);
1282 return ret;
1285 static krb5_error_code
1286 build_server_referral(krb5_context context,
1287 krb5_kdc_configuration *config,
1288 krb5_crypto session,
1289 krb5_const_realm referred_realm,
1290 const PrincipalName *true_principal_name,
1291 const PrincipalName *requested_principal,
1292 krb5_data *outdata)
1294 PA_ServerReferralData ref;
1295 krb5_error_code ret;
1296 EncryptedData ed;
1297 krb5_data data;
1298 size_t size;
1300 memset(&ref, 0, sizeof(ref));
1302 if (referred_realm) {
1303 ALLOC(ref.referred_realm);
1304 if (ref.referred_realm == NULL)
1305 goto eout;
1306 *ref.referred_realm = strdup(referred_realm);
1307 if (*ref.referred_realm == NULL)
1308 goto eout;
1310 if (true_principal_name) {
1311 ALLOC(ref.true_principal_name);
1312 if (ref.true_principal_name == NULL)
1313 goto eout;
1314 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1315 if (ret)
1316 goto eout;
1318 if (requested_principal) {
1319 ALLOC(ref.requested_principal_name);
1320 if (ref.requested_principal_name == NULL)
1321 goto eout;
1322 ret = copy_PrincipalName(requested_principal,
1323 ref.requested_principal_name);
1324 if (ret)
1325 goto eout;
1328 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1329 data.data, data.length,
1330 &ref, &size, ret);
1331 free_PA_ServerReferralData(&ref);
1332 if (ret)
1333 return ret;
1334 if (data.length != size)
1335 krb5_abortx(context, "internal asn.1 encoder error");
1337 ret = krb5_encrypt_EncryptedData(context, session,
1338 KRB5_KU_PA_SERVER_REFERRAL,
1339 data.data, data.length,
1340 0 /* kvno */, &ed);
1341 free(data.data);
1342 if (ret)
1343 return ret;
1345 ASN1_MALLOC_ENCODE(EncryptedData,
1346 outdata->data, outdata->length,
1347 &ed, &size, ret);
1348 free_EncryptedData(&ed);
1349 if (ret)
1350 return ret;
1351 if (outdata->length != size)
1352 krb5_abortx(context, "internal asn.1 encoder error");
1354 return 0;
1355 eout:
1356 free_PA_ServerReferralData(&ref);
1357 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1358 return ENOMEM;
1361 static krb5_error_code
1362 tgs_build_reply(krb5_context context,
1363 krb5_kdc_configuration *config,
1364 KDC_REQ *req,
1365 KDC_REQ_BODY *b,
1366 hdb_entry_ex *krbtgt,
1367 krb5_enctype krbtgt_etype,
1368 krb5_ticket *ticket,
1369 krb5_data *reply,
1370 const char *from,
1371 const char **e_text,
1372 AuthorizationData **auth_data,
1373 const struct sockaddr *from_addr)
1375 krb5_error_code ret;
1376 krb5_principal cp = NULL, sp = NULL;
1377 krb5_principal client_principal = NULL;
1378 char *spn = NULL, *cpn = NULL;
1379 hdb_entry_ex *server = NULL, *client = NULL;
1380 HDB *clientdb;
1381 krb5_realm ref_realm = NULL;
1382 EncTicketPart *tgt = &ticket->ticket;
1383 krb5_principals spp = NULL;
1384 const EncryptionKey *ekey;
1385 krb5_keyblock sessionkey;
1386 krb5_kvno kvno;
1387 krb5_data rspac;
1389 METHOD_DATA enc_pa_data;
1391 PrincipalName *s;
1392 Realm r;
1393 int nloop = 0;
1394 EncTicketPart adtkt;
1395 char opt_str[128];
1396 int signedpath = 0;
1398 Key *tkey;
1400 memset(&sessionkey, 0, sizeof(sessionkey));
1401 memset(&adtkt, 0, sizeof(adtkt));
1402 krb5_data_zero(&rspac);
1403 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1405 s = b->sname;
1406 r = b->realm;
1408 if(b->kdc_options.enc_tkt_in_skey){
1409 Ticket *t;
1410 hdb_entry_ex *uu;
1411 krb5_principal p;
1412 Key *uukey;
1414 if(b->additional_tickets == NULL ||
1415 b->additional_tickets->len == 0){
1416 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1417 kdc_log(context, config, 0,
1418 "No second ticket present in request");
1419 goto out;
1421 t = &b->additional_tickets->val[0];
1422 if(!get_krbtgt_realm(&t->sname)){
1423 kdc_log(context, config, 0,
1424 "Additional ticket is not a ticket-granting ticket");
1425 ret = KRB5KDC_ERR_POLICY;
1426 goto out;
1428 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1429 ret = _kdc_db_fetch(context, config, p,
1430 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1431 NULL, &uu);
1432 krb5_free_principal(context, p);
1433 if(ret){
1434 if (ret == HDB_ERR_NOENTRY)
1435 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1436 goto out;
1438 ret = hdb_enctype2key(context, &uu->entry,
1439 t->enc_part.etype, &uukey);
1440 if(ret){
1441 _kdc_free_ent(context, uu);
1442 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1443 goto out;
1445 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1446 _kdc_free_ent(context, uu);
1447 if(ret)
1448 goto out;
1450 ret = verify_flags(context, config, &adtkt, spn);
1451 if (ret)
1452 goto out;
1454 s = &adtkt.cname;
1455 r = adtkt.crealm;
1458 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1459 ret = krb5_unparse_name(context, sp, &spn);
1460 if (ret)
1461 goto out;
1462 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1463 ret = krb5_unparse_name(context, cp, &cpn);
1464 if (ret)
1465 goto out;
1466 unparse_flags (KDCOptions2int(b->kdc_options),
1467 asn1_KDCOptions_units(),
1468 opt_str, sizeof(opt_str));
1469 if(*opt_str)
1470 kdc_log(context, config, 0,
1471 "TGS-REQ %s from %s for %s [%s]",
1472 cpn, from, spn, opt_str);
1473 else
1474 kdc_log(context, config, 0,
1475 "TGS-REQ %s from %s for %s", cpn, from, spn);
1478 * Fetch server
1481 server_lookup:
1482 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1483 NULL, &server);
1485 if(ret){
1486 const char *new_rlm;
1487 Realm req_rlm;
1488 krb5_realm *realms;
1490 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1491 if(nloop++ < 2) {
1492 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1493 if(new_rlm) {
1494 kdc_log(context, config, 5, "krbtgt for realm %s "
1495 "not found, trying %s",
1496 req_rlm, new_rlm);
1497 krb5_free_principal(context, sp);
1498 free(spn);
1499 krb5_make_principal(context, &sp, r,
1500 KRB5_TGS_NAME, new_rlm, NULL);
1501 ret = krb5_unparse_name(context, sp, &spn);
1502 if (ret)
1503 goto out;
1505 if (ref_realm)
1506 free(ref_realm);
1507 ref_realm = strdup(new_rlm);
1508 goto server_lookup;
1511 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1512 if (strcmp(realms[0], sp->realm) != 0) {
1513 kdc_log(context, config, 5,
1514 "Returning a referral to realm %s for "
1515 "server %s that was not found",
1516 realms[0], spn);
1517 krb5_free_principal(context, sp);
1518 free(spn);
1519 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1520 realms[0], NULL);
1521 ret = krb5_unparse_name(context, sp, &spn);
1522 if (ret)
1523 goto out;
1525 if (ref_realm)
1526 free(ref_realm);
1527 ref_realm = strdup(realms[0]);
1529 krb5_free_host_realm(context, realms);
1530 goto server_lookup;
1532 krb5_free_host_realm(context, realms);
1534 kdc_log(context, config, 0,
1535 "Server not found in database: %s: %s", spn,
1536 krb5_get_err_text(context, ret));
1537 if (ret == HDB_ERR_NOENTRY)
1538 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1539 goto out;
1542 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1543 &clientdb, &client);
1544 if(ret) {
1545 const char *krbtgt_realm;
1548 * If the client belongs to the same realm as our krbtgt, it
1549 * should exist in the local database.
1553 krbtgt_realm =
1554 krb5_principal_get_comp_string(context,
1555 krbtgt->entry.principal, 1);
1557 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1558 if (ret == HDB_ERR_NOENTRY)
1559 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1560 kdc_log(context, config, 1, "Client no longer in database: %s",
1561 cpn);
1562 goto out;
1565 kdc_log(context, config, 1, "Client not found in database: %s: %s",
1566 cpn, krb5_get_err_text(context, ret));
1570 * Select enctype, return key and kvno.
1574 krb5_enctype etype;
1576 if(b->kdc_options.enc_tkt_in_skey) {
1577 int i;
1578 ekey = &adtkt.key;
1579 for(i = 0; i < b->etype.len; i++)
1580 if (b->etype.val[i] == adtkt.key.keytype)
1581 break;
1582 if(i == b->etype.len) {
1583 kdc_log(context, config, 0,
1584 "Addition ticket have not matching etypes");
1585 krb5_clear_error_message(context);
1586 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1587 goto out;
1589 etype = b->etype.val[i];
1590 kvno = 0;
1591 } else {
1592 Key *skey;
1594 ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1595 &skey, &etype);
1596 if(ret) {
1597 kdc_log(context, config, 0,
1598 "Server (%s) has no support for etypes", spn);
1599 goto out;
1601 ekey = &skey->key;
1602 kvno = server->entry.kvno;
1605 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1606 if (ret)
1607 goto out;
1611 * Check that service is in the same realm as the krbtgt. If it's
1612 * not the same, it's someone that is using a uni-directional trust
1613 * backward.
1616 if (strcmp(krb5_principal_get_realm(context, sp),
1617 krb5_principal_get_comp_string(context,
1618 krbtgt->entry.principal,
1619 1)) != 0) {
1620 char *tpn;
1621 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1622 kdc_log(context, config, 0,
1623 "Request with wrong krbtgt: %s",
1624 (ret == 0) ? tpn : "<unknown>");
1625 if(ret == 0)
1626 free(tpn);
1627 ret = KRB5KRB_AP_ERR_NOT_US;
1628 goto out;
1632 * Validate authoriation data
1635 ret = hdb_enctype2key(context, &krbtgt->entry,
1636 krbtgt_etype, &tkey);
1637 if(ret) {
1638 kdc_log(context, config, 0,
1639 "Failed to find key for krbtgt PAC check");
1640 goto out;
1643 ret = check_PAC(context, config, cp,
1644 client, server, ekey, &tkey->key,
1645 tgt, &rspac, &signedpath);
1646 if (ret) {
1647 kdc_log(context, config, 0,
1648 "Verify PAC failed for %s (%s) from %s with %s",
1649 spn, cpn, from, krb5_get_err_text(context, ret));
1650 goto out;
1653 /* also check the krbtgt for signature */
1654 ret = check_KRB5SignedPath(context,
1655 config,
1656 krbtgt,
1657 tgt,
1658 &spp,
1659 &signedpath);
1660 if (ret) {
1661 kdc_log(context, config, 0,
1662 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1663 spn, cpn, from, krb5_get_err_text(context, ret));
1664 goto out;
1668 * Process request
1671 client_principal = cp;
1673 if (client) {
1674 const PA_DATA *sdata;
1675 int i = 0;
1677 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1678 if (sdata) {
1679 krb5_crypto crypto;
1680 krb5_data datack;
1681 PA_S4U2Self self;
1682 char *selfcpn = NULL;
1683 const char *str;
1685 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1686 sdata->padata_value.length,
1687 &self, NULL);
1688 if (ret) {
1689 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1690 goto out;
1693 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1694 if (ret)
1695 goto out;
1697 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1698 if (ret) {
1699 free_PA_S4U2Self(&self);
1700 krb5_data_free(&datack);
1701 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1702 krb5_get_err_text(context, ret));
1703 goto out;
1706 ret = krb5_verify_checksum(context,
1707 crypto,
1708 KRB5_KU_OTHER_CKSUM,
1709 datack.data,
1710 datack.length,
1711 &self.cksum);
1712 krb5_data_free(&datack);
1713 krb5_crypto_destroy(context, crypto);
1714 if (ret) {
1715 free_PA_S4U2Self(&self);
1716 kdc_log(context, config, 0,
1717 "krb5_verify_checksum failed for S4U2Self: %s",
1718 krb5_get_err_text(context, ret));
1719 goto out;
1722 ret = _krb5_principalname2krb5_principal(context,
1723 &client_principal,
1724 self.name,
1725 self.realm);
1726 free_PA_S4U2Self(&self);
1727 if (ret)
1728 goto out;
1730 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1731 if (ret)
1732 goto out;
1735 * Check that service doing the impersonating is
1736 * requesting a ticket to it-self.
1738 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1739 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1740 "to impersonate some other user "
1741 "(tried for user %s to service %s)",
1742 cpn, selfcpn, spn);
1743 free(selfcpn);
1744 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1745 goto out;
1749 * If the service isn't trusted for authentication to
1750 * delegation, remove the forward flag.
1753 if (client->entry.flags.trusted_for_delegation) {
1754 str = "[forwardable]";
1755 } else {
1756 b->kdc_options.forwardable = 0;
1757 str = "";
1759 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1760 "service %s %s", cpn, selfcpn, spn, str);
1761 free(selfcpn);
1766 * Constrained delegation
1769 if (client != NULL
1770 && b->additional_tickets != NULL
1771 && b->additional_tickets->len != 0
1772 && b->kdc_options.enc_tkt_in_skey == 0)
1774 int ad_signedpath = 0;
1775 Key *clientkey;
1776 Ticket *t;
1777 char *str;
1780 * Require that the KDC have issued the service's krbtgt (not
1781 * self-issued ticket with kimpersonate(1).
1783 if (!signedpath) {
1784 ret = KRB5KDC_ERR_BADOPTION;
1785 kdc_log(context, config, 0,
1786 "Constrained delegation done on service ticket %s/%s",
1787 cpn, spn);
1788 goto out;
1791 t = &b->additional_tickets->val[0];
1793 ret = hdb_enctype2key(context, &client->entry,
1794 t->enc_part.etype, &clientkey);
1795 if(ret){
1796 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1797 goto out;
1800 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1801 if (ret) {
1802 kdc_log(context, config, 0,
1803 "failed to decrypt ticket for "
1804 "constrained delegation from %s to %s ", cpn, spn);
1805 goto out;
1808 /* check that ticket is valid */
1809 if (adtkt.flags.forwardable == 0) {
1810 kdc_log(context, config, 0,
1811 "Missing forwardable flag on ticket for "
1812 "constrained delegation from %s to %s ", cpn, spn);
1813 ret = KRB5KDC_ERR_BADOPTION;
1814 goto out;
1817 ret = check_constrained_delegation(context, config, clientdb,
1818 client, sp);
1819 if (ret) {
1820 kdc_log(context, config, 0,
1821 "constrained delegation from %s to %s not allowed",
1822 cpn, spn);
1823 goto out;
1826 ret = _krb5_principalname2krb5_principal(context,
1827 &client_principal,
1828 adtkt.cname,
1829 adtkt.crealm);
1830 if (ret)
1831 goto out;
1833 ret = krb5_unparse_name(context, client_principal, &str);
1834 if (ret)
1835 goto out;
1837 ret = verify_flags(context, config, &adtkt, str);
1838 if (ret) {
1839 free(str);
1840 goto out;
1844 * Check that the KDC issued the user's ticket.
1846 ret = check_KRB5SignedPath(context,
1847 config,
1848 krbtgt,
1849 &adtkt,
1850 NULL,
1851 &ad_signedpath);
1852 if (ret == 0 && !ad_signedpath)
1853 ret = KRB5KDC_ERR_BADOPTION;
1854 if (ret) {
1855 kdc_log(context, config, 0,
1856 "KRB5SignedPath check from service %s failed "
1857 "for delegation to %s for client %s "
1858 "from %s failed with %s",
1859 spn, str, cpn, from, krb5_get_err_text(context, ret));
1860 free(str);
1861 goto out;
1864 kdc_log(context, config, 0, "constrained delegation for %s "
1865 "from %s to %s", str, cpn, spn);
1866 free(str);
1870 * Check flags
1873 ret = kdc_check_flags(context, config,
1874 client, cpn,
1875 server, spn,
1876 FALSE);
1877 if(ret)
1878 goto out;
1880 if((b->kdc_options.validate || b->kdc_options.renew) &&
1881 !krb5_principal_compare(context,
1882 krbtgt->entry.principal,
1883 server->entry.principal)){
1884 kdc_log(context, config, 0, "Inconsistent request.");
1885 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1886 goto out;
1889 /* check for valid set of addresses */
1890 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1891 ret = KRB5KRB_AP_ERR_BADADDR;
1892 kdc_log(context, config, 0, "Request from wrong address");
1893 goto out;
1897 * If this is an referral, add server referral data to the
1898 * auth_data reply .
1900 if (ref_realm) {
1901 PA_DATA pa;
1902 krb5_crypto crypto;
1904 kdc_log(context, config, 0,
1905 "Adding server referral to %s", ref_realm);
1907 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1908 if (ret)
1909 goto out;
1911 ret = build_server_referral(context, config, crypto, ref_realm,
1912 NULL, s, &pa.padata_value);
1913 krb5_crypto_destroy(context, crypto);
1914 if (ret) {
1915 kdc_log(context, config, 0,
1916 "Failed building server referral");
1917 goto out;
1919 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1921 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1922 krb5_data_free(&pa.padata_value);
1923 if (ret) {
1924 kdc_log(context, config, 0,
1925 "Add server referral METHOD-DATA failed");
1926 goto out;
1934 ret = tgs_make_reply(context,
1935 config,
1937 client_principal,
1938 tgt,
1939 ekey,
1940 &sessionkey,
1941 kvno,
1942 *auth_data,
1943 server,
1945 spn,
1946 client,
1948 krbtgt,
1949 krbtgt_etype,
1950 spp,
1951 &rspac,
1952 &enc_pa_data,
1953 e_text,
1954 reply);
1956 out:
1957 free(spn);
1958 free(cpn);
1960 krb5_data_free(&rspac);
1961 krb5_free_keyblock_contents(context, &sessionkey);
1962 if(server)
1963 _kdc_free_ent(context, server);
1964 if(client)
1965 _kdc_free_ent(context, client);
1967 if (client_principal && client_principal != cp)
1968 krb5_free_principal(context, client_principal);
1969 if (cp)
1970 krb5_free_principal(context, cp);
1971 if (sp)
1972 krb5_free_principal(context, sp);
1973 if (ref_realm)
1974 free(ref_realm);
1975 free_METHOD_DATA(&enc_pa_data);
1977 free_EncTicketPart(&adtkt);
1979 return ret;
1986 krb5_error_code
1987 _kdc_tgs_rep(krb5_context context,
1988 krb5_kdc_configuration *config,
1989 KDC_REQ *req,
1990 krb5_data *data,
1991 const char *from,
1992 struct sockaddr *from_addr,
1993 int datagram_reply)
1995 AuthorizationData *auth_data = NULL;
1996 krb5_error_code ret;
1997 int i = 0;
1998 const PA_DATA *tgs_req;
2000 hdb_entry_ex *krbtgt = NULL;
2001 krb5_ticket *ticket = NULL;
2002 const char *e_text = NULL;
2003 krb5_enctype krbtgt_etype = ETYPE_NULL;
2005 time_t *csec = NULL;
2006 int *cusec = NULL;
2008 if(req->padata == NULL){
2009 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2010 kdc_log(context, config, 0,
2011 "TGS-REQ from %s without PA-DATA", from);
2012 goto out;
2015 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2017 if(tgs_req == NULL){
2018 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2020 kdc_log(context, config, 0,
2021 "TGS-REQ from %s without PA-TGS-REQ", from);
2022 goto out;
2024 ret = tgs_parse_request(context, config,
2025 &req->req_body, tgs_req,
2026 &krbtgt,
2027 &krbtgt_etype,
2028 &ticket,
2029 &e_text,
2030 from, from_addr,
2031 &csec, &cusec,
2032 &auth_data);
2033 if (ret) {
2034 kdc_log(context, config, 0,
2035 "Failed parsing TGS-REQ from %s", from);
2036 goto out;
2039 ret = tgs_build_reply(context,
2040 config,
2041 req,
2042 &req->req_body,
2043 krbtgt,
2044 krbtgt_etype,
2045 ticket,
2046 data,
2047 from,
2048 &e_text,
2049 &auth_data,
2050 from_addr);
2051 if (ret) {
2052 kdc_log(context, config, 0,
2053 "Failed building TGS-REP to %s", from);
2054 goto out;
2057 /* */
2058 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2059 krb5_data_free(data);
2060 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2061 e_text = "Reply packet too large";
2064 out:
2065 if(ret && data->data == NULL){
2066 krb5_mk_error(context,
2067 ret,
2068 NULL,
2069 NULL,
2070 NULL,
2071 NULL,
2072 csec,
2073 cusec,
2074 data);
2076 free(csec);
2077 free(cusec);
2078 if (ticket)
2079 krb5_free_ticket(context, ticket);
2080 if(krbtgt)
2081 _kdc_free_ent(context, krbtgt);
2083 if (auth_data) {
2084 free_AuthorizationData(auth_data);
2085 free(auth_data);
2088 return 0;