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
36 /* Awful hack to get access to 'struct samba_kdc_entry'. */
37 #include "../../kdc/samba_kdc.h"
40 * return the realm of a krbtgt-ticket or NULL
44 get_krbtgt_realm(const PrincipalName *p)
46 if(p->name_string.len == 2
47 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
48 return p->name_string.val[1];
57 static krb5_error_code
58 check_PAC(krb5_context context,
59 krb5_kdc_configuration *config,
60 const krb5_principal client_principal,
61 const krb5_principal delegated_proxy_principal,
65 hdb_entry_ex *ticket_server,
66 const EncryptionKey *server_check_key,
67 const EncryptionKey *krbtgt_check_key,
69 krb5_boolean *kdc_issued,
74 krb5_boolean signedticket;
79 ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
84 return KRB5KDC_ERR_TGT_REVOKED;
86 /* Verify the server signature. */
87 ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
88 server_check_key, NULL);
90 krb5_pac_free(context, pac);
94 /* Verify the KDC signatures. */
95 ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal,
96 client, server, krbtgt, &pac);
97 if (ret == KRB5_PLUGIN_NO_HANDLE) {
99 * We can't verify the KDC signatures if the ticket was issued by
100 * another realm's KDC.
102 if (krb5_realm_compare(context, server->entry.principal,
103 ticket_server->entry.principal)) {
104 ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
107 krb5_pac_free(context, pac);
111 /* Discard the PAC if the plugin didn't handle it */
112 krb5_pac_free(context, pac);
113 ret = krb5_pac_init(context, &pac);
117 krb5_pac_free(context, pac);
121 *kdc_issued = signedticket ||
122 krb5_principal_is_krbtgt(context,
123 ticket_server->entry.principal);
133 static krb5_error_code
134 check_tgs_flags(krb5_context context,
135 krb5_kdc_configuration *config,
136 const hdb_entry_ex *krbtgt_in,
137 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
139 KDCOptions f = b->kdc_options;
142 if(!tgt->flags.invalid || tgt->starttime == NULL){
143 kdc_log(context, config, 0,
144 "Bad request to validate ticket");
145 return KRB5KDC_ERR_BADOPTION;
147 if(*tgt->starttime > kdc_time){
148 kdc_log(context, config, 0,
149 "Early request to validate ticket");
150 return KRB5KRB_AP_ERR_TKT_NYV;
153 et->flags.invalid = 0;
154 }else if(tgt->flags.invalid){
155 kdc_log(context, config, 0,
156 "Ticket-granting ticket has INVALID flag set");
157 return KRB5KRB_AP_ERR_TKT_INVALID;
161 if(!tgt->flags.forwardable){
162 kdc_log(context, config, 0,
163 "Bad request for forwardable ticket");
164 return KRB5KDC_ERR_BADOPTION;
166 et->flags.forwardable = 1;
169 if(!tgt->flags.forwardable){
170 kdc_log(context, config, 0,
171 "Request to forward non-forwardable ticket");
172 return KRB5KDC_ERR_BADOPTION;
174 et->flags.forwarded = 1;
175 et->caddr = b->addresses;
177 if(tgt->flags.forwarded)
178 et->flags.forwarded = 1;
181 if(!tgt->flags.proxiable){
182 kdc_log(context, config, 0,
183 "Bad request for proxiable ticket");
184 return KRB5KDC_ERR_BADOPTION;
186 et->flags.proxiable = 1;
189 if(!tgt->flags.proxiable){
190 kdc_log(context, config, 0,
191 "Request to proxy non-proxiable ticket");
192 return KRB5KDC_ERR_BADOPTION;
195 et->caddr = b->addresses;
200 if(f.allow_postdate){
201 if(!tgt->flags.may_postdate){
202 kdc_log(context, config, 0,
203 "Bad request for post-datable ticket");
204 return KRB5KDC_ERR_BADOPTION;
206 et->flags.may_postdate = 1;
209 if(!tgt->flags.may_postdate){
210 kdc_log(context, config, 0,
211 "Bad request for postdated ticket");
212 return KRB5KDC_ERR_BADOPTION;
215 *et->starttime = *b->from;
216 et->flags.postdated = 1;
217 et->flags.invalid = 1;
218 }else if(b->from && *b->from > kdc_time + context->max_skew){
219 kdc_log(context, config, 0, "Ticket cannot be postdated");
220 return KRB5KDC_ERR_CANNOT_POSTDATE;
224 if(!tgt->flags.renewable || tgt->renew_till == NULL){
225 kdc_log(context, config, 0,
226 "Bad request for renewable ticket");
227 return KRB5KDC_ERR_BADOPTION;
229 et->flags.renewable = 1;
230 ALLOC(et->renew_till);
231 _kdc_fix_time(&b->rtime);
232 *et->renew_till = *b->rtime;
236 if(!tgt->flags.renewable || tgt->renew_till == NULL){
237 kdc_log(context, config, 0,
238 "Request to renew non-renewable ticket");
239 return KRB5KDC_ERR_BADOPTION;
241 old_life = tgt->endtime;
243 old_life -= *tgt->starttime;
245 old_life -= tgt->authtime;
246 et->endtime = *et->starttime + old_life;
247 if (et->renew_till != NULL)
248 et->endtime = min(*et->renew_till, et->endtime);
251 if (tgt->endtime - kdc_time <= CHANGEPW_LIFETIME) {
252 /* Check that the ticket has not arrived across a trust. */
253 const struct samba_kdc_entry *skdc_entry = krbtgt_in->ctx;
254 if (!skdc_entry->is_trust) {
255 /* This may be a kpasswd ticket rather than a TGT, so don't accept it. */
256 kdc_log(context, config, 0,
257 "Ticket is not a ticket-granting ticket");
258 return KRB5KRB_AP_ERR_TKT_EXPIRED;
263 /* checks for excess flags */
264 if(f.request_anonymous && !config->allow_anonymous){
265 kdc_log(context, config, 0,
266 "Request for anonymous ticket");
267 return KRB5KDC_ERR_BADOPTION;
274 * Determine if constrained delegation is allowed from this client to this server
277 static krb5_error_code
278 check_constrained_delegation(krb5_context context,
279 krb5_kdc_configuration *config,
281 hdb_entry_ex *client,
282 hdb_entry_ex *server,
283 krb5_const_principal target)
285 const HDB_Ext_Constrained_delegation_acl *acl;
290 * constrained_delegation (S4U2Proxy) only works within
291 * the same realm. We use the already canonicalized version
292 * of the principals here, while "target" is the principal
293 * provided by the client.
295 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
296 ret = KRB5KDC_ERR_BADOPTION;
297 kdc_log(context, config, 0,
298 "Bad request for constrained delegation");
302 if (clientdb->hdb_check_constrained_delegation) {
303 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
307 /* if client delegates to itself, that ok */
308 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
311 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
313 krb5_clear_error_message(context);
318 for (i = 0; i < acl->len; i++) {
319 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
323 ret = KRB5KDC_ERR_BADOPTION;
325 kdc_log(context, config, 0,
326 "Bad request for constrained delegation");
331 * Determine if s4u2self is allowed from this client to this server
333 * For example, regardless of the principal being impersonated, if the
334 * 'client' and 'server' (target) are the same, then it's safe.
337 static krb5_error_code
338 check_s4u2self(krb5_context context,
339 krb5_kdc_configuration *config,
341 hdb_entry_ex *client,
342 hdb_entry_ex *target_server,
343 krb5_const_principal target_server_principal)
348 * Always allow the plugin to check, this might be faster, allow a
349 * policy or audit check and can look into the DB records
352 if (clientdb->hdb_check_s4u2self) {
353 ret = clientdb->hdb_check_s4u2self(context,
359 } else if (krb5_principal_compare(context,
360 client->entry.principal,
361 target_server_principal) == TRUE) {
362 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
365 ret = KRB5KDC_ERR_BADOPTION;
374 static krb5_error_code
375 verify_flags (krb5_context context,
376 krb5_kdc_configuration *config,
377 const EncTicketPart *et,
380 if(et->endtime < kdc_time){
381 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
382 return KRB5KRB_AP_ERR_TKT_EXPIRED;
384 if(et->flags.invalid){
385 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
386 return KRB5KRB_AP_ERR_TKT_NYV;
395 static krb5_error_code
396 fix_transited_encoding(krb5_context context,
397 krb5_kdc_configuration *config,
398 krb5_boolean check_policy,
399 const TransitedEncoding *tr,
401 const char *client_realm,
402 const char *server_realm,
403 const char *tgt_realm)
405 krb5_error_code ret = 0;
406 char **realms, **tmp;
407 unsigned int num_realms;
410 switch (tr->tr_type) {
411 case DOMAIN_X500_COMPRESS:
415 * Allow empty content of type 0 because that is was Microsoft
416 * generates in their TGT.
418 if (tr->contents.length == 0)
420 kdc_log(context, config, 0,
421 "Transited type 0 with non empty content");
422 return KRB5KDC_ERR_TRTYPE_NOSUPP;
424 kdc_log(context, config, 0,
425 "Unknown transited type: %u", tr->tr_type);
426 return KRB5KDC_ERR_TRTYPE_NOSUPP;
429 ret = krb5_domain_x500_decode(context,
436 krb5_warn(context, ret,
437 "Decoding transited encoding");
442 * If the realm of the presented tgt is neither the client nor the server
443 * realm, it is a transit realm and must be added to transited set.
445 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
446 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
450 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
456 realms[num_realms] = strdup(tgt_realm);
457 if(realms[num_realms] == NULL){
463 if(num_realms == 0) {
464 if(strcmp(client_realm, server_realm))
465 kdc_log(context, config, 0,
466 "cross-realm %s -> %s", client_realm, server_realm);
470 for(i = 0; i < num_realms; i++)
471 l += strlen(realms[i]) + 2;
475 for(i = 0; i < num_realms; i++) {
477 strlcat(rs, ", ", l);
478 strlcat(rs, realms[i], l);
480 kdc_log(context, config, 0,
481 "cross-realm %s -> %s via [%s]",
482 client_realm, server_realm, rs);
487 ret = krb5_check_transited(context, client_realm,
489 realms, num_realms, NULL);
491 krb5_warn(context, ret, "cross-realm %s -> %s",
492 client_realm, server_realm);
495 et->flags.transited_policy_checked = 1;
497 et->transited.tr_type = DOMAIN_X500_COMPRESS;
498 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
500 krb5_warn(context, ret, "Encoding transited encoding");
502 for(i = 0; i < num_realms; i++)
509 static krb5_error_code
510 tgs_make_reply(krb5_context context,
511 krb5_kdc_configuration *config,
513 krb5_principal tgt_name,
514 const EncTicketPart *tgt,
515 const krb5_keyblock *replykey,
517 const EncryptionKey *serverkey,
518 const EncryptionKey *krbtgtkey,
519 const krb5_keyblock *sessionkey,
521 AuthorizationData *auth_data,
522 hdb_entry_ex *server,
523 krb5_principal server_principal,
524 const char *server_name,
525 hdb_entry_ex *client,
526 krb5_principal client_principal,
527 const char *tgt_realm,
528 const hdb_entry_ex *krbtgt_in,
529 hdb_entry_ex *krbtgt,
532 krb5_boolean add_ticket_sig,
533 const METHOD_DATA *enc_pa_data,
540 KDCOptions f = b->kdc_options;
544 memset(&rep, 0, sizeof(rep));
545 memset(&et, 0, sizeof(et));
546 memset(&ek, 0, sizeof(ek));
549 rep.msg_type = krb_tgs_rep;
551 et.authtime = tgt->authtime;
552 _kdc_fix_time(&b->till);
553 et.endtime = min(tgt->endtime, *b->till);
555 *et.starttime = kdc_time;
557 ret = check_tgs_flags(context, config, krbtgt_in, b, tgt, &et);
561 /* We should check the transited encoding if:
562 1) the request doesn't ask not to be checked
563 2) globally enforcing a check
564 3) principal requires checking
565 4) we allow non-check per-principal, but principal isn't marked as allowing this
566 5) we don't globally allow this
569 #define GLOBAL_FORCE_TRANSITED_CHECK \
570 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
571 #define GLOBAL_ALLOW_PER_PRINCIPAL \
572 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
573 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
574 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
576 /* these will consult the database in future release */
577 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
578 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
580 ret = fix_transited_encoding(context, config,
581 !f.disable_transited_check ||
582 GLOBAL_FORCE_TRANSITED_CHECK ||
583 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
584 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
585 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
586 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
587 &tgt->transited, &et,
588 krb5_principal_get_realm(context, client_principal),
589 krb5_principal_get_realm(context, server->entry.principal),
594 copy_Realm(&server_principal->realm, &rep.ticket.realm);
595 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
596 copy_Realm(&tgt_name->realm, &rep.crealm);
598 if (f.request_anonymous)
599 _kdc_make_anonymous_principalname (&rep.cname);
602 copy_PrincipalName(&tgt_name->name, &rep.cname);
603 rep.ticket.tkt_vno = 5;
607 et.caddr = tgt->caddr;
611 life = et.endtime - *et.starttime;
612 if(client && client->entry.max_life)
613 life = min(life, *client->entry.max_life);
614 if(server->entry.max_life)
615 life = min(life, *server->entry.max_life);
616 et.endtime = *et.starttime + life;
618 if(f.renewable_ok && tgt->flags.renewable &&
619 et.renew_till == NULL && et.endtime < *b->till &&
620 tgt->renew_till != NULL)
622 et.flags.renewable = 1;
623 ALLOC(et.renew_till);
624 *et.renew_till = *b->till;
628 renew = *et.renew_till - et.authtime;
629 if(client && client->entry.max_renew)
630 renew = min(renew, *client->entry.max_renew);
631 if(server->entry.max_renew)
632 renew = min(renew, *server->entry.max_renew);
633 *et.renew_till = et.authtime + renew;
637 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
638 *et.starttime = min(*et.starttime, *et.renew_till);
639 et.endtime = min(et.endtime, *et.renew_till);
642 *et.starttime = min(*et.starttime, et.endtime);
644 if(*et.starttime == et.endtime){
645 ret = KRB5KDC_ERR_NEVER_VALID;
648 if(et.renew_till && et.endtime == *et.renew_till){
650 et.renew_till = NULL;
651 et.flags.renewable = 0;
654 et.flags.pre_authent = tgt->flags.pre_authent;
655 et.flags.hw_authent = tgt->flags.hw_authent;
656 et.flags.anonymous = tgt->flags.anonymous;
657 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
659 /* See MS-KILE 3.3.5.1 */
660 if (!server->entry.flags.forwardable)
661 et.flags.forwardable = 0;
662 if (!server->entry.flags.proxiable)
663 et.flags.proxiable = 0;
668 /* XXX check authdata */
670 if (et.authorization_data == NULL) {
671 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
672 if (et.authorization_data == NULL) {
674 krb5_set_error_message(context, ret, "malloc: out of memory");
678 for(i = 0; i < auth_data->len ; i++) {
679 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
681 krb5_set_error_message(context, ret, "malloc: out of memory");
687 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
690 et.crealm = tgt_name->realm;
691 et.cname = tgt_name->name;
694 /* MIT must have at least one last_req */
696 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
697 if (ek.last_req.val == NULL) {
703 ek.authtime = et.authtime;
704 ek.starttime = et.starttime;
705 ek.endtime = et.endtime;
706 ek.renew_till = et.renew_till;
707 ek.srealm = rep.ticket.realm;
708 ek.sname = rep.ticket.sname;
710 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
711 et.endtime, et.renew_till);
713 if (enc_pa_data->len) {
714 rep.padata = calloc(1, sizeof(*rep.padata));
715 if (rep.padata == NULL) {
719 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
724 if (krb5_enctype_valid(context, et.key.keytype) != 0
725 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
727 krb5_enctype_enable(context, et.key.keytype);
731 /* The PAC should be the last change to the ticket. */
733 ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
734 krbtgtkey, rodc_id, add_ticket_sig, add_ticket_sig, &et);
739 /* It is somewhat unclear where the etype in the following
740 encryption should come from. What we have is a session
741 key in the passed tgt, and a list of preferred etypes
742 *for the new ticket*. Should we pick the best possible
743 etype, given the keytype in the tgt, or should we look
744 at the etype list here as well? What if the tgt
745 session key is DES3 and we want a ticket with a (say)
746 CAST session key. Should the DES3 etype be added to the
747 etype list, even if we don't want a session key with
749 ret = _kdc_encode_reply(context, config,
750 &rep, &et, &ek, serverkey->keytype,
752 serverkey, 0, replykey, rk_is_subkey,
755 krb5_enctype_disable(context, et.key.keytype);
759 free_TransitedEncoding(&et.transited);
764 if(et.authorization_data) {
765 free_AuthorizationData(et.authorization_data);
766 free(et.authorization_data);
768 free_LastReq(&ek.last_req);
769 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
770 free_EncryptionKey(&et.key);
774 static krb5_error_code
775 tgs_check_authenticator(krb5_context context,
776 krb5_kdc_configuration *config,
777 krb5_auth_context ac,
782 krb5_authenticator auth;
789 krb5_auth_con_getauthenticator(context, ac, &auth);
790 if(auth->cksum == NULL){
791 kdc_log(context, config, 0, "No authenticator in request");
792 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
796 * according to RFC1510 it doesn't need to be keyed,
797 * but according to the latest draft it needs to.
801 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
804 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
805 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
806 auth->cksum->cksumtype);
807 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
811 /* XXX should not re-encode this */
812 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
814 const char *msg = krb5_get_error_message(context, ret);
815 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
816 krb5_free_error_message(context, msg);
819 if(buf_size != len) {
821 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
822 *e_text = "KDC internal error";
823 ret = KRB5KRB_ERR_GENERIC;
826 ret = krb5_crypto_init(context, key, 0, &crypto);
828 const char *msg = krb5_get_error_message(context, ret);
830 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
831 krb5_free_error_message(context, msg);
834 ret = krb5_verify_checksum(context,
836 KRB5_KU_TGS_REQ_AUTH_CKSUM,
841 krb5_crypto_destroy(context, crypto);
843 const char *msg = krb5_get_error_message(context, ret);
844 kdc_log(context, config, 0,
845 "Failed to verify authenticator checksum: %s", msg);
846 krb5_free_error_message(context, msg);
849 free_Authenticator(auth);
859 find_rpath(krb5_context context, Realm crealm, Realm srealm)
861 const char *new_realm = krb5_config_get_string(context,
872 need_referral(krb5_context context, krb5_kdc_configuration *config,
873 const KDCOptions * const options, krb5_principal server,
878 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
881 if (server->name.name_string.len == 1)
882 name = server->name.name_string.val[0];
883 else if (server->name.name_string.len == 3) {
885 This is used to give referrals for the
886 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
887 SPN form, which is used for inter-domain communication in AD
889 name = server->name.name_string.val[2];
890 kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
891 *realms = malloc(sizeof(char *)*2);
892 if (*realms == NULL) {
893 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
896 (*realms)[0] = strdup(name);
899 } else if (server->name.name_string.len > 1)
900 name = server->name.name_string.val[1];
904 kdc_log(context, config, 0, "Searching referral for %s", name);
906 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
909 static krb5_error_code
910 tgs_parse_request(krb5_context context,
911 krb5_kdc_configuration *config,
913 const PA_DATA *tgs_req,
914 hdb_entry_ex **krbtgt,
915 krb5_enctype *krbtgt_etype,
916 krb5_ticket **ticket,
919 const struct sockaddr *from_addr,
922 AuthorizationData **auth_data,
923 krb5_keyblock **replykey,
927 static char failed[] = "<unparse_name failed>";
930 krb5_principal princ;
931 krb5_auth_context ac = NULL;
932 krb5_flags ap_req_options;
933 krb5_flags verify_ap_req_flags;
936 krb5_keyblock *subkey = NULL;
939 krb5uint32 *kvno_ptr = NULL;
946 memset(&ap_req, 0, sizeof(ap_req));
947 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
949 const char *msg = krb5_get_error_message(context, ret);
950 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
951 krb5_free_error_message(context, msg);
955 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
956 /* XXX check for ticket.sname == req.sname */
957 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
958 ret = KRB5KDC_ERR_POLICY; /* ? */
962 _krb5_principalname2krb5_principal(context,
965 ap_req.ticket.realm);
967 if (ap_req.ticket.enc_part.kvno) {
968 kvno = *ap_req.ticket.enc_part.kvno;
971 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, kvno_ptr,
974 if(ret == HDB_ERR_NOT_FOUND_HERE) {
976 ret = krb5_unparse_name(context, princ, &p);
979 krb5_free_principal(context, princ);
980 kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
983 ret = HDB_ERR_NOT_FOUND_HERE;
986 const char *msg = krb5_get_error_message(context, ret);
988 ret = krb5_unparse_name(context, princ, &p);
991 krb5_free_principal(context, princ);
992 kdc_log(context, config, 0,
993 "Ticket-granting ticket not found in database: %s", msg);
994 krb5_free_error_message(context, msg);
997 ret = KRB5KRB_AP_ERR_NOT_US;
1001 if(ap_req.ticket.enc_part.kvno &&
1002 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1005 ret = krb5_unparse_name (context, princ, &p);
1006 krb5_free_principal(context, princ);
1009 kdc_log(context, config, 0,
1010 "Ticket kvno = %d, DB kvno = %d (%s)",
1011 *ap_req.ticket.enc_part.kvno,
1012 (*krbtgt)->entry.kvno,
1016 ret = KRB5KRB_AP_ERR_BADKEYVER;
1020 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1022 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1023 ap_req.ticket.enc_part.etype, &tkey);
1025 char *str = NULL, *p = NULL;
1027 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1028 krb5_unparse_name(context, princ, &p);
1029 kdc_log(context, config, 0,
1030 "No server key with enctype %s found for %s",
1031 str ? str : "<unknown enctype>",
1032 p ? p : "<unparse_name failed>");
1035 ret = KRB5KRB_AP_ERR_BADKEYVER;
1039 if (b->kdc_options.validate)
1040 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1042 verify_ap_req_flags = 0;
1044 ret = krb5_verify_ap_req2(context,
1049 verify_ap_req_flags,
1052 KRB5_KU_TGS_REQ_AUTH);
1054 krb5_free_principal(context, princ);
1056 const char *msg = krb5_get_error_message(context, ret);
1057 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1058 krb5_free_error_message(context, msg);
1065 krb5_authenticator auth;
1067 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1069 *csec = malloc(sizeof(**csec));
1070 if (*csec == NULL) {
1071 krb5_free_authenticator(context, &auth);
1072 kdc_log(context, config, 0, "malloc failed");
1075 **csec = auth->ctime;
1076 *cusec = malloc(sizeof(**cusec));
1077 if (*cusec == NULL) {
1078 krb5_free_authenticator(context, &auth);
1079 kdc_log(context, config, 0, "malloc failed");
1082 **cusec = auth->cusec;
1083 krb5_free_authenticator(context, &auth);
1087 ret = tgs_check_authenticator(context, config,
1088 ac, b, e_text, &(*ticket)->ticket.key);
1090 krb5_auth_con_free(context, ac);
1094 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1097 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1099 const char *msg = krb5_get_error_message(context, ret);
1100 krb5_auth_con_free(context, ac);
1101 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1102 krb5_free_error_message(context, msg);
1106 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1109 ret = krb5_auth_con_getkey(context, ac, &subkey);
1111 const char *msg = krb5_get_error_message(context, ret);
1112 krb5_auth_con_free(context, ac);
1113 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1114 krb5_free_error_message(context, msg);
1119 krb5_auth_con_free(context, ac);
1120 kdc_log(context, config, 0,
1121 "Failed to get key for enc-authorization-data");
1122 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1128 if (b->enc_authorization_data) {
1131 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1133 const char *msg = krb5_get_error_message(context, ret);
1134 krb5_auth_con_free(context, ac);
1135 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1136 krb5_free_error_message(context, msg);
1139 ret = krb5_decrypt_EncryptedData (context,
1142 b->enc_authorization_data,
1144 krb5_crypto_destroy(context, crypto);
1146 krb5_auth_con_free(context, ac);
1147 kdc_log(context, config, 0,
1148 "Failed to decrypt enc-authorization-data");
1149 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1153 if (*auth_data == NULL) {
1154 krb5_auth_con_free(context, ac);
1155 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1158 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1160 krb5_auth_con_free(context, ac);
1163 kdc_log(context, config, 0, "Failed to decode authorization data");
1164 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1169 krb5_auth_con_free(context, ac);
1172 free_AP_REQ(&ap_req);
1177 static krb5_error_code
1178 build_server_referral(krb5_context context,
1179 krb5_kdc_configuration *config,
1180 krb5_crypto session,
1181 krb5_const_realm referred_realm,
1182 const PrincipalName *true_principal_name,
1183 const PrincipalName *requested_principal,
1186 PA_ServerReferralData ref;
1187 krb5_error_code ret;
1192 memset(&ref, 0, sizeof(ref));
1194 if (referred_realm) {
1195 ALLOC(ref.referred_realm);
1196 if (ref.referred_realm == NULL)
1198 *ref.referred_realm = strdup(referred_realm);
1199 if (*ref.referred_realm == NULL)
1202 if (true_principal_name) {
1203 ALLOC(ref.true_principal_name);
1204 if (ref.true_principal_name == NULL)
1206 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1210 if (requested_principal) {
1211 ALLOC(ref.requested_principal_name);
1212 if (ref.requested_principal_name == NULL)
1214 ret = copy_PrincipalName(requested_principal,
1215 ref.requested_principal_name);
1220 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1221 data.data, data.length,
1223 free_PA_ServerReferralData(&ref);
1226 if (data.length != size)
1227 krb5_abortx(context, "internal asn.1 encoder error");
1229 ret = krb5_encrypt_EncryptedData(context, session,
1230 KRB5_KU_PA_SERVER_REFERRAL,
1231 data.data, data.length,
1237 ASN1_MALLOC_ENCODE(EncryptedData,
1238 outdata->data, outdata->length,
1240 free_EncryptedData(&ed);
1243 if (outdata->length != size)
1244 krb5_abortx(context, "internal asn.1 encoder error");
1248 free_PA_ServerReferralData(&ref);
1249 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1253 static krb5_error_code
1254 db_fetch_client(krb5_context context,
1255 krb5_kdc_configuration *config,
1259 const char *krbtgt_realm,
1261 hdb_entry_ex **client_out)
1263 krb5_error_code ret;
1264 hdb_entry_ex *client = NULL;
1268 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1269 NULL, clientdb, &client);
1270 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1272 * This is OK, we are just trying to find out if they have
1273 * been disabled or deleted in the meantime; missing secrets
1278 * If the client belongs to the same realm as our TGS, it
1279 * should exist in the local database.
1283 if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1284 if (ret == HDB_ERR_NOENTRY)
1285 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1286 kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
1290 msg = krb5_get_error_message(context, ret);
1291 kdc_log(context, config, 4, "Client not found in database: %s", msg);
1292 krb5_free_error_message(context, msg);
1293 } else if (client->entry.flags.invalid || !client->entry.flags.client) {
1294 kdc_log(context, config, 4, "Client has invalid bit set");
1295 _kdc_free_ent(context, client);
1296 return KRB5KDC_ERR_POLICY;
1299 *client_out = client;
1304 static krb5_error_code
1305 tgs_build_reply(krb5_context context,
1306 krb5_kdc_configuration *config,
1309 hdb_entry_ex *krbtgt,
1310 krb5_enctype krbtgt_etype,
1312 const krb5_keyblock *replykey,
1314 krb5_ticket *ticket,
1317 const char **e_text,
1318 AuthorizationData **auth_data,
1319 const struct sockaddr *from_addr)
1321 krb5_error_code ret;
1322 krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
1323 krb5_principal krbtgt_out_principal = NULL;
1324 krb5_principal user2user_princ = NULL;
1325 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1326 char *user2user_name = NULL;
1327 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1328 hdb_entry_ex *user2user_krbtgt = NULL;
1329 HDB *clientdb, *s4u2self_impersonated_clientdb;
1330 HDB *serverdb = NULL;
1331 krb5_realm ref_realm = NULL;
1332 EncTicketPart *tgt = &ticket->ticket;
1333 const char *tgt_realm = /* Realm of TGT issuer */
1334 krb5_principal_get_realm(context, krbtgt->entry.principal);
1335 const EncryptionKey *ekey;
1336 krb5_keyblock sessionkey;
1338 krb5_pac mspac = NULL;
1339 krb5_pac user2user_pac = NULL;
1341 krb5_boolean add_ticket_sig = FALSE;
1342 hdb_entry_ex *krbtgt_out = NULL;
1344 METHOD_DATA enc_pa_data;
1349 EncTicketPart adtkt;
1351 krb5_boolean kdc_issued = FALSE;
1354 int flags = HDB_F_FOR_TGS_REQ;
1356 memset(&sessionkey, 0, sizeof(sessionkey));
1357 memset(&adtkt, 0, sizeof(adtkt));
1358 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1363 if (b->kdc_options.canonicalize)
1364 flags |= HDB_F_CANON;
1367 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1368 krb5_set_error_message(context, ret, "No server in request");
1372 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1373 ret = krb5_unparse_name(context, sp, &spn);
1376 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1377 ret = krb5_unparse_name(context, cp, &cpn);
1380 unparse_flags (KDCOptions2int(b->kdc_options),
1381 asn1_KDCOptions_units(),
1382 opt_str, sizeof(opt_str));
1384 kdc_log(context, config, 0,
1385 "TGS-REQ %s from %s for %s [%s]",
1386 cpn, from, spn, opt_str);
1388 kdc_log(context, config, 0,
1389 "TGS-REQ %s from %s for %s", cpn, from, spn);
1396 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1397 NULL, &serverdb, &server);
1399 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1400 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1402 } else if (ret == HDB_ERR_WRONG_REALM) {
1405 ref_realm = strdup(server->entry.principal->realm);
1406 if (ref_realm == NULL) {
1411 kdc_log(context, config, 5,
1412 "Returning a referral to realm %s for "
1415 krb5_free_principal(context, sp);
1419 ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1423 ret = krb5_unparse_name(context, sp, &spn);
1429 const char *new_rlm, *msg;
1433 if (!config->autodetect_referrals) {
1435 } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1437 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1439 kdc_log(context, config, 5, "krbtgt for realm %s "
1440 "not found, trying %s",
1442 krb5_free_principal(context, sp);
1444 krb5_make_principal(context, &sp, r,
1445 KRB5_TGS_NAME, new_rlm, NULL);
1446 ret = krb5_unparse_name(context, sp, &spn);
1452 ref_realm = strdup(new_rlm);
1456 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1457 if (strcmp(realms[0], sp->realm) != 0) {
1458 kdc_log(context, config, 5,
1459 "Returning a referral to realm %s for "
1460 "server %s that was not found",
1462 krb5_free_principal(context, sp);
1464 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1466 ret = krb5_unparse_name(context, sp, &spn);
1472 ref_realm = strdup(realms[0]);
1474 krb5_free_host_realm(context, realms);
1477 krb5_free_host_realm(context, realms);
1479 msg = krb5_get_error_message(context, ret);
1480 kdc_log(context, config, 0,
1481 "Server not found in database: %s: %s", spn, msg);
1482 krb5_free_error_message(context, msg);
1483 if (ret == HDB_ERR_NOENTRY)
1484 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1488 /* Now refetch the primary krbtgt, and get the current kvno (the
1489 * sign check may have been on an old kvno, and the server may
1490 * have been an incoming trust) */
1491 ret = krb5_make_principal(context, &krbtgt_out_principal,
1492 krb5_principal_get_comp_string(context,
1493 krbtgt->entry.principal,
1496 krb5_principal_get_comp_string(context,
1497 krbtgt->entry.principal,
1500 kdc_log(context, config, 0,
1501 "Failed to make krbtgt principal name object for "
1502 "authz-data signatures");
1505 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1507 kdc_log(context, config, 0,
1508 "Failed to make krbtgt principal name object for "
1509 "authz-data signatures");
1513 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1514 HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1517 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1518 kdc_log(context, config, 0,
1519 "No such principal %s (needed for authz-data signature keys) "
1520 "while processing TGS-REQ for service %s with krbtg %s",
1521 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1523 ret = KRB5KRB_AP_ERR_NOT_US;
1528 * Select enctype, return key and kvno.
1534 if(b->kdc_options.enc_tkt_in_skey) {
1538 krb5uint32 second_kvno = 0;
1539 krb5uint32 *kvno_ptr = NULL;
1541 hdb_entry_ex *user2user_client = NULL;
1542 krb5_boolean user2user_kdc_issued = FALSE;
1544 if(b->additional_tickets == NULL ||
1545 b->additional_tickets->len == 0){
1546 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1547 kdc_log(context, config, 0,
1548 "No second ticket present in request");
1551 t = &b->additional_tickets->val[0];
1552 if(!get_krbtgt_realm(&t->sname)){
1553 kdc_log(context, config, 0,
1554 "Additional ticket is not a ticket-granting ticket");
1555 ret = KRB5KDC_ERR_POLICY;
1558 ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1562 if(t->enc_part.kvno){
1563 second_kvno = *t->enc_part.kvno;
1564 kvno_ptr = &second_kvno;
1566 ret = _kdc_db_fetch(context, config, p,
1567 HDB_F_GET_KRBTGT, kvno_ptr,
1568 NULL, &user2user_krbtgt);
1569 krb5_free_principal(context, p);
1571 if (ret == HDB_ERR_NOENTRY)
1572 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1575 ret = hdb_enctype2key(context, &user2user_krbtgt->entry,
1576 t->enc_part.etype, &uukey);
1578 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1581 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1585 ret = verify_flags(context, config, &adtkt, spn);
1589 /* Fetch the name from the TGT. */
1590 ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1591 adtkt.cname, adtkt.crealm);
1596 ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1601 /* Look up the name given in the TGT in the database. */
1602 ret = db_fetch_client(context, config, flags, user2user_princ, user2user_name,
1603 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1604 NULL, &user2user_client);
1609 if (user2user_client != NULL) {
1611 * If the account is present in the database, check the account
1614 ret = kdc_check_flags(context, config,
1615 user2user_client, user2user_name,
1619 _kdc_free_ent(context, user2user_client);
1624 * Also check that the account is the same one specified in the
1627 ret = check_s4u2self(context, config, serverdb, server, user2user_client, user2user_princ);
1629 _kdc_free_ent(context, user2user_client);
1634 /* Verify the PAC of the TGT. */
1635 ret = check_PAC(context, config, user2user_princ, NULL,
1636 user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
1637 &uukey->key, &tkey_check->key, &adtkt, &user2user_kdc_issued, &user2user_pac);
1638 _kdc_free_ent(context, user2user_client);
1640 const char *msg = krb5_get_error_message(context, ret);
1641 kdc_log(context, config, 0,
1642 "Verify PAC failed for %s (%s) from %s with %s",
1643 spn, user2user_name, from, msg);
1644 krb5_free_error_message(context, msg);
1648 if (user2user_pac == NULL || !user2user_kdc_issued) {
1649 ret = KRB5KDC_ERR_BADOPTION;
1650 kdc_log(context, config, 0,
1651 "Ticket not signed with PAC; user-to-user failed (%s).",
1652 user2user_pac ? "Ticket unsigned" : "No PAC");
1657 for(i = 0; i < b->etype.len; i++)
1658 if (b->etype.val[i] == adtkt.key.keytype)
1660 if(i == b->etype.len) {
1661 kdc_log(context, config, 0,
1662 "Addition ticket have not matching etypes");
1663 krb5_clear_error_message(context);
1664 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1667 etype = b->etype.val[i];
1672 ret = _kdc_find_session_etype(context, b->etype.val, b->etype.len,
1675 kdc_log(context, config, 0,
1676 "Server (%s) has no support for etypes", spn);
1679 ret = _kdc_get_preferred_key(context, config, server, spn,
1682 kdc_log(context, config, 0,
1683 "Server (%s) has no supported etypes", spn);
1687 kvno = server->entry.kvno;
1690 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1696 * Check that service is in the same realm as the krbtgt. If it's
1697 * not the same, it's someone that is using a uni-directional trust
1701 /* The first realm is the realm of the service, the second is
1702 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1703 * encrypted to. The redirection via the krbtgt_out entry allows
1704 * the DB to possibly correct the case of the realm (Samba4 does
1705 * this) before the strcmp() */
1706 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1707 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1709 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1710 kdc_log(context, config, 0,
1711 "Request with wrong krbtgt: %s",
1712 (ret == 0) ? ktpn : "<unknown>");
1715 ret = KRB5KRB_AP_ERR_NOT_US;
1718 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1721 kdc_log(context, config, 0,
1722 "Failed to find key for krbtgt PAC signature");
1725 ret = hdb_enctype2key(context, &krbtgt_out->entry,
1726 tkey_sign->key.keytype, &tkey_sign);
1728 kdc_log(context, config, 0,
1729 "Failed to find key for krbtgt PAC signature");
1733 ret = db_fetch_client(context, config, flags, cp, cpn,
1734 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1735 &clientdb, &client);
1739 ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1740 &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
1742 const char *msg = krb5_get_error_message(context, ret);
1743 kdc_log(context, config, 0,
1744 "Verify PAC failed for %s (%s) from %s with %s",
1745 spn, cpn, from, msg);
1746 krb5_free_error_message(context, msg);
1754 /* by default the tgt principal matches the client principal */
1759 const PA_DATA *sdata;
1762 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1769 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1770 sdata->padata_value.length,
1773 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1777 if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1778 free_PA_S4U2Self(&self);
1779 kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
1780 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1784 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1788 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1790 const char *msg = krb5_get_error_message(context, ret);
1791 free_PA_S4U2Self(&self);
1792 krb5_data_free(&datack);
1793 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1794 krb5_free_error_message(context, msg);
1798 /* Allow HMAC_MD5 checksum with any key type */
1799 if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
1800 unsigned char csdata[16];
1803 cs.checksum.length = sizeof(csdata);
1804 cs.checksum.data = &csdata;
1806 ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
1807 datack.data, datack.length,
1808 KRB5_KU_OTHER_CKSUM, &cs);
1810 krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
1811 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1814 ret = krb5_verify_checksum(context,
1816 KRB5_KU_OTHER_CKSUM,
1821 krb5_data_free(&datack);
1822 krb5_crypto_destroy(context, crypto);
1824 const char *msg = krb5_get_error_message(context, ret);
1825 free_PA_S4U2Self(&self);
1826 kdc_log(context, config, 0,
1827 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1828 krb5_free_error_message(context, msg);
1832 ret = _krb5_principalname2krb5_principal(context,
1836 free_PA_S4U2Self(&self);
1840 ret = krb5_unparse_name(context, tp, &tpn);
1844 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1845 NULL, &s4u2self_impersonated_clientdb,
1846 &s4u2self_impersonated_client);
1851 * If the client belongs to the same realm as our krbtgt, it
1852 * should exist in the local database.
1856 if (ret == HDB_ERR_NOENTRY)
1857 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1858 msg = krb5_get_error_message(context, ret);
1859 kdc_log(context, config, 1,
1860 "S2U4Self principal to impersonate %s not found in database: %s",
1862 krb5_free_error_message(context, msg);
1866 /* Ignore pw_end attributes (as Windows does),
1867 * since S4U2Self is not password authentication. */
1868 free(s4u2self_impersonated_client->entry.pw_end);
1869 s4u2self_impersonated_client->entry.pw_end = NULL;
1871 ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
1876 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1878 krb5_pac_free(context, mspac);
1882 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, server,
1883 NULL, NULL, &mspac);
1885 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1891 * Check that service doing the impersonating is
1892 * requesting a ticket to it-self.
1894 ret = check_s4u2self(context, config, clientdb, client, server, sp);
1896 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1897 "to impersonate to service "
1898 "(tried for user %s to service %s)",
1904 * If the service isn't trusted for authentication to
1905 * delegation or if the impersonate client is disallowed
1906 * forwardable, remove the forwardable flag.
1909 if (client->entry.flags.trusted_for_delegation &&
1910 s4u2self_impersonated_client->entry.flags.forwardable) {
1911 str = "[forwardable]";
1913 b->kdc_options.forwardable = 0;
1916 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1917 "service %s %s", cpn, tpn, spn, str);
1922 * Constrained delegation
1926 && b->additional_tickets != NULL
1927 && b->additional_tickets->len != 0
1928 && b->kdc_options.enc_tkt_in_skey == 0)
1930 hdb_entry_ex *adclient = NULL;
1931 krb5_boolean ad_kdc_issued = FALSE;
1936 * We require that the service's krbtgt has a PAC.
1938 if (mspac == NULL) {
1939 ret = KRB5KDC_ERR_BADOPTION;
1940 kdc_log(context, config, 0,
1941 "Constrained delegation without PAC %s/%s",
1946 krb5_pac_free(context, mspac);
1949 t = &b->additional_tickets->val[0];
1951 ret = hdb_enctype2key(context, &client->entry,
1952 t->enc_part.etype, &clientkey);
1954 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1958 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1960 kdc_log(context, config, 0,
1961 "failed to decrypt ticket for "
1962 "constrained delegation from %s to %s ", cpn, spn);
1966 ret = _krb5_principalname2krb5_principal(context,
1973 ret = krb5_unparse_name(context, tp, &tpn);
1977 ret = _krb5_principalname2krb5_principal(context,
1984 ret = krb5_unparse_name(context, dp, &dpn);
1988 /* check that ticket is valid */
1989 if (adtkt.flags.forwardable == 0) {
1990 kdc_log(context, config, 0,
1991 "Missing forwardable flag on ticket for "
1992 "constrained delegation from %s (%s) as %s to %s ",
1993 cpn, dpn, tpn, spn);
1994 ret = KRB5KDC_ERR_BADOPTION;
1998 ret = check_constrained_delegation(context, config, clientdb,
1999 client, server, sp);
2001 kdc_log(context, config, 0,
2002 "constrained delegation from %s (%s) as %s to %s not allowed",
2003 cpn, dpn, tpn, spn);
2007 ret = verify_flags(context, config, &adtkt, tpn);
2012 /* Try lookup the delegated client in DB */
2013 ret = db_fetch_client(context, config, flags, tp, tpn,
2014 krb5_principal_get_realm(context, krbtgt_out->entry.principal),
2019 if (adclient != NULL) {
2020 ret = kdc_check_flags(context, config,
2025 _kdc_free_ent(context, adclient);
2031 * TODO: pass in t->sname and t->realm and build
2032 * a S4U_DELEGATION_INFO blob to the PAC.
2034 ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
2035 &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
2037 _kdc_free_ent(context, adclient);
2039 const char *msg = krb5_get_error_message(context, ret);
2040 kdc_log(context, config, 0,
2041 "Verify delegated PAC failed to %s for client"
2042 "%s (%s) as %s from %s with %s",
2043 spn, cpn, dpn, tpn, from, msg);
2044 krb5_free_error_message(context, msg);
2048 if (mspac == NULL || !ad_kdc_issued) {
2049 ret = KRB5KDC_ERR_BADOPTION;
2050 kdc_log(context, config, 0,
2051 "Ticket not signed with PAC; service %s failed for "
2052 "for delegation to %s for client %s (%s) from %s; (%s).",
2053 spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
2057 kdc_log(context, config, 0, "constrained delegation for %s "
2058 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2065 ret = kdc_check_flags(context, config,
2072 if((b->kdc_options.validate || b->kdc_options.renew) &&
2073 !krb5_principal_compare(context,
2074 krbtgt->entry.principal,
2075 server->entry.principal)){
2076 kdc_log(context, config, 0, "Inconsistent request.");
2077 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2081 /* check for valid set of addresses */
2082 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2083 ret = KRB5KRB_AP_ERR_BADADDR;
2084 kdc_log(context, config, 0, "Request from wrong address");
2089 * If this is an referral, add server referral data to the
2096 kdc_log(context, config, 0,
2097 "Adding server referral to %s", ref_realm);
2099 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2103 ret = build_server_referral(context, config, crypto, ref_realm,
2104 NULL, s, &pa.padata_value);
2105 krb5_crypto_destroy(context, crypto);
2107 kdc_log(context, config, 0,
2108 "Failed building server referral");
2111 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2113 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2114 krb5_data_free(&pa.padata_value);
2116 kdc_log(context, config, 0,
2117 "Add server referral METHOD-DATA failed");
2123 * Only add ticket signature if the requested server is not krbtgt, and
2124 * either the header server is krbtgt or, in the case of renewal/validation
2125 * if it was signed with PAC ticket signature and we verified it.
2126 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2127 * change one day (see issue #763) so make sure to check for it.
2131 !krb5_principal_is_krbtgt(context, server->entry.principal))
2132 add_ticket_sig = TRUE;
2135 * Active-Directory implementations use the high part of the kvno as the
2136 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2139 rodc_id = krbtgt_out->entry.kvno >> 16;
2145 ret = tgs_make_reply(context,
2158 server->entry.principal,
2173 free(user2user_name);
2181 krb5_free_keyblock_contents(context, &sessionkey);
2183 _kdc_free_ent(context, krbtgt_out);
2185 _kdc_free_ent(context, server);
2187 _kdc_free_ent(context, client);
2188 if(s4u2self_impersonated_client)
2189 _kdc_free_ent(context, s4u2self_impersonated_client);
2190 if (user2user_krbtgt)
2191 _kdc_free_ent(context, user2user_krbtgt);
2193 if (user2user_princ)
2194 krb5_free_principal(context, user2user_princ);
2196 krb5_free_principal(context, tp);
2197 krb5_free_principal(context, cp);
2198 krb5_free_principal(context, dp);
2199 krb5_free_principal(context, sp);
2200 krb5_free_principal(context, krbtgt_out_principal);
2203 free_METHOD_DATA(&enc_pa_data);
2205 free_EncTicketPart(&adtkt);
2207 krb5_pac_free(context, mspac);
2208 krb5_pac_free(context, user2user_pac);
2218 _kdc_tgs_rep(krb5_context context,
2219 krb5_kdc_configuration *config,
2223 struct sockaddr *from_addr,
2226 AuthorizationData *auth_data = NULL;
2227 krb5_error_code ret;
2229 const PA_DATA *tgs_req;
2230 Key *header_key = NULL;
2232 hdb_entry_ex *krbtgt = NULL;
2233 krb5_ticket *ticket = NULL;
2234 const char *e_text = NULL;
2235 krb5_enctype krbtgt_etype = ETYPE_NULL;
2237 krb5_keyblock *replykey = NULL;
2238 int rk_is_subkey = 0;
2239 time_t *csec = NULL;
2242 if(req->padata == NULL){
2243 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2244 kdc_log(context, config, 0,
2245 "TGS-REQ from %s without PA-DATA", from);
2249 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2251 if(tgs_req == NULL){
2252 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2254 kdc_log(context, config, 0,
2255 "TGS-REQ from %s without PA-TGS-REQ", from);
2258 ret = tgs_parse_request(context, config,
2259 &req->req_body, tgs_req,
2270 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2271 /* kdc_log() is called in tgs_parse_request() */
2275 kdc_log(context, config, 0,
2276 "Failed parsing TGS-REQ from %s", from);
2280 ret = tgs_build_reply(context,
2296 kdc_log(context, config, 0,
2297 "Failed building TGS-REP to %s", from);
2302 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2303 krb5_data_free(data);
2304 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2305 e_text = "Reply packet too large";
2310 krb5_free_keyblock(context, replykey);
2311 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2312 krb5_mk_error(context,
2326 krb5_free_ticket(context, ticket);
2328 _kdc_free_ent(context, krbtgt);
2331 free_AuthorizationData(auth_data);