make compile
[heimdal.git] / kdc / krb5tgs.c
blob6b98506e81caa2cda4207be9481065f02bfe6cab
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 (auth_data) {
810 /* XXX Check enc-authorization-data */
811 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
812 if (et.authorization_data == NULL) {
813 ret = ENOMEM;
814 goto out;
816 ret = copy_AuthorizationData(auth_data, et.authorization_data);
817 if (ret)
818 goto out;
820 /* Filter out type KRB5SignedPath */
821 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
822 if (ret == 0) {
823 if (et.authorization_data->len == 1) {
824 free_AuthorizationData(et.authorization_data);
825 free(et.authorization_data);
826 et.authorization_data = NULL;
827 } else {
828 AuthorizationData *ad = et.authorization_data;
829 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
830 ad->len--;
835 if(rspac->length) {
837 * No not need to filter out the any PAC from the
838 * auth_data since it's signed by the KDC.
840 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
841 KRB5_AUTHDATA_WIN2K_PAC,
842 rspac);
843 if (ret)
844 goto out;
847 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
848 if (ret)
849 goto out;
850 et.crealm = tgt->crealm;
851 et.cname = tgt_name->name;
853 ek.key = et.key;
854 /* MIT must have at least one last_req */
855 ek.last_req.len = 1;
856 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
857 if (ek.last_req.val == NULL) {
858 ret = ENOMEM;
859 goto out;
861 ek.nonce = b->nonce;
862 ek.flags = et.flags;
863 ek.authtime = et.authtime;
864 ek.starttime = et.starttime;
865 ek.endtime = et.endtime;
866 ek.renew_till = et.renew_till;
867 ek.srealm = rep.ticket.realm;
868 ek.sname = rep.ticket.sname;
870 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
871 et.endtime, et.renew_till);
873 /* Don't sign cross realm tickets, they can't be checked anyway */
875 char *r = get_krbtgt_realm(&ek.sname);
877 if (r == NULL || strcmp(r, ek.srealm) == 0) {
878 ret = _kdc_add_KRB5SignedPath(context,
879 config,
880 krbtgt,
881 krbtgt_etype,
882 NULL,
883 spp,
884 &et);
885 if (ret)
886 goto out;
890 if (enc_pa_data->len) {
891 rep.padata = calloc(1, sizeof(*rep.padata));
892 if (rep.padata == NULL) {
893 ret = ENOMEM;
894 goto out;
896 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
897 if (ret)
898 goto out;
901 if (krb5_enctype_valid(context, et.key.keytype) != 0
902 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
904 krb5_enctype_enable(context, et.key.keytype);
905 is_weak = 1;
909 /* It is somewhat unclear where the etype in the following
910 encryption should come from. What we have is a session
911 key in the passed tgt, and a list of preferred etypes
912 *for the new ticket*. Should we pick the best possible
913 etype, given the keytype in the tgt, or should we look
914 at the etype list here as well? What if the tgt
915 session key is DES3 and we want a ticket with a (say)
916 CAST session key. Should the DES3 etype be added to the
917 etype list, even if we don't want a session key with
918 DES3? */
919 ret = _kdc_encode_reply(context, config,
920 &rep, &et, &ek, et.key.keytype,
921 kvno,
922 serverkey, 0, &tgt->key, e_text, reply);
923 if (is_weak)
924 krb5_enctype_disable(context, et.key.keytype);
926 out:
927 free_TGS_REP(&rep);
928 free_TransitedEncoding(&et.transited);
929 if(et.starttime)
930 free(et.starttime);
931 if(et.renew_till)
932 free(et.renew_till);
933 if(et.authorization_data) {
934 free_AuthorizationData(et.authorization_data);
935 free(et.authorization_data);
937 free_LastReq(&ek.last_req);
938 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
939 free_EncryptionKey(&et.key);
940 return ret;
943 static krb5_error_code
944 tgs_check_authenticator(krb5_context context,
945 krb5_kdc_configuration *config,
946 krb5_auth_context ac,
947 KDC_REQ_BODY *b,
948 const char **e_text,
949 krb5_keyblock *key)
951 krb5_authenticator auth;
952 size_t len;
953 unsigned char *buf;
954 size_t buf_size;
955 krb5_error_code ret;
956 krb5_crypto crypto;
958 krb5_auth_con_getauthenticator(context, ac, &auth);
959 if(auth->cksum == NULL){
960 kdc_log(context, config, 0, "No authenticator in request");
961 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
962 goto out;
965 * according to RFC1510 it doesn't need to be keyed,
966 * but according to the latest draft it needs to.
968 if (
969 #if 0
970 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
972 #endif
973 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
974 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
975 auth->cksum->cksumtype);
976 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
977 goto out;
980 /* XXX should not re-encode this */
981 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
982 if(ret){
983 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
984 krb5_get_err_text(context, ret));
985 goto out;
987 if(buf_size != len) {
988 free(buf);
989 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
990 *e_text = "KDC internal error";
991 ret = KRB5KRB_ERR_GENERIC;
992 goto out;
994 ret = krb5_crypto_init(context, key, 0, &crypto);
995 if (ret) {
996 free(buf);
997 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
998 krb5_get_err_text(context, ret));
999 goto out;
1001 ret = krb5_verify_checksum(context,
1002 crypto,
1003 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1004 buf,
1005 len,
1006 auth->cksum);
1007 free(buf);
1008 krb5_crypto_destroy(context, crypto);
1009 if(ret){
1010 kdc_log(context, config, 0,
1011 "Failed to verify authenticator checksum: %s",
1012 krb5_get_err_text(context, ret));
1014 out:
1015 free_Authenticator(auth);
1016 free(auth);
1017 return ret;
1024 static const char *
1025 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1027 const char *new_realm = krb5_config_get_string(context,
1028 NULL,
1029 "capaths",
1030 crealm,
1031 srealm,
1032 NULL);
1033 return new_realm;
1037 static krb5_boolean
1038 need_referral(krb5_context context, krb5_kdc_configuration *config,
1039 const KDCOptions * const options, krb5_principal server,
1040 krb5_realm **realms)
1042 const char *name;
1044 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1045 return FALSE;
1047 if (server->name.name_string.len == 1)
1048 name = server->name.name_string.val[0];
1049 else if (server->name.name_string.len > 1)
1050 name = server->name.name_string.val[1];
1051 else
1052 return FALSE;
1054 kdc_log(context, config, 0, "Searching referral for %s", name);
1056 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1059 static krb5_error_code
1060 tgs_parse_request(krb5_context context,
1061 krb5_kdc_configuration *config,
1062 KDC_REQ_BODY *b,
1063 const PA_DATA *tgs_req,
1064 hdb_entry_ex **krbtgt,
1065 krb5_enctype *krbtgt_etype,
1066 krb5_ticket **ticket,
1067 const char **e_text,
1068 const char *from,
1069 const struct sockaddr *from_addr,
1070 time_t **csec,
1071 int **cusec,
1072 AuthorizationData **auth_data)
1074 krb5_ap_req ap_req;
1075 krb5_error_code ret;
1076 krb5_principal princ;
1077 krb5_auth_context ac = NULL;
1078 krb5_flags ap_req_options;
1079 krb5_flags verify_ap_req_flags;
1080 krb5_crypto crypto;
1081 Key *tkey;
1083 *auth_data = NULL;
1084 *csec = NULL;
1085 *cusec = NULL;
1087 memset(&ap_req, 0, sizeof(ap_req));
1088 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1089 if(ret){
1090 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1091 krb5_get_err_text(context, ret));
1092 goto out;
1095 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1096 /* XXX check for ticket.sname == req.sname */
1097 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1098 ret = KRB5KDC_ERR_POLICY; /* ? */
1099 goto out;
1102 _krb5_principalname2krb5_principal(context,
1103 &princ,
1104 ap_req.ticket.sname,
1105 ap_req.ticket.realm);
1107 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1109 if(ret) {
1110 char *p;
1111 ret = krb5_unparse_name(context, princ, &p);
1112 if (ret != 0)
1113 p = "<unparse_name failed>";
1114 krb5_free_principal(context, princ);
1115 kdc_log(context, config, 0,
1116 "Ticket-granting ticket not found in database: %s: %s",
1117 p, krb5_get_err_text(context, ret));
1118 if (ret == 0)
1119 free(p);
1120 ret = KRB5KRB_AP_ERR_NOT_US;
1121 goto out;
1124 if(ap_req.ticket.enc_part.kvno &&
1125 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1126 char *p;
1128 ret = krb5_unparse_name (context, princ, &p);
1129 krb5_free_principal(context, princ);
1130 if (ret != 0)
1131 p = "<unparse_name failed>";
1132 kdc_log(context, config, 0,
1133 "Ticket kvno = %d, DB kvno = %d (%s)",
1134 *ap_req.ticket.enc_part.kvno,
1135 (*krbtgt)->entry.kvno,
1137 if (ret == 0)
1138 free (p);
1139 ret = KRB5KRB_AP_ERR_BADKEYVER;
1140 goto out;
1143 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1145 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1146 ap_req.ticket.enc_part.etype, &tkey);
1147 if(ret){
1148 char *str = NULL, *p = NULL;
1150 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1151 krb5_unparse_name(context, princ, &p);
1152 kdc_log(context, config, 0,
1153 "No server key with enctype %s found for %s",
1154 str ? str : "<unknown enctype>",
1155 p ? p : "<unparse_name failed>");
1156 free(str);
1157 free(p);
1158 ret = KRB5KRB_AP_ERR_BADKEYVER;
1159 goto out;
1162 if (b->kdc_options.validate)
1163 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1164 else
1165 verify_ap_req_flags = 0;
1167 ret = krb5_verify_ap_req2(context,
1168 &ac,
1169 &ap_req,
1170 princ,
1171 &tkey->key,
1172 verify_ap_req_flags,
1173 &ap_req_options,
1174 ticket,
1175 KRB5_KU_TGS_REQ_AUTH);
1177 krb5_free_principal(context, princ);
1178 if(ret) {
1179 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1180 krb5_get_err_text(context, ret));
1181 goto out;
1185 krb5_authenticator auth;
1187 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1188 if (ret == 0) {
1189 *csec = malloc(sizeof(**csec));
1190 if (*csec == NULL) {
1191 krb5_free_authenticator(context, &auth);
1192 kdc_log(context, config, 0, "malloc failed");
1193 goto out;
1195 **csec = auth->ctime;
1196 *cusec = malloc(sizeof(**cusec));
1197 if (*cusec == NULL) {
1198 krb5_free_authenticator(context, &auth);
1199 kdc_log(context, config, 0, "malloc failed");
1200 goto out;
1202 **cusec = auth->cusec;
1203 krb5_free_authenticator(context, &auth);
1207 ret = tgs_check_authenticator(context, config,
1208 ac, b, e_text, &(*ticket)->ticket.key);
1209 if (ret) {
1210 krb5_auth_con_free(context, ac);
1211 goto out;
1214 if (b->enc_authorization_data) {
1215 unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1216 krb5_keyblock *subkey;
1217 krb5_data ad;
1219 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1220 if(ret){
1221 krb5_auth_con_free(context, ac);
1222 kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1223 krb5_get_err_text(context, ret));
1224 goto out;
1226 if(subkey == NULL){
1227 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1228 ret = krb5_auth_con_getkey(context, ac, &subkey);
1229 if(ret) {
1230 krb5_auth_con_free(context, ac);
1231 kdc_log(context, config, 0, "Failed to get session key: %s",
1232 krb5_get_err_text(context, ret));
1233 goto out;
1236 if(subkey == NULL){
1237 krb5_auth_con_free(context, ac);
1238 kdc_log(context, config, 0,
1239 "Failed to get key for enc-authorization-data");
1240 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1241 goto out;
1243 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1244 krb5_free_keyblock(context, subkey);
1245 if (ret) {
1246 krb5_auth_con_free(context, ac);
1247 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1248 krb5_get_err_text(context, ret));
1249 goto out;
1251 ret = krb5_decrypt_EncryptedData (context,
1252 crypto,
1253 usage,
1254 b->enc_authorization_data,
1255 &ad);
1256 krb5_crypto_destroy(context, crypto);
1257 if(ret){
1258 krb5_auth_con_free(context, ac);
1259 kdc_log(context, config, 0,
1260 "Failed to decrypt enc-authorization-data");
1261 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1262 goto out;
1264 ALLOC(*auth_data);
1265 if (*auth_data == NULL) {
1266 krb5_auth_con_free(context, ac);
1267 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1268 goto out;
1270 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1271 if(ret){
1272 krb5_auth_con_free(context, ac);
1273 free(*auth_data);
1274 *auth_data = NULL;
1275 kdc_log(context, config, 0, "Failed to decode authorization data");
1276 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1277 goto out;
1281 krb5_auth_con_free(context, ac);
1283 out:
1284 free_AP_REQ(&ap_req);
1286 return ret;
1289 static krb5_error_code
1290 build_server_referral(krb5_context context,
1291 krb5_kdc_configuration *config,
1292 krb5_crypto session,
1293 krb5_const_realm referred_realm,
1294 const PrincipalName *true_principal_name,
1295 const PrincipalName *requested_principal,
1296 krb5_data *outdata)
1298 PA_ServerReferralData ref;
1299 krb5_error_code ret;
1300 EncryptedData ed;
1301 krb5_data data;
1302 size_t size;
1304 memset(&ref, 0, sizeof(ref));
1306 if (referred_realm) {
1307 ALLOC(ref.referred_realm);
1308 if (ref.referred_realm == NULL)
1309 goto eout;
1310 *ref.referred_realm = strdup(referred_realm);
1311 if (*ref.referred_realm == NULL)
1312 goto eout;
1314 if (true_principal_name) {
1315 ALLOC(ref.true_principal_name);
1316 if (ref.true_principal_name == NULL)
1317 goto eout;
1318 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1319 if (ret)
1320 goto eout;
1322 if (requested_principal) {
1323 ALLOC(ref.requested_principal_name);
1324 if (ref.requested_principal_name == NULL)
1325 goto eout;
1326 ret = copy_PrincipalName(requested_principal,
1327 ref.requested_principal_name);
1328 if (ret)
1329 goto eout;
1332 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1333 data.data, data.length,
1334 &ref, &size, ret);
1335 free_PA_ServerReferralData(&ref);
1336 if (ret)
1337 return ret;
1338 if (data.length != size)
1339 krb5_abortx(context, "internal asn.1 encoder error");
1341 ret = krb5_encrypt_EncryptedData(context, session,
1342 KRB5_KU_PA_SERVER_REFERRAL,
1343 data.data, data.length,
1344 0 /* kvno */, &ed);
1345 free(data.data);
1346 if (ret)
1347 return ret;
1349 ASN1_MALLOC_ENCODE(EncryptedData,
1350 outdata->data, outdata->length,
1351 &ed, &size, ret);
1352 free_EncryptedData(&ed);
1353 if (ret)
1354 return ret;
1355 if (outdata->length != size)
1356 krb5_abortx(context, "internal asn.1 encoder error");
1358 return 0;
1359 eout:
1360 free_PA_ServerReferralData(&ref);
1361 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1362 return ENOMEM;
1365 static krb5_error_code
1366 tgs_build_reply(krb5_context context,
1367 krb5_kdc_configuration *config,
1368 KDC_REQ *req,
1369 KDC_REQ_BODY *b,
1370 hdb_entry_ex *krbtgt,
1371 krb5_enctype krbtgt_etype,
1372 krb5_ticket *ticket,
1373 krb5_data *reply,
1374 const char *from,
1375 const char **e_text,
1376 AuthorizationData **auth_data,
1377 const struct sockaddr *from_addr)
1379 krb5_error_code ret;
1380 krb5_principal cp = NULL, sp = NULL;
1381 krb5_principal client_principal = NULL;
1382 char *spn = NULL, *cpn = NULL;
1383 hdb_entry_ex *server = NULL, *client = NULL;
1384 HDB *clientdb;
1385 krb5_realm ref_realm = NULL;
1386 EncTicketPart *tgt = &ticket->ticket;
1387 krb5_principals spp = NULL;
1388 const EncryptionKey *ekey;
1389 krb5_keyblock sessionkey;
1390 krb5_kvno kvno;
1391 krb5_data rspac;
1393 METHOD_DATA enc_pa_data;
1395 PrincipalName *s;
1396 Realm r;
1397 int nloop = 0;
1398 EncTicketPart adtkt;
1399 char opt_str[128];
1400 int signedpath = 0;
1402 Key *tkey;
1404 memset(&sessionkey, 0, sizeof(sessionkey));
1405 memset(&adtkt, 0, sizeof(adtkt));
1406 krb5_data_zero(&rspac);
1407 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1409 s = b->sname;
1410 r = b->realm;
1412 if(b->kdc_options.enc_tkt_in_skey){
1413 Ticket *t;
1414 hdb_entry_ex *uu;
1415 krb5_principal p;
1416 Key *uukey;
1418 if(b->additional_tickets == NULL ||
1419 b->additional_tickets->len == 0){
1420 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1421 kdc_log(context, config, 0,
1422 "No second ticket present in request");
1423 goto out;
1425 t = &b->additional_tickets->val[0];
1426 if(!get_krbtgt_realm(&t->sname)){
1427 kdc_log(context, config, 0,
1428 "Additional ticket is not a ticket-granting ticket");
1429 ret = KRB5KDC_ERR_POLICY;
1430 goto out;
1432 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1433 ret = _kdc_db_fetch(context, config, p,
1434 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1435 NULL, &uu);
1436 krb5_free_principal(context, p);
1437 if(ret){
1438 if (ret == HDB_ERR_NOENTRY)
1439 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1440 goto out;
1442 ret = hdb_enctype2key(context, &uu->entry,
1443 t->enc_part.etype, &uukey);
1444 if(ret){
1445 _kdc_free_ent(context, uu);
1446 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1447 goto out;
1449 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1450 _kdc_free_ent(context, uu);
1451 if(ret)
1452 goto out;
1454 ret = verify_flags(context, config, &adtkt, spn);
1455 if (ret)
1456 goto out;
1458 s = &adtkt.cname;
1459 r = adtkt.crealm;
1462 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1463 ret = krb5_unparse_name(context, sp, &spn);
1464 if (ret)
1465 goto out;
1466 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1467 ret = krb5_unparse_name(context, cp, &cpn);
1468 if (ret)
1469 goto out;
1470 unparse_flags (KDCOptions2int(b->kdc_options),
1471 asn1_KDCOptions_units(),
1472 opt_str, sizeof(opt_str));
1473 if(*opt_str)
1474 kdc_log(context, config, 0,
1475 "TGS-REQ %s from %s for %s [%s]",
1476 cpn, from, spn, opt_str);
1477 else
1478 kdc_log(context, config, 0,
1479 "TGS-REQ %s from %s for %s", cpn, from, spn);
1482 * Fetch server
1485 server_lookup:
1486 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1487 NULL, &server);
1489 if(ret){
1490 const char *new_rlm;
1491 Realm req_rlm;
1492 krb5_realm *realms;
1494 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1495 if(nloop++ < 2) {
1496 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1497 if(new_rlm) {
1498 kdc_log(context, config, 5, "krbtgt for realm %s "
1499 "not found, trying %s",
1500 req_rlm, new_rlm);
1501 krb5_free_principal(context, sp);
1502 free(spn);
1503 krb5_make_principal(context, &sp, r,
1504 KRB5_TGS_NAME, new_rlm, NULL);
1505 ret = krb5_unparse_name(context, sp, &spn);
1506 if (ret)
1507 goto out;
1509 if (ref_realm)
1510 free(ref_realm);
1511 ref_realm = strdup(new_rlm);
1512 goto server_lookup;
1515 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1516 if (strcmp(realms[0], sp->realm) != 0) {
1517 kdc_log(context, config, 5,
1518 "Returning a referral to realm %s for "
1519 "server %s that was not found",
1520 realms[0], spn);
1521 krb5_free_principal(context, sp);
1522 free(spn);
1523 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1524 realms[0], NULL);
1525 ret = krb5_unparse_name(context, sp, &spn);
1526 if (ret)
1527 goto out;
1529 if (ref_realm)
1530 free(ref_realm);
1531 ref_realm = strdup(realms[0]);
1533 krb5_free_host_realm(context, realms);
1534 goto server_lookup;
1536 krb5_free_host_realm(context, realms);
1538 kdc_log(context, config, 0,
1539 "Server not found in database: %s: %s", spn,
1540 krb5_get_err_text(context, ret));
1541 if (ret == HDB_ERR_NOENTRY)
1542 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1543 goto out;
1546 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1547 &clientdb, &client);
1548 if(ret) {
1549 const char *krbtgt_realm;
1552 * If the client belongs to the same realm as our krbtgt, it
1553 * should exist in the local database.
1557 krbtgt_realm =
1558 krb5_principal_get_comp_string(context,
1559 krbtgt->entry.principal, 1);
1561 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1562 if (ret == HDB_ERR_NOENTRY)
1563 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1564 kdc_log(context, config, 1, "Client no longer in database: %s",
1565 cpn);
1566 goto out;
1569 kdc_log(context, config, 1, "Client not found in database: %s: %s",
1570 cpn, krb5_get_err_text(context, ret));
1574 * Select enctype, return key and kvno.
1578 krb5_enctype etype;
1580 if(b->kdc_options.enc_tkt_in_skey) {
1581 int i;
1582 ekey = &adtkt.key;
1583 for(i = 0; i < b->etype.len; i++)
1584 if (b->etype.val[i] == adtkt.key.keytype)
1585 break;
1586 if(i == b->etype.len) {
1587 kdc_log(context, config, 0,
1588 "Addition ticket have not matching etypes");
1589 krb5_clear_error_message(context);
1590 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1591 goto out;
1593 etype = b->etype.val[i];
1594 kvno = 0;
1595 } else {
1596 Key *skey;
1598 ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1599 &skey, &etype);
1600 if(ret) {
1601 kdc_log(context, config, 0,
1602 "Server (%s) has no support for etypes", spn);
1603 goto out;
1605 ekey = &skey->key;
1606 kvno = server->entry.kvno;
1609 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1610 if (ret)
1611 goto out;
1615 * Check that service is in the same realm as the krbtgt. If it's
1616 * not the same, it's someone that is using a uni-directional trust
1617 * backward.
1620 if (strcmp(krb5_principal_get_realm(context, sp),
1621 krb5_principal_get_comp_string(context,
1622 krbtgt->entry.principal,
1623 1)) != 0) {
1624 char *tpn;
1625 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1626 kdc_log(context, config, 0,
1627 "Request with wrong krbtgt: %s",
1628 (ret == 0) ? tpn : "<unknown>");
1629 if(ret == 0)
1630 free(tpn);
1631 ret = KRB5KRB_AP_ERR_NOT_US;
1632 goto out;
1636 * Validate authoriation data
1639 ret = hdb_enctype2key(context, &krbtgt->entry,
1640 krbtgt_etype, &tkey);
1641 if(ret) {
1642 kdc_log(context, config, 0,
1643 "Failed to find key for krbtgt PAC check");
1644 goto out;
1647 ret = check_PAC(context, config, cp,
1648 client, server, ekey, &tkey->key,
1649 tgt, &rspac, &signedpath);
1650 if (ret) {
1651 kdc_log(context, config, 0,
1652 "Verify PAC failed for %s (%s) from %s with %s",
1653 spn, cpn, from, krb5_get_err_text(context, ret));
1654 goto out;
1657 /* also check the krbtgt for signature */
1658 ret = check_KRB5SignedPath(context,
1659 config,
1660 krbtgt,
1661 tgt,
1662 &spp,
1663 &signedpath);
1664 if (ret) {
1665 kdc_log(context, config, 0,
1666 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1667 spn, cpn, from, krb5_get_err_text(context, ret));
1668 goto out;
1672 * Process request
1675 client_principal = cp;
1677 if (client) {
1678 const PA_DATA *sdata;
1679 int i = 0;
1681 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1682 if (sdata) {
1683 krb5_crypto crypto;
1684 krb5_data datack;
1685 PA_S4U2Self self;
1686 char *selfcpn = NULL;
1687 const char *str;
1689 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1690 sdata->padata_value.length,
1691 &self, NULL);
1692 if (ret) {
1693 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1694 goto out;
1697 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1698 if (ret)
1699 goto out;
1701 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1702 if (ret) {
1703 free_PA_S4U2Self(&self);
1704 krb5_data_free(&datack);
1705 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1706 krb5_get_err_text(context, ret));
1707 goto out;
1710 ret = krb5_verify_checksum(context,
1711 crypto,
1712 KRB5_KU_OTHER_CKSUM,
1713 datack.data,
1714 datack.length,
1715 &self.cksum);
1716 krb5_data_free(&datack);
1717 krb5_crypto_destroy(context, crypto);
1718 if (ret) {
1719 free_PA_S4U2Self(&self);
1720 kdc_log(context, config, 0,
1721 "krb5_verify_checksum failed for S4U2Self: %s",
1722 krb5_get_err_text(context, ret));
1723 goto out;
1726 ret = _krb5_principalname2krb5_principal(context,
1727 &client_principal,
1728 self.name,
1729 self.realm);
1730 free_PA_S4U2Self(&self);
1731 if (ret)
1732 goto out;
1734 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1735 if (ret)
1736 goto out;
1739 * Check that service doing the impersonating is
1740 * requesting a ticket to it-self.
1742 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1743 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1744 "to impersonate some other user "
1745 "(tried for user %s to service %s)",
1746 cpn, selfcpn, spn);
1747 free(selfcpn);
1748 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1749 goto out;
1753 * If the service isn't trusted for authentication to
1754 * delegation, remove the forward flag.
1757 if (client->entry.flags.trusted_for_delegation) {
1758 str = "[forwardable]";
1759 } else {
1760 b->kdc_options.forwardable = 0;
1761 str = "";
1763 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1764 "service %s %s", cpn, selfcpn, spn, str);
1765 free(selfcpn);
1770 * Constrained delegation
1773 if (client != NULL
1774 && b->additional_tickets != NULL
1775 && b->additional_tickets->len != 0
1776 && b->kdc_options.enc_tkt_in_skey == 0)
1778 int ad_signedpath = 0;
1779 Key *clientkey;
1780 Ticket *t;
1781 char *str;
1784 * Require that the KDC have issued the service's krbtgt (not
1785 * self-issued ticket with kimpersonate(1).
1787 if (!signedpath) {
1788 ret = KRB5KDC_ERR_BADOPTION;
1789 kdc_log(context, config, 0,
1790 "Constrained delegation done on service ticket %s/%s",
1791 cpn, spn);
1792 goto out;
1795 t = &b->additional_tickets->val[0];
1797 ret = hdb_enctype2key(context, &client->entry,
1798 t->enc_part.etype, &clientkey);
1799 if(ret){
1800 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1801 goto out;
1804 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1805 if (ret) {
1806 kdc_log(context, config, 0,
1807 "failed to decrypt ticket for "
1808 "constrained delegation from %s to %s ", cpn, spn);
1809 goto out;
1812 /* check that ticket is valid */
1813 if (adtkt.flags.forwardable == 0) {
1814 kdc_log(context, config, 0,
1815 "Missing forwardable flag on ticket for "
1816 "constrained delegation from %s to %s ", cpn, spn);
1817 ret = KRB5KDC_ERR_BADOPTION;
1818 goto out;
1821 ret = check_constrained_delegation(context, config, clientdb,
1822 client, sp);
1823 if (ret) {
1824 kdc_log(context, config, 0,
1825 "constrained delegation from %s to %s not allowed",
1826 cpn, spn);
1827 goto out;
1830 ret = _krb5_principalname2krb5_principal(context,
1831 &client_principal,
1832 adtkt.cname,
1833 adtkt.crealm);
1834 if (ret)
1835 goto out;
1837 ret = krb5_unparse_name(context, client_principal, &str);
1838 if (ret)
1839 goto out;
1841 ret = verify_flags(context, config, &adtkt, str);
1842 if (ret) {
1843 free(str);
1844 goto out;
1848 * Check that the KDC issued the user's ticket.
1850 ret = check_KRB5SignedPath(context,
1851 config,
1852 krbtgt,
1853 &adtkt,
1854 NULL,
1855 &ad_signedpath);
1856 if (ret == 0 && !ad_signedpath)
1857 ret = KRB5KDC_ERR_BADOPTION;
1858 if (ret) {
1859 kdc_log(context, config, 0,
1860 "KRB5SignedPath check from service %s failed "
1861 "for delegation to %s for client %s "
1862 "from %s failed with %s",
1863 spn, str, cpn, from, krb5_get_err_text(context, ret));
1864 free(str);
1865 goto out;
1868 kdc_log(context, config, 0, "constrained delegation for %s "
1869 "from %s to %s", str, cpn, spn);
1870 free(str);
1874 * Check flags
1877 ret = kdc_check_flags(context, config,
1878 client, cpn,
1879 server, spn,
1880 FALSE);
1881 if(ret)
1882 goto out;
1884 if((b->kdc_options.validate || b->kdc_options.renew) &&
1885 !krb5_principal_compare(context,
1886 krbtgt->entry.principal,
1887 server->entry.principal)){
1888 kdc_log(context, config, 0, "Inconsistent request.");
1889 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1890 goto out;
1893 /* check for valid set of addresses */
1894 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1895 ret = KRB5KRB_AP_ERR_BADADDR;
1896 kdc_log(context, config, 0, "Request from wrong address");
1897 goto out;
1901 * If this is an referral, add server referral data to the
1902 * auth_data reply .
1904 if (ref_realm) {
1905 PA_DATA pa;
1906 krb5_crypto crypto;
1908 kdc_log(context, config, 0,
1909 "Adding server referral to %s", ref_realm);
1911 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1912 if (ret)
1913 goto out;
1915 ret = build_server_referral(context, config, crypto, ref_realm,
1916 NULL, s, &pa.padata_value);
1917 krb5_crypto_destroy(context, crypto);
1918 if (ret) {
1919 kdc_log(context, config, 0,
1920 "Failed building server referral");
1921 goto out;
1923 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1925 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1926 krb5_data_free(&pa.padata_value);
1927 if (ret) {
1928 kdc_log(context, config, 0,
1929 "Add server referral METHOD-DATA failed");
1930 goto out;
1938 ret = tgs_make_reply(context,
1939 config,
1941 client_principal,
1942 tgt,
1943 ekey,
1944 &sessionkey,
1945 kvno,
1946 *auth_data,
1947 server,
1949 spn,
1950 client,
1952 krbtgt,
1953 krbtgt_etype,
1954 spp,
1955 &rspac,
1956 &enc_pa_data,
1957 e_text,
1958 reply);
1960 out:
1961 free(spn);
1962 free(cpn);
1964 krb5_data_free(&rspac);
1965 krb5_free_keyblock_contents(context, &sessionkey);
1966 if(server)
1967 _kdc_free_ent(context, server);
1968 if(client)
1969 _kdc_free_ent(context, client);
1971 if (client_principal && client_principal != cp)
1972 krb5_free_principal(context, client_principal);
1973 if (cp)
1974 krb5_free_principal(context, cp);
1975 if (sp)
1976 krb5_free_principal(context, sp);
1977 if (ref_realm)
1978 free(ref_realm);
1979 free_METHOD_DATA(&enc_pa_data);
1981 free_EncTicketPart(&adtkt);
1983 return ret;
1990 krb5_error_code
1991 _kdc_tgs_rep(krb5_context context,
1992 krb5_kdc_configuration *config,
1993 KDC_REQ *req,
1994 krb5_data *data,
1995 const char *from,
1996 struct sockaddr *from_addr,
1997 int datagram_reply)
1999 AuthorizationData *auth_data = NULL;
2000 krb5_error_code ret;
2001 int i = 0;
2002 const PA_DATA *tgs_req;
2004 hdb_entry_ex *krbtgt = NULL;
2005 krb5_ticket *ticket = NULL;
2006 const char *e_text = NULL;
2007 krb5_enctype krbtgt_etype = ETYPE_NULL;
2009 time_t *csec = NULL;
2010 int *cusec = NULL;
2012 if(req->padata == NULL){
2013 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2014 kdc_log(context, config, 0,
2015 "TGS-REQ from %s without PA-DATA", from);
2016 goto out;
2019 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2021 if(tgs_req == NULL){
2022 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2024 kdc_log(context, config, 0,
2025 "TGS-REQ from %s without PA-TGS-REQ", from);
2026 goto out;
2028 ret = tgs_parse_request(context, config,
2029 &req->req_body, tgs_req,
2030 &krbtgt,
2031 &krbtgt_etype,
2032 &ticket,
2033 &e_text,
2034 from, from_addr,
2035 &csec, &cusec,
2036 &auth_data);
2037 if (ret) {
2038 kdc_log(context, config, 0,
2039 "Failed parsing TGS-REQ from %s", from);
2040 goto out;
2043 ret = tgs_build_reply(context,
2044 config,
2045 req,
2046 &req->req_body,
2047 krbtgt,
2048 krbtgt_etype,
2049 ticket,
2050 data,
2051 from,
2052 &e_text,
2053 &auth_data,
2054 from_addr);
2055 if (ret) {
2056 kdc_log(context, config, 0,
2057 "Failed building TGS-REP to %s", from);
2058 goto out;
2061 /* */
2062 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2063 krb5_data_free(data);
2064 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2065 e_text = "Reply packet too large";
2068 out:
2069 if(ret && data->data == NULL){
2070 krb5_mk_error(context,
2071 ret,
2072 NULL,
2073 NULL,
2074 NULL,
2075 NULL,
2076 csec,
2077 cusec,
2078 data);
2080 free(csec);
2081 free(cusec);
2082 if (ticket)
2083 krb5_free_ticket(context, ticket);
2084 if(krbtgt)
2085 _kdc_free_ent(context, krbtgt);
2087 if (auth_data) {
2088 free_AuthorizationData(auth_data);
2089 free(auth_data);
2092 return 0;