support old SIGNTICKET too
[heimdal.git] / kdc / krb5tgs.c
blobff891a5bc1c85f525f66e9c065f832207a31e921
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 child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET_OLD) {
95 free_AuthorizationData(&child);
96 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
99 if (data)
100 ret = der_copy_octet_string(&child.val[0].ad_data, data);
101 free_AuthorizationData(&child);
102 return ret;
105 krb5_error_code
106 _kdc_add_KRB5SignedPath(krb5_context context,
107 krb5_kdc_configuration *config,
108 hdb_entry_ex *krbtgt,
109 krb5_enctype enctype,
110 krb5_principal client,
111 krb5_const_principal server,
112 krb5_principals principals,
113 EncTicketPart *tkt)
115 krb5_error_code ret;
116 KRB5SignedPath sp;
117 krb5_data data;
118 krb5_crypto crypto = NULL;
119 size_t size;
121 if (server && principals) {
122 ret = add_Principals(principals, server);
123 if (ret)
124 return ret;
128 KRB5SignedPathData spd;
130 spd.client = client;
131 spd.authtime = tkt->authtime;
132 spd.delegated = principals;
133 spd.method_data = NULL;
135 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
136 &spd, &size, ret);
137 if (ret)
138 return ret;
139 if (data.length != size)
140 krb5_abortx(context, "internal asn.1 encoder error");
144 Key *key;
145 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
146 if (ret == 0)
147 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
148 if (ret) {
149 free(data.data);
150 return ret;
155 * Fill in KRB5SignedPath
158 sp.etype = enctype;
159 sp.delegated = principals;
160 sp.method_data = NULL;
162 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
163 data.data, data.length, &sp.cksum);
164 krb5_crypto_destroy(context, crypto);
165 free(data.data);
166 if (ret)
167 return ret;
169 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
170 free_Checksum(&sp.cksum);
171 if (ret)
172 return ret;
173 if (data.length != size)
174 krb5_abortx(context, "internal asn.1 encoder error");
178 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
179 * authorization data field.
182 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
183 KRB5_AUTHDATA_SIGNTICKET, &data);
184 krb5_data_free(&data);
186 return ret;
189 static krb5_error_code
190 check_KRB5SignedPath(krb5_context context,
191 krb5_kdc_configuration *config,
192 hdb_entry_ex *krbtgt,
193 krb5_principal cp,
194 EncTicketPart *tkt,
195 krb5_principals *delegated,
196 int *signedpath)
198 krb5_error_code ret;
199 krb5_data data;
200 krb5_crypto crypto = NULL;
202 if (delegated)
203 *delegated = NULL;
205 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
206 if (ret == 0) {
207 KRB5SignedPathData spd;
208 KRB5SignedPath sp;
209 size_t size;
211 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
212 krb5_data_free(&data);
213 if (ret)
214 return ret;
216 spd.client = cp;
217 spd.authtime = tkt->authtime;
218 spd.delegated = sp.delegated;
219 spd.method_data = sp.method_data;
221 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
222 &spd, &size, ret);
223 if (ret) {
224 free_KRB5SignedPath(&sp);
225 return ret;
227 if (data.length != size)
228 krb5_abortx(context, "internal asn.1 encoder error");
231 Key *key;
232 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
233 if (ret == 0)
234 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
235 if (ret) {
236 free(data.data);
237 free_KRB5SignedPath(&sp);
238 return ret;
241 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
242 data.data, data.length,
243 &sp.cksum);
244 krb5_crypto_destroy(context, crypto);
245 free(data.data);
246 if (ret) {
247 free_KRB5SignedPath(&sp);
248 kdc_log(context, config, 5,
249 "KRB5SignedPath not signed correctly, not marking as signed");
250 return 0;
253 if (delegated && sp.delegated) {
255 *delegated = malloc(sizeof(*sp.delegated));
256 if (*delegated == NULL) {
257 free_KRB5SignedPath(&sp);
258 return ENOMEM;
261 ret = copy_Principals(*delegated, sp.delegated);
262 if (ret) {
263 free_KRB5SignedPath(&sp);
264 free(*delegated);
265 *delegated = NULL;
266 return ret;
269 free_KRB5SignedPath(&sp);
271 *signedpath = 1;
274 return 0;
281 static krb5_error_code
282 check_PAC(krb5_context context,
283 krb5_kdc_configuration *config,
284 const krb5_principal client_principal,
285 hdb_entry_ex *client,
286 hdb_entry_ex *server,
287 const EncryptionKey *server_key,
288 const EncryptionKey *krbtgt_key,
289 EncTicketPart *tkt,
290 krb5_data *rspac,
291 int *signedpath)
293 AuthorizationData *ad = tkt->authorization_data;
294 unsigned i, j;
295 krb5_error_code ret;
297 if (ad == NULL || ad->len == 0)
298 return 0;
300 for (i = 0; i < ad->len; i++) {
301 AuthorizationData child;
303 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
304 continue;
306 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
307 ad->val[i].ad_data.length,
308 &child,
309 NULL);
310 if (ret) {
311 krb5_set_error_message(context, ret, "Failed to decode "
312 "IF_RELEVANT with %d", ret);
313 return ret;
315 for (j = 0; j < child.len; j++) {
317 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
318 krb5_pac pac;
320 /* Found PAC */
321 ret = krb5_pac_parse(context,
322 child.val[j].ad_data.data,
323 child.val[j].ad_data.length,
324 &pac);
325 free_AuthorizationData(&child);
326 if (ret)
327 return ret;
329 ret = krb5_pac_verify(context, pac, tkt->authtime,
330 client_principal,
331 krbtgt_key, NULL);
332 if (ret) {
333 krb5_pac_free(context, pac);
334 return ret;
337 ret = _kdc_pac_verify(context, client_principal,
338 client, server, &pac);
339 if (ret) {
340 krb5_pac_free(context, pac);
341 return ret;
343 *signedpath = 1;
345 ret = _krb5_pac_sign(context, pac, tkt->authtime,
346 client_principal,
347 server_key, krbtgt_key, rspac);
349 krb5_pac_free(context, pac);
351 return ret;
354 free_AuthorizationData(&child);
356 return 0;
363 static krb5_error_code
364 check_tgs_flags(krb5_context context,
365 krb5_kdc_configuration *config,
366 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
368 KDCOptions f = b->kdc_options;
370 if(f.validate){
371 if(!tgt->flags.invalid || tgt->starttime == NULL){
372 kdc_log(context, config, 0,
373 "Bad request to validate ticket");
374 return KRB5KDC_ERR_BADOPTION;
376 if(*tgt->starttime > kdc_time){
377 kdc_log(context, config, 0,
378 "Early request to validate ticket");
379 return KRB5KRB_AP_ERR_TKT_NYV;
381 /* XXX tkt = tgt */
382 et->flags.invalid = 0;
383 }else if(tgt->flags.invalid){
384 kdc_log(context, config, 0,
385 "Ticket-granting ticket has INVALID flag set");
386 return KRB5KRB_AP_ERR_TKT_INVALID;
389 if(f.forwardable){
390 if(!tgt->flags.forwardable){
391 kdc_log(context, config, 0,
392 "Bad request for forwardable ticket");
393 return KRB5KDC_ERR_BADOPTION;
395 et->flags.forwardable = 1;
397 if(f.forwarded){
398 if(!tgt->flags.forwardable){
399 kdc_log(context, config, 0,
400 "Request to forward non-forwardable ticket");
401 return KRB5KDC_ERR_BADOPTION;
403 et->flags.forwarded = 1;
404 et->caddr = b->addresses;
406 if(tgt->flags.forwarded)
407 et->flags.forwarded = 1;
409 if(f.proxiable){
410 if(!tgt->flags.proxiable){
411 kdc_log(context, config, 0,
412 "Bad request for proxiable ticket");
413 return KRB5KDC_ERR_BADOPTION;
415 et->flags.proxiable = 1;
417 if(f.proxy){
418 if(!tgt->flags.proxiable){
419 kdc_log(context, config, 0,
420 "Request to proxy non-proxiable ticket");
421 return KRB5KDC_ERR_BADOPTION;
423 et->flags.proxy = 1;
424 et->caddr = b->addresses;
426 if(tgt->flags.proxy)
427 et->flags.proxy = 1;
429 if(f.allow_postdate){
430 if(!tgt->flags.may_postdate){
431 kdc_log(context, config, 0,
432 "Bad request for post-datable ticket");
433 return KRB5KDC_ERR_BADOPTION;
435 et->flags.may_postdate = 1;
437 if(f.postdated){
438 if(!tgt->flags.may_postdate){
439 kdc_log(context, config, 0,
440 "Bad request for postdated ticket");
441 return KRB5KDC_ERR_BADOPTION;
443 if(b->from)
444 *et->starttime = *b->from;
445 et->flags.postdated = 1;
446 et->flags.invalid = 1;
447 }else if(b->from && *b->from > kdc_time + context->max_skew){
448 kdc_log(context, config, 0, "Ticket cannot be postdated");
449 return KRB5KDC_ERR_CANNOT_POSTDATE;
452 if(f.renewable){
453 if(!tgt->flags.renewable){
454 kdc_log(context, config, 0,
455 "Bad request for renewable ticket");
456 return KRB5KDC_ERR_BADOPTION;
458 et->flags.renewable = 1;
459 ALLOC(et->renew_till);
460 _kdc_fix_time(&b->rtime);
461 *et->renew_till = *b->rtime;
463 if(f.renew){
464 time_t old_life;
465 if(!tgt->flags.renewable || tgt->renew_till == NULL){
466 kdc_log(context, config, 0,
467 "Request to renew non-renewable ticket");
468 return KRB5KDC_ERR_BADOPTION;
470 old_life = tgt->endtime;
471 if(tgt->starttime)
472 old_life -= *tgt->starttime;
473 else
474 old_life -= tgt->authtime;
475 et->endtime = *et->starttime + old_life;
476 if (et->renew_till != NULL)
477 et->endtime = min(*et->renew_till, et->endtime);
480 #if 0
481 /* checks for excess flags */
482 if(f.request_anonymous && !config->allow_anonymous){
483 kdc_log(context, config, 0,
484 "Request for anonymous ticket");
485 return KRB5KDC_ERR_BADOPTION;
487 #endif
488 return 0;
495 static krb5_error_code
496 check_constrained_delegation(krb5_context context,
497 krb5_kdc_configuration *config,
498 HDB *clientdb,
499 hdb_entry_ex *client,
500 krb5_const_principal server)
502 const HDB_Ext_Constrained_delegation_acl *acl;
503 krb5_error_code ret;
504 int i;
506 /* if client delegates to itself, that ok */
507 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
508 return 0;
510 if (clientdb->hdb_check_constrained_delegation) {
511 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
512 if (ret == 0)
513 return 0;
514 } else {
515 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
516 if (ret) {
517 krb5_clear_error_message(context);
518 return ret;
521 if (acl) {
522 for (i = 0; i < acl->len; i++) {
523 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
524 return 0;
527 ret = KRB5KDC_ERR_BADOPTION;
529 kdc_log(context, config, 0,
530 "Bad request for constrained delegation");
531 return ret;
538 static krb5_error_code
539 verify_flags (krb5_context context,
540 krb5_kdc_configuration *config,
541 const EncTicketPart *et,
542 const char *pstr)
544 if(et->endtime < kdc_time){
545 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
546 return KRB5KRB_AP_ERR_TKT_EXPIRED;
548 if(et->flags.invalid){
549 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
550 return KRB5KRB_AP_ERR_TKT_NYV;
552 return 0;
559 static krb5_error_code
560 fix_transited_encoding(krb5_context context,
561 krb5_kdc_configuration *config,
562 krb5_boolean check_policy,
563 const TransitedEncoding *tr,
564 EncTicketPart *et,
565 const char *client_realm,
566 const char *server_realm,
567 const char *tgt_realm)
569 krb5_error_code ret = 0;
570 char **realms, **tmp;
571 unsigned int num_realms;
572 int i;
574 switch (tr->tr_type) {
575 case DOMAIN_X500_COMPRESS:
576 break;
577 case 0:
579 * Allow empty content of type 0 because that is was Microsoft
580 * generates in their TGT.
582 if (tr->contents.length == 0)
583 break;
584 kdc_log(context, config, 0,
585 "Transited type 0 with non empty content");
586 return KRB5KDC_ERR_TRTYPE_NOSUPP;
587 default:
588 kdc_log(context, config, 0,
589 "Unknown transited type: %u", tr->tr_type);
590 return KRB5KDC_ERR_TRTYPE_NOSUPP;
593 ret = krb5_domain_x500_decode(context,
594 tr->contents,
595 &realms,
596 &num_realms,
597 client_realm,
598 server_realm);
599 if(ret){
600 krb5_warn(context, ret,
601 "Decoding transited encoding");
602 return ret;
604 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
605 /* not us, so add the previous realm to transited set */
606 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
607 ret = ERANGE;
608 goto free_realms;
610 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
611 if(tmp == NULL){
612 ret = ENOMEM;
613 goto free_realms;
615 realms = tmp;
616 realms[num_realms] = strdup(tgt_realm);
617 if(realms[num_realms] == NULL){
618 ret = ENOMEM;
619 goto free_realms;
621 num_realms++;
623 if(num_realms == 0) {
624 if(strcmp(client_realm, server_realm))
625 kdc_log(context, config, 0,
626 "cross-realm %s -> %s", client_realm, server_realm);
627 } else {
628 size_t l = 0;
629 char *rs;
630 for(i = 0; i < num_realms; i++)
631 l += strlen(realms[i]) + 2;
632 rs = malloc(l);
633 if(rs != NULL) {
634 *rs = '\0';
635 for(i = 0; i < num_realms; i++) {
636 if(i > 0)
637 strlcat(rs, ", ", l);
638 strlcat(rs, realms[i], l);
640 kdc_log(context, config, 0,
641 "cross-realm %s -> %s via [%s]",
642 client_realm, server_realm, rs);
643 free(rs);
646 if(check_policy) {
647 ret = krb5_check_transited(context, client_realm,
648 server_realm,
649 realms, num_realms, NULL);
650 if(ret) {
651 krb5_warn(context, ret, "cross-realm %s -> %s",
652 client_realm, server_realm);
653 goto free_realms;
655 et->flags.transited_policy_checked = 1;
657 et->transited.tr_type = DOMAIN_X500_COMPRESS;
658 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
659 if(ret)
660 krb5_warn(context, ret, "Encoding transited encoding");
661 free_realms:
662 for(i = 0; i < num_realms; i++)
663 free(realms[i]);
664 free(realms);
665 return ret;
669 static krb5_error_code
670 tgs_make_reply(krb5_context context,
671 krb5_kdc_configuration *config,
672 KDC_REQ_BODY *b,
673 krb5_const_principal tgt_name,
674 const EncTicketPart *tgt,
675 const krb5_keyblock *replykey,
676 int rk_is_subkey,
677 const EncryptionKey *serverkey,
678 const krb5_keyblock *sessionkey,
679 krb5_kvno kvno,
680 AuthorizationData *auth_data,
681 hdb_entry_ex *server,
682 krb5_principal server_principal,
683 const char *server_name,
684 hdb_entry_ex *client,
685 krb5_principal client_principal,
686 hdb_entry_ex *krbtgt,
687 krb5_enctype krbtgt_etype,
688 krb5_principals spp,
689 const krb5_data *rspac,
690 const METHOD_DATA *enc_pa_data,
691 const char **e_text,
692 krb5_data *reply)
694 KDC_REP rep;
695 EncKDCRepPart ek;
696 EncTicketPart et;
697 KDCOptions f = b->kdc_options;
698 krb5_error_code ret;
699 int is_weak = 0;
701 memset(&rep, 0, sizeof(rep));
702 memset(&et, 0, sizeof(et));
703 memset(&ek, 0, sizeof(ek));
705 rep.pvno = 5;
706 rep.msg_type = krb_tgs_rep;
708 et.authtime = tgt->authtime;
709 _kdc_fix_time(&b->till);
710 et.endtime = min(tgt->endtime, *b->till);
711 ALLOC(et.starttime);
712 *et.starttime = kdc_time;
714 ret = check_tgs_flags(context, config, b, tgt, &et);
715 if(ret)
716 goto out;
718 /* We should check the transited encoding if:
719 1) the request doesn't ask not to be checked
720 2) globally enforcing a check
721 3) principal requires checking
722 4) we allow non-check per-principal, but principal isn't marked as allowing this
723 5) we don't globally allow this
726 #define GLOBAL_FORCE_TRANSITED_CHECK \
727 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
728 #define GLOBAL_ALLOW_PER_PRINCIPAL \
729 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
730 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
731 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
733 /* these will consult the database in future release */
734 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
735 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
737 ret = fix_transited_encoding(context, config,
738 !f.disable_transited_check ||
739 GLOBAL_FORCE_TRANSITED_CHECK ||
740 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
741 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
742 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
743 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
744 &tgt->transited, &et,
745 krb5_principal_get_realm(context, client_principal),
746 krb5_principal_get_realm(context, server->entry.principal),
747 krb5_principal_get_realm(context, krbtgt->entry.principal));
748 if(ret)
749 goto out;
751 copy_Realm(&server_principal->realm, &rep.ticket.realm);
752 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
753 copy_Realm(&tgt_name->realm, &rep.crealm);
755 if (f.request_anonymous)
756 _kdc_make_anonymous_principalname (&rep.cname);
757 else */
759 copy_PrincipalName(&tgt_name->name, &rep.cname);
760 rep.ticket.tkt_vno = 5;
762 ek.caddr = et.caddr;
763 if(et.caddr == NULL)
764 et.caddr = tgt->caddr;
767 time_t life;
768 life = et.endtime - *et.starttime;
769 if(client && client->entry.max_life)
770 life = min(life, *client->entry.max_life);
771 if(server->entry.max_life)
772 life = min(life, *server->entry.max_life);
773 et.endtime = *et.starttime + life;
775 if(f.renewable_ok && tgt->flags.renewable &&
776 et.renew_till == NULL && et.endtime < *b->till){
777 et.flags.renewable = 1;
778 ALLOC(et.renew_till);
779 *et.renew_till = *b->till;
781 if(et.renew_till){
782 time_t renew;
783 renew = *et.renew_till - et.authtime;
784 if(client && client->entry.max_renew)
785 renew = min(renew, *client->entry.max_renew);
786 if(server->entry.max_renew)
787 renew = min(renew, *server->entry.max_renew);
788 *et.renew_till = et.authtime + renew;
791 if(et.renew_till){
792 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
793 *et.starttime = min(*et.starttime, *et.renew_till);
794 et.endtime = min(et.endtime, *et.renew_till);
797 *et.starttime = min(*et.starttime, et.endtime);
799 if(*et.starttime == et.endtime){
800 ret = KRB5KDC_ERR_NEVER_VALID;
801 goto out;
803 if(et.renew_till && et.endtime == *et.renew_till){
804 free(et.renew_till);
805 et.renew_till = NULL;
806 et.flags.renewable = 0;
809 et.flags.pre_authent = tgt->flags.pre_authent;
810 et.flags.hw_authent = tgt->flags.hw_authent;
811 et.flags.anonymous = tgt->flags.anonymous;
812 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
814 if(rspac->length) {
816 * No not need to filter out the any PAC from the
817 * auth_data since it's signed by the KDC.
819 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
820 KRB5_AUTHDATA_WIN2K_PAC, rspac);
821 if (ret)
822 goto out;
825 if (auth_data) {
826 unsigned int i = 0;
828 /* XXX check authdata */
830 if (et.authorization_data == NULL) {
831 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
832 if (et.authorization_data == NULL) {
833 ret = ENOMEM;
834 krb5_set_error_message(context, ret, "malloc: out of memory");
835 goto out;
838 for(i = 0; i < auth_data->len ; i++) {
839 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
840 if (ret) {
841 krb5_set_error_message(context, ret, "malloc: out of memory");
842 goto out;
846 /* Filter out type KRB5SignedPath */
847 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
848 if (ret == 0) {
849 if (et.authorization_data->len == 1) {
850 free_AuthorizationData(et.authorization_data);
851 free(et.authorization_data);
852 et.authorization_data = NULL;
853 } else {
854 AuthorizationData *ad = et.authorization_data;
855 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
856 ad->len--;
861 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
862 if (ret)
863 goto out;
864 et.crealm = tgt->crealm;
865 et.cname = tgt_name->name;
867 ek.key = et.key;
868 /* MIT must have at least one last_req */
869 ek.last_req.len = 1;
870 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
871 if (ek.last_req.val == NULL) {
872 ret = ENOMEM;
873 goto out;
875 ek.nonce = b->nonce;
876 ek.flags = et.flags;
877 ek.authtime = et.authtime;
878 ek.starttime = et.starttime;
879 ek.endtime = et.endtime;
880 ek.renew_till = et.renew_till;
881 ek.srealm = rep.ticket.realm;
882 ek.sname = rep.ticket.sname;
884 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
885 et.endtime, et.renew_till);
887 /* Don't sign cross realm tickets, they can't be checked anyway */
889 char *r = get_krbtgt_realm(&ek.sname);
891 if (r == NULL || strcmp(r, ek.srealm) == 0) {
892 ret = _kdc_add_KRB5SignedPath(context,
893 config,
894 krbtgt,
895 krbtgt_etype,
896 client_principal,
897 NULL,
898 spp,
899 &et);
900 if (ret)
901 goto out;
905 if (enc_pa_data->len) {
906 rep.padata = calloc(1, sizeof(*rep.padata));
907 if (rep.padata == NULL) {
908 ret = ENOMEM;
909 goto out;
911 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
912 if (ret)
913 goto out;
916 if (krb5_enctype_valid(context, et.key.keytype) != 0
917 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
919 krb5_enctype_enable(context, et.key.keytype);
920 is_weak = 1;
924 /* It is somewhat unclear where the etype in the following
925 encryption should come from. What we have is a session
926 key in the passed tgt, and a list of preferred etypes
927 *for the new ticket*. Should we pick the best possible
928 etype, given the keytype in the tgt, or should we look
929 at the etype list here as well? What if the tgt
930 session key is DES3 and we want a ticket with a (say)
931 CAST session key. Should the DES3 etype be added to the
932 etype list, even if we don't want a session key with
933 DES3? */
934 ret = _kdc_encode_reply(context, config,
935 &rep, &et, &ek, et.key.keytype,
936 kvno,
937 serverkey, 0, replykey, rk_is_subkey,
938 e_text, reply);
939 if (is_weak)
940 krb5_enctype_disable(context, et.key.keytype);
942 out:
943 free_TGS_REP(&rep);
944 free_TransitedEncoding(&et.transited);
945 if(et.starttime)
946 free(et.starttime);
947 if(et.renew_till)
948 free(et.renew_till);
949 if(et.authorization_data) {
950 free_AuthorizationData(et.authorization_data);
951 free(et.authorization_data);
953 free_LastReq(&ek.last_req);
954 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
955 free_EncryptionKey(&et.key);
956 return ret;
959 static krb5_error_code
960 tgs_check_authenticator(krb5_context context,
961 krb5_kdc_configuration *config,
962 krb5_auth_context ac,
963 KDC_REQ_BODY *b,
964 const char **e_text,
965 krb5_keyblock *key)
967 krb5_authenticator auth;
968 size_t len;
969 unsigned char *buf;
970 size_t buf_size;
971 krb5_error_code ret;
972 krb5_crypto crypto;
974 krb5_auth_con_getauthenticator(context, ac, &auth);
975 if(auth->cksum == NULL){
976 kdc_log(context, config, 0, "No authenticator in request");
977 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
978 goto out;
981 * according to RFC1510 it doesn't need to be keyed,
982 * but according to the latest draft it needs to.
984 if (
985 #if 0
986 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
988 #endif
989 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
990 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
991 auth->cksum->cksumtype);
992 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
993 goto out;
996 /* XXX should not re-encode this */
997 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
998 if(ret){
999 const char *msg = krb5_get_error_message(context, ret);
1000 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1001 krb5_free_error_message(context, msg);
1002 goto out;
1004 if(buf_size != len) {
1005 free(buf);
1006 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1007 *e_text = "KDC internal error";
1008 ret = KRB5KRB_ERR_GENERIC;
1009 goto out;
1011 ret = krb5_crypto_init(context, key, 0, &crypto);
1012 if (ret) {
1013 const char *msg = krb5_get_error_message(context, ret);
1014 free(buf);
1015 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1016 krb5_free_error_message(context, msg);
1017 goto out;
1019 ret = krb5_verify_checksum(context,
1020 crypto,
1021 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1022 buf,
1023 len,
1024 auth->cksum);
1025 free(buf);
1026 krb5_crypto_destroy(context, crypto);
1027 if(ret){
1028 const char *msg = krb5_get_error_message(context, ret);
1029 kdc_log(context, config, 0,
1030 "Failed to verify authenticator checksum: %s", msg);
1031 krb5_free_error_message(context, msg);
1033 out:
1034 free_Authenticator(auth);
1035 free(auth);
1036 return ret;
1043 static const char *
1044 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1046 const char *new_realm = krb5_config_get_string(context,
1047 NULL,
1048 "capaths",
1049 crealm,
1050 srealm,
1051 NULL);
1052 return new_realm;
1056 static krb5_boolean
1057 need_referral(krb5_context context, krb5_kdc_configuration *config,
1058 const KDCOptions * const options, krb5_principal server,
1059 krb5_realm **realms)
1061 const char *name;
1063 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1064 return FALSE;
1066 if (server->name.name_string.len == 1)
1067 name = server->name.name_string.val[0];
1068 else if (server->name.name_string.len > 1)
1069 name = server->name.name_string.val[1];
1070 else
1071 return FALSE;
1073 kdc_log(context, config, 0, "Searching referral for %s", name);
1075 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1078 static krb5_error_code
1079 tgs_parse_request(krb5_context context,
1080 krb5_kdc_configuration *config,
1081 KDC_REQ_BODY *b,
1082 const PA_DATA *tgs_req,
1083 hdb_entry_ex **krbtgt,
1084 krb5_enctype *krbtgt_etype,
1085 krb5_ticket **ticket,
1086 const char **e_text,
1087 const char *from,
1088 const struct sockaddr *from_addr,
1089 time_t **csec,
1090 int **cusec,
1091 AuthorizationData **auth_data,
1092 krb5_keyblock **replykey,
1093 int *rk_is_subkey)
1095 krb5_ap_req ap_req;
1096 krb5_error_code ret;
1097 krb5_principal princ;
1098 krb5_auth_context ac = NULL;
1099 krb5_flags ap_req_options;
1100 krb5_flags verify_ap_req_flags;
1101 krb5_crypto crypto;
1102 Key *tkey;
1103 krb5_keyblock *subkey = NULL;
1104 unsigned usage;
1106 *auth_data = NULL;
1107 *csec = NULL;
1108 *cusec = NULL;
1109 *replykey = NULL;
1111 memset(&ap_req, 0, sizeof(ap_req));
1112 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1113 if(ret){
1114 const char *msg = krb5_get_error_message(context, ret);
1115 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1116 krb5_free_error_message(context, msg);
1117 goto out;
1120 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1121 /* XXX check for ticket.sname == req.sname */
1122 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1123 ret = KRB5KDC_ERR_POLICY; /* ? */
1124 goto out;
1127 _krb5_principalname2krb5_principal(context,
1128 &princ,
1129 ap_req.ticket.sname,
1130 ap_req.ticket.realm);
1132 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1134 if(ret) {
1135 const char *msg = krb5_get_error_message(context, ret);
1136 char *p;
1137 ret = krb5_unparse_name(context, princ, &p);
1138 if (ret != 0)
1139 p = "<unparse_name failed>";
1140 krb5_free_principal(context, princ);
1141 kdc_log(context, config, 0,
1142 "Ticket-granting ticket not found in database: %s: %s", msg);
1143 krb5_free_error_message(context, msg);
1144 if (ret == 0)
1145 free(p);
1146 ret = KRB5KRB_AP_ERR_NOT_US;
1147 goto out;
1150 if(ap_req.ticket.enc_part.kvno &&
1151 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1152 char *p;
1154 ret = krb5_unparse_name (context, princ, &p);
1155 krb5_free_principal(context, princ);
1156 if (ret != 0)
1157 p = "<unparse_name failed>";
1158 kdc_log(context, config, 0,
1159 "Ticket kvno = %d, DB kvno = %d (%s)",
1160 *ap_req.ticket.enc_part.kvno,
1161 (*krbtgt)->entry.kvno,
1163 if (ret == 0)
1164 free (p);
1165 ret = KRB5KRB_AP_ERR_BADKEYVER;
1166 goto out;
1169 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1171 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1172 ap_req.ticket.enc_part.etype, &tkey);
1173 if(ret){
1174 char *str = NULL, *p = NULL;
1176 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1177 krb5_unparse_name(context, princ, &p);
1178 kdc_log(context, config, 0,
1179 "No server key with enctype %s found for %s",
1180 str ? str : "<unknown enctype>",
1181 p ? p : "<unparse_name failed>");
1182 free(str);
1183 free(p);
1184 ret = KRB5KRB_AP_ERR_BADKEYVER;
1185 goto out;
1188 if (b->kdc_options.validate)
1189 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1190 else
1191 verify_ap_req_flags = 0;
1193 ret = krb5_verify_ap_req2(context,
1194 &ac,
1195 &ap_req,
1196 princ,
1197 &tkey->key,
1198 verify_ap_req_flags,
1199 &ap_req_options,
1200 ticket,
1201 KRB5_KU_TGS_REQ_AUTH);
1203 krb5_free_principal(context, princ);
1204 if(ret) {
1205 const char *msg = krb5_get_error_message(context, ret);
1206 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1207 krb5_free_error_message(context, msg);
1208 goto out;
1212 krb5_authenticator auth;
1214 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1215 if (ret == 0) {
1216 *csec = malloc(sizeof(**csec));
1217 if (*csec == NULL) {
1218 krb5_free_authenticator(context, &auth);
1219 kdc_log(context, config, 0, "malloc failed");
1220 goto out;
1222 **csec = auth->ctime;
1223 *cusec = malloc(sizeof(**cusec));
1224 if (*cusec == NULL) {
1225 krb5_free_authenticator(context, &auth);
1226 kdc_log(context, config, 0, "malloc failed");
1227 goto out;
1229 **cusec = auth->cusec;
1230 krb5_free_authenticator(context, &auth);
1234 ret = tgs_check_authenticator(context, config,
1235 ac, b, e_text, &(*ticket)->ticket.key);
1236 if (ret) {
1237 krb5_auth_con_free(context, ac);
1238 goto out;
1241 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1242 *rk_is_subkey = 1;
1244 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1245 if(ret){
1246 const char *msg = krb5_get_error_message(context, ret);
1247 krb5_auth_con_free(context, ac);
1248 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1249 krb5_free_error_message(context, msg);
1250 goto out;
1252 if(subkey == NULL){
1253 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1254 *rk_is_subkey = 0;
1256 ret = krb5_auth_con_getkey(context, ac, &subkey);
1257 if(ret) {
1258 const char *msg = krb5_get_error_message(context, ret);
1259 krb5_auth_con_free(context, ac);
1260 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1261 krb5_free_error_message(context, msg);
1262 goto out;
1265 if(subkey == NULL){
1266 krb5_auth_con_free(context, ac);
1267 kdc_log(context, config, 0,
1268 "Failed to get key for enc-authorization-data");
1269 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1270 goto out;
1273 *replykey = subkey;
1275 if (b->enc_authorization_data) {
1276 krb5_data ad;
1278 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1279 if (ret) {
1280 const char *msg = krb5_get_error_message(context, ret);
1281 krb5_auth_con_free(context, ac);
1282 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1283 krb5_free_error_message(context, msg);
1284 goto out;
1286 ret = krb5_decrypt_EncryptedData (context,
1287 crypto,
1288 usage,
1289 b->enc_authorization_data,
1290 &ad);
1291 krb5_crypto_destroy(context, crypto);
1292 if(ret){
1293 krb5_auth_con_free(context, ac);
1294 kdc_log(context, config, 0,
1295 "Failed to decrypt enc-authorization-data");
1296 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1297 goto out;
1299 ALLOC(*auth_data);
1300 if (*auth_data == NULL) {
1301 krb5_auth_con_free(context, ac);
1302 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1303 goto out;
1305 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1306 if(ret){
1307 krb5_auth_con_free(context, ac);
1308 free(*auth_data);
1309 *auth_data = NULL;
1310 kdc_log(context, config, 0, "Failed to decode authorization data");
1311 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1312 goto out;
1316 krb5_auth_con_free(context, ac);
1318 out:
1319 free_AP_REQ(&ap_req);
1321 return ret;
1324 static krb5_error_code
1325 build_server_referral(krb5_context context,
1326 krb5_kdc_configuration *config,
1327 krb5_crypto session,
1328 krb5_const_realm referred_realm,
1329 const PrincipalName *true_principal_name,
1330 const PrincipalName *requested_principal,
1331 krb5_data *outdata)
1333 PA_ServerReferralData ref;
1334 krb5_error_code ret;
1335 EncryptedData ed;
1336 krb5_data data;
1337 size_t size;
1339 memset(&ref, 0, sizeof(ref));
1341 if (referred_realm) {
1342 ALLOC(ref.referred_realm);
1343 if (ref.referred_realm == NULL)
1344 goto eout;
1345 *ref.referred_realm = strdup(referred_realm);
1346 if (*ref.referred_realm == NULL)
1347 goto eout;
1349 if (true_principal_name) {
1350 ALLOC(ref.true_principal_name);
1351 if (ref.true_principal_name == NULL)
1352 goto eout;
1353 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1354 if (ret)
1355 goto eout;
1357 if (requested_principal) {
1358 ALLOC(ref.requested_principal_name);
1359 if (ref.requested_principal_name == NULL)
1360 goto eout;
1361 ret = copy_PrincipalName(requested_principal,
1362 ref.requested_principal_name);
1363 if (ret)
1364 goto eout;
1367 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1368 data.data, data.length,
1369 &ref, &size, ret);
1370 free_PA_ServerReferralData(&ref);
1371 if (ret)
1372 return ret;
1373 if (data.length != size)
1374 krb5_abortx(context, "internal asn.1 encoder error");
1376 ret = krb5_encrypt_EncryptedData(context, session,
1377 KRB5_KU_PA_SERVER_REFERRAL,
1378 data.data, data.length,
1379 0 /* kvno */, &ed);
1380 free(data.data);
1381 if (ret)
1382 return ret;
1384 ASN1_MALLOC_ENCODE(EncryptedData,
1385 outdata->data, outdata->length,
1386 &ed, &size, ret);
1387 free_EncryptedData(&ed);
1388 if (ret)
1389 return ret;
1390 if (outdata->length != size)
1391 krb5_abortx(context, "internal asn.1 encoder error");
1393 return 0;
1394 eout:
1395 free_PA_ServerReferralData(&ref);
1396 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1397 return ENOMEM;
1400 static krb5_error_code
1401 tgs_build_reply(krb5_context context,
1402 krb5_kdc_configuration *config,
1403 KDC_REQ *req,
1404 KDC_REQ_BODY *b,
1405 hdb_entry_ex *krbtgt,
1406 krb5_enctype krbtgt_etype,
1407 const krb5_keyblock *replykey,
1408 int rk_is_subkey,
1409 krb5_ticket *ticket,
1410 krb5_data *reply,
1411 const char *from,
1412 const char **e_text,
1413 AuthorizationData **auth_data,
1414 const struct sockaddr *from_addr)
1416 krb5_error_code ret;
1417 krb5_principal cp = NULL, sp = NULL;
1418 krb5_principal client_principal = NULL;
1419 char *spn = NULL, *cpn = NULL;
1420 hdb_entry_ex *server = NULL, *client = NULL;
1421 HDB *clientdb;
1422 krb5_realm ref_realm = NULL;
1423 EncTicketPart *tgt = &ticket->ticket;
1424 krb5_principals spp = NULL;
1425 const EncryptionKey *ekey;
1426 krb5_keyblock sessionkey;
1427 krb5_kvno kvno;
1428 krb5_data rspac;
1430 METHOD_DATA enc_pa_data;
1432 PrincipalName *s;
1433 Realm r;
1434 int nloop = 0;
1435 EncTicketPart adtkt;
1436 char opt_str[128];
1437 int signedpath = 0;
1439 Key *tkey;
1441 memset(&sessionkey, 0, sizeof(sessionkey));
1442 memset(&adtkt, 0, sizeof(adtkt));
1443 krb5_data_zero(&rspac);
1444 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1446 s = b->sname;
1447 r = b->realm;
1449 if(b->kdc_options.enc_tkt_in_skey){
1450 Ticket *t;
1451 hdb_entry_ex *uu;
1452 krb5_principal p;
1453 Key *uukey;
1455 if(b->additional_tickets == NULL ||
1456 b->additional_tickets->len == 0){
1457 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1458 kdc_log(context, config, 0,
1459 "No second ticket present in request");
1460 goto out;
1462 t = &b->additional_tickets->val[0];
1463 if(!get_krbtgt_realm(&t->sname)){
1464 kdc_log(context, config, 0,
1465 "Additional ticket is not a ticket-granting ticket");
1466 ret = KRB5KDC_ERR_POLICY;
1467 goto out;
1469 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1470 ret = _kdc_db_fetch(context, config, p,
1471 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1472 NULL, &uu);
1473 krb5_free_principal(context, p);
1474 if(ret){
1475 if (ret == HDB_ERR_NOENTRY)
1476 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1477 goto out;
1479 ret = hdb_enctype2key(context, &uu->entry,
1480 t->enc_part.etype, &uukey);
1481 if(ret){
1482 _kdc_free_ent(context, uu);
1483 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1484 goto out;
1486 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1487 _kdc_free_ent(context, uu);
1488 if(ret)
1489 goto out;
1491 ret = verify_flags(context, config, &adtkt, spn);
1492 if (ret)
1493 goto out;
1495 s = &adtkt.cname;
1496 r = adtkt.crealm;
1499 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1500 ret = krb5_unparse_name(context, sp, &spn);
1501 if (ret)
1502 goto out;
1503 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1504 ret = krb5_unparse_name(context, cp, &cpn);
1505 if (ret)
1506 goto out;
1507 unparse_flags (KDCOptions2int(b->kdc_options),
1508 asn1_KDCOptions_units(),
1509 opt_str, sizeof(opt_str));
1510 if(*opt_str)
1511 kdc_log(context, config, 0,
1512 "TGS-REQ %s from %s for %s [%s]",
1513 cpn, from, spn, opt_str);
1514 else
1515 kdc_log(context, config, 0,
1516 "TGS-REQ %s from %s for %s", cpn, from, spn);
1519 * Fetch server
1522 server_lookup:
1523 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1524 NULL, &server);
1526 if(ret){
1527 const char *new_rlm, *msg;
1528 Realm req_rlm;
1529 krb5_realm *realms;
1531 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1532 if(nloop++ < 2) {
1533 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1534 if(new_rlm) {
1535 kdc_log(context, config, 5, "krbtgt for realm %s "
1536 "not found, trying %s",
1537 req_rlm, new_rlm);
1538 krb5_free_principal(context, sp);
1539 free(spn);
1540 krb5_make_principal(context, &sp, r,
1541 KRB5_TGS_NAME, new_rlm, NULL);
1542 ret = krb5_unparse_name(context, sp, &spn);
1543 if (ret)
1544 goto out;
1546 if (ref_realm)
1547 free(ref_realm);
1548 ref_realm = strdup(new_rlm);
1549 goto server_lookup;
1552 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1553 if (strcmp(realms[0], sp->realm) != 0) {
1554 kdc_log(context, config, 5,
1555 "Returning a referral to realm %s for "
1556 "server %s that was not found",
1557 realms[0], spn);
1558 krb5_free_principal(context, sp);
1559 free(spn);
1560 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1561 realms[0], NULL);
1562 ret = krb5_unparse_name(context, sp, &spn);
1563 if (ret)
1564 goto out;
1566 if (ref_realm)
1567 free(ref_realm);
1568 ref_realm = strdup(realms[0]);
1570 krb5_free_host_realm(context, realms);
1571 goto server_lookup;
1573 krb5_free_host_realm(context, realms);
1575 msg = krb5_get_error_message(context, ret);
1576 kdc_log(context, config, 0,
1577 "Server not found in database: %s: %s", spn, msg);
1578 krb5_free_error_message(context, msg);
1579 if (ret == HDB_ERR_NOENTRY)
1580 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1581 goto out;
1584 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1585 &clientdb, &client);
1586 if(ret) {
1587 const char *krbtgt_realm, *msg;
1590 * If the client belongs to the same realm as our krbtgt, it
1591 * should exist in the local database.
1595 krbtgt_realm =
1596 krb5_principal_get_comp_string(context,
1597 krbtgt->entry.principal, 1);
1599 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1600 if (ret == HDB_ERR_NOENTRY)
1601 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1602 kdc_log(context, config, 1, "Client no longer in database: %s",
1603 cpn);
1604 goto out;
1607 msg = krb5_get_error_message(context, ret);
1608 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1609 krb5_free_error_message(context, msg);
1613 * Select enctype, return key and kvno.
1617 krb5_enctype etype;
1619 if(b->kdc_options.enc_tkt_in_skey) {
1620 int i;
1621 ekey = &adtkt.key;
1622 for(i = 0; i < b->etype.len; i++)
1623 if (b->etype.val[i] == adtkt.key.keytype)
1624 break;
1625 if(i == b->etype.len) {
1626 kdc_log(context, config, 0,
1627 "Addition ticket have not matching etypes");
1628 krb5_clear_error_message(context);
1629 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1630 goto out;
1632 etype = b->etype.val[i];
1633 kvno = 0;
1634 } else {
1635 Key *skey;
1637 ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1638 &skey, &etype);
1639 if(ret) {
1640 kdc_log(context, config, 0,
1641 "Server (%s) has no support for etypes", spn);
1642 goto out;
1644 ekey = &skey->key;
1645 kvno = server->entry.kvno;
1648 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1649 if (ret)
1650 goto out;
1654 * Check that service is in the same realm as the krbtgt. If it's
1655 * not the same, it's someone that is using a uni-directional trust
1656 * backward.
1659 if (strcmp(krb5_principal_get_realm(context, sp),
1660 krb5_principal_get_comp_string(context,
1661 krbtgt->entry.principal,
1662 1)) != 0) {
1663 char *tpn;
1664 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1665 kdc_log(context, config, 0,
1666 "Request with wrong krbtgt: %s",
1667 (ret == 0) ? tpn : "<unknown>");
1668 if(ret == 0)
1669 free(tpn);
1670 ret = KRB5KRB_AP_ERR_NOT_US;
1671 goto out;
1675 * Validate authoriation data
1678 ret = hdb_enctype2key(context, &krbtgt->entry,
1679 krbtgt_etype, &tkey);
1680 if(ret) {
1681 kdc_log(context, config, 0,
1682 "Failed to find key for krbtgt PAC check");
1683 goto out;
1686 ret = check_PAC(context, config, cp,
1687 client, server, ekey, &tkey->key,
1688 tgt, &rspac, &signedpath);
1689 if (ret) {
1690 const char *msg = krb5_get_error_message(context, ret);
1691 kdc_log(context, config, 0,
1692 "Verify PAC failed for %s (%s) from %s with %s",
1693 spn, cpn, from, msg);
1694 krb5_free_error_message(context, msg);
1695 goto out;
1698 /* also check the krbtgt for signature */
1699 ret = check_KRB5SignedPath(context,
1700 config,
1701 krbtgt,
1703 tgt,
1704 &spp,
1705 &signedpath);
1706 if (ret) {
1707 const char *msg = krb5_get_error_message(context, ret);
1708 kdc_log(context, config, 0,
1709 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1710 spn, cpn, from, msg);
1711 krb5_free_error_message(context, msg);
1712 goto out;
1716 * Process request
1719 client_principal = cp;
1721 if (client) {
1722 const PA_DATA *sdata;
1723 int i = 0;
1725 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1726 if (sdata) {
1727 krb5_crypto crypto;
1728 krb5_data datack;
1729 PA_S4U2Self self;
1730 char *selfcpn = NULL;
1731 const char *str;
1733 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1734 sdata->padata_value.length,
1735 &self, NULL);
1736 if (ret) {
1737 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1738 goto out;
1741 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1742 if (ret)
1743 goto out;
1745 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1746 if (ret) {
1747 const char *msg = krb5_get_error_message(context, ret);
1748 free_PA_S4U2Self(&self);
1749 krb5_data_free(&datack);
1750 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1751 krb5_free_error_message(context, msg);
1752 goto out;
1755 ret = krb5_verify_checksum(context,
1756 crypto,
1757 KRB5_KU_OTHER_CKSUM,
1758 datack.data,
1759 datack.length,
1760 &self.cksum);
1761 krb5_data_free(&datack);
1762 krb5_crypto_destroy(context, crypto);
1763 if (ret) {
1764 const char *msg = krb5_get_error_message(context, ret);
1765 free_PA_S4U2Self(&self);
1766 kdc_log(context, config, 0,
1767 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1768 krb5_free_error_message(context, msg);
1769 goto out;
1772 ret = _krb5_principalname2krb5_principal(context,
1773 &client_principal,
1774 self.name,
1775 self.realm);
1776 free_PA_S4U2Self(&self);
1777 if (ret)
1778 goto out;
1780 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1781 if (ret)
1782 goto out;
1785 * Check that service doing the impersonating is
1786 * requesting a ticket to it-self.
1788 if (krb5_principal_compare(context, cp, sp) != TRUE) {
1789 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1790 "to impersonate some other user "
1791 "(tried for user %s to service %s)",
1792 cpn, selfcpn, spn);
1793 free(selfcpn);
1794 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1795 goto out;
1799 * If the service isn't trusted for authentication to
1800 * delegation, remove the forward flag.
1803 if (client->entry.flags.trusted_for_delegation) {
1804 str = "[forwardable]";
1805 } else {
1806 b->kdc_options.forwardable = 0;
1807 str = "";
1809 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1810 "service %s %s", cpn, selfcpn, spn, str);
1811 free(selfcpn);
1816 * Constrained delegation
1819 if (client != NULL
1820 && b->additional_tickets != NULL
1821 && b->additional_tickets->len != 0
1822 && b->kdc_options.enc_tkt_in_skey == 0)
1824 int ad_signedpath = 0;
1825 Key *clientkey;
1826 Ticket *t;
1827 char *str;
1830 * Require that the KDC have issued the service's krbtgt (not
1831 * self-issued ticket with kimpersonate(1).
1833 if (!signedpath) {
1834 ret = KRB5KDC_ERR_BADOPTION;
1835 kdc_log(context, config, 0,
1836 "Constrained delegation done on service ticket %s/%s",
1837 cpn, spn);
1838 goto out;
1841 t = &b->additional_tickets->val[0];
1843 ret = hdb_enctype2key(context, &client->entry,
1844 t->enc_part.etype, &clientkey);
1845 if(ret){
1846 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1847 goto out;
1850 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1851 if (ret) {
1852 kdc_log(context, config, 0,
1853 "failed to decrypt ticket for "
1854 "constrained delegation from %s to %s ", cpn, spn);
1855 goto out;
1858 /* check that ticket is valid */
1859 if (adtkt.flags.forwardable == 0) {
1860 kdc_log(context, config, 0,
1861 "Missing forwardable flag on ticket for "
1862 "constrained delegation from %s to %s ", cpn, spn);
1863 ret = KRB5KDC_ERR_BADOPTION;
1864 goto out;
1867 ret = check_constrained_delegation(context, config, clientdb,
1868 client, sp);
1869 if (ret) {
1870 kdc_log(context, config, 0,
1871 "constrained delegation from %s to %s not allowed",
1872 cpn, spn);
1873 goto out;
1876 ret = _krb5_principalname2krb5_principal(context,
1877 &client_principal,
1878 adtkt.cname,
1879 adtkt.crealm);
1880 if (ret)
1881 goto out;
1883 ret = krb5_unparse_name(context, client_principal, &str);
1884 if (ret)
1885 goto out;
1887 ret = verify_flags(context, config, &adtkt, str);
1888 if (ret) {
1889 free(str);
1890 goto out;
1894 * Check that the KDC issued the user's ticket.
1896 ret = check_KRB5SignedPath(context,
1897 config,
1898 krbtgt,
1900 &adtkt,
1901 NULL,
1902 &ad_signedpath);
1903 if (ret == 0 && !ad_signedpath)
1904 ret = KRB5KDC_ERR_BADOPTION;
1905 if (ret) {
1906 const char *msg = krb5_get_error_message(context, ret);
1907 kdc_log(context, config, 0,
1908 "KRB5SignedPath check from service %s failed "
1909 "for delegation to %s for client %s "
1910 "from %s failed with %s",
1911 spn, str, cpn, from, msg);
1912 krb5_free_error_message(context, msg);
1913 free(str);
1914 goto out;
1917 kdc_log(context, config, 0, "constrained delegation for %s "
1918 "from %s to %s", str, cpn, spn);
1919 free(str);
1923 * Check flags
1926 ret = kdc_check_flags(context, config,
1927 client, cpn,
1928 server, spn,
1929 FALSE);
1930 if(ret)
1931 goto out;
1933 if((b->kdc_options.validate || b->kdc_options.renew) &&
1934 !krb5_principal_compare(context,
1935 krbtgt->entry.principal,
1936 server->entry.principal)){
1937 kdc_log(context, config, 0, "Inconsistent request.");
1938 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1939 goto out;
1942 /* check for valid set of addresses */
1943 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1944 ret = KRB5KRB_AP_ERR_BADADDR;
1945 kdc_log(context, config, 0, "Request from wrong address");
1946 goto out;
1950 * If this is an referral, add server referral data to the
1951 * auth_data reply .
1953 if (ref_realm) {
1954 PA_DATA pa;
1955 krb5_crypto crypto;
1957 kdc_log(context, config, 0,
1958 "Adding server referral to %s", ref_realm);
1960 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1961 if (ret)
1962 goto out;
1964 ret = build_server_referral(context, config, crypto, ref_realm,
1965 NULL, s, &pa.padata_value);
1966 krb5_crypto_destroy(context, crypto);
1967 if (ret) {
1968 kdc_log(context, config, 0,
1969 "Failed building server referral");
1970 goto out;
1972 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1974 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1975 krb5_data_free(&pa.padata_value);
1976 if (ret) {
1977 kdc_log(context, config, 0,
1978 "Add server referral METHOD-DATA failed");
1979 goto out;
1987 ret = tgs_make_reply(context,
1988 config,
1990 client_principal,
1991 tgt,
1992 replykey,
1993 rk_is_subkey,
1994 ekey,
1995 &sessionkey,
1996 kvno,
1997 *auth_data,
1998 server,
2000 spn,
2001 client,
2003 krbtgt,
2004 krbtgt_etype,
2005 spp,
2006 &rspac,
2007 &enc_pa_data,
2008 e_text,
2009 reply);
2011 out:
2012 free(spn);
2013 free(cpn);
2015 krb5_data_free(&rspac);
2016 krb5_free_keyblock_contents(context, &sessionkey);
2017 if(server)
2018 _kdc_free_ent(context, server);
2019 if(client)
2020 _kdc_free_ent(context, client);
2022 if (client_principal && client_principal != cp)
2023 krb5_free_principal(context, client_principal);
2024 if (cp)
2025 krb5_free_principal(context, cp);
2026 if (sp)
2027 krb5_free_principal(context, sp);
2028 if (ref_realm)
2029 free(ref_realm);
2030 free_METHOD_DATA(&enc_pa_data);
2032 free_EncTicketPart(&adtkt);
2034 return ret;
2041 krb5_error_code
2042 _kdc_tgs_rep(krb5_context context,
2043 krb5_kdc_configuration *config,
2044 KDC_REQ *req,
2045 krb5_data *data,
2046 const char *from,
2047 struct sockaddr *from_addr,
2048 int datagram_reply)
2050 AuthorizationData *auth_data = NULL;
2051 krb5_error_code ret;
2052 int i = 0;
2053 const PA_DATA *tgs_req;
2055 hdb_entry_ex *krbtgt = NULL;
2056 krb5_ticket *ticket = NULL;
2057 const char *e_text = NULL;
2058 krb5_enctype krbtgt_etype = ETYPE_NULL;
2060 krb5_keyblock *replykey = NULL;
2061 int rk_is_subkey = 0;
2062 time_t *csec = NULL;
2063 int *cusec = NULL;
2065 if(req->padata == NULL){
2066 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2067 kdc_log(context, config, 0,
2068 "TGS-REQ from %s without PA-DATA", from);
2069 goto out;
2072 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2074 if(tgs_req == NULL){
2075 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2077 kdc_log(context, config, 0,
2078 "TGS-REQ from %s without PA-TGS-REQ", from);
2079 goto out;
2081 ret = tgs_parse_request(context, config,
2082 &req->req_body, tgs_req,
2083 &krbtgt,
2084 &krbtgt_etype,
2085 &ticket,
2086 &e_text,
2087 from, from_addr,
2088 &csec, &cusec,
2089 &auth_data,
2090 &replykey,
2091 &rk_is_subkey);
2092 if (ret) {
2093 kdc_log(context, config, 0,
2094 "Failed parsing TGS-REQ from %s", from);
2095 goto out;
2098 ret = tgs_build_reply(context,
2099 config,
2100 req,
2101 &req->req_body,
2102 krbtgt,
2103 krbtgt_etype,
2104 replykey,
2105 rk_is_subkey,
2106 ticket,
2107 data,
2108 from,
2109 &e_text,
2110 &auth_data,
2111 from_addr);
2112 if (ret) {
2113 kdc_log(context, config, 0,
2114 "Failed building TGS-REP to %s", from);
2115 goto out;
2118 /* */
2119 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2120 krb5_data_free(data);
2121 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2122 e_text = "Reply packet too large";
2125 out:
2126 if (replykey)
2127 krb5_free_keyblock(context, replykey);
2128 if(ret && data->data == NULL){
2129 krb5_mk_error(context,
2130 ret,
2131 NULL,
2132 NULL,
2133 NULL,
2134 NULL,
2135 csec,
2136 cusec,
2137 data);
2139 free(csec);
2140 free(cusec);
2141 if (ticket)
2142 krb5_free_ticket(context, ticket);
2143 if(krbtgt)
2144 _kdc_free_ent(context, krbtgt);
2146 if (auth_data) {
2147 free_AuthorizationData(auth_data);
2148 free(auth_data);
2151 return 0;