2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
37 * return the realm of a krbtgt-ticket or NULL
41 get_krbtgt_realm(const PrincipalName *p)
43 if(p->name_string.len == 2
44 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
45 return p->name_string.val[1];
51 * The KDC might add a signed path to the ticket authorization data
52 * field. This is to avoid server impersonating clients and the
53 * request constrained delegation.
55 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
56 * entry of type KRB5SignedPath.
59 static krb5_error_code
60 find_KRB5SignedPath(krb5_context context,
61 const AuthorizationData *ad,
64 AuthorizationData child;
68 if (ad == NULL || ad->len == 0)
69 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
73 if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
74 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
76 ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
77 ad->val[pos].ad_data.length,
81 krb5_set_error_message(context, ret, "Failed to decode "
82 "IF_RELEVANT with %d", ret);
87 free_AuthorizationData(&child);
88 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
91 if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
92 free_AuthorizationData(&child);
93 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
97 ret = der_copy_octet_string(&child.val[0].ad_data, data);
98 free_AuthorizationData(&child);
103 _kdc_add_KRB5SignedPath(krb5_context context,
104 krb5_kdc_configuration *config,
105 hdb_entry_ex *krbtgt,
106 krb5_enctype enctype,
107 krb5_principal client,
108 krb5_const_principal server,
109 krb5_principals principals,
115 krb5_crypto crypto = NULL;
118 if (server && principals) {
119 ret = add_Principals(principals, server);
125 KRB5SignedPathData spd;
128 spd.authtime = tkt->authtime;
129 spd.delegated = principals;
130 spd.method_data = NULL;
132 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
136 if (data.length != size)
137 krb5_abortx(context, "internal asn.1 encoder error");
142 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
144 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
152 * Fill in KRB5SignedPath
156 sp.delegated = principals;
157 sp.method_data = NULL;
159 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
160 data.data, data.length, &sp.cksum);
161 krb5_crypto_destroy(context, crypto);
166 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
167 free_Checksum(&sp.cksum);
170 if (data.length != size)
171 krb5_abortx(context, "internal asn.1 encoder error");
175 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
176 * authorization data field.
179 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
180 KRB5_AUTHDATA_SIGNTICKET, &data);
181 krb5_data_free(&data);
186 static krb5_error_code
187 check_KRB5SignedPath(krb5_context context,
188 krb5_kdc_configuration *config,
189 hdb_entry_ex *krbtgt,
192 krb5_principals *delegated,
197 krb5_crypto crypto = NULL;
202 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
204 KRB5SignedPathData spd;
208 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
209 krb5_data_free(&data);
214 spd.authtime = tkt->authtime;
215 spd.delegated = sp.delegated;
216 spd.method_data = sp.method_data;
218 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
221 free_KRB5SignedPath(&sp);
224 if (data.length != size)
225 krb5_abortx(context, "internal asn.1 encoder error");
229 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
231 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
234 free_KRB5SignedPath(&sp);
238 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
239 data.data, data.length,
241 krb5_crypto_destroy(context, crypto);
244 free_KRB5SignedPath(&sp);
245 kdc_log(context, config, 5,
246 "KRB5SignedPath not signed correctly, not marking as signed");
250 if (delegated && sp.delegated) {
252 *delegated = malloc(sizeof(*sp.delegated));
253 if (*delegated == NULL) {
254 free_KRB5SignedPath(&sp);
258 ret = copy_Principals(*delegated, sp.delegated);
260 free_KRB5SignedPath(&sp);
266 free_KRB5SignedPath(&sp);
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,
290 AuthorizationData *ad = tkt->authorization_data;
294 if (ad == NULL || ad->len == 0)
297 for (i = 0; i < ad->len; i++) {
298 AuthorizationData child;
300 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
303 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
304 ad->val[i].ad_data.length,
308 krb5_set_error_message(context, ret, "Failed to decode "
309 "IF_RELEVANT with %d", ret);
312 for (j = 0; j < child.len; j++) {
314 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
319 ret = krb5_pac_parse(context,
320 child.val[j].ad_data.data,
321 child.val[j].ad_data.length,
323 free_AuthorizationData(&child);
327 ret = krb5_pac_verify(context, pac, tkt->authtime,
331 krb5_pac_free(context, pac);
335 ret = _kdc_pac_verify(context, client_principal,
336 client, server, &pac, &signed_pac);
338 krb5_pac_free(context, pac);
343 * Only re-sign PAC if we could verify it with the PAC
344 * function. The no-verify case happens when we get in
345 * a PAC from cross realm from a Windows domain and
346 * that there is no PAC verification function.
350 ret = _krb5_pac_sign(context, pac, tkt->authtime,
352 server_key, krbtgt_key, rspac);
354 krb5_pac_free(context, pac);
359 free_AuthorizationData(&child);
368 static krb5_error_code
369 check_tgs_flags(krb5_context context,
370 krb5_kdc_configuration *config,
371 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
373 KDCOptions f = b->kdc_options;
376 if(!tgt->flags.invalid || tgt->starttime == NULL){
377 kdc_log(context, config, 0,
378 "Bad request to validate ticket");
379 return KRB5KDC_ERR_BADOPTION;
381 if(*tgt->starttime > kdc_time){
382 kdc_log(context, config, 0,
383 "Early request to validate ticket");
384 return KRB5KRB_AP_ERR_TKT_NYV;
387 et->flags.invalid = 0;
388 }else if(tgt->flags.invalid){
389 kdc_log(context, config, 0,
390 "Ticket-granting ticket has INVALID flag set");
391 return KRB5KRB_AP_ERR_TKT_INVALID;
395 if(!tgt->flags.forwardable){
396 kdc_log(context, config, 0,
397 "Bad request for forwardable ticket");
398 return KRB5KDC_ERR_BADOPTION;
400 et->flags.forwardable = 1;
403 if(!tgt->flags.forwardable){
404 kdc_log(context, config, 0,
405 "Request to forward non-forwardable ticket");
406 return KRB5KDC_ERR_BADOPTION;
408 et->flags.forwarded = 1;
409 et->caddr = b->addresses;
411 if(tgt->flags.forwarded)
412 et->flags.forwarded = 1;
415 if(!tgt->flags.proxiable){
416 kdc_log(context, config, 0,
417 "Bad request for proxiable ticket");
418 return KRB5KDC_ERR_BADOPTION;
420 et->flags.proxiable = 1;
423 if(!tgt->flags.proxiable){
424 kdc_log(context, config, 0,
425 "Request to proxy non-proxiable ticket");
426 return KRB5KDC_ERR_BADOPTION;
429 et->caddr = b->addresses;
434 if(f.allow_postdate){
435 if(!tgt->flags.may_postdate){
436 kdc_log(context, config, 0,
437 "Bad request for post-datable ticket");
438 return KRB5KDC_ERR_BADOPTION;
440 et->flags.may_postdate = 1;
443 if(!tgt->flags.may_postdate){
444 kdc_log(context, config, 0,
445 "Bad request for postdated ticket");
446 return KRB5KDC_ERR_BADOPTION;
449 *et->starttime = *b->from;
450 et->flags.postdated = 1;
451 et->flags.invalid = 1;
452 }else if(b->from && *b->from > kdc_time + context->max_skew){
453 kdc_log(context, config, 0, "Ticket cannot be postdated");
454 return KRB5KDC_ERR_CANNOT_POSTDATE;
458 if(!tgt->flags.renewable || tgt->renew_till == NULL){
459 kdc_log(context, config, 0,
460 "Bad request for renewable ticket");
461 return KRB5KDC_ERR_BADOPTION;
463 et->flags.renewable = 1;
464 ALLOC(et->renew_till);
465 _kdc_fix_time(&b->rtime);
466 *et->renew_till = *b->rtime;
470 if(!tgt->flags.renewable || tgt->renew_till == NULL){
471 kdc_log(context, config, 0,
472 "Request to renew non-renewable ticket");
473 return KRB5KDC_ERR_BADOPTION;
475 old_life = tgt->endtime;
477 old_life -= *tgt->starttime;
479 old_life -= tgt->authtime;
480 et->endtime = *et->starttime + old_life;
481 if (et->renew_till != NULL)
482 et->endtime = min(*et->renew_till, et->endtime);
486 /* checks for excess flags */
487 if(f.request_anonymous && !config->allow_anonymous){
488 kdc_log(context, config, 0,
489 "Request for anonymous ticket");
490 return KRB5KDC_ERR_BADOPTION;
497 * Determine if constrained delegation is allowed from this client to this server
500 static krb5_error_code
501 check_constrained_delegation(krb5_context context,
502 krb5_kdc_configuration *config,
504 hdb_entry_ex *client,
505 krb5_const_principal server)
507 const HDB_Ext_Constrained_delegation_acl *acl;
511 /* if client delegates to itself, that ok */
512 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
515 if (clientdb->hdb_check_constrained_delegation) {
516 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
520 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
522 krb5_clear_error_message(context);
527 for (i = 0; i < acl->len; i++) {
528 if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
532 ret = KRB5KDC_ERR_BADOPTION;
534 kdc_log(context, config, 0,
535 "Bad request for constrained delegation");
540 * Determine if s4u2self is allowed from this client to this server
542 * For example, regardless of the principal being impersonated, if the
543 * 'client' and 'server' are the same, then it's safe.
546 static krb5_error_code
547 check_s4u2self(krb5_context context,
548 krb5_kdc_configuration *config,
550 hdb_entry_ex *client,
551 krb5_const_principal server)
555 /* if client does a s4u2self to itself, that ok */
556 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
559 if (clientdb->hdb_check_s4u2self) {
560 ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
564 ret = KRB5KDC_ERR_BADOPTION;
573 static krb5_error_code
574 verify_flags (krb5_context context,
575 krb5_kdc_configuration *config,
576 const EncTicketPart *et,
579 if(et->endtime < kdc_time){
580 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
581 return KRB5KRB_AP_ERR_TKT_EXPIRED;
583 if(et->flags.invalid){
584 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
585 return KRB5KRB_AP_ERR_TKT_NYV;
594 static krb5_error_code
595 fix_transited_encoding(krb5_context context,
596 krb5_kdc_configuration *config,
597 krb5_boolean check_policy,
598 const TransitedEncoding *tr,
600 const char *client_realm,
601 const char *server_realm,
602 const char *tgt_realm)
604 krb5_error_code ret = 0;
605 char **realms, **tmp;
606 unsigned int num_realms;
609 switch (tr->tr_type) {
610 case DOMAIN_X500_COMPRESS:
614 * Allow empty content of type 0 because that is was Microsoft
615 * generates in their TGT.
617 if (tr->contents.length == 0)
619 kdc_log(context, config, 0,
620 "Transited type 0 with non empty content");
621 return KRB5KDC_ERR_TRTYPE_NOSUPP;
623 kdc_log(context, config, 0,
624 "Unknown transited type: %u", tr->tr_type);
625 return KRB5KDC_ERR_TRTYPE_NOSUPP;
628 ret = krb5_domain_x500_decode(context,
635 krb5_warn(context, ret,
636 "Decoding transited encoding");
639 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
640 /* not us, so add the previous realm to transited set */
641 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
645 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
651 realms[num_realms] = strdup(tgt_realm);
652 if(realms[num_realms] == NULL){
658 if(num_realms == 0) {
659 if(strcmp(client_realm, server_realm))
660 kdc_log(context, config, 0,
661 "cross-realm %s -> %s", client_realm, server_realm);
665 for(i = 0; i < num_realms; i++)
666 l += strlen(realms[i]) + 2;
670 for(i = 0; i < num_realms; i++) {
672 strlcat(rs, ", ", l);
673 strlcat(rs, realms[i], l);
675 kdc_log(context, config, 0,
676 "cross-realm %s -> %s via [%s]",
677 client_realm, server_realm, rs);
682 ret = krb5_check_transited(context, client_realm,
684 realms, num_realms, NULL);
686 krb5_warn(context, ret, "cross-realm %s -> %s",
687 client_realm, server_realm);
690 et->flags.transited_policy_checked = 1;
692 et->transited.tr_type = DOMAIN_X500_COMPRESS;
693 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
695 krb5_warn(context, ret, "Encoding transited encoding");
697 for(i = 0; i < num_realms; i++)
704 static krb5_error_code
705 tgs_make_reply(krb5_context context,
706 krb5_kdc_configuration *config,
708 krb5_const_principal tgt_name,
709 const EncTicketPart *tgt,
710 const krb5_keyblock *replykey,
712 const EncryptionKey *serverkey,
713 const krb5_keyblock *sessionkey,
715 AuthorizationData *auth_data,
716 hdb_entry_ex *server,
717 krb5_principal server_principal,
718 const char *server_name,
719 hdb_entry_ex *client,
720 krb5_principal client_principal,
721 hdb_entry_ex *krbtgt,
722 krb5_enctype krbtgt_etype,
724 const krb5_data *rspac,
725 const METHOD_DATA *enc_pa_data,
732 KDCOptions f = b->kdc_options;
736 memset(&rep, 0, sizeof(rep));
737 memset(&et, 0, sizeof(et));
738 memset(&ek, 0, sizeof(ek));
741 rep.msg_type = krb_tgs_rep;
743 et.authtime = tgt->authtime;
744 _kdc_fix_time(&b->till);
745 et.endtime = min(tgt->endtime, *b->till);
747 *et.starttime = kdc_time;
749 ret = check_tgs_flags(context, config, b, tgt, &et);
753 /* We should check the transited encoding if:
754 1) the request doesn't ask not to be checked
755 2) globally enforcing a check
756 3) principal requires checking
757 4) we allow non-check per-principal, but principal isn't marked as allowing this
758 5) we don't globally allow this
761 #define GLOBAL_FORCE_TRANSITED_CHECK \
762 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
763 #define GLOBAL_ALLOW_PER_PRINCIPAL \
764 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
765 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
766 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
768 /* these will consult the database in future release */
769 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
770 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
772 ret = fix_transited_encoding(context, config,
773 !f.disable_transited_check ||
774 GLOBAL_FORCE_TRANSITED_CHECK ||
775 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
776 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
777 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
778 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
779 &tgt->transited, &et,
780 krb5_principal_get_realm(context, client_principal),
781 krb5_principal_get_realm(context, server->entry.principal),
782 krb5_principal_get_realm(context, krbtgt->entry.principal));
786 copy_Realm(&server_principal->realm, &rep.ticket.realm);
787 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
788 copy_Realm(&tgt_name->realm, &rep.crealm);
790 if (f.request_anonymous)
791 _kdc_make_anonymous_principalname (&rep.cname);
794 copy_PrincipalName(&tgt_name->name, &rep.cname);
795 rep.ticket.tkt_vno = 5;
799 et.caddr = tgt->caddr;
803 life = et.endtime - *et.starttime;
804 if(client && client->entry.max_life)
805 life = min(life, *client->entry.max_life);
806 if(server->entry.max_life)
807 life = min(life, *server->entry.max_life);
808 et.endtime = *et.starttime + life;
810 if(f.renewable_ok && tgt->flags.renewable &&
811 et.renew_till == NULL && et.endtime < *b->till &&
812 tgt->renew_till != NULL)
814 et.flags.renewable = 1;
815 ALLOC(et.renew_till);
816 *et.renew_till = *b->till;
820 renew = *et.renew_till - et.authtime;
821 if(client && client->entry.max_renew)
822 renew = min(renew, *client->entry.max_renew);
823 if(server->entry.max_renew)
824 renew = min(renew, *server->entry.max_renew);
825 *et.renew_till = et.authtime + renew;
829 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
830 *et.starttime = min(*et.starttime, *et.renew_till);
831 et.endtime = min(et.endtime, *et.renew_till);
834 *et.starttime = min(*et.starttime, et.endtime);
836 if(*et.starttime == et.endtime){
837 ret = KRB5KDC_ERR_NEVER_VALID;
840 if(et.renew_till && et.endtime == *et.renew_till){
842 et.renew_till = NULL;
843 et.flags.renewable = 0;
846 et.flags.pre_authent = tgt->flags.pre_authent;
847 et.flags.hw_authent = tgt->flags.hw_authent;
848 et.flags.anonymous = tgt->flags.anonymous;
849 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
853 * No not need to filter out the any PAC from the
854 * auth_data since it's signed by the KDC.
856 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
857 KRB5_AUTHDATA_WIN2K_PAC, rspac);
865 /* XXX check authdata */
867 if (et.authorization_data == NULL) {
868 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
869 if (et.authorization_data == NULL) {
871 krb5_set_error_message(context, ret, "malloc: out of memory");
875 for(i = 0; i < auth_data->len ; i++) {
876 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
878 krb5_set_error_message(context, ret, "malloc: out of memory");
883 /* Filter out type KRB5SignedPath */
884 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
886 if (et.authorization_data->len == 1) {
887 free_AuthorizationData(et.authorization_data);
888 free(et.authorization_data);
889 et.authorization_data = NULL;
891 AuthorizationData *ad = et.authorization_data;
892 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
898 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
901 et.crealm = tgt->crealm;
902 et.cname = tgt_name->name;
905 /* MIT must have at least one last_req */
907 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
908 if (ek.last_req.val == NULL) {
914 ek.authtime = et.authtime;
915 ek.starttime = et.starttime;
916 ek.endtime = et.endtime;
917 ek.renew_till = et.renew_till;
918 ek.srealm = rep.ticket.realm;
919 ek.sname = rep.ticket.sname;
921 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
922 et.endtime, et.renew_till);
924 /* Don't sign cross realm tickets, they can't be checked anyway */
926 char *r = get_krbtgt_realm(&ek.sname);
928 if (r == NULL || strcmp(r, ek.srealm) == 0) {
929 ret = _kdc_add_KRB5SignedPath(context,
942 if (enc_pa_data->len) {
943 rep.padata = calloc(1, sizeof(*rep.padata));
944 if (rep.padata == NULL) {
948 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
953 if (krb5_enctype_valid(context, et.key.keytype) != 0
954 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
956 krb5_enctype_enable(context, et.key.keytype);
961 /* It is somewhat unclear where the etype in the following
962 encryption should come from. What we have is a session
963 key in the passed tgt, and a list of preferred etypes
964 *for the new ticket*. Should we pick the best possible
965 etype, given the keytype in the tgt, or should we look
966 at the etype list here as well? What if the tgt
967 session key is DES3 and we want a ticket with a (say)
968 CAST session key. Should the DES3 etype be added to the
969 etype list, even if we don't want a session key with
971 ret = _kdc_encode_reply(context, config,
972 &rep, &et, &ek, et.key.keytype,
974 serverkey, 0, replykey, rk_is_subkey,
977 krb5_enctype_disable(context, et.key.keytype);
981 free_TransitedEncoding(&et.transited);
986 if(et.authorization_data) {
987 free_AuthorizationData(et.authorization_data);
988 free(et.authorization_data);
990 free_LastReq(&ek.last_req);
991 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
992 free_EncryptionKey(&et.key);
996 static krb5_error_code
997 tgs_check_authenticator(krb5_context context,
998 krb5_kdc_configuration *config,
999 krb5_auth_context ac,
1001 const char **e_text,
1004 krb5_authenticator auth;
1008 krb5_error_code ret;
1011 krb5_auth_con_getauthenticator(context, ac, &auth);
1012 if(auth->cksum == NULL){
1013 kdc_log(context, config, 0, "No authenticator in request");
1014 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1018 * according to RFC1510 it doesn't need to be keyed,
1019 * but according to the latest draft it needs to.
1023 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1026 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1027 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1028 auth->cksum->cksumtype);
1029 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1033 /* XXX should not re-encode this */
1034 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1036 const char *msg = krb5_get_error_message(context, ret);
1037 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1038 krb5_free_error_message(context, msg);
1041 if(buf_size != len) {
1043 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1044 *e_text = "KDC internal error";
1045 ret = KRB5KRB_ERR_GENERIC;
1048 ret = krb5_crypto_init(context, key, 0, &crypto);
1050 const char *msg = krb5_get_error_message(context, ret);
1052 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1053 krb5_free_error_message(context, msg);
1056 ret = krb5_verify_checksum(context,
1058 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1063 krb5_crypto_destroy(context, crypto);
1065 const char *msg = krb5_get_error_message(context, ret);
1066 kdc_log(context, config, 0,
1067 "Failed to verify authenticator checksum: %s", msg);
1068 krb5_free_error_message(context, msg);
1071 free_Authenticator(auth);
1081 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1083 const char *new_realm = krb5_config_get_string(context,
1094 need_referral(krb5_context context, krb5_kdc_configuration *config,
1095 const KDCOptions * const options, krb5_principal server,
1096 krb5_realm **realms)
1100 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1103 if (server->name.name_string.len == 1)
1104 name = server->name.name_string.val[0];
1105 else if (server->name.name_string.len > 1)
1106 name = server->name.name_string.val[1];
1110 kdc_log(context, config, 0, "Searching referral for %s", name);
1112 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1115 static krb5_error_code
1116 tgs_parse_request(krb5_context context,
1117 krb5_kdc_configuration *config,
1119 const PA_DATA *tgs_req,
1120 hdb_entry_ex **krbtgt,
1121 krb5_enctype *krbtgt_etype,
1122 krb5_ticket **ticket,
1123 const char **e_text,
1125 const struct sockaddr *from_addr,
1128 AuthorizationData **auth_data,
1129 krb5_keyblock **replykey,
1133 krb5_error_code ret;
1134 krb5_principal princ;
1135 krb5_auth_context ac = NULL;
1136 krb5_flags ap_req_options;
1137 krb5_flags verify_ap_req_flags;
1140 krb5_keyblock *subkey = NULL;
1148 memset(&ap_req, 0, sizeof(ap_req));
1149 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1151 const char *msg = krb5_get_error_message(context, ret);
1152 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1153 krb5_free_error_message(context, msg);
1157 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1158 /* XXX check for ticket.sname == req.sname */
1159 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1160 ret = KRB5KDC_ERR_POLICY; /* ? */
1164 _krb5_principalname2krb5_principal(context,
1166 ap_req.ticket.sname,
1167 ap_req.ticket.realm);
1169 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1172 const char *msg = krb5_get_error_message(context, ret);
1174 ret = krb5_unparse_name(context, princ, &p);
1176 p = "<unparse_name failed>";
1177 krb5_free_principal(context, princ);
1178 kdc_log(context, config, 0,
1179 "Ticket-granting ticket not found in database: %s", msg);
1180 krb5_free_error_message(context, msg);
1183 ret = KRB5KRB_AP_ERR_NOT_US;
1187 if(ap_req.ticket.enc_part.kvno &&
1188 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1191 ret = krb5_unparse_name (context, princ, &p);
1192 krb5_free_principal(context, princ);
1194 p = "<unparse_name failed>";
1195 kdc_log(context, config, 0,
1196 "Ticket kvno = %d, DB kvno = %d (%s)",
1197 *ap_req.ticket.enc_part.kvno,
1198 (*krbtgt)->entry.kvno,
1202 ret = KRB5KRB_AP_ERR_BADKEYVER;
1206 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1208 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1209 ap_req.ticket.enc_part.etype, &tkey);
1211 char *str = NULL, *p = NULL;
1213 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1214 krb5_unparse_name(context, princ, &p);
1215 kdc_log(context, config, 0,
1216 "No server key with enctype %s found for %s",
1217 str ? str : "<unknown enctype>",
1218 p ? p : "<unparse_name failed>");
1221 ret = KRB5KRB_AP_ERR_BADKEYVER;
1225 if (b->kdc_options.validate)
1226 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1228 verify_ap_req_flags = 0;
1230 ret = krb5_verify_ap_req2(context,
1235 verify_ap_req_flags,
1238 KRB5_KU_TGS_REQ_AUTH);
1240 krb5_free_principal(context, princ);
1242 const char *msg = krb5_get_error_message(context, ret);
1243 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1244 krb5_free_error_message(context, msg);
1249 krb5_authenticator auth;
1251 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1253 *csec = malloc(sizeof(**csec));
1254 if (*csec == NULL) {
1255 krb5_free_authenticator(context, &auth);
1256 kdc_log(context, config, 0, "malloc failed");
1259 **csec = auth->ctime;
1260 *cusec = malloc(sizeof(**cusec));
1261 if (*cusec == NULL) {
1262 krb5_free_authenticator(context, &auth);
1263 kdc_log(context, config, 0, "malloc failed");
1266 **cusec = auth->cusec;
1267 krb5_free_authenticator(context, &auth);
1271 ret = tgs_check_authenticator(context, config,
1272 ac, b, e_text, &(*ticket)->ticket.key);
1274 krb5_auth_con_free(context, ac);
1278 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1281 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1283 const char *msg = krb5_get_error_message(context, ret);
1284 krb5_auth_con_free(context, ac);
1285 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1286 krb5_free_error_message(context, msg);
1290 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1293 ret = krb5_auth_con_getkey(context, ac, &subkey);
1295 const char *msg = krb5_get_error_message(context, ret);
1296 krb5_auth_con_free(context, ac);
1297 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1298 krb5_free_error_message(context, msg);
1303 krb5_auth_con_free(context, ac);
1304 kdc_log(context, config, 0,
1305 "Failed to get key for enc-authorization-data");
1306 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1312 if (b->enc_authorization_data) {
1315 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1317 const char *msg = krb5_get_error_message(context, ret);
1318 krb5_auth_con_free(context, ac);
1319 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1320 krb5_free_error_message(context, msg);
1323 ret = krb5_decrypt_EncryptedData (context,
1326 b->enc_authorization_data,
1328 krb5_crypto_destroy(context, crypto);
1330 krb5_auth_con_free(context, ac);
1331 kdc_log(context, config, 0,
1332 "Failed to decrypt enc-authorization-data");
1333 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1337 if (*auth_data == NULL) {
1338 krb5_auth_con_free(context, ac);
1339 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1342 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1344 krb5_auth_con_free(context, ac);
1347 kdc_log(context, config, 0, "Failed to decode authorization data");
1348 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1353 krb5_auth_con_free(context, ac);
1356 free_AP_REQ(&ap_req);
1361 static krb5_error_code
1362 build_server_referral(krb5_context context,
1363 krb5_kdc_configuration *config,
1364 krb5_crypto session,
1365 krb5_const_realm referred_realm,
1366 const PrincipalName *true_principal_name,
1367 const PrincipalName *requested_principal,
1370 PA_ServerReferralData ref;
1371 krb5_error_code ret;
1376 memset(&ref, 0, sizeof(ref));
1378 if (referred_realm) {
1379 ALLOC(ref.referred_realm);
1380 if (ref.referred_realm == NULL)
1382 *ref.referred_realm = strdup(referred_realm);
1383 if (*ref.referred_realm == NULL)
1386 if (true_principal_name) {
1387 ALLOC(ref.true_principal_name);
1388 if (ref.true_principal_name == NULL)
1390 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1394 if (requested_principal) {
1395 ALLOC(ref.requested_principal_name);
1396 if (ref.requested_principal_name == NULL)
1398 ret = copy_PrincipalName(requested_principal,
1399 ref.requested_principal_name);
1404 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1405 data.data, data.length,
1407 free_PA_ServerReferralData(&ref);
1410 if (data.length != size)
1411 krb5_abortx(context, "internal asn.1 encoder error");
1413 ret = krb5_encrypt_EncryptedData(context, session,
1414 KRB5_KU_PA_SERVER_REFERRAL,
1415 data.data, data.length,
1421 ASN1_MALLOC_ENCODE(EncryptedData,
1422 outdata->data, outdata->length,
1424 free_EncryptedData(&ed);
1427 if (outdata->length != size)
1428 krb5_abortx(context, "internal asn.1 encoder error");
1432 free_PA_ServerReferralData(&ref);
1433 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1437 static krb5_error_code
1438 tgs_build_reply(krb5_context context,
1439 krb5_kdc_configuration *config,
1442 hdb_entry_ex *krbtgt,
1443 krb5_enctype krbtgt_etype,
1444 const krb5_keyblock *replykey,
1446 krb5_ticket *ticket,
1449 const char **e_text,
1450 AuthorizationData **auth_data,
1451 const struct sockaddr *from_addr)
1453 krb5_error_code ret;
1454 krb5_principal cp = NULL, sp = NULL;
1455 krb5_principal client_principal = NULL;
1456 char *spn = NULL, *cpn = NULL;
1457 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1458 HDB *clientdb, *s4u2self_impersonated_clientdb;
1459 krb5_realm ref_realm = NULL;
1460 EncTicketPart *tgt = &ticket->ticket;
1461 krb5_principals spp = NULL;
1462 const EncryptionKey *ekey;
1463 krb5_keyblock sessionkey;
1467 METHOD_DATA enc_pa_data;
1472 EncTicketPart adtkt;
1478 memset(&sessionkey, 0, sizeof(sessionkey));
1479 memset(&adtkt, 0, sizeof(adtkt));
1480 krb5_data_zero(&rspac);
1481 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1486 if(b->kdc_options.enc_tkt_in_skey){
1492 if(b->additional_tickets == NULL ||
1493 b->additional_tickets->len == 0){
1494 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1495 kdc_log(context, config, 0,
1496 "No second ticket present in request");
1499 t = &b->additional_tickets->val[0];
1500 if(!get_krbtgt_realm(&t->sname)){
1501 kdc_log(context, config, 0,
1502 "Additional ticket is not a ticket-granting ticket");
1503 ret = KRB5KDC_ERR_POLICY;
1506 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1507 ret = _kdc_db_fetch(context, config, p,
1508 HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1510 krb5_free_principal(context, p);
1512 if (ret == HDB_ERR_NOENTRY)
1513 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1516 ret = hdb_enctype2key(context, &uu->entry,
1517 t->enc_part.etype, &uukey);
1519 _kdc_free_ent(context, uu);
1520 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1523 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1524 _kdc_free_ent(context, uu);
1528 ret = verify_flags(context, config, &adtkt, spn);
1536 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1537 ret = krb5_unparse_name(context, sp, &spn);
1540 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1541 ret = krb5_unparse_name(context, cp, &cpn);
1544 unparse_flags (KDCOptions2int(b->kdc_options),
1545 asn1_KDCOptions_units(),
1546 opt_str, sizeof(opt_str));
1548 kdc_log(context, config, 0,
1549 "TGS-REQ %s from %s for %s [%s]",
1550 cpn, from, spn, opt_str);
1552 kdc_log(context, config, 0,
1553 "TGS-REQ %s from %s for %s", cpn, from, spn);
1560 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1564 const char *new_rlm, *msg;
1568 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1570 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1572 kdc_log(context, config, 5, "krbtgt for realm %s "
1573 "not found, trying %s",
1575 krb5_free_principal(context, sp);
1577 krb5_make_principal(context, &sp, r,
1578 KRB5_TGS_NAME, new_rlm, NULL);
1579 ret = krb5_unparse_name(context, sp, &spn);
1585 ref_realm = strdup(new_rlm);
1589 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1590 if (strcmp(realms[0], sp->realm) != 0) {
1591 kdc_log(context, config, 5,
1592 "Returning a referral to realm %s for "
1593 "server %s that was not found",
1595 krb5_free_principal(context, sp);
1597 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1599 ret = krb5_unparse_name(context, sp, &spn);
1605 ref_realm = strdup(realms[0]);
1607 krb5_free_host_realm(context, realms);
1610 krb5_free_host_realm(context, realms);
1612 msg = krb5_get_error_message(context, ret);
1613 kdc_log(context, config, 0,
1614 "Server not found in database: %s: %s", spn, msg);
1615 krb5_free_error_message(context, msg);
1616 if (ret == HDB_ERR_NOENTRY)
1617 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1621 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1622 &clientdb, &client);
1624 const char *krbtgt_realm, *msg;
1627 * If the client belongs to the same realm as our krbtgt, it
1628 * should exist in the local database.
1633 krb5_principal_get_comp_string(context,
1634 krbtgt->entry.principal, 1);
1636 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1637 if (ret == HDB_ERR_NOENTRY)
1638 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1639 kdc_log(context, config, 1, "Client no longer in database: %s",
1644 msg = krb5_get_error_message(context, ret);
1645 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1646 krb5_free_error_message(context, msg);
1650 * Select enctype, return key and kvno.
1656 if(b->kdc_options.enc_tkt_in_skey) {
1659 for(i = 0; i < b->etype.len; i++)
1660 if (b->etype.val[i] == adtkt.key.keytype)
1662 if(i == b->etype.len) {
1663 kdc_log(context, config, 0,
1664 "Addition ticket have not matching etypes");
1665 krb5_clear_error_message(context);
1666 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1669 etype = b->etype.val[i];
1674 ret = _kdc_find_etype(context, server,
1675 b->etype.val, b->etype.len, &skey);
1677 kdc_log(context, config, 0,
1678 "Server (%s) has no support for etypes", spn);
1682 etype = skey->key.keytype;
1683 kvno = server->entry.kvno;
1686 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1692 * Check that service is in the same realm as the krbtgt. If it's
1693 * not the same, it's someone that is using a uni-directional trust
1697 if (strcmp(krb5_principal_get_realm(context, sp),
1698 krb5_principal_get_comp_string(context,
1699 krbtgt->entry.principal,
1702 ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1703 kdc_log(context, config, 0,
1704 "Request with wrong krbtgt: %s",
1705 (ret == 0) ? tpn : "<unknown>");
1708 ret = KRB5KRB_AP_ERR_NOT_US;
1713 * Validate authoriation data
1716 ret = hdb_enctype2key(context, &krbtgt->entry,
1717 krbtgt_etype, &tkey);
1719 kdc_log(context, config, 0,
1720 "Failed to find key for krbtgt PAC check");
1724 ret = check_PAC(context, config, cp,
1725 client, server, ekey, &tkey->key,
1726 tgt, &rspac, &signedpath);
1728 const char *msg = krb5_get_error_message(context, ret);
1729 kdc_log(context, config, 0,
1730 "Verify PAC failed for %s (%s) from %s with %s",
1731 spn, cpn, from, msg);
1732 krb5_free_error_message(context, msg);
1736 /* also check the krbtgt for signature */
1737 ret = check_KRB5SignedPath(context,
1745 const char *msg = krb5_get_error_message(context, ret);
1746 kdc_log(context, config, 0,
1747 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1748 spn, cpn, from, msg);
1749 krb5_free_error_message(context, msg);
1757 client_principal = cp;
1760 const PA_DATA *sdata;
1763 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1768 char *selfcpn = NULL;
1771 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1772 sdata->padata_value.length,
1775 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1779 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1783 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1785 const char *msg = krb5_get_error_message(context, ret);
1786 free_PA_S4U2Self(&self);
1787 krb5_data_free(&datack);
1788 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1789 krb5_free_error_message(context, msg);
1793 ret = krb5_verify_checksum(context,
1795 KRB5_KU_OTHER_CKSUM,
1799 krb5_data_free(&datack);
1800 krb5_crypto_destroy(context, crypto);
1802 const char *msg = krb5_get_error_message(context, ret);
1803 free_PA_S4U2Self(&self);
1804 kdc_log(context, config, 0,
1805 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1806 krb5_free_error_message(context, msg);
1810 ret = _krb5_principalname2krb5_principal(context,
1814 free_PA_S4U2Self(&self);
1818 ret = krb5_unparse_name(context, client_principal, &selfcpn);
1822 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1825 krb5_data_free(&rspac);
1826 ret = _kdc_db_fetch(context, config, client_principal, HDB_F_GET_CLIENT | HDB_F_CANON,
1827 &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
1832 * If the client belongs to the same realm as our krbtgt, it
1833 * should exist in the local database.
1837 if (ret == HDB_ERR_NOENTRY)
1838 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1839 msg = krb5_get_error_message(context, ret);
1840 kdc_log(context, config, 1, "S2U4Self principal to impersonate %s not found in database: %s", cpn, msg);
1841 krb5_free_error_message(context, msg);
1844 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1846 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1851 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1852 s4u2self_impersonated_client->entry.principal,
1855 krb5_pac_free(context, p);
1857 kdc_log(context, config, 0, "PAC signing failed for -- %s",
1865 * Check that service doing the impersonating is
1866 * requesting a ticket to it-self.
1868 ret = check_s4u2self(context, config, clientdb, client, sp);
1870 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1871 "to impersonate to service "
1872 "(tried for user %s to service %s)",
1879 * If the service isn't trusted for authentication to
1880 * delegation, remove the forward flag.
1883 if (client->entry.flags.trusted_for_delegation) {
1884 str = "[forwardable]";
1886 b->kdc_options.forwardable = 0;
1889 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1890 "service %s %s", cpn, selfcpn, spn, str);
1896 * Constrained delegation
1900 && b->additional_tickets != NULL
1901 && b->additional_tickets->len != 0
1902 && b->kdc_options.enc_tkt_in_skey == 0)
1904 int ad_signedpath = 0;
1910 * Require that the KDC have issued the service's krbtgt (not
1911 * self-issued ticket with kimpersonate(1).
1914 ret = KRB5KDC_ERR_BADOPTION;
1915 kdc_log(context, config, 0,
1916 "Constrained delegation done on service ticket %s/%s",
1921 t = &b->additional_tickets->val[0];
1923 ret = hdb_enctype2key(context, &client->entry,
1924 t->enc_part.etype, &clientkey);
1926 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1930 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1932 kdc_log(context, config, 0,
1933 "failed to decrypt ticket for "
1934 "constrained delegation from %s to %s ", cpn, spn);
1938 /* check that ticket is valid */
1939 if (adtkt.flags.forwardable == 0) {
1940 kdc_log(context, config, 0,
1941 "Missing forwardable flag on ticket for "
1942 "constrained delegation from %s to %s ", cpn, spn);
1943 ret = KRB5KDC_ERR_BADOPTION;
1947 ret = check_constrained_delegation(context, config, clientdb,
1950 kdc_log(context, config, 0,
1951 "constrained delegation from %s to %s not allowed",
1956 ret = _krb5_principalname2krb5_principal(context,
1963 ret = krb5_unparse_name(context, client_principal, &str);
1967 ret = verify_flags(context, config, &adtkt, str);
1974 * Check that the KDC issued the user's ticket.
1976 ret = check_KRB5SignedPath(context,
1983 if (ret == 0 && !ad_signedpath)
1984 ret = KRB5KDC_ERR_BADOPTION;
1986 const char *msg = krb5_get_error_message(context, ret);
1987 kdc_log(context, config, 0,
1988 "KRB5SignedPath check from service %s failed "
1989 "for delegation to %s for client %s "
1990 "from %s failed with %s",
1991 spn, str, cpn, from, msg);
1992 krb5_free_error_message(context, msg);
1997 kdc_log(context, config, 0, "constrained delegation for %s "
1998 "from %s to %s", str, cpn, spn);
2006 ret = kdc_check_flags(context, config,
2013 if((b->kdc_options.validate || b->kdc_options.renew) &&
2014 !krb5_principal_compare(context,
2015 krbtgt->entry.principal,
2016 server->entry.principal)){
2017 kdc_log(context, config, 0, "Inconsistent request.");
2018 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2022 /* check for valid set of addresses */
2023 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2024 ret = KRB5KRB_AP_ERR_BADADDR;
2025 kdc_log(context, config, 0, "Request from wrong address");
2030 * If this is an referral, add server referral data to the
2037 kdc_log(context, config, 0,
2038 "Adding server referral to %s", ref_realm);
2040 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2044 ret = build_server_referral(context, config, crypto, ref_realm,
2045 NULL, s, &pa.padata_value);
2046 krb5_crypto_destroy(context, crypto);
2048 kdc_log(context, config, 0,
2049 "Failed building server referral");
2052 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2054 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2055 krb5_data_free(&pa.padata_value);
2057 kdc_log(context, config, 0,
2058 "Add server referral METHOD-DATA failed");
2067 ret = tgs_make_reply(context,
2095 krb5_data_free(&rspac);
2096 krb5_free_keyblock_contents(context, &sessionkey);
2098 _kdc_free_ent(context, server);
2100 _kdc_free_ent(context, client);
2101 if(s4u2self_impersonated_client)
2102 _kdc_free_ent(context, s4u2self_impersonated_client);
2104 if (client_principal && client_principal != cp)
2105 krb5_free_principal(context, client_principal);
2107 krb5_free_principal(context, cp);
2109 krb5_free_principal(context, sp);
2112 free_METHOD_DATA(&enc_pa_data);
2114 free_EncTicketPart(&adtkt);
2124 _kdc_tgs_rep(krb5_context context,
2125 krb5_kdc_configuration *config,
2129 struct sockaddr *from_addr,
2132 AuthorizationData *auth_data = NULL;
2133 krb5_error_code ret;
2135 const PA_DATA *tgs_req;
2137 hdb_entry_ex *krbtgt = NULL;
2138 krb5_ticket *ticket = NULL;
2139 const char *e_text = NULL;
2140 krb5_enctype krbtgt_etype = ETYPE_NULL;
2142 krb5_keyblock *replykey = NULL;
2143 int rk_is_subkey = 0;
2144 time_t *csec = NULL;
2147 if(req->padata == NULL){
2148 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2149 kdc_log(context, config, 0,
2150 "TGS-REQ from %s without PA-DATA", from);
2154 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2156 if(tgs_req == NULL){
2157 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2159 kdc_log(context, config, 0,
2160 "TGS-REQ from %s without PA-TGS-REQ", from);
2163 ret = tgs_parse_request(context, config,
2164 &req->req_body, tgs_req,
2175 kdc_log(context, config, 0,
2176 "Failed parsing TGS-REQ from %s", from);
2180 ret = tgs_build_reply(context,
2195 kdc_log(context, config, 0,
2196 "Failed building TGS-REP to %s", from);
2201 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2202 krb5_data_free(data);
2203 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2204 e_text = "Reply packet too large";
2209 krb5_free_keyblock(context, replykey);
2210 if(ret && data->data == NULL){
2211 krb5_mk_error(context,
2224 krb5_free_ticket(context, ticket);
2226 _kdc_free_ent(context, krbtgt);
2229 free_AuthorizationData(auth_data);