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];
54 static krb5_error_code
55 check_PAC(krb5_context context,
56 krb5_kdc_configuration *config,
57 const krb5_principal client_principal,
58 const krb5_principal delegated_proxy_principal,
62 hdb_entry_ex *ticket_server,
63 const EncryptionKey *server_check_key,
64 const EncryptionKey *krbtgt_check_key,
66 krb5_boolean *kdc_issued,
71 krb5_boolean signedticket;
76 ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
77 if (ret || pac == NULL)
80 /* Verify the server signature. */
81 ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
82 server_check_key, NULL);
84 krb5_pac_free(context, pac);
88 /* Verify the KDC signatures. */
89 ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal,
90 client, server, krbtgt, &pac);
91 if (ret == KRB5_PLUGIN_NO_HANDLE) {
93 * We can't verify the KDC signatures if the ticket was issued by
94 * another realm's KDC.
96 if (krb5_realm_compare(context, server->entry.principal,
97 ticket_server->entry.principal)) {
98 ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
101 krb5_pac_free(context, pac);
105 /* Discard the PAC if the plugin didn't handle it */
106 krb5_pac_free(context, pac);
107 ret = krb5_pac_init(context, &pac);
111 krb5_pac_free(context, pac);
115 *kdc_issued = signedticket ||
116 krb5_principal_is_krbtgt(context,
117 ticket_server->entry.principal);
127 static krb5_error_code
128 check_tgs_flags(krb5_context context,
129 krb5_kdc_configuration *config,
130 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
132 KDCOptions f = b->kdc_options;
135 if(!tgt->flags.invalid || tgt->starttime == NULL){
136 kdc_log(context, config, 0,
137 "Bad request to validate ticket");
138 return KRB5KDC_ERR_BADOPTION;
140 if(*tgt->starttime > kdc_time){
141 kdc_log(context, config, 0,
142 "Early request to validate ticket");
143 return KRB5KRB_AP_ERR_TKT_NYV;
146 et->flags.invalid = 0;
147 }else if(tgt->flags.invalid){
148 kdc_log(context, config, 0,
149 "Ticket-granting ticket has INVALID flag set");
150 return KRB5KRB_AP_ERR_TKT_INVALID;
154 if(!tgt->flags.forwardable){
155 kdc_log(context, config, 0,
156 "Bad request for forwardable ticket");
157 return KRB5KDC_ERR_BADOPTION;
159 et->flags.forwardable = 1;
162 if(!tgt->flags.forwardable){
163 kdc_log(context, config, 0,
164 "Request to forward non-forwardable ticket");
165 return KRB5KDC_ERR_BADOPTION;
167 et->flags.forwarded = 1;
168 et->caddr = b->addresses;
170 if(tgt->flags.forwarded)
171 et->flags.forwarded = 1;
174 if(!tgt->flags.proxiable){
175 kdc_log(context, config, 0,
176 "Bad request for proxiable ticket");
177 return KRB5KDC_ERR_BADOPTION;
179 et->flags.proxiable = 1;
182 if(!tgt->flags.proxiable){
183 kdc_log(context, config, 0,
184 "Request to proxy non-proxiable ticket");
185 return KRB5KDC_ERR_BADOPTION;
188 et->caddr = b->addresses;
193 if(f.allow_postdate){
194 if(!tgt->flags.may_postdate){
195 kdc_log(context, config, 0,
196 "Bad request for post-datable ticket");
197 return KRB5KDC_ERR_BADOPTION;
199 et->flags.may_postdate = 1;
202 if(!tgt->flags.may_postdate){
203 kdc_log(context, config, 0,
204 "Bad request for postdated ticket");
205 return KRB5KDC_ERR_BADOPTION;
208 *et->starttime = *b->from;
209 et->flags.postdated = 1;
210 et->flags.invalid = 1;
211 }else if(b->from && *b->from > kdc_time + context->max_skew){
212 kdc_log(context, config, 0, "Ticket cannot be postdated");
213 return KRB5KDC_ERR_CANNOT_POSTDATE;
217 if(!tgt->flags.renewable || tgt->renew_till == NULL){
218 kdc_log(context, config, 0,
219 "Bad request for renewable ticket");
220 return KRB5KDC_ERR_BADOPTION;
222 et->flags.renewable = 1;
223 ALLOC(et->renew_till);
224 _kdc_fix_time(&b->rtime);
225 *et->renew_till = *b->rtime;
229 if(!tgt->flags.renewable || tgt->renew_till == NULL){
230 kdc_log(context, config, 0,
231 "Request to renew non-renewable ticket");
232 return KRB5KDC_ERR_BADOPTION;
234 old_life = tgt->endtime;
236 old_life -= *tgt->starttime;
238 old_life -= tgt->authtime;
239 et->endtime = *et->starttime + old_life;
240 if (et->renew_till != NULL)
241 et->endtime = min(*et->renew_till, et->endtime);
245 /* checks for excess flags */
246 if(f.request_anonymous && !config->allow_anonymous){
247 kdc_log(context, config, 0,
248 "Request for anonymous ticket");
249 return KRB5KDC_ERR_BADOPTION;
256 * Determine if constrained delegation is allowed from this client to this server
259 static krb5_error_code
260 check_constrained_delegation(krb5_context context,
261 krb5_kdc_configuration *config,
263 hdb_entry_ex *client,
264 hdb_entry_ex *server,
265 krb5_const_principal target)
267 const HDB_Ext_Constrained_delegation_acl *acl;
272 * constrained_delegation (S4U2Proxy) only works within
273 * the same realm. We use the already canonicalized version
274 * of the principals here, while "target" is the principal
275 * provided by the client.
277 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
278 ret = KRB5KDC_ERR_BADOPTION;
279 kdc_log(context, config, 0,
280 "Bad request for constrained delegation");
284 if (clientdb->hdb_check_constrained_delegation) {
285 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
289 /* if client delegates to itself, that ok */
290 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
293 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
295 krb5_clear_error_message(context);
300 for (i = 0; i < acl->len; i++) {
301 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
305 ret = KRB5KDC_ERR_BADOPTION;
307 kdc_log(context, config, 0,
308 "Bad request for constrained delegation");
313 * Determine if s4u2self is allowed from this client to this server
315 * For example, regardless of the principal being impersonated, if the
316 * 'client' and 'server' (target) are the same, then it's safe.
319 static krb5_error_code
320 check_s4u2self(krb5_context context,
321 krb5_kdc_configuration *config,
323 hdb_entry_ex *client,
324 hdb_entry_ex *target_server,
325 krb5_const_principal target_server_principal)
330 * Always allow the plugin to check, this might be faster, allow a
331 * policy or audit check and can look into the DB records
334 if (clientdb->hdb_check_s4u2self) {
335 ret = clientdb->hdb_check_s4u2self(context,
341 } else if (krb5_principal_compare(context,
342 client->entry.principal,
343 target_server_principal) == TRUE) {
344 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
347 ret = KRB5KDC_ERR_BADOPTION;
356 static krb5_error_code
357 verify_flags (krb5_context context,
358 krb5_kdc_configuration *config,
359 const EncTicketPart *et,
362 if(et->endtime < kdc_time){
363 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
364 return KRB5KRB_AP_ERR_TKT_EXPIRED;
366 if(et->flags.invalid){
367 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
368 return KRB5KRB_AP_ERR_TKT_NYV;
377 static krb5_error_code
378 fix_transited_encoding(krb5_context context,
379 krb5_kdc_configuration *config,
380 krb5_boolean check_policy,
381 const TransitedEncoding *tr,
383 const char *client_realm,
384 const char *server_realm,
385 const char *tgt_realm)
387 krb5_error_code ret = 0;
388 char **realms, **tmp;
389 unsigned int num_realms;
392 switch (tr->tr_type) {
393 case DOMAIN_X500_COMPRESS:
397 * Allow empty content of type 0 because that is was Microsoft
398 * generates in their TGT.
400 if (tr->contents.length == 0)
402 kdc_log(context, config, 0,
403 "Transited type 0 with non empty content");
404 return KRB5KDC_ERR_TRTYPE_NOSUPP;
406 kdc_log(context, config, 0,
407 "Unknown transited type: %u", tr->tr_type);
408 return KRB5KDC_ERR_TRTYPE_NOSUPP;
411 ret = krb5_domain_x500_decode(context,
418 krb5_warn(context, ret,
419 "Decoding transited encoding");
424 * If the realm of the presented tgt is neither the client nor the server
425 * realm, it is a transit realm and must be added to transited set.
427 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
428 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
432 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
438 realms[num_realms] = strdup(tgt_realm);
439 if(realms[num_realms] == NULL){
445 if(num_realms == 0) {
446 if(strcmp(client_realm, server_realm))
447 kdc_log(context, config, 0,
448 "cross-realm %s -> %s", client_realm, server_realm);
452 for(i = 0; i < num_realms; i++)
453 l += strlen(realms[i]) + 2;
457 for(i = 0; i < num_realms; i++) {
459 strlcat(rs, ", ", l);
460 strlcat(rs, realms[i], l);
462 kdc_log(context, config, 0,
463 "cross-realm %s -> %s via [%s]",
464 client_realm, server_realm, rs);
469 ret = krb5_check_transited(context, client_realm,
471 realms, num_realms, NULL);
473 krb5_warn(context, ret, "cross-realm %s -> %s",
474 client_realm, server_realm);
477 et->flags.transited_policy_checked = 1;
479 et->transited.tr_type = DOMAIN_X500_COMPRESS;
480 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
482 krb5_warn(context, ret, "Encoding transited encoding");
484 for(i = 0; i < num_realms; i++)
491 static krb5_error_code
492 tgs_make_reply(krb5_context context,
493 krb5_kdc_configuration *config,
495 krb5_principal tgt_name,
496 const EncTicketPart *tgt,
497 const krb5_keyblock *replykey,
499 const EncryptionKey *serverkey,
500 const EncryptionKey *krbtgtkey,
501 const krb5_keyblock *sessionkey,
503 AuthorizationData *auth_data,
504 hdb_entry_ex *server,
505 krb5_principal server_principal,
506 const char *server_name,
507 hdb_entry_ex *client,
508 krb5_principal client_principal,
509 const char *tgt_realm,
510 hdb_entry_ex *krbtgt,
513 krb5_boolean add_ticket_sig,
514 const METHOD_DATA *enc_pa_data,
521 KDCOptions f = b->kdc_options;
525 memset(&rep, 0, sizeof(rep));
526 memset(&et, 0, sizeof(et));
527 memset(&ek, 0, sizeof(ek));
530 rep.msg_type = krb_tgs_rep;
532 et.authtime = tgt->authtime;
533 _kdc_fix_time(&b->till);
534 et.endtime = min(tgt->endtime, *b->till);
536 *et.starttime = kdc_time;
538 ret = check_tgs_flags(context, config, b, tgt, &et);
542 /* We should check the transited encoding if:
543 1) the request doesn't ask not to be checked
544 2) globally enforcing a check
545 3) principal requires checking
546 4) we allow non-check per-principal, but principal isn't marked as allowing this
547 5) we don't globally allow this
550 #define GLOBAL_FORCE_TRANSITED_CHECK \
551 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
552 #define GLOBAL_ALLOW_PER_PRINCIPAL \
553 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
554 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
555 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
557 /* these will consult the database in future release */
558 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
559 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
561 ret = fix_transited_encoding(context, config,
562 !f.disable_transited_check ||
563 GLOBAL_FORCE_TRANSITED_CHECK ||
564 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
565 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
566 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
567 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
568 &tgt->transited, &et,
569 krb5_principal_get_realm(context, client_principal),
570 krb5_principal_get_realm(context, server->entry.principal),
575 copy_Realm(&server_principal->realm, &rep.ticket.realm);
576 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
577 copy_Realm(&tgt_name->realm, &rep.crealm);
579 if (f.request_anonymous)
580 _kdc_make_anonymous_principalname (&rep.cname);
583 copy_PrincipalName(&tgt_name->name, &rep.cname);
584 rep.ticket.tkt_vno = 5;
588 et.caddr = tgt->caddr;
592 life = et.endtime - *et.starttime;
593 if(client && client->entry.max_life)
594 life = min(life, *client->entry.max_life);
595 if(server->entry.max_life)
596 life = min(life, *server->entry.max_life);
597 et.endtime = *et.starttime + life;
599 if(f.renewable_ok && tgt->flags.renewable &&
600 et.renew_till == NULL && et.endtime < *b->till &&
601 tgt->renew_till != NULL)
603 et.flags.renewable = 1;
604 ALLOC(et.renew_till);
605 *et.renew_till = *b->till;
609 renew = *et.renew_till - et.authtime;
610 if(client && client->entry.max_renew)
611 renew = min(renew, *client->entry.max_renew);
612 if(server->entry.max_renew)
613 renew = min(renew, *server->entry.max_renew);
614 *et.renew_till = et.authtime + renew;
618 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
619 *et.starttime = min(*et.starttime, *et.renew_till);
620 et.endtime = min(et.endtime, *et.renew_till);
623 *et.starttime = min(*et.starttime, et.endtime);
625 if(*et.starttime == et.endtime){
626 ret = KRB5KDC_ERR_NEVER_VALID;
629 if(et.renew_till && et.endtime == *et.renew_till){
631 et.renew_till = NULL;
632 et.flags.renewable = 0;
635 et.flags.pre_authent = tgt->flags.pre_authent;
636 et.flags.hw_authent = tgt->flags.hw_authent;
637 et.flags.anonymous = tgt->flags.anonymous;
638 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
640 /* See MS-KILE 3.3.5.1 */
641 if (!server->entry.flags.forwardable)
642 et.flags.forwardable = 0;
643 if (!server->entry.flags.proxiable)
644 et.flags.proxiable = 0;
649 /* XXX check authdata */
651 if (et.authorization_data == NULL) {
652 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
653 if (et.authorization_data == NULL) {
655 krb5_set_error_message(context, ret, "malloc: out of memory");
659 for(i = 0; i < auth_data->len ; i++) {
660 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
662 krb5_set_error_message(context, ret, "malloc: out of memory");
668 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
671 et.crealm = tgt_name->realm;
672 et.cname = tgt_name->name;
675 /* MIT must have at least one last_req */
677 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
678 if (ek.last_req.val == NULL) {
684 ek.authtime = et.authtime;
685 ek.starttime = et.starttime;
686 ek.endtime = et.endtime;
687 ek.renew_till = et.renew_till;
688 ek.srealm = rep.ticket.realm;
689 ek.sname = rep.ticket.sname;
691 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
692 et.endtime, et.renew_till);
694 if (enc_pa_data->len) {
695 rep.padata = calloc(1, sizeof(*rep.padata));
696 if (rep.padata == NULL) {
700 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
705 if (krb5_enctype_valid(context, et.key.keytype) != 0
706 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
708 krb5_enctype_enable(context, et.key.keytype);
712 /* The PAC should be the last change to the ticket. */
714 ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
715 krbtgtkey, rodc_id, add_ticket_sig, &et);
720 /* It is somewhat unclear where the etype in the following
721 encryption should come from. What we have is a session
722 key in the passed tgt, and a list of preferred etypes
723 *for the new ticket*. Should we pick the best possible
724 etype, given the keytype in the tgt, or should we look
725 at the etype list here as well? What if the tgt
726 session key is DES3 and we want a ticket with a (say)
727 CAST session key. Should the DES3 etype be added to the
728 etype list, even if we don't want a session key with
730 ret = _kdc_encode_reply(context, config,
731 &rep, &et, &ek, et.key.keytype,
733 serverkey, 0, replykey, rk_is_subkey,
736 krb5_enctype_disable(context, et.key.keytype);
740 free_TransitedEncoding(&et.transited);
745 if(et.authorization_data) {
746 free_AuthorizationData(et.authorization_data);
747 free(et.authorization_data);
749 free_LastReq(&ek.last_req);
750 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
751 free_EncryptionKey(&et.key);
755 static krb5_error_code
756 tgs_check_authenticator(krb5_context context,
757 krb5_kdc_configuration *config,
758 krb5_auth_context ac,
763 krb5_authenticator auth;
770 krb5_auth_con_getauthenticator(context, ac, &auth);
771 if(auth->cksum == NULL){
772 kdc_log(context, config, 0, "No authenticator in request");
773 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
777 * according to RFC1510 it doesn't need to be keyed,
778 * but according to the latest draft it needs to.
782 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
785 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
786 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
787 auth->cksum->cksumtype);
788 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
792 /* XXX should not re-encode this */
793 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
795 const char *msg = krb5_get_error_message(context, ret);
796 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
797 krb5_free_error_message(context, msg);
800 if(buf_size != len) {
802 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
803 *e_text = "KDC internal error";
804 ret = KRB5KRB_ERR_GENERIC;
807 ret = krb5_crypto_init(context, key, 0, &crypto);
809 const char *msg = krb5_get_error_message(context, ret);
811 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
812 krb5_free_error_message(context, msg);
815 ret = krb5_verify_checksum(context,
817 KRB5_KU_TGS_REQ_AUTH_CKSUM,
822 krb5_crypto_destroy(context, crypto);
824 const char *msg = krb5_get_error_message(context, ret);
825 kdc_log(context, config, 0,
826 "Failed to verify authenticator checksum: %s", msg);
827 krb5_free_error_message(context, msg);
830 free_Authenticator(auth);
840 find_rpath(krb5_context context, Realm crealm, Realm srealm)
842 const char *new_realm = krb5_config_get_string(context,
853 need_referral(krb5_context context, krb5_kdc_configuration *config,
854 const KDCOptions * const options, krb5_principal server,
859 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
862 if (server->name.name_string.len == 1)
863 name = server->name.name_string.val[0];
864 else if (server->name.name_string.len == 3) {
866 This is used to give referrals for the
867 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
868 SPN form, which is used for inter-domain communication in AD
870 name = server->name.name_string.val[2];
871 kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
872 *realms = malloc(sizeof(char *)*2);
873 if (*realms == NULL) {
874 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
877 (*realms)[0] = strdup(name);
880 } else if (server->name.name_string.len > 1)
881 name = server->name.name_string.val[1];
885 kdc_log(context, config, 0, "Searching referral for %s", name);
887 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
890 static krb5_error_code
891 tgs_parse_request(krb5_context context,
892 krb5_kdc_configuration *config,
894 const PA_DATA *tgs_req,
895 hdb_entry_ex **krbtgt,
896 krb5_enctype *krbtgt_etype,
897 krb5_ticket **ticket,
900 const struct sockaddr *from_addr,
903 AuthorizationData **auth_data,
904 krb5_keyblock **replykey,
908 static char failed[] = "<unparse_name failed>";
911 krb5_principal princ;
912 krb5_auth_context ac = NULL;
913 krb5_flags ap_req_options;
914 krb5_flags verify_ap_req_flags;
917 krb5_keyblock *subkey = NULL;
920 krb5uint32 *kvno_ptr = NULL;
927 memset(&ap_req, 0, sizeof(ap_req));
928 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
930 const char *msg = krb5_get_error_message(context, ret);
931 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
932 krb5_free_error_message(context, msg);
936 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
937 /* XXX check for ticket.sname == req.sname */
938 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
939 ret = KRB5KDC_ERR_POLICY; /* ? */
943 _krb5_principalname2krb5_principal(context,
946 ap_req.ticket.realm);
948 if (ap_req.ticket.enc_part.kvno) {
949 kvno = *ap_req.ticket.enc_part.kvno;
952 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, kvno_ptr,
955 if(ret == HDB_ERR_NOT_FOUND_HERE) {
957 ret = krb5_unparse_name(context, princ, &p);
960 krb5_free_principal(context, princ);
961 kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
964 ret = HDB_ERR_NOT_FOUND_HERE;
967 const char *msg = krb5_get_error_message(context, ret);
969 ret = krb5_unparse_name(context, princ, &p);
972 krb5_free_principal(context, princ);
973 kdc_log(context, config, 0,
974 "Ticket-granting ticket not found in database: %s", msg);
975 krb5_free_error_message(context, msg);
978 ret = KRB5KRB_AP_ERR_NOT_US;
982 if(ap_req.ticket.enc_part.kvno &&
983 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
986 ret = krb5_unparse_name (context, princ, &p);
987 krb5_free_principal(context, princ);
990 kdc_log(context, config, 0,
991 "Ticket kvno = %d, DB kvno = %d (%s)",
992 *ap_req.ticket.enc_part.kvno,
993 (*krbtgt)->entry.kvno,
997 ret = KRB5KRB_AP_ERR_BADKEYVER;
1001 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1003 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1004 ap_req.ticket.enc_part.etype, &tkey);
1006 char *str = NULL, *p = NULL;
1008 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1009 krb5_unparse_name(context, princ, &p);
1010 kdc_log(context, config, 0,
1011 "No server key with enctype %s found for %s",
1012 str ? str : "<unknown enctype>",
1013 p ? p : "<unparse_name failed>");
1016 ret = KRB5KRB_AP_ERR_BADKEYVER;
1020 if (b->kdc_options.validate)
1021 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1023 verify_ap_req_flags = 0;
1025 ret = krb5_verify_ap_req2(context,
1030 verify_ap_req_flags,
1033 KRB5_KU_TGS_REQ_AUTH);
1035 krb5_free_principal(context, princ);
1037 const char *msg = krb5_get_error_message(context, ret);
1038 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1039 krb5_free_error_message(context, msg);
1046 krb5_authenticator auth;
1048 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1050 *csec = malloc(sizeof(**csec));
1051 if (*csec == NULL) {
1052 krb5_free_authenticator(context, &auth);
1053 kdc_log(context, config, 0, "malloc failed");
1056 **csec = auth->ctime;
1057 *cusec = malloc(sizeof(**cusec));
1058 if (*cusec == NULL) {
1059 krb5_free_authenticator(context, &auth);
1060 kdc_log(context, config, 0, "malloc failed");
1063 **cusec = auth->cusec;
1064 krb5_free_authenticator(context, &auth);
1068 ret = tgs_check_authenticator(context, config,
1069 ac, b, e_text, &(*ticket)->ticket.key);
1071 krb5_auth_con_free(context, ac);
1075 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1078 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1080 const char *msg = krb5_get_error_message(context, ret);
1081 krb5_auth_con_free(context, ac);
1082 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1083 krb5_free_error_message(context, msg);
1087 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1090 ret = krb5_auth_con_getkey(context, ac, &subkey);
1092 const char *msg = krb5_get_error_message(context, ret);
1093 krb5_auth_con_free(context, ac);
1094 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1095 krb5_free_error_message(context, msg);
1100 krb5_auth_con_free(context, ac);
1101 kdc_log(context, config, 0,
1102 "Failed to get key for enc-authorization-data");
1103 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1109 if (b->enc_authorization_data) {
1112 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1114 const char *msg = krb5_get_error_message(context, ret);
1115 krb5_auth_con_free(context, ac);
1116 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1117 krb5_free_error_message(context, msg);
1120 ret = krb5_decrypt_EncryptedData (context,
1123 b->enc_authorization_data,
1125 krb5_crypto_destroy(context, crypto);
1127 krb5_auth_con_free(context, ac);
1128 kdc_log(context, config, 0,
1129 "Failed to decrypt enc-authorization-data");
1130 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1134 if (*auth_data == NULL) {
1135 krb5_auth_con_free(context, ac);
1136 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1139 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1141 krb5_auth_con_free(context, ac);
1144 kdc_log(context, config, 0, "Failed to decode authorization data");
1145 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1150 krb5_auth_con_free(context, ac);
1153 free_AP_REQ(&ap_req);
1158 static krb5_error_code
1159 build_server_referral(krb5_context context,
1160 krb5_kdc_configuration *config,
1161 krb5_crypto session,
1162 krb5_const_realm referred_realm,
1163 const PrincipalName *true_principal_name,
1164 const PrincipalName *requested_principal,
1167 PA_ServerReferralData ref;
1168 krb5_error_code ret;
1173 memset(&ref, 0, sizeof(ref));
1175 if (referred_realm) {
1176 ALLOC(ref.referred_realm);
1177 if (ref.referred_realm == NULL)
1179 *ref.referred_realm = strdup(referred_realm);
1180 if (*ref.referred_realm == NULL)
1183 if (true_principal_name) {
1184 ALLOC(ref.true_principal_name);
1185 if (ref.true_principal_name == NULL)
1187 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1191 if (requested_principal) {
1192 ALLOC(ref.requested_principal_name);
1193 if (ref.requested_principal_name == NULL)
1195 ret = copy_PrincipalName(requested_principal,
1196 ref.requested_principal_name);
1201 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1202 data.data, data.length,
1204 free_PA_ServerReferralData(&ref);
1207 if (data.length != size)
1208 krb5_abortx(context, "internal asn.1 encoder error");
1210 ret = krb5_encrypt_EncryptedData(context, session,
1211 KRB5_KU_PA_SERVER_REFERRAL,
1212 data.data, data.length,
1218 ASN1_MALLOC_ENCODE(EncryptedData,
1219 outdata->data, outdata->length,
1221 free_EncryptedData(&ed);
1224 if (outdata->length != size)
1225 krb5_abortx(context, "internal asn.1 encoder error");
1229 free_PA_ServerReferralData(&ref);
1230 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1234 static krb5_error_code
1235 db_fetch_client(krb5_context context,
1236 krb5_kdc_configuration *config,
1240 const char *krbtgt_realm,
1242 hdb_entry_ex **client_out)
1244 krb5_error_code ret;
1245 hdb_entry_ex *client = NULL;
1249 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1250 NULL, clientdb, &client);
1251 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1253 * This is OK, we are just trying to find out if they have
1254 * been disabled or deleted in the meantime; missing secrets
1259 * If the client belongs to the same realm as our TGS, it
1260 * should exist in the local database.
1264 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1265 if (ret == HDB_ERR_NOENTRY)
1266 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1267 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1271 msg = krb5_get_error_message(context, ret);
1272 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1273 krb5_free_error_message(context, msg);
1274 } else if (client->entry.flags.invalid || !client->entry.flags.client) {
1275 kdc_log(context, config, 4, "Client has invalid bit set");
1276 _kdc_free_ent(context, client);
1277 return KRB5KDC_ERR_POLICY;
1280 *client_out = client;
1285 static krb5_error_code
1286 tgs_build_reply(krb5_context context,
1287 krb5_kdc_configuration *config,
1290 hdb_entry_ex *krbtgt,
1291 krb5_enctype krbtgt_etype,
1293 const krb5_keyblock *replykey,
1295 krb5_ticket *ticket,
1298 const char **e_text,
1299 AuthorizationData **auth_data,
1300 const struct sockaddr *from_addr)
1302 krb5_error_code ret;
1303 krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
1304 krb5_principal krbtgt_principal = NULL;
1305 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1306 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1307 HDB *clientdb, *s4u2self_impersonated_clientdb;
1308 krb5_realm ref_realm = NULL;
1309 EncTicketPart *tgt = &ticket->ticket;
1310 const char *tgt_realm = /* Realm of TGT issuer */
1311 krb5_principal_get_realm(context, krbtgt->entry.principal);
1312 const EncryptionKey *ekey;
1313 krb5_keyblock sessionkey;
1315 krb5_pac mspac = NULL;
1317 krb5_boolean add_ticket_sig = FALSE;
1318 hdb_entry_ex *krbtgt_out = NULL;
1320 METHOD_DATA enc_pa_data;
1325 EncTicketPart adtkt;
1327 krb5_boolean kdc_issued = FALSE;
1330 int flags = HDB_F_FOR_TGS_REQ;
1332 memset(&sessionkey, 0, sizeof(sessionkey));
1333 memset(&adtkt, 0, sizeof(adtkt));
1334 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1339 if (b->kdc_options.canonicalize)
1340 flags |= HDB_F_CANON;
1342 if(b->kdc_options.enc_tkt_in_skey){
1347 krb5uint32 second_kvno = 0;
1348 krb5uint32 *kvno_ptr = NULL;
1350 if(b->additional_tickets == NULL ||
1351 b->additional_tickets->len == 0){
1352 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1353 kdc_log(context, config, 0,
1354 "No second ticket present in request");
1357 t = &b->additional_tickets->val[0];
1358 if(!get_krbtgt_realm(&t->sname)){
1359 kdc_log(context, config, 0,
1360 "Additional ticket is not a ticket-granting ticket");
1361 ret = KRB5KDC_ERR_POLICY;
1364 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1368 if(t->enc_part.kvno){
1369 second_kvno = *t->enc_part.kvno;
1370 kvno_ptr = &second_kvno;
1372 ret = _kdc_db_fetch(context, config, p,
1373 HDB_F_GET_KRBTGT, kvno_ptr,
1375 krb5_free_principal(context, p);
1377 if (ret == HDB_ERR_NOENTRY)
1378 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1381 ret = hdb_enctype2key(context, &uu->entry,
1382 t->enc_part.etype, &uukey);
1384 _kdc_free_ent(context, uu);
1385 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1388 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1389 _kdc_free_ent(context, uu);
1393 ret = verify_flags(context, config, &adtkt, spn);
1399 } else if (s == NULL) {
1400 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1401 krb5_set_error_message(context, ret, "No server in request");
1405 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1406 ret = krb5_unparse_name(context, sp, &spn);
1409 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1410 ret = krb5_unparse_name(context, cp, &cpn);
1413 unparse_flags (KDCOptions2int(b->kdc_options),
1414 asn1_KDCOptions_units(),
1415 opt_str, sizeof(opt_str));
1417 kdc_log(context, config, 0,
1418 "TGS-REQ %s from %s for %s [%s]",
1419 cpn, from, spn, opt_str);
1421 kdc_log(context, config, 0,
1422 "TGS-REQ %s from %s for %s", cpn, from, spn);
1429 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1430 NULL, NULL, &server);
1432 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1433 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1435 } else if (ret == HDB_ERR_WRONG_REALM) {
1438 ref_realm = strdup(server->entry.principal->realm);
1439 if (ref_realm == NULL) {
1444 kdc_log(context, config, 5,
1445 "Returning a referral to realm %s for "
1448 krb5_free_principal(context, sp);
1452 ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1456 ret = krb5_unparse_name(context, sp, &spn);
1462 const char *new_rlm, *msg;
1466 if (!config->autodetect_referrals) {
1468 } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1470 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1472 kdc_log(context, config, 5, "krbtgt for realm %s "
1473 "not found, trying %s",
1475 krb5_free_principal(context, sp);
1477 krb5_make_principal(context, &sp, r,
1478 KRB5_TGS_NAME, new_rlm, NULL);
1479 ret = krb5_unparse_name(context, sp, &spn);
1485 ref_realm = strdup(new_rlm);
1489 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1490 if (strcmp(realms[0], sp->realm) != 0) {
1491 kdc_log(context, config, 5,
1492 "Returning a referral to realm %s for "
1493 "server %s that was not found",
1495 krb5_free_principal(context, sp);
1497 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1499 ret = krb5_unparse_name(context, sp, &spn);
1505 ref_realm = strdup(realms[0]);
1507 krb5_free_host_realm(context, realms);
1510 krb5_free_host_realm(context, realms);
1512 msg = krb5_get_error_message(context, ret);
1513 kdc_log(context, config, 0,
1514 "Server not found in database: %s: %s", spn, msg);
1515 krb5_free_error_message(context, msg);
1516 if (ret == HDB_ERR_NOENTRY)
1517 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1522 * Select enctype, return key and kvno.
1528 if(b->kdc_options.enc_tkt_in_skey) {
1531 for(i = 0; i < b->etype.len; i++)
1532 if (b->etype.val[i] == adtkt.key.keytype)
1534 if(i == b->etype.len) {
1535 kdc_log(context, config, 0,
1536 "Addition ticket have not matching etypes");
1537 krb5_clear_error_message(context);
1538 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1541 etype = b->etype.val[i];
1546 ret = _kdc_find_etype(context,
1547 config->tgs_use_strongest_session_key, FALSE,
1548 server, b->etype.val, b->etype.len, NULL,
1551 kdc_log(context, config, 0,
1552 "Server (%s) has no support for etypes", spn);
1556 etype = skey->key.keytype;
1557 kvno = server->entry.kvno;
1560 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1566 * Check that service is in the same realm as the krbtgt. If it's
1567 * not the same, it's someone that is using a uni-directional trust
1571 /* Now refetch the primary krbtgt, and get the current kvno (the
1572 * sign check may have been on an old kvno, and the server may
1573 * have been an incoming trust) */
1574 ret = krb5_make_principal(context, &krbtgt_principal,
1575 krb5_principal_get_comp_string(context,
1576 krbtgt->entry.principal,
1579 krb5_principal_get_comp_string(context,
1580 krbtgt->entry.principal,
1583 kdc_log(context, config, 0,
1584 "Failed to generate krbtgt principal");
1588 ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1589 krb5_free_principal(context, krbtgt_principal);
1591 krb5_error_code ret2;
1593 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1594 ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1595 kdc_log(context, config, 0,
1596 "Request with wrong krbtgt: %s, %s not found in our database",
1597 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1602 ret = KRB5KRB_AP_ERR_NOT_US;
1606 /* The first realm is the realm of the service, the second is
1607 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1608 * encrypted to. The redirection via the krbtgt_out entry allows
1609 * the DB to possibly correct the case of the realm (Samba4 does
1610 * this) before the strcmp() */
1611 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1612 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1614 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1615 kdc_log(context, config, 0,
1616 "Request with wrong krbtgt: %s",
1617 (ret == 0) ? ktpn : "<unknown>");
1620 ret = KRB5KRB_AP_ERR_NOT_US;
1623 ret = hdb_enctype2key(context, &krbtgt_out->entry,
1624 krbtgt_etype, &tkey_sign);
1626 kdc_log(context, config, 0,
1627 "Failed to find key for krbtgt PAC signature");
1631 ret = db_fetch_client(context, config, flags, cp, cpn,
1632 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1633 &clientdb, &client);
1637 ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1638 &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
1640 const char *msg = krb5_get_error_message(context, ret);
1641 kdc_log(context, config, 0,
1642 "Verify PAC failed for %s (%s) from %s with %s",
1643 spn, cpn, from, msg);
1644 krb5_free_error_message(context, msg);
1652 /* by default the tgt principal matches the client principal */
1657 const PA_DATA *sdata;
1660 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1667 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1668 sdata->padata_value.length,
1671 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1675 if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1676 free_PA_S4U2Self(&self);
1677 kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
1678 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1682 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1686 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1688 const char *msg = krb5_get_error_message(context, ret);
1689 free_PA_S4U2Self(&self);
1690 krb5_data_free(&datack);
1691 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1692 krb5_free_error_message(context, msg);
1696 /* Allow HMAC_MD5 checksum with any key type */
1697 if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
1698 unsigned char csdata[16];
1701 cs.checksum.length = sizeof(csdata);
1702 cs.checksum.data = &csdata;
1704 ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
1705 datack.data, datack.length,
1706 KRB5_KU_OTHER_CKSUM, &cs);
1708 krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
1709 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1712 ret = krb5_verify_checksum(context,
1714 KRB5_KU_OTHER_CKSUM,
1719 krb5_data_free(&datack);
1720 krb5_crypto_destroy(context, crypto);
1722 const char *msg = krb5_get_error_message(context, ret);
1723 free_PA_S4U2Self(&self);
1724 kdc_log(context, config, 0,
1725 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1726 krb5_free_error_message(context, msg);
1730 ret = _krb5_principalname2krb5_principal(context,
1734 free_PA_S4U2Self(&self);
1738 ret = krb5_unparse_name(context, tp, &tpn);
1742 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1743 NULL, &s4u2self_impersonated_clientdb,
1744 &s4u2self_impersonated_client);
1749 * If the client belongs to the same realm as our krbtgt, it
1750 * should exist in the local database.
1754 if (ret == HDB_ERR_NOENTRY)
1755 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1756 msg = krb5_get_error_message(context, ret);
1757 kdc_log(context, config, 1,
1758 "S2U4Self principal to impersonate %s not found in database: %s",
1760 krb5_free_error_message(context, msg);
1764 /* Ignore pw_end attributes (as Windows does),
1765 * since S4U2Self is not password authentication. */
1766 free(s4u2self_impersonated_client->entry.pw_end);
1767 s4u2self_impersonated_client->entry.pw_end = NULL;
1769 ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
1774 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1776 krb5_pac_free(context, mspac);
1778 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
1780 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1787 * Check that service doing the impersonating is
1788 * requesting a ticket to it-self.
1790 ret = check_s4u2self(context, config, clientdb, client, server, sp);
1792 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1793 "to impersonate to service "
1794 "(tried for user %s to service %s)",
1800 * If the service isn't trusted for authentication to
1801 * delegation or if the impersonate client is disallowed
1802 * forwardable, remove the forwardable flag.
1805 if (client->entry.flags.trusted_for_delegation &&
1806 s4u2self_impersonated_client->entry.flags.forwardable) {
1807 str = "[forwardable]";
1809 b->kdc_options.forwardable = 0;
1812 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1813 "service %s %s", cpn, tpn, spn, str);
1818 * Constrained delegation
1822 && b->additional_tickets != NULL
1823 && b->additional_tickets->len != 0
1824 && b->kdc_options.enc_tkt_in_skey == 0)
1826 hdb_entry_ex *adclient = NULL;
1827 krb5_boolean ad_kdc_issued = FALSE;
1832 * We require that the service's krbtgt has a PAC.
1834 if (mspac == NULL) {
1835 ret = KRB5KDC_ERR_BADOPTION;
1836 kdc_log(context, config, 0,
1837 "Constrained delegation without PAC %s/%s",
1842 krb5_pac_free(context, mspac);
1845 t = &b->additional_tickets->val[0];
1847 ret = hdb_enctype2key(context, &client->entry,
1848 t->enc_part.etype, &clientkey);
1850 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1854 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1856 kdc_log(context, config, 0,
1857 "failed to decrypt ticket for "
1858 "constrained delegation from %s to %s ", cpn, spn);
1862 ret = _krb5_principalname2krb5_principal(context,
1869 ret = krb5_unparse_name(context, tp, &tpn);
1873 ret = _krb5_principalname2krb5_principal(context,
1880 ret = krb5_unparse_name(context, dp, &dpn);
1884 /* check that ticket is valid */
1885 if (adtkt.flags.forwardable == 0) {
1886 kdc_log(context, config, 0,
1887 "Missing forwardable flag on ticket for "
1888 "constrained delegation from %s (%s) as %s to %s ",
1889 cpn, dpn, tpn, spn);
1890 ret = KRB5KDC_ERR_BADOPTION;
1894 ret = check_constrained_delegation(context, config, clientdb,
1895 client, server, sp);
1897 kdc_log(context, config, 0,
1898 "constrained delegation from %s (%s) as %s to %s not allowed",
1899 cpn, dpn, tpn, spn);
1903 ret = verify_flags(context, config, &adtkt, tpn);
1908 /* Try lookup the delegated client in DB */
1909 ret = db_fetch_client(context, config, flags, tp, tpn,
1910 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1915 if (adclient != NULL) {
1916 ret = kdc_check_flags(context, config,
1921 _kdc_free_ent(context, adclient);
1927 * TODO: pass in t->sname and t->realm and build
1928 * a S4U_DELEGATION_INFO blob to the PAC.
1930 ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
1931 &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
1933 _kdc_free_ent(context, adclient);
1935 const char *msg = krb5_get_error_message(context, ret);
1936 kdc_log(context, config, 0,
1937 "Verify delegated PAC failed to %s for client"
1938 "%s (%s) as %s from %s with %s",
1939 spn, cpn, dpn, tpn, from, msg);
1940 krb5_free_error_message(context, msg);
1944 if (mspac == NULL || !ad_kdc_issued) {
1945 ret = KRB5KDC_ERR_BADOPTION;
1946 kdc_log(context, config, 0,
1947 "Ticket not signed with PAC; service %s failed for "
1948 "for delegation to %s for client %s (%s) from %s; (%s).",
1949 spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
1953 kdc_log(context, config, 0, "constrained delegation for %s "
1954 "from %s (%s) to %s", tpn, cpn, dpn, spn);
1961 ret = kdc_check_flags(context, config,
1968 if((b->kdc_options.validate || b->kdc_options.renew) &&
1969 !krb5_principal_compare(context,
1970 krbtgt->entry.principal,
1971 server->entry.principal)){
1972 kdc_log(context, config, 0, "Inconsistent request.");
1973 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1977 /* check for valid set of addresses */
1978 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1979 ret = KRB5KRB_AP_ERR_BADADDR;
1980 kdc_log(context, config, 0, "Request from wrong address");
1985 * If this is an referral, add server referral data to the
1992 kdc_log(context, config, 0,
1993 "Adding server referral to %s", ref_realm);
1995 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1999 ret = build_server_referral(context, config, crypto, ref_realm,
2000 NULL, s, &pa.padata_value);
2001 krb5_crypto_destroy(context, crypto);
2003 kdc_log(context, config, 0,
2004 "Failed building server referral");
2007 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2009 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2010 krb5_data_free(&pa.padata_value);
2012 kdc_log(context, config, 0,
2013 "Add server referral METHOD-DATA failed");
2019 * Only add ticket signature if the requested server is not krbtgt, and
2020 * either the header server is krbtgt or, in the case of renewal/validation
2021 * if it was signed with PAC ticket signature and we verified it.
2022 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2023 * change one day (see issue #763) so make sure to check for it.
2027 !krb5_principal_is_krbtgt(context, server->entry.principal))
2028 add_ticket_sig = TRUE;
2031 * Active-Directory implementations use the high part of the kvno as the
2032 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2035 rodc_id = krbtgt_out->entry.kvno >> 16;
2041 ret = tgs_make_reply(context,
2054 server->entry.principal,
2075 krb5_free_keyblock_contents(context, &sessionkey);
2077 _kdc_free_ent(context, krbtgt_out);
2079 _kdc_free_ent(context, server);
2081 _kdc_free_ent(context, client);
2082 if(s4u2self_impersonated_client)
2083 _kdc_free_ent(context, s4u2self_impersonated_client);
2086 krb5_free_principal(context, tp);
2088 krb5_free_principal(context, cp);
2090 krb5_free_principal(context, dp);
2092 krb5_free_principal(context, sp);
2095 free_METHOD_DATA(&enc_pa_data);
2097 free_EncTicketPart(&adtkt);
2099 krb5_pac_free(context, mspac);
2109 _kdc_tgs_rep(krb5_context context,
2110 krb5_kdc_configuration *config,
2114 struct sockaddr *from_addr,
2117 AuthorizationData *auth_data = NULL;
2118 krb5_error_code ret;
2120 const PA_DATA *tgs_req;
2121 Key *header_key = NULL;
2123 hdb_entry_ex *krbtgt = NULL;
2124 krb5_ticket *ticket = NULL;
2125 const char *e_text = NULL;
2126 krb5_enctype krbtgt_etype = ETYPE_NULL;
2128 krb5_keyblock *replykey = NULL;
2129 int rk_is_subkey = 0;
2130 time_t *csec = NULL;
2133 if(req->padata == NULL){
2134 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2135 kdc_log(context, config, 0,
2136 "TGS-REQ from %s without PA-DATA", from);
2140 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2142 if(tgs_req == NULL){
2143 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2145 kdc_log(context, config, 0,
2146 "TGS-REQ from %s without PA-TGS-REQ", from);
2149 ret = tgs_parse_request(context, config,
2150 &req->req_body, tgs_req,
2161 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2162 /* kdc_log() is called in tgs_parse_request() */
2166 kdc_log(context, config, 0,
2167 "Failed parsing TGS-REQ from %s", from);
2171 ret = tgs_build_reply(context,
2187 kdc_log(context, config, 0,
2188 "Failed building TGS-REP to %s", from);
2193 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2194 krb5_data_free(data);
2195 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2196 e_text = "Reply packet too large";
2201 krb5_free_keyblock(context, replykey);
2202 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2203 krb5_mk_error(context,
2217 krb5_free_ticket(context, ticket);
2219 _kdc_free_ent(context, krbtgt);
2222 free_AuthorizationData(auth_data);