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