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];
55 _kdc_check_pac(krb5_context context,
56 krb5_kdc_configuration *config,
57 const krb5_principal client_principal,
58 const krb5_principal delegated_proxy_principal,
62 hdb_entry_ex *ticket_server,
63 const EncryptionKey *server_check_key,
64 const EncryptionKey *krbtgt_check_key,
66 krb5_boolean *kdc_issued,
71 krb5_boolean signedticket;
76 ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
81 if (config->require_pac)
82 ret = KRB5KDC_ERR_TGT_REVOKED;
86 /* Verify the server signature. */
87 ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
88 server_check_key, NULL);
90 krb5_pac_free(context, pac);
94 /* Verify the KDC signatures. */
95 ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal,
96 client, server, krbtgt, &pac);
97 if (ret == KRB5_PLUGIN_NO_HANDLE) {
99 * We can't verify the KDC signatures if the ticket was issued by
100 * another realm's KDC.
102 if (krb5_realm_compare(context, server->entry.principal,
103 ticket_server->entry.principal)) {
104 ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
107 krb5_pac_free(context, pac);
111 /* Discard the PAC if the plugin didn't handle it */
112 krb5_pac_free(context, pac);
113 ret = krb5_pac_init(context, &pac);
117 krb5_pac_free(context, pac);
121 *kdc_issued = signedticket ||
122 krb5_principal_is_krbtgt(context,
123 ticket_server->entry.principal);
130 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
131 const EncTicketPart *tgt)
133 KDCOptions f = b->kdc_options;
136 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
137 * request-anonymous and cname-in-addl-tkt flags for constrained
138 * delegation requests. A true anonymous TGS request will only
139 * have the request-anonymous flag set. (A corollary of this is
140 * that it is not possible to support anonymous constrained
141 * delegation requests, although they would be of limited utility.)
143 return tgt->flags.anonymous ||
144 (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
151 static krb5_error_code
152 check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b,
153 krb5_const_principal tgt_name,
154 const EncTicketPart *tgt, EncTicketPart *et)
156 KDCOptions f = b->kdc_options;
159 if (!tgt->flags.invalid || tgt->starttime == NULL) {
160 _kdc_audit_addreason((kdc_request_t)r,
161 "Bad request to validate ticket");
162 return KRB5KDC_ERR_BADOPTION;
164 if(*tgt->starttime > kdc_time){
165 _kdc_audit_addreason((kdc_request_t)r,
166 "Early request to validate ticket");
167 return KRB5KRB_AP_ERR_TKT_NYV;
170 et->flags.invalid = 0;
171 } else if (tgt->flags.invalid) {
172 _kdc_audit_addreason((kdc_request_t)r,
173 "Ticket-granting ticket has INVALID flag set");
174 return KRB5KRB_AP_ERR_TKT_INVALID;
178 if (!tgt->flags.forwardable) {
179 _kdc_audit_addreason((kdc_request_t)r,
180 "Bad request for forwardable ticket");
181 return KRB5KDC_ERR_BADOPTION;
183 et->flags.forwardable = 1;
186 if (!tgt->flags.forwardable) {
187 _kdc_audit_addreason((kdc_request_t)r,
188 "Request to forward non-forwardable ticket");
189 return KRB5KDC_ERR_BADOPTION;
191 et->flags.forwarded = 1;
192 et->caddr = b->addresses;
194 if(tgt->flags.forwarded)
195 et->flags.forwarded = 1;
198 if (!tgt->flags.proxiable) {
199 _kdc_audit_addreason((kdc_request_t)r,
200 "Bad request for proxiable ticket");
201 return KRB5KDC_ERR_BADOPTION;
203 et->flags.proxiable = 1;
206 if (!tgt->flags.proxiable) {
207 _kdc_audit_addreason((kdc_request_t)r,
208 "Request to proxy non-proxiable ticket");
209 return KRB5KDC_ERR_BADOPTION;
212 et->caddr = b->addresses;
217 if(f.allow_postdate){
218 if (!tgt->flags.may_postdate) {
219 _kdc_audit_addreason((kdc_request_t)r,
220 "Bad request for post-datable ticket");
221 return KRB5KDC_ERR_BADOPTION;
223 et->flags.may_postdate = 1;
226 if (!tgt->flags.may_postdate) {
227 _kdc_audit_addreason((kdc_request_t)r,
228 "Bad request for postdated ticket");
229 return KRB5KDC_ERR_BADOPTION;
232 *et->starttime = *b->from;
233 et->flags.postdated = 1;
234 et->flags.invalid = 1;
235 } else if (b->from && *b->from > kdc_time + r->context->max_skew) {
236 _kdc_audit_addreason((kdc_request_t)r,
237 "Ticket cannot be postdated");
238 return KRB5KDC_ERR_CANNOT_POSTDATE;
242 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
243 _kdc_audit_addreason((kdc_request_t)r,
244 "Bad request for renewable ticket");
245 return KRB5KDC_ERR_BADOPTION;
247 et->flags.renewable = 1;
248 ALLOC(et->renew_till);
249 _kdc_fix_time(&b->rtime);
250 *et->renew_till = *b->rtime;
254 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
255 _kdc_audit_addreason((kdc_request_t)r,
256 "Request to renew non-renewable ticket");
257 return KRB5KDC_ERR_BADOPTION;
259 old_life = tgt->endtime;
261 old_life -= *tgt->starttime;
263 old_life -= tgt->authtime;
264 et->endtime = *et->starttime + old_life;
265 if (et->renew_till != NULL)
266 et->endtime = min(*et->renew_till, et->endtime);
270 * RFC 8062 section 3 defines an anonymous ticket as one containing
271 * the anonymous principal and the anonymous ticket flag.
273 if (tgt->flags.anonymous &&
274 !_kdc_is_anonymous(r->context, tgt_name)) {
275 _kdc_audit_addreason((kdc_request_t)r,
276 "Anonymous ticket flag set without "
277 "anonymous principal");
278 return KRB5KDC_ERR_BADOPTION;
282 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
283 * anonymous KDC option SHOULD be set, but it is not required.
284 * Treat an anonymous TGT as if the anonymous flag was set.
286 if (is_anon_tgs_request_p(b, tgt))
287 et->flags.anonymous = 1;
293 * Determine if constrained delegation is allowed from this client to this server
296 static krb5_error_code
297 check_constrained_delegation(krb5_context context,
298 krb5_kdc_configuration *config,
300 hdb_entry_ex *client,
301 hdb_entry_ex *server,
302 krb5_const_principal target)
304 const HDB_Ext_Constrained_delegation_acl *acl;
309 * constrained_delegation (S4U2Proxy) only works within
310 * the same realm. We use the already canonicalized version
311 * of the principals here, while "target" is the principal
312 * provided by the client.
314 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
315 ret = KRB5KDC_ERR_BADOPTION;
316 kdc_log(context, config, 4,
317 "Bad request for constrained delegation");
321 if (clientdb->hdb_check_constrained_delegation) {
322 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
326 /* if client delegates to itself, that ok */
327 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
330 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
332 krb5_clear_error_message(context);
337 for (i = 0; i < acl->len; i++) {
338 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
342 ret = KRB5KDC_ERR_BADOPTION;
344 kdc_log(context, config, 4,
345 "Bad request for constrained delegation");
350 * Determine if s4u2self is allowed from this client to this server
354 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
355 * service given by the client.
357 * For example, regardless of the principal being impersonated, if the
358 * 'client' and 'server' (target) are the same, or server is an SPN
359 * alias of client, then it's safe.
362 static krb5_error_code
363 check_client_matches_target_service(krb5_context context,
364 krb5_kdc_configuration *config,
366 hdb_entry_ex *client,
367 hdb_entry_ex *target_server,
368 krb5_const_principal target_server_principal)
373 * Always allow the plugin to check, this might be faster, allow a
374 * policy or audit check and can look into the DB records
377 if (clientdb->hdb_check_client_matches_target_service) {
378 ret = clientdb->hdb_check_client_matches_target_service(context,
384 } else if (krb5_principal_compare(context,
385 client->entry.principal,
386 target_server_principal) == TRUE) {
387 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
390 ret = KRB5KDC_ERR_BADOPTION;
400 _kdc_verify_flags(krb5_context context,
401 krb5_kdc_configuration *config,
402 const EncTicketPart *et,
405 if(et->endtime < kdc_time){
406 kdc_log(context, config, 4, "Ticket expired (%s)", pstr);
407 return KRB5KRB_AP_ERR_TKT_EXPIRED;
409 if(et->flags.invalid){
410 kdc_log(context, config, 4, "Ticket not valid (%s)", pstr);
411 return KRB5KRB_AP_ERR_TKT_NYV;
420 static krb5_error_code
421 fix_transited_encoding(krb5_context context,
422 krb5_kdc_configuration *config,
423 krb5_boolean check_policy,
424 const TransitedEncoding *tr,
426 const char *client_realm,
427 const char *server_realm,
428 const char *tgt_realm)
430 krb5_error_code ret = 0;
431 char **realms, **tmp;
432 unsigned int num_realms;
435 switch (tr->tr_type) {
436 case domain_X500_Compress:
440 * Allow empty content of type 0 because that is was Microsoft
441 * generates in their TGT.
443 if (tr->contents.length == 0)
445 kdc_log(context, config, 4,
446 "Transited type 0 with non empty content");
447 return KRB5KDC_ERR_TRTYPE_NOSUPP;
449 kdc_log(context, config, 4,
450 "Unknown transited type: %u", tr->tr_type);
451 return KRB5KDC_ERR_TRTYPE_NOSUPP;
454 ret = krb5_domain_x500_decode(context,
461 krb5_warn(context, ret,
462 "Decoding transited encoding");
467 * If the realm of the presented tgt is neither the client nor the server
468 * realm, it is a transit realm and must be added to transited set.
470 if (strcmp(client_realm, tgt_realm) != 0 &&
471 strcmp(server_realm, tgt_realm) != 0) {
472 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
476 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
482 realms[num_realms] = strdup(tgt_realm);
483 if(realms[num_realms] == NULL){
489 if(num_realms == 0) {
490 if (strcmp(client_realm, server_realm) != 0)
491 kdc_log(context, config, 4,
492 "cross-realm %s -> %s", client_realm, server_realm);
496 for(i = 0; i < num_realms; i++)
497 l += strlen(realms[i]) + 2;
501 for(i = 0; i < num_realms; i++) {
503 strlcat(rs, ", ", l);
504 strlcat(rs, realms[i], l);
506 kdc_log(context, config, 4,
507 "cross-realm %s -> %s via [%s]",
508 client_realm, server_realm, rs);
513 ret = krb5_check_transited(context, client_realm,
515 realms, num_realms, NULL);
517 krb5_warn(context, ret, "cross-realm %s -> %s",
518 client_realm, server_realm);
521 et->flags.transited_policy_checked = 1;
523 et->transited.tr_type = domain_X500_Compress;
524 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
526 krb5_warn(context, ret, "Encoding transited encoding");
528 for(i = 0; i < num_realms; i++)
535 static krb5_error_code
536 tgs_make_reply(astgs_request_t r,
537 krb5_principal tgt_name,
538 const EncTicketPart *tgt,
539 const EncryptionKey *serverkey,
540 const EncryptionKey *krbtgtkey,
541 const krb5_keyblock *sessionkey,
543 AuthorizationData *auth_data,
544 hdb_entry_ex *server,
545 krb5_principal server_principal,
546 hdb_entry_ex *client,
547 krb5_principal client_principal,
548 const char *tgt_realm,
551 krb5_boolean add_ticket_sig,
552 const METHOD_DATA *enc_pa_data)
554 KDC_REQ_BODY *b = &r->req.req_body;
555 const char **e_text = &r->e_text;
556 krb5_data *reply = r->reply;
560 KDCOptions f = b->kdc_options;
564 memset(&rep, 0, sizeof(rep));
565 memset(&et, 0, sizeof(et));
566 memset(&ek, 0, sizeof(ek));
569 rep.msg_type = krb_tgs_rep;
571 et.authtime = tgt->authtime;
572 _kdc_fix_time(&b->till);
573 et.endtime = min(tgt->endtime, *b->till);
575 *et.starttime = kdc_time;
577 ret = check_tgs_flags(r, b, tgt_name, tgt, &et);
581 /* We should check the transited encoding if:
582 1) the request doesn't ask not to be checked
583 2) globally enforcing a check
584 3) principal requires checking
585 4) we allow non-check per-principal, but principal isn't marked as allowing this
586 5) we don't globally allow this
589 #define GLOBAL_FORCE_TRANSITED_CHECK \
590 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
591 #define GLOBAL_ALLOW_PER_PRINCIPAL \
592 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
593 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
594 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
596 /* these will consult the database in future release */
597 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
598 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
600 ret = fix_transited_encoding(r->context, r->config,
601 !f.disable_transited_check ||
602 GLOBAL_FORCE_TRANSITED_CHECK ||
603 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
604 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
605 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
606 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
607 &tgt->transited, &et,
608 krb5_principal_get_realm(r->context, client_principal),
609 krb5_principal_get_realm(r->context, server->entry.principal),
614 ret = copy_Realm(&server_principal->realm, &rep.ticket.realm);
617 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
618 ret = copy_Realm(&tgt_name->realm, &rep.crealm);
623 * RFC 8062 states "if the ticket in the TGS request is an anonymous
624 * one, the client and client realm are copied from that ticket". So
625 * whilst the TGT flag check below is superfluous, it is included in
626 * order to follow the specification to its letter.
628 if (et.flags.anonymous && !tgt->flags.anonymous)
629 _kdc_make_anonymous_principalname(&rep.cname);
631 ret = copy_PrincipalName(&tgt_name->name, &rep.cname);
634 rep.ticket.tkt_vno = 5;
640 life = et.endtime - *et.starttime;
641 if(client && client->entry.max_life)
642 life = min(life, *client->entry.max_life);
643 if(server->entry.max_life)
644 life = min(life, *server->entry.max_life);
645 et.endtime = *et.starttime + life;
647 if(f.renewable_ok && tgt->flags.renewable &&
648 et.renew_till == NULL && et.endtime < *b->till &&
649 tgt->renew_till != NULL)
651 et.flags.renewable = 1;
652 ALLOC(et.renew_till);
653 *et.renew_till = *b->till;
657 renew = *et.renew_till - *et.starttime;
658 if(client && client->entry.max_renew)
659 renew = min(renew, *client->entry.max_renew);
660 if(server->entry.max_renew)
661 renew = min(renew, *server->entry.max_renew);
662 *et.renew_till = *et.starttime + renew;
666 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
667 *et.starttime = min(*et.starttime, *et.renew_till);
668 et.endtime = min(et.endtime, *et.renew_till);
671 *et.starttime = min(*et.starttime, et.endtime);
673 if(*et.starttime == et.endtime){
674 ret = KRB5KDC_ERR_NEVER_VALID;
677 if(et.renew_till && et.endtime == *et.renew_till){
679 et.renew_till = NULL;
680 et.flags.renewable = 0;
683 et.flags.pre_authent = tgt->flags.pre_authent;
684 et.flags.hw_authent = tgt->flags.hw_authent;
685 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
687 /* See MS-KILE 3.3.5.1 */
688 if (!server->entry.flags.forwardable)
689 et.flags.forwardable = 0;
690 if (!server->entry.flags.proxiable)
691 et.flags.proxiable = 0;
696 /* XXX check authdata */
698 if (et.authorization_data == NULL) {
699 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
700 if (et.authorization_data == NULL) {
702 krb5_set_error_message(r->context, ret, "malloc: out of memory");
706 for(i = 0; i < auth_data->len ; i++) {
707 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
709 krb5_set_error_message(r->context, ret, "malloc: out of memory");
715 ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et.key);
718 et.crealm = rep.crealm;
719 et.cname = rep.cname;
722 /* MIT must have at least one last_req */
723 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
724 if (ek.last_req.val == NULL) {
728 ek.last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
731 ek.authtime = et.authtime;
732 ek.starttime = et.starttime;
733 ek.endtime = et.endtime;
734 ek.renew_till = et.renew_till;
735 ek.srealm = rep.ticket.realm;
736 ek.sname = rep.ticket.sname;
738 _kdc_log_timestamp(r, "TGS-REQ", et.authtime, et.starttime,
739 et.endtime, et.renew_till);
741 if (enc_pa_data->len) {
742 rep.padata = calloc(1, sizeof(*rep.padata));
743 if (rep.padata == NULL) {
747 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
752 if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
753 && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
755 krb5_enctype_enable(r->context, serverkey->keytype);
760 * For anonymous tickets, we should filter out positive authorization data
761 * that could reveal the client's identity, and return a policy error for
762 * restrictive authorization data. Policy for unknown authorization types
763 * is implementation dependent.
765 if (mspac && !et.flags.anonymous) {
767 /* The PAC should be the last change to the ticket. */
768 ret = _krb5_kdc_pac_sign_ticket(r->context, mspac, tgt_name, serverkey,
769 krbtgtkey, rodc_id, add_ticket_sig, &et);
774 /* It is somewhat unclear where the etype in the following
775 encryption should come from. What we have is a session
776 key in the passed tgt, and a list of preferred etypes
777 *for the new ticket*. Should we pick the best possible
778 etype, given the keytype in the tgt, or should we look
779 at the etype list here as well? What if the tgt
780 session key is DES3 and we want a ticket with a (say)
781 CAST session key. Should the DES3 etype be added to the
782 etype list, even if we don't want a session key with
784 ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
785 &rep, &et, &ek, serverkey->keytype,
787 serverkey, 0, r->rk_is_subkey,
790 krb5_enctype_disable(r->context, serverkey->keytype);
792 _log_astgs_req(r, serverkey->keytype);
796 free_TransitedEncoding(&et.transited);
801 if(et.authorization_data) {
802 free_AuthorizationData(et.authorization_data);
803 free(et.authorization_data);
805 free_LastReq(&ek.last_req);
806 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
807 free_EncryptionKey(&et.key);
811 static krb5_error_code
812 tgs_check_authenticator(krb5_context context,
813 krb5_kdc_configuration *config,
814 krb5_auth_context ac,
819 krb5_authenticator auth;
823 krb5_auth_con_getauthenticator(context, ac, &auth);
824 if(auth->cksum == NULL){
825 kdc_log(context, config, 4, "No authenticator in request");
826 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
830 if (!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
831 kdc_log(context, config, 4, "Bad checksum type in authenticator: %d",
832 auth->cksum->cksumtype);
833 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
837 ret = krb5_crypto_init(context, key, 0, &crypto);
839 const char *msg = krb5_get_error_message(context, ret);
840 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
841 krb5_free_error_message(context, msg);
846 * RFC4120 says the checksum must be collision-proof, but it does
847 * not require it to be keyed (as the authenticator is encrypted).
849 _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
850 ret = _kdc_verify_checksum(context,
852 KRB5_KU_TGS_REQ_AUTH_CKSUM,
855 krb5_crypto_destroy(context, crypto);
857 const char *msg = krb5_get_error_message(context, ret);
858 kdc_log(context, config, 4,
859 "Failed to verify authenticator checksum: %s", msg);
860 krb5_free_error_message(context, msg);
863 free_Authenticator(auth);
869 need_referral(krb5_context context, krb5_kdc_configuration *config,
870 const KDCOptions * const options, krb5_principal server,
875 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
878 if (server->name.name_string.len == 1)
879 name = server->name.name_string.val[0];
880 else if (server->name.name_string.len == 3) {
882 This is used to give referrals for the
883 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
884 SPN form, which is used for inter-domain communication in AD
886 name = server->name.name_string.val[2];
887 kdc_log(context, config, 4, "Giving 3 part referral for %s", name);
888 *realms = malloc(sizeof(char *)*2);
889 if (*realms == NULL) {
890 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
893 (*realms)[0] = strdup(name);
896 } else if (server->name.name_string.len > 1)
897 name = server->name.name_string.val[1];
901 kdc_log(context, config, 5, "Searching referral for %s", name);
903 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
906 static krb5_error_code
907 validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
912 krb5_data_zero(&data);
914 ret = _krb5_get_ad(r->context, auth_data, NULL,
915 KRB5_AUTHDATA_FX_FAST_USED, &data);
917 r->fast_asserted = 1;
918 krb5_data_free(&data);
921 ret = _krb5_get_ad(r->context, auth_data, NULL,
922 KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
924 kdc_log(r->context, r->config, 2,
925 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
926 krb5_data_free(&data);
927 return KRB5KRB_AP_ERR_BAD_INTEGRITY;
933 static krb5_error_code
934 tgs_parse_request(astgs_request_t r,
935 const PA_DATA *tgs_req,
936 hdb_entry_ex **krbtgt,
937 krb5_enctype *krbtgt_etype,
938 krb5_ticket **ticket,
941 const struct sockaddr *from_addr,
944 AuthorizationData **auth_data)
946 krb5_kdc_configuration *config = r->config;
947 KDC_REQ_BODY *b = &r->req.req_body;
948 static char failed[] = "<unparse_name failed>";
951 krb5_principal princ;
952 krb5_auth_context ac = NULL;
953 krb5_flags ap_req_options;
954 krb5_flags verify_ap_req_flags = 0;
956 krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
957 krb5uint32 krbtgt_kvno_try;
958 int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
959 const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
961 krb5_keyblock *subkey = NULL;
968 memset(&ap_req, 0, sizeof(ap_req));
969 ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req);
971 const char *msg = krb5_get_error_message(r->context, ret);
972 kdc_log(r->context, config, 4, "Failed to decode AP-REQ: %s", msg);
973 krb5_free_error_message(r->context, msg);
977 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
978 /* XXX check for ticket.sname == req.sname */
979 kdc_log(r->context, config, 4, "PA-DATA is not a ticket-granting ticket");
980 ret = KRB5KDC_ERR_POLICY; /* ? */
984 _krb5_principalname2krb5_principal(r->context,
987 ap_req.ticket.realm);
989 krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
990 ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT,
991 &krbtgt_kvno, NULL, krbtgt);
993 if (ret == HDB_ERR_NOT_FOUND_HERE) {
994 /* XXX Factor out this unparsing of the same princ all over */
996 ret = krb5_unparse_name(r->context, princ, &p);
999 krb5_free_principal(r->context, princ);
1000 kdc_log(r->context, config, 5,
1001 "Ticket-granting ticket account %s does not have secrets at "
1002 "this KDC, need to proxy", p);
1005 ret = HDB_ERR_NOT_FOUND_HERE;
1007 } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1009 ret = krb5_unparse_name(r->context, princ, &p);
1012 krb5_free_principal(r->context, princ);
1013 kdc_log(r->context, config, 5,
1014 "Ticket-granting ticket account %s does not have keys for "
1015 "kvno %d at this KDC", p, krbtgt_kvno);
1018 ret = HDB_ERR_KVNO_NOT_FOUND;
1020 } else if (ret == HDB_ERR_NO_MKEY) {
1022 ret = krb5_unparse_name(r->context, princ, &p);
1025 krb5_free_principal(r->context, princ);
1026 kdc_log(r->context, config, 5,
1027 "Missing master key for decrypting keys for ticket-granting "
1028 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1031 ret = HDB_ERR_KVNO_NOT_FOUND;
1034 const char *msg = krb5_get_error_message(r->context, ret);
1036 ret = krb5_unparse_name(r->context, princ, &p);
1039 kdc_log(r->context, config, 4,
1040 "Ticket-granting ticket %s not found in database: %s", p, msg);
1041 krb5_free_principal(r->context, princ);
1042 krb5_free_error_message(r->context, msg);
1045 ret = KRB5KRB_AP_ERR_NOT_US;
1049 krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1050 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1053 krbtgt_keys = hdb_kvno2keys(r->context, &(*krbtgt)->entry, krbtgt_kvno_try);
1054 ret = hdb_enctype2key(r->context, &(*krbtgt)->entry, krbtgt_keys,
1055 ap_req.ticket.enc_part.etype, &tkey);
1056 if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1057 kvno_search_tries--;
1061 char *str = NULL, *p = NULL;
1063 krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str);
1064 krb5_unparse_name(r->context, princ, &p);
1065 kdc_log(r->context, config, 4,
1066 "No server key with enctype %s found for %s",
1067 str ? str : "<unknown enctype>",
1068 p ? p : "<unparse_name failed>");
1071 ret = KRB5KRB_AP_ERR_BADKEYVER;
1075 if (b->kdc_options.validate)
1076 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1078 if (r->config->warn_ticket_addresses)
1079 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS;
1081 ret = krb5_verify_ap_req2(r->context,
1086 verify_ap_req_flags,
1089 KRB5_KU_TGS_REQ_AUTH);
1090 if (ticket && *ticket && (*ticket)->ticket.caddr)
1091 _kdc_audit_addaddrs((kdc_request_t)r, (*ticket)->ticket.caddr, "tixaddrs");
1092 if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR &&
1094 _kdc_audit_addkv((kdc_request_t)r, 0, "wrongaddr", "yes");
1097 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1098 kvno_search_tries--;
1103 krb5_free_principal(r->context, princ);
1105 const char *msg = krb5_get_error_message(r->context, ret);
1106 kdc_log(r->context, config, 4, "Failed to verify AP-REQ: %s", msg);
1107 krb5_free_error_message(r->context, msg);
1111 r->ticket_key = tkey;
1114 krb5_authenticator auth;
1116 ret = krb5_auth_con_getauthenticator(r->context, ac, &auth);
1118 *csec = malloc(sizeof(**csec));
1119 if (*csec == NULL) {
1120 krb5_free_authenticator(r->context, &auth);
1121 kdc_log(r->context, config, 4, "malloc failed");
1124 **csec = auth->ctime;
1125 *cusec = malloc(sizeof(**cusec));
1126 if (*cusec == NULL) {
1127 krb5_free_authenticator(r->context, &auth);
1128 kdc_log(r->context, config, 4, "malloc failed");
1131 **cusec = auth->cusec;
1133 ret = validate_fast_ad(r, auth->authorization_data);
1134 krb5_free_authenticator(r->context, &auth);
1140 ret = tgs_check_authenticator(r->context, config,
1141 ac, b, e_text, &(*ticket)->ticket.key);
1143 krb5_auth_con_free(r->context, ac);
1147 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1148 r->rk_is_subkey = 1;
1150 ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
1152 const char *msg = krb5_get_error_message(r->context, ret);
1153 krb5_auth_con_free(r->context, ac);
1154 kdc_log(r->context, config, 4, "Failed to get remote subkey: %s", msg);
1155 krb5_free_error_message(r->context, msg);
1159 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1160 r->rk_is_subkey = 0;
1162 ret = krb5_auth_con_getkey(r->context, ac, &subkey);
1164 const char *msg = krb5_get_error_message(r->context, ret);
1165 krb5_auth_con_free(r->context, ac);
1166 kdc_log(r->context, config, 4, "Failed to get session key: %s", msg);
1167 krb5_free_error_message(r->context, msg);
1172 krb5_auth_con_free(r->context, ac);
1173 kdc_log(r->context, config, 4,
1174 "Failed to get key for enc-authorization-data");
1175 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1179 krb5_free_keyblock_contents(r->context, &r->reply_key);
1180 ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
1181 krb5_free_keyblock(r->context, subkey);
1185 if (b->enc_authorization_data) {
1188 ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto);
1190 const char *msg = krb5_get_error_message(r->context, ret);
1191 krb5_auth_con_free(r->context, ac);
1192 kdc_log(r->context, config, 4, "krb5_crypto_init failed: %s", msg);
1193 krb5_free_error_message(r->context, msg);
1196 ret = krb5_decrypt_EncryptedData (r->context,
1199 b->enc_authorization_data,
1201 krb5_crypto_destroy(r->context, crypto);
1203 krb5_auth_con_free(r->context, ac);
1204 kdc_log(r->context, config, 4,
1205 "Failed to decrypt enc-authorization-data");
1206 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1210 if (*auth_data == NULL) {
1211 krb5_auth_con_free(r->context, ac);
1212 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1215 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1217 krb5_auth_con_free(r->context, ac);
1220 kdc_log(r->context, config, 4, "Failed to decode authorization data");
1221 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1226 ret = validate_fast_ad(r, (*ticket)->ticket.authorization_data);
1232 * Check for FAST request
1235 ret = _kdc_fast_unwrap_request(r, *ticket, ac);
1239 krb5_auth_con_free(r->context, ac);
1242 free_AP_REQ(&ap_req);
1247 static krb5_error_code
1248 build_server_referral(krb5_context context,
1249 krb5_kdc_configuration *config,
1250 krb5_crypto session,
1251 krb5_const_realm referred_realm,
1252 const PrincipalName *true_principal_name,
1253 const PrincipalName *requested_principal,
1256 PA_ServerReferralData ref;
1257 krb5_error_code ret;
1262 memset(&ref, 0, sizeof(ref));
1264 if (referred_realm) {
1265 ALLOC(ref.referred_realm);
1266 if (ref.referred_realm == NULL)
1268 *ref.referred_realm = strdup(referred_realm);
1269 if (*ref.referred_realm == NULL)
1272 if (true_principal_name) {
1273 ALLOC(ref.true_principal_name);
1274 if (ref.true_principal_name == NULL)
1276 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1280 if (requested_principal) {
1281 ALLOC(ref.requested_principal_name);
1282 if (ref.requested_principal_name == NULL)
1284 ret = copy_PrincipalName(requested_principal,
1285 ref.requested_principal_name);
1290 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1291 data.data, data.length,
1293 free_PA_ServerReferralData(&ref);
1296 if (data.length != size)
1297 krb5_abortx(context, "internal asn.1 encoder error");
1299 ret = krb5_encrypt_EncryptedData(context, session,
1300 KRB5_KU_PA_SERVER_REFERRAL,
1301 data.data, data.length,
1307 ASN1_MALLOC_ENCODE(EncryptedData,
1308 outdata->data, outdata->length,
1310 free_EncryptedData(&ed);
1313 if (outdata->length != size)
1314 krb5_abortx(context, "internal asn.1 encoder error");
1318 free_PA_ServerReferralData(&ref);
1319 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1324 * This function is intended to be used when failure to find the client is
1327 static krb5_error_code
1328 db_fetch_client(krb5_context context,
1329 krb5_kdc_configuration *config,
1333 const char *krbtgt_realm,
1335 hdb_entry_ex **client_out)
1337 krb5_error_code ret;
1338 hdb_entry_ex *client = NULL;
1342 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1343 NULL, clientdb, &client);
1344 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1346 * This is OK, we are just trying to find out if they have
1347 * been disabled or deleted in the meantime; missing secrets
1352 * If the client belongs to the same realm as our TGS, it
1353 * should exist in the local database.
1357 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1358 if (ret == HDB_ERR_NOENTRY)
1359 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1360 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1364 msg = krb5_get_error_message(context, ret);
1365 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1366 krb5_free_error_message(context, msg);
1367 } else if (client->entry.flags.invalid || !client->entry.flags.client) {
1368 kdc_log(context, config, 4, "Client has invalid bit set");
1369 _kdc_free_ent(context, client);
1370 return KRB5KDC_ERR_POLICY;
1373 *client_out = client;
1378 static krb5_error_code
1379 tgs_build_reply(astgs_request_t priv,
1380 hdb_entry_ex *krbtgt,
1381 krb5_enctype krbtgt_etype,
1382 krb5_ticket *ticket,
1383 const char **e_text,
1384 AuthorizationData **auth_data,
1385 const struct sockaddr *from_addr)
1387 krb5_context context = priv->context;
1388 krb5_kdc_configuration *config = priv->config;
1389 KDC_REQ *req = &priv->req;
1390 KDC_REQ_BODY *b = &priv->req.req_body;
1391 const char *from = priv->from;
1392 krb5_error_code ret, ret2;
1393 krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1394 krb5_principal krbtgt_out_principal = NULL;
1395 krb5_principal user2user_princ = NULL;
1396 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1397 char *user2user_name = NULL;
1398 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1399 hdb_entry_ex *user2user_krbtgt = NULL;
1400 HDB *clientdb, *s4u2self_impersonated_clientdb;
1401 HDB *serverdb = NULL;
1402 krb5_realm ref_realm = NULL;
1403 EncTicketPart *tgt = &ticket->ticket;
1404 const EncryptionKey *ekey;
1405 krb5_keyblock sessionkey;
1407 krb5_pac mspac = NULL;
1408 krb5_pac user2user_pac = NULL;
1410 krb5_boolean add_ticket_sig = FALSE;
1411 const char *tgt_realm = /* Realm of TGT issuer */
1412 krb5_principal_get_realm(context, krbtgt->entry.principal);
1413 const char *our_realm = /* Realm of this KDC */
1414 krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1415 char **capath = NULL;
1416 size_t num_capath = 0;
1418 hdb_entry_ex *krbtgt_out = NULL;
1420 METHOD_DATA enc_pa_data;
1424 EncTicketPart adtkt;
1426 krb5_boolean kdc_issued = FALSE;
1429 int flags = HDB_F_FOR_TGS_REQ;
1431 memset(&sessionkey, 0, sizeof(sessionkey));
1432 memset(&adtkt, 0, sizeof(adtkt));
1433 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1439 * The canonicalize KDC option is passed as a hint to the backend, but
1440 * can typically be ignored. Per RFC 6806, names are not canonicalized
1441 * in response to a TGS request (although we make an exception, see
1442 * force-canonicalize below).
1444 if (b->kdc_options.canonicalize)
1445 flags |= HDB_F_CANON;
1448 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1449 _kdc_set_e_text(priv, "No server in request");
1453 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1454 ret = krb5_unparse_name(context, sp, &priv->sname);
1458 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1459 ret = krb5_unparse_name(context, cp, &priv->cname);
1463 unparse_flags (KDCOptions2int(b->kdc_options),
1464 asn1_KDCOptions_units(),
1465 opt_str, sizeof(opt_str));
1467 kdc_log(context, config, 4,
1468 "TGS-REQ %s from %s for %s [%s]",
1469 cpn, from, spn, opt_str);
1471 kdc_log(context, config, 4,
1472 "TGS-REQ %s from %s for %s", cpn, from, spn);
1479 priv->server = NULL;
1481 _kdc_free_ent(context, server);
1483 ret = _kdc_db_fetch(context, config, sp,
1484 HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags,
1485 NULL, &serverdb, &server);
1486 priv->server = server;
1487 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1488 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn);
1489 _kdc_audit_addreason((kdc_request_t)priv, "Target not found here");
1491 } else if (ret == HDB_ERR_WRONG_REALM) {
1493 ref_realm = strdup(server->entry.principal->realm);
1494 if (ref_realm == NULL) {
1495 ret = krb5_enomem(context);
1499 kdc_log(context, config, 4,
1500 "Returning a referral to realm %s for "
1503 krb5_free_principal(context, sp);
1505 ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1511 ret = krb5_unparse_name(context, sp, &priv->sname);
1518 const char *new_rlm, *msg;
1522 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1523 if (capath == NULL) {
1524 /* With referalls, hierarchical capaths are always enabled */
1525 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1526 req_rlm, TRUE, &capath, &num_capath);
1529 _kdc_audit_addreason((kdc_request_t)priv,
1530 "No trusted path from client realm to ours");
1534 new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1536 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1537 "realm %s not found, trying %s", tgt->crealm,
1538 our_realm, req_rlm, new_rlm);
1541 ref_realm = strdup(new_rlm);
1542 if (ref_realm == NULL) {
1543 ret = krb5_enomem(context);
1547 krb5_free_principal(context, sp);
1549 krb5_make_principal(context, &sp, r,
1550 KRB5_TGS_NAME, ref_realm, NULL);
1553 ret = krb5_unparse_name(context, sp, &priv->sname);
1559 } else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
1560 if (strcmp(realms[0], sp->realm) != 0) {
1561 kdc_log(context, config, 4,
1562 "Returning a referral to realm %s for "
1563 "server %s that was not found",
1565 krb5_free_principal(context, sp);
1567 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1571 ret = krb5_unparse_name(context, sp, &priv->sname);
1573 krb5_free_host_realm(context, realms);
1579 ref_realm = strdup(realms[0]);
1581 krb5_free_host_realm(context, realms);
1584 krb5_free_host_realm(context, realms);
1586 msg = krb5_get_error_message(context, ret);
1587 kdc_log(context, config, 3,
1588 "Server not found in database: %s: %s", spn, msg);
1589 krb5_free_error_message(context, msg);
1590 if (ret == HDB_ERR_NOENTRY)
1591 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1592 _kdc_audit_addreason((kdc_request_t)priv,
1593 "Service principal unknown");
1598 * RFC 6806 notes that names MUST NOT be changed in the response to
1599 * a TGS request. Hence we ignore the setting of the canonicalize
1600 * KDC option. However, for legacy interoperability we do allow the
1601 * backend to override this by setting the force-canonicalize HDB
1602 * flag in the server entry.
1604 if (server->entry.flags.force_canonicalize)
1605 rsp = server->entry.principal;
1610 * Now refetch the primary krbtgt, and get the current kvno (the
1611 * sign check may have been on an old kvno, and the server may
1612 * have been an incoming trust)
1615 ret = krb5_make_principal(context,
1616 &krbtgt_out_principal,
1622 kdc_log(context, config, 4,
1623 "Failed to make krbtgt principal name object for "
1624 "authz-data signatures");
1627 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1629 kdc_log(context, config, 4,
1630 "Failed to make krbtgt principal name object for "
1631 "authz-data signatures");
1635 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1636 HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1639 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1640 kdc_log(context, config, 4,
1641 "No such principal %s (needed for authz-data signature keys) "
1642 "while processing TGS-REQ for service %s with krbtg %s",
1643 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1645 ret = KRB5KRB_AP_ERR_NOT_US;
1650 * Select enctype, return key and kvno.
1656 if(b->kdc_options.enc_tkt_in_skey) {
1660 krb5uint32 second_kvno = 0;
1661 krb5uint32 *kvno_ptr = NULL;
1663 hdb_entry_ex *user2user_client = NULL;
1664 krb5_boolean user2user_kdc_issued = FALSE;
1666 if(b->additional_tickets == NULL ||
1667 b->additional_tickets->len == 0){
1668 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1669 kdc_log(context, config, 4,
1670 "No second ticket present in user-to-user request");
1671 _kdc_audit_addreason((kdc_request_t)priv,
1672 "No second ticket present in user-to-user request");
1675 t = &b->additional_tickets->val[0];
1676 if(!get_krbtgt_realm(&t->sname)){
1677 kdc_log(context, config, 4,
1678 "Additional ticket is not a ticket-granting ticket");
1679 _kdc_audit_addreason((kdc_request_t)priv,
1680 "Additional ticket is not a ticket-granting ticket");
1681 ret = KRB5KDC_ERR_POLICY;
1684 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1688 ret = krb5_unparse_name(context, p, &tpn);
1691 if(t->enc_part.kvno){
1692 second_kvno = *t->enc_part.kvno;
1693 kvno_ptr = &second_kvno;
1695 ret = _kdc_db_fetch(context, config, p,
1696 HDB_F_GET_KRBTGT, kvno_ptr,
1697 NULL, &user2user_krbtgt);
1698 krb5_free_principal(context, p);
1700 if (ret == HDB_ERR_NOENTRY)
1701 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1702 _kdc_audit_addreason((kdc_request_t)priv,
1703 "User-to-user service principal (TGS) unknown");
1706 ret = hdb_enctype2key(context, &user2user_krbtgt->entry, NULL,
1707 t->enc_part.etype, &uukey);
1709 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1710 _kdc_audit_addreason((kdc_request_t)priv,
1711 "User-to-user enctype not supported");
1714 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1716 _kdc_audit_addreason((kdc_request_t)priv,
1717 "User-to-user TGT decrypt failure");
1721 ret = _kdc_verify_flags(context, config, &adtkt, tpn);
1723 _kdc_audit_addreason((kdc_request_t)priv,
1724 "User-to-user TGT expired or invalid");
1728 /* Fetch the name from the TGT. */
1729 ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1730 adtkt.cname, adtkt.crealm);
1734 ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1739 * Look up the name given in the TGT in the database. The user
1740 * claims to have a ticket-granting-ticket to our KDC, so we should
1741 * fail hard if we can't find the user - otherwise we can't do
1744 ret = _kdc_db_fetch(context, config, user2user_princ,
1745 HDB_F_GET_CLIENT | flags,
1746 NULL, NULL, &user2user_client);
1747 if (ret == HDB_ERR_NOENTRY)
1748 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1753 * The account is present in the database, now check the
1756 * We check this as a client (because the purpose of
1757 * user2user is that the server flag is not set, because
1758 * the long-term key is not strong, but this does mean
1759 * that a client with an expired password can't get accept
1760 * a user2user ticket.
1762 ret = kdc_check_flags(priv,
1767 _kdc_free_ent(context, user2user_client);
1772 * Also check that the account is the same one specified in the
1775 ret = check_client_matches_target_service(context,
1782 _kdc_free_ent(context, user2user_client);
1786 /* Verify the PAC of the TGT. */
1787 ret = _kdc_check_pac(context, config, user2user_princ, NULL,
1788 user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
1789 &uukey->key, &priv->ticket_key->key, &adtkt, &user2user_kdc_issued, &user2user_pac);
1790 _kdc_free_ent(context, user2user_client);
1792 const char *msg = krb5_get_error_message(context, ret);
1793 kdc_log(context, config, 0,
1794 "Verify PAC failed for %s (%s) from %s with %s",
1795 spn, user2user_name, from, msg);
1796 krb5_free_error_message(context, msg);
1800 if ((config->require_pac && !user2user_pac)
1801 || (user2user_pac && !user2user_kdc_issued))
1803 ret = KRB5KDC_ERR_BADOPTION;
1804 kdc_log(context, config, 0,
1805 "Ticket not signed with PAC; user-to-user failed (%s).",
1806 user2user_pac ? "Ticket unsigned" : "No PAC");
1811 for(i = 0; i < b->etype.len; i++)
1812 if (b->etype.val[i] == adtkt.key.keytype)
1814 if(i == b->etype.len) {
1815 kdc_log(context, config, 4,
1816 "Addition ticket have not matching etypes");
1817 krb5_clear_error_message(context);
1818 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1819 _kdc_audit_addreason((kdc_request_t)priv,
1820 "No matching enctypes for 2nd ticket");
1823 etype = b->etype.val[i];
1828 ret = _kdc_find_etype(priv, krb5_principal_is_krbtgt(context, sp)
1830 b->etype.val, b->etype.len, &etype, NULL,
1833 kdc_log(context, config, 4,
1834 "Server (%s) has no support for etypes", spn);
1835 _kdc_audit_addreason((kdc_request_t)priv,
1836 "Enctype not supported");
1839 ret = _kdc_get_preferred_key(context, config, server, spn,
1842 kdc_log(context, config, 4,
1843 "Server (%s) has no supported etypes", spn);
1844 _kdc_audit_addreason((kdc_request_t)priv,
1845 "Enctype not supported");
1849 kvno = server->entry.kvno;
1852 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1858 * Check that service is in the same realm as the krbtgt. If it's
1859 * not the same, it's someone that is using a uni-directional trust
1864 * The first realm is the realm of the service, the second is
1865 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1866 * encrypted to. The redirection via the krbtgt_out entry allows
1867 * the DB to possibly correct the case of the realm (Samba4 does
1868 * this) before the strcmp()
1870 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1871 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1873 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1874 kdc_log(context, config, 4,
1875 "Request with wrong krbtgt: %s",
1876 (ret == 0) ? ktpn : "<unknown>");
1879 ret = KRB5KRB_AP_ERR_NOT_US;
1880 _kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT");
1884 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1887 kdc_log(context, config, 4,
1888 "Failed to find key for krbtgt PAC signature");
1889 _kdc_audit_addreason((kdc_request_t)priv,
1890 "Failed to find key for krbtgt PAC signature");
1893 ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1894 tkey_sign->key.keytype, &tkey_sign);
1896 kdc_log(context, config, 4,
1897 "Failed to find key for krbtgt PAC signature");
1898 _kdc_audit_addreason((kdc_request_t)priv,
1899 "Failed to find key for krbtgt PAC signature");
1904 krb5_data verified_cas;
1907 * If the client doesn't exist in the HDB but has a TGT and it's
1908 * obtained with PKINIT then we assume it's a synthetic client -- that
1909 * is, a client whose name was vouched for by a CA using a PKINIT SAN,
1910 * but which doesn't exist in the HDB proper. We'll allow such a
1911 * client to do TGT requests even though normally we'd reject all
1912 * clients that don't exist in the HDB.
1914 ret = krb5_ticket_get_authorization_data_type(context, ticket,
1915 KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
1918 krb5_data_free(&verified_cas);
1919 flags |= HDB_F_SYNTHETIC_OK;
1922 ret = db_fetch_client(context, config, flags, cp, cpn, our_realm,
1923 &clientdb, &client);
1926 flags &= ~HDB_F_SYNTHETIC_OK;
1927 priv->client = client;
1929 ret = _kdc_check_pac(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1930 &priv->ticket_key->key, &priv->ticket_key->key, tgt, &kdc_issued, &mspac);
1932 const char *msg = krb5_get_error_message(context, ret);
1933 _kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
1934 kdc_log(context, config, 4,
1935 "Verify PAC failed for %s (%s) from %s with %s",
1936 spn, cpn, from, msg);
1937 krb5_free_error_message(context, msg);
1945 /* by default the tgt principal matches the client principal */
1950 const PA_DATA *sdata;
1953 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1960 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1961 sdata->padata_value.length,
1964 _kdc_audit_addreason((kdc_request_t)priv,
1965 "Failed to decode PA-S4U2Self");
1966 kdc_log(context, config, 4, "Failed to decode PA-S4U2Self");
1970 if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1971 free_PA_S4U2Self(&self);
1972 _kdc_audit_addreason((kdc_request_t)priv,
1973 "PA-S4U2Self with unkeyed checksum");
1974 kdc_log(context, config, 4, "Reject PA-S4U2Self with unkeyed checksum");
1975 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1979 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1983 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1985 const char *msg = krb5_get_error_message(context, ret);
1986 free_PA_S4U2Self(&self);
1987 krb5_data_free(&datack);
1988 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
1989 krb5_free_error_message(context, msg);
1993 /* Allow HMAC_MD5 checksum with any key type */
1994 if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
1995 struct krb5_crypto_iov iov;
1996 unsigned char csdata[16];
1999 cs.checksum.length = sizeof(csdata);
2000 cs.checksum.data = &csdata;
2002 iov.data.data = datack.data;
2003 iov.data.length = datack.length;
2004 iov.flags = KRB5_CRYPTO_TYPE_DATA;
2006 ret = _krb5_HMAC_MD5_checksum(context, NULL, &crypto->key,
2007 KRB5_KU_OTHER_CKSUM, &iov, 1,
2010 krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
2011 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2014 ret = _kdc_verify_checksum(context,
2016 KRB5_KU_OTHER_CKSUM,
2020 krb5_data_free(&datack);
2021 krb5_crypto_destroy(context, crypto);
2023 const char *msg = krb5_get_error_message(context, ret);
2024 free_PA_S4U2Self(&self);
2025 _kdc_audit_addreason((kdc_request_t)priv,
2026 "S4U2Self checksum failed");
2027 kdc_log(context, config, 4,
2028 "krb5_verify_checksum failed for S4U2Self: %s", msg);
2029 krb5_free_error_message(context, msg);
2033 ret = _krb5_principalname2krb5_principal(context,
2037 free_PA_S4U2Self(&self);
2041 ret = krb5_unparse_name(context, tp, &tpn);
2046 * Note no HDB_F_SYNTHETIC_OK -- impersonating non-existent clients
2047 * is probably not desirable!
2049 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2050 NULL, &s4u2self_impersonated_clientdb,
2051 &s4u2self_impersonated_client);
2056 * If the client belongs to the same realm as our krbtgt, it
2057 * should exist in the local database.
2061 if (ret == HDB_ERR_NOENTRY)
2062 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2063 msg = krb5_get_error_message(context, ret);
2064 _kdc_audit_addreason((kdc_request_t)priv,
2065 "S4U2Self principal to impersonate not found");
2066 kdc_log(context, config, 2,
2067 "S4U2Self principal to impersonate %s not found in database: %s",
2069 krb5_free_error_message(context, msg);
2073 /* Ignore require_pwchange and pw_end attributes (as Windows does),
2074 * since S4U2Self is not password authentication. */
2075 s4u2self_impersonated_client->entry.flags.require_pwchange = FALSE;
2076 free(s4u2self_impersonated_client->entry.pw_end);
2077 s4u2self_impersonated_client->entry.pw_end = NULL;
2079 ret = kdc_check_flags(priv, FALSE, s4u2self_impersonated_client, priv->server);
2081 goto out; /* kdc_check_flags() calls _kdc_audit_addreason() */
2083 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2084 krb5_pac_free(context, mspac);
2087 ret = _kdc_pac_generate(context,
2088 s4u2self_impersonated_client,
2094 kdc_log(context, config, 4, "PAC generation failed for -- %s", tpn);
2099 * Check that service doing the impersonating is
2100 * requesting a ticket to it-self.
2102 ret = check_client_matches_target_service(context,
2109 kdc_log(context, config, 4, "S4U2Self: %s is not allowed "
2110 "to impersonate to service "
2111 "(tried for user %s to service %s)",
2117 * If the service isn't trusted for authentication to
2118 * delegation or if the impersonate client is disallowed
2119 * forwardable, remove the forwardable flag.
2122 if (client->entry.flags.trusted_for_delegation &&
2123 s4u2self_impersonated_client->entry.flags.forwardable) {
2124 str = "[forwardable]";
2126 b->kdc_options.forwardable = 0;
2129 kdc_log(context, config, 4, "s4u2self %s impersonating %s to "
2130 "service %s %s", cpn, tpn, spn, str);
2135 * Constrained delegation
2139 && b->additional_tickets != NULL
2140 && b->additional_tickets->len != 0
2141 && b->kdc_options.cname_in_addl_tkt
2142 && b->kdc_options.enc_tkt_in_skey == 0)
2144 hdb_entry_ex *adclient = NULL;
2145 krb5_boolean ad_kdc_issued = FALSE;
2150 * We require that the service's krbtgt has a PAC.
2152 if (mspac == NULL) {
2153 ret = KRB5KDC_ERR_BADOPTION;
2154 _kdc_audit_addreason((kdc_request_t)priv, "Missing PAC");
2155 kdc_log(context, config, 4,
2156 "Constrained delegation without PAC, %s/%s",
2161 krb5_pac_free(context, mspac);
2164 t = &b->additional_tickets->val[0];
2166 ret = hdb_enctype2key(context, &client->entry,
2167 hdb_kvno2keys(context, &client->entry,
2168 t->enc_part.kvno ? * t->enc_part.kvno : 0),
2169 t->enc_part.etype, &clientkey);
2171 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2175 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2177 _kdc_audit_addreason((kdc_request_t)priv,
2178 "Failed to decrypt constrained delegation ticket");
2179 kdc_log(context, config, 4,
2180 "failed to decrypt ticket for "
2181 "constrained delegation from %s to %s ", cpn, spn);
2185 ret = _krb5_principalname2krb5_principal(context,
2192 ret = krb5_unparse_name(context, tp, &tpn);
2196 _kdc_audit_addkv((kdc_request_t)priv, 0, "impersonatee", "%s", tpn);
2198 ret = _krb5_principalname2krb5_principal(context,
2205 ret = krb5_unparse_name(context, dp, &dpn);
2209 /* check that ticket is valid */
2210 if (adtkt.flags.forwardable == 0) {
2211 _kdc_audit_addreason((kdc_request_t)priv,
2212 "Missing forwardable flag on ticket for constrained delegation");
2213 kdc_log(context, config, 4,
2214 "Missing forwardable flag on ticket for "
2215 "constrained delegation from %s (%s) as %s to %s ",
2216 cpn, dpn, tpn, spn);
2217 ret = KRB5KDC_ERR_BADOPTION;
2221 ret = check_constrained_delegation(context, config, clientdb,
2222 client, server, sp);
2224 _kdc_audit_addreason((kdc_request_t)priv,
2225 "Constrained delegation not allowed");
2226 kdc_log(context, config, 4,
2227 "constrained delegation from %s (%s) as %s to %s not allowed",
2228 cpn, dpn, tpn, spn);
2232 ret = _kdc_verify_flags(context, config, &adtkt, tpn);
2234 _kdc_audit_addreason((kdc_request_t)priv,
2235 "Constrained delegation ticket expired or invalid");
2239 /* Try lookup the delegated client in DB */
2240 ret = db_fetch_client(context, config, flags, tp, tpn, our_realm,
2245 if (adclient != NULL) {
2246 ret = kdc_check_flags(priv, FALSE, adclient, priv->server);
2248 _kdc_free_ent(context, adclient);
2254 * TODO: pass in t->sname and t->realm and build
2255 * a S4U_DELEGATION_INFO blob to the PAC.
2257 ret = _kdc_check_pac(context, config, tp, dp, adclient, server, krbtgt, client,
2258 &clientkey->key, &priv->ticket_key->key, &adtkt, &ad_kdc_issued, &mspac);
2260 _kdc_free_ent(context, adclient);
2262 const char *msg = krb5_get_error_message(context, ret);
2263 _kdc_audit_addreason((kdc_request_t)priv,
2264 "Constrained delegation ticket PAC check failed");
2265 kdc_log(context, config, 4,
2266 "Verify delegated PAC failed to %s for client"
2267 "%s (%s) as %s from %s with %s",
2268 spn, cpn, dpn, tpn, from, msg);
2269 krb5_free_error_message(context, msg);
2273 if (mspac == NULL || !ad_kdc_issued) {
2274 ret = KRB5KDC_ERR_BADOPTION;
2275 kdc_log(context, config, 4,
2276 "Ticket not signed with PAC; service %s failed for "
2277 "for delegation to %s for client %s (%s) from %s; (%s).",
2278 spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
2279 _kdc_audit_addreason((kdc_request_t)priv,
2280 "Constrained delegation ticket not signed");
2284 kdc_log(context, config, 4, "constrained delegation for %s "
2285 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2292 ret = kdc_check_flags(priv, FALSE, priv->client, priv->server);
2296 if((b->kdc_options.validate || b->kdc_options.renew) &&
2297 !krb5_principal_compare(context,
2298 krbtgt->entry.principal,
2299 server->entry.principal)){
2300 _kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request");
2301 kdc_log(context, config, 4, "Inconsistent request.");
2302 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2306 /* check for valid set of addresses */
2307 if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) {
2308 if (config->check_ticket_addresses) {
2309 ret = KRB5KRB_AP_ERR_BADADDR;
2310 _kdc_audit_addkv((kdc_request_t)priv, 0, "wrongaddr", "yes");
2311 kdc_log(context, config, 4, "Request from wrong address");
2312 _kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address");
2314 } else if (config->warn_ticket_addresses) {
2315 _kdc_audit_addkv((kdc_request_t)priv, 0, "wrongaddr", "yes");
2319 /* check local and per-principal anonymous ticket issuance policy */
2320 if (is_anon_tgs_request_p(b, tgt)) {
2321 ret = _kdc_check_anon_policy(priv);
2327 * If this is an referral, add server referral data to the
2334 kdc_log(context, config, 3,
2335 "Adding server referral to %s", ref_realm);
2337 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2341 ret = build_server_referral(context, config, crypto, ref_realm,
2342 NULL, s, &pa.padata_value);
2343 krb5_crypto_destroy(context, crypto);
2345 _kdc_audit_addreason((kdc_request_t)priv, "Referral build failed");
2346 kdc_log(context, config, 4,
2347 "Failed building server referral");
2350 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2352 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2353 krb5_data_free(&pa.padata_value);
2355 kdc_log(context, config, 4,
2356 "Add server referral METHOD-DATA failed");
2362 * Only add ticket signature if the requested server is not krbtgt, and
2363 * either the header server is krbtgt or, in the case of renewal/validation
2364 * if it was signed with PAC ticket signature and we verified it.
2365 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2366 * change one day (see issue #763) so make sure to check for it.
2370 !krb5_principal_is_krbtgt(context, server->entry.principal))
2371 add_ticket_sig = TRUE;
2374 * Active-Directory implementations use the high part of the kvno as the
2375 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2378 rodc_id = krbtgt_out->entry.kvno >> 16;
2384 ret = tgs_make_reply(priv,
2403 free(user2user_name);
2408 _krb5_free_capath(context, capath);
2410 krb5_free_keyblock_contents(context, &sessionkey);
2412 _kdc_free_ent(context, krbtgt_out);
2414 _kdc_free_ent(context, server);
2416 _kdc_free_ent(context, client);
2417 if(s4u2self_impersonated_client)
2418 _kdc_free_ent(context, s4u2self_impersonated_client);
2419 if(user2user_krbtgt)
2420 _kdc_free_ent(context, user2user_krbtgt);
2422 krb5_free_principal(context, user2user_princ);
2424 krb5_free_principal(context, tp);
2425 krb5_free_principal(context, cp);
2426 krb5_free_principal(context, dp);
2427 krb5_free_principal(context, sp);
2428 krb5_free_principal(context, krbtgt_out_principal);
2430 free_METHOD_DATA(&enc_pa_data);
2432 free_EncTicketPart(&adtkt);
2434 krb5_pac_free(context, mspac);
2435 krb5_pac_free(context, user2user_pac);
2445 _kdc_tgs_rep(astgs_request_t r)
2447 krb5_kdc_configuration *config = r->config;
2448 KDC_REQ *req = &r->req;
2449 krb5_data *data = r->reply;
2450 const char *from = r->from;
2451 struct sockaddr *from_addr = r->addr;
2452 int datagram_reply = r->datagram_reply;
2453 AuthorizationData *auth_data = NULL;
2454 krb5_error_code ret;
2456 const PA_DATA *tgs_req, *pa;
2458 hdb_entry_ex *krbtgt = NULL;
2459 krb5_ticket *ticket = NULL;
2460 const char *e_text = NULL;
2461 krb5_enctype krbtgt_etype = ETYPE_NULL;
2463 time_t *csec = NULL;
2466 if(req->padata == NULL){
2467 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2468 kdc_log(r->context, config, 4,
2469 "TGS-REQ from %s without PA-DATA", from);
2474 pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
2476 kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2477 ret = KRB5KRB_ERR_GENERIC;
2482 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2483 if(tgs_req == NULL){
2484 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2486 kdc_log(r->context, config, 4,
2487 "TGS-REQ from %s without PA-TGS-REQ", from);
2490 ret = tgs_parse_request(r, tgs_req,
2498 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2499 /* kdc_log() is called in tgs_parse_request() */
2503 kdc_log(r->context, config, 4,
2504 "Failed parsing TGS-REQ from %s", from);
2508 ret = _kdc_fast_strengthen_reply_key(r);
2512 ret = tgs_build_reply(r,
2520 kdc_log(r->context, config, 4,
2521 "Failed building TGS-REP to %s", from);
2526 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2527 krb5_data_free(data);
2528 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2529 e_text = "Reply packet too large";
2533 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2534 METHOD_DATA error_method = { 0, NULL };
2536 kdc_log(r->context, config, 5, "tgs-req: sending error: %d to client", ret);
2537 ret = _kdc_fast_mk_error(r,
2542 ticket != NULL ? ticket->client : NULL,
2543 ticket != NULL ? ticket->server : NULL,
2546 free_METHOD_DATA(&error_method);
2551 if (r->armor_crypto) {
2552 krb5_crypto_destroy(r->context, r->armor_crypto);
2553 r->armor_crypto = NULL;
2555 krb5_free_keyblock_contents(r->context, &r->reply_key);
2556 krb5_free_keyblock_contents(r->context, &r->strengthen_key);
2559 krb5_free_ticket(r->context, ticket);
2561 _kdc_free_ent(r->context, krbtgt);
2563 _kdc_free_fast_state(&r->fast);
2566 free_AuthorizationData(auth_data);