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 krb5_principal user2user_princ = NULL;
1306 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1307 char *user2user_name = NULL;
1308 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1309 HDB *clientdb, *s4u2self_impersonated_clientdb;
1310 HDB *serverdb = NULL;
1311 krb5_realm ref_realm = NULL;
1312 EncTicketPart *tgt = &ticket->ticket;
1313 const char *tgt_realm = /* Realm of TGT issuer */
1314 krb5_principal_get_realm(context, krbtgt->entry.principal);
1315 const EncryptionKey *ekey;
1316 krb5_keyblock sessionkey;
1318 krb5_pac mspac = NULL;
1320 krb5_boolean add_ticket_sig = FALSE;
1321 hdb_entry_ex *krbtgt_out = NULL;
1323 METHOD_DATA enc_pa_data;
1328 EncTicketPart adtkt;
1330 krb5_boolean kdc_issued = FALSE;
1333 int flags = HDB_F_FOR_TGS_REQ;
1335 memset(&sessionkey, 0, sizeof(sessionkey));
1336 memset(&adtkt, 0, sizeof(adtkt));
1337 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1342 if (b->kdc_options.canonicalize)
1343 flags |= HDB_F_CANON;
1346 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1347 krb5_set_error_message(context, ret, "No server in request");
1351 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1352 ret = krb5_unparse_name(context, sp, &spn);
1355 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1356 ret = krb5_unparse_name(context, cp, &cpn);
1359 unparse_flags (KDCOptions2int(b->kdc_options),
1360 asn1_KDCOptions_units(),
1361 opt_str, sizeof(opt_str));
1363 kdc_log(context, config, 0,
1364 "TGS-REQ %s from %s for %s [%s]",
1365 cpn, from, spn, opt_str);
1367 kdc_log(context, config, 0,
1368 "TGS-REQ %s from %s for %s", cpn, from, spn);
1375 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1376 NULL, &serverdb, &server);
1378 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1379 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1381 } else if (ret == HDB_ERR_WRONG_REALM) {
1384 ref_realm = strdup(server->entry.principal->realm);
1385 if (ref_realm == NULL) {
1390 kdc_log(context, config, 5,
1391 "Returning a referral to realm %s for "
1394 krb5_free_principal(context, sp);
1398 ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1402 ret = krb5_unparse_name(context, sp, &spn);
1408 const char *new_rlm, *msg;
1412 if (!config->autodetect_referrals) {
1414 } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1416 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1418 kdc_log(context, config, 5, "krbtgt for realm %s "
1419 "not found, trying %s",
1421 krb5_free_principal(context, sp);
1423 krb5_make_principal(context, &sp, r,
1424 KRB5_TGS_NAME, new_rlm, NULL);
1425 ret = krb5_unparse_name(context, sp, &spn);
1431 ref_realm = strdup(new_rlm);
1435 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1436 if (strcmp(realms[0], sp->realm) != 0) {
1437 kdc_log(context, config, 5,
1438 "Returning a referral to realm %s for "
1439 "server %s that was not found",
1441 krb5_free_principal(context, sp);
1443 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1445 ret = krb5_unparse_name(context, sp, &spn);
1451 ref_realm = strdup(realms[0]);
1453 krb5_free_host_realm(context, realms);
1456 krb5_free_host_realm(context, realms);
1458 msg = krb5_get_error_message(context, ret);
1459 kdc_log(context, config, 0,
1460 "Server not found in database: %s: %s", spn, msg);
1461 krb5_free_error_message(context, msg);
1462 if (ret == HDB_ERR_NOENTRY)
1463 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1467 /* Now refetch the primary krbtgt, and get the current kvno (the
1468 * sign check may have been on an old kvno, and the server may
1469 * have been an incoming trust) */
1470 ret = krb5_make_principal(context, &krbtgt_principal,
1471 krb5_principal_get_comp_string(context,
1472 krbtgt->entry.principal,
1475 krb5_principal_get_comp_string(context,
1476 krbtgt->entry.principal,
1479 kdc_log(context, config, 0,
1480 "Failed to generate krbtgt principal");
1484 ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1485 krb5_free_principal(context, krbtgt_principal);
1487 krb5_error_code ret2;
1489 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1490 ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1491 kdc_log(context, config, 0,
1492 "Request with wrong krbtgt: %s, %s not found in our database",
1493 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1498 ret = KRB5KRB_AP_ERR_NOT_US;
1503 * Select enctype, return key and kvno.
1509 if(b->kdc_options.enc_tkt_in_skey) {
1514 krb5uint32 second_kvno = 0;
1515 krb5uint32 *kvno_ptr = NULL;
1517 hdb_entry_ex *user2user_client = NULL;
1519 if(b->additional_tickets == NULL ||
1520 b->additional_tickets->len == 0){
1521 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1522 kdc_log(context, config, 0,
1523 "No second ticket present in request");
1526 t = &b->additional_tickets->val[0];
1527 if(!get_krbtgt_realm(&t->sname)){
1528 kdc_log(context, config, 0,
1529 "Additional ticket is not a ticket-granting ticket");
1530 ret = KRB5KDC_ERR_POLICY;
1533 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1537 if(t->enc_part.kvno){
1538 second_kvno = *t->enc_part.kvno;
1539 kvno_ptr = &second_kvno;
1541 ret = _kdc_db_fetch(context, config, p,
1542 HDB_F_GET_KRBTGT, kvno_ptr,
1544 krb5_free_principal(context, p);
1546 if (ret == HDB_ERR_NOENTRY)
1547 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1550 ret = hdb_enctype2key(context, &uu->entry,
1551 t->enc_part.etype, &uukey);
1553 _kdc_free_ent(context, uu);
1554 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1557 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1558 _kdc_free_ent(context, uu);
1562 ret = verify_flags(context, config, &adtkt, spn);
1566 /* Fetch the name from the TGT. */
1567 ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1568 adtkt.cname, adtkt.crealm);
1573 ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1578 /* Look up the name given in the TGT in the database. */
1579 ret = db_fetch_client(context, config, flags, user2user_princ, user2user_name,
1580 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1581 NULL, &user2user_client);
1586 if (user2user_client != NULL) {
1588 * If the account is present in the database, check the account
1591 ret = kdc_check_flags(context, config,
1592 user2user_client, user2user_name,
1596 _kdc_free_ent(context, user2user_client);
1601 * Also check that the account is the same one specified in the
1604 ret = check_s4u2self(context, config, serverdb, server, user2user_client, user2user_princ);
1606 _kdc_free_ent(context, user2user_client);
1611 _kdc_free_ent(context, user2user_client);
1614 for(i = 0; i < b->etype.len; i++)
1615 if (b->etype.val[i] == adtkt.key.keytype)
1617 if(i == b->etype.len) {
1618 kdc_log(context, config, 0,
1619 "Addition ticket have not matching etypes");
1620 krb5_clear_error_message(context);
1621 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1624 etype = b->etype.val[i];
1629 ret = _kdc_find_etype(context,
1630 config->tgs_use_strongest_session_key, FALSE,
1631 server, b->etype.val, b->etype.len, NULL,
1634 kdc_log(context, config, 0,
1635 "Server (%s) has no support for etypes", spn);
1639 etype = skey->key.keytype;
1640 kvno = server->entry.kvno;
1643 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1649 * Check that service is in the same realm as the krbtgt. If it's
1650 * not the same, it's someone that is using a uni-directional trust
1654 /* The first realm is the realm of the service, the second is
1655 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1656 * encrypted to. The redirection via the krbtgt_out entry allows
1657 * the DB to possibly correct the case of the realm (Samba4 does
1658 * this) before the strcmp() */
1659 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1660 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1662 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1663 kdc_log(context, config, 0,
1664 "Request with wrong krbtgt: %s",
1665 (ret == 0) ? ktpn : "<unknown>");
1668 ret = KRB5KRB_AP_ERR_NOT_US;
1671 ret = hdb_enctype2key(context, &krbtgt_out->entry,
1672 krbtgt_etype, &tkey_sign);
1674 kdc_log(context, config, 0,
1675 "Failed to find key for krbtgt PAC signature");
1679 ret = db_fetch_client(context, config, flags, cp, cpn,
1680 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1681 &clientdb, &client);
1685 ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1686 &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
1688 const char *msg = krb5_get_error_message(context, ret);
1689 kdc_log(context, config, 0,
1690 "Verify PAC failed for %s (%s) from %s with %s",
1691 spn, cpn, from, msg);
1692 krb5_free_error_message(context, msg);
1700 /* by default the tgt principal matches the client principal */
1705 const PA_DATA *sdata;
1708 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1715 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1716 sdata->padata_value.length,
1719 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1723 if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1724 free_PA_S4U2Self(&self);
1725 kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
1726 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1730 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1734 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1736 const char *msg = krb5_get_error_message(context, ret);
1737 free_PA_S4U2Self(&self);
1738 krb5_data_free(&datack);
1739 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1740 krb5_free_error_message(context, msg);
1744 /* Allow HMAC_MD5 checksum with any key type */
1745 if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
1746 unsigned char csdata[16];
1749 cs.checksum.length = sizeof(csdata);
1750 cs.checksum.data = &csdata;
1752 ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
1753 datack.data, datack.length,
1754 KRB5_KU_OTHER_CKSUM, &cs);
1756 krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
1757 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1760 ret = krb5_verify_checksum(context,
1762 KRB5_KU_OTHER_CKSUM,
1767 krb5_data_free(&datack);
1768 krb5_crypto_destroy(context, crypto);
1770 const char *msg = krb5_get_error_message(context, ret);
1771 free_PA_S4U2Self(&self);
1772 kdc_log(context, config, 0,
1773 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1774 krb5_free_error_message(context, msg);
1778 ret = _krb5_principalname2krb5_principal(context,
1782 free_PA_S4U2Self(&self);
1786 ret = krb5_unparse_name(context, tp, &tpn);
1790 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1791 NULL, &s4u2self_impersonated_clientdb,
1792 &s4u2self_impersonated_client);
1797 * If the client belongs to the same realm as our krbtgt, it
1798 * should exist in the local database.
1802 if (ret == HDB_ERR_NOENTRY)
1803 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1804 msg = krb5_get_error_message(context, ret);
1805 kdc_log(context, config, 1,
1806 "S2U4Self principal to impersonate %s not found in database: %s",
1808 krb5_free_error_message(context, msg);
1812 /* Ignore pw_end attributes (as Windows does),
1813 * since S4U2Self is not password authentication. */
1814 free(s4u2self_impersonated_client->entry.pw_end);
1815 s4u2self_impersonated_client->entry.pw_end = NULL;
1817 ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
1822 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1824 krb5_pac_free(context, mspac);
1826 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
1828 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1835 * Check that service doing the impersonating is
1836 * requesting a ticket to it-self.
1838 ret = check_s4u2self(context, config, clientdb, client, server, sp);
1840 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1841 "to impersonate to service "
1842 "(tried for user %s to service %s)",
1848 * If the service isn't trusted for authentication to
1849 * delegation or if the impersonate client is disallowed
1850 * forwardable, remove the forwardable flag.
1853 if (client->entry.flags.trusted_for_delegation &&
1854 s4u2self_impersonated_client->entry.flags.forwardable) {
1855 str = "[forwardable]";
1857 b->kdc_options.forwardable = 0;
1860 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1861 "service %s %s", cpn, tpn, spn, str);
1866 * Constrained delegation
1870 && b->additional_tickets != NULL
1871 && b->additional_tickets->len != 0
1872 && b->kdc_options.enc_tkt_in_skey == 0)
1874 hdb_entry_ex *adclient = NULL;
1875 krb5_boolean ad_kdc_issued = FALSE;
1880 * We require that the service's krbtgt has a PAC.
1882 if (mspac == NULL) {
1883 ret = KRB5KDC_ERR_BADOPTION;
1884 kdc_log(context, config, 0,
1885 "Constrained delegation without PAC %s/%s",
1890 krb5_pac_free(context, mspac);
1893 t = &b->additional_tickets->val[0];
1895 ret = hdb_enctype2key(context, &client->entry,
1896 t->enc_part.etype, &clientkey);
1898 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1902 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1904 kdc_log(context, config, 0,
1905 "failed to decrypt ticket for "
1906 "constrained delegation from %s to %s ", cpn, spn);
1910 ret = _krb5_principalname2krb5_principal(context,
1917 ret = krb5_unparse_name(context, tp, &tpn);
1921 ret = _krb5_principalname2krb5_principal(context,
1928 ret = krb5_unparse_name(context, dp, &dpn);
1932 /* check that ticket is valid */
1933 if (adtkt.flags.forwardable == 0) {
1934 kdc_log(context, config, 0,
1935 "Missing forwardable flag on ticket for "
1936 "constrained delegation from %s (%s) as %s to %s ",
1937 cpn, dpn, tpn, spn);
1938 ret = KRB5KDC_ERR_BADOPTION;
1942 ret = check_constrained_delegation(context, config, clientdb,
1943 client, server, sp);
1945 kdc_log(context, config, 0,
1946 "constrained delegation from %s (%s) as %s to %s not allowed",
1947 cpn, dpn, tpn, spn);
1951 ret = verify_flags(context, config, &adtkt, tpn);
1956 /* Try lookup the delegated client in DB */
1957 ret = db_fetch_client(context, config, flags, tp, tpn,
1958 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1963 if (adclient != NULL) {
1964 ret = kdc_check_flags(context, config,
1969 _kdc_free_ent(context, adclient);
1975 * TODO: pass in t->sname and t->realm and build
1976 * a S4U_DELEGATION_INFO blob to the PAC.
1978 ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
1979 &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
1981 _kdc_free_ent(context, adclient);
1983 const char *msg = krb5_get_error_message(context, ret);
1984 kdc_log(context, config, 0,
1985 "Verify delegated PAC failed to %s for client"
1986 "%s (%s) as %s from %s with %s",
1987 spn, cpn, dpn, tpn, from, msg);
1988 krb5_free_error_message(context, msg);
1992 if (mspac == NULL || !ad_kdc_issued) {
1993 ret = KRB5KDC_ERR_BADOPTION;
1994 kdc_log(context, config, 0,
1995 "Ticket not signed with PAC; service %s failed for "
1996 "for delegation to %s for client %s (%s) from %s; (%s).",
1997 spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
2001 kdc_log(context, config, 0, "constrained delegation for %s "
2002 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2009 ret = kdc_check_flags(context, config,
2016 if((b->kdc_options.validate || b->kdc_options.renew) &&
2017 !krb5_principal_compare(context,
2018 krbtgt->entry.principal,
2019 server->entry.principal)){
2020 kdc_log(context, config, 0, "Inconsistent request.");
2021 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2025 /* check for valid set of addresses */
2026 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2027 ret = KRB5KRB_AP_ERR_BADADDR;
2028 kdc_log(context, config, 0, "Request from wrong address");
2033 * If this is an referral, add server referral data to the
2040 kdc_log(context, config, 0,
2041 "Adding server referral to %s", ref_realm);
2043 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2047 ret = build_server_referral(context, config, crypto, ref_realm,
2048 NULL, s, &pa.padata_value);
2049 krb5_crypto_destroy(context, crypto);
2051 kdc_log(context, config, 0,
2052 "Failed building server referral");
2055 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2057 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2058 krb5_data_free(&pa.padata_value);
2060 kdc_log(context, config, 0,
2061 "Add server referral METHOD-DATA failed");
2067 * Only add ticket signature if the requested server is not krbtgt, and
2068 * either the header server is krbtgt or, in the case of renewal/validation
2069 * if it was signed with PAC ticket signature and we verified it.
2070 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2071 * change one day (see issue #763) so make sure to check for it.
2075 !krb5_principal_is_krbtgt(context, server->entry.principal))
2076 add_ticket_sig = TRUE;
2079 * Active-Directory implementations use the high part of the kvno as the
2080 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2083 rodc_id = krbtgt_out->entry.kvno >> 16;
2089 ret = tgs_make_reply(context,
2102 server->entry.principal,
2116 free(user2user_name);
2124 krb5_free_keyblock_contents(context, &sessionkey);
2126 _kdc_free_ent(context, krbtgt_out);
2128 _kdc_free_ent(context, server);
2130 _kdc_free_ent(context, client);
2131 if(s4u2self_impersonated_client)
2132 _kdc_free_ent(context, s4u2self_impersonated_client);
2134 if (user2user_princ)
2135 krb5_free_principal(context, user2user_princ);
2137 krb5_free_principal(context, tp);
2139 krb5_free_principal(context, cp);
2141 krb5_free_principal(context, dp);
2143 krb5_free_principal(context, sp);
2146 free_METHOD_DATA(&enc_pa_data);
2148 free_EncTicketPart(&adtkt);
2150 krb5_pac_free(context, mspac);
2160 _kdc_tgs_rep(krb5_context context,
2161 krb5_kdc_configuration *config,
2165 struct sockaddr *from_addr,
2168 AuthorizationData *auth_data = NULL;
2169 krb5_error_code ret;
2171 const PA_DATA *tgs_req;
2172 Key *header_key = NULL;
2174 hdb_entry_ex *krbtgt = NULL;
2175 krb5_ticket *ticket = NULL;
2176 const char *e_text = NULL;
2177 krb5_enctype krbtgt_etype = ETYPE_NULL;
2179 krb5_keyblock *replykey = NULL;
2180 int rk_is_subkey = 0;
2181 time_t *csec = NULL;
2184 if(req->padata == NULL){
2185 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2186 kdc_log(context, config, 0,
2187 "TGS-REQ from %s without PA-DATA", from);
2191 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2193 if(tgs_req == NULL){
2194 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2196 kdc_log(context, config, 0,
2197 "TGS-REQ from %s without PA-TGS-REQ", from);
2200 ret = tgs_parse_request(context, config,
2201 &req->req_body, tgs_req,
2212 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2213 /* kdc_log() is called in tgs_parse_request() */
2217 kdc_log(context, config, 0,
2218 "Failed parsing TGS-REQ from %s", from);
2222 ret = tgs_build_reply(context,
2238 kdc_log(context, config, 0,
2239 "Failed building TGS-REP to %s", from);
2244 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2245 krb5_data_free(data);
2246 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2247 e_text = "Reply packet too large";
2252 krb5_free_keyblock(context, replykey);
2253 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2254 krb5_mk_error(context,
2268 krb5_free_ticket(context, ticket);
2270 _kdc_free_ent(context, krbtgt);
2273 free_AuthorizationData(auth_data);