Include ec*.h files
[heimdal.git] / kdc / krb5tgs.c
blob635eb27e75aa6cf8e14731c6d921f751a98f7360
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 client delegates to itself, that ok */
504 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
505 return 0;
507 if (clientdb->hdb_check_constrained_delegation) {
508 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
509 if (ret == 0)
510 return 0;
511 } else {
512 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
513 if (ret) {
514 krb5_clear_error_message(context);
515 return ret;
518 if (acl) {
519 for (i = 0; i < acl->len; i++) {
520 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
521 return 0;
524 ret = KRB5KDC_ERR_BADOPTION;
526 kdc_log(context, config, 0,
527 "Bad request for constrained delegation");
528 return ret;
535 static krb5_error_code
536 verify_flags (krb5_context context,
537 krb5_kdc_configuration *config,
538 const EncTicketPart *et,
539 const char *pstr)
541 if(et->endtime < kdc_time){
542 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
543 return KRB5KRB_AP_ERR_TKT_EXPIRED;
545 if(et->flags.invalid){
546 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
547 return KRB5KRB_AP_ERR_TKT_NYV;
549 return 0;
556 static krb5_error_code
557 fix_transited_encoding(krb5_context context,
558 krb5_kdc_configuration *config,
559 krb5_boolean check_policy,
560 const TransitedEncoding *tr,
561 EncTicketPart *et,
562 const char *client_realm,
563 const char *server_realm,
564 const char *tgt_realm)
566 krb5_error_code ret = 0;
567 char **realms, **tmp;
568 unsigned int num_realms;
569 int i;
571 switch (tr->tr_type) {
572 case DOMAIN_X500_COMPRESS:
573 break;
574 case 0:
576 * Allow empty content of type 0 because that is was Microsoft
577 * generates in their TGT.
579 if (tr->contents.length == 0)
580 break;
581 kdc_log(context, config, 0,
582 "Transited type 0 with non empty content");
583 return KRB5KDC_ERR_TRTYPE_NOSUPP;
584 default:
585 kdc_log(context, config, 0,
586 "Unknown transited type: %u", tr->tr_type);
587 return KRB5KDC_ERR_TRTYPE_NOSUPP;
590 ret = krb5_domain_x500_decode(context,
591 tr->contents,
592 &realms,
593 &num_realms,
594 client_realm,
595 server_realm);
596 if(ret){
597 krb5_warn(context, ret,
598 "Decoding transited encoding");
599 return ret;
601 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
602 /* not us, so add the previous realm to transited set */
603 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
604 ret = ERANGE;
605 goto free_realms;
607 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
608 if(tmp == NULL){
609 ret = ENOMEM;
610 goto free_realms;
612 realms = tmp;
613 realms[num_realms] = strdup(tgt_realm);
614 if(realms[num_realms] == NULL){
615 ret = ENOMEM;
616 goto free_realms;
618 num_realms++;
620 if(num_realms == 0) {
621 if(strcmp(client_realm, server_realm))
622 kdc_log(context, config, 0,
623 "cross-realm %s -> %s", client_realm, server_realm);
624 } else {
625 size_t l = 0;
626 char *rs;
627 for(i = 0; i < num_realms; i++)
628 l += strlen(realms[i]) + 2;
629 rs = malloc(l);
630 if(rs != NULL) {
631 *rs = '\0';
632 for(i = 0; i < num_realms; i++) {
633 if(i > 0)
634 strlcat(rs, ", ", l);
635 strlcat(rs, realms[i], l);
637 kdc_log(context, config, 0,
638 "cross-realm %s -> %s via [%s]",
639 client_realm, server_realm, rs);
640 free(rs);
643 if(check_policy) {
644 ret = krb5_check_transited(context, client_realm,
645 server_realm,
646 realms, num_realms, NULL);
647 if(ret) {
648 krb5_warn(context, ret, "cross-realm %s -> %s",
649 client_realm, server_realm);
650 goto free_realms;
652 et->flags.transited_policy_checked = 1;
654 et->transited.tr_type = DOMAIN_X500_COMPRESS;
655 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
656 if(ret)
657 krb5_warn(context, ret, "Encoding transited encoding");
658 free_realms:
659 for(i = 0; i < num_realms; i++)
660 free(realms[i]);
661 free(realms);
662 return ret;
666 static krb5_error_code
667 tgs_make_reply(krb5_context context,
668 krb5_kdc_configuration *config,
669 KDC_REQ_BODY *b,
670 krb5_const_principal tgt_name,
671 const EncTicketPart *tgt,
672 const EncryptionKey *serverkey,
673 const krb5_keyblock *sessionkey,
674 krb5_kvno kvno,
675 AuthorizationData *auth_data,
676 hdb_entry_ex *server,
677 krb5_principal server_principal,
678 const char *server_name,
679 hdb_entry_ex *client,
680 krb5_principal client_principal,
681 hdb_entry_ex *krbtgt,
682 krb5_enctype krbtgt_etype,
683 krb5_principals spp,
684 const krb5_data *rspac,
685 const METHOD_DATA *enc_pa_data,
686 const char **e_text,
687 krb5_data *reply)
689 KDC_REP rep;
690 EncKDCRepPart ek;
691 EncTicketPart et;
692 KDCOptions f = b->kdc_options;
693 krb5_error_code ret;
694 int is_weak = 0;
696 memset(&rep, 0, sizeof(rep));
697 memset(&et, 0, sizeof(et));
698 memset(&ek, 0, sizeof(ek));
700 rep.pvno = 5;
701 rep.msg_type = krb_tgs_rep;
703 et.authtime = tgt->authtime;
704 _kdc_fix_time(&b->till);
705 et.endtime = min(tgt->endtime, *b->till);
706 ALLOC(et.starttime);
707 *et.starttime = kdc_time;
709 ret = check_tgs_flags(context, config, b, tgt, &et);
710 if(ret)
711 goto out;
713 /* We should check the transited encoding if:
714 1) the request doesn't ask not to be checked
715 2) globally enforcing a check
716 3) principal requires checking
717 4) we allow non-check per-principal, but principal isn't marked as allowing this
718 5) we don't globally allow this
721 #define GLOBAL_FORCE_TRANSITED_CHECK \
722 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
723 #define GLOBAL_ALLOW_PER_PRINCIPAL \
724 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
725 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
726 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
728 /* these will consult the database in future release */
729 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
730 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
732 ret = fix_transited_encoding(context, config,
733 !f.disable_transited_check ||
734 GLOBAL_FORCE_TRANSITED_CHECK ||
735 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
736 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
737 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
738 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
739 &tgt->transited, &et,
740 krb5_principal_get_realm(context, client_principal),
741 krb5_principal_get_realm(context, server->entry.principal),
742 krb5_principal_get_realm(context, krbtgt->entry.principal));
743 if(ret)
744 goto out;
746 copy_Realm(&server_principal->realm, &rep.ticket.realm);
747 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
748 copy_Realm(&tgt_name->realm, &rep.crealm);
750 if (f.request_anonymous)
751 _kdc_make_anonymous_principalname (&rep.cname);
752 else */
754 copy_PrincipalName(&tgt_name->name, &rep.cname);
755 rep.ticket.tkt_vno = 5;
757 ek.caddr = et.caddr;
758 if(et.caddr == NULL)
759 et.caddr = tgt->caddr;
762 time_t life;
763 life = et.endtime - *et.starttime;
764 if(client && client->entry.max_life)
765 life = min(life, *client->entry.max_life);
766 if(server->entry.max_life)
767 life = min(life, *server->entry.max_life);
768 et.endtime = *et.starttime + life;
770 if(f.renewable_ok && tgt->flags.renewable &&
771 et.renew_till == NULL && et.endtime < *b->till){
772 et.flags.renewable = 1;
773 ALLOC(et.renew_till);
774 *et.renew_till = *b->till;
776 if(et.renew_till){
777 time_t renew;
778 renew = *et.renew_till - et.authtime;
779 if(client && client->entry.max_renew)
780 renew = min(renew, *client->entry.max_renew);
781 if(server->entry.max_renew)
782 renew = min(renew, *server->entry.max_renew);
783 *et.renew_till = et.authtime + renew;
786 if(et.renew_till){
787 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
788 *et.starttime = min(*et.starttime, *et.renew_till);
789 et.endtime = min(et.endtime, *et.renew_till);
792 *et.starttime = min(*et.starttime, et.endtime);
794 if(*et.starttime == et.endtime){
795 ret = KRB5KDC_ERR_NEVER_VALID;
796 goto out;
798 if(et.renew_till && et.endtime == *et.renew_till){
799 free(et.renew_till);
800 et.renew_till = NULL;
801 et.flags.renewable = 0;
804 et.flags.pre_authent = tgt->flags.pre_authent;
805 et.flags.hw_authent = tgt->flags.hw_authent;
806 et.flags.anonymous = tgt->flags.anonymous;
807 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
809 if(rspac->length) {
811 * No not need to filter out the any PAC from the
812 * auth_data since it's signed by the KDC.
814 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
815 KRB5_AUTHDATA_WIN2K_PAC, rspac);
816 if (ret)
817 goto out;
820 if (auth_data) {
821 unsigned int i = 0;
823 /* XXX check authdata */
824 if (et.authorization_data == NULL) {
825 ret = ENOMEM;
826 krb5_set_error_message(context, ret, "malloc: out of memory");
827 goto out;
829 for(i = 0; i < auth_data->len ; i++) {
830 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
831 if (ret) {
832 krb5_set_error_message(context, ret, "malloc: out of memory");
833 goto out;
837 /* Filter out type KRB5SignedPath */
838 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
839 if (ret == 0) {
840 if (et.authorization_data->len == 1) {
841 free_AuthorizationData(et.authorization_data);
842 free(et.authorization_data);
843 et.authorization_data = NULL;
844 } else {
845 AuthorizationData *ad = et.authorization_data;
846 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
847 ad->len--;
852 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
853 if (ret)
854 goto out;
855 et.crealm = tgt->crealm;
856 et.cname = tgt_name->name;
858 ek.key = et.key;
859 /* MIT must have at least one last_req */
860 ek.last_req.len = 1;
861 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
862 if (ek.last_req.val == NULL) {
863 ret = ENOMEM;
864 goto out;
866 ek.nonce = b->nonce;
867 ek.flags = et.flags;
868 ek.authtime = et.authtime;
869 ek.starttime = et.starttime;
870 ek.endtime = et.endtime;
871 ek.renew_till = et.renew_till;
872 ek.srealm = rep.ticket.realm;
873 ek.sname = rep.ticket.sname;
875 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
876 et.endtime, et.renew_till);
878 /* Don't sign cross realm tickets, they can't be checked anyway */
880 char *r = get_krbtgt_realm(&ek.sname);
882 if (r == NULL || strcmp(r, ek.srealm) == 0) {
883 ret = _kdc_add_KRB5SignedPath(context,
884 config,
885 krbtgt,
886 krbtgt_etype,
887 NULL,
888 spp,
889 &et);
890 if (ret)
891 goto out;
895 if (enc_pa_data->len) {
896 rep.padata = calloc(1, sizeof(*rep.padata));
897 if (rep.padata == NULL) {
898 ret = ENOMEM;
899 goto out;
901 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
902 if (ret)
903 goto out;
906 if (krb5_enctype_valid(context, et.key.keytype) != 0
907 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
909 krb5_enctype_enable(context, et.key.keytype);
910 is_weak = 1;
914 /* It is somewhat unclear where the etype in the following
915 encryption should come from. What we have is a session
916 key in the passed tgt, and a list of preferred etypes
917 *for the new ticket*. Should we pick the best possible
918 etype, given the keytype in the tgt, or should we look
919 at the etype list here as well? What if the tgt
920 session key is DES3 and we want a ticket with a (say)
921 CAST session key. Should the DES3 etype be added to the
922 etype list, even if we don't want a session key with
923 DES3? */
924 ret = _kdc_encode_reply(context, config,
925 &rep, &et, &ek, et.key.keytype,
926 kvno,
927 serverkey, 0, &tgt->key, e_text, reply);
928 if (is_weak)
929 krb5_enctype_disable(context, et.key.keytype);
931 out:
932 free_TGS_REP(&rep);
933 free_TransitedEncoding(&et.transited);
934 if(et.starttime)
935 free(et.starttime);
936 if(et.renew_till)
937 free(et.renew_till);
938 if(et.authorization_data) {
939 free_AuthorizationData(et.authorization_data);
940 free(et.authorization_data);
942 free_LastReq(&ek.last_req);
943 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
944 free_EncryptionKey(&et.key);
945 return ret;
948 static krb5_error_code
949 tgs_check_authenticator(krb5_context context,
950 krb5_kdc_configuration *config,
951 krb5_auth_context ac,
952 KDC_REQ_BODY *b,
953 const char **e_text,
954 krb5_keyblock *key)
956 krb5_authenticator auth;
957 size_t len;
958 unsigned char *buf;
959 size_t buf_size;
960 krb5_error_code ret;
961 krb5_crypto crypto;
963 krb5_auth_con_getauthenticator(context, ac, &auth);
964 if(auth->cksum == NULL){
965 kdc_log(context, config, 0, "No authenticator in request");
966 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
967 goto out;
970 * according to RFC1510 it doesn't need to be keyed,
971 * but according to the latest draft it needs to.
973 if (
974 #if 0
975 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
977 #endif
978 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
979 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
980 auth->cksum->cksumtype);
981 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
982 goto out;
985 /* XXX should not re-encode this */
986 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
987 if(ret){
988 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
989 krb5_get_err_text(context, ret));
990 goto out;
992 if(buf_size != len) {
993 free(buf);
994 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
995 *e_text = "KDC internal error";
996 ret = KRB5KRB_ERR_GENERIC;
997 goto out;
999 ret = krb5_crypto_init(context, key, 0, &crypto);
1000 if (ret) {
1001 free(buf);
1002 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1003 krb5_get_err_text(context, ret));
1004 goto out;
1006 ret = krb5_verify_checksum(context,
1007 crypto,
1008 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1009 buf,
1010 len,
1011 auth->cksum);
1012 free(buf);
1013 krb5_crypto_destroy(context, crypto);
1014 if(ret){
1015 kdc_log(context, config, 0,
1016 "Failed to verify authenticator checksum: %s",
1017 krb5_get_err_text(context, ret));
1019 out:
1020 free_Authenticator(auth);
1021 free(auth);
1022 return ret;
1029 static const char *
1030 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1032 const char *new_realm = krb5_config_get_string(context,
1033 NULL,
1034 "capaths",
1035 crealm,
1036 srealm,
1037 NULL);
1038 return new_realm;
1042 static krb5_boolean
1043 need_referral(krb5_context context, krb5_kdc_configuration *config,
1044 const KDCOptions * const options, krb5_principal server,
1045 krb5_realm **realms)
1047 const char *name;
1049 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1050 return FALSE;
1052 if (server->name.name_string.len == 1)
1053 name = server->name.name_string.val[0];
1054 else if (server->name.name_string.len > 1)
1055 name = server->name.name_string.val[1];
1056 else
1057 return FALSE;
1059 kdc_log(context, config, 0, "Searching referral for %s", name);
1061 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1064 static krb5_error_code
1065 tgs_parse_request(krb5_context context,
1066 krb5_kdc_configuration *config,
1067 KDC_REQ_BODY *b,
1068 const PA_DATA *tgs_req,
1069 hdb_entry_ex **krbtgt,
1070 krb5_enctype *krbtgt_etype,
1071 krb5_ticket **ticket,
1072 const char **e_text,
1073 const char *from,
1074 const struct sockaddr *from_addr,
1075 time_t **csec,
1076 int **cusec,
1077 AuthorizationData **auth_data)
1079 krb5_ap_req ap_req;
1080 krb5_error_code ret;
1081 krb5_principal princ;
1082 krb5_auth_context ac = NULL;
1083 krb5_flags ap_req_options;
1084 krb5_flags verify_ap_req_flags;
1085 krb5_crypto crypto;
1086 Key *tkey;
1088 *auth_data = NULL;
1089 *csec = NULL;
1090 *cusec = NULL;
1092 memset(&ap_req, 0, sizeof(ap_req));
1093 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1094 if(ret){
1095 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1096 krb5_get_err_text(context, ret));
1097 goto out;
1100 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1101 /* XXX check for ticket.sname == req.sname */
1102 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1103 ret = KRB5KDC_ERR_POLICY; /* ? */
1104 goto out;
1107 _krb5_principalname2krb5_principal(context,
1108 &princ,
1109 ap_req.ticket.sname,
1110 ap_req.ticket.realm);
1112 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1114 if(ret) {
1115 char *p;
1116 ret = krb5_unparse_name(context, princ, &p);
1117 if (ret != 0)
1118 p = "<unparse_name failed>";
1119 krb5_free_principal(context, princ);
1120 kdc_log(context, config, 0,
1121 "Ticket-granting ticket not found in database: %s: %s",
1122 p, krb5_get_err_text(context, ret));
1123 if (ret == 0)
1124 free(p);
1125 ret = KRB5KRB_AP_ERR_NOT_US;
1126 goto out;
1129 if(ap_req.ticket.enc_part.kvno &&
1130 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1131 char *p;
1133 ret = krb5_unparse_name (context, princ, &p);
1134 krb5_free_principal(context, princ);
1135 if (ret != 0)
1136 p = "<unparse_name failed>";
1137 kdc_log(context, config, 0,
1138 "Ticket kvno = %d, DB kvno = %d (%s)",
1139 *ap_req.ticket.enc_part.kvno,
1140 (*krbtgt)->entry.kvno,
1142 if (ret == 0)
1143 free (p);
1144 ret = KRB5KRB_AP_ERR_BADKEYVER;
1145 goto out;
1148 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1150 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1151 ap_req.ticket.enc_part.etype, &tkey);
1152 if(ret){
1153 char *str = NULL, *p = NULL;
1155 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1156 krb5_unparse_name(context, princ, &p);
1157 kdc_log(context, config, 0,
1158 "No server key with enctype %s found for %s",
1159 str ? str : "<unknown enctype>",
1160 p ? p : "<unparse_name failed>");
1161 free(str);
1162 free(p);
1163 ret = KRB5KRB_AP_ERR_BADKEYVER;
1164 goto out;
1167 if (b->kdc_options.validate)
1168 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1169 else
1170 verify_ap_req_flags = 0;
1172 ret = krb5_verify_ap_req2(context,
1173 &ac,
1174 &ap_req,
1175 princ,
1176 &tkey->key,
1177 verify_ap_req_flags,
1178 &ap_req_options,
1179 ticket,
1180 KRB5_KU_TGS_REQ_AUTH);
1182 krb5_free_principal(context, princ);
1183 if(ret) {
1184 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1185 krb5_get_err_text(context, ret));
1186 goto out;
1190 krb5_authenticator auth;
1192 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1193 if (ret == 0) {
1194 *csec = malloc(sizeof(**csec));
1195 if (*csec == NULL) {
1196 krb5_free_authenticator(context, &auth);
1197 kdc_log(context, config, 0, "malloc failed");
1198 goto out;
1200 **csec = auth->ctime;
1201 *cusec = malloc(sizeof(**cusec));
1202 if (*cusec == NULL) {
1203 krb5_free_authenticator(context, &auth);
1204 kdc_log(context, config, 0, "malloc failed");
1205 goto out;
1207 **cusec = auth->cusec;
1208 krb5_free_authenticator(context, &auth);
1212 ret = tgs_check_authenticator(context, config,
1213 ac, b, e_text, &(*ticket)->ticket.key);
1214 if (ret) {
1215 krb5_auth_con_free(context, ac);
1216 goto out;
1219 if (b->enc_authorization_data) {
1220 unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1221 krb5_keyblock *subkey;
1222 krb5_data ad;
1224 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1225 if(ret){
1226 krb5_auth_con_free(context, ac);
1227 kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1228 krb5_get_err_text(context, ret));
1229 goto out;
1231 if(subkey == NULL){
1232 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1233 ret = krb5_auth_con_getkey(context, ac, &subkey);
1234 if(ret) {
1235 krb5_auth_con_free(context, ac);
1236 kdc_log(context, config, 0, "Failed to get session key: %s",
1237 krb5_get_err_text(context, ret));
1238 goto out;
1241 if(subkey == NULL){
1242 krb5_auth_con_free(context, ac);
1243 kdc_log(context, config, 0,
1244 "Failed to get key for enc-authorization-data");
1245 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1246 goto out;
1248 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1249 krb5_free_keyblock(context, subkey);
1250 if (ret) {
1251 krb5_auth_con_free(context, ac);
1252 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1253 krb5_get_err_text(context, ret));
1254 goto out;
1256 ret = krb5_decrypt_EncryptedData (context,
1257 crypto,
1258 usage,
1259 b->enc_authorization_data,
1260 &ad);
1261 krb5_crypto_destroy(context, crypto);
1262 if(ret){
1263 krb5_auth_con_free(context, ac);
1264 kdc_log(context, config, 0,
1265 "Failed to decrypt enc-authorization-data");
1266 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1267 goto out;
1269 ALLOC(*auth_data);
1270 if (*auth_data == NULL) {
1271 krb5_auth_con_free(context, ac);
1272 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1273 goto out;
1275 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1276 if(ret){
1277 krb5_auth_con_free(context, ac);
1278 free(*auth_data);
1279 *auth_data = NULL;
1280 kdc_log(context, config, 0, "Failed to decode authorization data");
1281 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1282 goto out;
1286 krb5_auth_con_free(context, ac);
1288 out:
1289 free_AP_REQ(&ap_req);
1291 return ret;
1294 static krb5_error_code
1295 build_server_referral(krb5_context context,
1296 krb5_kdc_configuration *config,
1297 krb5_crypto session,
1298 krb5_const_realm referred_realm,
1299 const PrincipalName *true_principal_name,
1300 const PrincipalName *requested_principal,
1301 krb5_data *outdata)
1303 PA_ServerReferralData ref;
1304 krb5_error_code ret;
1305 EncryptedData ed;
1306 krb5_data data;
1307 size_t size;
1309 memset(&ref, 0, sizeof(ref));
1311 if (referred_realm) {
1312 ALLOC(ref.referred_realm);
1313 if (ref.referred_realm == NULL)
1314 goto eout;
1315 *ref.referred_realm = strdup(referred_realm);
1316 if (*ref.referred_realm == NULL)
1317 goto eout;
1319 if (true_principal_name) {
1320 ALLOC(ref.true_principal_name);
1321 if (ref.true_principal_name == NULL)
1322 goto eout;
1323 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1324 if (ret)
1325 goto eout;
1327 if (requested_principal) {
1328 ALLOC(ref.requested_principal_name);
1329 if (ref.requested_principal_name == NULL)
1330 goto eout;
1331 ret = copy_PrincipalName(requested_principal,
1332 ref.requested_principal_name);
1333 if (ret)
1334 goto eout;
1337 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1338 data.data, data.length,
1339 &ref, &size, ret);
1340 free_PA_ServerReferralData(&ref);
1341 if (ret)
1342 return ret;
1343 if (data.length != size)
1344 krb5_abortx(context, "internal asn.1 encoder error");
1346 ret = krb5_encrypt_EncryptedData(context, session,
1347 KRB5_KU_PA_SERVER_REFERRAL,
1348 data.data, data.length,
1349 0 /* kvno */, &ed);
1350 free(data.data);
1351 if (ret)
1352 return ret;
1354 ASN1_MALLOC_ENCODE(EncryptedData,
1355 outdata->data, outdata->length,
1356 &ed, &size, ret);
1357 free_EncryptedData(&ed);
1358 if (ret)
1359 return ret;
1360 if (outdata->length != size)
1361 krb5_abortx(context, "internal asn.1 encoder error");
1363 return 0;
1364 eout:
1365 free_PA_ServerReferralData(&ref);
1366 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1367 return ENOMEM;
1370 static krb5_error_code
1371 tgs_build_reply(krb5_context context,
1372 krb5_kdc_configuration *config,
1373 KDC_REQ *req,
1374 KDC_REQ_BODY *b,
1375 hdb_entry_ex *krbtgt,
1376 krb5_enctype krbtgt_etype,
1377 krb5_ticket *ticket,
1378 krb5_data *reply,
1379 const char *from,
1380 const char **e_text,
1381 AuthorizationData **auth_data,
1382 const struct sockaddr *from_addr)
1384 krb5_error_code ret;
1385 krb5_principal cp = NULL, sp = NULL;
1386 krb5_principal client_principal = NULL;
1387 char *spn = NULL, *cpn = NULL;
1388 hdb_entry_ex *server = NULL, *client = NULL;
1389 HDB *clientdb;
1390 krb5_realm ref_realm = NULL;
1391 EncTicketPart *tgt = &ticket->ticket;
1392 krb5_principals spp = NULL;
1393 const EncryptionKey *ekey;
1394 krb5_keyblock sessionkey;
1395 krb5_kvno kvno;
1396 krb5_data rspac;
1398 METHOD_DATA enc_pa_data;
1400 PrincipalName *s;
1401 Realm r;
1402 int nloop = 0;
1403 EncTicketPart adtkt;
1404 char opt_str[128];
1405 int signedpath = 0;
1407 Key *tkey;
1409 memset(&sessionkey, 0, sizeof(sessionkey));
1410 memset(&adtkt, 0, sizeof(adtkt));
1411 krb5_data_zero(&rspac);
1412 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1414 s = b->sname;
1415 r = b->realm;
1417 if(b->kdc_options.enc_tkt_in_skey){
1418 Ticket *t;
1419 hdb_entry_ex *uu;
1420 krb5_principal p;
1421 Key *uukey;
1423 if(b->additional_tickets == NULL ||
1424 b->additional_tickets->len == 0){
1425 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1426 kdc_log(context, config, 0,
1427 "No second ticket present in request");
1428 goto out;
1430 t = &b->additional_tickets->val[0];
1431 if(!get_krbtgt_realm(&t->sname)){
1432 kdc_log(context, config, 0,
1433 "Additional ticket is not a ticket-granting ticket");
1434 ret = KRB5KDC_ERR_POLICY;
1435 goto out;
1437 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1438 ret = _kdc_db_fetch(context, config, p,
1439 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1440 NULL, &uu);
1441 krb5_free_principal(context, p);
1442 if(ret){
1443 if (ret == HDB_ERR_NOENTRY)
1444 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1445 goto out;
1447 ret = hdb_enctype2key(context, &uu->entry,
1448 t->enc_part.etype, &uukey);
1449 if(ret){
1450 _kdc_free_ent(context, uu);
1451 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1452 goto out;
1454 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1455 _kdc_free_ent(context, uu);
1456 if(ret)
1457 goto out;
1459 ret = verify_flags(context, config, &adtkt, spn);
1460 if (ret)
1461 goto out;
1463 s = &adtkt.cname;
1464 r = adtkt.crealm;
1467 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1468 ret = krb5_unparse_name(context, sp, &spn);
1469 if (ret)
1470 goto out;
1471 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1472 ret = krb5_unparse_name(context, cp, &cpn);
1473 if (ret)
1474 goto out;
1475 unparse_flags (KDCOptions2int(b->kdc_options),
1476 asn1_KDCOptions_units(),
1477 opt_str, sizeof(opt_str));
1478 if(*opt_str)
1479 kdc_log(context, config, 0,
1480 "TGS-REQ %s from %s for %s [%s]",
1481 cpn, from, spn, opt_str);
1482 else
1483 kdc_log(context, config, 0,
1484 "TGS-REQ %s from %s for %s", cpn, from, spn);
1487 * Fetch server
1490 server_lookup:
1491 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1492 NULL, &server);
1494 if(ret){
1495 const char *new_rlm;
1496 Realm req_rlm;
1497 krb5_realm *realms;
1499 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1500 if(nloop++ < 2) {
1501 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1502 if(new_rlm) {
1503 kdc_log(context, config, 5, "krbtgt for realm %s "
1504 "not found, trying %s",
1505 req_rlm, new_rlm);
1506 krb5_free_principal(context, sp);
1507 free(spn);
1508 krb5_make_principal(context, &sp, r,
1509 KRB5_TGS_NAME, new_rlm, NULL);
1510 ret = krb5_unparse_name(context, sp, &spn);
1511 if (ret)
1512 goto out;
1514 if (ref_realm)
1515 free(ref_realm);
1516 ref_realm = strdup(new_rlm);
1517 goto server_lookup;
1520 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1521 if (strcmp(realms[0], sp->realm) != 0) {
1522 kdc_log(context, config, 5,
1523 "Returning a referral to realm %s for "
1524 "server %s that was not found",
1525 realms[0], spn);
1526 krb5_free_principal(context, sp);
1527 free(spn);
1528 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1529 realms[0], NULL);
1530 ret = krb5_unparse_name(context, sp, &spn);
1531 if (ret)
1532 goto out;
1534 if (ref_realm)
1535 free(ref_realm);
1536 ref_realm = strdup(realms[0]);
1538 krb5_free_host_realm(context, realms);
1539 goto server_lookup;
1541 krb5_free_host_realm(context, realms);
1543 kdc_log(context, config, 0,
1544 "Server not found in database: %s: %s", spn,
1545 krb5_get_err_text(context, ret));
1546 if (ret == HDB_ERR_NOENTRY)
1547 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1548 goto out;
1551 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1552 &clientdb, &client);
1553 if(ret) {
1554 const char *krbtgt_realm;
1557 * If the client belongs to the same realm as our krbtgt, it
1558 * should exist in the local database.
1562 krbtgt_realm =
1563 krb5_principal_get_comp_string(context,
1564 krbtgt->entry.principal, 1);
1566 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1567 if (ret == HDB_ERR_NOENTRY)
1568 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1569 kdc_log(context, config, 1, "Client no longer in database: %s",
1570 cpn);
1571 goto out;
1574 kdc_log(context, config, 1, "Client not found in database: %s: %s",
1575 cpn, krb5_get_err_text(context, ret));
1579 * Select enctype, return key and kvno.
1583 krb5_enctype etype;
1585 if(b->kdc_options.enc_tkt_in_skey) {
1586 int i;
1587 ekey = &adtkt.key;
1588 for(i = 0; i < b->etype.len; i++)
1589 if (b->etype.val[i] == adtkt.key.keytype)
1590 break;
1591 if(i == b->etype.len) {
1592 kdc_log(context, config, 0,
1593 "Addition ticket have not matching etypes");
1594 krb5_clear_error_message(context);
1595 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1596 goto out;
1598 etype = b->etype.val[i];
1599 kvno = 0;
1600 } else {
1601 Key *skey;
1603 ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1604 &skey, &etype);
1605 if(ret) {
1606 kdc_log(context, config, 0,
1607 "Server (%s) has no support for etypes", spn);
1608 goto out;
1610 ekey = &skey->key;
1611 kvno = server->entry.kvno;
1614 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1615 if (ret)
1616 goto out;
1620 * Check that service is in the same realm as the krbtgt. If it's
1621 * not the same, it's someone that is using a uni-directional trust
1622 * backward.
1625 if (strcmp(krb5_principal_get_realm(context, sp),
1626 krb5_principal_get_comp_string(context,
1627 krbtgt->entry.principal,
1628 1)) != 0) {
1629 char *tpn;
1630 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1631 kdc_log(context, config, 0,
1632 "Request with wrong krbtgt: %s",
1633 (ret == 0) ? tpn : "<unknown>");
1634 if(ret == 0)
1635 free(tpn);
1636 ret = KRB5KRB_AP_ERR_NOT_US;
1637 goto out;
1641 * Validate authoriation data
1644 ret = hdb_enctype2key(context, &krbtgt->entry,
1645 krbtgt_etype, &tkey);
1646 if(ret) {
1647 kdc_log(context, config, 0,
1648 "Failed to find key for krbtgt PAC check");
1649 goto out;
1652 ret = check_PAC(context, config, cp,
1653 client, server, ekey, &tkey->key,
1654 tgt, &rspac, &signedpath);
1655 if (ret) {
1656 kdc_log(context, config, 0,
1657 "Verify PAC failed for %s (%s) from %s with %s",
1658 spn, cpn, from, krb5_get_err_text(context, ret));
1659 goto out;
1662 /* also check the krbtgt for signature */
1663 ret = check_KRB5SignedPath(context,
1664 config,
1665 krbtgt,
1666 tgt,
1667 &spp,
1668 &signedpath);
1669 if (ret) {
1670 kdc_log(context, config, 0,
1671 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1672 spn, cpn, from, krb5_get_err_text(context, ret));
1673 goto out;
1677 * Process request
1680 client_principal = cp;
1682 if (client) {
1683 const PA_DATA *sdata;
1684 int i = 0;
1686 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1687 if (sdata) {
1688 krb5_crypto crypto;
1689 krb5_data datack;
1690 PA_S4U2Self self;
1691 char *selfcpn = NULL;
1692 const char *str;
1694 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1695 sdata->padata_value.length,
1696 &self, NULL);
1697 if (ret) {
1698 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1699 goto out;
1702 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1703 if (ret)
1704 goto out;
1706 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1707 if (ret) {
1708 free_PA_S4U2Self(&self);
1709 krb5_data_free(&datack);
1710 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1711 krb5_get_err_text(context, ret));
1712 goto out;
1715 ret = krb5_verify_checksum(context,
1716 crypto,
1717 KRB5_KU_OTHER_CKSUM,
1718 datack.data,
1719 datack.length,
1720 &self.cksum);
1721 krb5_data_free(&datack);
1722 krb5_crypto_destroy(context, crypto);
1723 if (ret) {
1724 free_PA_S4U2Self(&self);
1725 kdc_log(context, config, 0,
1726 "krb5_verify_checksum failed for S4U2Self: %s",
1727 krb5_get_err_text(context, ret));
1728 goto out;
1731 ret = _krb5_principalname2krb5_principal(context,
1732 &client_principal,
1733 self.name,
1734 self.realm);
1735 free_PA_S4U2Self(&self);
1736 if (ret)
1737 goto out;
1739 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1740 if (ret)
1741 goto out;
1744 * Check that service doing the impersonating is
1745 * requesting a ticket to it-self.
1747 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1748 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1749 "to impersonate some other user "
1750 "(tried for user %s to service %s)",
1751 cpn, selfcpn, spn);
1752 free(selfcpn);
1753 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1754 goto out;
1758 * If the service isn't trusted for authentication to
1759 * delegation, remove the forward flag.
1762 if (client->entry.flags.trusted_for_delegation) {
1763 str = "[forwardable]";
1764 } else {
1765 b->kdc_options.forwardable = 0;
1766 str = "";
1768 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1769 "service %s %s", cpn, selfcpn, spn, str);
1770 free(selfcpn);
1775 * Constrained delegation
1778 if (client != NULL
1779 && b->additional_tickets != NULL
1780 && b->additional_tickets->len != 0
1781 && b->kdc_options.enc_tkt_in_skey == 0)
1783 int ad_signedpath = 0;
1784 Key *clientkey;
1785 Ticket *t;
1786 char *str;
1789 * Require that the KDC have issued the service's krbtgt (not
1790 * self-issued ticket with kimpersonate(1).
1792 if (!signedpath) {
1793 ret = KRB5KDC_ERR_BADOPTION;
1794 kdc_log(context, config, 0,
1795 "Constrained delegation done on service ticket %s/%s",
1796 cpn, spn);
1797 goto out;
1800 t = &b->additional_tickets->val[0];
1802 ret = hdb_enctype2key(context, &client->entry,
1803 t->enc_part.etype, &clientkey);
1804 if(ret){
1805 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1806 goto out;
1809 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1810 if (ret) {
1811 kdc_log(context, config, 0,
1812 "failed to decrypt ticket for "
1813 "constrained delegation from %s to %s ", cpn, spn);
1814 goto out;
1817 /* check that ticket is valid */
1818 if (adtkt.flags.forwardable == 0) {
1819 kdc_log(context, config, 0,
1820 "Missing forwardable flag on ticket for "
1821 "constrained delegation from %s to %s ", cpn, spn);
1822 ret = KRB5KDC_ERR_BADOPTION;
1823 goto out;
1826 ret = check_constrained_delegation(context, config, clientdb,
1827 client, sp);
1828 if (ret) {
1829 kdc_log(context, config, 0,
1830 "constrained delegation from %s to %s not allowed",
1831 cpn, spn);
1832 goto out;
1835 ret = _krb5_principalname2krb5_principal(context,
1836 &client_principal,
1837 adtkt.cname,
1838 adtkt.crealm);
1839 if (ret)
1840 goto out;
1842 ret = krb5_unparse_name(context, client_principal, &str);
1843 if (ret)
1844 goto out;
1846 ret = verify_flags(context, config, &adtkt, str);
1847 if (ret) {
1848 free(str);
1849 goto out;
1853 * Check that the KDC issued the user's ticket.
1855 ret = check_KRB5SignedPath(context,
1856 config,
1857 krbtgt,
1858 &adtkt,
1859 NULL,
1860 &ad_signedpath);
1861 if (ret == 0 && !ad_signedpath)
1862 ret = KRB5KDC_ERR_BADOPTION;
1863 if (ret) {
1864 kdc_log(context, config, 0,
1865 "KRB5SignedPath check from service %s failed "
1866 "for delegation to %s for client %s "
1867 "from %s failed with %s",
1868 spn, str, cpn, from, krb5_get_err_text(context, ret));
1869 free(str);
1870 goto out;
1873 kdc_log(context, config, 0, "constrained delegation for %s "
1874 "from %s to %s", str, cpn, spn);
1875 free(str);
1879 * Check flags
1882 ret = kdc_check_flags(context, config,
1883 client, cpn,
1884 server, spn,
1885 FALSE);
1886 if(ret)
1887 goto out;
1889 if((b->kdc_options.validate || b->kdc_options.renew) &&
1890 !krb5_principal_compare(context,
1891 krbtgt->entry.principal,
1892 server->entry.principal)){
1893 kdc_log(context, config, 0, "Inconsistent request.");
1894 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1895 goto out;
1898 /* check for valid set of addresses */
1899 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1900 ret = KRB5KRB_AP_ERR_BADADDR;
1901 kdc_log(context, config, 0, "Request from wrong address");
1902 goto out;
1906 * If this is an referral, add server referral data to the
1907 * auth_data reply .
1909 if (ref_realm) {
1910 PA_DATA pa;
1911 krb5_crypto crypto;
1913 kdc_log(context, config, 0,
1914 "Adding server referral to %s", ref_realm);
1916 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1917 if (ret)
1918 goto out;
1920 ret = build_server_referral(context, config, crypto, ref_realm,
1921 NULL, s, &pa.padata_value);
1922 krb5_crypto_destroy(context, crypto);
1923 if (ret) {
1924 kdc_log(context, config, 0,
1925 "Failed building server referral");
1926 goto out;
1928 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1930 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1931 krb5_data_free(&pa.padata_value);
1932 if (ret) {
1933 kdc_log(context, config, 0,
1934 "Add server referral METHOD-DATA failed");
1935 goto out;
1943 ret = tgs_make_reply(context,
1944 config,
1946 client_principal,
1947 tgt,
1948 ekey,
1949 &sessionkey,
1950 kvno,
1951 *auth_data,
1952 server,
1954 spn,
1955 client,
1957 krbtgt,
1958 krbtgt_etype,
1959 spp,
1960 &rspac,
1961 &enc_pa_data,
1962 e_text,
1963 reply);
1965 out:
1966 free(spn);
1967 free(cpn);
1969 krb5_data_free(&rspac);
1970 krb5_free_keyblock_contents(context, &sessionkey);
1971 if(server)
1972 _kdc_free_ent(context, server);
1973 if(client)
1974 _kdc_free_ent(context, client);
1976 if (client_principal && client_principal != cp)
1977 krb5_free_principal(context, client_principal);
1978 if (cp)
1979 krb5_free_principal(context, cp);
1980 if (sp)
1981 krb5_free_principal(context, sp);
1982 if (ref_realm)
1983 free(ref_realm);
1984 free_METHOD_DATA(&enc_pa_data);
1986 free_EncTicketPart(&adtkt);
1988 return ret;
1995 krb5_error_code
1996 _kdc_tgs_rep(krb5_context context,
1997 krb5_kdc_configuration *config,
1998 KDC_REQ *req,
1999 krb5_data *data,
2000 const char *from,
2001 struct sockaddr *from_addr,
2002 int datagram_reply)
2004 AuthorizationData *auth_data = NULL;
2005 krb5_error_code ret;
2006 int i = 0;
2007 const PA_DATA *tgs_req;
2009 hdb_entry_ex *krbtgt = NULL;
2010 krb5_ticket *ticket = NULL;
2011 const char *e_text = NULL;
2012 krb5_enctype krbtgt_etype = ETYPE_NULL;
2014 time_t *csec = NULL;
2015 int *cusec = NULL;
2017 if(req->padata == NULL){
2018 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2019 kdc_log(context, config, 0,
2020 "TGS-REQ from %s without PA-DATA", from);
2021 goto out;
2024 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2026 if(tgs_req == NULL){
2027 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2029 kdc_log(context, config, 0,
2030 "TGS-REQ from %s without PA-TGS-REQ", from);
2031 goto out;
2033 ret = tgs_parse_request(context, config,
2034 &req->req_body, tgs_req,
2035 &krbtgt,
2036 &krbtgt_etype,
2037 &ticket,
2038 &e_text,
2039 from, from_addr,
2040 &csec, &cusec,
2041 &auth_data);
2042 if (ret) {
2043 kdc_log(context, config, 0,
2044 "Failed parsing TGS-REQ from %s", from);
2045 goto out;
2048 ret = tgs_build_reply(context,
2049 config,
2050 req,
2051 &req->req_body,
2052 krbtgt,
2053 krbtgt_etype,
2054 ticket,
2055 data,
2056 from,
2057 &e_text,
2058 &auth_data,
2059 from_addr);
2060 if (ret) {
2061 kdc_log(context, config, 0,
2062 "Failed building TGS-REP to %s", from);
2063 goto out;
2066 /* */
2067 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2068 krb5_data_free(data);
2069 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2070 e_text = "Reply packet too large";
2073 out:
2074 if(ret && data->data == NULL){
2075 krb5_mk_error(context,
2076 ret,
2077 NULL,
2078 NULL,
2079 NULL,
2080 NULL,
2081 csec,
2082 cusec,
2083 data);
2085 free(csec);
2086 free(cusec);
2087 if (ticket)
2088 krb5_free_ticket(context, ticket);
2089 if(krbtgt)
2090 _kdc_free_ent(context, krbtgt);
2092 if (auth_data) {
2093 free_AuthorizationData(auth_data);
2094 free(auth_data);
2097 return 0;