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' 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 krb5_const_principal server)
328 /* if client does a s4u2self to itself, that ok */
329 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
332 if (clientdb->hdb_check_s4u2self) {
333 ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
337 ret = KRB5KDC_ERR_BADOPTION;
346 static krb5_error_code
347 verify_flags (krb5_context context,
348 krb5_kdc_configuration *config,
349 const EncTicketPart *et,
352 if(et->endtime < kdc_time){
353 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
354 return KRB5KRB_AP_ERR_TKT_EXPIRED;
356 if(et->flags.invalid){
357 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
358 return KRB5KRB_AP_ERR_TKT_NYV;
367 static krb5_error_code
368 fix_transited_encoding(krb5_context context,
369 krb5_kdc_configuration *config,
370 krb5_boolean check_policy,
371 const TransitedEncoding *tr,
373 const char *client_realm,
374 const char *server_realm,
375 const char *tgt_realm)
377 krb5_error_code ret = 0;
378 char **realms, **tmp;
379 unsigned int num_realms;
382 switch (tr->tr_type) {
383 case DOMAIN_X500_COMPRESS:
387 * Allow empty content of type 0 because that is was Microsoft
388 * generates in their TGT.
390 if (tr->contents.length == 0)
392 kdc_log(context, config, 0,
393 "Transited type 0 with non empty content");
394 return KRB5KDC_ERR_TRTYPE_NOSUPP;
396 kdc_log(context, config, 0,
397 "Unknown transited type: %u", tr->tr_type);
398 return KRB5KDC_ERR_TRTYPE_NOSUPP;
401 ret = krb5_domain_x500_decode(context,
408 krb5_warn(context, ret,
409 "Decoding transited encoding");
414 * If the realm of the presented tgt is neither the client nor the server
415 * realm, it is a transit realm and must be added to transited set.
417 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
418 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
422 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
428 realms[num_realms] = strdup(tgt_realm);
429 if(realms[num_realms] == NULL){
435 if(num_realms == 0) {
436 if(strcmp(client_realm, server_realm))
437 kdc_log(context, config, 0,
438 "cross-realm %s -> %s", client_realm, server_realm);
442 for(i = 0; i < num_realms; i++)
443 l += strlen(realms[i]) + 2;
447 for(i = 0; i < num_realms; i++) {
449 strlcat(rs, ", ", l);
450 strlcat(rs, realms[i], l);
452 kdc_log(context, config, 0,
453 "cross-realm %s -> %s via [%s]",
454 client_realm, server_realm, rs);
459 ret = krb5_check_transited(context, client_realm,
461 realms, num_realms, NULL);
463 krb5_warn(context, ret, "cross-realm %s -> %s",
464 client_realm, server_realm);
467 et->flags.transited_policy_checked = 1;
469 et->transited.tr_type = DOMAIN_X500_COMPRESS;
470 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
472 krb5_warn(context, ret, "Encoding transited encoding");
474 for(i = 0; i < num_realms; i++)
481 static krb5_error_code
482 tgs_make_reply(krb5_context context,
483 krb5_kdc_configuration *config,
485 krb5_principal tgt_name,
486 const EncTicketPart *tgt,
487 const krb5_keyblock *replykey,
489 const EncryptionKey *serverkey,
490 const EncryptionKey *krbtgtkey,
491 const krb5_keyblock *sessionkey,
493 AuthorizationData *auth_data,
494 hdb_entry_ex *server,
495 krb5_principal server_principal,
496 const char *server_name,
497 hdb_entry_ex *client,
498 krb5_principal client_principal,
499 const char *tgt_realm,
500 hdb_entry_ex *krbtgt,
503 krb5_boolean add_ticket_sig,
504 const METHOD_DATA *enc_pa_data,
511 KDCOptions f = b->kdc_options;
515 memset(&rep, 0, sizeof(rep));
516 memset(&et, 0, sizeof(et));
517 memset(&ek, 0, sizeof(ek));
520 rep.msg_type = krb_tgs_rep;
522 et.authtime = tgt->authtime;
523 _kdc_fix_time(&b->till);
524 et.endtime = min(tgt->endtime, *b->till);
526 *et.starttime = kdc_time;
528 ret = check_tgs_flags(context, config, b, tgt, &et);
532 /* We should check the transited encoding if:
533 1) the request doesn't ask not to be checked
534 2) globally enforcing a check
535 3) principal requires checking
536 4) we allow non-check per-principal, but principal isn't marked as allowing this
537 5) we don't globally allow this
540 #define GLOBAL_FORCE_TRANSITED_CHECK \
541 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
542 #define GLOBAL_ALLOW_PER_PRINCIPAL \
543 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
544 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
545 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
547 /* these will consult the database in future release */
548 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
549 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
551 ret = fix_transited_encoding(context, config,
552 !f.disable_transited_check ||
553 GLOBAL_FORCE_TRANSITED_CHECK ||
554 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
555 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
556 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
557 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
558 &tgt->transited, &et,
559 krb5_principal_get_realm(context, client_principal),
560 krb5_principal_get_realm(context, server->entry.principal),
565 copy_Realm(&server_principal->realm, &rep.ticket.realm);
566 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
567 copy_Realm(&tgt_name->realm, &rep.crealm);
569 if (f.request_anonymous)
570 _kdc_make_anonymous_principalname (&rep.cname);
573 copy_PrincipalName(&tgt_name->name, &rep.cname);
574 rep.ticket.tkt_vno = 5;
578 et.caddr = tgt->caddr;
582 life = et.endtime - *et.starttime;
583 if(client && client->entry.max_life)
584 life = min(life, *client->entry.max_life);
585 if(server->entry.max_life)
586 life = min(life, *server->entry.max_life);
587 et.endtime = *et.starttime + life;
589 if(f.renewable_ok && tgt->flags.renewable &&
590 et.renew_till == NULL && et.endtime < *b->till &&
591 tgt->renew_till != NULL)
593 et.flags.renewable = 1;
594 ALLOC(et.renew_till);
595 *et.renew_till = *b->till;
599 renew = *et.renew_till - et.authtime;
600 if(client && client->entry.max_renew)
601 renew = min(renew, *client->entry.max_renew);
602 if(server->entry.max_renew)
603 renew = min(renew, *server->entry.max_renew);
604 *et.renew_till = et.authtime + renew;
608 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
609 *et.starttime = min(*et.starttime, *et.renew_till);
610 et.endtime = min(et.endtime, *et.renew_till);
613 *et.starttime = min(*et.starttime, et.endtime);
615 if(*et.starttime == et.endtime){
616 ret = KRB5KDC_ERR_NEVER_VALID;
619 if(et.renew_till && et.endtime == *et.renew_till){
621 et.renew_till = NULL;
622 et.flags.renewable = 0;
625 et.flags.pre_authent = tgt->flags.pre_authent;
626 et.flags.hw_authent = tgt->flags.hw_authent;
627 et.flags.anonymous = tgt->flags.anonymous;
628 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
630 /* See MS-KILE 3.3.5.1 */
631 if (!server->entry.flags.forwardable)
632 et.flags.forwardable = 0;
633 if (!server->entry.flags.proxiable)
634 et.flags.proxiable = 0;
639 /* XXX check authdata */
641 if (et.authorization_data == NULL) {
642 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
643 if (et.authorization_data == NULL) {
645 krb5_set_error_message(context, ret, "malloc: out of memory");
649 for(i = 0; i < auth_data->len ; i++) {
650 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
652 krb5_set_error_message(context, ret, "malloc: out of memory");
658 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
661 et.crealm = tgt_name->realm;
662 et.cname = tgt_name->name;
665 /* MIT must have at least one last_req */
667 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
668 if (ek.last_req.val == NULL) {
674 ek.authtime = et.authtime;
675 ek.starttime = et.starttime;
676 ek.endtime = et.endtime;
677 ek.renew_till = et.renew_till;
678 ek.srealm = rep.ticket.realm;
679 ek.sname = rep.ticket.sname;
681 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
682 et.endtime, et.renew_till);
684 if (enc_pa_data->len) {
685 rep.padata = calloc(1, sizeof(*rep.padata));
686 if (rep.padata == NULL) {
690 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
695 if (krb5_enctype_valid(context, et.key.keytype) != 0
696 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
698 krb5_enctype_enable(context, et.key.keytype);
702 /* The PAC should be the last change to the ticket. */
704 ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
705 krbtgtkey, rodc_id, add_ticket_sig, &et);
710 /* It is somewhat unclear where the etype in the following
711 encryption should come from. What we have is a session
712 key in the passed tgt, and a list of preferred etypes
713 *for the new ticket*. Should we pick the best possible
714 etype, given the keytype in the tgt, or should we look
715 at the etype list here as well? What if the tgt
716 session key is DES3 and we want a ticket with a (say)
717 CAST session key. Should the DES3 etype be added to the
718 etype list, even if we don't want a session key with
720 ret = _kdc_encode_reply(context, config,
721 &rep, &et, &ek, et.key.keytype,
723 serverkey, 0, replykey, rk_is_subkey,
726 krb5_enctype_disable(context, et.key.keytype);
730 free_TransitedEncoding(&et.transited);
735 if(et.authorization_data) {
736 free_AuthorizationData(et.authorization_data);
737 free(et.authorization_data);
739 free_LastReq(&ek.last_req);
740 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
741 free_EncryptionKey(&et.key);
745 static krb5_error_code
746 tgs_check_authenticator(krb5_context context,
747 krb5_kdc_configuration *config,
748 krb5_auth_context ac,
753 krb5_authenticator auth;
760 krb5_auth_con_getauthenticator(context, ac, &auth);
761 if(auth->cksum == NULL){
762 kdc_log(context, config, 0, "No authenticator in request");
763 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
767 * according to RFC1510 it doesn't need to be keyed,
768 * but according to the latest draft it needs to.
772 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
775 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
776 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
777 auth->cksum->cksumtype);
778 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
782 /* XXX should not re-encode this */
783 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
785 const char *msg = krb5_get_error_message(context, ret);
786 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
787 krb5_free_error_message(context, msg);
790 if(buf_size != len) {
792 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
793 *e_text = "KDC internal error";
794 ret = KRB5KRB_ERR_GENERIC;
797 ret = krb5_crypto_init(context, key, 0, &crypto);
799 const char *msg = krb5_get_error_message(context, ret);
801 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
802 krb5_free_error_message(context, msg);
805 ret = krb5_verify_checksum(context,
807 KRB5_KU_TGS_REQ_AUTH_CKSUM,
812 krb5_crypto_destroy(context, crypto);
814 const char *msg = krb5_get_error_message(context, ret);
815 kdc_log(context, config, 0,
816 "Failed to verify authenticator checksum: %s", msg);
817 krb5_free_error_message(context, msg);
820 free_Authenticator(auth);
830 find_rpath(krb5_context context, Realm crealm, Realm srealm)
832 const char *new_realm = krb5_config_get_string(context,
843 need_referral(krb5_context context, krb5_kdc_configuration *config,
844 const KDCOptions * const options, krb5_principal server,
849 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
852 if (server->name.name_string.len == 1)
853 name = server->name.name_string.val[0];
854 else if (server->name.name_string.len == 3) {
856 This is used to give referrals for the
857 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
858 SPN form, which is used for inter-domain communication in AD
860 name = server->name.name_string.val[2];
861 kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
862 *realms = malloc(sizeof(char *)*2);
863 if (*realms == NULL) {
864 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
867 (*realms)[0] = strdup(name);
870 } else if (server->name.name_string.len > 1)
871 name = server->name.name_string.val[1];
875 kdc_log(context, config, 0, "Searching referral for %s", name);
877 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
880 static krb5_error_code
881 tgs_parse_request(krb5_context context,
882 krb5_kdc_configuration *config,
884 const PA_DATA *tgs_req,
885 hdb_entry_ex **krbtgt,
886 krb5_enctype *krbtgt_etype,
887 krb5_ticket **ticket,
890 const struct sockaddr *from_addr,
893 AuthorizationData **auth_data,
894 krb5_keyblock **replykey,
898 static char failed[] = "<unparse_name failed>";
901 krb5_principal princ;
902 krb5_auth_context ac = NULL;
903 krb5_flags ap_req_options;
904 krb5_flags verify_ap_req_flags;
907 krb5_keyblock *subkey = NULL;
910 krb5uint32 *kvno_ptr = NULL;
917 memset(&ap_req, 0, sizeof(ap_req));
918 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
920 const char *msg = krb5_get_error_message(context, ret);
921 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
922 krb5_free_error_message(context, msg);
926 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
927 /* XXX check for ticket.sname == req.sname */
928 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
929 ret = KRB5KDC_ERR_POLICY; /* ? */
933 _krb5_principalname2krb5_principal(context,
936 ap_req.ticket.realm);
938 if (ap_req.ticket.enc_part.kvno) {
939 kvno = *ap_req.ticket.enc_part.kvno;
942 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, kvno_ptr,
945 if(ret == HDB_ERR_NOT_FOUND_HERE) {
947 ret = krb5_unparse_name(context, princ, &p);
950 krb5_free_principal(context, princ);
951 kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
954 ret = HDB_ERR_NOT_FOUND_HERE;
957 const char *msg = krb5_get_error_message(context, ret);
959 ret = krb5_unparse_name(context, princ, &p);
962 krb5_free_principal(context, princ);
963 kdc_log(context, config, 0,
964 "Ticket-granting ticket not found in database: %s", msg);
965 krb5_free_error_message(context, msg);
968 ret = KRB5KRB_AP_ERR_NOT_US;
972 if(ap_req.ticket.enc_part.kvno &&
973 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
976 ret = krb5_unparse_name (context, princ, &p);
977 krb5_free_principal(context, princ);
980 kdc_log(context, config, 0,
981 "Ticket kvno = %d, DB kvno = %d (%s)",
982 *ap_req.ticket.enc_part.kvno,
983 (*krbtgt)->entry.kvno,
987 ret = KRB5KRB_AP_ERR_BADKEYVER;
991 *krbtgt_etype = ap_req.ticket.enc_part.etype;
993 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
994 ap_req.ticket.enc_part.etype, &tkey);
996 char *str = NULL, *p = NULL;
998 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
999 krb5_unparse_name(context, princ, &p);
1000 kdc_log(context, config, 0,
1001 "No server key with enctype %s found for %s",
1002 str ? str : "<unknown enctype>",
1003 p ? p : "<unparse_name failed>");
1006 ret = KRB5KRB_AP_ERR_BADKEYVER;
1010 if (b->kdc_options.validate)
1011 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1013 verify_ap_req_flags = 0;
1015 ret = krb5_verify_ap_req2(context,
1020 verify_ap_req_flags,
1023 KRB5_KU_TGS_REQ_AUTH);
1025 krb5_free_principal(context, princ);
1027 const char *msg = krb5_get_error_message(context, ret);
1028 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1029 krb5_free_error_message(context, msg);
1036 krb5_authenticator auth;
1038 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1040 *csec = malloc(sizeof(**csec));
1041 if (*csec == NULL) {
1042 krb5_free_authenticator(context, &auth);
1043 kdc_log(context, config, 0, "malloc failed");
1046 **csec = auth->ctime;
1047 *cusec = malloc(sizeof(**cusec));
1048 if (*cusec == NULL) {
1049 krb5_free_authenticator(context, &auth);
1050 kdc_log(context, config, 0, "malloc failed");
1053 **cusec = auth->cusec;
1054 krb5_free_authenticator(context, &auth);
1058 ret = tgs_check_authenticator(context, config,
1059 ac, b, e_text, &(*ticket)->ticket.key);
1061 krb5_auth_con_free(context, ac);
1065 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1068 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1070 const char *msg = krb5_get_error_message(context, ret);
1071 krb5_auth_con_free(context, ac);
1072 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1073 krb5_free_error_message(context, msg);
1077 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1080 ret = krb5_auth_con_getkey(context, ac, &subkey);
1082 const char *msg = krb5_get_error_message(context, ret);
1083 krb5_auth_con_free(context, ac);
1084 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1085 krb5_free_error_message(context, msg);
1090 krb5_auth_con_free(context, ac);
1091 kdc_log(context, config, 0,
1092 "Failed to get key for enc-authorization-data");
1093 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1099 if (b->enc_authorization_data) {
1102 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1104 const char *msg = krb5_get_error_message(context, ret);
1105 krb5_auth_con_free(context, ac);
1106 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1107 krb5_free_error_message(context, msg);
1110 ret = krb5_decrypt_EncryptedData (context,
1113 b->enc_authorization_data,
1115 krb5_crypto_destroy(context, crypto);
1117 krb5_auth_con_free(context, ac);
1118 kdc_log(context, config, 0,
1119 "Failed to decrypt enc-authorization-data");
1120 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1124 if (*auth_data == NULL) {
1125 krb5_auth_con_free(context, ac);
1126 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1129 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1131 krb5_auth_con_free(context, ac);
1134 kdc_log(context, config, 0, "Failed to decode authorization data");
1135 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1140 krb5_auth_con_free(context, ac);
1143 free_AP_REQ(&ap_req);
1148 static krb5_error_code
1149 build_server_referral(krb5_context context,
1150 krb5_kdc_configuration *config,
1151 krb5_crypto session,
1152 krb5_const_realm referred_realm,
1153 const PrincipalName *true_principal_name,
1154 const PrincipalName *requested_principal,
1157 PA_ServerReferralData ref;
1158 krb5_error_code ret;
1163 memset(&ref, 0, sizeof(ref));
1165 if (referred_realm) {
1166 ALLOC(ref.referred_realm);
1167 if (ref.referred_realm == NULL)
1169 *ref.referred_realm = strdup(referred_realm);
1170 if (*ref.referred_realm == NULL)
1173 if (true_principal_name) {
1174 ALLOC(ref.true_principal_name);
1175 if (ref.true_principal_name == NULL)
1177 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1181 if (requested_principal) {
1182 ALLOC(ref.requested_principal_name);
1183 if (ref.requested_principal_name == NULL)
1185 ret = copy_PrincipalName(requested_principal,
1186 ref.requested_principal_name);
1191 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1192 data.data, data.length,
1194 free_PA_ServerReferralData(&ref);
1197 if (data.length != size)
1198 krb5_abortx(context, "internal asn.1 encoder error");
1200 ret = krb5_encrypt_EncryptedData(context, session,
1201 KRB5_KU_PA_SERVER_REFERRAL,
1202 data.data, data.length,
1208 ASN1_MALLOC_ENCODE(EncryptedData,
1209 outdata->data, outdata->length,
1211 free_EncryptedData(&ed);
1214 if (outdata->length != size)
1215 krb5_abortx(context, "internal asn.1 encoder error");
1219 free_PA_ServerReferralData(&ref);
1220 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1224 static krb5_error_code
1225 db_fetch_client(krb5_context context,
1226 krb5_kdc_configuration *config,
1230 const char *krbtgt_realm,
1232 hdb_entry_ex **client_out)
1234 krb5_error_code ret;
1235 hdb_entry_ex *client = NULL;
1239 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1240 NULL, clientdb, &client);
1241 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1243 * This is OK, we are just trying to find out if they have
1244 * been disabled or deleted in the meantime; missing secrets
1249 * If the client belongs to the same realm as our TGS, it
1250 * should exist in the local database.
1254 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1255 if (ret == HDB_ERR_NOENTRY)
1256 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1257 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1261 msg = krb5_get_error_message(context, ret);
1262 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1263 krb5_free_error_message(context, msg);
1264 } else if (client->entry.flags.invalid || !client->entry.flags.client) {
1265 kdc_log(context, config, 4, "Client has invalid bit set");
1266 _kdc_free_ent(context, client);
1267 return KRB5KDC_ERR_POLICY;
1270 *client_out = client;
1275 static krb5_error_code
1276 tgs_build_reply(krb5_context context,
1277 krb5_kdc_configuration *config,
1280 hdb_entry_ex *krbtgt,
1281 krb5_enctype krbtgt_etype,
1283 const krb5_keyblock *replykey,
1285 krb5_ticket *ticket,
1288 const char **e_text,
1289 AuthorizationData **auth_data,
1290 const struct sockaddr *from_addr)
1292 krb5_error_code ret;
1293 krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
1294 krb5_principal krbtgt_principal = NULL;
1295 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1296 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1297 HDB *clientdb, *s4u2self_impersonated_clientdb;
1298 krb5_realm ref_realm = NULL;
1299 EncTicketPart *tgt = &ticket->ticket;
1300 const char *tgt_realm = /* Realm of TGT issuer */
1301 krb5_principal_get_realm(context, krbtgt->entry.principal);
1302 const EncryptionKey *ekey;
1303 krb5_keyblock sessionkey;
1305 krb5_pac mspac = NULL;
1307 krb5_boolean add_ticket_sig = FALSE;
1308 hdb_entry_ex *krbtgt_out = NULL;
1310 METHOD_DATA enc_pa_data;
1315 EncTicketPart adtkt;
1317 krb5_boolean kdc_issued = FALSE;
1320 int flags = HDB_F_FOR_TGS_REQ;
1322 memset(&sessionkey, 0, sizeof(sessionkey));
1323 memset(&adtkt, 0, sizeof(adtkt));
1324 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1329 if (b->kdc_options.canonicalize)
1330 flags |= HDB_F_CANON;
1332 if(b->kdc_options.enc_tkt_in_skey){
1337 krb5uint32 second_kvno = 0;
1338 krb5uint32 *kvno_ptr = NULL;
1340 if(b->additional_tickets == NULL ||
1341 b->additional_tickets->len == 0){
1342 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1343 kdc_log(context, config, 0,
1344 "No second ticket present in request");
1347 t = &b->additional_tickets->val[0];
1348 if(!get_krbtgt_realm(&t->sname)){
1349 kdc_log(context, config, 0,
1350 "Additional ticket is not a ticket-granting ticket");
1351 ret = KRB5KDC_ERR_POLICY;
1354 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1355 if(t->enc_part.kvno){
1356 second_kvno = *t->enc_part.kvno;
1357 kvno_ptr = &second_kvno;
1359 ret = _kdc_db_fetch(context, config, p,
1360 HDB_F_GET_KRBTGT, kvno_ptr,
1362 krb5_free_principal(context, p);
1364 if (ret == HDB_ERR_NOENTRY)
1365 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1368 ret = hdb_enctype2key(context, &uu->entry,
1369 t->enc_part.etype, &uukey);
1371 _kdc_free_ent(context, uu);
1372 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1375 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1376 _kdc_free_ent(context, uu);
1380 ret = verify_flags(context, config, &adtkt, spn);
1386 } else if (s == NULL) {
1387 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1388 krb5_set_error_message(context, ret, "No server in request");
1392 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1393 ret = krb5_unparse_name(context, sp, &spn);
1396 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1397 ret = krb5_unparse_name(context, cp, &cpn);
1400 unparse_flags (KDCOptions2int(b->kdc_options),
1401 asn1_KDCOptions_units(),
1402 opt_str, sizeof(opt_str));
1404 kdc_log(context, config, 0,
1405 "TGS-REQ %s from %s for %s [%s]",
1406 cpn, from, spn, opt_str);
1408 kdc_log(context, config, 0,
1409 "TGS-REQ %s from %s for %s", cpn, from, spn);
1416 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1417 NULL, NULL, &server);
1419 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1420 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1422 } else if (ret == HDB_ERR_WRONG_REALM) {
1425 ref_realm = strdup(server->entry.principal->realm);
1426 if (ref_realm == NULL) {
1431 kdc_log(context, config, 5,
1432 "Returning a referral to realm %s for "
1435 krb5_free_principal(context, sp);
1439 ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1443 ret = krb5_unparse_name(context, sp, &spn);
1449 const char *new_rlm, *msg;
1453 if (!config->autodetect_referrals) {
1455 } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1457 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1459 kdc_log(context, config, 5, "krbtgt for realm %s "
1460 "not found, trying %s",
1462 krb5_free_principal(context, sp);
1464 krb5_make_principal(context, &sp, r,
1465 KRB5_TGS_NAME, new_rlm, NULL);
1466 ret = krb5_unparse_name(context, sp, &spn);
1472 ref_realm = strdup(new_rlm);
1476 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1477 if (strcmp(realms[0], sp->realm) != 0) {
1478 kdc_log(context, config, 5,
1479 "Returning a referral to realm %s for "
1480 "server %s that was not found",
1482 krb5_free_principal(context, sp);
1484 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1486 ret = krb5_unparse_name(context, sp, &spn);
1492 ref_realm = strdup(realms[0]);
1494 krb5_free_host_realm(context, realms);
1497 krb5_free_host_realm(context, realms);
1499 msg = krb5_get_error_message(context, ret);
1500 kdc_log(context, config, 0,
1501 "Server not found in database: %s: %s", spn, msg);
1502 krb5_free_error_message(context, msg);
1503 if (ret == HDB_ERR_NOENTRY)
1504 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1509 * Select enctype, return key and kvno.
1515 if(b->kdc_options.enc_tkt_in_skey) {
1518 for(i = 0; i < b->etype.len; i++)
1519 if (b->etype.val[i] == adtkt.key.keytype)
1521 if(i == b->etype.len) {
1522 kdc_log(context, config, 0,
1523 "Addition ticket have not matching etypes");
1524 krb5_clear_error_message(context);
1525 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1528 etype = b->etype.val[i];
1533 ret = _kdc_find_etype(context,
1534 config->tgs_use_strongest_session_key, FALSE,
1535 server, b->etype.val, b->etype.len, NULL,
1538 kdc_log(context, config, 0,
1539 "Server (%s) has no support for etypes", spn);
1543 etype = skey->key.keytype;
1544 kvno = server->entry.kvno;
1547 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1553 * Check that service is in the same realm as the krbtgt. If it's
1554 * not the same, it's someone that is using a uni-directional trust
1558 /* Now refetch the primary krbtgt, and get the current kvno (the
1559 * sign check may have been on an old kvno, and the server may
1560 * have been an incoming trust) */
1561 ret = krb5_make_principal(context, &krbtgt_principal,
1562 krb5_principal_get_comp_string(context,
1563 krbtgt->entry.principal,
1566 krb5_principal_get_comp_string(context,
1567 krbtgt->entry.principal,
1570 kdc_log(context, config, 0,
1571 "Failed to generate krbtgt principal");
1575 ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1576 krb5_free_principal(context, krbtgt_principal);
1578 krb5_error_code ret2;
1580 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1581 ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1582 kdc_log(context, config, 0,
1583 "Request with wrong krbtgt: %s, %s not found in our database",
1584 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1589 ret = KRB5KRB_AP_ERR_NOT_US;
1593 /* The first realm is the realm of the service, the second is
1594 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1595 * encrypted to. The redirection via the krbtgt_out entry allows
1596 * the DB to possibly correct the case of the realm (Samba4 does
1597 * this) before the strcmp() */
1598 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1599 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1601 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1602 kdc_log(context, config, 0,
1603 "Request with wrong krbtgt: %s",
1604 (ret == 0) ? ktpn : "<unknown>");
1607 ret = KRB5KRB_AP_ERR_NOT_US;
1610 ret = hdb_enctype2key(context, &krbtgt_out->entry,
1611 krbtgt_etype, &tkey_sign);
1613 kdc_log(context, config, 0,
1614 "Failed to find key for krbtgt PAC signature");
1618 ret = db_fetch_client(context, config, flags, cp, cpn,
1619 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1620 &clientdb, &client);
1624 ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1625 &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
1627 const char *msg = krb5_get_error_message(context, ret);
1628 kdc_log(context, config, 0,
1629 "Verify PAC failed for %s (%s) from %s with %s",
1630 spn, cpn, from, msg);
1631 krb5_free_error_message(context, msg);
1639 /* by default the tgt principal matches the client principal */
1644 const PA_DATA *sdata;
1647 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1654 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1655 sdata->padata_value.length,
1658 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1662 if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1663 free_PA_S4U2Self(&self);
1664 kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
1665 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1669 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1673 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1675 const char *msg = krb5_get_error_message(context, ret);
1676 free_PA_S4U2Self(&self);
1677 krb5_data_free(&datack);
1678 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1679 krb5_free_error_message(context, msg);
1683 /* Allow HMAC_MD5 checksum with any key type */
1684 if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
1685 unsigned char csdata[16];
1688 cs.checksum.length = sizeof(csdata);
1689 cs.checksum.data = &csdata;
1691 ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
1692 datack.data, datack.length,
1693 KRB5_KU_OTHER_CKSUM, &cs);
1695 krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
1696 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1699 ret = krb5_verify_checksum(context,
1701 KRB5_KU_OTHER_CKSUM,
1706 krb5_data_free(&datack);
1707 krb5_crypto_destroy(context, crypto);
1709 const char *msg = krb5_get_error_message(context, ret);
1710 free_PA_S4U2Self(&self);
1711 kdc_log(context, config, 0,
1712 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1713 krb5_free_error_message(context, msg);
1717 ret = _krb5_principalname2krb5_principal(context,
1721 free_PA_S4U2Self(&self);
1725 ret = krb5_unparse_name(context, tp, &tpn);
1729 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1730 NULL, &s4u2self_impersonated_clientdb,
1731 &s4u2self_impersonated_client);
1736 * If the client belongs to the same realm as our krbtgt, it
1737 * should exist in the local database.
1741 if (ret == HDB_ERR_NOENTRY)
1742 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1743 msg = krb5_get_error_message(context, ret);
1744 kdc_log(context, config, 1,
1745 "S2U4Self principal to impersonate %s not found in database: %s",
1747 krb5_free_error_message(context, msg);
1751 /* Ignore pw_end attributes (as Windows does),
1752 * since S4U2Self is not password authentication. */
1753 free(s4u2self_impersonated_client->entry.pw_end);
1754 s4u2self_impersonated_client->entry.pw_end = NULL;
1756 ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
1761 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1763 krb5_pac_free(context, mspac);
1765 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &mspac);
1767 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1774 * Check that service doing the impersonating is
1775 * requesting a ticket to it-self.
1777 ret = check_s4u2self(context, config, clientdb, client, sp);
1779 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1780 "to impersonate to service "
1781 "(tried for user %s to service %s)",
1787 * If the service isn't trusted for authentication to
1788 * delegation or if the impersonate client is disallowed
1789 * forwardable, remove the forwardable flag.
1792 if (client->entry.flags.trusted_for_delegation &&
1793 s4u2self_impersonated_client->entry.flags.forwardable) {
1794 str = "[forwardable]";
1796 b->kdc_options.forwardable = 0;
1799 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1800 "service %s %s", cpn, tpn, spn, str);
1805 * Constrained delegation
1809 && b->additional_tickets != NULL
1810 && b->additional_tickets->len != 0
1811 && b->kdc_options.enc_tkt_in_skey == 0)
1813 hdb_entry_ex *adclient = NULL;
1814 krb5_boolean ad_kdc_issued = FALSE;
1819 * We require that the service's krbtgt has a PAC.
1821 if (mspac == NULL) {
1822 ret = KRB5KDC_ERR_BADOPTION;
1823 kdc_log(context, config, 0,
1824 "Constrained delegation without PAC %s/%s",
1829 krb5_pac_free(context, mspac);
1832 t = &b->additional_tickets->val[0];
1834 ret = hdb_enctype2key(context, &client->entry,
1835 t->enc_part.etype, &clientkey);
1837 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1841 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1843 kdc_log(context, config, 0,
1844 "failed to decrypt ticket for "
1845 "constrained delegation from %s to %s ", cpn, spn);
1849 ret = _krb5_principalname2krb5_principal(context,
1856 ret = krb5_unparse_name(context, tp, &tpn);
1860 ret = _krb5_principalname2krb5_principal(context,
1867 ret = krb5_unparse_name(context, dp, &dpn);
1871 /* check that ticket is valid */
1872 if (adtkt.flags.forwardable == 0) {
1873 kdc_log(context, config, 0,
1874 "Missing forwardable flag on ticket for "
1875 "constrained delegation from %s (%s) as %s to %s ",
1876 cpn, dpn, tpn, spn);
1877 ret = KRB5KDC_ERR_BADOPTION;
1881 ret = check_constrained_delegation(context, config, clientdb,
1882 client, server, sp);
1884 kdc_log(context, config, 0,
1885 "constrained delegation from %s (%s) as %s to %s not allowed",
1886 cpn, dpn, tpn, spn);
1890 ret = verify_flags(context, config, &adtkt, tpn);
1895 /* Try lookup the delegated client in DB */
1896 ret = db_fetch_client(context, config, flags, tp, tpn,
1897 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1902 if (adclient != NULL) {
1903 ret = kdc_check_flags(context, config,
1908 _kdc_free_ent(context, adclient);
1914 * TODO: pass in t->sname and t->realm and build
1915 * a S4U_DELEGATION_INFO blob to the PAC.
1917 ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
1918 &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
1920 _kdc_free_ent(context, adclient);
1922 const char *msg = krb5_get_error_message(context, ret);
1923 kdc_log(context, config, 0,
1924 "Verify delegated PAC failed to %s for client"
1925 "%s (%s) as %s from %s with %s",
1926 spn, cpn, dpn, tpn, from, msg);
1927 krb5_free_error_message(context, msg);
1931 if (mspac == NULL || !ad_kdc_issued) {
1932 ret = KRB5KDC_ERR_BADOPTION;
1933 kdc_log(context, config, 0,
1934 "Ticket not signed with PAC; service %s failed for "
1935 "for delegation to %s for client %s (%s) from %s; (%s).",
1936 spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
1940 kdc_log(context, config, 0, "constrained delegation for %s "
1941 "from %s (%s) to %s", tpn, cpn, dpn, spn);
1948 ret = kdc_check_flags(context, config,
1955 if((b->kdc_options.validate || b->kdc_options.renew) &&
1956 !krb5_principal_compare(context,
1957 krbtgt->entry.principal,
1958 server->entry.principal)){
1959 kdc_log(context, config, 0, "Inconsistent request.");
1960 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1964 /* check for valid set of addresses */
1965 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1966 ret = KRB5KRB_AP_ERR_BADADDR;
1967 kdc_log(context, config, 0, "Request from wrong address");
1972 * If this is an referral, add server referral data to the
1979 kdc_log(context, config, 0,
1980 "Adding server referral to %s", ref_realm);
1982 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1986 ret = build_server_referral(context, config, crypto, ref_realm,
1987 NULL, s, &pa.padata_value);
1988 krb5_crypto_destroy(context, crypto);
1990 kdc_log(context, config, 0,
1991 "Failed building server referral");
1994 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1996 ret = add_METHOD_DATA(&enc_pa_data, &pa);
1997 krb5_data_free(&pa.padata_value);
1999 kdc_log(context, config, 0,
2000 "Add server referral METHOD-DATA failed");
2006 * Only add ticket signature if the requested server is not krbtgt, and
2007 * either the header server is krbtgt or, in the case of renewal/validation
2008 * if it was signed with PAC ticket signature and we verified it.
2009 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2010 * change one day (see issue #763) so make sure to check for it.
2014 !krb5_principal_is_krbtgt(context, server->entry.principal))
2015 add_ticket_sig = TRUE;
2018 * Active-Directory implementations use the high part of the kvno as the
2019 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2022 rodc_id = krbtgt_out->entry.kvno >> 16;
2028 ret = tgs_make_reply(context,
2041 server->entry.principal,
2062 krb5_free_keyblock_contents(context, &sessionkey);
2064 _kdc_free_ent(context, krbtgt_out);
2066 _kdc_free_ent(context, server);
2068 _kdc_free_ent(context, client);
2069 if(s4u2self_impersonated_client)
2070 _kdc_free_ent(context, s4u2self_impersonated_client);
2073 krb5_free_principal(context, tp);
2075 krb5_free_principal(context, cp);
2077 krb5_free_principal(context, dp);
2079 krb5_free_principal(context, sp);
2082 free_METHOD_DATA(&enc_pa_data);
2084 free_EncTicketPart(&adtkt);
2086 krb5_pac_free(context, mspac);
2096 _kdc_tgs_rep(krb5_context context,
2097 krb5_kdc_configuration *config,
2101 struct sockaddr *from_addr,
2104 AuthorizationData *auth_data = NULL;
2105 krb5_error_code ret;
2107 const PA_DATA *tgs_req;
2108 Key *header_key = NULL;
2110 hdb_entry_ex *krbtgt = NULL;
2111 krb5_ticket *ticket = NULL;
2112 const char *e_text = NULL;
2113 krb5_enctype krbtgt_etype = ETYPE_NULL;
2115 krb5_keyblock *replykey = NULL;
2116 int rk_is_subkey = 0;
2117 time_t *csec = NULL;
2120 if(req->padata == NULL){
2121 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2122 kdc_log(context, config, 0,
2123 "TGS-REQ from %s without PA-DATA", from);
2127 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2129 if(tgs_req == NULL){
2130 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2132 kdc_log(context, config, 0,
2133 "TGS-REQ from %s without PA-TGS-REQ", from);
2136 ret = tgs_parse_request(context, config,
2137 &req->req_body, tgs_req,
2148 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2149 /* kdc_log() is called in tgs_parse_request() */
2153 kdc_log(context, config, 0,
2154 "Failed parsing TGS-REQ from %s", from);
2158 ret = tgs_build_reply(context,
2174 kdc_log(context, config, 0,
2175 "Failed building TGS-REP to %s", from);
2180 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2181 krb5_data_free(data);
2182 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2183 e_text = "Reply packet too large";
2188 krb5_free_keyblock(context, replykey);
2189 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2190 krb5_mk_error(context,
2204 krb5_free_ticket(context, ticket);
2206 _kdc_free_ent(context, krbtgt);
2209 free_AuthorizationData(auth_data);