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 * return TRUE if client was a synthetic principal, as indicated by
55 _kdc_synthetic_princ_used_p(krb5_context context, krb5_ticket *ticket)
57 krb5_data synthetic_princ_used;
60 ret = krb5_ticket_get_authorization_data_type(context, ticket,
61 KRB5_AUTHDATA_SYNTHETIC_PRINC_USED,
62 &synthetic_princ_used);
64 ret = krb5_ticket_get_authorization_data_type(context, ticket,
65 KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
66 &synthetic_princ_used);
69 krb5_data_free(&synthetic_princ_used);
79 _kdc_check_pac(krb5_context context,
80 krb5_kdc_configuration *config,
81 const krb5_principal client_principal,
82 const krb5_principal delegated_proxy_principal,
86 hdb_entry_ex *ticket_server,
87 const EncryptionKey *server_check_key,
88 const EncryptionKey *krbtgt_check_key,
90 krb5_boolean *kdc_issued,
92 krb5_principal *pac_canon_name,
93 uint64_t *pac_attributes)
97 krb5_boolean signedticket;
102 *pac_canon_name = NULL;
104 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
106 ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
111 if (config->require_pac)
112 ret = KRB5KDC_ERR_TGT_REVOKED;
116 /* Verify the server signature. */
117 ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
118 server_check_key, NULL);
120 krb5_pac_free(context, pac);
124 if (pac_canon_name) {
125 ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
126 if (ret && ret != ENOENT) {
127 krb5_pac_free(context, pac);
131 if (pac_attributes) {
132 ret = _krb5_pac_get_attributes_info(context, pac, pac_attributes);
133 if (ret && ret != ENOENT) {
134 krb5_pac_free(context, pac);
138 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
141 /* Verify the KDC signatures. */
142 ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal,
143 client, server, krbtgt, &pac);
146 /* the plugin may indicate no PAC should be generated */
149 } else if (ret == KRB5_PLUGIN_NO_HANDLE) {
151 * We can't verify the KDC signatures if the ticket was issued by
152 * another realm's KDC.
154 if (krb5_realm_compare(context, server->entry.principal,
155 ticket_server->entry.principal)) {
156 ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
159 krb5_pac_free(context, pac);
164 /* Discard the PAC if the plugin didn't handle it */
165 krb5_pac_free(context, pac);
166 ret = krb5_pac_init(context, &pac);
170 krb5_pac_free(context, pac);
174 *kdc_issued = signedticket ||
175 krb5_principal_is_krbtgt(context,
176 ticket_server->entry.principal);
183 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
184 const EncTicketPart *tgt)
186 KDCOptions f = b->kdc_options;
189 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
190 * request-anonymous and cname-in-addl-tkt flags for constrained
191 * delegation requests. A true anonymous TGS request will only
192 * have the request-anonymous flag set. (A corollary of this is
193 * that it is not possible to support anonymous constrained
194 * delegation requests, although they would be of limited utility.)
196 return tgt->flags.anonymous ||
197 (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
204 static krb5_error_code
205 check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b,
206 krb5_const_principal tgt_name,
207 const EncTicketPart *tgt, EncTicketPart *et)
209 KDCOptions f = b->kdc_options;
212 if (!tgt->flags.invalid || tgt->starttime == NULL) {
213 _kdc_audit_addreason((kdc_request_t)r,
214 "Bad request to validate ticket");
215 return KRB5KDC_ERR_BADOPTION;
217 if(*tgt->starttime > kdc_time){
218 _kdc_audit_addreason((kdc_request_t)r,
219 "Early request to validate ticket");
220 return KRB5KRB_AP_ERR_TKT_NYV;
223 et->flags.invalid = 0;
224 } else if (tgt->flags.invalid) {
225 _kdc_audit_addreason((kdc_request_t)r,
226 "Ticket-granting ticket has INVALID flag set");
227 return KRB5KRB_AP_ERR_TKT_INVALID;
231 if (!tgt->flags.forwardable) {
232 _kdc_audit_addreason((kdc_request_t)r,
233 "Bad request for forwardable ticket");
234 return KRB5KDC_ERR_BADOPTION;
236 et->flags.forwardable = 1;
239 if (!tgt->flags.forwardable) {
240 _kdc_audit_addreason((kdc_request_t)r,
241 "Request to forward non-forwardable ticket");
242 return KRB5KDC_ERR_BADOPTION;
244 et->flags.forwarded = 1;
245 et->caddr = b->addresses;
247 if(tgt->flags.forwarded)
248 et->flags.forwarded = 1;
251 if (!tgt->flags.proxiable) {
252 _kdc_audit_addreason((kdc_request_t)r,
253 "Bad request for proxiable ticket");
254 return KRB5KDC_ERR_BADOPTION;
256 et->flags.proxiable = 1;
259 if (!tgt->flags.proxiable) {
260 _kdc_audit_addreason((kdc_request_t)r,
261 "Request to proxy non-proxiable ticket");
262 return KRB5KDC_ERR_BADOPTION;
265 et->caddr = b->addresses;
270 if(f.allow_postdate){
271 if (!tgt->flags.may_postdate) {
272 _kdc_audit_addreason((kdc_request_t)r,
273 "Bad request for post-datable ticket");
274 return KRB5KDC_ERR_BADOPTION;
276 et->flags.may_postdate = 1;
279 if (!tgt->flags.may_postdate) {
280 _kdc_audit_addreason((kdc_request_t)r,
281 "Bad request for postdated ticket");
282 return KRB5KDC_ERR_BADOPTION;
285 *et->starttime = *b->from;
286 et->flags.postdated = 1;
287 et->flags.invalid = 1;
288 } else if (b->from && *b->from > kdc_time + r->context->max_skew) {
289 _kdc_audit_addreason((kdc_request_t)r,
290 "Ticket cannot be postdated");
291 return KRB5KDC_ERR_CANNOT_POSTDATE;
295 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
296 _kdc_audit_addreason((kdc_request_t)r,
297 "Bad request for renewable ticket");
298 return KRB5KDC_ERR_BADOPTION;
300 et->flags.renewable = 1;
301 ALLOC(et->renew_till);
302 _kdc_fix_time(&b->rtime);
303 *et->renew_till = *b->rtime;
307 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
308 _kdc_audit_addreason((kdc_request_t)r,
309 "Request to renew non-renewable ticket");
310 return KRB5KDC_ERR_BADOPTION;
312 old_life = tgt->endtime;
314 old_life -= *tgt->starttime;
316 old_life -= tgt->authtime;
317 et->endtime = *et->starttime + old_life;
318 if (et->renew_till != NULL)
319 et->endtime = min(*et->renew_till, et->endtime);
323 * RFC 8062 section 3 defines an anonymous ticket as one containing
324 * the anonymous principal and the anonymous ticket flag.
326 if (tgt->flags.anonymous &&
327 !_kdc_is_anonymous(r->context, tgt_name)) {
328 _kdc_audit_addreason((kdc_request_t)r,
329 "Anonymous ticket flag set without "
330 "anonymous principal");
331 return KRB5KDC_ERR_BADOPTION;
335 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
336 * anonymous KDC option SHOULD be set, but it is not required.
337 * Treat an anonymous TGT as if the anonymous flag was set.
339 if (is_anon_tgs_request_p(b, tgt))
340 et->flags.anonymous = 1;
346 * Determine if constrained delegation is allowed from this client to this server
349 static krb5_error_code
350 check_constrained_delegation(krb5_context context,
351 krb5_kdc_configuration *config,
353 hdb_entry_ex *client,
354 hdb_entry_ex *server,
355 krb5_const_principal target)
357 const HDB_Ext_Constrained_delegation_acl *acl;
362 * constrained_delegation (S4U2Proxy) only works within
363 * the same realm. We use the already canonicalized version
364 * of the principals here, while "target" is the principal
365 * provided by the client.
367 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
368 ret = KRB5KDC_ERR_BADOPTION;
369 kdc_log(context, config, 4,
370 "Bad request for constrained delegation");
374 if (clientdb->hdb_check_constrained_delegation) {
375 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
379 /* if client delegates to itself, that ok */
380 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
383 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
385 krb5_clear_error_message(context);
390 for (i = 0; i < acl->len; i++) {
391 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
395 ret = KRB5KDC_ERR_BADOPTION;
397 kdc_log(context, config, 4,
398 "Bad request for constrained delegation");
403 * Determine if s4u2self is allowed from this client to this server
407 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
408 * service given by the client.
410 * For example, regardless of the principal being impersonated, if the
411 * 'client' and 'server' (target) are the same, or server is an SPN
412 * alias of client, then it's safe.
415 static krb5_error_code
416 check_client_matches_target_service(krb5_context context,
417 krb5_kdc_configuration *config,
419 hdb_entry_ex *client,
420 hdb_entry_ex *target_server,
421 krb5_const_principal target_server_principal)
426 * Always allow the plugin to check, this might be faster, allow a
427 * policy or audit check and can look into the DB records
430 if (clientdb->hdb_check_client_matches_target_service) {
431 ret = clientdb->hdb_check_client_matches_target_service(context,
437 } else if (krb5_principal_compare(context,
438 client->entry.principal,
439 target_server_principal) == TRUE) {
440 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
443 ret = KRB5KDC_ERR_BADOPTION;
453 _kdc_verify_flags(krb5_context context,
454 krb5_kdc_configuration *config,
455 const EncTicketPart *et,
458 if(et->endtime < kdc_time){
459 kdc_log(context, config, 4, "Ticket expired (%s)", pstr);
460 return KRB5KRB_AP_ERR_TKT_EXPIRED;
462 if(et->flags.invalid){
463 kdc_log(context, config, 4, "Ticket not valid (%s)", pstr);
464 return KRB5KRB_AP_ERR_TKT_NYV;
473 static krb5_error_code
474 fix_transited_encoding(krb5_context context,
475 krb5_kdc_configuration *config,
476 krb5_boolean check_policy,
477 const TransitedEncoding *tr,
479 const char *client_realm,
480 const char *server_realm,
481 const char *tgt_realm)
483 krb5_error_code ret = 0;
484 char **realms, **tmp;
485 unsigned int num_realms;
488 switch (tr->tr_type) {
489 case domain_X500_Compress:
493 * Allow empty content of type 0 because that is was Microsoft
494 * generates in their TGT.
496 if (tr->contents.length == 0)
498 kdc_log(context, config, 4,
499 "Transited type 0 with non empty content");
500 return KRB5KDC_ERR_TRTYPE_NOSUPP;
502 kdc_log(context, config, 4,
503 "Unknown transited type: %u", tr->tr_type);
504 return KRB5KDC_ERR_TRTYPE_NOSUPP;
507 ret = krb5_domain_x500_decode(context,
514 krb5_warn(context, ret,
515 "Decoding transited encoding");
520 * If the realm of the presented tgt is neither the client nor the server
521 * realm, it is a transit realm and must be added to transited set.
523 if (strcmp(client_realm, tgt_realm) != 0 &&
524 strcmp(server_realm, tgt_realm) != 0) {
525 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
529 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
535 realms[num_realms] = strdup(tgt_realm);
536 if(realms[num_realms] == NULL){
542 if(num_realms == 0) {
543 if (strcmp(client_realm, server_realm) != 0)
544 kdc_log(context, config, 4,
545 "cross-realm %s -> %s", client_realm, server_realm);
549 for(i = 0; i < num_realms; i++)
550 l += strlen(realms[i]) + 2;
554 for(i = 0; i < num_realms; i++) {
556 strlcat(rs, ", ", l);
557 strlcat(rs, realms[i], l);
559 kdc_log(context, config, 4,
560 "cross-realm %s -> %s via [%s]",
561 client_realm, server_realm, rs);
566 ret = krb5_check_transited(context, client_realm,
568 realms, num_realms, NULL);
570 krb5_warn(context, ret, "cross-realm %s -> %s",
571 client_realm, server_realm);
574 et->flags.transited_policy_checked = 1;
576 et->transited.tr_type = domain_X500_Compress;
577 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
579 krb5_warn(context, ret, "Encoding transited encoding");
581 for(i = 0; i < num_realms; i++)
588 static krb5_error_code
589 tgs_make_reply(astgs_request_t r,
590 krb5_principal tgt_name,
591 const EncTicketPart *tgt,
592 const EncryptionKey *serverkey,
593 const EncryptionKey *krbtgtkey,
594 const krb5_keyblock *sessionkey,
596 AuthorizationData *auth_data,
597 hdb_entry_ex *server,
598 krb5_principal server_principal,
599 hdb_entry_ex *client,
600 krb5_principal client_principal,
601 const char *tgt_realm,
603 krb5_boolean add_ticket_sig)
605 KDC_REQ_BODY *b = &r->req.req_body;
606 krb5_data *reply = r->reply;
607 KDC_REP *rep = &r->rep;
608 EncTicketPart *et = &r->et;
609 EncKDCRepPart *ek = &r->ek;
610 KDCOptions f = b->kdc_options;
615 rep->msg_type = krb_tgs_rep;
617 et->authtime = tgt->authtime;
618 _kdc_fix_time(&b->till);
619 et->endtime = min(tgt->endtime, *b->till);
620 ALLOC(et->starttime);
621 *et->starttime = kdc_time;
623 ret = check_tgs_flags(r, b, tgt_name, tgt, et);
627 /* We should check the transited encoding if:
628 1) the request doesn't ask not to be checked
629 2) globally enforcing a check
630 3) principal requires checking
631 4) we allow non-check per-principal, but principal isn't marked as allowing this
632 5) we don't globally allow this
635 #define GLOBAL_FORCE_TRANSITED_CHECK \
636 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
637 #define GLOBAL_ALLOW_PER_PRINCIPAL \
638 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
639 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
640 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
642 /* these will consult the database in future release */
643 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
644 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
646 ret = fix_transited_encoding(r->context, r->config,
647 !f.disable_transited_check ||
648 GLOBAL_FORCE_TRANSITED_CHECK ||
649 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
650 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
651 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
652 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
654 krb5_principal_get_realm(r->context, client_principal),
655 krb5_principal_get_realm(r->context, server->entry.principal),
660 ret = copy_Realm(&server_principal->realm, &rep->ticket.realm);
663 _krb5_principal2principalname(&rep->ticket.sname, server_principal);
664 ret = copy_Realm(&tgt_name->realm, &rep->crealm);
669 * RFC 8062 states "if the ticket in the TGS request is an anonymous
670 * one, the client and client realm are copied from that ticket". So
671 * whilst the TGT flag check below is superfluous, it is included in
672 * order to follow the specification to its letter.
674 if (et->flags.anonymous && !tgt->flags.anonymous)
675 _kdc_make_anonymous_principalname(&rep->cname);
677 ret = copy_PrincipalName(&tgt_name->name, &rep->cname);
680 rep->ticket.tkt_vno = 5;
682 ek->caddr = et->caddr;
686 life = et->endtime - *et->starttime;
687 if(client && client->entry.max_life)
688 life = min(life, *client->entry.max_life);
689 if(server->entry.max_life)
690 life = min(life, *server->entry.max_life);
691 et->endtime = *et->starttime + life;
693 if(f.renewable_ok && tgt->flags.renewable &&
694 et->renew_till == NULL && et->endtime < *b->till &&
695 tgt->renew_till != NULL)
697 et->flags.renewable = 1;
698 ALLOC(et->renew_till);
699 *et->renew_till = *b->till;
703 renew = *et->renew_till - *et->starttime;
704 if(client && client->entry.max_renew)
705 renew = min(renew, *client->entry.max_renew);
706 if(server->entry.max_renew)
707 renew = min(renew, *server->entry.max_renew);
708 *et->renew_till = *et->starttime + renew;
712 *et->renew_till = min(*et->renew_till, *tgt->renew_till);
713 *et->starttime = min(*et->starttime, *et->renew_till);
714 et->endtime = min(et->endtime, *et->renew_till);
717 *et->starttime = min(*et->starttime, et->endtime);
719 if(*et->starttime == et->endtime){
720 ret = KRB5KDC_ERR_NEVER_VALID;
723 if(et->renew_till && et->endtime == *et->renew_till){
724 free(et->renew_till);
725 et->renew_till = NULL;
726 et->flags.renewable = 0;
729 et->flags.pre_authent = tgt->flags.pre_authent;
730 et->flags.hw_authent = tgt->flags.hw_authent;
731 et->flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
733 /* See MS-KILE 3.3.5.1 */
734 if (!server->entry.flags.forwardable)
735 et->flags.forwardable = 0;
736 if (!server->entry.flags.proxiable)
737 et->flags.proxiable = 0;
742 /* XXX check authdata */
744 if (et->authorization_data == NULL) {
745 et->authorization_data = calloc(1, sizeof(*et->authorization_data));
746 if (et->authorization_data == NULL) {
748 krb5_set_error_message(r->context, ret, "malloc: out of memory");
752 for(i = 0; i < auth_data->len ; i++) {
753 ret = add_AuthorizationData(et->authorization_data, &auth_data->val[i]);
755 krb5_set_error_message(r->context, ret, "malloc: out of memory");
761 ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et->key);
764 et->crealm = rep->crealm;
765 et->cname = rep->cname;
768 /* MIT must have at least one last_req */
769 ek->last_req.val = calloc(1, sizeof(*ek->last_req.val));
770 if (ek->last_req.val == NULL) {
774 ek->last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
775 ek->nonce = b->nonce;
776 ek->flags = et->flags;
777 ek->authtime = et->authtime;
778 ek->starttime = et->starttime;
779 ek->endtime = et->endtime;
780 ek->renew_till = et->renew_till;
781 ek->srealm = rep->ticket.realm;
782 ek->sname = rep->ticket.sname;
784 _kdc_log_timestamp(r, "TGS-REQ", et->authtime, et->starttime,
785 et->endtime, et->renew_till);
787 if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
788 && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
790 krb5_enctype_enable(r->context, serverkey->keytype);
794 if (r->client_princ) {
797 krb5_unparse_name(r->context, r->client_princ, &cpn);
798 _kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s",
799 cpn ? cpn : "<unknown>");
804 * For anonymous tickets, we should filter out positive authorization data
805 * that could reveal the client's identity, and return a policy error for
806 * restrictive authorization data. Policy for unknown authorization types
807 * is implementation dependent.
809 if (r->pac && !et->flags.anonymous) {
810 _kdc_audit_addkv((kdc_request_t)r, 0, "pac_attributes", "%lx",
811 (long)r->pac_attributes);
814 * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
815 * buffer (legacy behavior) or if the attributes buffer indicates the
816 * AS client requested one.
818 if (_kdc_include_pac_p(r)) {
819 krb5_boolean is_tgs =
820 krb5_principal_is_krbtgt(r->context, server->entry.principal);
822 ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, tgt_name, serverkey,
823 krbtgtkey, rodc_id, NULL, r->client_princ,
825 is_tgs ? &r->pac_attributes : NULL);
831 ret = _kdc_finalize_reply(r);
835 /* It is somewhat unclear where the etype in the following
836 encryption should come from. What we have is a session
837 key in the passed tgt, and a list of preferred etypes
838 *for the new ticket*. Should we pick the best possible
839 etype, given the keytype in the tgt, or should we look
840 at the etype list here as well? What if the tgt
841 session key is DES3 and we want a ticket with a (say)
842 CAST session key. Should the DES3 etype be added to the
843 etype list, even if we don't want a session key with
845 ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
846 serverkey->keytype, kvno,
847 serverkey, 0, r->rk_is_subkey, reply);
849 krb5_enctype_disable(r->context, serverkey->keytype);
851 _log_astgs_req(r, serverkey->keytype);
857 static krb5_error_code
858 tgs_check_authenticator(krb5_context context,
859 krb5_kdc_configuration *config,
860 krb5_auth_context ac,
864 krb5_authenticator auth;
868 krb5_auth_con_getauthenticator(context, ac, &auth);
869 if(auth->cksum == NULL){
870 kdc_log(context, config, 4, "No authenticator in request");
871 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
875 if (!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
876 kdc_log(context, config, 4, "Bad checksum type in authenticator: %d",
877 auth->cksum->cksumtype);
878 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
882 ret = krb5_crypto_init(context, key, 0, &crypto);
884 const char *msg = krb5_get_error_message(context, ret);
885 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
886 krb5_free_error_message(context, msg);
891 * RFC4120 says the checksum must be collision-proof, but it does
892 * not require it to be keyed (as the authenticator is encrypted).
894 _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
895 ret = _kdc_verify_checksum(context,
897 KRB5_KU_TGS_REQ_AUTH_CKSUM,
900 krb5_crypto_destroy(context, crypto);
902 const char *msg = krb5_get_error_message(context, ret);
903 kdc_log(context, config, 4,
904 "Failed to verify authenticator checksum: %s", msg);
905 krb5_free_error_message(context, msg);
908 free_Authenticator(auth);
914 need_referral(krb5_context context, krb5_kdc_configuration *config,
915 const KDCOptions * const options, krb5_principal server,
920 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
923 if (server->name.name_string.len == 1)
924 name = server->name.name_string.val[0];
925 else if (server->name.name_string.len == 3) {
927 This is used to give referrals for the
928 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
929 SPN form, which is used for inter-domain communication in AD
931 name = server->name.name_string.val[2];
932 kdc_log(context, config, 4, "Giving 3 part referral for %s", name);
933 *realms = malloc(sizeof(char *)*2);
934 if (*realms == NULL) {
935 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
938 (*realms)[0] = strdup(name);
941 } else if (server->name.name_string.len > 1)
942 name = server->name.name_string.val[1];
946 kdc_log(context, config, 5, "Searching referral for %s", name);
948 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
951 static krb5_error_code
952 validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
957 krb5_data_zero(&data);
959 ret = _krb5_get_ad(r->context, auth_data, NULL,
960 KRB5_AUTHDATA_FX_FAST_USED, &data);
962 r->fast_asserted = 1;
963 krb5_data_free(&data);
966 ret = _krb5_get_ad(r->context, auth_data, NULL,
967 KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
969 kdc_log(r->context, r->config, 2,
970 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
971 krb5_data_free(&data);
972 return KRB5KRB_AP_ERR_BAD_INTEGRITY;
978 static krb5_error_code
979 tgs_parse_request(astgs_request_t r,
980 const PA_DATA *tgs_req,
981 hdb_entry_ex **krbtgt,
982 krb5_enctype *krbtgt_etype,
983 krb5_ticket **ticket,
985 const struct sockaddr *from_addr,
988 AuthorizationData **auth_data)
990 krb5_kdc_configuration *config = r->config;
991 KDC_REQ_BODY *b = &r->req.req_body;
992 static char failed[] = "<unparse_name failed>";
995 krb5_principal princ;
996 krb5_auth_context ac = NULL;
997 krb5_flags ap_req_options;
998 krb5_flags verify_ap_req_flags = 0;
1000 krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1001 krb5uint32 krbtgt_kvno_try;
1002 int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
1003 const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
1005 krb5_keyblock *subkey = NULL;
1012 memset(&ap_req, 0, sizeof(ap_req));
1013 ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req);
1015 const char *msg = krb5_get_error_message(r->context, ret);
1016 kdc_log(r->context, config, 4, "Failed to decode AP-REQ: %s", msg);
1017 krb5_free_error_message(r->context, msg);
1021 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1022 /* XXX check for ticket.sname == req.sname */
1023 kdc_log(r->context, config, 4, "PA-DATA is not a ticket-granting ticket");
1024 ret = KRB5KDC_ERR_POLICY; /* ? */
1028 _krb5_principalname2krb5_principal(r->context,
1030 ap_req.ticket.sname,
1031 ap_req.ticket.realm);
1033 krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
1034 ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT,
1035 &krbtgt_kvno, NULL, krbtgt);
1037 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1038 /* XXX Factor out this unparsing of the same princ all over */
1040 ret = krb5_unparse_name(r->context, princ, &p);
1043 krb5_free_principal(r->context, princ);
1044 kdc_log(r->context, config, 5,
1045 "Ticket-granting ticket account %s does not have secrets at "
1046 "this KDC, need to proxy", p);
1049 ret = HDB_ERR_NOT_FOUND_HERE;
1051 } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1053 ret = krb5_unparse_name(r->context, princ, &p);
1056 krb5_free_principal(r->context, princ);
1057 kdc_log(r->context, config, 5,
1058 "Ticket-granting ticket account %s does not have keys for "
1059 "kvno %d at this KDC", p, krbtgt_kvno);
1062 ret = HDB_ERR_KVNO_NOT_FOUND;
1064 } else if (ret == HDB_ERR_NO_MKEY) {
1066 ret = krb5_unparse_name(r->context, princ, &p);
1069 krb5_free_principal(r->context, princ);
1070 kdc_log(r->context, config, 5,
1071 "Missing master key for decrypting keys for ticket-granting "
1072 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1075 ret = HDB_ERR_KVNO_NOT_FOUND;
1078 const char *msg = krb5_get_error_message(r->context, ret);
1080 ret = krb5_unparse_name(r->context, princ, &p);
1083 kdc_log(r->context, config, 4,
1084 "Ticket-granting ticket %s not found in database: %s", p, msg);
1085 krb5_free_principal(r->context, princ);
1086 krb5_free_error_message(r->context, msg);
1089 ret = KRB5KRB_AP_ERR_NOT_US;
1093 krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1094 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1097 krbtgt_keys = hdb_kvno2keys(r->context, &(*krbtgt)->entry, krbtgt_kvno_try);
1098 ret = hdb_enctype2key(r->context, &(*krbtgt)->entry, krbtgt_keys,
1099 ap_req.ticket.enc_part.etype, &tkey);
1100 if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1101 kvno_search_tries--;
1105 char *str = NULL, *p = NULL;
1107 krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str);
1108 krb5_unparse_name(r->context, princ, &p);
1109 kdc_log(r->context, config, 4,
1110 "No server key with enctype %s found for %s",
1111 str ? str : "<unknown enctype>",
1112 p ? p : "<unparse_name failed>");
1115 ret = KRB5KRB_AP_ERR_BADKEYVER;
1119 if (b->kdc_options.validate)
1120 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1122 if (r->config->warn_ticket_addresses)
1123 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS;
1125 ret = krb5_verify_ap_req2(r->context,
1130 verify_ap_req_flags,
1133 KRB5_KU_TGS_REQ_AUTH);
1134 if (*ticket && (*ticket)->ticket.caddr)
1135 _kdc_audit_addaddrs((kdc_request_t)r, (*ticket)->ticket.caddr, "tixaddrs");
1136 if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR &&
1138 _kdc_audit_addkv((kdc_request_t)r, 0, "wrongaddr", "yes");
1141 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1142 kvno_search_tries--;
1147 krb5_free_principal(r->context, princ);
1149 const char *msg = krb5_get_error_message(r->context, ret);
1150 kdc_log(r->context, config, 4, "Failed to verify AP-REQ: %s", msg);
1151 krb5_free_error_message(r->context, msg);
1155 r->ticket_key = tkey;
1158 krb5_authenticator auth;
1160 ret = krb5_auth_con_getauthenticator(r->context, ac, &auth);
1162 *csec = malloc(sizeof(**csec));
1163 if (*csec == NULL) {
1164 krb5_free_authenticator(r->context, &auth);
1165 kdc_log(r->context, config, 4, "malloc failed");
1168 **csec = auth->ctime;
1169 *cusec = malloc(sizeof(**cusec));
1170 if (*cusec == NULL) {
1171 krb5_free_authenticator(r->context, &auth);
1172 kdc_log(r->context, config, 4, "malloc failed");
1175 **cusec = auth->cusec;
1177 ret = validate_fast_ad(r, auth->authorization_data);
1178 krb5_free_authenticator(r->context, &auth);
1184 ret = tgs_check_authenticator(r->context, config, ac, b,
1185 &(*ticket)->ticket.key);
1187 krb5_auth_con_free(r->context, ac);
1191 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1192 r->rk_is_subkey = 1;
1194 ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
1196 const char *msg = krb5_get_error_message(r->context, ret);
1197 krb5_auth_con_free(r->context, ac);
1198 kdc_log(r->context, config, 4, "Failed to get remote subkey: %s", msg);
1199 krb5_free_error_message(r->context, msg);
1203 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1204 r->rk_is_subkey = 0;
1206 ret = krb5_auth_con_getkey(r->context, ac, &subkey);
1208 const char *msg = krb5_get_error_message(r->context, ret);
1209 krb5_auth_con_free(r->context, ac);
1210 kdc_log(r->context, config, 4, "Failed to get session key: %s", msg);
1211 krb5_free_error_message(r->context, msg);
1216 krb5_auth_con_free(r->context, ac);
1217 kdc_log(r->context, config, 4,
1218 "Failed to get key for enc-authorization-data");
1219 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1223 krb5_free_keyblock_contents(r->context, &r->reply_key);
1224 ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
1225 krb5_free_keyblock(r->context, subkey);
1229 if (b->enc_authorization_data) {
1232 ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto);
1234 const char *msg = krb5_get_error_message(r->context, ret);
1235 krb5_auth_con_free(r->context, ac);
1236 kdc_log(r->context, config, 4, "krb5_crypto_init failed: %s", msg);
1237 krb5_free_error_message(r->context, msg);
1240 ret = krb5_decrypt_EncryptedData (r->context,
1243 b->enc_authorization_data,
1245 krb5_crypto_destroy(r->context, crypto);
1247 krb5_auth_con_free(r->context, ac);
1248 kdc_log(r->context, config, 4,
1249 "Failed to decrypt enc-authorization-data");
1250 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1254 if (*auth_data == NULL) {
1255 krb5_auth_con_free(r->context, ac);
1256 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1259 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1261 krb5_auth_con_free(r->context, ac);
1264 kdc_log(r->context, config, 4, "Failed to decode authorization data");
1265 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1270 ret = validate_fast_ad(r, (*ticket)->ticket.authorization_data);
1276 * Check for FAST request
1279 ret = _kdc_fast_unwrap_request(r, *ticket, ac);
1283 krb5_auth_con_free(r->context, ac);
1286 free_AP_REQ(&ap_req);
1291 static krb5_error_code
1292 build_server_referral(krb5_context context,
1293 krb5_kdc_configuration *config,
1294 krb5_crypto session,
1295 krb5_const_realm referred_realm,
1296 const PrincipalName *true_principal_name,
1297 const PrincipalName *requested_principal,
1300 PA_ServerReferralData ref;
1301 krb5_error_code ret;
1306 memset(&ref, 0, sizeof(ref));
1308 if (referred_realm) {
1309 ALLOC(ref.referred_realm);
1310 if (ref.referred_realm == NULL)
1312 *ref.referred_realm = strdup(referred_realm);
1313 if (*ref.referred_realm == NULL)
1316 if (true_principal_name) {
1317 ALLOC(ref.true_principal_name);
1318 if (ref.true_principal_name == NULL)
1320 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1324 if (requested_principal) {
1325 ALLOC(ref.requested_principal_name);
1326 if (ref.requested_principal_name == NULL)
1328 ret = copy_PrincipalName(requested_principal,
1329 ref.requested_principal_name);
1334 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1335 data.data, data.length,
1337 free_PA_ServerReferralData(&ref);
1340 if (data.length != size)
1341 krb5_abortx(context, "internal asn.1 encoder error");
1343 ret = krb5_encrypt_EncryptedData(context, session,
1344 KRB5_KU_PA_SERVER_REFERRAL,
1345 data.data, data.length,
1351 ASN1_MALLOC_ENCODE(EncryptedData,
1352 outdata->data, outdata->length,
1354 free_EncryptedData(&ed);
1357 if (outdata->length != size)
1358 krb5_abortx(context, "internal asn.1 encoder error");
1362 free_PA_ServerReferralData(&ref);
1363 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1368 * This function is intended to be used when failure to find the client is
1372 _kdc_db_fetch_client(krb5_context context,
1373 krb5_kdc_configuration *config,
1377 const char *krbtgt_realm,
1379 hdb_entry_ex **client_out)
1381 krb5_error_code ret;
1382 hdb_entry_ex *client = NULL;
1386 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1387 NULL, clientdb, &client);
1388 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1390 * This is OK, we are just trying to find out if they have
1391 * been disabled or deleted in the meantime; missing secrets
1396 * If the client belongs to the same realm as our TGS, it
1397 * should exist in the local database.
1401 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1402 if (ret == HDB_ERR_NOENTRY)
1403 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1404 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1408 msg = krb5_get_error_message(context, ret);
1409 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1410 krb5_free_error_message(context, msg);
1411 } else if (client->entry.flags.invalid || !client->entry.flags.client) {
1412 kdc_log(context, config, 4, "Client has invalid bit set");
1413 _kdc_free_ent(context, client);
1414 return KRB5KDC_ERR_POLICY;
1417 *client_out = client;
1422 static krb5_error_code
1423 tgs_build_reply(astgs_request_t priv,
1424 hdb_entry_ex *krbtgt,
1425 krb5_enctype krbtgt_etype,
1426 krb5_ticket *ticket,
1427 AuthorizationData **auth_data,
1428 const struct sockaddr *from_addr)
1430 krb5_context context = priv->context;
1431 krb5_kdc_configuration *config = priv->config;
1432 KDC_REQ *req = &priv->req;
1433 KDC_REQ_BODY *b = &priv->req.req_body;
1434 const char *from = priv->from;
1435 krb5_error_code ret, ret2;
1436 krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1437 krb5_principal krbtgt_out_principal = NULL;
1438 krb5_principal user2user_princ = NULL;
1439 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1440 char *user2user_name = NULL;
1441 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1442 hdb_entry_ex *user2user_krbtgt = NULL;
1443 HDB *clientdb, *s4u2self_impersonated_clientdb;
1444 HDB *serverdb = NULL;
1445 krb5_realm ref_realm = NULL;
1446 EncTicketPart *tgt = &ticket->ticket;
1447 const EncryptionKey *ekey;
1448 krb5_keyblock sessionkey;
1450 krb5_pac user2user_pac = NULL;
1452 krb5_boolean add_ticket_sig = FALSE;
1453 const char *tgt_realm = /* Realm of TGT issuer */
1454 krb5_principal_get_realm(context, krbtgt->entry.principal);
1455 const char *our_realm = /* Realm of this KDC */
1456 krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1457 char **capath = NULL;
1458 size_t num_capath = 0;
1460 hdb_entry_ex *krbtgt_out = NULL;
1464 EncTicketPart adtkt;
1466 krb5_boolean kdc_issued = FALSE;
1469 int flags = HDB_F_FOR_TGS_REQ;
1473 memset(&sessionkey, 0, sizeof(sessionkey));
1474 memset(&adtkt, 0, sizeof(adtkt));
1480 * The canonicalize KDC option is passed as a hint to the backend, but
1481 * can typically be ignored. Per RFC 6806, names are not canonicalized
1482 * in response to a TGS request (although we make an exception, see
1483 * force-canonicalize below).
1485 if (b->kdc_options.canonicalize)
1486 flags |= HDB_F_CANON;
1489 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1490 _kdc_set_const_e_text(priv, "No server in request");
1494 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1495 ret = krb5_unparse_name(context, sp, &priv->sname);
1499 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1500 ret = krb5_unparse_name(context, cp, &priv->cname);
1504 result = unparse_flags(KDCOptions2int(b->kdc_options),
1505 asn1_KDCOptions_units(),
1506 opt_str, sizeof(opt_str));
1508 kdc_log(context, config, 4,
1509 "TGS-REQ %s from %s for %s [%s]",
1510 cpn, from, spn, opt_str);
1512 kdc_log(context, config, 4,
1513 "TGS-REQ %s from %s for %s", cpn, from, spn);
1520 priv->server = NULL;
1522 _kdc_free_ent(context, server);
1524 ret = _kdc_db_fetch(context, config, sp,
1525 HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags,
1526 NULL, &serverdb, &server);
1527 priv->server = server;
1528 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1529 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn);
1530 _kdc_audit_addreason((kdc_request_t)priv, "Target not found here");
1532 } else if (ret == HDB_ERR_WRONG_REALM) {
1534 ref_realm = strdup(server->entry.principal->realm);
1535 if (ref_realm == NULL) {
1536 ret = krb5_enomem(context);
1540 kdc_log(context, config, 4,
1541 "Returning a referral to realm %s for "
1544 krb5_free_principal(context, sp);
1546 ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1552 ret = krb5_unparse_name(context, sp, &priv->sname);
1559 const char *new_rlm, *msg;
1563 if (!config->autodetect_referrals) {
1565 } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1566 if (capath == NULL) {
1567 /* With referalls, hierarchical capaths are always enabled */
1568 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1569 req_rlm, TRUE, &capath, &num_capath);
1572 _kdc_audit_addreason((kdc_request_t)priv,
1573 "No trusted path from client realm to ours");
1577 new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1579 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1580 "realm %s not found, trying %s", tgt->crealm,
1581 our_realm, req_rlm, new_rlm);
1584 ref_realm = strdup(new_rlm);
1585 if (ref_realm == NULL) {
1586 ret = krb5_enomem(context);
1590 krb5_free_principal(context, sp);
1592 krb5_make_principal(context, &sp, r,
1593 KRB5_TGS_NAME, ref_realm, NULL);
1596 ret = krb5_unparse_name(context, sp, &priv->sname);
1602 } else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
1603 if (strcmp(realms[0], sp->realm) != 0) {
1604 kdc_log(context, config, 4,
1605 "Returning a referral to realm %s for "
1606 "server %s that was not found",
1608 krb5_free_principal(context, sp);
1610 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1614 ret = krb5_unparse_name(context, sp, &priv->sname);
1616 krb5_free_host_realm(context, realms);
1622 ref_realm = strdup(realms[0]);
1624 krb5_free_host_realm(context, realms);
1627 krb5_free_host_realm(context, realms);
1629 msg = krb5_get_error_message(context, ret);
1630 kdc_log(context, config, 3,
1631 "Server not found in database: %s: %s", spn, msg);
1632 krb5_free_error_message(context, msg);
1633 if (ret == HDB_ERR_NOENTRY)
1634 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1635 _kdc_audit_addreason((kdc_request_t)priv,
1636 "Service principal unknown");
1641 * RFC 6806 notes that names MUST NOT be changed in the response to
1642 * a TGS request. Hence we ignore the setting of the canonicalize
1643 * KDC option. However, for legacy interoperability we do allow the
1644 * backend to override this by setting the force-canonicalize HDB
1645 * flag in the server entry.
1647 if (server->entry.flags.force_canonicalize)
1648 rsp = server->entry.principal;
1653 * Now refetch the primary krbtgt, and get the current kvno (the
1654 * sign check may have been on an old kvno, and the server may
1655 * have been an incoming trust)
1658 ret = krb5_make_principal(context,
1659 &krbtgt_out_principal,
1665 kdc_log(context, config, 4,
1666 "Failed to make krbtgt principal name object for "
1667 "authz-data signatures");
1670 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1672 kdc_log(context, config, 4,
1673 "Failed to make krbtgt principal name object for "
1674 "authz-data signatures");
1678 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1679 HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1682 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1683 kdc_log(context, config, 4,
1684 "No such principal %s (needed for authz-data signature keys) "
1685 "while processing TGS-REQ for service %s with krbtg %s",
1686 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1688 ret = KRB5KRB_AP_ERR_NOT_US;
1693 * Select enctype, return key and kvno.
1699 if(b->kdc_options.enc_tkt_in_skey) {
1703 krb5uint32 second_kvno = 0;
1704 krb5uint32 *kvno_ptr = NULL;
1706 hdb_entry_ex *user2user_client = NULL;
1707 krb5_boolean user2user_kdc_issued = FALSE;
1709 if(b->additional_tickets == NULL ||
1710 b->additional_tickets->len == 0){
1711 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1712 kdc_log(context, config, 4,
1713 "No second ticket present in user-to-user request");
1714 _kdc_audit_addreason((kdc_request_t)priv,
1715 "No second ticket present in user-to-user request");
1718 t = &b->additional_tickets->val[0];
1719 if(!get_krbtgt_realm(&t->sname)){
1720 kdc_log(context, config, 4,
1721 "Additional ticket is not a ticket-granting ticket");
1722 _kdc_audit_addreason((kdc_request_t)priv,
1723 "Additional ticket is not a ticket-granting ticket");
1724 ret = KRB5KDC_ERR_POLICY;
1727 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1731 ret = krb5_unparse_name(context, p, &tpn);
1734 if(t->enc_part.kvno){
1735 second_kvno = *t->enc_part.kvno;
1736 kvno_ptr = &second_kvno;
1738 ret = _kdc_db_fetch(context, config, p,
1739 HDB_F_GET_KRBTGT, kvno_ptr,
1740 NULL, &user2user_krbtgt);
1741 krb5_free_principal(context, p);
1743 if (ret == HDB_ERR_NOENTRY)
1744 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1745 _kdc_audit_addreason((kdc_request_t)priv,
1746 "User-to-user service principal (TGS) unknown");
1749 ret = hdb_enctype2key(context, &user2user_krbtgt->entry, NULL,
1750 t->enc_part.etype, &uukey);
1752 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1753 _kdc_audit_addreason((kdc_request_t)priv,
1754 "User-to-user enctype not supported");
1757 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1759 _kdc_audit_addreason((kdc_request_t)priv,
1760 "User-to-user TGT decrypt failure");
1764 ret = _kdc_verify_flags(context, config, &adtkt, tpn);
1766 _kdc_audit_addreason((kdc_request_t)priv,
1767 "User-to-user TGT expired or invalid");
1771 /* Fetch the name from the TGT. */
1772 ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1773 adtkt.cname, adtkt.crealm);
1777 ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1782 * Look up the name given in the TGT in the database. The user
1783 * claims to have a ticket-granting-ticket to our KDC, so we should
1784 * fail hard if we can't find the user - otherwise we can't do
1787 ret = _kdc_db_fetch(context, config, user2user_princ,
1788 HDB_F_GET_CLIENT | flags,
1789 NULL, NULL, &user2user_client);
1790 if (ret == HDB_ERR_NOENTRY)
1791 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1796 * The account is present in the database, now check the
1799 * We check this as a client (because the purpose of
1800 * user2user is that the server flag is not set, because
1801 * the long-term key is not strong, but this does mean
1802 * that a client with an expired password can't get accept
1803 * a user2user ticket.
1805 ret = kdc_check_flags(priv,
1810 _kdc_free_ent(context, user2user_client);
1815 * Also check that the account is the same one specified in the
1818 ret = check_client_matches_target_service(context,
1825 _kdc_free_ent(context, user2user_client);
1829 /* Verify the PAC of the TGT. */
1830 ret = _kdc_check_pac(context, config, user2user_princ, NULL,
1831 user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
1832 &uukey->key, &priv->ticket_key->key, &adtkt,
1833 &user2user_kdc_issued, &user2user_pac, NULL, NULL);
1834 _kdc_free_ent(context, user2user_client);
1836 const char *msg = krb5_get_error_message(context, ret);
1837 kdc_log(context, config, 0,
1838 "Verify PAC failed for %s (%s) from %s with %s",
1839 spn, user2user_name, from, msg);
1840 krb5_free_error_message(context, msg);
1844 if ((config->require_pac && !user2user_pac)
1845 || (user2user_pac && !user2user_kdc_issued))
1847 ret = KRB5KDC_ERR_BADOPTION;
1848 kdc_log(context, config, 0,
1849 "Ticket not signed with PAC; user-to-user failed (%s).",
1850 user2user_pac ? "Ticket unsigned" : "No PAC");
1855 for(i = 0; i < b->etype.len; i++)
1856 if (b->etype.val[i] == adtkt.key.keytype)
1858 if(i == b->etype.len) {
1859 kdc_log(context, config, 4,
1860 "Addition ticket have not matching etypes");
1861 krb5_clear_error_message(context);
1862 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1863 _kdc_audit_addreason((kdc_request_t)priv,
1864 "No matching enctypes for 2nd ticket");
1867 etype = b->etype.val[i];
1872 ret = _kdc_find_etype(priv, krb5_principal_is_krbtgt(context, sp)
1874 b->etype.val, b->etype.len, &etype, NULL,
1877 kdc_log(context, config, 4,
1878 "Server (%s) has no support for etypes", spn);
1879 _kdc_audit_addreason((kdc_request_t)priv,
1880 "Enctype not supported");
1883 ret = _kdc_get_preferred_key(context, config, server, spn,
1886 kdc_log(context, config, 4,
1887 "Server (%s) has no supported etypes", spn);
1888 _kdc_audit_addreason((kdc_request_t)priv,
1889 "Enctype not supported");
1893 kvno = server->entry.kvno;
1896 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1902 * Check that service is in the same realm as the krbtgt. If it's
1903 * not the same, it's someone that is using a uni-directional trust
1908 * The first realm is the realm of the service, the second is
1909 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1910 * encrypted to. The redirection via the krbtgt_out entry allows
1911 * the DB to possibly correct the case of the realm (Samba4 does
1912 * this) before the strcmp()
1914 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1915 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1917 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1918 kdc_log(context, config, 4,
1919 "Request with wrong krbtgt: %s",
1920 (ret == 0) ? ktpn : "<unknown>");
1923 ret = KRB5KRB_AP_ERR_NOT_US;
1924 _kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT");
1928 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1931 kdc_log(context, config, 4,
1932 "Failed to find key for krbtgt PAC signature");
1933 _kdc_audit_addreason((kdc_request_t)priv,
1934 "Failed to find key for krbtgt PAC signature");
1937 ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1938 tkey_sign->key.keytype, &tkey_sign);
1940 kdc_log(context, config, 4,
1941 "Failed to find key for krbtgt PAC signature");
1942 _kdc_audit_addreason((kdc_request_t)priv,
1943 "Failed to find key for krbtgt PAC signature");
1947 if (_kdc_synthetic_princ_used_p(context, ticket))
1948 flags |= HDB_F_SYNTHETIC_OK;
1950 ret = _kdc_db_fetch_client(context, config, flags, cp, cpn, our_realm,
1951 &clientdb, &client);
1954 flags &= ~HDB_F_SYNTHETIC_OK;
1955 priv->client = client;
1957 heim_assert(priv->client_princ == NULL, "client_princ should be NULL for TGS");
1959 ret = _kdc_check_pac(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1960 &priv->ticket_key->key, &priv->ticket_key->key, tgt,
1961 &kdc_issued, &priv->pac, &priv->client_princ, &priv->pac_attributes);
1963 const char *msg = krb5_get_error_message(context, ret);
1964 _kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
1965 kdc_log(context, config, 4,
1966 "Verify PAC failed for %s (%s) from %s with %s",
1967 spn, cpn, from, msg);
1968 krb5_free_error_message(context, msg);
1976 /* by default the tgt principal matches the client principal */
1981 const PA_DATA *sdata;
1984 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1991 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1992 sdata->padata_value.length,
1995 _kdc_audit_addreason((kdc_request_t)priv,
1996 "Failed to decode PA-S4U2Self");
1997 kdc_log(context, config, 4, "Failed to decode PA-S4U2Self");
2001 if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
2002 free_PA_S4U2Self(&self);
2003 _kdc_audit_addreason((kdc_request_t)priv,
2004 "PA-S4U2Self with unkeyed checksum");
2005 kdc_log(context, config, 4, "Reject PA-S4U2Self with unkeyed checksum");
2006 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
2010 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
2014 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
2016 const char *msg = krb5_get_error_message(context, ret);
2017 free_PA_S4U2Self(&self);
2018 krb5_data_free(&datack);
2019 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
2020 krb5_free_error_message(context, msg);
2024 /* Allow HMAC_MD5 checksum with any key type */
2025 if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
2026 struct krb5_crypto_iov iov;
2027 unsigned char csdata[16];
2030 cs.checksum.length = sizeof(csdata);
2031 cs.checksum.data = &csdata;
2033 iov.data.data = datack.data;
2034 iov.data.length = datack.length;
2035 iov.flags = KRB5_CRYPTO_TYPE_DATA;
2037 ret = _krb5_HMAC_MD5_checksum(context, NULL, &crypto->key,
2038 KRB5_KU_OTHER_CKSUM, &iov, 1,
2041 krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
2042 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2045 ret = _kdc_verify_checksum(context,
2047 KRB5_KU_OTHER_CKSUM,
2051 krb5_data_free(&datack);
2052 krb5_crypto_destroy(context, crypto);
2054 const char *msg = krb5_get_error_message(context, ret);
2055 free_PA_S4U2Self(&self);
2056 _kdc_audit_addreason((kdc_request_t)priv,
2057 "S4U2Self checksum failed");
2058 kdc_log(context, config, 4,
2059 "krb5_verify_checksum failed for S4U2Self: %s", msg);
2060 krb5_free_error_message(context, msg);
2064 ret = _krb5_principalname2krb5_principal(context,
2068 free_PA_S4U2Self(&self);
2072 ret = krb5_unparse_name(context, tp, &tpn);
2077 * Note no HDB_F_SYNTHETIC_OK -- impersonating non-existent clients
2078 * is probably not desirable!
2080 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2081 NULL, &s4u2self_impersonated_clientdb,
2082 &s4u2self_impersonated_client);
2087 * If the client belongs to the same realm as our krbtgt, it
2088 * should exist in the local database.
2092 if (ret == HDB_ERR_NOENTRY)
2093 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2094 msg = krb5_get_error_message(context, ret);
2095 _kdc_audit_addreason((kdc_request_t)priv,
2096 "S4U2Self principal to impersonate not found");
2097 kdc_log(context, config, 2,
2098 "S4U2Self principal to impersonate %s not found in database: %s",
2100 krb5_free_error_message(context, msg);
2104 /* Ignore require_pwchange and pw_end attributes (as Windows does),
2105 * since S4U2Self is not password authentication. */
2106 s4u2self_impersonated_client->entry.flags.require_pwchange = FALSE;
2107 free(s4u2self_impersonated_client->entry.pw_end);
2108 s4u2self_impersonated_client->entry.pw_end = NULL;
2110 ret = kdc_check_flags(priv, FALSE, s4u2self_impersonated_client, priv->server);
2112 goto out; /* kdc_check_flags() calls _kdc_audit_addreason() */
2114 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2115 krb5_pac_free(context, priv->pac);
2118 ret = _kdc_pac_generate(context,
2119 s4u2self_impersonated_client,
2122 KRB5_PAC_WAS_GIVEN_IMPLICITLY,
2125 kdc_log(context, config, 4, "PAC generation failed for -- %s", tpn);
2130 * Check that service doing the impersonating is
2131 * requesting a ticket to it-self.
2133 ret = check_client_matches_target_service(context,
2140 kdc_log(context, config, 4, "S4U2Self: %s is not allowed "
2141 "to impersonate to service "
2142 "(tried for user %s to service %s)",
2148 * If the service isn't trusted for authentication to
2149 * delegation or if the impersonate client is disallowed
2150 * forwardable, remove the forwardable flag.
2153 if (client->entry.flags.trusted_for_delegation &&
2154 s4u2self_impersonated_client->entry.flags.forwardable) {
2155 str = "[forwardable]";
2157 b->kdc_options.forwardable = 0;
2160 kdc_log(context, config, 4, "s4u2self %s impersonating %s to "
2161 "service %s %s", cpn, tpn, spn, str);
2166 * Constrained delegation
2170 && b->additional_tickets != NULL
2171 && b->additional_tickets->len != 0
2172 && b->kdc_options.cname_in_addl_tkt
2173 && b->kdc_options.enc_tkt_in_skey == 0)
2175 hdb_entry_ex *adclient = NULL;
2176 krb5_boolean ad_kdc_issued = FALSE;
2181 * We require that the service's krbtgt has a PAC.
2183 if (priv->pac == NULL) {
2184 ret = KRB5KDC_ERR_BADOPTION;
2185 _kdc_audit_addreason((kdc_request_t)priv, "Missing PAC");
2186 kdc_log(context, config, 4,
2187 "Constrained delegation without PAC, %s/%s",
2192 krb5_pac_free(context, priv->pac);
2195 krb5_free_principal(context, priv->client_princ);
2196 priv->client_princ = NULL;
2198 t = &b->additional_tickets->val[0];
2200 ret = hdb_enctype2key(context, &client->entry,
2201 hdb_kvno2keys(context, &client->entry,
2202 t->enc_part.kvno ? * t->enc_part.kvno : 0),
2203 t->enc_part.etype, &clientkey);
2205 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2209 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2211 _kdc_audit_addreason((kdc_request_t)priv,
2212 "Failed to decrypt constrained delegation ticket");
2213 kdc_log(context, config, 4,
2214 "failed to decrypt ticket for "
2215 "constrained delegation from %s to %s ", cpn, spn);
2219 ret = _krb5_principalname2krb5_principal(context,
2226 ret = krb5_unparse_name(context, tp, &tpn);
2230 _kdc_audit_addkv((kdc_request_t)priv, 0, "impersonatee", "%s", tpn);
2232 ret = _krb5_principalname2krb5_principal(context,
2239 ret = krb5_unparse_name(context, dp, &dpn);
2243 /* check that ticket is valid */
2244 if (adtkt.flags.forwardable == 0) {
2245 _kdc_audit_addreason((kdc_request_t)priv,
2246 "Missing forwardable flag on ticket for constrained delegation");
2247 kdc_log(context, config, 4,
2248 "Missing forwardable flag on ticket for "
2249 "constrained delegation from %s (%s) as %s to %s ",
2250 cpn, dpn, tpn, spn);
2251 ret = KRB5KDC_ERR_BADOPTION;
2255 ret = check_constrained_delegation(context, config, clientdb,
2256 client, server, sp);
2258 _kdc_audit_addreason((kdc_request_t)priv,
2259 "Constrained delegation not allowed");
2260 kdc_log(context, config, 4,
2261 "constrained delegation from %s (%s) as %s to %s not allowed",
2262 cpn, dpn, tpn, spn);
2266 ret = _kdc_verify_flags(context, config, &adtkt, tpn);
2268 _kdc_audit_addreason((kdc_request_t)priv,
2269 "Constrained delegation ticket expired or invalid");
2273 /* Try lookup the delegated client in DB */
2274 ret = _kdc_db_fetch_client(context, config, flags, tp, tpn, our_realm,
2279 if (adclient != NULL) {
2280 ret = kdc_check_flags(priv, FALSE, adclient, priv->server);
2282 _kdc_free_ent(context, adclient);
2288 * TODO: pass in t->sname and t->realm and build
2289 * a S4U_DELEGATION_INFO blob to the PAC.
2291 ret = _kdc_check_pac(context, config, tp, dp, adclient, server, krbtgt, client,
2292 &clientkey->key, &priv->ticket_key->key, &adtkt,
2293 &ad_kdc_issued, &priv->pac, &priv->client_princ, &priv->pac_attributes);
2295 _kdc_free_ent(context, adclient);
2297 const char *msg = krb5_get_error_message(context, ret);
2298 _kdc_audit_addreason((kdc_request_t)priv,
2299 "Constrained delegation ticket PAC check failed");
2300 kdc_log(context, config, 4,
2301 "Verify delegated PAC failed to %s for client"
2302 "%s (%s) as %s from %s with %s",
2303 spn, cpn, dpn, tpn, from, msg);
2304 krb5_free_error_message(context, msg);
2308 if (priv->pac == NULL || !ad_kdc_issued) {
2309 ret = KRB5KDC_ERR_BADOPTION;
2310 kdc_log(context, config, 4,
2311 "Ticket not signed with PAC; service %s failed for "
2312 "for delegation to %s for client %s (%s) from %s; (%s).",
2313 spn, tpn, dpn, cpn, from, priv->pac ? "Ticket unsigned" : "No PAC");
2314 _kdc_audit_addreason((kdc_request_t)priv,
2315 "Constrained delegation ticket not signed");
2319 kdc_log(context, config, 4, "constrained delegation for %s "
2320 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2327 ret = kdc_check_flags(priv, FALSE, priv->client, priv->server);
2331 if((b->kdc_options.validate || b->kdc_options.renew) &&
2332 !krb5_principal_compare(context,
2333 krbtgt->entry.principal,
2334 server->entry.principal)){
2335 _kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request");
2336 kdc_log(context, config, 4, "Inconsistent request.");
2337 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2341 /* check for valid set of addresses */
2342 if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) {
2343 if (config->check_ticket_addresses) {
2344 ret = KRB5KRB_AP_ERR_BADADDR;
2345 _kdc_audit_addkv((kdc_request_t)priv, 0, "wrongaddr", "yes");
2346 kdc_log(context, config, 4, "Request from wrong address");
2347 _kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address");
2349 } else if (config->warn_ticket_addresses) {
2350 _kdc_audit_addkv((kdc_request_t)priv, 0, "wrongaddr", "yes");
2354 /* check local and per-principal anonymous ticket issuance policy */
2355 if (is_anon_tgs_request_p(b, tgt)) {
2356 ret = _kdc_check_anon_policy(priv);
2362 * If this is an referral, add server referral data to the
2369 kdc_log(context, config, 3,
2370 "Adding server referral to %s", ref_realm);
2372 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2376 ret = build_server_referral(context, config, crypto, ref_realm,
2377 NULL, s, &pa.padata_value);
2378 krb5_crypto_destroy(context, crypto);
2380 _kdc_audit_addreason((kdc_request_t)priv, "Referral build failed");
2381 kdc_log(context, config, 4,
2382 "Failed building server referral");
2385 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2387 ret = add_METHOD_DATA(priv->rep.padata, &pa);
2388 krb5_data_free(&pa.padata_value);
2390 kdc_log(context, config, 4,
2391 "Add server referral METHOD-DATA failed");
2397 * Only add ticket signature if the requested server is not krbtgt, and
2398 * either the header server is krbtgt or, in the case of renewal/validation
2399 * if it was signed with PAC ticket signature and we verified it.
2400 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2401 * change one day (see issue #763) so make sure to check for it.
2405 !krb5_principal_is_krbtgt(context, server->entry.principal)) {
2407 /* Validate armor TGT before potentially including device claims */
2408 if (priv->armor_ticket) {
2409 ret = _kdc_fast_check_armor_pac(priv);
2414 add_ticket_sig = TRUE;
2418 * Active-Directory implementations use the high part of the kvno as the
2419 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2422 rodc_id = krbtgt_out->entry.kvno >> 16;
2428 ret = tgs_make_reply(priv,
2445 free(user2user_name);
2450 _krb5_free_capath(context, capath);
2452 krb5_free_keyblock_contents(context, &sessionkey);
2454 _kdc_free_ent(context, krbtgt_out);
2456 _kdc_free_ent(context, server);
2458 _kdc_free_ent(context, client);
2459 if(s4u2self_impersonated_client)
2460 _kdc_free_ent(context, s4u2self_impersonated_client);
2461 if(user2user_krbtgt)
2462 _kdc_free_ent(context, user2user_krbtgt);
2464 krb5_free_principal(context, user2user_princ);
2466 krb5_free_principal(context, tp);
2467 krb5_free_principal(context, cp);
2468 krb5_free_principal(context, dp);
2469 krb5_free_principal(context, sp);
2470 krb5_free_principal(context, krbtgt_out_principal);
2473 free_EncTicketPart(&adtkt);
2475 krb5_pac_free(context, user2user_pac);
2485 _kdc_tgs_rep(astgs_request_t r)
2487 krb5_kdc_configuration *config = r->config;
2488 KDC_REQ *req = &r->req;
2489 krb5_data *data = r->reply;
2490 const char *from = r->from;
2491 struct sockaddr *from_addr = r->addr;
2492 int datagram_reply = r->datagram_reply;
2493 AuthorizationData *auth_data = NULL;
2494 krb5_error_code ret;
2496 const PA_DATA *tgs_req, *pa;
2498 hdb_entry_ex *krbtgt = NULL;
2499 krb5_ticket *ticket = NULL;
2500 krb5_enctype krbtgt_etype = ETYPE_NULL;
2502 time_t *csec = NULL;
2507 if(req->padata == NULL){
2508 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2509 kdc_log(r->context, config, 4,
2510 "TGS-REQ from %s without PA-DATA", from);
2515 pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
2517 kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2518 ret = KRB5KRB_ERR_GENERIC;
2523 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2524 if(tgs_req == NULL){
2525 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2527 kdc_log(r->context, config, 4,
2528 "TGS-REQ from %s without PA-TGS-REQ", from);
2531 ret = tgs_parse_request(r, tgs_req,
2538 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2539 /* kdc_log() is called in tgs_parse_request() */
2543 kdc_log(r->context, config, 4,
2544 "Failed parsing TGS-REQ from %s", from);
2548 ret = _kdc_fast_strengthen_reply_key(r);
2552 ALLOC(r->rep.padata);
2553 if (r->rep.padata == NULL) {
2555 krb5_set_error_message(r->context, ret, N_("malloc: out of memory", ""));
2559 ret = tgs_build_reply(r,
2566 kdc_log(r->context, config, 4,
2567 "Failed building TGS-REP to %s", from);
2572 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2573 krb5_data_free(data);
2574 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2575 _kdc_set_const_e_text(r, "Reply packet too large");
2579 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2580 METHOD_DATA error_method = { 0, NULL };
2582 kdc_log(r->context, config, 5, "tgs-req: sending error: %d to client", ret);
2583 ret = _kdc_fast_mk_error(r,
2588 ticket != NULL ? ticket->client : NULL,
2589 ticket != NULL ? ticket->server : NULL,
2592 free_METHOD_DATA(&error_method);
2597 free_TGS_REP(&r->rep);
2598 free_TransitedEncoding(&r->et.transited);
2599 free(r->et.starttime);
2600 free(r->et.renew_till);
2601 if(r->et.authorization_data) {
2602 free_AuthorizationData(r->et.authorization_data);
2603 free(r->et.authorization_data);
2605 free_LastReq(&r->ek.last_req);
2606 if (r->et.key.keyvalue.data) {
2607 memset_s(r->et.key.keyvalue.data, 0, r->et.key.keyvalue.length,
2608 r->et.key.keyvalue.length);
2610 free_EncryptionKey(&r->et.key);
2612 if (r->client_princ) {
2613 krb5_free_principal(r->context, r->client_princ);
2614 r->client_princ = NULL;
2616 if (r->armor_crypto) {
2617 krb5_crypto_destroy(r->context, r->armor_crypto);
2618 r->armor_crypto = NULL;
2620 if (r->armor_ticket)
2621 krb5_free_ticket(r->context, r->armor_ticket);
2622 if (r->armor_server)
2623 _kdc_free_ent(r->context, r->armor_server);
2624 krb5_free_keyblock_contents(r->context, &r->reply_key);
2625 krb5_free_keyblock_contents(r->context, &r->strengthen_key);
2628 krb5_free_ticket(r->context, ticket);
2630 _kdc_free_ent(r->context, krbtgt);
2632 _kdc_free_fast_state(&r->fast);
2633 krb5_pac_free(r->context, r->pac);
2636 free_AuthorizationData(auth_data);