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