Home | History | Annotate | Line # | Download | only in kdc
      1 /*	$NetBSD: krb5tgs.c,v 1.4 2023/06/19 21:41:41 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997-2008 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "kdc_locl.h"
     37 
     38 /*
     39  * return the realm of a krbtgt-ticket or NULL
     40  */
     41 
     42 static Realm
     43 get_krbtgt_realm(const PrincipalName *p)
     44 {
     45     if(p->name_string.len == 2
     46        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
     47 	return p->name_string.val[1];
     48     else
     49 	return NULL;
     50 }
     51 
     52 /*
     53  * The KDC might add a signed path to the ticket authorization data
     54  * field. This is to avoid server impersonating clients and the
     55  * request constrained delegation.
     56  *
     57  * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
     58  * entry of type KRB5SignedPath.
     59  */
     60 
     61 static krb5_error_code
     62 find_KRB5SignedPath(krb5_context context,
     63 		    const AuthorizationData *ad,
     64 		    krb5_data *data)
     65 {
     66     AuthorizationData child;
     67     krb5_error_code ret;
     68     int pos;
     69 
     70     if (ad == NULL || ad->len == 0)
     71 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
     72 
     73     pos = ad->len - 1;
     74 
     75     if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
     76 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
     77 
     78     ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
     79 				   ad->val[pos].ad_data.length,
     80 				   &child,
     81 				   NULL);
     82     if (ret) {
     83 	krb5_set_error_message(context, ret, "Failed to decode "
     84 			       "IF_RELEVANT with %d", ret);
     85 	return ret;
     86     }
     87 
     88     if (child.len != 1) {
     89 	free_AuthorizationData(&child);
     90 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
     91     }
     92 
     93     if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
     94 	free_AuthorizationData(&child);
     95 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
     96     }
     97 
     98     if (data)
     99 	ret = der_copy_octet_string(&child.val[0].ad_data, data);
    100     free_AuthorizationData(&child);
    101     return ret;
    102 }
    103 
    104 krb5_error_code
    105 _kdc_add_KRB5SignedPath(krb5_context context,
    106 			krb5_kdc_configuration *config,
    107 			hdb_entry_ex *krbtgt,
    108 			krb5_enctype enctype,
    109 			krb5_const_principal client,
    110 			krb5_const_principal server,
    111 			krb5_principals principals,
    112 			EncTicketPart *tkt)
    113 {
    114     krb5_error_code ret;
    115     KRB5SignedPath sp;
    116     krb5_data data;
    117     krb5_crypto crypto = NULL;
    118     size_t size = 0;
    119 
    120     if (server && principals) {
    121 	ret = add_Principals(principals, server);
    122 	if (ret)
    123 	    return ret;
    124     }
    125 
    126     {
    127 	KRB5SignedPathData spd;
    128 
    129 	spd.client = rk_UNCONST(client);
    130 	spd.authtime = tkt->authtime;
    131 	spd.delegated = principals;
    132 	spd.method_data = NULL;
    133 
    134 	ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
    135 			   &spd, &size, ret);
    136 	if (ret)
    137 	    return ret;
    138 	if (data.length != size)
    139 	    krb5_abortx(context, "internal asn.1 encoder error");
    140     }
    141 
    142     {
    143 	Key *key;
    144 	ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
    145 	if (ret == 0)
    146 	    ret = krb5_crypto_init(context, &key->key, 0, &crypto);
    147 	if (ret) {
    148 	    free(data.data);
    149 	    return ret;
    150 	}
    151     }
    152 
    153     /*
    154      * Fill in KRB5SignedPath
    155      */
    156 
    157     sp.etype = enctype;
    158     sp.delegated = principals;
    159     sp.method_data = NULL;
    160 
    161     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
    162 			       data.data, data.length, &sp.cksum);
    163     krb5_crypto_destroy(context, crypto);
    164     free(data.data);
    165     if (ret)
    166 	return ret;
    167 
    168     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
    169     free_Checksum(&sp.cksum);
    170     if (ret)
    171 	return ret;
    172     if (data.length != size)
    173 	krb5_abortx(context, "internal asn.1 encoder error");
    174 
    175 
    176     /*
    177      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
    178      * authorization data field.
    179      */
    180 
    181     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
    182 				      KRB5_AUTHDATA_SIGNTICKET, &data);
    183     krb5_data_free(&data);
    184 
    185     return ret;
    186 }
    187 
    188 static krb5_error_code
    189 check_KRB5SignedPath(krb5_context context,
    190 		     krb5_kdc_configuration *config,
    191 		     hdb_entry_ex *krbtgt,
    192 		     krb5_principal cp,
    193 		     EncTicketPart *tkt,
    194 		     krb5_principals *delegated,
    195 		     int *signedpath)
    196 {
    197     krb5_error_code ret;
    198     krb5_data data;
    199     krb5_crypto crypto = NULL;
    200 
    201     if (delegated)
    202 	*delegated = NULL;
    203 
    204     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
    205     if (ret == 0) {
    206 	KRB5SignedPathData spd;
    207 	KRB5SignedPath sp;
    208 	size_t size = 0;
    209 
    210 	ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
    211 	krb5_data_free(&data);
    212 	if (ret)
    213 	    return ret;
    214 
    215 	spd.client = cp;
    216 	spd.authtime = tkt->authtime;
    217 	spd.delegated = sp.delegated;
    218 	spd.method_data = sp.method_data;
    219 
    220 	ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
    221 			   &spd, &size, ret);
    222 	if (ret) {
    223 	    free_KRB5SignedPath(&sp);
    224 	    return ret;
    225 	}
    226 	if (data.length != size)
    227 	    krb5_abortx(context, "internal asn.1 encoder error");
    228 
    229 	{
    230 	    Key *key;
    231 	    ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
    232 				  sp.etype, &key);
    233 	    if (ret == 0)
    234 		ret = krb5_crypto_init(context, &key->key, 0, &crypto);
    235 	    if (ret) {
    236 		free(data.data);
    237 		free_KRB5SignedPath(&sp);
    238 		return ret;
    239 	    }
    240 	}
    241 	ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
    242 				   data.data, data.length,
    243 				   &sp.cksum);
    244 	krb5_crypto_destroy(context, crypto);
    245 	free(data.data);
    246 	if (ret) {
    247 	    free_KRB5SignedPath(&sp);
    248 	    kdc_log(context, config, 5,
    249 		    "KRB5SignedPath not signed correctly, not marking as signed");
    250 	    return 0;
    251 	}
    252 
    253 	if (delegated && sp.delegated) {
    254 
    255 	    *delegated = malloc(sizeof(*sp.delegated));
    256 	    if (*delegated == NULL) {
    257 		free_KRB5SignedPath(&sp);
    258 		return ENOMEM;
    259 	    }
    260 
    261 	    ret = copy_Principals(*delegated, sp.delegated);
    262 	    if (ret) {
    263 		free_KRB5SignedPath(&sp);
    264 		free(*delegated);
    265 		*delegated = NULL;
    266 		return ret;
    267 	    }
    268 	}
    269 	free_KRB5SignedPath(&sp);
    270 
    271 	*signedpath = 1;
    272     }
    273 
    274     return 0;
    275 }
    276 
    277 /*
    278  *
    279  */
    280 
    281 static krb5_error_code
    282 check_PAC(krb5_context context,
    283 	  krb5_kdc_configuration *config,
    284 	  const krb5_principal client_principal,
    285 	  const krb5_principal delegated_proxy_principal,
    286 	  hdb_entry_ex *client,
    287 	  hdb_entry_ex *server,
    288 	  hdb_entry_ex *krbtgt,
    289 	  const EncryptionKey *server_check_key,
    290 	  const EncryptionKey *server_sign_key,
    291 	  const EncryptionKey *krbtgt_sign_key,
    292 	  EncTicketPart *tkt,
    293 	  krb5_data *rspac,
    294 	  int *signedpath)
    295 {
    296     AuthorizationData *ad = tkt->authorization_data;
    297     unsigned i, j;
    298     krb5_error_code ret;
    299 
    300     if (ad == NULL || ad->len == 0)
    301 	return 0;
    302 
    303     for (i = 0; i < ad->len; i++) {
    304 	AuthorizationData child;
    305 
    306 	if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
    307 	    continue;
    308 
    309 	ret = decode_AuthorizationData(ad->val[i].ad_data.data,
    310 				       ad->val[i].ad_data.length,
    311 				       &child,
    312 				       NULL);
    313 	if (ret) {
    314 	    krb5_set_error_message(context, ret, "Failed to decode "
    315 				   "IF_RELEVANT with %d", ret);
    316 	    return ret;
    317 	}
    318 	for (j = 0; j < child.len; j++) {
    319 
    320 	    if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
    321 		int signed_pac = 0;
    322 		krb5_pac pac;
    323 
    324 		/* Found PAC */
    325 		ret = krb5_pac_parse(context,
    326 				     child.val[j].ad_data.data,
    327 				     child.val[j].ad_data.length,
    328 				     &pac);
    329 		free_AuthorizationData(&child);
    330 		if (ret)
    331 		    return ret;
    332 
    333 		ret = krb5_pac_verify(context, pac, tkt->authtime,
    334 				      client_principal,
    335 				      server_check_key, NULL);
    336 		if (ret) {
    337 		    krb5_pac_free(context, pac);
    338 		    return ret;
    339 		}
    340 
    341 		ret = _kdc_pac_verify(context, client_principal,
    342 				      delegated_proxy_principal,
    343 				      client, server, krbtgt, &pac, &signed_pac);
    344 		if (ret) {
    345 		    krb5_pac_free(context, pac);
    346 		    return ret;
    347 		}
    348 
    349 		/*
    350 		 * Only re-sign PAC if we could verify it with the PAC
    351 		 * function. The no-verify case happens when we get in
    352 		 * a PAC from cross realm from a Windows domain and
    353 		 * that there is no PAC verification function.
    354 		 */
    355 		if (signed_pac) {
    356 		    *signedpath = 1;
    357 		    ret = _krb5_pac_sign(context, pac, tkt->authtime,
    358 					 client_principal,
    359 					 server_sign_key, krbtgt_sign_key, rspac);
    360 		}
    361 		krb5_pac_free(context, pac);
    362 
    363 		return ret;
    364 	    }
    365 	}
    366 	free_AuthorizationData(&child);
    367     }
    368     return 0;
    369 }
    370 
    371 static krb5_boolean
    372 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
    373 		      const EncTicketPart *tgt)
    374 {
    375     KDCOptions f = b->kdc_options;
    376 
    377     /*
    378      * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
    379      * request-anonymous and cname-in-addl-tkt flags for constrained
    380      * delegation requests. A true anonymous TGS request will only
    381      * have the request-anonymous flag set. (A corollary of this is
    382      * that it is not possible to support anonymous constrained
    383      * delegation requests, although they would be of limited utility.)
    384      */
    385     return tgt->flags.anonymous ||
    386 	(f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
    387 }
    388 
    389 /*
    390  *
    391  */
    392 
    393 static krb5_error_code
    394 check_tgs_flags(krb5_context context,
    395 		krb5_kdc_configuration *config,
    396 		KDC_REQ_BODY *b,
    397 		krb5_const_principal tgt_name,
    398 		const EncTicketPart *tgt,
    399 		EncTicketPart *et)
    400 {
    401     KDCOptions f = b->kdc_options;
    402 
    403     if(f.validate){
    404 	if(!tgt->flags.invalid || tgt->starttime == NULL){
    405 	    kdc_log(context, config, 0,
    406 		    "Bad request to validate ticket");
    407 	    return KRB5KDC_ERR_BADOPTION;
    408 	}
    409 	if(*tgt->starttime > kdc_time){
    410 	    kdc_log(context, config, 0,
    411 		    "Early request to validate ticket");
    412 	    return KRB5KRB_AP_ERR_TKT_NYV;
    413 	}
    414 	/* XXX  tkt = tgt */
    415 	et->flags.invalid = 0;
    416     }else if(tgt->flags.invalid){
    417 	kdc_log(context, config, 0,
    418 		"Ticket-granting ticket has INVALID flag set");
    419 	return KRB5KRB_AP_ERR_TKT_INVALID;
    420     }
    421 
    422     if(f.forwardable){
    423 	if(!tgt->flags.forwardable){
    424 	    kdc_log(context, config, 0,
    425 		    "Bad request for forwardable ticket");
    426 	    return KRB5KDC_ERR_BADOPTION;
    427 	}
    428 	et->flags.forwardable = 1;
    429     }
    430     if(f.forwarded){
    431 	if(!tgt->flags.forwardable){
    432 	    kdc_log(context, config, 0,
    433 		    "Request to forward non-forwardable ticket");
    434 	    return KRB5KDC_ERR_BADOPTION;
    435 	}
    436 	et->flags.forwarded = 1;
    437 	et->caddr = b->addresses;
    438     }
    439     if(tgt->flags.forwarded)
    440 	et->flags.forwarded = 1;
    441 
    442     if(f.proxiable){
    443 	if(!tgt->flags.proxiable){
    444 	    kdc_log(context, config, 0,
    445 		    "Bad request for proxiable ticket");
    446 	    return KRB5KDC_ERR_BADOPTION;
    447 	}
    448 	et->flags.proxiable = 1;
    449     }
    450     if(f.proxy){
    451 	if(!tgt->flags.proxiable){
    452 	    kdc_log(context, config, 0,
    453 		    "Request to proxy non-proxiable ticket");
    454 	    return KRB5KDC_ERR_BADOPTION;
    455 	}
    456 	et->flags.proxy = 1;
    457 	et->caddr = b->addresses;
    458     }
    459     if(tgt->flags.proxy)
    460 	et->flags.proxy = 1;
    461 
    462     if(f.allow_postdate){
    463 	if(!tgt->flags.may_postdate){
    464 	    kdc_log(context, config, 0,
    465 		    "Bad request for post-datable ticket");
    466 	    return KRB5KDC_ERR_BADOPTION;
    467 	}
    468 	et->flags.may_postdate = 1;
    469     }
    470     if(f.postdated){
    471 	if(!tgt->flags.may_postdate){
    472 	    kdc_log(context, config, 0,
    473 		    "Bad request for postdated ticket");
    474 	    return KRB5KDC_ERR_BADOPTION;
    475 	}
    476 	if(b->from)
    477 	    *et->starttime = *b->from;
    478 	et->flags.postdated = 1;
    479 	et->flags.invalid = 1;
    480     }else if(b->from && *b->from > kdc_time + context->max_skew){
    481 	kdc_log(context, config, 0, "Ticket cannot be postdated");
    482 	return KRB5KDC_ERR_CANNOT_POSTDATE;
    483     }
    484 
    485     if(f.renewable){
    486 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
    487 	    kdc_log(context, config, 0,
    488 		    "Bad request for renewable ticket");
    489 	    return KRB5KDC_ERR_BADOPTION;
    490 	}
    491 	et->flags.renewable = 1;
    492 	ALLOC(et->renew_till);
    493 	_kdc_fix_time(&b->rtime);
    494 	*et->renew_till = *b->rtime;
    495     }
    496     if(f.renew){
    497 	time_t old_life;
    498 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
    499 	    kdc_log(context, config, 0,
    500 		    "Request to renew non-renewable ticket");
    501 	    return KRB5KDC_ERR_BADOPTION;
    502 	}
    503 	old_life = tgt->endtime;
    504 	if(tgt->starttime)
    505 	    old_life -= *tgt->starttime;
    506 	else
    507 	    old_life -= tgt->authtime;
    508 	et->endtime = *et->starttime + old_life;
    509 	if (et->renew_till != NULL)
    510 	    et->endtime = min(*et->renew_till, et->endtime);
    511     }
    512 
    513     /*
    514      * RFC 8062 section 3 defines an anonymous ticket as one containing
    515      * the anonymous principal and the anonymous ticket flag.
    516      */
    517     if (tgt->flags.anonymous &&
    518 	!_kdc_is_anonymous(context, tgt_name)) {
    519 	kdc_log(context, config, 0,
    520 		"Anonymous ticket flag set without anonymous principal");
    521 	return KRB5KDC_ERR_BADOPTION;
    522     }
    523 
    524     /*
    525      * RFC 8062 section 4.2 states that if the TGT is anonymous, the
    526      * anonymous KDC option SHOULD be set, but it is not required.
    527      * Treat an anonymous TGT as if the anonymous flag was set.
    528      */
    529     if (is_anon_tgs_request_p(b, tgt))
    530 	et->flags.anonymous = 1;
    531 
    532     return 0;
    533 }
    534 
    535 /*
    536  * Determine if constrained delegation is allowed from this client to this server
    537  */
    538 
    539 static krb5_error_code
    540 check_constrained_delegation(krb5_context context,
    541 			     krb5_kdc_configuration *config,
    542 			     HDB *clientdb,
    543 			     hdb_entry_ex *client,
    544 			     hdb_entry_ex *server,
    545 			     krb5_const_principal target)
    546 {
    547     const HDB_Ext_Constrained_delegation_acl *acl;
    548     krb5_error_code ret;
    549     size_t i;
    550 
    551     /*
    552      * constrained_delegation (S4U2Proxy) only works within
    553      * the same realm. We use the already canonicalized version
    554      * of the principals here, while "target" is the principal
    555      * provided by the client.
    556      */
    557     if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
    558 	ret = KRB5KDC_ERR_BADOPTION;
    559 	kdc_log(context, config, 0,
    560 	    "Bad request for constrained delegation");
    561 	return ret;
    562     }
    563 
    564     if (clientdb->hdb_check_constrained_delegation) {
    565 	ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
    566 	if (ret == 0)
    567 	    return 0;
    568     } else {
    569 	/* if client delegates to itself, that ok */
    570 	if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
    571 	    return 0;
    572 
    573 	ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
    574 	if (ret) {
    575 	    krb5_clear_error_message(context);
    576 	    return ret;
    577 	}
    578 
    579 	if (acl) {
    580 	    for (i = 0; i < acl->len; i++) {
    581 		if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
    582 		    return 0;
    583 	    }
    584 	}
    585 	ret = KRB5KDC_ERR_BADOPTION;
    586     }
    587     kdc_log(context, config, 0,
    588 	    "Bad request for constrained delegation");
    589     return ret;
    590 }
    591 
    592 /*
    593  * Determine if s4u2self is allowed from this client to this server
    594  *
    595  * For example, regardless of the principal being impersonated, if the
    596  * 'client' and 'server' are the same, then it's safe.
    597  */
    598 
    599 static krb5_error_code
    600 check_s4u2self(krb5_context context,
    601 	       krb5_kdc_configuration *config,
    602 	       HDB *clientdb,
    603 	       hdb_entry_ex *client,
    604 	       krb5_const_principal server)
    605 {
    606     krb5_error_code ret;
    607 
    608     /* if client does a s4u2self to itself, that ok */
    609     if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
    610 	return 0;
    611 
    612     if (clientdb->hdb_check_s4u2self) {
    613 	ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
    614 	if (ret == 0)
    615 	    return 0;
    616     } else {
    617 	ret = KRB5KDC_ERR_BADOPTION;
    618     }
    619     return ret;
    620 }
    621 
    622 /*
    623  *
    624  */
    625 
    626 static krb5_error_code
    627 verify_flags (krb5_context context,
    628 	      krb5_kdc_configuration *config,
    629 	      const EncTicketPart *et,
    630 	      const char *pstr)
    631 {
    632     if(et->endtime < kdc_time){
    633 	kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
    634 	return KRB5KRB_AP_ERR_TKT_EXPIRED;
    635     }
    636     if(et->flags.invalid){
    637 	kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
    638 	return KRB5KRB_AP_ERR_TKT_NYV;
    639     }
    640     return 0;
    641 }
    642 
    643 /*
    644  *
    645  */
    646 
    647 static krb5_error_code
    648 fix_transited_encoding(krb5_context context,
    649 		       krb5_kdc_configuration *config,
    650 		       krb5_boolean check_policy,
    651 		       const TransitedEncoding *tr,
    652 		       EncTicketPart *et,
    653 		       const char *client_realm,
    654 		       const char *server_realm,
    655 		       const char *tgt_realm)
    656 {
    657     krb5_error_code ret = 0;
    658     char **realms, **tmp;
    659     unsigned int num_realms;
    660     size_t i;
    661 
    662     switch (tr->tr_type) {
    663     case DOMAIN_X500_COMPRESS:
    664 	break;
    665     case 0:
    666 	/*
    667 	 * Allow empty content of type 0 because that is was Microsoft
    668 	 * generates in their TGT.
    669 	 */
    670 	if (tr->contents.length == 0)
    671 	    break;
    672 	kdc_log(context, config, 0,
    673 		"Transited type 0 with non empty content");
    674 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
    675     default:
    676 	kdc_log(context, config, 0,
    677 		"Unknown transited type: %u", tr->tr_type);
    678 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
    679     }
    680 
    681     ret = krb5_domain_x500_decode(context,
    682 				  tr->contents,
    683 				  &realms,
    684 				  &num_realms,
    685 				  client_realm,
    686 				  server_realm);
    687     if(ret){
    688 	krb5_warn(context, ret,
    689 		  "Decoding transited encoding");
    690 	return ret;
    691     }
    692 
    693     /*
    694      * If the realm of the presented tgt is neither the client nor the server
    695      * realm, it is a transit realm and must be added to transited set.
    696      */
    697     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
    698 	if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
    699 	    ret = ERANGE;
    700 	    goto free_realms;
    701 	}
    702 	tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
    703 	if(tmp == NULL){
    704 	    ret = ENOMEM;
    705 	    goto free_realms;
    706 	}
    707 	realms = tmp;
    708 	realms[num_realms] = strdup(tgt_realm);
    709 	if(realms[num_realms] == NULL){
    710 	    ret = ENOMEM;
    711 	    goto free_realms;
    712 	}
    713 	num_realms++;
    714     }
    715     if(num_realms == 0) {
    716 	if(strcmp(client_realm, server_realm))
    717 	    kdc_log(context, config, 0,
    718 		    "cross-realm %s -> %s", client_realm, server_realm);
    719     } else {
    720 	size_t l = 0;
    721 	char *rs;
    722 	for(i = 0; i < num_realms; i++)
    723 	    l += strlen(realms[i]) + 2;
    724 	rs = malloc(l);
    725 	if(rs != NULL) {
    726 	    *rs = '\0';
    727 	    for(i = 0; i < num_realms; i++) {
    728 		if(i > 0)
    729 		    strlcat(rs, ", ", l);
    730 		strlcat(rs, realms[i], l);
    731 	    }
    732 	    kdc_log(context, config, 0,
    733 		    "cross-realm %s -> %s via [%s]",
    734 		    client_realm, server_realm, rs);
    735 	    free(rs);
    736 	}
    737     }
    738     if(check_policy) {
    739 	ret = krb5_check_transited(context, client_realm,
    740 				   server_realm,
    741 				   realms, num_realms, NULL);
    742 	if(ret) {
    743 	    krb5_warn(context, ret, "cross-realm %s -> %s",
    744 		      client_realm, server_realm);
    745 	    goto free_realms;
    746 	}
    747 	et->flags.transited_policy_checked = 1;
    748     }
    749     et->transited.tr_type = DOMAIN_X500_COMPRESS;
    750     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
    751     if(ret)
    752 	krb5_warn(context, ret, "Encoding transited encoding");
    753   free_realms:
    754     for(i = 0; i < num_realms; i++)
    755 	free(realms[i]);
    756     free(realms);
    757     return ret;
    758 }
    759 
    760 
    761 static krb5_error_code
    762 tgs_make_reply(krb5_context context,
    763 	       krb5_kdc_configuration *config,
    764 	       KDC_REQ_BODY *b,
    765 	       krb5_const_principal tgt_name,
    766 	       const EncTicketPart *tgt,
    767 	       const krb5_keyblock *replykey,
    768 	       int rk_is_subkey,
    769 	       const EncryptionKey *serverkey,
    770 	       const krb5_keyblock *sessionkey,
    771 	       krb5_kvno kvno,
    772 	       AuthorizationData *auth_data,
    773 	       hdb_entry_ex *server,
    774 	       krb5_principal server_principal,
    775 	       const char *server_name,
    776 	       hdb_entry_ex *client,
    777 	       krb5_principal client_principal,
    778                const char *tgt_realm,
    779 	       hdb_entry_ex *krbtgt,
    780 	       krb5_enctype krbtgt_etype,
    781 	       krb5_principals spp,
    782 	       const krb5_data *rspac,
    783 	       const METHOD_DATA *enc_pa_data,
    784 	       const char **e_text,
    785 	       krb5_data *reply)
    786 {
    787     KDC_REP rep;
    788     EncKDCRepPart ek;
    789     EncTicketPart et;
    790     KDCOptions f = b->kdc_options;
    791     krb5_error_code ret;
    792     int is_weak = 0;
    793 
    794     memset(&rep, 0, sizeof(rep));
    795     memset(&et, 0, sizeof(et));
    796     memset(&ek, 0, sizeof(ek));
    797 
    798     rep.pvno = 5;
    799     rep.msg_type = krb_tgs_rep;
    800 
    801     et.authtime = tgt->authtime;
    802     _kdc_fix_time(&b->till);
    803     et.endtime = min(tgt->endtime, *b->till);
    804     ALLOC(et.starttime);
    805     *et.starttime = kdc_time;
    806 
    807     ret = check_tgs_flags(context, config, b, tgt_name, tgt, &et);
    808     if(ret)
    809 	goto out;
    810 
    811     /* We should check the transited encoding if:
    812        1) the request doesn't ask not to be checked
    813        2) globally enforcing a check
    814        3) principal requires checking
    815        4) we allow non-check per-principal, but principal isn't marked as allowing this
    816        5) we don't globally allow this
    817     */
    818 
    819 #define GLOBAL_FORCE_TRANSITED_CHECK		\
    820     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
    821 #define GLOBAL_ALLOW_PER_PRINCIPAL			\
    822     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
    823 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK			\
    824     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
    825 
    826 /* these will consult the database in future release */
    827 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)		0
    828 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)	0
    829 
    830     ret = fix_transited_encoding(context, config,
    831 				 !f.disable_transited_check ||
    832 				 GLOBAL_FORCE_TRANSITED_CHECK ||
    833 				 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
    834 				 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
    835 				    PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
    836 				   GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
    837 				 &tgt->transited, &et,
    838 				 krb5_principal_get_realm(context, client_principal),
    839 				 krb5_principal_get_realm(context, server->entry.principal),
    840 				 tgt_realm);
    841     if(ret)
    842 	goto out;
    843 
    844     ret = copy_Realm(&server_principal->realm, &rep.ticket.realm);
    845     if (ret)
    846 	goto out;
    847     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
    848     ret = copy_Realm(&tgt_name->realm, &rep.crealm);
    849     if (ret)
    850 	goto out;
    851 
    852     /*
    853      * RFC 8062 states "if the ticket in the TGS request is an anonymous
    854      * one, the client and client realm are copied from that ticket". So
    855      * whilst the TGT flag check below is superfluous, it is included in
    856      * order to follow the specification to its letter.
    857      */
    858     if (et.flags.anonymous && !tgt->flags.anonymous)
    859 	_kdc_make_anonymous_principalname(&rep.cname);
    860     else
    861 	ret = copy_PrincipalName(&tgt_name->name, &rep.cname);
    862     if (ret)
    863 	goto out;
    864     rep.ticket.tkt_vno = 5;
    865 
    866     ek.caddr = et.caddr;
    867 
    868     {
    869 	time_t life;
    870 	life = et.endtime - *et.starttime;
    871 	if(client && client->entry.max_life)
    872 	    life = min(life, *client->entry.max_life);
    873 	if(server->entry.max_life)
    874 	    life = min(life, *server->entry.max_life);
    875 	et.endtime = *et.starttime + life;
    876     }
    877     if(f.renewable_ok && tgt->flags.renewable &&
    878        et.renew_till == NULL && et.endtime < *b->till &&
    879        tgt->renew_till != NULL)
    880     {
    881 	et.flags.renewable = 1;
    882 	ALLOC(et.renew_till);
    883 	*et.renew_till = *b->till;
    884     }
    885     if(et.renew_till){
    886 	time_t renew;
    887 	renew = *et.renew_till - *et.starttime;
    888 	if(client && client->entry.max_renew)
    889 	    renew = min(renew, *client->entry.max_renew);
    890 	if(server->entry.max_renew)
    891 	    renew = min(renew, *server->entry.max_renew);
    892 	*et.renew_till = *et.starttime + renew;
    893     }
    894 
    895     if(et.renew_till){
    896 	*et.renew_till = min(*et.renew_till, *tgt->renew_till);
    897 	*et.starttime = min(*et.starttime, *et.renew_till);
    898 	et.endtime = min(et.endtime, *et.renew_till);
    899     }
    900 
    901     *et.starttime = min(*et.starttime, et.endtime);
    902 
    903     if(*et.starttime == et.endtime){
    904 	ret = KRB5KDC_ERR_NEVER_VALID;
    905 	goto out;
    906     }
    907     if(et.renew_till && et.endtime == *et.renew_till){
    908 	free(et.renew_till);
    909 	et.renew_till = NULL;
    910 	et.flags.renewable = 0;
    911     }
    912 
    913     et.flags.pre_authent = tgt->flags.pre_authent;
    914     et.flags.hw_authent  = tgt->flags.hw_authent;
    915     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
    916 
    917     /* See MS-KILE 3.3.5.1 */
    918     if (!server->entry.flags.forwardable)
    919 	et.flags.forwardable = 0;
    920     if (!server->entry.flags.proxiable)
    921 	et.flags.proxiable = 0;
    922 
    923     /*
    924      * For anonymous tickets, we should filter out positive authorization data
    925      * that could reveal the client's identity, and return a policy error for
    926      * restrictive authorization data. Policy for unknown authorization types
    927      * is implementation dependent.
    928      */
    929     if (rspac->length && !et.flags.anonymous) {
    930 	/*
    931 	 * No not need to filter out the any PAC from the
    932 	 * auth_data since it's signed by the KDC.
    933 	 */
    934 	ret = _kdc_tkt_add_if_relevant_ad(context, &et,
    935 					  KRB5_AUTHDATA_WIN2K_PAC, rspac);
    936 	if (ret)
    937 	    goto out;
    938     }
    939 
    940     if (auth_data) {
    941 	unsigned int i = 0;
    942 
    943 	/* XXX check authdata */
    944 
    945 	if (et.authorization_data == NULL) {
    946 	    et.authorization_data = calloc(1, sizeof(*et.authorization_data));
    947 	    if (et.authorization_data == NULL) {
    948 		ret = ENOMEM;
    949 		krb5_set_error_message(context, ret, "malloc: out of memory");
    950 		goto out;
    951 	    }
    952 	}
    953 	for(i = 0; i < auth_data->len ; i++) {
    954 	    ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
    955 	    if (ret) {
    956 		krb5_set_error_message(context, ret, "malloc: out of memory");
    957 		goto out;
    958 	    }
    959 	}
    960 
    961 	/* Filter out type KRB5SignedPath */
    962 	ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
    963 	if (ret == 0) {
    964 	    if (et.authorization_data->len == 1) {
    965 		free_AuthorizationData(et.authorization_data);
    966 		free(et.authorization_data);
    967 		et.authorization_data = NULL;
    968 	    } else {
    969 		AuthorizationData *ad = et.authorization_data;
    970 		free_AuthorizationDataElement(&ad->val[ad->len - 1]);
    971 		ad->len--;
    972 	    }
    973 	}
    974     }
    975 
    976     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
    977     if (ret)
    978 	goto out;
    979     et.crealm = rep.crealm;
    980     et.cname = rep.cname;
    981 
    982     ek.key = et.key;
    983     /* MIT must have at least one last_req */
    984     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
    985     if (ek.last_req.val == NULL) {
    986 	ret = ENOMEM;
    987 	goto out;
    988     }
    989     ek.last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
    990     ek.nonce = b->nonce;
    991     ek.flags = et.flags;
    992     ek.authtime = et.authtime;
    993     ek.starttime = et.starttime;
    994     ek.endtime = et.endtime;
    995     ek.renew_till = et.renew_till;
    996     ek.srealm = rep.ticket.realm;
    997     ek.sname = rep.ticket.sname;
    998 
    999     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
   1000 		       et.endtime, et.renew_till);
   1001 
   1002     /* Don't sign cross realm tickets, they can't be checked anyway */
   1003     {
   1004 	char *r = get_krbtgt_realm(&ek.sname);
   1005 
   1006 	if (r == NULL || strcmp(r, ek.srealm) == 0) {
   1007 	    ret = _kdc_add_KRB5SignedPath(context,
   1008 					  config,
   1009 					  krbtgt,
   1010 					  krbtgt_etype,
   1011 					  client_principal,
   1012 					  NULL,
   1013 					  spp,
   1014 					  &et);
   1015 	    if (ret)
   1016 		goto out;
   1017 	}
   1018     }
   1019 
   1020     if (enc_pa_data->len) {
   1021 	rep.padata = calloc(1, sizeof(*rep.padata));
   1022 	if (rep.padata == NULL) {
   1023 	    ret = ENOMEM;
   1024 	    goto out;
   1025 	}
   1026 	ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
   1027 	if (ret)
   1028 	    goto out;
   1029     }
   1030 
   1031     if (krb5_enctype_valid(context, serverkey->keytype) != 0
   1032 	&& _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
   1033     {
   1034 	krb5_enctype_enable(context, serverkey->keytype);
   1035 	is_weak = 1;
   1036     }
   1037 
   1038 
   1039     /* It is somewhat unclear where the etype in the following
   1040        encryption should come from. What we have is a session
   1041        key in the passed tgt, and a list of preferred etypes
   1042        *for the new ticket*. Should we pick the best possible
   1043        etype, given the keytype in the tgt, or should we look
   1044        at the etype list here as well?  What if the tgt
   1045        session key is DES3 and we want a ticket with a (say)
   1046        CAST session key. Should the DES3 etype be added to the
   1047        etype list, even if we don't want a session key with
   1048        DES3? */
   1049     ret = _kdc_encode_reply(context, config, NULL, 0,
   1050 			    &rep, &et, &ek, serverkey->keytype,
   1051 			    kvno,
   1052 			    serverkey, 0, replykey, rk_is_subkey,
   1053 			    e_text, reply);
   1054     if (is_weak)
   1055 	krb5_enctype_disable(context, serverkey->keytype);
   1056 
   1057 out:
   1058     free_TGS_REP(&rep);
   1059     free_TransitedEncoding(&et.transited);
   1060     if(et.starttime)
   1061 	free(et.starttime);
   1062     if(et.renew_till)
   1063 	free(et.renew_till);
   1064     if(et.authorization_data) {
   1065 	free_AuthorizationData(et.authorization_data);
   1066 	free(et.authorization_data);
   1067     }
   1068     free_LastReq(&ek.last_req);
   1069     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
   1070     free_EncryptionKey(&et.key);
   1071     return ret;
   1072 }
   1073 
   1074 static krb5_error_code
   1075 tgs_check_authenticator(krb5_context context,
   1076 			krb5_kdc_configuration *config,
   1077 	                krb5_auth_context ac,
   1078 			KDC_REQ_BODY *b,
   1079 			const char **e_text,
   1080 			krb5_keyblock *key)
   1081 {
   1082     krb5_authenticator auth;
   1083     size_t len = 0;
   1084     unsigned char *buf;
   1085     size_t buf_size;
   1086     krb5_error_code ret;
   1087     krb5_crypto crypto;
   1088 
   1089     krb5_auth_con_getauthenticator(context, ac, &auth);
   1090     if(auth->cksum == NULL){
   1091 	kdc_log(context, config, 0, "No authenticator in request");
   1092 	ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
   1093 	goto out;
   1094     }
   1095     /*
   1096      * according to RFC1510 it doesn't need to be keyed,
   1097      * but according to the latest draft it needs to.
   1098      */
   1099     if (
   1100 #if 0
   1101 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
   1102 	||
   1103 #endif
   1104  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
   1105 	kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
   1106 		auth->cksum->cksumtype);
   1107 	ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
   1108 	goto out;
   1109     }
   1110 
   1111     /* XXX should not re-encode this */
   1112     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
   1113     if(ret){
   1114 	const char *msg = krb5_get_error_message(context, ret);
   1115 	kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
   1116 	krb5_free_error_message(context, msg);
   1117 	goto out;
   1118     }
   1119     if(buf_size != len) {
   1120 	free(buf);
   1121 	kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
   1122 	*e_text = "KDC internal error";
   1123 	ret = KRB5KRB_ERR_GENERIC;
   1124 	goto out;
   1125     }
   1126     ret = krb5_crypto_init(context, key, 0, &crypto);
   1127     if (ret) {
   1128 	const char *msg = krb5_get_error_message(context, ret);
   1129 	free(buf);
   1130 	kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
   1131 	krb5_free_error_message(context, msg);
   1132 	goto out;
   1133     }
   1134     ret = krb5_verify_checksum(context,
   1135 			       crypto,
   1136 			       KRB5_KU_TGS_REQ_AUTH_CKSUM,
   1137 			       buf,
   1138 			       len,
   1139 			       auth->cksum);
   1140     free(buf);
   1141     krb5_crypto_destroy(context, crypto);
   1142     if(ret){
   1143 	const char *msg = krb5_get_error_message(context, ret);
   1144 	kdc_log(context, config, 0,
   1145 		"Failed to verify authenticator checksum: %s", msg);
   1146 	krb5_free_error_message(context, msg);
   1147     }
   1148 out:
   1149     free_Authenticator(auth);
   1150     free(auth);
   1151     return ret;
   1152 }
   1153 
   1154 static krb5_boolean
   1155 need_referral(krb5_context context, krb5_kdc_configuration *config,
   1156 	      const KDCOptions * const options, krb5_principal server,
   1157 	      krb5_realm **realms)
   1158 {
   1159     const char *name;
   1160 
   1161     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
   1162 	return FALSE;
   1163 
   1164     if (server->name.name_string.len == 1)
   1165 	name = server->name.name_string.val[0];
   1166     else if (server->name.name_string.len == 3) {
   1167 	/*
   1168 	  This is used to give referrals for the
   1169 	  E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
   1170 	  SPN form, which is used for inter-domain communication in AD
   1171 	 */
   1172 	name = server->name.name_string.val[2];
   1173 	kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
   1174 	*realms = malloc(sizeof(char *)*2);
   1175 	if (*realms == NULL) {
   1176 	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
   1177 	    return FALSE;
   1178 	}
   1179 	(*realms)[0] = strdup(name);
   1180 	(*realms)[1] = NULL;
   1181 	return TRUE;
   1182     } else if (server->name.name_string.len > 1)
   1183 	name = server->name.name_string.val[1];
   1184     else
   1185 	return FALSE;
   1186 
   1187     kdc_log(context, config, 0, "Searching referral for %s", name);
   1188 
   1189     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
   1190 }
   1191 
   1192 static krb5_error_code
   1193 tgs_parse_request(krb5_context context,
   1194 		  krb5_kdc_configuration *config,
   1195 		  KDC_REQ_BODY *b,
   1196 		  const PA_DATA *tgs_req,
   1197 		  hdb_entry_ex **krbtgt,
   1198 		  krb5_enctype *krbtgt_etype,
   1199 		  krb5_ticket **ticket,
   1200 		  const char **e_text,
   1201 		  const char *from,
   1202 		  const struct sockaddr *from_addr,
   1203 		  time_t **csec,
   1204 		  int **cusec,
   1205 		  AuthorizationData **auth_data,
   1206 		  krb5_keyblock **replykey,
   1207 		  int *rk_is_subkey)
   1208 {
   1209     static char failed[] = "<unparse_name failed>";
   1210     krb5_ap_req ap_req;
   1211     krb5_error_code ret;
   1212     krb5_principal princ;
   1213     krb5_auth_context ac = NULL;
   1214     krb5_flags ap_req_options;
   1215     krb5_flags verify_ap_req_flags;
   1216     krb5_crypto crypto;
   1217     krb5uint32 krbtgt_kvno;     /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
   1218     krb5uint32 krbtgt_kvno_try;
   1219     int kvno_search_tries = 4;  /* number of kvnos to try when tkt_vno == 0 */
   1220     const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
   1221     Key *tkey;
   1222     krb5_keyblock *subkey = NULL;
   1223     unsigned usage;
   1224 
   1225     *auth_data = NULL;
   1226     *csec  = NULL;
   1227     *cusec = NULL;
   1228     *replykey = NULL;
   1229 
   1230     memset(&ap_req, 0, sizeof(ap_req));
   1231     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
   1232     if(ret){
   1233 	const char *msg = krb5_get_error_message(context, ret);
   1234 	kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
   1235 	krb5_free_error_message(context, msg);
   1236 	goto out;
   1237     }
   1238 
   1239     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
   1240 	/* XXX check for ticket.sname == req.sname */
   1241 	kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
   1242 	ret = KRB5KDC_ERR_POLICY; /* ? */
   1243 	goto out;
   1244     }
   1245 
   1246     _krb5_principalname2krb5_principal(context,
   1247 				       &princ,
   1248 				       ap_req.ticket.sname,
   1249 				       ap_req.ticket.realm);
   1250 
   1251     krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
   1252     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
   1253 			&krbtgt_kvno, NULL, krbtgt);
   1254 
   1255     if (ret == HDB_ERR_NOT_FOUND_HERE) {
   1256 	/* XXX Factor out this unparsing of the same princ all over */
   1257 	char *p;
   1258 	ret = krb5_unparse_name(context, princ, &p);
   1259 	if (ret != 0)
   1260 	    p = failed;
   1261 	krb5_free_principal(context, princ);
   1262 	kdc_log(context, config, 5,
   1263 		"Ticket-granting ticket account %s does not have secrets at "
   1264 		"this KDC, need to proxy", p);
   1265 	if (ret == 0)
   1266 	    free(p);
   1267 	ret = HDB_ERR_NOT_FOUND_HERE;
   1268 	goto out;
   1269     } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
   1270 	char *p;
   1271 	ret = krb5_unparse_name(context, princ, &p);
   1272 	if (ret != 0)
   1273 	    p = failed;
   1274 	krb5_free_principal(context, princ);
   1275 	kdc_log(context, config, 5,
   1276 		"Ticket-granting ticket account %s does not have keys for "
   1277 		"kvno %d at this KDC", p, krbtgt_kvno);
   1278 	if (ret == 0)
   1279 	    free(p);
   1280 	ret = HDB_ERR_KVNO_NOT_FOUND;
   1281 	goto out;
   1282     } else if (ret == HDB_ERR_NO_MKEY) {
   1283 	char *p;
   1284 	ret = krb5_unparse_name(context, princ, &p);
   1285 	if (ret != 0)
   1286 	    p = failed;
   1287 	krb5_free_principal(context, princ);
   1288 	kdc_log(context, config, 5,
   1289 		"Missing master key for decrypting keys for ticket-granting "
   1290 		"ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
   1291 	if (ret == 0)
   1292 	    free(p);
   1293 	ret = HDB_ERR_KVNO_NOT_FOUND;
   1294 	goto out;
   1295     } else if (ret) {
   1296 	const char *msg = krb5_get_error_message(context, ret);
   1297 	char *p;
   1298 	ret = krb5_unparse_name(context, princ, &p);
   1299 	if (ret != 0)
   1300 	    p = failed;
   1301 	krb5_free_principal(context, princ);
   1302 	kdc_log(context, config, 0,
   1303 		"Ticket-granting ticket not found in database: %s", msg);
   1304 	krb5_free_error_message(context, msg);
   1305 	if (ret == 0)
   1306 	    free(p);
   1307 	ret = KRB5KRB_AP_ERR_NOT_US;
   1308 	goto out;
   1309     }
   1310 
   1311     krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
   1312     *krbtgt_etype = ap_req.ticket.enc_part.etype;
   1313 
   1314 next_kvno:
   1315     krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
   1316     ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
   1317 			  ap_req.ticket.enc_part.etype, &tkey);
   1318     if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
   1319 	kvno_search_tries--;
   1320 	krbtgt_kvno_try--;
   1321 	goto next_kvno;
   1322     } else if (ret) {
   1323 	char *str = NULL, *p = NULL;
   1324 
   1325 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
   1326 	krb5_unparse_name(context, princ, &p);
   1327  	kdc_log(context, config, 0,
   1328 		"No server key with enctype %s found for %s",
   1329 		str ? str : "<unknown enctype>",
   1330 		p ? p : "<unparse_name failed>");
   1331 	free(str);
   1332 	free(p);
   1333 	ret = KRB5KRB_AP_ERR_BADKEYVER;
   1334 	goto out;
   1335     }
   1336 
   1337     if (b->kdc_options.validate)
   1338 	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
   1339     else
   1340 	verify_ap_req_flags = 0;
   1341 
   1342     ret = krb5_verify_ap_req2(context,
   1343 			      &ac,
   1344 			      &ap_req,
   1345 			      princ,
   1346 			      &tkey->key,
   1347 			      verify_ap_req_flags,
   1348 			      &ap_req_options,
   1349 			      ticket,
   1350 			      KRB5_KU_TGS_REQ_AUTH);
   1351     if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
   1352 	kvno_search_tries--;
   1353 	krbtgt_kvno_try--;
   1354 	goto next_kvno;
   1355     }
   1356 
   1357     krb5_free_principal(context, princ);
   1358     if(ret) {
   1359 	const char *msg = krb5_get_error_message(context, ret);
   1360 	kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
   1361 	krb5_free_error_message(context, msg);
   1362 	goto out;
   1363     }
   1364 
   1365     {
   1366 	krb5_authenticator auth;
   1367 
   1368 	ret = krb5_auth_con_getauthenticator(context, ac, &auth);
   1369 	if (ret == 0) {
   1370 	    *csec   = malloc(sizeof(**csec));
   1371 	    if (*csec == NULL) {
   1372 		krb5_free_authenticator(context, &auth);
   1373 		kdc_log(context, config, 0, "malloc failed");
   1374 		goto out;
   1375 	    }
   1376 	    **csec  = auth->ctime;
   1377 	    *cusec  = malloc(sizeof(**cusec));
   1378 	    if (*cusec == NULL) {
   1379 		krb5_free_authenticator(context, &auth);
   1380 		kdc_log(context, config, 0, "malloc failed");
   1381 		goto out;
   1382 	    }
   1383 	    **cusec  = auth->cusec;
   1384 	    krb5_free_authenticator(context, &auth);
   1385 	}
   1386     }
   1387 
   1388     ret = tgs_check_authenticator(context, config,
   1389 				  ac, b, e_text, &(*ticket)->ticket.key);
   1390     if (ret) {
   1391 	krb5_auth_con_free(context, ac);
   1392 	goto out;
   1393     }
   1394 
   1395     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
   1396     *rk_is_subkey = 1;
   1397 
   1398     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
   1399     if(ret){
   1400 	const char *msg = krb5_get_error_message(context, ret);
   1401 	krb5_auth_con_free(context, ac);
   1402 	kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
   1403 	krb5_free_error_message(context, msg);
   1404 	goto out;
   1405     }
   1406     if(subkey == NULL){
   1407 	usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
   1408 	*rk_is_subkey = 0;
   1409 
   1410 	ret = krb5_auth_con_getkey(context, ac, &subkey);
   1411 	if(ret) {
   1412 	    const char *msg = krb5_get_error_message(context, ret);
   1413 	    krb5_auth_con_free(context, ac);
   1414 	    kdc_log(context, config, 0, "Failed to get session key: %s", msg);
   1415 	    krb5_free_error_message(context, msg);
   1416 	    goto out;
   1417 	}
   1418     }
   1419     if(subkey == NULL){
   1420 	krb5_auth_con_free(context, ac);
   1421 	kdc_log(context, config, 0,
   1422 		"Failed to get key for enc-authorization-data");
   1423 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
   1424 	goto out;
   1425     }
   1426 
   1427     *replykey = subkey;
   1428 
   1429     if (b->enc_authorization_data) {
   1430 	krb5_data ad;
   1431 
   1432 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
   1433 	if (ret) {
   1434 	    const char *msg = krb5_get_error_message(context, ret);
   1435 	    krb5_auth_con_free(context, ac);
   1436 	    kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
   1437 	    krb5_free_error_message(context, msg);
   1438 	    goto out;
   1439 	}
   1440 	ret = krb5_decrypt_EncryptedData (context,
   1441 					  crypto,
   1442 					  usage,
   1443 					  b->enc_authorization_data,
   1444 					  &ad);
   1445 	krb5_crypto_destroy(context, crypto);
   1446 	if(ret){
   1447 	    krb5_auth_con_free(context, ac);
   1448 	    kdc_log(context, config, 0,
   1449 		    "Failed to decrypt enc-authorization-data");
   1450 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
   1451 	    goto out;
   1452 	}
   1453 	ALLOC(*auth_data);
   1454 	if (*auth_data == NULL) {
   1455 	    krb5_auth_con_free(context, ac);
   1456 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
   1457 	    goto out;
   1458 	}
   1459 	ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
   1460 	if(ret){
   1461 	    krb5_auth_con_free(context, ac);
   1462 	    free(*auth_data);
   1463 	    *auth_data = NULL;
   1464 	    kdc_log(context, config, 0, "Failed to decode authorization data");
   1465 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
   1466 	    goto out;
   1467 	}
   1468     }
   1469 
   1470     krb5_auth_con_free(context, ac);
   1471 
   1472 out:
   1473     free_AP_REQ(&ap_req);
   1474 
   1475     return ret;
   1476 }
   1477 
   1478 static krb5_error_code
   1479 build_server_referral(krb5_context context,
   1480 		      krb5_kdc_configuration *config,
   1481 		      krb5_crypto session,
   1482 		      krb5_const_realm referred_realm,
   1483 		      const PrincipalName *true_principal_name,
   1484 		      const PrincipalName *requested_principal,
   1485 		      krb5_data *outdata)
   1486 {
   1487     PA_ServerReferralData ref;
   1488     krb5_error_code ret;
   1489     EncryptedData ed;
   1490     krb5_data data;
   1491     size_t size = 0;
   1492 
   1493     memset(&ref, 0, sizeof(ref));
   1494 
   1495     if (referred_realm) {
   1496 	ALLOC(ref.referred_realm);
   1497 	if (ref.referred_realm == NULL)
   1498 	    goto eout;
   1499 	*ref.referred_realm = strdup(referred_realm);
   1500 	if (*ref.referred_realm == NULL)
   1501 	    goto eout;
   1502     }
   1503     if (true_principal_name) {
   1504 	ALLOC(ref.true_principal_name);
   1505 	if (ref.true_principal_name == NULL)
   1506 	    goto eout;
   1507 	ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
   1508 	if (ret)
   1509 	    goto eout;
   1510     }
   1511     if (requested_principal) {
   1512 	ALLOC(ref.requested_principal_name);
   1513 	if (ref.requested_principal_name == NULL)
   1514 	    goto eout;
   1515 	ret = copy_PrincipalName(requested_principal,
   1516 				 ref.requested_principal_name);
   1517 	if (ret)
   1518 	    goto eout;
   1519     }
   1520 
   1521     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
   1522 		       data.data, data.length,
   1523 		       &ref, &size, ret);
   1524     free_PA_ServerReferralData(&ref);
   1525     if (ret)
   1526 	return ret;
   1527     if (data.length != size)
   1528 	krb5_abortx(context, "internal asn.1 encoder error");
   1529 
   1530     ret = krb5_encrypt_EncryptedData(context, session,
   1531 				     KRB5_KU_PA_SERVER_REFERRAL,
   1532 				     data.data, data.length,
   1533 				     0 /* kvno */, &ed);
   1534     free(data.data);
   1535     if (ret)
   1536 	return ret;
   1537 
   1538     ASN1_MALLOC_ENCODE(EncryptedData,
   1539 		       outdata->data, outdata->length,
   1540 		       &ed, &size, ret);
   1541     free_EncryptedData(&ed);
   1542     if (ret)
   1543 	return ret;
   1544     if (outdata->length != size)
   1545 	krb5_abortx(context, "internal asn.1 encoder error");
   1546 
   1547     return 0;
   1548 eout:
   1549     free_PA_ServerReferralData(&ref);
   1550     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
   1551     return ENOMEM;
   1552 }
   1553 
   1554 static krb5_error_code
   1555 tgs_build_reply(krb5_context context,
   1556 		krb5_kdc_configuration *config,
   1557 		KDC_REQ *req,
   1558 		KDC_REQ_BODY *b,
   1559 		hdb_entry_ex *krbtgt,
   1560 		krb5_enctype krbtgt_etype,
   1561 		const krb5_keyblock *replykey,
   1562 		int rk_is_subkey,
   1563 		krb5_ticket *ticket,
   1564 		krb5_data *reply,
   1565 		const char *from,
   1566 		const char **e_text,
   1567 		AuthorizationData **auth_data,
   1568 		const struct sockaddr *from_addr)
   1569 {
   1570     krb5_error_code ret, ret2;
   1571     krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
   1572     krb5_principal krbtgt_out_principal = NULL;
   1573     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
   1574     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
   1575     HDB *clientdb, *s4u2self_impersonated_clientdb;
   1576     krb5_realm ref_realm = NULL;
   1577     EncTicketPart *tgt = &ticket->ticket;
   1578     krb5_principals spp = NULL;
   1579     const EncryptionKey *ekey;
   1580     krb5_keyblock sessionkey;
   1581     krb5_kvno kvno;
   1582     krb5_data rspac;
   1583     const char *tgt_realm = /* Realm of TGT issuer */
   1584         krb5_principal_get_realm(context, krbtgt->entry.principal);
   1585     const char *our_realm = /* Realm of this KDC */
   1586         krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
   1587     char **capath = NULL;
   1588     size_t num_capath = 0;
   1589 
   1590     hdb_entry_ex *krbtgt_out = NULL;
   1591 
   1592     METHOD_DATA enc_pa_data;
   1593 
   1594     PrincipalName *s;
   1595     Realm r;
   1596     EncTicketPart adtkt;
   1597     char opt_str[128];
   1598     int signedpath = 0;
   1599 
   1600     Key *tkey_check;
   1601     Key *tkey_sign;
   1602     int flags = HDB_F_FOR_TGS_REQ;
   1603 
   1604     memset(&sessionkey, 0, sizeof(sessionkey));
   1605     memset(&adtkt, 0, sizeof(adtkt));
   1606     krb5_data_zero(&rspac);
   1607     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
   1608 
   1609     s = b->sname;
   1610     r = b->realm;
   1611 
   1612     /*
   1613      * Always to do CANON, see comment below about returned server principal (rsp).
   1614      */
   1615     flags |= HDB_F_CANON;
   1616 
   1617     if(b->kdc_options.enc_tkt_in_skey){
   1618 	Ticket *t;
   1619 	hdb_entry_ex *uu;
   1620 	krb5_principal p;
   1621 	Key *uukey;
   1622 	krb5uint32 second_kvno = 0;
   1623 	krb5uint32 *kvno_ptr = NULL;
   1624 
   1625 	if(b->additional_tickets == NULL ||
   1626 	   b->additional_tickets->len == 0){
   1627 	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
   1628 	    kdc_log(context, config, 0,
   1629 		    "No second ticket present in request");
   1630 	    goto out;
   1631 	}
   1632 	t = &b->additional_tickets->val[0];
   1633 	if(!get_krbtgt_realm(&t->sname)){
   1634 	    kdc_log(context, config, 0,
   1635 		    "Additional ticket is not a ticket-granting ticket");
   1636 	    ret = KRB5KDC_ERR_POLICY;
   1637 	    goto out;
   1638 	}
   1639 	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
   1640 	if(t->enc_part.kvno){
   1641 	    second_kvno = *t->enc_part.kvno;
   1642 	    kvno_ptr = &second_kvno;
   1643 	}
   1644 	ret = _kdc_db_fetch(context, config, p,
   1645 			    HDB_F_GET_KRBTGT, kvno_ptr,
   1646 			    NULL, &uu);
   1647 	krb5_free_principal(context, p);
   1648 	if(ret){
   1649 	    if (ret == HDB_ERR_NOENTRY)
   1650 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
   1651 	    goto out;
   1652 	}
   1653 	ret = hdb_enctype2key(context, &uu->entry, NULL,
   1654 			      t->enc_part.etype, &uukey);
   1655 	if(ret){
   1656 	    _kdc_free_ent(context, uu);
   1657 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
   1658 	    goto out;
   1659 	}
   1660 	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
   1661 	_kdc_free_ent(context, uu);
   1662 	if(ret)
   1663 	    goto out;
   1664 
   1665 	ret = verify_flags(context, config, &adtkt, spn);
   1666 	if (ret)
   1667 	    goto out;
   1668 
   1669 	s = &adtkt.cname;
   1670 	r = adtkt.crealm;
   1671     } else if (s == NULL) {
   1672 	ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
   1673 	kdc_log(context, config, 0, "No server in request");
   1674 	goto out;
   1675     }
   1676 
   1677     _krb5_principalname2krb5_principal(context, &sp, *s, r);
   1678     ret = krb5_unparse_name(context, sp, &spn);
   1679     if (ret)
   1680 	goto out;
   1681     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
   1682     ret = krb5_unparse_name(context, cp, &cpn);
   1683     if (ret)
   1684 	goto out;
   1685     unparse_flags (KDCOptions2int(b->kdc_options),
   1686 		   asn1_KDCOptions_units(),
   1687 		   opt_str, sizeof(opt_str));
   1688     if(*opt_str)
   1689 	kdc_log(context, config, 0,
   1690 		"TGS-REQ %s from %s for %s [%s]",
   1691 		cpn, from, spn, opt_str);
   1692     else
   1693 	kdc_log(context, config, 0,
   1694 		"TGS-REQ %s from %s for %s", cpn, from, spn);
   1695 
   1696     /*
   1697      * Fetch server
   1698      */
   1699 
   1700 server_lookup:
   1701     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
   1702 			NULL, NULL, &server);
   1703 
   1704     if (ret == HDB_ERR_NOT_FOUND_HERE) {
   1705 	kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
   1706 	goto out;
   1707     } else if (ret == HDB_ERR_WRONG_REALM) {
   1708         free(ref_realm);
   1709 	ref_realm = strdup(server->entry.principal->realm);
   1710 	if (ref_realm == NULL) {
   1711             ret = krb5_enomem(context);
   1712 	    goto out;
   1713 	}
   1714 
   1715 	kdc_log(context, config, 5,
   1716 		"Returning a referral to realm %s for "
   1717 		"server %s.",
   1718 		ref_realm, spn);
   1719 	krb5_free_principal(context, sp);
   1720 	sp = NULL;
   1721 	ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
   1722 				  ref_realm, NULL);
   1723 	if (ret)
   1724 	    goto out;
   1725 	free(spn);
   1726         spn = NULL;
   1727 	ret = krb5_unparse_name(context, sp, &spn);
   1728 	if (ret)
   1729 	    goto out;
   1730 
   1731 	goto server_lookup;
   1732     } else if (ret) {
   1733 	const char *new_rlm, *msg;
   1734 	Realm req_rlm;
   1735 	krb5_realm *realms;
   1736 
   1737 	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
   1738             if (capath == NULL) {
   1739                 /* With referalls, hierarchical capaths are always enabled */
   1740                 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
   1741                                          req_rlm, TRUE, &capath, &num_capath);
   1742                 if (ret2) {
   1743                     ret = ret2;
   1744                     goto out;
   1745                 }
   1746             }
   1747             new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
   1748             if (new_rlm) {
   1749                 kdc_log(context, config, 5, "krbtgt from %s via %s for "
   1750                         "realm %s not found, trying %s", tgt->crealm,
   1751                         our_realm, req_rlm, new_rlm);
   1752 
   1753                 free(ref_realm);
   1754                 ref_realm = strdup(new_rlm);
   1755                 if (ref_realm == NULL) {
   1756                     ret = krb5_enomem(context);
   1757                     goto out;
   1758                 }
   1759 
   1760                 krb5_free_principal(context, sp);
   1761                 sp = NULL;
   1762                 krb5_make_principal(context, &sp, r,
   1763                                     KRB5_TGS_NAME, ref_realm, NULL);
   1764                 free(spn);
   1765                 spn = NULL;
   1766                 ret = krb5_unparse_name(context, sp, &spn);
   1767                 if (ret)
   1768                     goto out;
   1769                 goto server_lookup;
   1770             }
   1771 	} else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
   1772 	    if (strcmp(realms[0], sp->realm) != 0) {
   1773 		kdc_log(context, config, 5,
   1774 			"Returning a referral to realm %s for "
   1775 			"server %s that was not found",
   1776 			realms[0], spn);
   1777 		krb5_free_principal(context, sp);
   1778                 sp = NULL;
   1779 		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
   1780 				    realms[0], NULL);
   1781 		free(spn);
   1782                 spn = NULL;
   1783 		ret = krb5_unparse_name(context, sp, &spn);
   1784 		if (ret) {
   1785 		    krb5_free_host_realm(context, realms);
   1786 		    goto out;
   1787 		}
   1788 
   1789                 free(ref_realm);
   1790 		ref_realm = strdup(realms[0]);
   1791 
   1792 		krb5_free_host_realm(context, realms);
   1793 		goto server_lookup;
   1794 	    }
   1795 	    krb5_free_host_realm(context, realms);
   1796 	}
   1797 	msg = krb5_get_error_message(context, ret);
   1798 	kdc_log(context, config, 0,
   1799 		"Server not found in database: %s: %s", spn, msg);
   1800 	krb5_free_error_message(context, msg);
   1801 	if (ret == HDB_ERR_NOENTRY)
   1802 	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
   1803 	goto out;
   1804     }
   1805 
   1806     /* the name returned to the client depend on what was asked for,
   1807      * return canonical name if kdc_options.canonicalize was set, the
   1808      * client wants the true name of the principal, if not it just
   1809      * wants the name its asked for.
   1810      */
   1811 
   1812     if (b->kdc_options.canonicalize)
   1813 	rsp = server->entry.principal;
   1814     else
   1815 	rsp = sp;
   1816 
   1817 
   1818     /*
   1819      * Select enctype, return key and kvno.
   1820      */
   1821 
   1822     {
   1823 	krb5_enctype etype;
   1824 
   1825 	if(b->kdc_options.enc_tkt_in_skey) {
   1826 	    size_t i;
   1827 	    ekey = &adtkt.key;
   1828 	    for(i = 0; i < b->etype.len; i++)
   1829 		if (b->etype.val[i] == adtkt.key.keytype)
   1830 		    break;
   1831 	    if(i == b->etype.len) {
   1832 		kdc_log(context, config, 0,
   1833 			"Addition ticket have not matching etypes");
   1834 		krb5_clear_error_message(context);
   1835 		ret = KRB5KDC_ERR_ETYPE_NOSUPP;
   1836 		goto out;
   1837 	    }
   1838 	    etype = b->etype.val[i];
   1839 	    kvno = 0;
   1840 	} else {
   1841 	    Key *skey;
   1842 
   1843 	    ret = _kdc_find_etype(context,
   1844 				  krb5_principal_is_krbtgt(context, sp) ?
   1845 				  config->tgt_use_strongest_session_key :
   1846 				  config->svc_use_strongest_session_key, FALSE,
   1847 				  server, b->etype.val, b->etype.len, &etype,
   1848 				  NULL);
   1849 	    if(ret) {
   1850 		kdc_log(context, config, 0,
   1851 			"Server (%s) has no support for etypes", spn);
   1852 		goto out;
   1853 	    }
   1854 	    ret = _kdc_get_preferred_key(context, config, server, spn,
   1855 					 NULL, &skey);
   1856 	    if(ret) {
   1857 		kdc_log(context, config, 0,
   1858 			"Server (%s) has no supported etypes", spn);
   1859 		goto out;
   1860 	    }
   1861 	    ekey = &skey->key;
   1862 	    kvno = server->entry.kvno;
   1863 	}
   1864 
   1865 	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
   1866 	if (ret)
   1867 	    goto out;
   1868     }
   1869 
   1870     /*
   1871      * Check that service is in the same realm as the krbtgt. If it's
   1872      * not the same, it's someone that is using a uni-directional trust
   1873      * backward.
   1874      */
   1875 
   1876     /*
   1877      * Validate authoriation data
   1878      */
   1879 
   1880     ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
   1881 			  krbtgt_etype, &tkey_check);
   1882     if(ret) {
   1883 	kdc_log(context, config, 0,
   1884 		    "Failed to find key for krbtgt PAC check");
   1885 	goto out;
   1886     }
   1887 
   1888     /*
   1889      * Now refetch the primary krbtgt, and get the current kvno (the
   1890      * sign check may have been on an old kvno, and the server may
   1891      * have been an incoming trust)
   1892      */
   1893 
   1894     ret = krb5_make_principal(context,
   1895                               &krbtgt_out_principal,
   1896                               our_realm,
   1897                               KRB5_TGS_NAME,
   1898                               our_realm,
   1899                               NULL);
   1900     if (ret) {
   1901         kdc_log(context, config, 0,
   1902                 "Failed to make krbtgt principal name object for "
   1903                 "authz-data signatures");
   1904         goto out;
   1905     }
   1906     ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
   1907     if (ret) {
   1908         kdc_log(context, config, 0,
   1909                 "Failed to make krbtgt principal name object for "
   1910                 "authz-data signatures");
   1911         goto out;
   1912     }
   1913 
   1914     ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
   1915 			HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
   1916     if (ret) {
   1917 	char *ktpn = NULL;
   1918 	ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
   1919 	kdc_log(context, config, 0,
   1920 		"No such principal %s (needed for authz-data signature keys) "
   1921 		"while processing TGS-REQ for service %s with krbtg %s",
   1922 		krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
   1923 	free(ktpn);
   1924 	ret = KRB5KRB_AP_ERR_NOT_US;
   1925 	goto out;
   1926     }
   1927 
   1928     /*
   1929      * The first realm is the realm of the service, the second is
   1930      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
   1931      * encrypted to.  The redirection via the krbtgt_out entry allows
   1932      * the DB to possibly correct the case of the realm (Samba4 does
   1933      * this) before the strcmp()
   1934      */
   1935     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
   1936 	       krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
   1937 	char *ktpn;
   1938 	ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
   1939 	kdc_log(context, config, 0,
   1940 		"Request with wrong krbtgt: %s",
   1941 		(ret == 0) ? ktpn : "<unknown>");
   1942 	if(ret == 0)
   1943 	    free(ktpn);
   1944 	ret = KRB5KRB_AP_ERR_NOT_US;
   1945 	goto out;
   1946     }
   1947 
   1948     ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
   1949 				 NULL, &tkey_sign);
   1950     if (ret) {
   1951 	kdc_log(context, config, 0,
   1952 		    "Failed to find key for krbtgt PAC signature");
   1953 	goto out;
   1954     }
   1955     ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
   1956 			  tkey_sign->key.keytype, &tkey_sign);
   1957     if(ret) {
   1958 	kdc_log(context, config, 0,
   1959 		    "Failed to find key for krbtgt PAC signature");
   1960 	goto out;
   1961     }
   1962 
   1963     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
   1964 			NULL, &clientdb, &client);
   1965     if(ret == HDB_ERR_NOT_FOUND_HERE) {
   1966 	/* This is OK, we are just trying to find out if they have
   1967 	 * been disabled or deleted in the meantime, missing secrets
   1968 	 * is OK */
   1969     } else if(ret){
   1970 	const char *krbtgt_realm, *msg;
   1971 
   1972 	/*
   1973 	 * If the client belongs to the same realm as our krbtgt, it
   1974 	 * should exist in the local database.
   1975 	 *
   1976 	 */
   1977 
   1978 	krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
   1979 
   1980 	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
   1981 	    if (ret == HDB_ERR_NOENTRY)
   1982 		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
   1983 	    kdc_log(context, config, 1, "Client no longer in database: %s",
   1984 		    cpn);
   1985 	    goto out;
   1986 	}
   1987 
   1988 	msg = krb5_get_error_message(context, ret);
   1989 	kdc_log(context, config, 1, "Client not found in database: %s", msg);
   1990 	krb5_free_error_message(context, msg);
   1991     }
   1992 
   1993     ret = check_PAC(context, config, cp, NULL,
   1994 		    client, server, krbtgt,
   1995 		    &tkey_check->key,
   1996 		    ekey, &tkey_sign->key,
   1997 		    tgt, &rspac, &signedpath);
   1998     if (ret) {
   1999 	const char *msg = krb5_get_error_message(context, ret);
   2000 	kdc_log(context, config, 0,
   2001 		"Verify PAC failed for %s (%s) from %s with %s",
   2002 		spn, cpn, from, msg);
   2003 	krb5_free_error_message(context, msg);
   2004 	goto out;
   2005     }
   2006 
   2007     /* also check the krbtgt for signature */
   2008     ret = check_KRB5SignedPath(context,
   2009 			       config,
   2010 			       krbtgt,
   2011 			       cp,
   2012 			       tgt,
   2013 			       &spp,
   2014 			       &signedpath);
   2015     if (ret) {
   2016 	const char *msg = krb5_get_error_message(context, ret);
   2017 	kdc_log(context, config, 0,
   2018 		"KRB5SignedPath check failed for %s (%s) from %s with %s",
   2019 		spn, cpn, from, msg);
   2020 	krb5_free_error_message(context, msg);
   2021 	goto out;
   2022     }
   2023 
   2024     /*
   2025      * Process request
   2026      */
   2027 
   2028     /* by default the tgt principal matches the client principal */
   2029     tp = cp;
   2030     tpn = cpn;
   2031 
   2032     if (client) {
   2033 	const PA_DATA *sdata;
   2034 	int i = 0;
   2035 
   2036 	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
   2037 	if (sdata) {
   2038 	    krb5_crypto crypto;
   2039 	    krb5_data datack;
   2040 	    PA_S4U2Self self;
   2041 	    const char *str;
   2042 
   2043 	    ret = decode_PA_S4U2Self(sdata->padata_value.data,
   2044 				     sdata->padata_value.length,
   2045 				     &self, NULL);
   2046 	    if (ret) {
   2047 		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
   2048 		goto out;
   2049 	    }
   2050 
   2051 	    if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
   2052 		free_PA_S4U2Self(&self);
   2053 		kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
   2054 		ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
   2055 		goto out;
   2056 	    }
   2057 
   2058 	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
   2059 	    if (ret)
   2060 		goto out;
   2061 
   2062 	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
   2063 	    if (ret) {
   2064 		const char *msg = krb5_get_error_message(context, ret);
   2065 		free_PA_S4U2Self(&self);
   2066 		krb5_data_free(&datack);
   2067 		kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
   2068 		krb5_free_error_message(context, msg);
   2069 		goto out;
   2070 	    }
   2071 
   2072 	    /* Allow HMAC_MD5 checksum with any key type */
   2073 	    if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
   2074 		unsigned char csdata[16];
   2075 		Checksum cs;
   2076 
   2077 		cs.checksum.length = sizeof(csdata);
   2078 		cs.checksum.data = &csdata;
   2079 
   2080 		ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
   2081 					      datack.data, datack.length,
   2082 					      KRB5_KU_OTHER_CKSUM, &cs);
   2083 		if (ret == 0 &&
   2084 		    krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
   2085 		    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
   2086 	    }
   2087 	    else {
   2088 		ret = krb5_verify_checksum(context,
   2089 					   crypto,
   2090 					   KRB5_KU_OTHER_CKSUM,
   2091 					   datack.data,
   2092 					   datack.length,
   2093 					   &self.cksum);
   2094 	    }
   2095 	    krb5_data_free(&datack);
   2096 	    krb5_crypto_destroy(context, crypto);
   2097 	    if (ret) {
   2098 		const char *msg = krb5_get_error_message(context, ret);
   2099 		free_PA_S4U2Self(&self);
   2100 		kdc_log(context, config, 0,
   2101 			"krb5_verify_checksum failed for S4U2Self: %s", msg);
   2102 		krb5_free_error_message(context, msg);
   2103 		goto out;
   2104 	    }
   2105 
   2106 	    ret = _krb5_principalname2krb5_principal(context,
   2107 						     &tp,
   2108 						     self.name,
   2109 						     self.realm);
   2110 	    free_PA_S4U2Self(&self);
   2111 	    if (ret)
   2112 		goto out;
   2113 
   2114 	    ret = krb5_unparse_name(context, tp, &tpn);
   2115 	    if (ret)
   2116 		goto out;
   2117 
   2118 	    ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
   2119 				NULL, &s4u2self_impersonated_clientdb,
   2120 				&s4u2self_impersonated_client);
   2121 	    if (ret) {
   2122 		const char *msg;
   2123 
   2124 		/*
   2125 		 * If the client belongs to the same realm as our krbtgt, it
   2126 		 * should exist in the local database.
   2127 		 *
   2128 		 */
   2129 
   2130 		if (ret == HDB_ERR_NOENTRY)
   2131 		    ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
   2132 		msg = krb5_get_error_message(context, ret);
   2133 		kdc_log(context, config, 2,
   2134 			"S4U2Self principal to impersonate %s not found in database: %s",
   2135 			tpn, msg);
   2136 		krb5_free_error_message(context, msg);
   2137 		goto out;
   2138 	    }
   2139 
   2140 	    /* Ignore require_pwchange and pw_end attributes (as Windows does),
   2141 	     * since S4U2Self is not password authentication. */
   2142 	    s4u2self_impersonated_client->entry.flags.require_pwchange = FALSE;
   2143 	    free(s4u2self_impersonated_client->entry.pw_end);
   2144 	    s4u2self_impersonated_client->entry.pw_end = NULL;
   2145 
   2146 	    ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
   2147 				  NULL, NULL, FALSE);
   2148 	    if (ret)
   2149 		goto out;
   2150 
   2151 	    /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
   2152 	    if(rspac.data) {
   2153 		krb5_pac p = NULL;
   2154 		krb5_data_free(&rspac);
   2155 		ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
   2156 		if (ret) {
   2157 		    kdc_log(context, config, 0, "PAC generation failed for -- %s",
   2158 			    tpn);
   2159 		    goto out;
   2160 		}
   2161 		if (p != NULL) {
   2162 		    ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
   2163 					 s4u2self_impersonated_client->entry.principal,
   2164 					 ekey, &tkey_sign->key,
   2165 					 &rspac);
   2166 		    krb5_pac_free(context, p);
   2167 		    if (ret) {
   2168 			kdc_log(context, config, 0, "PAC signing failed for -- %s",
   2169 				tpn);
   2170 			goto out;
   2171 		    }
   2172 		}
   2173 	    }
   2174 
   2175 	    /*
   2176 	     * Check that service doing the impersonating is
   2177 	     * requesting a ticket to it-self.
   2178 	     */
   2179 	    ret = check_s4u2self(context, config, clientdb, client, sp);
   2180 	    if (ret) {
   2181 		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
   2182 			"to impersonate to service "
   2183 			"(tried for user %s to service %s)",
   2184 			cpn, tpn, spn);
   2185 		goto out;
   2186 	    }
   2187 
   2188 	    /*
   2189 	     * If the service isn't trusted for authentication to
   2190 	     * delegation or if the impersonate client is disallowed
   2191 	     * forwardable, remove the forwardable flag.
   2192 	     */
   2193 
   2194 	    if (client->entry.flags.trusted_for_delegation &&
   2195 		s4u2self_impersonated_client->entry.flags.forwardable) {
   2196 		str = "[forwardable]";
   2197 	    } else {
   2198 		b->kdc_options.forwardable = 0;
   2199 		str = "";
   2200 	    }
   2201 	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
   2202 		    "service %s %s", cpn, tpn, spn, str);
   2203 	}
   2204     }
   2205 
   2206     /*
   2207      * Constrained delegation
   2208      */
   2209 
   2210     if (client != NULL
   2211 	&& b->additional_tickets != NULL
   2212 	&& b->additional_tickets->len != 0
   2213 	&& b->kdc_options.cname_in_addl_tkt
   2214 	&& b->kdc_options.enc_tkt_in_skey == 0)
   2215     {
   2216 	int ad_signedpath = 0;
   2217 	Key *clientkey;
   2218 	Ticket *t;
   2219 
   2220 	/*
   2221 	 * Require that the KDC have issued the service's krbtgt (not
   2222 	 * self-issued ticket with kimpersonate(1).
   2223 	 */
   2224 	if (!signedpath) {
   2225 	    ret = KRB5KDC_ERR_BADOPTION;
   2226 	    kdc_log(context, config, 0,
   2227 		    "Constrained delegation done on service ticket %s/%s",
   2228 		    cpn, spn);
   2229 	    goto out;
   2230 	}
   2231 
   2232 	t = &b->additional_tickets->val[0];
   2233 
   2234 	ret = hdb_enctype2key(context, &client->entry,
   2235 			      hdb_kvno2keys(context, &client->entry,
   2236 					    t->enc_part.kvno ? * t->enc_part.kvno : 0),
   2237 			      t->enc_part.etype, &clientkey);
   2238 	if(ret){
   2239 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
   2240 	    goto out;
   2241 	}
   2242 
   2243 	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
   2244 	if (ret) {
   2245 	    kdc_log(context, config, 0,
   2246 		    "failed to decrypt ticket for "
   2247 		    "constrained delegation from %s to %s ", cpn, spn);
   2248 	    goto out;
   2249 	}
   2250 
   2251 	ret = _krb5_principalname2krb5_principal(context,
   2252 						 &tp,
   2253 						 adtkt.cname,
   2254 						 adtkt.crealm);
   2255 	if (ret)
   2256 	    goto out;
   2257 
   2258 	ret = krb5_unparse_name(context, tp, &tpn);
   2259 	if (ret)
   2260 	    goto out;
   2261 
   2262 	ret = _krb5_principalname2krb5_principal(context,
   2263 						 &dp,
   2264 						 t->sname,
   2265 						 t->realm);
   2266 	if (ret)
   2267 	    goto out;
   2268 
   2269 	ret = krb5_unparse_name(context, dp, &dpn);
   2270 	if (ret)
   2271 	    goto out;
   2272 
   2273 	/* check that ticket is valid */
   2274 	if (adtkt.flags.forwardable == 0) {
   2275 	    kdc_log(context, config, 0,
   2276 		    "Missing forwardable flag on ticket for "
   2277 		    "constrained delegation from %s (%s) as %s to %s ",
   2278 		    cpn, dpn, tpn, spn);
   2279 	    ret = KRB5KDC_ERR_BADOPTION;
   2280 	    goto out;
   2281 	}
   2282 
   2283 	ret = check_constrained_delegation(context, config, clientdb,
   2284 					   client, server, sp);
   2285 	if (ret) {
   2286 	    kdc_log(context, config, 0,
   2287 		    "constrained delegation from %s (%s) as %s to %s not allowed",
   2288 		    cpn, dpn, tpn, spn);
   2289 	    goto out;
   2290 	}
   2291 
   2292 	ret = verify_flags(context, config, &adtkt, tpn);
   2293 	if (ret) {
   2294 	    goto out;
   2295 	}
   2296 
   2297 	krb5_data_free(&rspac);
   2298 
   2299 	/*
   2300 	 * generate the PAC for the user.
   2301 	 *
   2302 	 * TODO: pass in t->sname and t->realm and build
   2303 	 * a S4U_DELEGATION_INFO blob to the PAC.
   2304 	 */
   2305 	ret = check_PAC(context, config, tp, dp,
   2306 			client, server, krbtgt,
   2307 			&clientkey->key,
   2308 			ekey, &tkey_sign->key,
   2309 			&adtkt, &rspac, &ad_signedpath);
   2310 	if (ret) {
   2311 	    const char *msg = krb5_get_error_message(context, ret);
   2312 	    kdc_log(context, config, 0,
   2313 		    "Verify delegated PAC failed to %s for client"
   2314 		    "%s (%s) as %s from %s with %s",
   2315 		    spn, cpn, dpn, tpn, from, msg);
   2316 	    krb5_free_error_message(context, msg);
   2317 	    goto out;
   2318 	}
   2319 
   2320 	/*
   2321 	 * Check that the KDC issued the user's ticket.
   2322 	 */
   2323 	ret = check_KRB5SignedPath(context,
   2324 				   config,
   2325 				   krbtgt,
   2326 				   cp,
   2327 				   &adtkt,
   2328 				   NULL,
   2329 				   &ad_signedpath);
   2330 	if (ret) {
   2331 	    const char *msg = krb5_get_error_message(context, ret);
   2332 	    kdc_log(context, config, 0,
   2333 		    "KRB5SignedPath check from service %s failed "
   2334 		    "for delegation to %s for client %s (%s)"
   2335 		    "from %s failed with %s",
   2336 		    spn, tpn, dpn, cpn, from, msg);
   2337 	    krb5_free_error_message(context, msg);
   2338 	    goto out;
   2339 	}
   2340 
   2341 	if (!ad_signedpath) {
   2342 	    ret = KRB5KDC_ERR_BADOPTION;
   2343 	    kdc_log(context, config, 0,
   2344 		    "Ticket not signed with PAC nor SignedPath service %s failed "
   2345 		    "for delegation to %s for client %s (%s)"
   2346 		    "from %s",
   2347 		    spn, tpn, dpn, cpn, from);
   2348 	    goto out;
   2349 	}
   2350 
   2351 	kdc_log(context, config, 0, "constrained delegation for %s "
   2352 		"from %s (%s) to %s", tpn, cpn, dpn, spn);
   2353     }
   2354 
   2355     /*
   2356      * Check flags
   2357      */
   2358 
   2359     ret = kdc_check_flags(context, config,
   2360 			  client, cpn,
   2361 			  server, spn,
   2362 			  FALSE);
   2363     if(ret)
   2364 	goto out;
   2365 
   2366     if((b->kdc_options.validate || b->kdc_options.renew) &&
   2367        !krb5_principal_compare(context,
   2368 			       krbtgt->entry.principal,
   2369 			       server->entry.principal)){
   2370 	kdc_log(context, config, 0, "Inconsistent request.");
   2371 	ret = KRB5KDC_ERR_SERVER_NOMATCH;
   2372 	goto out;
   2373     }
   2374 
   2375     /* check for valid set of addresses */
   2376     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
   2377 	ret = KRB5KRB_AP_ERR_BADADDR;
   2378 	kdc_log(context, config, 0, "Request from wrong address");
   2379 	goto out;
   2380     }
   2381 
   2382     /* check local and per-principal anonymous ticket issuance policy */
   2383     if (is_anon_tgs_request_p(b, tgt)) {
   2384 	ret = _kdc_check_anon_policy(context, config, client, server);
   2385 	if (ret)
   2386 	    goto out;
   2387     }
   2388 
   2389     /*
   2390      * If this is an referral, add server referral data to the
   2391      * auth_data reply .
   2392      */
   2393     if (ref_realm) {
   2394 	PA_DATA pa;
   2395 	krb5_crypto crypto;
   2396 
   2397 	kdc_log(context, config, 0,
   2398 		"Adding server referral to %s", ref_realm);
   2399 
   2400 	ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
   2401 	if (ret)
   2402 	    goto out;
   2403 
   2404 	ret = build_server_referral(context, config, crypto, ref_realm,
   2405 				    NULL, s, &pa.padata_value);
   2406 	krb5_crypto_destroy(context, crypto);
   2407 	if (ret) {
   2408 	    kdc_log(context, config, 0,
   2409 		    "Failed building server referral");
   2410 	    goto out;
   2411 	}
   2412 	pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
   2413 
   2414 	ret = add_METHOD_DATA(&enc_pa_data, &pa);
   2415 	krb5_data_free(&pa.padata_value);
   2416 	if (ret) {
   2417 	    kdc_log(context, config, 0,
   2418 		    "Add server referral METHOD-DATA failed");
   2419 	    goto out;
   2420 	}
   2421     }
   2422 
   2423     /*
   2424      *
   2425      */
   2426 
   2427     ret = tgs_make_reply(context,
   2428 			 config,
   2429 			 b,
   2430 			 tp,
   2431 			 tgt,
   2432 			 replykey,
   2433 			 rk_is_subkey,
   2434 			 ekey,
   2435 			 &sessionkey,
   2436 			 kvno,
   2437 			 *auth_data,
   2438 			 server,
   2439 			 rsp,
   2440 			 spn,
   2441 			 client,
   2442 			 cp,
   2443                          tgt_realm,
   2444 			 krbtgt_out,
   2445 			 tkey_sign->key.keytype,
   2446 			 spp,
   2447 			 &rspac,
   2448 			 &enc_pa_data,
   2449 			 e_text,
   2450 			 reply);
   2451 
   2452 out:
   2453     if (tpn != cpn)
   2454 	    free(tpn);
   2455     free(spn);
   2456     free(cpn);
   2457     free(dpn);
   2458     free(krbtgt_out_n);
   2459     _krb5_free_capath(context, capath);
   2460 
   2461     krb5_data_free(&rspac);
   2462     krb5_free_keyblock_contents(context, &sessionkey);
   2463     if(krbtgt_out)
   2464 	_kdc_free_ent(context, krbtgt_out);
   2465     if(server)
   2466 	_kdc_free_ent(context, server);
   2467     if(client)
   2468 	_kdc_free_ent(context, client);
   2469     if(s4u2self_impersonated_client)
   2470 	_kdc_free_ent(context, s4u2self_impersonated_client);
   2471 
   2472     if (tp && tp != cp)
   2473 	krb5_free_principal(context, tp);
   2474     krb5_free_principal(context, cp);
   2475     krb5_free_principal(context, dp);
   2476     krb5_free_principal(context, sp);
   2477     krb5_free_principal(context, krbtgt_out_principal);
   2478     free(ref_realm);
   2479     free_METHOD_DATA(&enc_pa_data);
   2480 
   2481     free_EncTicketPart(&adtkt);
   2482 
   2483     return ret;
   2484 }
   2485 
   2486 /*
   2487  *
   2488  */
   2489 
   2490 krb5_error_code
   2491 _kdc_tgs_rep(krb5_context context,
   2492 	     krb5_kdc_configuration *config,
   2493 	     KDC_REQ *req,
   2494 	     krb5_data *data,
   2495 	     const char *from,
   2496 	     struct sockaddr *from_addr,
   2497 	     int datagram_reply)
   2498 {
   2499     AuthorizationData *auth_data = NULL;
   2500     krb5_error_code ret;
   2501     int i = 0;
   2502     const PA_DATA *tgs_req;
   2503 
   2504     hdb_entry_ex *krbtgt = NULL;
   2505     krb5_ticket *ticket = NULL;
   2506     const char *e_text = NULL;
   2507     krb5_enctype krbtgt_etype = ETYPE_NULL;
   2508 
   2509     krb5_keyblock *replykey = NULL;
   2510     int rk_is_subkey = 0;
   2511     time_t *csec = NULL;
   2512     int *cusec = NULL;
   2513 
   2514     if(req->padata == NULL){
   2515 	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
   2516 	kdc_log(context, config, 0,
   2517 		"TGS-REQ from %s without PA-DATA", from);
   2518 	goto out;
   2519     }
   2520 
   2521     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
   2522 
   2523     if(tgs_req == NULL){
   2524 	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
   2525 
   2526 	kdc_log(context, config, 0,
   2527 		"TGS-REQ from %s without PA-TGS-REQ", from);
   2528 	goto out;
   2529     }
   2530     ret = tgs_parse_request(context, config,
   2531 			    &req->req_body, tgs_req,
   2532 			    &krbtgt,
   2533 			    &krbtgt_etype,
   2534 			    &ticket,
   2535 			    &e_text,
   2536 			    from, from_addr,
   2537 			    &csec, &cusec,
   2538 			    &auth_data,
   2539 			    &replykey,
   2540 			    &rk_is_subkey);
   2541     if (ret == HDB_ERR_NOT_FOUND_HERE) {
   2542 	/* kdc_log() is called in tgs_parse_request() */
   2543 	goto out;
   2544     }
   2545     if (ret) {
   2546 	kdc_log(context, config, 0,
   2547 		"Failed parsing TGS-REQ from %s", from);
   2548 	goto out;
   2549     }
   2550 
   2551     {
   2552 	const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
   2553 	if (pa)
   2554 	    kdc_log(context, config, 10, "Got TGS FAST request");
   2555     }
   2556 
   2557 
   2558     ret = tgs_build_reply(context,
   2559 			  config,
   2560 			  req,
   2561 			  &req->req_body,
   2562 			  krbtgt,
   2563 			  krbtgt_etype,
   2564 			  replykey,
   2565 			  rk_is_subkey,
   2566 			  ticket,
   2567 			  data,
   2568 			  from,
   2569 			  &e_text,
   2570 			  &auth_data,
   2571 			  from_addr);
   2572     if (ret) {
   2573 	kdc_log(context, config, 0,
   2574 		"Failed building TGS-REP to %s", from);
   2575 	goto out;
   2576     }
   2577 
   2578     /* */
   2579     if (datagram_reply && data->length > config->max_datagram_reply_length) {
   2580 	krb5_data_free(data);
   2581 	ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
   2582 	e_text = "Reply packet too large";
   2583     }
   2584 
   2585 out:
   2586     if (replykey)
   2587 	krb5_free_keyblock(context, replykey);
   2588 
   2589     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
   2590 	/* XXX add fast wrapping on the error */
   2591 	METHOD_DATA error_method = { 0, NULL };
   2592 
   2593 
   2594 	kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
   2595 	ret = _kdc_fast_mk_error(context, NULL,
   2596 				 &error_method,
   2597 				 NULL,
   2598 				 NULL,
   2599 				 ret, NULL,
   2600 				 NULL,
   2601 				 NULL, NULL,
   2602 				 csec, cusec,
   2603 				 data);
   2604 	free_METHOD_DATA(&error_method);
   2605     }
   2606     free(csec);
   2607     free(cusec);
   2608     if (ticket)
   2609 	krb5_free_ticket(context, ticket);
   2610     if(krbtgt)
   2611 	_kdc_free_ent(context, krbtgt);
   2612 
   2613     if (auth_data) {
   2614 	free_AuthorizationData(auth_data);
   2615 	free(auth_data);
   2616     }
   2617 
   2618     return ret;
   2619 }
   2620