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;
99 krb5_boolean is_trusted = FALSE;
104 *pac_canon_name = NULL;
106 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
108 ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
113 if (config->require_pac)
114 ret = KRB5KDC_ERR_TGT_REVOKED;
118 /* Verify the server signature. */
119 ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
120 server_check_key, NULL);
122 krb5_pac_free(context, pac);
126 /* Verify the KDC signatures. */
127 ret = _kdc_pac_verify(r,
128 client_principal, delegated_proxy_principal,
129 client, server, krbtgt, tkt, pac, &is_trusted);
132 krb5_pac_set_trusted(pac, TRUE);
135 if (pac_canon_name) {
136 ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
137 if (ret && ret != ENOENT) {
138 krb5_pac_free(context, pac);
142 if (pac_attributes &&
143 _krb5_pac_get_attributes_info(context, pac, pac_attributes) != 0)
144 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
145 } else if (ret == KRB5_PLUGIN_NO_HANDLE) {
147 * We can't verify the KDC signatures if the ticket was issued by
148 * another realm's KDC.
150 if (krb5_realm_compare(context, server->principal,
151 ticket_server->principal)) {
152 ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
155 krb5_pac_free(context, pac);
160 if (pac_canon_name) {
161 ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
162 if (ret && ret != ENOENT) {
163 krb5_pac_free(context, pac);
167 if (pac_attributes &&
168 _krb5_pac_get_attributes_info(context, pac, pac_attributes) != 0)
169 *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
171 /* Discard the PAC if the plugin didn't handle it */
172 krb5_pac_free(context, pac);
173 ret = krb5_pac_init(context, &pac);
177 krb5_pac_free(context, pac);
181 *kdc_issued = signedticket ||
182 krb5_principal_is_krbtgt(context,
183 ticket_server->principal);
190 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
191 const EncTicketPart *tgt)
193 KDCOptions f = b->kdc_options;
196 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
197 * request-anonymous and cname-in-addl-tkt flags for constrained
198 * delegation requests. A true anonymous TGS request will only
199 * have the request-anonymous flag set. (A corollary of this is
200 * that it is not possible to support anonymous constrained
201 * delegation requests, although they would be of limited utility.)
203 return tgt->flags.anonymous ||
204 (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
211 static krb5_error_code
212 check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b,
213 krb5_const_principal tgt_name,
214 const EncTicketPart *tgt, EncTicketPart *et)
216 KDCOptions f = b->kdc_options;
219 if (!tgt->flags.invalid || tgt->starttime == NULL) {
220 kdc_audit_addreason((kdc_request_t)r,
221 "Bad request to validate ticket");
222 return KRB5KDC_ERR_BADOPTION;
224 if(*tgt->starttime > kdc_time){
225 kdc_audit_addreason((kdc_request_t)r,
226 "Early request to validate ticket");
227 return KRB5KRB_AP_ERR_TKT_NYV;
230 et->flags.invalid = 0;
231 } else if (tgt->flags.invalid) {
232 kdc_audit_addreason((kdc_request_t)r,
233 "Ticket-granting ticket has INVALID flag set");
234 return KRB5KRB_AP_ERR_TKT_INVALID;
238 if (!tgt->flags.forwardable) {
239 kdc_audit_addreason((kdc_request_t)r,
240 "Bad request for forwardable ticket");
241 return KRB5KDC_ERR_BADOPTION;
243 et->flags.forwardable = 1;
246 if (!tgt->flags.forwardable) {
247 kdc_audit_addreason((kdc_request_t)r,
248 "Request to forward non-forwardable ticket");
249 return KRB5KDC_ERR_BADOPTION;
251 et->flags.forwarded = 1;
252 et->caddr = b->addresses;
254 if(tgt->flags.forwarded)
255 et->flags.forwarded = 1;
258 if (!tgt->flags.proxiable) {
259 kdc_audit_addreason((kdc_request_t)r,
260 "Bad request for proxiable ticket");
261 return KRB5KDC_ERR_BADOPTION;
263 et->flags.proxiable = 1;
266 if (!tgt->flags.proxiable) {
267 kdc_audit_addreason((kdc_request_t)r,
268 "Request to proxy non-proxiable ticket");
269 return KRB5KDC_ERR_BADOPTION;
272 et->caddr = b->addresses;
277 if(f.allow_postdate){
278 if (!tgt->flags.may_postdate) {
279 kdc_audit_addreason((kdc_request_t)r,
280 "Bad request for post-datable ticket");
281 return KRB5KDC_ERR_BADOPTION;
283 et->flags.may_postdate = 1;
286 if (!tgt->flags.may_postdate) {
287 kdc_audit_addreason((kdc_request_t)r,
288 "Bad request for postdated ticket");
289 return KRB5KDC_ERR_BADOPTION;
292 *et->starttime = *b->from;
293 et->flags.postdated = 1;
294 et->flags.invalid = 1;
295 } else if (b->from && *b->from > kdc_time + r->context->max_skew) {
296 kdc_audit_addreason((kdc_request_t)r,
297 "Ticket cannot be postdated");
298 return KRB5KDC_ERR_CANNOT_POSTDATE;
302 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
303 kdc_audit_addreason((kdc_request_t)r,
304 "Bad request for renewable ticket");
305 return KRB5KDC_ERR_BADOPTION;
307 et->flags.renewable = 1;
308 ALLOC(et->renew_till);
309 _kdc_fix_time(&b->rtime);
310 *et->renew_till = *b->rtime;
314 if (!tgt->flags.renewable || tgt->renew_till == NULL) {
315 kdc_audit_addreason((kdc_request_t)r,
316 "Request to renew non-renewable ticket");
317 return KRB5KDC_ERR_BADOPTION;
319 old_life = tgt->endtime;
321 old_life -= *tgt->starttime;
323 old_life -= tgt->authtime;
324 et->endtime = *et->starttime + old_life;
325 if (et->renew_till != NULL)
326 et->endtime = min(*et->renew_till, et->endtime);
330 * RFC 8062 section 3 defines an anonymous ticket as one containing
331 * the anonymous principal and the anonymous ticket flag.
333 if (tgt->flags.anonymous &&
334 !_kdc_is_anonymous(r->context, tgt_name)) {
335 kdc_audit_addreason((kdc_request_t)r,
336 "Anonymous ticket flag set without "
337 "anonymous principal");
338 return KRB5KDC_ERR_BADOPTION;
342 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
343 * anonymous KDC option SHOULD be set, but it is not required.
344 * Treat an anonymous TGT as if the anonymous flag was set.
346 if (is_anon_tgs_request_p(b, tgt))
347 et->flags.anonymous = 1;
353 * Determine if s4u2self is allowed from this client to this server
357 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
358 * service given by the client.
360 * For example, regardless of the principal being impersonated, if the
361 * 'client' and 'server' (target) are the same, or server is an SPN
362 * alias of client, then it's safe.
366 _kdc_check_client_matches_target_service(krb5_context context,
367 krb5_kdc_configuration *config,
370 hdb_entry *target_server,
371 krb5_const_principal target_server_principal)
376 * Always allow the plugin to check, this might be faster, allow a
377 * policy or audit check and can look into the DB records
380 if (clientdb->hdb_check_client_matches_target_service) {
381 ret = clientdb->hdb_check_client_matches_target_service(context,
387 } else if (krb5_principal_compare(context,
389 target_server_principal) == TRUE) {
390 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
393 ret = KRB5KDC_ERR_BADOPTION;
403 _kdc_verify_flags(krb5_context context,
404 krb5_kdc_configuration *config,
405 const EncTicketPart *et,
408 if(et->endtime < kdc_time){
409 kdc_log(context, config, 4, "Ticket expired (%s)", pstr);
410 return KRB5KRB_AP_ERR_TKT_EXPIRED;
412 if(et->flags.invalid){
413 kdc_log(context, config, 4, "Ticket not valid (%s)", pstr);
414 return KRB5KRB_AP_ERR_TKT_NYV;
423 static krb5_error_code
424 fix_transited_encoding(krb5_context context,
425 krb5_kdc_configuration *config,
426 krb5_boolean check_policy,
427 const TransitedEncoding *tr,
429 const char *client_realm,
430 const char *server_realm,
431 const char *tgt_realm)
433 krb5_error_code ret = 0;
434 char **realms, **tmp;
435 unsigned int num_realms;
438 switch (tr->tr_type) {
439 case domain_X500_Compress:
443 * Allow empty content of type 0 because that is was Microsoft
444 * generates in their TGT.
446 if (tr->contents.length == 0)
448 kdc_log(context, config, 4,
449 "Transited type 0 with non empty content");
450 return KRB5KDC_ERR_TRTYPE_NOSUPP;
452 kdc_log(context, config, 4,
453 "Unknown transited type: %u", tr->tr_type);
454 return KRB5KDC_ERR_TRTYPE_NOSUPP;
457 ret = krb5_domain_x500_decode(context,
464 krb5_warn(context, ret,
465 "Decoding transited encoding");
470 * If the realm of the presented tgt is neither the client nor the server
471 * realm, it is a transit realm and must be added to transited set.
473 if (strcmp(client_realm, tgt_realm) != 0 &&
474 strcmp(server_realm, tgt_realm) != 0) {
475 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
479 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
485 realms[num_realms] = strdup(tgt_realm);
486 if(realms[num_realms] == NULL){
492 if(num_realms == 0) {
493 if (strcmp(client_realm, server_realm) != 0)
494 kdc_log(context, config, 4,
495 "cross-realm %s -> %s", client_realm, server_realm);
499 for(i = 0; i < num_realms; i++)
500 l += strlen(realms[i]) + 2;
504 for(i = 0; i < num_realms; i++) {
506 strlcat(rs, ", ", l);
507 strlcat(rs, realms[i], l);
509 kdc_log(context, config, 4,
510 "cross-realm %s -> %s via [%s]",
511 client_realm, server_realm, rs);
516 ret = krb5_check_transited(context, client_realm,
518 realms, num_realms, NULL);
520 krb5_warn(context, ret, "cross-realm %s -> %s",
521 client_realm, server_realm);
524 et->flags.transited_policy_checked = 1;
526 et->transited.tr_type = domain_X500_Compress;
527 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
529 krb5_warn(context, ret, "Encoding transited encoding");
531 for(i = 0; i < num_realms; i++)
538 static krb5_error_code
539 tgs_make_reply(astgs_request_t r,
540 const EncTicketPart *tgt,
541 const EncryptionKey *serverkey,
542 const EncryptionKey *krbtgtkey,
543 const krb5_keyblock *sessionkey,
545 AuthorizationData *auth_data,
546 const char *tgt_realm,
548 krb5_boolean add_ticket_sig)
550 KDC_REQ_BODY *b = &r->req.req_body;
551 krb5_data *reply = r->reply;
552 KDC_REP *rep = &r->rep;
553 EncTicketPart *et = &r->et;
554 EncKDCRepPart *ek = &r->ek;
555 KDCOptions f = b->kdc_options;
559 heim_assert(r->client_princ != NULL, "invalid client name passed to tgs_make_reply");
562 rep->msg_type = krb_tgs_rep;
564 if (et->authtime == 0)
565 et->authtime = tgt->authtime;
566 _kdc_fix_time(&b->till);
567 et->endtime = min(tgt->endtime, *b->till);
568 ALLOC(et->starttime);
569 *et->starttime = kdc_time;
571 ret = check_tgs_flags(r, b, r->client_princ, tgt, et);
575 /* We should check the transited encoding if:
576 1) the request doesn't ask not to be checked
577 2) globally enforcing a check
578 3) principal requires checking
579 4) we allow non-check per-principal, but principal isn't marked as allowing this
580 5) we don't globally allow this
583 #define GLOBAL_FORCE_TRANSITED_CHECK \
584 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
585 #define GLOBAL_ALLOW_PER_PRINCIPAL \
586 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
587 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
588 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
590 /* these will consult the database in future release */
591 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
592 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
594 ret = fix_transited_encoding(r->context, r->config,
595 !f.disable_transited_check ||
596 GLOBAL_FORCE_TRANSITED_CHECK ||
597 PRINCIPAL_FORCE_TRANSITED_CHECK(r->server) ||
598 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
599 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(r->server)) ||
600 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
602 krb5_principal_get_realm(r->context, r->client_princ),
603 krb5_principal_get_realm(r->context, r->server->principal),
608 * RFC 6806 notes that names MUST NOT be changed in the response to a
609 * TGS request. Hence we ignore the setting of the canonicalize KDC
610 * option. However, for legacy interoperability we do allow the backend
611 * to override this by setting the force-canonicalize HDB flag in the
614 krb5_const_principal rsp;
616 if (r->server->flags.force_canonicalize)
617 rsp = r->server->principal;
619 rsp = r->server_princ;
621 ret = copy_Realm(&rsp->realm, &rep->ticket.realm);
623 ret = _krb5_principal2principalname(&rep->ticket.sname, rsp);
627 ret = copy_Realm(&r->client_princ->realm, &rep->crealm);
632 * RFC 8062 states "if the ticket in the TGS request is an anonymous
633 * one, the client and client realm are copied from that ticket". So
634 * whilst the TGT flag check below is superfluous, it is included in
635 * order to follow the specification to its letter.
637 if (et->flags.anonymous && !tgt->flags.anonymous)
638 _kdc_make_anonymous_principalname(&rep->cname);
640 ret = copy_PrincipalName(&r->client_princ->name, &rep->cname);
643 rep->ticket.tkt_vno = 5;
645 ek->caddr = et->caddr;
649 life = et->endtime - *et->starttime;
650 if(r->client && r->client->max_life)
651 life = min(life, *r->client->max_life);
652 if(r->server->max_life)
653 life = min(life, *r->server->max_life);
654 et->endtime = *et->starttime + life;
656 if(f.renewable_ok && tgt->flags.renewable &&
657 et->renew_till == NULL && et->endtime < *b->till &&
658 tgt->renew_till != NULL)
660 et->flags.renewable = 1;
661 ALLOC(et->renew_till);
662 *et->renew_till = *b->till;
666 renew = *et->renew_till - *et->starttime;
667 if(r->client && r->client->max_renew)
668 renew = min(renew, *r->client->max_renew);
669 if(r->server->max_renew)
670 renew = min(renew, *r->server->max_renew);
671 *et->renew_till = *et->starttime + renew;
675 *et->renew_till = min(*et->renew_till, *tgt->renew_till);
676 *et->starttime = min(*et->starttime, *et->renew_till);
677 et->endtime = min(et->endtime, *et->renew_till);
680 *et->starttime = min(*et->starttime, et->endtime);
682 if(*et->starttime == et->endtime){
683 ret = KRB5KDC_ERR_NEVER_VALID;
686 if(et->renew_till && et->endtime == *et->renew_till){
687 free(et->renew_till);
688 et->renew_till = NULL;
689 et->flags.renewable = 0;
692 et->flags.pre_authent = tgt->flags.pre_authent;
693 et->flags.hw_authent = tgt->flags.hw_authent;
694 et->flags.ok_as_delegate = r->server->flags.ok_as_delegate;
696 /* See MS-KILE 3.3.5.1 */
697 if (!r->server->flags.forwardable)
698 et->flags.forwardable = 0;
699 if (!r->server->flags.proxiable)
700 et->flags.proxiable = 0;
705 /* XXX check authdata */
707 if (et->authorization_data == NULL) {
708 et->authorization_data = calloc(1, sizeof(*et->authorization_data));
709 if (et->authorization_data == NULL) {
711 krb5_set_error_message(r->context, ret, "malloc: out of memory");
715 for(i = 0; i < auth_data->len ; i++) {
716 ret = add_AuthorizationData(et->authorization_data, &auth_data->val[i]);
718 krb5_set_error_message(r->context, ret, "malloc: out of memory");
724 ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et->key);
727 et->crealm = rep->crealm;
728 et->cname = rep->cname;
731 /* MIT must have at least one last_req */
732 ek->last_req.val = calloc(1, sizeof(*ek->last_req.val));
733 if (ek->last_req.val == NULL) {
737 ek->last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
738 ek->nonce = b->nonce;
739 ek->flags = et->flags;
740 ek->authtime = et->authtime;
741 ek->starttime = et->starttime;
742 ek->endtime = et->endtime;
743 ek->renew_till = et->renew_till;
744 ek->srealm = rep->ticket.realm;
745 ek->sname = rep->ticket.sname;
747 _kdc_log_timestamp(r, "TGS-REQ", et->authtime, et->starttime,
748 et->endtime, et->renew_till);
750 if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
751 && _kdc_is_weak_exception(r->server->principal, serverkey->keytype))
753 krb5_enctype_enable(r->context, serverkey->keytype);
757 if (r->canon_client_princ) {
760 (void) krb5_unparse_name(r->context, r->canon_client_princ, &cpn);
761 kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s",
762 cpn ? cpn : "<unknown>");
767 * For anonymous tickets, we should filter out positive authorization data
768 * that could reveal the client's identity, and return a policy error for
769 * restrictive authorization data. Policy for unknown authorization types
770 * is implementation dependent.
772 if (r->pac && !et->flags.anonymous) {
773 kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes",
777 * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
778 * buffer (legacy behavior) or if the attributes buffer indicates the
779 * AS client requested one.
781 if (_kdc_include_pac_p(r)) {
782 krb5_boolean is_tgs =
783 krb5_principal_is_krbtgt(r->context, r->server->principal);
785 ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, r->client_princ, serverkey,
786 krbtgtkey, rodc_id, NULL, r->canon_client_princ,
787 add_ticket_sig, add_ticket_sig, et,
788 is_tgs ? &r->pac_attributes : NULL);
794 ret = _kdc_finalize_reply(r);
798 /* It is somewhat unclear where the etype in the following
799 encryption should come from. What we have is a session
800 key in the passed tgt, and a list of preferred etypes
801 *for the new ticket*. Should we pick the best possible
802 etype, given the keytype in the tgt, or should we look
803 at the etype list here as well? What if the tgt
804 session key is DES3 and we want a ticket with a (say)
805 CAST session key. Should the DES3 etype be added to the
806 etype list, even if we don't want a session key with
808 ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
809 serverkey->keytype, kvno,
810 serverkey, 0, r->rk_is_subkey, reply);
812 krb5_enctype_disable(r->context, serverkey->keytype);
814 _log_astgs_req(r, serverkey->keytype);
820 static krb5_error_code
821 tgs_check_authenticator(krb5_context context,
822 krb5_kdc_configuration *config,
823 krb5_auth_context ac,
827 krb5_authenticator auth;
831 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
833 kdc_log(context, config, 2,
834 "Out of memory checking PA-TGS Authenticator");
837 if(auth->cksum == NULL){
838 kdc_log(context, config, 4, "No authenticator in request");
839 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
843 if (!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
844 kdc_log(context, config, 4, "Bad checksum type in authenticator: %d",
845 auth->cksum->cksumtype);
846 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
850 ret = krb5_crypto_init(context, key, 0, &crypto);
852 const char *msg = krb5_get_error_message(context, ret);
853 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
854 krb5_free_error_message(context, msg);
859 * RFC4120 says the checksum must be collision-proof, but it does
860 * not require it to be keyed (as the authenticator is encrypted).
862 _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
863 ret = _kdc_verify_checksum(context,
865 KRB5_KU_TGS_REQ_AUTH_CKSUM,
868 krb5_crypto_destroy(context, crypto);
870 const char *msg = krb5_get_error_message(context, ret);
871 kdc_log(context, config, 4,
872 "Failed to verify authenticator checksum: %s", msg);
873 krb5_free_error_message(context, msg);
876 free_Authenticator(auth);
882 need_referral(krb5_context context, krb5_kdc_configuration *config,
883 const KDCOptions * const options, krb5_principal server,
888 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
891 if (server->name.name_string.len == 1)
892 name = server->name.name_string.val[0];
893 else if (server->name.name_string.len > 1)
894 name = server->name.name_string.val[1];
898 kdc_log(context, config, 5, "Searching referral for %s", name);
900 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
903 static krb5_error_code
904 validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
909 krb5_data_zero(&data);
911 if (!r->config->enable_fast)
914 ret = _krb5_get_ad(r->context, auth_data, NULL,
915 KRB5_AUTHDATA_FX_FAST_USED, &data);
917 r->fast_asserted = 1;
918 krb5_data_free(&data);
921 ret = _krb5_get_ad(r->context, auth_data, NULL,
922 KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
924 kdc_log(r->context, r->config, 2,
925 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
926 krb5_data_free(&data);
927 return KRB5KRB_AP_ERR_BAD_INTEGRITY;
933 static krb5_error_code
934 tgs_parse_request(astgs_request_t r,
935 const PA_DATA *tgs_req,
936 krb5_enctype *krbtgt_etype,
938 const struct sockaddr *from_addr,
942 krb5_kdc_configuration *config = r->config;
943 KDC_REQ_BODY *b = &r->req.req_body;
944 static char failed[] = "<unparse_name failed>";
947 krb5_principal princ;
948 krb5_auth_context ac = NULL;
949 krb5_flags ap_req_options;
950 krb5_flags verify_ap_req_flags = 0;
951 krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
952 krb5uint32 krbtgt_kvno_try;
953 int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
954 const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
956 krb5_keyblock *subkey = NULL;
961 memset(&ap_req, 0, sizeof(ap_req));
962 ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req);
964 const char *msg = krb5_get_error_message(r->context, ret);
965 kdc_log(r->context, config, 4, "Failed to decode AP-REQ: %s", msg);
966 krb5_free_error_message(r->context, msg);
970 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
971 /* XXX check for ticket.sname == req.sname */
972 kdc_log(r->context, config, 4, "PA-DATA is not a ticket-granting ticket");
973 ret = KRB5KDC_ERR_POLICY; /* ? */
977 _krb5_principalname2krb5_principal(r->context,
980 ap_req.ticket.realm);
982 krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
983 ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT,
984 &krbtgt_kvno, &r->krbtgtdb, &r->krbtgt);
986 if (ret == HDB_ERR_NOT_FOUND_HERE) {
987 /* XXX Factor out this unparsing of the same princ all over */
989 ret = krb5_unparse_name(r->context, princ, &p);
992 krb5_free_principal(r->context, princ);
993 kdc_log(r->context, config, 5,
994 "Ticket-granting ticket account %s does not have secrets at "
995 "this KDC, need to proxy", p);
998 ret = HDB_ERR_NOT_FOUND_HERE;
1000 } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1002 ret = krb5_unparse_name(r->context, princ, &p);
1005 krb5_free_principal(r->context, princ);
1006 kdc_log(r->context, config, 5,
1007 "Ticket-granting ticket account %s does not have keys for "
1008 "kvno %d at this KDC", p, krbtgt_kvno);
1011 ret = HDB_ERR_KVNO_NOT_FOUND;
1013 } else if (ret == HDB_ERR_NO_MKEY) {
1015 ret = krb5_unparse_name(r->context, princ, &p);
1018 krb5_free_principal(r->context, princ);
1019 kdc_log(r->context, config, 5,
1020 "Missing master key for decrypting keys for ticket-granting "
1021 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1024 ret = HDB_ERR_KVNO_NOT_FOUND;
1027 const char *msg = krb5_get_error_message(r->context, ret);
1029 ret = krb5_unparse_name(r->context, princ, &p);
1032 kdc_log(r->context, config, 4,
1033 "Ticket-granting ticket %s not found in database: %s", p, msg);
1034 krb5_free_principal(r->context, princ);
1035 krb5_free_error_message(r->context, msg);
1038 ret = KRB5KRB_AP_ERR_NOT_US;
1042 krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : r->krbtgt->kvno;
1043 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1046 krbtgt_keys = hdb_kvno2keys(r->context, r->krbtgt, krbtgt_kvno_try);
1047 ret = hdb_enctype2key(r->context, r->krbtgt, krbtgt_keys,
1048 ap_req.ticket.enc_part.etype, &tkey);
1049 if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1050 kvno_search_tries--;
1054 char *str = NULL, *p = NULL;
1056 /* We should implement the MIT `trace_format()' concept */
1057 (void) krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str);
1058 (void) krb5_unparse_name(r->context, princ, &p);
1059 kdc_log(r->context, config, 4,
1060 "No server key with enctype %s found for %s",
1061 str ? str : "<unknown enctype>",
1062 p ? p : "<unparse_name failed>");
1065 ret = KRB5KRB_AP_ERR_BADKEYVER;
1069 if (b->kdc_options.validate)
1070 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1072 if (r->config->warn_ticket_addresses)
1073 verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS;
1075 ret = krb5_verify_ap_req2(r->context,
1080 verify_ap_req_flags,
1083 KRB5_KU_TGS_REQ_AUTH);
1084 if (r->ticket && r->ticket->ticket.caddr)
1085 kdc_audit_addaddrs((kdc_request_t)r, r->ticket->ticket.caddr, "tixaddrs");
1086 if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR &&
1087 r->ticket != NULL) {
1088 kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE);
1091 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1092 kvno_search_tries--;
1097 krb5_free_principal(r->context, princ);
1099 const char *msg = krb5_get_error_message(r->context, ret);
1100 kdc_log(r->context, config, 4, "Failed to verify AP-REQ: %s", msg);
1101 krb5_free_error_message(r->context, msg);
1105 r->ticket_key = tkey;
1108 krb5_authenticator auth;
1110 ret = krb5_auth_con_getauthenticator(r->context, ac, &auth);
1112 *csec = malloc(sizeof(**csec));
1113 if (*csec == NULL) {
1114 krb5_free_authenticator(r->context, &auth);
1115 kdc_log(r->context, config, 4, "malloc failed");
1118 **csec = auth->ctime;
1119 *cusec = malloc(sizeof(**cusec));
1120 if (*cusec == NULL) {
1121 krb5_free_authenticator(r->context, &auth);
1122 kdc_log(r->context, config, 4, "malloc failed");
1125 **cusec = auth->cusec;
1127 ret = validate_fast_ad(r, auth->authorization_data);
1128 krb5_free_authenticator(r->context, &auth);
1134 ret = tgs_check_authenticator(r->context, config, ac, b, &r->ticket->ticket.key);
1136 krb5_auth_con_free(r->context, ac);
1140 r->rk_is_subkey = 1;
1142 ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
1144 const char *msg = krb5_get_error_message(r->context, ret);
1145 krb5_auth_con_free(r->context, ac);
1146 kdc_log(r->context, config, 4, "Failed to get remote subkey: %s", msg);
1147 krb5_free_error_message(r->context, msg);
1151 r->rk_is_subkey = 0;
1153 ret = krb5_auth_con_getkey(r->context, ac, &subkey);
1155 const char *msg = krb5_get_error_message(r->context, ret);
1156 krb5_auth_con_free(r->context, ac);
1157 kdc_log(r->context, config, 4, "Failed to get session key: %s", msg);
1158 krb5_free_error_message(r->context, msg);
1163 krb5_auth_con_free(r->context, ac);
1164 kdc_log(r->context, config, 4,
1165 "Failed to get key for enc-authorization-data");
1166 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1170 krb5_free_keyblock_contents(r->context, &r->reply_key);
1171 ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
1172 krb5_free_keyblock(r->context, subkey);
1176 krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
1177 if (b->enc_authorization_data) {
1178 ret = krb5_copy_keyblock_contents(r->context,
1185 ret = validate_fast_ad(r, r->ticket->ticket.authorization_data);
1191 * Check for FAST request
1194 ret = _kdc_fast_unwrap_request(r, r->ticket, ac);
1198 krb5_auth_con_free(r->context, ac);
1201 free_AP_REQ(&ap_req);
1206 static krb5_error_code
1207 build_server_referral(krb5_context context,
1208 krb5_kdc_configuration *config,
1209 krb5_crypto session,
1210 krb5_const_realm referred_realm,
1211 const PrincipalName *true_principal_name,
1212 const PrincipalName *requested_principal,
1215 PA_ServerReferralData ref;
1216 krb5_error_code ret;
1221 memset(&ref, 0, sizeof(ref));
1223 if (referred_realm) {
1224 ALLOC(ref.referred_realm);
1225 if (ref.referred_realm == NULL)
1227 *ref.referred_realm = strdup(referred_realm);
1228 if (*ref.referred_realm == NULL)
1231 if (true_principal_name) {
1232 ALLOC(ref.true_principal_name);
1233 if (ref.true_principal_name == NULL)
1235 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1239 if (requested_principal) {
1240 ALLOC(ref.requested_principal_name);
1241 if (ref.requested_principal_name == NULL)
1243 ret = copy_PrincipalName(requested_principal,
1244 ref.requested_principal_name);
1249 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1250 data.data, data.length,
1252 free_PA_ServerReferralData(&ref);
1255 if (data.length != size)
1256 krb5_abortx(context, "internal asn.1 encoder error");
1258 ret = krb5_encrypt_EncryptedData(context, session,
1259 KRB5_KU_PA_SERVER_REFERRAL,
1260 data.data, data.length,
1266 ASN1_MALLOC_ENCODE(EncryptedData,
1267 outdata->data, outdata->length,
1269 free_EncryptedData(&ed);
1272 if (outdata->length != size)
1273 krb5_abortx(context, "internal asn.1 encoder error");
1277 free_PA_ServerReferralData(&ref);
1278 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1283 * This function is intended to be used when failure to find the client is
1287 _kdc_db_fetch_client(krb5_context context,
1288 krb5_kdc_configuration *config,
1292 const char *krbtgt_realm,
1294 hdb_entry **client_out)
1296 krb5_error_code ret;
1297 hdb_entry *client = NULL;
1302 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1303 NULL, clientdb, &client);
1304 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1306 * This is OK, we are just trying to find out if they have
1307 * been disabled or deleted in the meantime; missing secrets
1312 * If the client belongs to the same realm as our TGS, it
1313 * should exist in the local database.
1317 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1318 if (ret == HDB_ERR_NOENTRY)
1319 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1320 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1324 msg = krb5_get_error_message(context, ret);
1325 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1326 krb5_free_error_message(context, msg);
1327 } else if (client->flags.invalid || !client->flags.client) {
1328 kdc_log(context, config, 4, "Client has invalid bit set");
1329 _kdc_free_ent(context, *clientdb, client);
1330 return KRB5KDC_ERR_POLICY;
1333 *client_out = client;
1338 static krb5_error_code
1339 tgs_build_reply(astgs_request_t priv,
1340 krb5_enctype krbtgt_etype,
1341 const struct sockaddr *from_addr)
1343 krb5_context context = priv->context;
1344 krb5_kdc_configuration *config = priv->config;
1345 KDC_REQ_BODY *b = &priv->req.req_body;
1346 const char *from = priv->from;
1347 krb5_error_code ret, ret2;
1348 krb5_principal krbtgt_out_principal = NULL;
1349 krb5_principal user2user_princ = NULL;
1350 char *spn = NULL, *cpn = NULL, *krbtgt_out_n = NULL;
1351 char *user2user_name = NULL;
1352 HDB *user2user_krbtgtdb;
1353 hdb_entry *user2user_krbtgt = NULL;
1354 HDB *clientdb = NULL;
1355 HDB *serverdb = NULL;
1356 krb5_realm ref_realm = NULL;
1357 EncTicketPart *tgt = &priv->ticket->ticket;
1358 const EncryptionKey *ekey;
1359 krb5_keyblock sessionkey;
1361 krb5_pac user2user_pac = NULL;
1363 krb5_boolean add_ticket_sig = FALSE;
1364 const char *tgt_realm = /* Realm of TGT issuer */
1365 krb5_principal_get_realm(context, priv->krbtgt->principal);
1366 const char *our_realm = /* Realm of this KDC */
1367 krb5_principal_get_comp_string(context, priv->krbtgt->principal, 1);
1368 char **capath = NULL;
1369 size_t num_capath = 0;
1370 AuthorizationData *auth_data = NULL;
1373 hdb_entry *krbtgt_out = NULL;
1377 EncTicketPart adtkt;
1379 krb5_boolean kdc_issued = FALSE;
1382 int flags = HDB_F_FOR_TGS_REQ;
1386 const PA_DATA *for_user = NULL;
1387 int for_user_idx = 0;
1389 memset(&sessionkey, 0, sizeof(sessionkey));
1390 memset(&adtkt, 0, sizeof(adtkt));
1396 * The canonicalize KDC option is passed as a hint to the backend, but
1397 * can typically be ignored. Per RFC 6806, names are not canonicalized
1398 * in response to a TGS request (although we make an exception, see
1399 * force-canonicalize below).
1401 if (b->kdc_options.canonicalize)
1402 flags |= HDB_F_CANON;
1405 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1406 _kdc_set_const_e_text(priv, "No server in request");
1410 _krb5_principalname2krb5_principal(context, &priv->server_princ, *s, r);
1411 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1415 _krb5_principalname2krb5_principal(context, &priv->client_princ,
1416 tgt->cname, tgt->crealm);
1417 ret = krb5_unparse_name(context, priv->client_princ, &priv->cname);
1421 result = unparse_flags(KDCOptions2int(b->kdc_options),
1422 asn1_KDCOptions_units(),
1423 opt_str, sizeof(opt_str));
1425 kdc_log(context, config, 4,
1426 "TGS-REQ %s from %s for %s [%s]",
1427 cpn, from, spn, opt_str);
1429 kdc_log(context, config, 4,
1430 "TGS-REQ %s from %s for %s", cpn, from, spn);
1438 _kdc_free_ent(context, serverdb, priv->server);
1439 priv->server = NULL;
1440 ret = _kdc_db_fetch(context, config, priv->server_princ,
1441 HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags,
1442 NULL, &serverdb, &priv->server);
1443 priv->serverdb = serverdb;
1444 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1445 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn);
1446 kdc_audit_addreason((kdc_request_t)priv, "Target not found here");
1448 } else if (ret == HDB_ERR_WRONG_REALM) {
1450 ref_realm = strdup(priv->server->principal->realm);
1451 if (ref_realm == NULL) {
1452 ret = krb5_enomem(context);
1456 kdc_log(context, config, 4,
1457 "Returning a referral to realm %s for "
1460 krb5_free_principal(context, priv->server_princ);
1461 priv->server_princ = NULL;
1462 ret = krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
1468 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1475 const char *new_rlm, *msg;
1479 priv->error_code = ret; /* advise policy plugin of failure reason */
1480 ret2 = _kdc_referral_policy(priv);
1482 krb5_xfree(priv->sname);
1484 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1488 } else if (ret2 != KRB5_PLUGIN_NO_HANDLE) {
1490 } else if ((req_rlm = get_krbtgt_realm(&priv->server_princ->name)) != NULL) {
1491 if (capath == NULL) {
1492 /* With referalls, hierarchical capaths are always enabled */
1493 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1494 req_rlm, TRUE, &capath, &num_capath);
1497 kdc_audit_addreason((kdc_request_t)priv,
1498 "No trusted path from client realm to ours");
1502 new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1504 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1505 "realm %s not found, trying %s", tgt->crealm,
1506 our_realm, req_rlm, new_rlm);
1509 ref_realm = strdup(new_rlm);
1510 if (ref_realm == NULL) {
1511 ret = krb5_enomem(context);
1515 krb5_free_principal(context, priv->server_princ);
1516 priv->server_princ = NULL;
1517 krb5_make_principal(context, &priv->server_princ, r,
1518 KRB5_TGS_NAME, ref_realm, NULL);
1521 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1527 } else if (need_referral(context, config, &b->kdc_options, priv->server_princ, &realms)) {
1528 if (strcmp(realms[0], priv->server_princ->realm) != 0) {
1529 kdc_log(context, config, 4,
1530 "Returning a referral to realm %s for "
1531 "server %s that was not found",
1533 krb5_free_principal(context, priv->server_princ);
1534 priv->server_princ = NULL;
1535 krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
1539 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
1541 krb5_free_host_realm(context, realms);
1547 ref_realm = strdup(realms[0]);
1549 krb5_free_host_realm(context, realms);
1552 krb5_free_host_realm(context, realms);
1554 msg = krb5_get_error_message(context, ret);
1555 kdc_log(context, config, 3,
1556 "Server not found in database: %s: %s", spn, msg);
1557 krb5_free_error_message(context, msg);
1558 if (ret == HDB_ERR_NOENTRY)
1559 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1560 kdc_audit_addreason((kdc_request_t)priv,
1561 "Service principal unknown");
1566 * Now refetch the primary krbtgt, and get the current kvno (the
1567 * sign check may have been on an old kvno, and the server may
1568 * have been an incoming trust)
1571 ret = krb5_make_principal(context,
1572 &krbtgt_out_principal,
1578 kdc_log(context, config, 4,
1579 "Failed to make krbtgt principal name object for "
1580 "authz-data signatures");
1583 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1585 kdc_log(context, config, 4,
1586 "Failed to make krbtgt principal name object for "
1587 "authz-data signatures");
1591 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1592 HDB_F_GET_KRBTGT, NULL, &krbtgt_outdb, &krbtgt_out);
1595 ret = krb5_unparse_name(context, priv->krbtgt->principal, &ktpn);
1596 kdc_log(context, config, 4,
1597 "No such principal %s (needed for authz-data signature keys) "
1598 "while processing TGS-REQ for service %s with krbtgt %s",
1599 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1601 ret = KRB5KRB_AP_ERR_NOT_US;
1606 * Select enctype, return key and kvno.
1612 if(b->kdc_options.enc_tkt_in_skey) {
1616 krb5uint32 second_kvno = 0;
1617 krb5uint32 *kvno_ptr = NULL;
1620 hdb_entry *user2user_client = NULL;
1621 krb5_boolean user2user_kdc_issued = FALSE;
1624 if(b->additional_tickets == NULL ||
1625 b->additional_tickets->len == 0){
1626 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1627 kdc_log(context, config, 4,
1628 "No second ticket present in user-to-user request");
1629 kdc_audit_addreason((kdc_request_t)priv,
1630 "No second ticket present in user-to-user request");
1633 t = &b->additional_tickets->val[0];
1634 if(!get_krbtgt_realm(&t->sname)){
1635 kdc_log(context, config, 4,
1636 "Additional ticket is not a ticket-granting ticket");
1637 kdc_audit_addreason((kdc_request_t)priv,
1638 "Additional ticket is not a ticket-granting ticket");
1639 ret = KRB5KDC_ERR_POLICY;
1642 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1646 ret = krb5_unparse_name(context, p, &tpn);
1649 if(t->enc_part.kvno){
1650 second_kvno = *t->enc_part.kvno;
1651 kvno_ptr = &second_kvno;
1653 ret = _kdc_db_fetch(context, config, p,
1654 HDB_F_GET_KRBTGT, kvno_ptr,
1655 &user2user_krbtgtdb, &user2user_krbtgt);
1656 krb5_free_principal(context, p);
1658 if (ret == HDB_ERR_NOENTRY)
1659 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1660 kdc_audit_addreason((kdc_request_t)priv,
1661 "User-to-user service principal (TGS) unknown");
1665 ret = hdb_enctype2key(context, user2user_krbtgt, NULL,
1666 t->enc_part.etype, &uukey);
1668 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1669 kdc_audit_addreason((kdc_request_t)priv,
1670 "User-to-user enctype not supported");
1674 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1676 kdc_audit_addreason((kdc_request_t)priv,
1677 "User-to-user TGT decrypt failure");
1682 ret = _kdc_verify_flags(context, config, &adtkt, tpn);
1684 kdc_audit_addreason((kdc_request_t)priv,
1685 "User-to-user TGT expired or invalid");
1691 /* Fetch the name from the TGT. */
1692 ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1693 adtkt.cname, adtkt.crealm);
1697 ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1702 * Look up the name given in the TGT in the database. The user
1703 * claims to have a ticket-granting-ticket to our KDC, so we should
1704 * fail hard if we can't find the user - otherwise we can't do
1707 ret = _kdc_db_fetch(context, config, user2user_princ,
1708 HDB_F_GET_CLIENT | flags,
1709 NULL, &user2user_db, &user2user_client);
1710 if (ret == HDB_ERR_NOENTRY)
1711 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1716 * The account is present in the database, now check the
1719 * We check this as a client (because the purpose of
1720 * user2user is that the server flag is not set, because
1721 * the long-term key is not strong, but this does mean
1722 * that a client with an expired password can't get accept
1723 * a user2user ticket.
1725 ret = kdc_check_flags(priv,
1730 _kdc_free_ent(context, user2user_db, user2user_client);
1735 * Also check that the account is the same one specified in the
1738 ret = _kdc_check_client_matches_target_service(context,
1745 _kdc_free_ent(context, user2user_db, user2user_client);
1749 /* Verify the PAC of the TGT. */
1750 ret = _kdc_check_pac(priv, user2user_princ, NULL,
1751 user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
1752 &uukey->key, &priv->ticket_key->key, &adtkt,
1753 &user2user_kdc_issued, &user2user_pac, NULL, NULL);
1754 _kdc_free_ent(context, user2user_db, user2user_client);
1756 const char *msg = krb5_get_error_message(context, ret);
1757 kdc_log(context, config, 0,
1758 "Verify PAC failed for %s (%s) from %s with %s",
1759 spn, user2user_name, from, msg);
1760 krb5_free_error_message(context, msg);
1764 if ((config->require_pac && !user2user_pac)
1765 || (user2user_pac && !user2user_kdc_issued))
1767 ret = KRB5KDC_ERR_BADOPTION;
1768 kdc_log(context, config, 0,
1769 "Ticket not signed with PAC; user-to-user failed (%s).",
1770 user2user_pac ? "Ticket unsigned" : "No PAC");
1775 for(i = 0; i < b->etype.len; i++)
1776 if (b->etype.val[i] == adtkt.key.keytype)
1778 if(i == b->etype.len) {
1779 kdc_log(context, config, 4,
1780 "Addition ticket have not matching etypes");
1781 krb5_clear_error_message(context);
1782 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1783 kdc_audit_addreason((kdc_request_t)priv,
1784 "No matching enctypes for 2nd ticket");
1787 etype = b->etype.val[i];
1792 ret = _kdc_find_session_etype(priv, b->etype.val, b->etype.len,
1793 priv->server, &etype);
1795 kdc_log(context, config, 4,
1796 "Server (%s) has no support for etypes", spn);
1797 kdc_audit_addreason((kdc_request_t)priv,
1798 "Enctype not supported");
1801 ret = _kdc_get_preferred_key(context, config, priv->server, spn,
1804 kdc_log(context, config, 4,
1805 "Server (%s) has no supported etypes", spn);
1806 kdc_audit_addreason((kdc_request_t)priv,
1807 "Enctype not supported");
1811 kvno = priv->server->kvno;
1814 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1820 * Check that service is in the same realm as the krbtgt. If it's
1821 * not the same, it's someone that is using a uni-directional trust
1826 * The first realm is the realm of the service, the second is
1827 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1828 * encrypted to. The redirection via the krbtgt_out entry allows
1829 * the DB to possibly correct the case of the realm (Samba4 does
1830 * this) before the strcmp()
1832 if (strcmp(krb5_principal_get_realm(context, priv->server->principal),
1833 krb5_principal_get_realm(context, krbtgt_out->principal)) != 0) {
1835 ret = krb5_unparse_name(context, krbtgt_out->principal, &ktpn);
1836 kdc_log(context, config, 4,
1837 "Request with wrong krbtgt: %s",
1838 (ret == 0) ? ktpn : "<unknown>");
1841 ret = KRB5KRB_AP_ERR_NOT_US;
1842 kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT");
1846 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1849 kdc_log(context, config, 4,
1850 "Failed to find key for krbtgt PAC signature");
1851 kdc_audit_addreason((kdc_request_t)priv,
1852 "Failed to find key for krbtgt PAC signature");
1855 ret = hdb_enctype2key(context, krbtgt_out, NULL,
1856 tkey_sign->key.keytype, &tkey_sign);
1858 kdc_log(context, config, 4,
1859 "Failed to find key for krbtgt PAC signature");
1860 kdc_audit_addreason((kdc_request_t)priv,
1861 "Failed to find key for krbtgt PAC signature");
1865 if (_kdc_synthetic_princ_used_p(context, priv->ticket))
1866 flags |= HDB_F_SYNTHETIC_OK;
1868 ret = _kdc_db_fetch_client(context, config, flags, priv->client_princ,
1869 cpn, our_realm, &clientdb, &priv->client);
1872 /* flags &= ~HDB_F_SYNTHETIC_OK; */ /* `flags' is not used again below */
1873 priv->clientdb = clientdb;
1875 /* Validate armor TGT before potentially including device claims */
1876 if (priv->armor_ticket) {
1877 ret = _kdc_fast_check_armor_pac(priv, HDB_F_FOR_TGS_REQ);
1882 ret = _kdc_check_pac(priv, priv->client_princ, NULL,
1883 priv->client, priv->server,
1884 priv->krbtgt, priv->krbtgt,
1885 &priv->ticket_key->key, &priv->ticket_key->key, tgt,
1886 &kdc_issued, &priv->pac, &priv->canon_client_princ,
1887 &priv->pac_attributes);
1889 const char *msg = krb5_get_error_message(context, ret);
1890 kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
1891 kdc_log(context, config, 4,
1892 "Verify PAC failed for %s (%s) from %s with %s",
1893 spn, cpn, from, msg);
1894 krb5_free_error_message(context, msg);
1903 * Services for User: protocol transition and constrained delegation
1906 if (priv->client != NULL &&
1907 (for_user = _kdc_find_padata(&priv->req,
1909 KRB5_PADATA_FOR_USER)) != NULL)
1911 /* Process an S4U2Self request. */
1912 ret = _kdc_validate_protocol_transition(priv, for_user);
1915 } else if (priv->client != NULL
1916 && b->additional_tickets != NULL
1917 && b->additional_tickets->len != 0
1918 && b->kdc_options.cname_in_addl_tkt
1919 && b->kdc_options.enc_tkt_in_skey == 0)
1921 /* Process an S4U2Proxy request. */
1922 ret = _kdc_validate_constrained_delegation(priv);
1925 } else if (priv->pac != NULL) {
1926 ret = _kdc_pac_update(priv, priv->client_princ, NULL,
1927 priv->client, priv->server, priv->krbtgt,
1929 if (ret == KRB5_PLUGIN_NO_HANDLE) {
1933 const char *msg = krb5_get_error_message(context, ret);
1934 kdc_audit_addreason((kdc_request_t)priv, "PAC update failed");
1935 kdc_log(context, config, 4,
1936 "Update PAC failed for %s (%s) from %s with %s",
1937 spn, cpn, from, msg);
1938 krb5_free_error_message(context, msg);
1942 if (priv->pac == NULL) {
1943 /* the plugin may indicate no PAC should be generated */
1944 priv->pac_attributes = 0;
1948 if (b->enc_authorization_data) {
1949 unsigned auth_data_usage;
1953 if (priv->rk_is_subkey != 0) {
1954 auth_data_usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1956 auth_data_usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1959 ret = krb5_crypto_init(context, &priv->enc_ad_key, 0, &crypto);
1961 const char *msg = krb5_get_error_message(context, ret);
1962 kdc_audit_addreason((kdc_request_t)priv,
1963 "krb5_crypto_init() failed for "
1964 "enc_authorization_data");
1965 kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
1966 krb5_free_error_message(context, msg);
1969 ret = krb5_decrypt_EncryptedData(context,
1972 b->enc_authorization_data,
1974 krb5_crypto_destroy(context, crypto);
1976 kdc_audit_addreason((kdc_request_t)priv,
1977 "Failed to decrypt enc-authorization-data");
1978 kdc_log(context, config, 4,
1979 "Failed to decrypt enc-authorization-data");
1980 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1984 if (auth_data == NULL) {
1985 krb5_data_free(&ad);
1986 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1989 ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
1990 krb5_data_free(&ad);
1994 kdc_audit_addreason((kdc_request_t)priv,
1995 "Failed to decode authorization data");
1996 kdc_log(context, config, 4, "Failed to decode authorization data");
1997 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
2006 ret = kdc_check_flags(priv, FALSE, priv->client, priv->server);
2010 if((b->kdc_options.validate || b->kdc_options.renew) &&
2011 !krb5_principal_compare(context,
2012 priv->krbtgt->principal,
2013 priv->server->principal)){
2014 kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request");
2015 kdc_log(context, config, 4, "Inconsistent request.");
2016 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2020 /* check for valid set of addresses */
2021 if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) {
2022 if (config->check_ticket_addresses) {
2023 ret = KRB5KRB_AP_ERR_BADADDR;
2024 kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
2025 kdc_log(context, config, 4, "Request from wrong address");
2026 kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address");
2028 } else if (config->warn_ticket_addresses) {
2029 kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
2033 /* check local and per-principal anonymous ticket issuance policy */
2034 if (is_anon_tgs_request_p(b, tgt)) {
2035 ret = _kdc_check_anon_policy(priv);
2041 * If this is an referral, add server referral data to the
2048 kdc_log(context, config, 3,
2049 "Adding server referral to %s", ref_realm);
2051 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2055 ret = build_server_referral(context, config, crypto, ref_realm,
2056 NULL, s, &pa.padata_value);
2057 krb5_crypto_destroy(context, crypto);
2059 kdc_audit_addreason((kdc_request_t)priv, "Referral build failed");
2060 kdc_log(context, config, 4,
2061 "Failed building server referral");
2064 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2066 ret = add_METHOD_DATA(priv->rep.padata, &pa);
2067 krb5_data_free(&pa.padata_value);
2069 kdc_log(context, config, 4,
2070 "Add server referral METHOD-DATA failed");
2076 * Only add ticket signature if the requested server is not krbtgt, and
2077 * either the header server is krbtgt or, in the case of renewal/validation
2078 * if it was signed with PAC ticket signature and we verified it.
2079 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2080 * change one day (see issue #763) so make sure to check for it.
2084 !krb5_principal_is_krbtgt(context, priv->server->principal)) {
2086 add_ticket_sig = TRUE;
2090 * Active-Directory implementations use the high part of the kvno as the
2091 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2094 rodc_id = krbtgt_out->kvno >> 16;
2100 ret = tgs_make_reply(priv,
2112 free(user2user_name);
2114 _krb5_free_capath(context, capath);
2116 krb5_free_keyblock_contents(context, &sessionkey);
2118 _kdc_free_ent(context, krbtgt_outdb, krbtgt_out);
2119 if(user2user_krbtgt)
2120 _kdc_free_ent(context, user2user_krbtgtdb, user2user_krbtgt);
2122 krb5_free_principal(context, user2user_princ);
2123 krb5_free_principal(context, krbtgt_out_principal);
2127 free_AuthorizationData(auth_data);
2131 free_EncTicketPart(&adtkt);
2133 krb5_pac_free(context, user2user_pac);
2143 _kdc_tgs_rep(astgs_request_t r)
2145 krb5_kdc_configuration *config = r->config;
2146 KDC_REQ *req = &r->req;
2147 krb5_data *data = r->reply;
2148 const char *from = r->from;
2149 struct sockaddr *from_addr = r->addr;
2150 int datagram_reply = r->datagram_reply;
2151 krb5_error_code ret;
2153 const PA_DATA *tgs_req, *pa;
2154 krb5_enctype krbtgt_etype = ETYPE_NULL;
2156 time_t *csec = NULL;
2161 if(req->padata == NULL){
2162 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2163 kdc_log(r->context, config, 4,
2164 "TGS-REQ from %s without PA-DATA", from);
2169 pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
2171 kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2172 ret = KRB5KRB_ERR_GENERIC;
2177 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2178 if(tgs_req == NULL){
2179 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2181 kdc_log(r->context, config, 4,
2182 "TGS-REQ from %s without PA-TGS-REQ", from);
2185 ret = tgs_parse_request(r, tgs_req,
2189 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2190 /* kdc_log() is called in tgs_parse_request() */
2194 kdc_log(r->context, config, 4,
2195 "Failed parsing TGS-REQ from %s", from);
2199 ret = _kdc_fast_strengthen_reply_key(r);
2203 ALLOC(r->rep.padata);
2204 if (r->rep.padata == NULL) {
2206 krb5_set_error_message(r->context, ret, N_("malloc: out of memory", ""));
2210 ret = tgs_build_reply(r,
2214 kdc_log(r->context, config, 4,
2215 "Failed building TGS-REP to %s", from);
2220 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2221 krb5_data_free(data);
2222 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2223 _kdc_set_const_e_text(r, "Reply packet too large");
2228 /* Overwrite ‘error_code’ only if we have an actual error. */
2229 r->error_code = ret;
2232 krb5_error_code ret2 = _kdc_audit_request(r);
2234 krb5_data_free(data);
2239 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2240 METHOD_DATA error_method = { 0, NULL };
2242 kdc_log(r->context, config, 5, "tgs-req: sending error: %d to client", ret);
2243 ret = _kdc_fast_mk_error(r,
2247 r->error_code ? r->error_code : ret,
2248 r->client_princ ? r->client_princ :(r->ticket != NULL ? r->ticket->client : NULL),
2249 r->server_princ ? r->server_princ :(r->ticket != NULL ? r->ticket->server : NULL),
2252 free_METHOD_DATA(&error_method);
2257 free_TGS_REP(&r->rep);
2258 free_TransitedEncoding(&r->et.transited);
2259 free(r->et.starttime);
2260 free(r->et.renew_till);
2261 if(r->et.authorization_data) {
2262 free_AuthorizationData(r->et.authorization_data);
2263 free(r->et.authorization_data);
2265 free_LastReq(&r->ek.last_req);
2266 if (r->et.key.keyvalue.data) {
2267 memset_s(r->et.key.keyvalue.data, 0, r->et.key.keyvalue.length,
2268 r->et.key.keyvalue.length);
2270 free_EncryptionKey(&r->et.key);
2272 if (r->canon_client_princ) {
2273 krb5_free_principal(r->context, r->canon_client_princ);
2274 r->canon_client_princ = NULL;
2276 if (r->armor_crypto) {
2277 krb5_crypto_destroy(r->context, r->armor_crypto);
2278 r->armor_crypto = NULL;
2280 if (r->armor_ticket)
2281 krb5_free_ticket(r->context, r->armor_ticket);
2282 if (r->armor_server)
2283 _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server);
2284 if (r->armor_client)
2285 _kdc_free_ent(r->context,
2289 krb5_pac_free(r->context, r->armor_pac);
2290 krb5_free_keyblock_contents(r->context, &r->reply_key);
2291 krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
2292 krb5_free_keyblock_contents(r->context, &r->strengthen_key);
2295 krb5_free_ticket(r->context, r->ticket);
2297 _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt);
2300 _kdc_free_ent(r->context, r->clientdb, r->client);
2301 krb5_free_principal(r->context, r->client_princ);
2303 _kdc_free_ent(r->context, r->serverdb, r->server);
2304 krb5_free_principal(r->context, r->server_princ);
2305 _kdc_free_fast_state(&r->fast);
2306 krb5_pac_free(r->context, r->pac);