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(astgs_request_t r,
80 const krb5_principal client_principal,
81 const krb5_principal delegated_proxy_principal,
85 hdb_entry *ticket_server,
86 const EncryptionKey *server_check_key,
87 const EncryptionKey *krbtgt_check_key,
89 krb5_boolean *kdc_issued,
91 krb5_principal *pac_canon_name,
92 uint64_t *pac_attributes)
94 krb5_context context = r->context;
95 krb5_kdc_configuration *config = r->config;
98 krb5_boolean signedticket;
103 *pac_canon_name = NULL;
105 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
107 ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
112 if (config->require_pac)
113 ret = KRB5KDC_ERR_TGT_REVOKED;
117 /* Verify the server signature. */
118 ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
119 server_check_key, NULL);
121 krb5_pac_free(context, pac);
125 if (pac_canon_name) {
126 ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
127 if (ret && ret != ENOENT) {
128 krb5_pac_free(context, pac);
132 if (pac_attributes) {
133 ret = _krb5_pac_get_attributes_info(context, pac, pac_attributes);
134 if (ret && ret != ENOENT) {
135 krb5_pac_free(context, pac);
139 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
142 /* Verify the KDC signatures. */
143 ret = _kdc_pac_verify(r,
144 client_principal, delegated_proxy_principal,
145 client, server, krbtgt, &pac);
148 /* the plugin may indicate no PAC should be generated */
151 } else if (ret == KRB5_PLUGIN_NO_HANDLE) {
153 * We can't verify the KDC signatures if the ticket was issued by
154 * another realm's KDC.
156 if (krb5_realm_compare(context, server->principal,
157 ticket_server->principal)) {
158 ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
161 krb5_pac_free(context, pac);
166 /* Discard the PAC if the plugin didn't handle it */
167 krb5_pac_free(context, pac);
168 ret = krb5_pac_init(context, &pac);
172 krb5_pac_free(context, pac);
176 *kdc_issued = signedticket ||
177 krb5_principal_is_krbtgt(context,
178 ticket_server->principal);
185 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
186 const EncTicketPart *tgt)
188 KDCOptions f = b->kdc_options;
191 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
192 * request-anonymous and cname-in-addl-tkt flags for constrained
193 * delegation requests. A true anonymous TGS request will only
194 * have the request-anonymous flag set. (A corollary of this is
195 * that it is not possible to support anonymous constrained
196 * delegation requests, although they would be of limited utility.)
198 return tgt->flags.anonymous ||
199 (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
206 static krb5_error_code
207 check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b,
208 krb5_const_principal tgt_name,
209 const EncTicketPart *tgt, EncTicketPart *et)
211 KDCOptions f = b->kdc_options;
214 if (!tgt->flags.invalid || tgt->starttime == NULL) {
215 kdc_audit_addreason((kdc_request_t)r,
216 "Bad request to validate ticket");
217 return KRB5KDC_ERR_BADOPTION;
219 if(*tgt->starttime > kdc_time){
220 kdc_audit_addreason((kdc_request_t)r,
221 "Early request to validate ticket");
222 return KRB5KRB_AP_ERR_TKT_NYV;
225 et->flags.invalid = 0;
226 } else if (tgt->flags.invalid) {
227 kdc_audit_addreason((kdc_request_t)r,
228 "Ticket-granting ticket has INVALID flag set");
229 return KRB5KRB_AP_ERR_TKT_INVALID;
233 if (!tgt->flags.forwardable) {
234 kdc_audit_addreason((kdc_request_t)r,
235 "Bad request for forwardable ticket");
236 return KRB5KDC_ERR_BADOPTION;
238 et->flags.forwardable = 1;
241 if (!tgt->flags.forwardable) {
242 kdc_audit_addreason((kdc_request_t)r,
243 "Request to forward non-forwardable ticket");
244 return KRB5KDC_ERR_BADOPTION;
246 et->flags.forwarded = 1;
247 et->caddr = b->addresses;
249 if(tgt->flags.forwarded)
250 et->flags.forwarded = 1;
253 if (!tgt->flags.proxiable) {
254 kdc_audit_addreason((kdc_request_t)r,
255 "Bad request for proxiable ticket");
256 return KRB5KDC_ERR_BADOPTION;
258 et->flags.proxiable = 1;
261 if (!tgt->flags.proxiable) {
262 kdc_audit_addreason((kdc_request_t)r,
263 "Request to proxy non-proxiable ticket");
264 return KRB5KDC_ERR_BADOPTION;
267 et->caddr = b->addresses;
272 if(f.allow_postdate){
273 if (!tgt->flags.may_postdate) {
274 kdc_audit_addreason((kdc_request_t)r,
275 "Bad request for post-datable ticket");
276 return KRB5KDC_ERR_BADOPTION;
278 et->flags.may_postdate = 1;
281 if (!tgt->flags.may_postdate) {
282 kdc_audit_addreason((kdc_request_t)r,
283 "Bad request for postdated ticket");
284 return KRB5KDC_ERR_BADOPTION;
287 *et->starttime = *b->from;
288 et->flags.postdated = 1;
289 et->flags.invalid = 1;
290 } else if (b->from && *b->from > kdc_time + r->context->max_skew) {
291 kdc_audit_addreason((kdc_request_t)r,
292 "Ticket cannot be postdated");
293 return KRB5KDC_ERR_CANNOT_POSTDATE;
297 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
298 kdc_audit_addreason((kdc_request_t)r,
299 "Bad request for renewable ticket");
300 return KRB5KDC_ERR_BADOPTION;
302 et->flags.renewable = 1;
303 ALLOC(et->renew_till);
304 _kdc_fix_time(&b->rtime);
305 *et->renew_till = *b->rtime;
309 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
310 kdc_audit_addreason((kdc_request_t)r,
311 "Request to renew non-renewable ticket");
312 return KRB5KDC_ERR_BADOPTION;
314 old_life = tgt->endtime;
316 old_life -= *tgt->starttime;
318 old_life -= tgt->authtime;
319 et->endtime = *et->starttime + old_life;
320 if (et->renew_till != NULL)
321 et->endtime = min(*et->renew_till, et->endtime);
325 * RFC 8062 section 3 defines an anonymous ticket as one containing
326 * the anonymous principal and the anonymous ticket flag.
328 if (tgt->flags.anonymous &&
329 !_kdc_is_anonymous(r->context, tgt_name)) {
330 kdc_audit_addreason((kdc_request_t)r,
331 "Anonymous ticket flag set without "
332 "anonymous principal");
333 return KRB5KDC_ERR_BADOPTION;
337 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
338 * anonymous KDC option SHOULD be set, but it is not required.
339 * Treat an anonymous TGT as if the anonymous flag was set.
341 if (is_anon_tgs_request_p(b, tgt))
342 et->flags.anonymous = 1;
348 * Determine if s4u2self is allowed from this client to this server
352 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
353 * service given by the client.
355 * For example, regardless of the principal being impersonated, if the
356 * 'client' and 'server' (target) are the same, or server is an SPN
357 * alias of client, then it's safe.
361 _kdc_check_client_matches_target_service(krb5_context context,
362 krb5_kdc_configuration *config,
365 hdb_entry *target_server,
366 krb5_const_principal target_server_principal)
371 * Always allow the plugin to check, this might be faster, allow a
372 * policy or audit check and can look into the DB records
375 if (clientdb->hdb_check_client_matches_target_service) {
376 ret = clientdb->hdb_check_client_matches_target_service(context,
382 } else if (krb5_principal_compare(context,
384 target_server_principal) == TRUE) {
385 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
388 ret = KRB5KDC_ERR_BADOPTION;
398 _kdc_verify_flags(krb5_context context,
399 krb5_kdc_configuration *config,
400 const EncTicketPart *et,
403 if(et->endtime < kdc_time){
404 kdc_log(context, config, 4, "Ticket expired (%s)", pstr);
405 return KRB5KRB_AP_ERR_TKT_EXPIRED;
407 if(et->flags.invalid){
408 kdc_log(context, config, 4, "Ticket not valid (%s)", pstr);
409 return KRB5KRB_AP_ERR_TKT_NYV;
418 static krb5_error_code
419 fix_transited_encoding(krb5_context context,
420 krb5_kdc_configuration *config,
421 krb5_boolean check_policy,
422 const TransitedEncoding *tr,
424 const char *client_realm,
425 const char *server_realm,
426 const char *tgt_realm)
428 krb5_error_code ret = 0;
429 char **realms, **tmp;
430 unsigned int num_realms;
433 switch (tr->tr_type) {
434 case domain_X500_Compress:
438 * Allow empty content of type 0 because that is was Microsoft
439 * generates in their TGT.
441 if (tr->contents.length == 0)
443 kdc_log(context, config, 4,
444 "Transited type 0 with non empty content");
445 return KRB5KDC_ERR_TRTYPE_NOSUPP;
447 kdc_log(context, config, 4,
448 "Unknown transited type: %u", tr->tr_type);
449 return KRB5KDC_ERR_TRTYPE_NOSUPP;
452 ret = krb5_domain_x500_decode(context,
459 krb5_warn(context, ret,
460 "Decoding transited encoding");
465 * If the realm of the presented tgt is neither the client nor the server
466 * realm, it is a transit realm and must be added to transited set.
468 if (strcmp(client_realm, tgt_realm) != 0 &&
469 strcmp(server_realm, tgt_realm) != 0) {
470 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
474 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
480 realms[num_realms] = strdup(tgt_realm);
481 if(realms[num_realms] == NULL){
487 if(num_realms == 0) {
488 if (strcmp(client_realm, server_realm) != 0)
489 kdc_log(context, config, 4,
490 "cross-realm %s -> %s", client_realm, server_realm);
494 for(i = 0; i < num_realms; i++)
495 l += strlen(realms[i]) + 2;
499 for(i = 0; i < num_realms; i++) {
501 strlcat(rs, ", ", l);
502 strlcat(rs, realms[i], l);
504 kdc_log(context, config, 4,
505 "cross-realm %s -> %s via [%s]",
506 client_realm, server_realm, rs);
511 ret = krb5_check_transited(context, client_realm,
513 realms, num_realms, NULL);
515 krb5_warn(context, ret, "cross-realm %s -> %s",
516 client_realm, server_realm);
519 et->flags.transited_policy_checked = 1;
521 et->transited.tr_type = domain_X500_Compress;
522 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
524 krb5_warn(context, ret, "Encoding transited encoding");
526 for(i = 0; i < num_realms; i++)
533 static krb5_error_code
534 tgs_make_reply(astgs_request_t r,
535 const EncTicketPart *tgt,
536 const EncryptionKey *serverkey,
537 const EncryptionKey *krbtgtkey,
538 const krb5_keyblock *sessionkey,
540 AuthorizationData *auth_data,
541 const char *tgt_realm,
543 krb5_boolean add_ticket_sig)
545 KDC_REQ_BODY *b = &r->req.req_body;
546 krb5_data *reply = r->reply;
547 KDC_REP *rep = &r->rep;
548 EncTicketPart *et = &r->et;
549 EncKDCRepPart *ek = &r->ek;
550 KDCOptions f = b->kdc_options;
554 heim_assert(r->client_princ != NULL, "invalid client name passed to tgs_make_reply");
557 rep->msg_type = krb_tgs_rep;
559 et->authtime = tgt->authtime;
560 _kdc_fix_time(&b->till);
561 et->endtime = min(tgt->endtime, *b->till);
562 ALLOC(et->starttime);
563 *et->starttime = kdc_time;
565 ret = check_tgs_flags(r, b, r->client_princ, tgt, et);
569 /* We should check the transited encoding if:
570 1) the request doesn't ask not to be checked
571 2) globally enforcing a check
572 3) principal requires checking
573 4) we allow non-check per-principal, but principal isn't marked as allowing this
574 5) we don't globally allow this
577 #define GLOBAL_FORCE_TRANSITED_CHECK \
578 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
579 #define GLOBAL_ALLOW_PER_PRINCIPAL \
580 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
581 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
582 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
584 /* these will consult the database in future release */
585 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
586 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
588 ret = fix_transited_encoding(r->context, r->config,
589 !f.disable_transited_check ||
590 GLOBAL_FORCE_TRANSITED_CHECK ||
591 PRINCIPAL_FORCE_TRANSITED_CHECK(r->server) ||
592 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
593 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(r->server)) ||
594 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
596 krb5_principal_get_realm(r->context, r->client_princ),
597 krb5_principal_get_realm(r->context, r->server->principal),
602 * RFC 6806 notes that names MUST NOT be changed in the response to a
603 * TGS request. Hence we ignore the setting of the canonicalize KDC
604 * option. However, for legacy interoperability we do allow the backend
605 * to override this by setting the force-canonicalize HDB flag in the
608 krb5_const_principal rsp;
610 if (r->server->flags.force_canonicalize)
611 rsp = r->server->principal;
613 rsp = r->server_princ;
615 ret = copy_Realm(&rsp->realm, &rep->ticket.realm);
617 ret = _krb5_principal2principalname(&rep->ticket.sname, rsp);
621 ret = copy_Realm(&r->client_princ->realm, &rep->crealm);
626 * RFC 8062 states "if the ticket in the TGS request is an anonymous
627 * one, the client and client realm are copied from that ticket". So
628 * whilst the TGT flag check below is superfluous, it is included in
629 * order to follow the specification to its letter.
631 if (et->flags.anonymous && !tgt->flags.anonymous)
632 _kdc_make_anonymous_principalname(&rep->cname);
634 ret = copy_PrincipalName(&r->client_princ->name, &rep->cname);
637 rep->ticket.tkt_vno = 5;
639 ek->caddr = et->caddr;
643 life = et->endtime - *et->starttime;
644 if(r->client && r->client->max_life)
645 life = min(life, *r->client->max_life);
646 if(r->server->max_life)
647 life = min(life, *r->server->max_life);
648 et->endtime = *et->starttime + life;
650 if(f.renewable_ok && tgt->flags.renewable &&
651 et->renew_till == NULL && et->endtime < *b->till &&
652 tgt->renew_till != NULL)
654 et->flags.renewable = 1;
655 ALLOC(et->renew_till);
656 *et->renew_till = *b->till;
660 renew = *et->renew_till - *et->starttime;
661 if(r->client && r->client->max_renew)
662 renew = min(renew, *r->client->max_renew);
663 if(r->server->max_renew)
664 renew = min(renew, *r->server->max_renew);
665 *et->renew_till = *et->starttime + renew;
669 *et->renew_till = min(*et->renew_till, *tgt->renew_till);
670 *et->starttime = min(*et->starttime, *et->renew_till);
671 et->endtime = min(et->endtime, *et->renew_till);
674 *et->starttime = min(*et->starttime, et->endtime);
676 if(*et->starttime == et->endtime){
677 ret = KRB5KDC_ERR_NEVER_VALID;
680 if(et->renew_till && et->endtime == *et->renew_till){
681 free(et->renew_till);
682 et->renew_till = NULL;
683 et->flags.renewable = 0;
686 et->flags.pre_authent = tgt->flags.pre_authent;
687 et->flags.hw_authent = tgt->flags.hw_authent;
688 et->flags.ok_as_delegate = r->server->flags.ok_as_delegate;
690 /* See MS-KILE 3.3.5.1 */
691 if (!r->server->flags.forwardable)
692 et->flags.forwardable = 0;
693 if (!r->server->flags.proxiable)
694 et->flags.proxiable = 0;
699 /* XXX check authdata */
701 if (et->authorization_data == NULL) {
702 et->authorization_data = calloc(1, sizeof(*et->authorization_data));
703 if (et->authorization_data == NULL) {
705 krb5_set_error_message(r->context, ret, "malloc: out of memory");
709 for(i = 0; i < auth_data->len ; i++) {
710 ret = add_AuthorizationData(et->authorization_data, &auth_data->val[i]);
712 krb5_set_error_message(r->context, ret, "malloc: out of memory");
718 ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et->key);
721 et->crealm = rep->crealm;
722 et->cname = rep->cname;
725 /* MIT must have at least one last_req */
726 ek->last_req.val = calloc(1, sizeof(*ek->last_req.val));
727 if (ek->last_req.val == NULL) {
731 ek->last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
732 ek->nonce = b->nonce;
733 ek->flags = et->flags;
734 ek->authtime = et->authtime;
735 ek->starttime = et->starttime;
736 ek->endtime = et->endtime;
737 ek->renew_till = et->renew_till;
738 ek->srealm = rep->ticket.realm;
739 ek->sname = rep->ticket.sname;
741 _kdc_log_timestamp(r, "TGS-REQ", et->authtime, et->starttime,
742 et->endtime, et->renew_till);
744 if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
745 && _kdc_is_weak_exception(r->server->principal, serverkey->keytype))
747 krb5_enctype_enable(r->context, serverkey->keytype);
751 if (r->canon_client_princ) {
754 (void) krb5_unparse_name(r->context, r->canon_client_princ, &cpn);
755 kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s",
756 cpn ? cpn : "<unknown>");
761 * For anonymous tickets, we should filter out positive authorization data
762 * that could reveal the client's identity, and return a policy error for
763 * restrictive authorization data. Policy for unknown authorization types
764 * is implementation dependent.
766 if (r->pac && !et->flags.anonymous) {
767 kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes",
771 * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
772 * buffer (legacy behavior) or if the attributes buffer indicates the
773 * AS client requested one.
775 if (_kdc_include_pac_p(r)) {
776 krb5_boolean is_tgs =
777 krb5_principal_is_krbtgt(r->context, r->server->principal);
779 ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, r->client_princ, serverkey,
780 krbtgtkey, rodc_id, NULL, r->canon_client_princ,
781 add_ticket_sig, add_ticket_sig, et,
782 is_tgs ? &r->pac_attributes : NULL);
788 ret = _kdc_finalize_reply(r);
792 /* It is somewhat unclear where the etype in the following
793 encryption should come from. What we have is a session
794 key in the passed tgt, and a list of preferred etypes
795 *for the new ticket*. Should we pick the best possible
796 etype, given the keytype in the tgt, or should we look
797 at the etype list here as well? What if the tgt
798 session key is DES3 and we want a ticket with a (say)
799 CAST session key. Should the DES3 etype be added to the
800 etype list, even if we don't want a session key with
802 ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
803 serverkey->keytype, kvno,
804 serverkey, 0, r->rk_is_subkey, reply);
806 krb5_enctype_disable(r->context, serverkey->keytype);
808 _log_astgs_req(r, serverkey->keytype);
814 static krb5_error_code
815 tgs_check_authenticator(krb5_context context,
816 krb5_kdc_configuration *config,
817 krb5_auth_context ac,
821 krb5_authenticator auth;
825 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
827 kdc_log(context, config, 2,
828 "Out of memory checking PA-TGS Authenticator");
831 if(auth->cksum == NULL){
832 kdc_log(context, config, 4, "No authenticator in request");
833 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
837 if (!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
838 kdc_log(context, config, 4, "Bad checksum type in authenticator: %d",
839 auth->cksum->cksumtype);
840 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
844 ret = krb5_crypto_init(context, key, 0, &crypto);
846 const char *msg = krb5_get_error_message(context, ret);
847 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
848 krb5_free_error_message(context, msg);
853 * RFC4120 says the checksum must be collision-proof, but it does
854 * not require it to be keyed (as the authenticator is encrypted).
856 _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
857 ret = _kdc_verify_checksum(context,
859 KRB5_KU_TGS_REQ_AUTH_CKSUM,
862 krb5_crypto_destroy(context, crypto);
864 const char *msg = krb5_get_error_message(context, ret);
865 kdc_log(context, config, 4,
866 "Failed to verify authenticator checksum: %s", msg);
867 krb5_free_error_message(context, msg);
870 free_Authenticator(auth);
876 need_referral(krb5_context context, krb5_kdc_configuration *config,
877 const KDCOptions * const options, krb5_principal server,
882 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
885 if (server->name.name_string.len == 1)
886 name = server->name.name_string.val[0];
887 else if (server->name.name_string.len > 1)
888 name = server->name.name_string.val[1];
892 kdc_log(context, config, 5, "Searching referral for %s", name);
894 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
897 static krb5_error_code
898 validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
903 krb5_data_zero(&data);
905 if (!r->config->enable_fast)
908 ret = _krb5_get_ad(r->context, auth_data, NULL,
909 KRB5_AUTHDATA_FX_FAST_USED, &data);
911 r->fast_asserted = 1;
912 krb5_data_free(&data);
915 ret = _krb5_get_ad(r->context, auth_data, NULL,
916 KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
918 kdc_log(r->context, r->config, 2,
919 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
920 krb5_data_free(&data);
921 return KRB5KRB_AP_ERR_BAD_INTEGRITY;
927 static krb5_error_code
928 tgs_parse_request(astgs_request_t r,
929 const PA_DATA *tgs_req,
930 krb5_enctype *krbtgt_etype,
932 const struct sockaddr *from_addr,
935 AuthorizationData **auth_data)
937 krb5_kdc_configuration *config = r->config;
938 KDC_REQ_BODY *b = &r->req.req_body;
939 static char failed[] = "<unparse_name failed>";
942 krb5_principal princ;
943 krb5_auth_context ac = NULL;
944 krb5_flags ap_req_options;
945 krb5_flags verify_ap_req_flags = 0;
947 krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
948 krb5uint32 krbtgt_kvno_try;
949 int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
950 const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
952 krb5_keyblock *subkey = NULL;
959 memset(&ap_req, 0, sizeof(ap_req));
960 ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req);
962 const char *msg = krb5_get_error_message(r->context, ret);
963 kdc_log(r->context, config, 4, "Failed to decode AP-REQ: %s", msg);
964 krb5_free_error_message(r->context, msg);
968 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
969 /* XXX check for ticket.sname == req.sname */
970 kdc_log(r->context, config, 4, "PA-DATA is not a ticket-granting ticket");
971 ret = KRB5KDC_ERR_POLICY; /* ? */
975 _krb5_principalname2krb5_principal(r->context,
978 ap_req.ticket.realm);
980 krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
981 ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT,
982 &krbtgt_kvno, &r->krbtgtdb, &r->krbtgt);
984 if (ret == HDB_ERR_NOT_FOUND_HERE) {
985 /* XXX Factor out this unparsing of the same princ all over */
987 ret = krb5_unparse_name(r->context, princ, &p);
990 krb5_free_principal(r->context, princ);
991 kdc_log(r->context, config, 5,
992 "Ticket-granting ticket account %s does not have secrets at "
993 "this KDC, need to proxy", p);
996 ret = HDB_ERR_NOT_FOUND_HERE;
998 } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1000 ret = krb5_unparse_name(r->context, princ, &p);
1003 krb5_free_principal(r->context, princ);
1004 kdc_log(r->context, config, 5,
1005 "Ticket-granting ticket account %s does not have keys for "
1006 "kvno %d at this KDC", p, krbtgt_kvno);
1009 ret = HDB_ERR_KVNO_NOT_FOUND;
1011 } else if (ret == HDB_ERR_NO_MKEY) {
1013 ret = krb5_unparse_name(r->context, princ, &p);
1016 krb5_free_principal(r->context, princ);
1017 kdc_log(r->context, config, 5,
1018 "Missing master key for decrypting keys for ticket-granting "
1019 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1022 ret = HDB_ERR_KVNO_NOT_FOUND;
1025 const char *msg = krb5_get_error_message(r->context, ret);
1027 ret = krb5_unparse_name(r->context, princ, &p);
1030 kdc_log(r->context, config, 4,
1031 "Ticket-granting ticket %s not found in database: %s", p, msg);
1032 krb5_free_principal(r->context, princ);
1033 krb5_free_error_message(r->context, msg);
1036 ret = KRB5KRB_AP_ERR_NOT_US;
1040 krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : r->krbtgt->kvno;
1041 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1044 krbtgt_keys = hdb_kvno2keys(r->context, r->krbtgt, krbtgt_kvno_try);
1045 ret = hdb_enctype2key(r->context, r->krbtgt, krbtgt_keys,
1046 ap_req.ticket.enc_part.etype, &tkey);
1047 if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1048 kvno_search_tries--;
1052 char *str = NULL, *p = NULL;
1054 krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str);
1055 krb5_unparse_name(r->context, princ, &p);
1056 kdc_log(r->context, config, 4,
1057 "No server key with enctype %s found for %s",
1058 str ? str : "<unknown enctype>",
1059 p ? p : "<unparse_name failed>");
1062 ret = KRB5KRB_AP_ERR_BADKEYVER;
1066 if (b->kdc_options.validate)
1067 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1069 if (r->config->warn_ticket_addresses)
1070 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS;
1072 ret = krb5_verify_ap_req2(r->context,
1077 verify_ap_req_flags,
1080 KRB5_KU_TGS_REQ_AUTH);
1081 if (r->ticket && r->ticket->ticket.caddr)
1082 kdc_audit_addaddrs((kdc_request_t)r, r->ticket->ticket.caddr, "tixaddrs");
1083 if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR &&
1084 r->ticket != NULL) {
1085 kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE);
1088 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1089 kvno_search_tries--;
1094 krb5_free_principal(r->context, princ);
1096 const char *msg = krb5_get_error_message(r->context, ret);
1097 kdc_log(r->context, config, 4, "Failed to verify AP-REQ: %s", msg);
1098 krb5_free_error_message(r->context, msg);
1102 r->ticket_key = tkey;
1105 krb5_authenticator auth;
1107 ret = krb5_auth_con_getauthenticator(r->context, ac, &auth);
1109 *csec = malloc(sizeof(**csec));
1110 if (*csec == NULL) {
1111 krb5_free_authenticator(r->context, &auth);
1112 kdc_log(r->context, config, 4, "malloc failed");
1115 **csec = auth->ctime;
1116 *cusec = malloc(sizeof(**cusec));
1117 if (*cusec == NULL) {
1118 krb5_free_authenticator(r->context, &auth);
1119 kdc_log(r->context, config, 4, "malloc failed");
1122 **cusec = auth->cusec;
1124 ret = validate_fast_ad(r, auth->authorization_data);
1125 krb5_free_authenticator(r->context, &auth);
1131 ret = tgs_check_authenticator(r->context, config, ac, b, &r->ticket->ticket.key);
1133 krb5_auth_con_free(r->context, ac);
1137 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1138 r->rk_is_subkey = 1;
1140 ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
1142 const char *msg = krb5_get_error_message(r->context, ret);
1143 krb5_auth_con_free(r->context, ac);
1144 kdc_log(r->context, config, 4, "Failed to get remote subkey: %s", msg);
1145 krb5_free_error_message(r->context, msg);
1149 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1150 r->rk_is_subkey = 0;
1152 ret = krb5_auth_con_getkey(r->context, ac, &subkey);
1154 const char *msg = krb5_get_error_message(r->context, ret);
1155 krb5_auth_con_free(r->context, ac);
1156 kdc_log(r->context, config, 4, "Failed to get session key: %s", msg);
1157 krb5_free_error_message(r->context, msg);
1162 krb5_auth_con_free(r->context, ac);
1163 kdc_log(r->context, config, 4,
1164 "Failed to get key for enc-authorization-data");
1165 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1169 krb5_free_keyblock_contents(r->context, &r->reply_key);
1170 ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
1171 krb5_free_keyblock(r->context, subkey);
1175 if (b->enc_authorization_data) {
1178 ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto);
1180 const char *msg = krb5_get_error_message(r->context, ret);
1181 krb5_auth_con_free(r->context, ac);
1182 kdc_log(r->context, config, 4, "krb5_crypto_init failed: %s", msg);
1183 krb5_free_error_message(r->context, msg);
1186 ret = krb5_decrypt_EncryptedData (r->context,
1189 b->enc_authorization_data,
1191 krb5_crypto_destroy(r->context, crypto);
1193 krb5_auth_con_free(r->context, ac);
1194 kdc_log(r->context, config, 4,
1195 "Failed to decrypt enc-authorization-data");
1196 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1200 if (*auth_data == NULL) {
1201 krb5_auth_con_free(r->context, ac);
1202 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1205 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1207 krb5_auth_con_free(r->context, ac);
1210 kdc_log(r->context, config, 4, "Failed to decode authorization data");
1211 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1216 ret = validate_fast_ad(r, r->ticket->ticket.authorization_data);
1222 * Check for FAST request
1225 ret = _kdc_fast_unwrap_request(r, r->ticket, ac);
1229 krb5_auth_con_free(r->context, ac);
1232 free_AP_REQ(&ap_req);
1237 static krb5_error_code
1238 build_server_referral(krb5_context context,
1239 krb5_kdc_configuration *config,
1240 krb5_crypto session,
1241 krb5_const_realm referred_realm,
1242 const PrincipalName *true_principal_name,
1243 const PrincipalName *requested_principal,
1246 PA_ServerReferralData ref;
1247 krb5_error_code ret;
1252 memset(&ref, 0, sizeof(ref));
1254 if (referred_realm) {
1255 ALLOC(ref.referred_realm);
1256 if (ref.referred_realm == NULL)
1258 *ref.referred_realm = strdup(referred_realm);
1259 if (*ref.referred_realm == NULL)
1262 if (true_principal_name) {
1263 ALLOC(ref.true_principal_name);
1264 if (ref.true_principal_name == NULL)
1266 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1270 if (requested_principal) {
1271 ALLOC(ref.requested_principal_name);
1272 if (ref.requested_principal_name == NULL)
1274 ret = copy_PrincipalName(requested_principal,
1275 ref.requested_principal_name);
1280 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1281 data.data, data.length,
1283 free_PA_ServerReferralData(&ref);
1286 if (data.length != size)
1287 krb5_abortx(context, "internal asn.1 encoder error");
1289 ret = krb5_encrypt_EncryptedData(context, session,
1290 KRB5_KU_PA_SERVER_REFERRAL,
1291 data.data, data.length,
1297 ASN1_MALLOC_ENCODE(EncryptedData,
1298 outdata->data, outdata->length,
1300 free_EncryptedData(&ed);
1303 if (outdata->length != size)
1304 krb5_abortx(context, "internal asn.1 encoder error");
1308 free_PA_ServerReferralData(&ref);
1309 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1314 * This function is intended to be used when failure to find the client is
1318 _kdc_db_fetch_client(krb5_context context,
1319 krb5_kdc_configuration *config,
1323 const char *krbtgt_realm,
1325 hdb_entry **client_out)
1327 krb5_error_code ret;
1328 hdb_entry *client = NULL;
1332 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1333 NULL, clientdb, &client);
1334 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1336 * This is OK, we are just trying to find out if they have
1337 * been disabled or deleted in the meantime; missing secrets
1342 * If the client belongs to the same realm as our TGS, it
1343 * should exist in the local database.
1347 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1348 if (ret == HDB_ERR_NOENTRY)
1349 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1350 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1354 msg = krb5_get_error_message(context, ret);
1355 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1356 krb5_free_error_message(context, msg);
1357 } else if (client->flags.invalid || !client->flags.client) {
1358 kdc_log(context, config, 4, "Client has invalid bit set");
1359 _kdc_free_ent(context, *clientdb, client);
1360 return KRB5KDC_ERR_POLICY;
1363 *client_out = client;
1368 static krb5_error_code
1369 tgs_build_reply(astgs_request_t priv,
1370 krb5_enctype krbtgt_etype,
1371 AuthorizationData **auth_data,
1372 const struct sockaddr *from_addr)
1374 krb5_context context = priv->context;
1375 krb5_kdc_configuration *config = priv->config;
1376 KDC_REQ_BODY *b = &priv->req.req_body;
1377 const char *from = priv->from;
1378 krb5_error_code ret, ret2;
1379 krb5_principal krbtgt_out_principal = NULL;
1380 krb5_principal user2user_princ = NULL;
1381 char *spn = NULL, *cpn = NULL, *krbtgt_out_n = NULL;
1382 char *user2user_name = NULL;
1383 HDB *user2user_krbtgtdb;
1384 hdb_entry *user2user_krbtgt = NULL;
1386 HDB *serverdb = NULL;
1387 krb5_realm ref_realm = NULL;
1388 EncTicketPart *tgt = &priv->ticket->ticket;
1389 const EncryptionKey *ekey;
1390 krb5_keyblock sessionkey;
1392 krb5_pac user2user_pac = NULL;
1394 krb5_boolean add_ticket_sig = FALSE;
1395 const char *tgt_realm = /* Realm of TGT issuer */
1396 krb5_principal_get_realm(context, priv->krbtgt->principal);
1397 const char *our_realm = /* Realm of this KDC */
1398 krb5_principal_get_comp_string(context, priv->krbtgt->principal, 1);
1399 char **capath = NULL;
1400 size_t num_capath = 0;
1403 hdb_entry *krbtgt_out = NULL;
1407 EncTicketPart adtkt;
1409 krb5_boolean kdc_issued = FALSE;
1412 int flags = HDB_F_FOR_TGS_REQ;
1416 memset(&sessionkey, 0, sizeof(sessionkey));
1417 memset(&adtkt, 0, sizeof(adtkt));
1423 * The canonicalize KDC option is passed as a hint to the backend, but
1424 * can typically be ignored. Per RFC 6806, names are not canonicalized
1425 * in response to a TGS request (although we make an exception, see
1426 * force-canonicalize below).
1428 if (b->kdc_options.canonicalize)
1429 flags |= HDB_F_CANON;
1432 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1433 _kdc_set_const_e_text(priv, "No server in request");
1437 _krb5_principalname2krb5_principal(context, &priv->server_princ, *s, r);
1438 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1442 _krb5_principalname2krb5_principal(context, &priv->client_princ,
1443 tgt->cname, tgt->crealm);
1444 ret = krb5_unparse_name(context, priv->client_princ, &priv->cname);
1448 result = unparse_flags(KDCOptions2int(b->kdc_options),
1449 asn1_KDCOptions_units(),
1450 opt_str, sizeof(opt_str));
1452 kdc_log(context, config, 4,
1453 "TGS-REQ %s from %s for %s [%s]",
1454 cpn, from, spn, opt_str);
1456 kdc_log(context, config, 4,
1457 "TGS-REQ %s from %s for %s", cpn, from, spn);
1465 _kdc_free_ent(context, serverdb, priv->server);
1466 priv->server = NULL;
1467 ret = _kdc_db_fetch(context, config, priv->server_princ,
1468 HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags,
1469 NULL, &serverdb, &priv->server);
1470 priv->serverdb = serverdb;
1471 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1472 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn);
1473 kdc_audit_addreason((kdc_request_t)priv, "Target not found here");
1475 } else if (ret == HDB_ERR_WRONG_REALM) {
1477 ref_realm = strdup(priv->server->principal->realm);
1478 if (ref_realm == NULL) {
1479 ret = krb5_enomem(context);
1483 kdc_log(context, config, 4,
1484 "Returning a referral to realm %s for "
1487 krb5_free_principal(context, priv->server_princ);
1488 priv->server_princ = NULL;
1489 ret = krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
1495 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1502 const char *new_rlm, *msg;
1506 priv->error_code = ret; /* advise policy plugin of failure reason */
1507 ret2 = _kdc_referral_policy(priv);
1509 krb5_xfree(priv->sname);
1511 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1515 } else if (ret2 != KRB5_PLUGIN_NO_HANDLE) {
1517 } else if ((req_rlm = get_krbtgt_realm(&priv->server_princ->name)) != NULL) {
1518 if (capath == NULL) {
1519 /* With referalls, hierarchical capaths are always enabled */
1520 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1521 req_rlm, TRUE, &capath, &num_capath);
1524 kdc_audit_addreason((kdc_request_t)priv,
1525 "No trusted path from client realm to ours");
1529 new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1531 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1532 "realm %s not found, trying %s", tgt->crealm,
1533 our_realm, req_rlm, new_rlm);
1536 ref_realm = strdup(new_rlm);
1537 if (ref_realm == NULL) {
1538 ret = krb5_enomem(context);
1542 krb5_free_principal(context, priv->server_princ);
1543 priv->server_princ = NULL;
1544 krb5_make_principal(context, &priv->server_princ, r,
1545 KRB5_TGS_NAME, ref_realm, NULL);
1548 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1554 } else if (need_referral(context, config, &b->kdc_options, priv->server_princ, &realms)) {
1555 if (strcmp(realms[0], priv->server_princ->realm) != 0) {
1556 kdc_log(context, config, 4,
1557 "Returning a referral to realm %s for "
1558 "server %s that was not found",
1560 krb5_free_principal(context, priv->server_princ);
1561 priv->server_princ = NULL;
1562 krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
1566 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1568 krb5_free_host_realm(context, realms);
1574 ref_realm = strdup(realms[0]);
1576 krb5_free_host_realm(context, realms);
1579 krb5_free_host_realm(context, realms);
1581 msg = krb5_get_error_message(context, ret);
1582 kdc_log(context, config, 3,
1583 "Server not found in database: %s: %s", spn, msg);
1584 krb5_free_error_message(context, msg);
1585 if (ret == HDB_ERR_NOENTRY)
1586 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1587 kdc_audit_addreason((kdc_request_t)priv,
1588 "Service principal unknown");
1593 * Now refetch the primary krbtgt, and get the current kvno (the
1594 * sign check may have been on an old kvno, and the server may
1595 * have been an incoming trust)
1598 ret = krb5_make_principal(context,
1599 &krbtgt_out_principal,
1605 kdc_log(context, config, 4,
1606 "Failed to make krbtgt principal name object for "
1607 "authz-data signatures");
1610 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1612 kdc_log(context, config, 4,
1613 "Failed to make krbtgt principal name object for "
1614 "authz-data signatures");
1618 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1619 HDB_F_GET_KRBTGT, NULL, &krbtgt_outdb, &krbtgt_out);
1622 ret = krb5_unparse_name(context, priv->krbtgt->principal, &ktpn);
1623 kdc_log(context, config, 4,
1624 "No such principal %s (needed for authz-data signature keys) "
1625 "while processing TGS-REQ for service %s with krbtg %s",
1626 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1628 ret = KRB5KRB_AP_ERR_NOT_US;
1633 * Select enctype, return key and kvno.
1639 if(b->kdc_options.enc_tkt_in_skey) {
1643 krb5uint32 second_kvno = 0;
1644 krb5uint32 *kvno_ptr = NULL;
1647 hdb_entry *user2user_client = NULL;
1648 krb5_boolean user2user_kdc_issued = FALSE;
1651 if(b->additional_tickets == NULL ||
1652 b->additional_tickets->len == 0){
1653 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1654 kdc_log(context, config, 4,
1655 "No second ticket present in user-to-user request");
1656 kdc_audit_addreason((kdc_request_t)priv,
1657 "No second ticket present in user-to-user request");
1660 t = &b->additional_tickets->val[0];
1661 if(!get_krbtgt_realm(&t->sname)){
1662 kdc_log(context, config, 4,
1663 "Additional ticket is not a ticket-granting ticket");
1664 kdc_audit_addreason((kdc_request_t)priv,
1665 "Additional ticket is not a ticket-granting ticket");
1666 ret = KRB5KDC_ERR_POLICY;
1669 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1673 ret = krb5_unparse_name(context, p, &tpn);
1676 if(t->enc_part.kvno){
1677 second_kvno = *t->enc_part.kvno;
1678 kvno_ptr = &second_kvno;
1680 ret = _kdc_db_fetch(context, config, p,
1681 HDB_F_GET_KRBTGT, kvno_ptr,
1682 &user2user_krbtgtdb, &user2user_krbtgt);
1683 krb5_free_principal(context, p);
1685 if (ret == HDB_ERR_NOENTRY)
1686 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1687 kdc_audit_addreason((kdc_request_t)priv,
1688 "User-to-user service principal (TGS) unknown");
1692 ret = hdb_enctype2key(context, user2user_krbtgt, NULL,
1693 t->enc_part.etype, &uukey);
1695 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1696 kdc_audit_addreason((kdc_request_t)priv,
1697 "User-to-user enctype not supported");
1701 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1703 kdc_audit_addreason((kdc_request_t)priv,
1704 "User-to-user TGT decrypt failure");
1709 ret = _kdc_verify_flags(context, config, &adtkt, tpn);
1711 kdc_audit_addreason((kdc_request_t)priv,
1712 "User-to-user TGT expired or invalid");
1718 /* Fetch the name from the TGT. */
1719 ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1720 adtkt.cname, adtkt.crealm);
1724 ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1729 * Look up the name given in the TGT in the database. The user
1730 * claims to have a ticket-granting-ticket to our KDC, so we should
1731 * fail hard if we can't find the user - otherwise we can't do
1734 ret = _kdc_db_fetch(context, config, user2user_princ,
1735 HDB_F_GET_CLIENT | flags,
1736 NULL, &user2user_db, &user2user_client);
1737 if (ret == HDB_ERR_NOENTRY)
1738 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1743 * The account is present in the database, now check the
1746 * We check this as a client (because the purpose of
1747 * user2user is that the server flag is not set, because
1748 * the long-term key is not strong, but this does mean
1749 * that a client with an expired password can't get accept
1750 * a user2user ticket.
1752 ret = kdc_check_flags(priv,
1757 _kdc_free_ent(context, user2user_db, user2user_client);
1762 * Also check that the account is the same one specified in the
1765 ret = _kdc_check_client_matches_target_service(context,
1772 _kdc_free_ent(context, user2user_db, user2user_client);
1776 /* Verify the PAC of the TGT. */
1777 ret = _kdc_check_pac(priv, user2user_princ, NULL,
1778 user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
1779 &uukey->key, &priv->ticket_key->key, &adtkt,
1780 &user2user_kdc_issued, &user2user_pac, NULL, NULL);
1781 _kdc_free_ent(context, user2user_db, user2user_client);
1783 const char *msg = krb5_get_error_message(context, ret);
1784 kdc_log(context, config, 0,
1785 "Verify PAC failed for %s (%s) from %s with %s",
1786 spn, user2user_name, from, msg);
1787 krb5_free_error_message(context, msg);
1791 if ((config->require_pac && !user2user_pac)
1792 || (user2user_pac && !user2user_kdc_issued))
1794 ret = KRB5KDC_ERR_BADOPTION;
1795 kdc_log(context, config, 0,
1796 "Ticket not signed with PAC; user-to-user failed (%s).",
1797 user2user_pac ? "Ticket unsigned" : "No PAC");
1802 for(i = 0; i < b->etype.len; i++)
1803 if (b->etype.val[i] == adtkt.key.keytype)
1805 if(i == b->etype.len) {
1806 kdc_log(context, config, 4,
1807 "Addition ticket have not matching etypes");
1808 krb5_clear_error_message(context);
1809 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1810 kdc_audit_addreason((kdc_request_t)priv,
1811 "No matching enctypes for 2nd ticket");
1814 etype = b->etype.val[i];
1819 ret = _kdc_find_etype(priv, krb5_principal_is_krbtgt(context, priv->server_princ)
1821 b->etype.val, b->etype.len, &etype, NULL,
1824 kdc_log(context, config, 4,
1825 "Server (%s) has no support for etypes", spn);
1826 kdc_audit_addreason((kdc_request_t)priv,
1827 "Enctype not supported");
1830 ret = _kdc_get_preferred_key(context, config, priv->server, spn,
1833 kdc_log(context, config, 4,
1834 "Server (%s) has no supported etypes", spn);
1835 kdc_audit_addreason((kdc_request_t)priv,
1836 "Enctype not supported");
1840 kvno = priv->server->kvno;
1843 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1849 * Check that service is in the same realm as the krbtgt. If it's
1850 * not the same, it's someone that is using a uni-directional trust
1855 * The first realm is the realm of the service, the second is
1856 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1857 * encrypted to. The redirection via the krbtgt_out entry allows
1858 * the DB to possibly correct the case of the realm (Samba4 does
1859 * this) before the strcmp()
1861 if (strcmp(krb5_principal_get_realm(context, priv->server->principal),
1862 krb5_principal_get_realm(context, krbtgt_out->principal)) != 0) {
1864 ret = krb5_unparse_name(context, krbtgt_out->principal, &ktpn);
1865 kdc_log(context, config, 4,
1866 "Request with wrong krbtgt: %s",
1867 (ret == 0) ? ktpn : "<unknown>");
1870 ret = KRB5KRB_AP_ERR_NOT_US;
1871 kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT");
1875 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1878 kdc_log(context, config, 4,
1879 "Failed to find key for krbtgt PAC signature");
1880 kdc_audit_addreason((kdc_request_t)priv,
1881 "Failed to find key for krbtgt PAC signature");
1884 ret = hdb_enctype2key(context, krbtgt_out, NULL,
1885 tkey_sign->key.keytype, &tkey_sign);
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");
1894 if (_kdc_synthetic_princ_used_p(context, priv->ticket))
1895 flags |= HDB_F_SYNTHETIC_OK;
1897 ret = _kdc_db_fetch_client(context, config, flags, priv->client_princ,
1898 cpn, our_realm, &clientdb, &priv->client);
1901 flags &= ~HDB_F_SYNTHETIC_OK;
1902 priv->clientdb = clientdb;
1904 ret = _kdc_check_pac(priv, priv->client_princ, NULL,
1905 priv->client, priv->server,
1906 priv->krbtgt, priv->krbtgt,
1907 &priv->ticket_key->key, &priv->ticket_key->key, tgt,
1908 &kdc_issued, &priv->pac, &priv->canon_client_princ,
1909 &priv->pac_attributes);
1911 const char *msg = krb5_get_error_message(context, ret);
1912 kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
1913 kdc_log(context, config, 4,
1914 "Verify PAC failed for %s (%s) from %s with %s",
1915 spn, cpn, from, msg);
1916 krb5_free_error_message(context, msg);
1925 * Services for User: protocol transition and constrained delegation
1928 ret = _kdc_validate_services_for_user(priv);
1936 ret = kdc_check_flags(priv, FALSE, priv->client, priv->server);
1940 if((b->kdc_options.validate || b->kdc_options.renew) &&
1941 !krb5_principal_compare(context,
1942 priv->krbtgt->principal,
1943 priv->server->principal)){
1944 kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request");
1945 kdc_log(context, config, 4, "Inconsistent request.");
1946 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1950 /* check for valid set of addresses */
1951 if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) {
1952 if (config->check_ticket_addresses) {
1953 ret = KRB5KRB_AP_ERR_BADADDR;
1954 kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
1955 kdc_log(context, config, 4, "Request from wrong address");
1956 kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address");
1958 } else if (config->warn_ticket_addresses) {
1959 kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
1963 /* check local and per-principal anonymous ticket issuance policy */
1964 if (is_anon_tgs_request_p(b, tgt)) {
1965 ret = _kdc_check_anon_policy(priv);
1971 * If this is an referral, add server referral data to the
1978 kdc_log(context, config, 3,
1979 "Adding server referral to %s", ref_realm);
1981 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1985 ret = build_server_referral(context, config, crypto, ref_realm,
1986 NULL, s, &pa.padata_value);
1987 krb5_crypto_destroy(context, crypto);
1989 kdc_audit_addreason((kdc_request_t)priv, "Referral build failed");
1990 kdc_log(context, config, 4,
1991 "Failed building server referral");
1994 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1996 ret = add_METHOD_DATA(priv->rep.padata, &pa);
1997 krb5_data_free(&pa.padata_value);
1999 kdc_log(context, config, 4,
2000 "Add server referral METHOD-DATA failed");
2006 * Only add ticket signature if the requested server is not krbtgt, and
2007 * either the header server is krbtgt or, in the case of renewal/validation
2008 * if it was signed with PAC ticket signature and we verified it.
2009 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2010 * change one day (see issue #763) so make sure to check for it.
2014 !krb5_principal_is_krbtgt(context, priv->server->principal)) {
2016 /* Validate armor TGT before potentially including device claims */
2017 if (priv->armor_ticket) {
2018 ret = _kdc_fast_check_armor_pac(priv);
2023 add_ticket_sig = TRUE;
2027 * Active-Directory implementations use the high part of the kvno as the
2028 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2031 rodc_id = krbtgt_out->kvno >> 16;
2037 ret = tgs_make_reply(priv,
2049 free(user2user_name);
2051 _krb5_free_capath(context, capath);
2053 krb5_free_keyblock_contents(context, &sessionkey);
2055 _kdc_free_ent(context, krbtgt_outdb, krbtgt_out);
2056 if(user2user_krbtgt)
2057 _kdc_free_ent(context, user2user_krbtgtdb, user2user_krbtgt);
2059 krb5_free_principal(context, user2user_princ);
2060 krb5_free_principal(context, krbtgt_out_principal);
2063 free_EncTicketPart(&adtkt);
2065 krb5_pac_free(context, user2user_pac);
2075 _kdc_tgs_rep(astgs_request_t r)
2077 krb5_kdc_configuration *config = r->config;
2078 KDC_REQ *req = &r->req;
2079 krb5_data *data = r->reply;
2080 const char *from = r->from;
2081 struct sockaddr *from_addr = r->addr;
2082 int datagram_reply = r->datagram_reply;
2083 AuthorizationData *auth_data = NULL;
2084 krb5_error_code ret;
2086 const PA_DATA *tgs_req, *pa;
2087 krb5_enctype krbtgt_etype = ETYPE_NULL;
2089 time_t *csec = NULL;
2094 if(req->padata == NULL){
2095 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2096 kdc_log(r->context, config, 4,
2097 "TGS-REQ from %s without PA-DATA", from);
2102 pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
2104 kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2105 ret = KRB5KRB_ERR_GENERIC;
2110 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2111 if(tgs_req == NULL){
2112 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2114 kdc_log(r->context, config, 4,
2115 "TGS-REQ from %s without PA-TGS-REQ", from);
2118 ret = tgs_parse_request(r, tgs_req,
2123 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2124 /* kdc_log() is called in tgs_parse_request() */
2128 kdc_log(r->context, config, 4,
2129 "Failed parsing TGS-REQ from %s", from);
2133 ret = _kdc_fast_strengthen_reply_key(r);
2137 ALLOC(r->rep.padata);
2138 if (r->rep.padata == NULL) {
2140 krb5_set_error_message(r->context, ret, N_("malloc: out of memory", ""));
2144 ret = tgs_build_reply(r,
2149 kdc_log(r->context, config, 4,
2150 "Failed building TGS-REP to %s", from);
2155 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2156 krb5_data_free(data);
2157 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2158 _kdc_set_const_e_text(r, "Reply packet too large");
2162 r->error_code = ret;
2164 krb5_error_code ret2 = _kdc_audit_request(r);
2166 krb5_data_free(data);
2171 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2172 METHOD_DATA error_method = { 0, NULL };
2174 kdc_log(r->context, config, 5, "tgs-req: sending error: %d to client", ret);
2175 ret = _kdc_fast_mk_error(r,
2180 r->client_princ ? r->client_princ :(r->ticket != NULL ? r->ticket->client : NULL),
2181 r->server_princ ? r->server_princ :(r->ticket != NULL ? r->ticket->server : NULL),
2184 free_METHOD_DATA(&error_method);
2189 free_TGS_REP(&r->rep);
2190 free_TransitedEncoding(&r->et.transited);
2191 free(r->et.starttime);
2192 free(r->et.renew_till);
2193 if(r->et.authorization_data) {
2194 free_AuthorizationData(r->et.authorization_data);
2195 free(r->et.authorization_data);
2197 free_LastReq(&r->ek.last_req);
2198 if (r->et.key.keyvalue.data) {
2199 memset_s(r->et.key.keyvalue.data, 0, r->et.key.keyvalue.length,
2200 r->et.key.keyvalue.length);
2202 free_EncryptionKey(&r->et.key);
2204 if (r->canon_client_princ) {
2205 krb5_free_principal(r->context, r->canon_client_princ);
2206 r->canon_client_princ = NULL;
2208 if (r->armor_crypto) {
2209 krb5_crypto_destroy(r->context, r->armor_crypto);
2210 r->armor_crypto = NULL;
2212 if (r->armor_ticket)
2213 krb5_free_ticket(r->context, r->armor_ticket);
2214 if (r->armor_server)
2215 _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server);
2216 if (r->explicit_armor_client)
2217 _kdc_free_ent(r->context,
2218 r->explicit_armor_clientdb,
2219 r->explicit_armor_client);
2220 if (r->explicit_armor_pac)
2221 krb5_pac_free(r->context, r->explicit_armor_pac);
2222 krb5_free_keyblock_contents(r->context, &r->reply_key);
2223 krb5_free_keyblock_contents(r->context, &r->strengthen_key);
2226 krb5_free_ticket(r->context, r->ticket);
2228 _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt);
2231 _kdc_free_ent(r->context, r->clientdb, r->client);
2232 krb5_free_principal(r->context, r->client_princ);
2234 _kdc_free_ent(r->context, r->serverdb, r->server);
2235 krb5_free_principal(r->context, r->server_princ);
2236 _kdc_free_fast_state(&r->fast);
2237 krb5_pac_free(r->context, r->pac);
2240 free_AuthorizationData(auth_data);