1178825Sdfr/* 2178825Sdfr * Copyright (c) 1997-2007 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "kdc_locl.h" 35178825Sdfr 36178825SdfrRCSID("$Id: krb5tgs.c 22071 2007-11-14 20:04:50Z lha $"); 37178825Sdfr 38178825Sdfr/* 39178825Sdfr * return the realm of a krbtgt-ticket or NULL 40178825Sdfr */ 41178825Sdfr 42178825Sdfrstatic Realm 43178825Sdfrget_krbtgt_realm(const PrincipalName *p) 44178825Sdfr{ 45178825Sdfr if(p->name_string.len == 2 46178825Sdfr && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0) 47178825Sdfr return p->name_string.val[1]; 48178825Sdfr else 49178825Sdfr return NULL; 50178825Sdfr} 51178825Sdfr 52178825Sdfr/* 53178825Sdfr * The KDC might add a signed path to the ticket authorization data 54178825Sdfr * field. This is to avoid server impersonating clients and the 55178825Sdfr * request constrained delegation. 56178825Sdfr * 57178825Sdfr * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single 58178825Sdfr * entry of type KRB5SignedPath. 59178825Sdfr */ 60178825Sdfr 61178825Sdfrstatic krb5_error_code 62178825Sdfrfind_KRB5SignedPath(krb5_context context, 63178825Sdfr const AuthorizationData *ad, 64178825Sdfr krb5_data *data) 65178825Sdfr{ 66178825Sdfr AuthorizationData child; 67178825Sdfr krb5_error_code ret; 68178825Sdfr int pos; 69178825Sdfr 70178825Sdfr if (ad == NULL || ad->len == 0) 71178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 72178825Sdfr 73178825Sdfr pos = ad->len - 1; 74178825Sdfr 75178825Sdfr if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 76178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 77178825Sdfr 78178825Sdfr ret = decode_AuthorizationData(ad->val[pos].ad_data.data, 79178825Sdfr ad->val[pos].ad_data.length, 80178825Sdfr &child, 81178825Sdfr NULL); 82178825Sdfr if (ret) { 83178825Sdfr krb5_set_error_string(context, "Failed to decode " 84178825Sdfr "IF_RELEVANT with %d", ret); 85178825Sdfr return ret; 86178825Sdfr } 87178825Sdfr 88178825Sdfr if (child.len != 1) { 89178825Sdfr free_AuthorizationData(&child); 90178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 91178825Sdfr } 92178825Sdfr 93178825Sdfr if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { 94178825Sdfr free_AuthorizationData(&child); 95178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 96178825Sdfr } 97178825Sdfr 98178825Sdfr if (data) 99178825Sdfr ret = der_copy_octet_string(&child.val[0].ad_data, data); 100178825Sdfr free_AuthorizationData(&child); 101178825Sdfr return ret; 102178825Sdfr} 103178825Sdfr 104178825Sdfrkrb5_error_code 105178825Sdfr_kdc_add_KRB5SignedPath(krb5_context context, 106178825Sdfr krb5_kdc_configuration *config, 107178825Sdfr hdb_entry_ex *krbtgt, 108178825Sdfr krb5_enctype enctype, 109178825Sdfr krb5_const_principal server, 110178825Sdfr KRB5SignedPathPrincipals *principals, 111178825Sdfr EncTicketPart *tkt) 112178825Sdfr{ 113178825Sdfr krb5_error_code ret; 114178825Sdfr KRB5SignedPath sp; 115178825Sdfr krb5_data data; 116178825Sdfr krb5_crypto crypto = NULL; 117178825Sdfr size_t size; 118178825Sdfr 119178825Sdfr if (server && principals) { 120178825Sdfr ret = add_KRB5SignedPathPrincipals(principals, server); 121178825Sdfr if (ret) 122178825Sdfr return ret; 123178825Sdfr } 124178825Sdfr 125178825Sdfr { 126178825Sdfr KRB5SignedPathData spd; 127178825Sdfr 128178825Sdfr spd.encticket = *tkt; 129178825Sdfr spd.delegated = principals; 130178825Sdfr 131178825Sdfr ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 132178825Sdfr &spd, &size, ret); 133178825Sdfr if (ret) 134178825Sdfr return ret; 135178825Sdfr if (data.length != size) 136178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 137178825Sdfr } 138178825Sdfr 139178825Sdfr { 140178825Sdfr Key *key; 141178825Sdfr ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key); 142178825Sdfr if (ret == 0) 143178825Sdfr ret = krb5_crypto_init(context, &key->key, 0, &crypto); 144178825Sdfr if (ret) { 145178825Sdfr free(data.data); 146178825Sdfr return ret; 147178825Sdfr } 148178825Sdfr } 149178825Sdfr 150178825Sdfr /* 151178825Sdfr * Fill in KRB5SignedPath 152178825Sdfr */ 153178825Sdfr 154178825Sdfr sp.etype = enctype; 155178825Sdfr sp.delegated = principals; 156178825Sdfr 157178825Sdfr ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0, 158178825Sdfr data.data, data.length, &sp.cksum); 159178825Sdfr krb5_crypto_destroy(context, crypto); 160178825Sdfr free(data.data); 161178825Sdfr if (ret) 162178825Sdfr return ret; 163178825Sdfr 164178825Sdfr ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); 165178825Sdfr free_Checksum(&sp.cksum); 166178825Sdfr if (ret) 167178825Sdfr return ret; 168178825Sdfr if (data.length != size) 169178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 170178825Sdfr 171178825Sdfr 172178825Sdfr /* 173178825Sdfr * Add IF-RELEVANT(KRB5SignedPath) to the last slot in 174178825Sdfr * authorization data field. 175178825Sdfr */ 176178825Sdfr 177178825Sdfr ret = _kdc_tkt_add_if_relevant_ad(context, tkt, 178178825Sdfr KRB5_AUTHDATA_SIGNTICKET, &data); 179178825Sdfr krb5_data_free(&data); 180178825Sdfr 181178825Sdfr return ret; 182178825Sdfr} 183178825Sdfr 184178825Sdfrstatic krb5_error_code 185178825Sdfrcheck_KRB5SignedPath(krb5_context context, 186178825Sdfr krb5_kdc_configuration *config, 187178825Sdfr hdb_entry_ex *krbtgt, 188178825Sdfr EncTicketPart *tkt, 189178825Sdfr KRB5SignedPathPrincipals **delegated, 190178825Sdfr int require_signedpath) 191178825Sdfr{ 192178825Sdfr krb5_error_code ret; 193178825Sdfr krb5_data data; 194178825Sdfr krb5_crypto crypto = NULL; 195178825Sdfr 196178825Sdfr *delegated = NULL; 197178825Sdfr 198178825Sdfr ret = find_KRB5SignedPath(context, tkt->authorization_data, &data); 199178825Sdfr if (ret == 0) { 200178825Sdfr KRB5SignedPathData spd; 201178825Sdfr KRB5SignedPath sp; 202178825Sdfr AuthorizationData *ad; 203178825Sdfr size_t size; 204178825Sdfr 205178825Sdfr ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL); 206178825Sdfr krb5_data_free(&data); 207178825Sdfr if (ret) 208178825Sdfr return ret; 209178825Sdfr 210178825Sdfr spd.encticket = *tkt; 211178825Sdfr /* the KRB5SignedPath is the last entry */ 212178825Sdfr ad = spd.encticket.authorization_data; 213178825Sdfr if (--ad->len == 0) 214178825Sdfr spd.encticket.authorization_data = NULL; 215178825Sdfr spd.delegated = sp.delegated; 216178825Sdfr 217178825Sdfr ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 218178825Sdfr &spd, &size, ret); 219178825Sdfr ad->len++; 220178825Sdfr spd.encticket.authorization_data = ad; 221178825Sdfr if (ret) { 222178825Sdfr free_KRB5SignedPath(&sp); 223178825Sdfr return ret; 224178825Sdfr } 225178825Sdfr if (data.length != size) 226178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 227178825Sdfr 228178825Sdfr { 229178825Sdfr Key *key; 230178825Sdfr ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key); 231178825Sdfr if (ret == 0) 232178825Sdfr ret = krb5_crypto_init(context, &key->key, 0, &crypto); 233178825Sdfr if (ret) { 234178825Sdfr free(data.data); 235178825Sdfr free_KRB5SignedPath(&sp); 236178825Sdfr return ret; 237178825Sdfr } 238178825Sdfr } 239178825Sdfr ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 240178825Sdfr data.data, data.length, 241178825Sdfr &sp.cksum); 242178825Sdfr krb5_crypto_destroy(context, crypto); 243178825Sdfr free(data.data); 244178825Sdfr if (ret) { 245178825Sdfr free_KRB5SignedPath(&sp); 246178825Sdfr return ret; 247178825Sdfr } 248178825Sdfr 249178825Sdfr if (sp.delegated) { 250178825Sdfr 251178825Sdfr *delegated = malloc(sizeof(*sp.delegated)); 252178825Sdfr if (*delegated == NULL) { 253178825Sdfr free_KRB5SignedPath(&sp); 254178825Sdfr return ENOMEM; 255178825Sdfr } 256178825Sdfr 257178825Sdfr ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated); 258178825Sdfr if (ret) { 259178825Sdfr free_KRB5SignedPath(&sp); 260178825Sdfr free(*delegated); 261178825Sdfr *delegated = NULL; 262178825Sdfr return ret; 263178825Sdfr } 264178825Sdfr } 265178825Sdfr free_KRB5SignedPath(&sp); 266178825Sdfr 267178825Sdfr } else { 268178825Sdfr if (require_signedpath) 269178825Sdfr return KRB5KDC_ERR_BADOPTION; 270178825Sdfr } 271178825Sdfr 272178825Sdfr return 0; 273178825Sdfr} 274178825Sdfr 275178825Sdfr/* 276178825Sdfr * 277178825Sdfr */ 278178825Sdfr 279178825Sdfrstatic krb5_error_code 280178825Sdfrcheck_PAC(krb5_context context, 281178825Sdfr krb5_kdc_configuration *config, 282178825Sdfr const krb5_principal client_principal, 283178825Sdfr hdb_entry_ex *client, 284178825Sdfr hdb_entry_ex *server, 285178825Sdfr const EncryptionKey *server_key, 286178825Sdfr const EncryptionKey *krbtgt_key, 287178825Sdfr EncTicketPart *tkt, 288178825Sdfr krb5_data *rspac, 289178825Sdfr int *require_signedpath) 290178825Sdfr{ 291178825Sdfr AuthorizationData *ad = tkt->authorization_data; 292178825Sdfr unsigned i, j; 293178825Sdfr krb5_error_code ret; 294178825Sdfr 295178825Sdfr if (ad == NULL || ad->len == 0) 296178825Sdfr return 0; 297178825Sdfr 298178825Sdfr for (i = 0; i < ad->len; i++) { 299178825Sdfr AuthorizationData child; 300178825Sdfr 301178825Sdfr if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 302178825Sdfr continue; 303178825Sdfr 304178825Sdfr ret = decode_AuthorizationData(ad->val[i].ad_data.data, 305178825Sdfr ad->val[i].ad_data.length, 306178825Sdfr &child, 307178825Sdfr NULL); 308178825Sdfr if (ret) { 309178825Sdfr krb5_set_error_string(context, "Failed to decode " 310178825Sdfr "IF_RELEVANT with %d", ret); 311178825Sdfr return ret; 312178825Sdfr } 313178825Sdfr for (j = 0; j < child.len; j++) { 314178825Sdfr 315178825Sdfr if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { 316178825Sdfr krb5_pac pac; 317178825Sdfr 318178825Sdfr /* Found PAC */ 319178825Sdfr ret = krb5_pac_parse(context, 320178825Sdfr child.val[j].ad_data.data, 321178825Sdfr child.val[j].ad_data.length, 322178825Sdfr &pac); 323178825Sdfr free_AuthorizationData(&child); 324178825Sdfr if (ret) 325178825Sdfr return ret; 326178825Sdfr 327178825Sdfr ret = krb5_pac_verify(context, pac, tkt->authtime, 328178825Sdfr client_principal, 329178825Sdfr krbtgt_key, NULL); 330178825Sdfr if (ret) { 331178825Sdfr krb5_pac_free(context, pac); 332178825Sdfr return ret; 333178825Sdfr } 334178825Sdfr 335178825Sdfr ret = _kdc_pac_verify(context, client_principal, 336178825Sdfr client, server, &pac); 337178825Sdfr if (ret) { 338178825Sdfr krb5_pac_free(context, pac); 339178825Sdfr return ret; 340178825Sdfr } 341178825Sdfr *require_signedpath = 0; 342178825Sdfr 343178825Sdfr ret = _krb5_pac_sign(context, pac, tkt->authtime, 344178825Sdfr client_principal, 345178825Sdfr server_key, krbtgt_key, rspac); 346178825Sdfr 347178825Sdfr krb5_pac_free(context, pac); 348178825Sdfr 349178825Sdfr return ret; 350178825Sdfr } 351178825Sdfr } 352178825Sdfr free_AuthorizationData(&child); 353178825Sdfr } 354178825Sdfr return 0; 355178825Sdfr} 356178825Sdfr 357178825Sdfr/* 358178825Sdfr * 359178825Sdfr */ 360178825Sdfr 361178825Sdfrstatic krb5_error_code 362178825Sdfrcheck_tgs_flags(krb5_context context, 363178825Sdfr krb5_kdc_configuration *config, 364178825Sdfr KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et) 365178825Sdfr{ 366178825Sdfr KDCOptions f = b->kdc_options; 367178825Sdfr 368178825Sdfr if(f.validate){ 369178825Sdfr if(!tgt->flags.invalid || tgt->starttime == NULL){ 370178825Sdfr kdc_log(context, config, 0, 371178825Sdfr "Bad request to validate ticket"); 372178825Sdfr return KRB5KDC_ERR_BADOPTION; 373178825Sdfr } 374178825Sdfr if(*tgt->starttime > kdc_time){ 375178825Sdfr kdc_log(context, config, 0, 376178825Sdfr "Early request to validate ticket"); 377178825Sdfr return KRB5KRB_AP_ERR_TKT_NYV; 378178825Sdfr } 379178825Sdfr /* XXX tkt = tgt */ 380178825Sdfr et->flags.invalid = 0; 381178825Sdfr }else if(tgt->flags.invalid){ 382178825Sdfr kdc_log(context, config, 0, 383178825Sdfr "Ticket-granting ticket has INVALID flag set"); 384178825Sdfr return KRB5KRB_AP_ERR_TKT_INVALID; 385178825Sdfr } 386178825Sdfr 387178825Sdfr if(f.forwardable){ 388178825Sdfr if(!tgt->flags.forwardable){ 389178825Sdfr kdc_log(context, config, 0, 390178825Sdfr "Bad request for forwardable ticket"); 391178825Sdfr return KRB5KDC_ERR_BADOPTION; 392178825Sdfr } 393178825Sdfr et->flags.forwardable = 1; 394178825Sdfr } 395178825Sdfr if(f.forwarded){ 396178825Sdfr if(!tgt->flags.forwardable){ 397178825Sdfr kdc_log(context, config, 0, 398178825Sdfr "Request to forward non-forwardable ticket"); 399178825Sdfr return KRB5KDC_ERR_BADOPTION; 400178825Sdfr } 401178825Sdfr et->flags.forwarded = 1; 402178825Sdfr et->caddr = b->addresses; 403178825Sdfr } 404178825Sdfr if(tgt->flags.forwarded) 405178825Sdfr et->flags.forwarded = 1; 406178825Sdfr 407178825Sdfr if(f.proxiable){ 408178825Sdfr if(!tgt->flags.proxiable){ 409178825Sdfr kdc_log(context, config, 0, 410178825Sdfr "Bad request for proxiable ticket"); 411178825Sdfr return KRB5KDC_ERR_BADOPTION; 412178825Sdfr } 413178825Sdfr et->flags.proxiable = 1; 414178825Sdfr } 415178825Sdfr if(f.proxy){ 416178825Sdfr if(!tgt->flags.proxiable){ 417178825Sdfr kdc_log(context, config, 0, 418178825Sdfr "Request to proxy non-proxiable ticket"); 419178825Sdfr return KRB5KDC_ERR_BADOPTION; 420178825Sdfr } 421178825Sdfr et->flags.proxy = 1; 422178825Sdfr et->caddr = b->addresses; 423178825Sdfr } 424178825Sdfr if(tgt->flags.proxy) 425178825Sdfr et->flags.proxy = 1; 426178825Sdfr 427178825Sdfr if(f.allow_postdate){ 428178825Sdfr if(!tgt->flags.may_postdate){ 429178825Sdfr kdc_log(context, config, 0, 430178825Sdfr "Bad request for post-datable ticket"); 431178825Sdfr return KRB5KDC_ERR_BADOPTION; 432178825Sdfr } 433178825Sdfr et->flags.may_postdate = 1; 434178825Sdfr } 435178825Sdfr if(f.postdated){ 436178825Sdfr if(!tgt->flags.may_postdate){ 437178825Sdfr kdc_log(context, config, 0, 438178825Sdfr "Bad request for postdated ticket"); 439178825Sdfr return KRB5KDC_ERR_BADOPTION; 440178825Sdfr } 441178825Sdfr if(b->from) 442178825Sdfr *et->starttime = *b->from; 443178825Sdfr et->flags.postdated = 1; 444178825Sdfr et->flags.invalid = 1; 445178825Sdfr }else if(b->from && *b->from > kdc_time + context->max_skew){ 446178825Sdfr kdc_log(context, config, 0, "Ticket cannot be postdated"); 447178825Sdfr return KRB5KDC_ERR_CANNOT_POSTDATE; 448178825Sdfr } 449178825Sdfr 450178825Sdfr if(f.renewable){ 451178825Sdfr if(!tgt->flags.renewable){ 452178825Sdfr kdc_log(context, config, 0, 453178825Sdfr "Bad request for renewable ticket"); 454178825Sdfr return KRB5KDC_ERR_BADOPTION; 455178825Sdfr } 456178825Sdfr et->flags.renewable = 1; 457178825Sdfr ALLOC(et->renew_till); 458178825Sdfr _kdc_fix_time(&b->rtime); 459178825Sdfr *et->renew_till = *b->rtime; 460178825Sdfr } 461178825Sdfr if(f.renew){ 462178825Sdfr time_t old_life; 463178825Sdfr if(!tgt->flags.renewable || tgt->renew_till == NULL){ 464178825Sdfr kdc_log(context, config, 0, 465178825Sdfr "Request to renew non-renewable ticket"); 466178825Sdfr return KRB5KDC_ERR_BADOPTION; 467178825Sdfr } 468178825Sdfr old_life = tgt->endtime; 469178825Sdfr if(tgt->starttime) 470178825Sdfr old_life -= *tgt->starttime; 471178825Sdfr else 472178825Sdfr old_life -= tgt->authtime; 473178825Sdfr et->endtime = *et->starttime + old_life; 474178825Sdfr if (et->renew_till != NULL) 475178825Sdfr et->endtime = min(*et->renew_till, et->endtime); 476178825Sdfr } 477178825Sdfr 478178825Sdfr#if 0 479178825Sdfr /* checks for excess flags */ 480178825Sdfr if(f.request_anonymous && !config->allow_anonymous){ 481178825Sdfr kdc_log(context, config, 0, 482178825Sdfr "Request for anonymous ticket"); 483178825Sdfr return KRB5KDC_ERR_BADOPTION; 484178825Sdfr } 485178825Sdfr#endif 486178825Sdfr return 0; 487178825Sdfr} 488178825Sdfr 489178825Sdfr/* 490178825Sdfr * 491178825Sdfr */ 492178825Sdfr 493178825Sdfrstatic krb5_error_code 494178825Sdfrcheck_constrained_delegation(krb5_context context, 495178825Sdfr krb5_kdc_configuration *config, 496178825Sdfr hdb_entry_ex *client, 497178825Sdfr krb5_const_principal server) 498178825Sdfr{ 499178825Sdfr const HDB_Ext_Constrained_delegation_acl *acl; 500178825Sdfr krb5_error_code ret; 501178825Sdfr int i; 502178825Sdfr 503178825Sdfr ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl); 504178825Sdfr if (ret) { 505178825Sdfr krb5_clear_error_string(context); 506178825Sdfr return ret; 507178825Sdfr } 508178825Sdfr 509178825Sdfr if (acl) { 510178825Sdfr for (i = 0; i < acl->len; i++) { 511178825Sdfr if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE) 512178825Sdfr return 0; 513178825Sdfr } 514178825Sdfr } 515178825Sdfr kdc_log(context, config, 0, 516178825Sdfr "Bad request for constrained delegation"); 517178825Sdfr return KRB5KDC_ERR_BADOPTION; 518178825Sdfr} 519178825Sdfr 520178825Sdfr/* 521178825Sdfr * 522178825Sdfr */ 523178825Sdfr 524178825Sdfrstatic krb5_error_code 525178825Sdfrverify_flags (krb5_context context, 526178825Sdfr krb5_kdc_configuration *config, 527178825Sdfr const EncTicketPart *et, 528178825Sdfr const char *pstr) 529178825Sdfr{ 530178825Sdfr if(et->endtime < kdc_time){ 531178825Sdfr kdc_log(context, config, 0, "Ticket expired (%s)", pstr); 532178825Sdfr return KRB5KRB_AP_ERR_TKT_EXPIRED; 533178825Sdfr } 534178825Sdfr if(et->flags.invalid){ 535178825Sdfr kdc_log(context, config, 0, "Ticket not valid (%s)", pstr); 536178825Sdfr return KRB5KRB_AP_ERR_TKT_NYV; 537178825Sdfr } 538178825Sdfr return 0; 539178825Sdfr} 540178825Sdfr 541178825Sdfr/* 542178825Sdfr * 543178825Sdfr */ 544178825Sdfr 545178825Sdfrstatic krb5_error_code 546178825Sdfrfix_transited_encoding(krb5_context context, 547178825Sdfr krb5_kdc_configuration *config, 548178825Sdfr krb5_boolean check_policy, 549178825Sdfr const TransitedEncoding *tr, 550178825Sdfr EncTicketPart *et, 551178825Sdfr const char *client_realm, 552178825Sdfr const char *server_realm, 553178825Sdfr const char *tgt_realm) 554178825Sdfr{ 555178825Sdfr krb5_error_code ret = 0; 556178825Sdfr char **realms, **tmp; 557178825Sdfr int num_realms; 558178825Sdfr int i; 559178825Sdfr 560178825Sdfr switch (tr->tr_type) { 561178825Sdfr case DOMAIN_X500_COMPRESS: 562178825Sdfr break; 563178825Sdfr case 0: 564178825Sdfr /* 565178825Sdfr * Allow empty content of type 0 because that is was Microsoft 566178825Sdfr * generates in their TGT. 567178825Sdfr */ 568178825Sdfr if (tr->contents.length == 0) 569178825Sdfr break; 570178825Sdfr kdc_log(context, config, 0, 571178825Sdfr "Transited type 0 with non empty content"); 572178825Sdfr return KRB5KDC_ERR_TRTYPE_NOSUPP; 573178825Sdfr default: 574178825Sdfr kdc_log(context, config, 0, 575178825Sdfr "Unknown transited type: %u", tr->tr_type); 576178825Sdfr return KRB5KDC_ERR_TRTYPE_NOSUPP; 577178825Sdfr } 578178825Sdfr 579178825Sdfr ret = krb5_domain_x500_decode(context, 580178825Sdfr tr->contents, 581178825Sdfr &realms, 582178825Sdfr &num_realms, 583178825Sdfr client_realm, 584178825Sdfr server_realm); 585178825Sdfr if(ret){ 586178825Sdfr krb5_warn(context, ret, 587178825Sdfr "Decoding transited encoding"); 588178825Sdfr return ret; 589178825Sdfr } 590178825Sdfr if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) { 591178825Sdfr /* not us, so add the previous realm to transited set */ 592178825Sdfr if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) { 593178825Sdfr ret = ERANGE; 594178825Sdfr goto free_realms; 595178825Sdfr } 596178825Sdfr tmp = realloc(realms, (num_realms + 1) * sizeof(*realms)); 597178825Sdfr if(tmp == NULL){ 598178825Sdfr ret = ENOMEM; 599178825Sdfr goto free_realms; 600178825Sdfr } 601178825Sdfr realms = tmp; 602178825Sdfr realms[num_realms] = strdup(tgt_realm); 603178825Sdfr if(realms[num_realms] == NULL){ 604178825Sdfr ret = ENOMEM; 605178825Sdfr goto free_realms; 606178825Sdfr } 607178825Sdfr num_realms++; 608178825Sdfr } 609178825Sdfr if(num_realms == 0) { 610178825Sdfr if(strcmp(client_realm, server_realm)) 611178825Sdfr kdc_log(context, config, 0, 612178825Sdfr "cross-realm %s -> %s", client_realm, server_realm); 613178825Sdfr } else { 614178825Sdfr size_t l = 0; 615178825Sdfr char *rs; 616178825Sdfr for(i = 0; i < num_realms; i++) 617178825Sdfr l += strlen(realms[i]) + 2; 618178825Sdfr rs = malloc(l); 619178825Sdfr if(rs != NULL) { 620178825Sdfr *rs = '\0'; 621178825Sdfr for(i = 0; i < num_realms; i++) { 622178825Sdfr if(i > 0) 623178825Sdfr strlcat(rs, ", ", l); 624178825Sdfr strlcat(rs, realms[i], l); 625178825Sdfr } 626178825Sdfr kdc_log(context, config, 0, 627178825Sdfr "cross-realm %s -> %s via [%s]", 628178825Sdfr client_realm, server_realm, rs); 629178825Sdfr free(rs); 630178825Sdfr } 631178825Sdfr } 632178825Sdfr if(check_policy) { 633178825Sdfr ret = krb5_check_transited(context, client_realm, 634178825Sdfr server_realm, 635178825Sdfr realms, num_realms, NULL); 636178825Sdfr if(ret) { 637178825Sdfr krb5_warn(context, ret, "cross-realm %s -> %s", 638178825Sdfr client_realm, server_realm); 639178825Sdfr goto free_realms; 640178825Sdfr } 641178825Sdfr et->flags.transited_policy_checked = 1; 642178825Sdfr } 643178825Sdfr et->transited.tr_type = DOMAIN_X500_COMPRESS; 644178825Sdfr ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents); 645178825Sdfr if(ret) 646178825Sdfr krb5_warn(context, ret, "Encoding transited encoding"); 647178825Sdfr free_realms: 648178825Sdfr for(i = 0; i < num_realms; i++) 649178825Sdfr free(realms[i]); 650178825Sdfr free(realms); 651178825Sdfr return ret; 652178825Sdfr} 653178825Sdfr 654178825Sdfr 655178825Sdfrstatic krb5_error_code 656178825Sdfrtgs_make_reply(krb5_context context, 657178825Sdfr krb5_kdc_configuration *config, 658178825Sdfr KDC_REQ_BODY *b, 659178825Sdfr krb5_const_principal tgt_name, 660178825Sdfr const EncTicketPart *tgt, 661178825Sdfr const EncryptionKey *serverkey, 662178825Sdfr const krb5_keyblock *sessionkey, 663178825Sdfr krb5_kvno kvno, 664178825Sdfr AuthorizationData *auth_data, 665178825Sdfr hdb_entry_ex *server, 666178825Sdfr const char *server_name, 667178825Sdfr hdb_entry_ex *client, 668178825Sdfr krb5_principal client_principal, 669178825Sdfr hdb_entry_ex *krbtgt, 670178825Sdfr krb5_enctype krbtgt_etype, 671178825Sdfr KRB5SignedPathPrincipals *spp, 672178825Sdfr const krb5_data *rspac, 673178825Sdfr const char **e_text, 674178825Sdfr krb5_data *reply) 675178825Sdfr{ 676178825Sdfr KDC_REP rep; 677178825Sdfr EncKDCRepPart ek; 678178825Sdfr EncTicketPart et; 679178825Sdfr KDCOptions f = b->kdc_options; 680178825Sdfr krb5_error_code ret; 681178825Sdfr 682178825Sdfr memset(&rep, 0, sizeof(rep)); 683178825Sdfr memset(&et, 0, sizeof(et)); 684178825Sdfr memset(&ek, 0, sizeof(ek)); 685178825Sdfr 686178825Sdfr rep.pvno = 5; 687178825Sdfr rep.msg_type = krb_tgs_rep; 688178825Sdfr 689178825Sdfr et.authtime = tgt->authtime; 690178825Sdfr _kdc_fix_time(&b->till); 691178825Sdfr et.endtime = min(tgt->endtime, *b->till); 692178825Sdfr ALLOC(et.starttime); 693178825Sdfr *et.starttime = kdc_time; 694178825Sdfr 695178825Sdfr ret = check_tgs_flags(context, config, b, tgt, &et); 696178825Sdfr if(ret) 697178825Sdfr goto out; 698178825Sdfr 699178825Sdfr /* We should check the transited encoding if: 700178825Sdfr 1) the request doesn't ask not to be checked 701178825Sdfr 2) globally enforcing a check 702178825Sdfr 3) principal requires checking 703178825Sdfr 4) we allow non-check per-principal, but principal isn't marked as allowing this 704178825Sdfr 5) we don't globally allow this 705178825Sdfr */ 706178825Sdfr 707178825Sdfr#define GLOBAL_FORCE_TRANSITED_CHECK \ 708178825Sdfr (config->trpolicy == TRPOLICY_ALWAYS_CHECK) 709178825Sdfr#define GLOBAL_ALLOW_PER_PRINCIPAL \ 710178825Sdfr (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) 711178825Sdfr#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \ 712178825Sdfr (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) 713178825Sdfr 714178825Sdfr/* these will consult the database in future release */ 715178825Sdfr#define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0 716178825Sdfr#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0 717178825Sdfr 718178825Sdfr ret = fix_transited_encoding(context, config, 719178825Sdfr !f.disable_transited_check || 720178825Sdfr GLOBAL_FORCE_TRANSITED_CHECK || 721178825Sdfr PRINCIPAL_FORCE_TRANSITED_CHECK(server) || 722178825Sdfr !((GLOBAL_ALLOW_PER_PRINCIPAL && 723178825Sdfr PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || 724178825Sdfr GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), 725178825Sdfr &tgt->transited, &et, 726178825Sdfr *krb5_princ_realm(context, client_principal), 727178825Sdfr *krb5_princ_realm(context, server->entry.principal), 728178825Sdfr *krb5_princ_realm(context, krbtgt->entry.principal)); 729178825Sdfr if(ret) 730178825Sdfr goto out; 731178825Sdfr 732178825Sdfr copy_Realm(krb5_princ_realm(context, server->entry.principal), 733178825Sdfr &rep.ticket.realm); 734178825Sdfr _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal); 735178825Sdfr copy_Realm(&tgt_name->realm, &rep.crealm); 736178825Sdfr/* 737178825Sdfr if (f.request_anonymous) 738178825Sdfr _kdc_make_anonymous_principalname (&rep.cname); 739178825Sdfr else */ 740178825Sdfr 741178825Sdfr copy_PrincipalName(&tgt_name->name, &rep.cname); 742178825Sdfr rep.ticket.tkt_vno = 5; 743178825Sdfr 744178825Sdfr ek.caddr = et.caddr; 745178825Sdfr if(et.caddr == NULL) 746178825Sdfr et.caddr = tgt->caddr; 747178825Sdfr 748178825Sdfr { 749178825Sdfr time_t life; 750178825Sdfr life = et.endtime - *et.starttime; 751178825Sdfr if(client && client->entry.max_life) 752178825Sdfr life = min(life, *client->entry.max_life); 753178825Sdfr if(server->entry.max_life) 754178825Sdfr life = min(life, *server->entry.max_life); 755178825Sdfr et.endtime = *et.starttime + life; 756178825Sdfr } 757178825Sdfr if(f.renewable_ok && tgt->flags.renewable && 758178825Sdfr et.renew_till == NULL && et.endtime < *b->till){ 759178825Sdfr et.flags.renewable = 1; 760178825Sdfr ALLOC(et.renew_till); 761178825Sdfr *et.renew_till = *b->till; 762178825Sdfr } 763178825Sdfr if(et.renew_till){ 764178825Sdfr time_t renew; 765178825Sdfr renew = *et.renew_till - et.authtime; 766178825Sdfr if(client && client->entry.max_renew) 767178825Sdfr renew = min(renew, *client->entry.max_renew); 768178825Sdfr if(server->entry.max_renew) 769178825Sdfr renew = min(renew, *server->entry.max_renew); 770178825Sdfr *et.renew_till = et.authtime + renew; 771178825Sdfr } 772178825Sdfr 773178825Sdfr if(et.renew_till){ 774178825Sdfr *et.renew_till = min(*et.renew_till, *tgt->renew_till); 775178825Sdfr *et.starttime = min(*et.starttime, *et.renew_till); 776178825Sdfr et.endtime = min(et.endtime, *et.renew_till); 777178825Sdfr } 778178825Sdfr 779178825Sdfr *et.starttime = min(*et.starttime, et.endtime); 780178825Sdfr 781178825Sdfr if(*et.starttime == et.endtime){ 782178825Sdfr ret = KRB5KDC_ERR_NEVER_VALID; 783178825Sdfr goto out; 784178825Sdfr } 785178825Sdfr if(et.renew_till && et.endtime == *et.renew_till){ 786178825Sdfr free(et.renew_till); 787178825Sdfr et.renew_till = NULL; 788178825Sdfr et.flags.renewable = 0; 789178825Sdfr } 790178825Sdfr 791178825Sdfr et.flags.pre_authent = tgt->flags.pre_authent; 792178825Sdfr et.flags.hw_authent = tgt->flags.hw_authent; 793178825Sdfr et.flags.anonymous = tgt->flags.anonymous; 794178825Sdfr et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate; 795178825Sdfr 796178825Sdfr if (auth_data) { 797178825Sdfr /* XXX Check enc-authorization-data */ 798178825Sdfr et.authorization_data = calloc(1, sizeof(*et.authorization_data)); 799178825Sdfr if (et.authorization_data == NULL) { 800178825Sdfr ret = ENOMEM; 801178825Sdfr goto out; 802178825Sdfr } 803178825Sdfr ret = copy_AuthorizationData(auth_data, et.authorization_data); 804178825Sdfr if (ret) 805178825Sdfr goto out; 806178825Sdfr 807178825Sdfr /* Filter out type KRB5SignedPath */ 808178825Sdfr ret = find_KRB5SignedPath(context, et.authorization_data, NULL); 809178825Sdfr if (ret == 0) { 810178825Sdfr if (et.authorization_data->len == 1) { 811178825Sdfr free_AuthorizationData(et.authorization_data); 812178825Sdfr free(et.authorization_data); 813178825Sdfr et.authorization_data = NULL; 814178825Sdfr } else { 815178825Sdfr AuthorizationData *ad = et.authorization_data; 816178825Sdfr free_AuthorizationDataElement(&ad->val[ad->len - 1]); 817178825Sdfr ad->len--; 818178825Sdfr } 819178825Sdfr } 820178825Sdfr } 821178825Sdfr 822178825Sdfr if(rspac->length) { 823178825Sdfr /* 824178825Sdfr * No not need to filter out the any PAC from the 825178825Sdfr * auth_data since it's signed by the KDC. 826178825Sdfr */ 827178825Sdfr ret = _kdc_tkt_add_if_relevant_ad(context, &et, 828178825Sdfr KRB5_AUTHDATA_WIN2K_PAC, 829178825Sdfr rspac); 830178825Sdfr if (ret) 831178825Sdfr goto out; 832178825Sdfr } 833178825Sdfr 834178825Sdfr ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); 835178825Sdfr if (ret) 836178825Sdfr goto out; 837178825Sdfr et.crealm = tgt->crealm; 838178825Sdfr et.cname = tgt_name->name; 839178825Sdfr 840178825Sdfr ek.key = et.key; 841178825Sdfr /* MIT must have at least one last_req */ 842178825Sdfr ek.last_req.len = 1; 843178825Sdfr ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); 844178825Sdfr if (ek.last_req.val == NULL) { 845178825Sdfr ret = ENOMEM; 846178825Sdfr goto out; 847178825Sdfr } 848178825Sdfr ek.nonce = b->nonce; 849178825Sdfr ek.flags = et.flags; 850178825Sdfr ek.authtime = et.authtime; 851178825Sdfr ek.starttime = et.starttime; 852178825Sdfr ek.endtime = et.endtime; 853178825Sdfr ek.renew_till = et.renew_till; 854178825Sdfr ek.srealm = rep.ticket.realm; 855178825Sdfr ek.sname = rep.ticket.sname; 856178825Sdfr 857178825Sdfr _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 858178825Sdfr et.endtime, et.renew_till); 859178825Sdfr 860178825Sdfr /* Don't sign cross realm tickets, they can't be checked anyway */ 861178825Sdfr { 862178825Sdfr char *r = get_krbtgt_realm(&ek.sname); 863178825Sdfr 864178825Sdfr if (r == NULL || strcmp(r, ek.srealm) == 0) { 865178825Sdfr ret = _kdc_add_KRB5SignedPath(context, 866178825Sdfr config, 867178825Sdfr krbtgt, 868178825Sdfr krbtgt_etype, 869178825Sdfr NULL, 870178825Sdfr spp, 871178825Sdfr &et); 872178825Sdfr if (ret) 873178825Sdfr goto out; 874178825Sdfr } 875178825Sdfr } 876178825Sdfr 877178825Sdfr /* It is somewhat unclear where the etype in the following 878178825Sdfr encryption should come from. What we have is a session 879178825Sdfr key in the passed tgt, and a list of preferred etypes 880178825Sdfr *for the new ticket*. Should we pick the best possible 881178825Sdfr etype, given the keytype in the tgt, or should we look 882178825Sdfr at the etype list here as well? What if the tgt 883178825Sdfr session key is DES3 and we want a ticket with a (say) 884178825Sdfr CAST session key. Should the DES3 etype be added to the 885178825Sdfr etype list, even if we don't want a session key with 886178825Sdfr DES3? */ 887178825Sdfr ret = _kdc_encode_reply(context, config, 888178825Sdfr &rep, &et, &ek, et.key.keytype, 889178825Sdfr kvno, 890178825Sdfr serverkey, 0, &tgt->key, e_text, reply); 891178825Sdfrout: 892178825Sdfr free_TGS_REP(&rep); 893178825Sdfr free_TransitedEncoding(&et.transited); 894178825Sdfr if(et.starttime) 895178825Sdfr free(et.starttime); 896178825Sdfr if(et.renew_till) 897178825Sdfr free(et.renew_till); 898178825Sdfr if(et.authorization_data) { 899178825Sdfr free_AuthorizationData(et.authorization_data); 900178825Sdfr free(et.authorization_data); 901178825Sdfr } 902178825Sdfr free_LastReq(&ek.last_req); 903178825Sdfr memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); 904178825Sdfr free_EncryptionKey(&et.key); 905178825Sdfr return ret; 906178825Sdfr} 907178825Sdfr 908178825Sdfrstatic krb5_error_code 909178825Sdfrtgs_check_authenticator(krb5_context context, 910178825Sdfr krb5_kdc_configuration *config, 911178825Sdfr krb5_auth_context ac, 912178825Sdfr KDC_REQ_BODY *b, 913178825Sdfr const char **e_text, 914178825Sdfr krb5_keyblock *key) 915178825Sdfr{ 916178825Sdfr krb5_authenticator auth; 917178825Sdfr size_t len; 918178825Sdfr unsigned char *buf; 919178825Sdfr size_t buf_size; 920178825Sdfr krb5_error_code ret; 921178825Sdfr krb5_crypto crypto; 922178825Sdfr 923178825Sdfr krb5_auth_con_getauthenticator(context, ac, &auth); 924178825Sdfr if(auth->cksum == NULL){ 925178825Sdfr kdc_log(context, config, 0, "No authenticator in request"); 926178825Sdfr ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 927178825Sdfr goto out; 928178825Sdfr } 929178825Sdfr /* 930178825Sdfr * according to RFC1510 it doesn't need to be keyed, 931178825Sdfr * but according to the latest draft it needs to. 932178825Sdfr */ 933178825Sdfr if ( 934178825Sdfr#if 0 935178825Sdfr!krb5_checksum_is_keyed(context, auth->cksum->cksumtype) 936178825Sdfr || 937178825Sdfr#endif 938178825Sdfr !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) { 939178825Sdfr kdc_log(context, config, 0, "Bad checksum type in authenticator: %d", 940178825Sdfr auth->cksum->cksumtype); 941178825Sdfr ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 942178825Sdfr goto out; 943178825Sdfr } 944178825Sdfr 945178825Sdfr /* XXX should not re-encode this */ 946178825Sdfr ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret); 947178825Sdfr if(ret){ 948178825Sdfr kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", 949178825Sdfr krb5_get_err_text(context, ret)); 950178825Sdfr goto out; 951178825Sdfr } 952178825Sdfr if(buf_size != len) { 953178825Sdfr free(buf); 954178825Sdfr kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); 955178825Sdfr *e_text = "KDC internal error"; 956178825Sdfr ret = KRB5KRB_ERR_GENERIC; 957178825Sdfr goto out; 958178825Sdfr } 959178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 960178825Sdfr if (ret) { 961178825Sdfr free(buf); 962178825Sdfr kdc_log(context, config, 0, "krb5_crypto_init failed: %s", 963178825Sdfr krb5_get_err_text(context, ret)); 964178825Sdfr goto out; 965178825Sdfr } 966178825Sdfr ret = krb5_verify_checksum(context, 967178825Sdfr crypto, 968178825Sdfr KRB5_KU_TGS_REQ_AUTH_CKSUM, 969178825Sdfr buf, 970178825Sdfr len, 971178825Sdfr auth->cksum); 972178825Sdfr free(buf); 973178825Sdfr krb5_crypto_destroy(context, crypto); 974178825Sdfr if(ret){ 975178825Sdfr kdc_log(context, config, 0, 976178825Sdfr "Failed to verify authenticator checksum: %s", 977178825Sdfr krb5_get_err_text(context, ret)); 978178825Sdfr } 979178825Sdfrout: 980178825Sdfr free_Authenticator(auth); 981178825Sdfr free(auth); 982178825Sdfr return ret; 983178825Sdfr} 984178825Sdfr 985178825Sdfr/* 986178825Sdfr * 987178825Sdfr */ 988178825Sdfr 989178825Sdfrstatic const char * 990178825Sdfrfind_rpath(krb5_context context, Realm crealm, Realm srealm) 991178825Sdfr{ 992178825Sdfr const char *new_realm = krb5_config_get_string(context, 993178825Sdfr NULL, 994178825Sdfr "capaths", 995178825Sdfr crealm, 996178825Sdfr srealm, 997178825Sdfr NULL); 998178825Sdfr return new_realm; 999178825Sdfr} 1000178825Sdfr 1001178825Sdfr 1002178825Sdfrstatic krb5_boolean 1003178825Sdfrneed_referral(krb5_context context, krb5_principal server, krb5_realm **realms) 1004178825Sdfr{ 1005178825Sdfr if(server->name.name_type != KRB5_NT_SRV_INST || 1006178825Sdfr server->name.name_string.len != 2) 1007178825Sdfr return FALSE; 1008178825Sdfr 1009178825Sdfr return _krb5_get_host_realm_int(context, server->name.name_string.val[1], 1010178825Sdfr FALSE, realms) == 0; 1011178825Sdfr} 1012178825Sdfr 1013178825Sdfrstatic krb5_error_code 1014178825Sdfrtgs_parse_request(krb5_context context, 1015178825Sdfr krb5_kdc_configuration *config, 1016178825Sdfr KDC_REQ_BODY *b, 1017178825Sdfr const PA_DATA *tgs_req, 1018178825Sdfr hdb_entry_ex **krbtgt, 1019178825Sdfr krb5_enctype *krbtgt_etype, 1020178825Sdfr krb5_ticket **ticket, 1021178825Sdfr const char **e_text, 1022178825Sdfr const char *from, 1023178825Sdfr const struct sockaddr *from_addr, 1024178825Sdfr time_t **csec, 1025178825Sdfr int **cusec, 1026178825Sdfr AuthorizationData **auth_data) 1027178825Sdfr{ 1028178825Sdfr krb5_ap_req ap_req; 1029178825Sdfr krb5_error_code ret; 1030178825Sdfr krb5_principal princ; 1031178825Sdfr krb5_auth_context ac = NULL; 1032178825Sdfr krb5_flags ap_req_options; 1033178825Sdfr krb5_flags verify_ap_req_flags; 1034178825Sdfr krb5_crypto crypto; 1035178825Sdfr Key *tkey; 1036178825Sdfr 1037178825Sdfr *auth_data = NULL; 1038178825Sdfr *csec = NULL; 1039178825Sdfr *cusec = NULL; 1040178825Sdfr 1041178825Sdfr memset(&ap_req, 0, sizeof(ap_req)); 1042178825Sdfr ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req); 1043178825Sdfr if(ret){ 1044178825Sdfr kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", 1045178825Sdfr krb5_get_err_text(context, ret)); 1046178825Sdfr goto out; 1047178825Sdfr } 1048178825Sdfr 1049178825Sdfr if(!get_krbtgt_realm(&ap_req.ticket.sname)){ 1050178825Sdfr /* XXX check for ticket.sname == req.sname */ 1051178825Sdfr kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket"); 1052178825Sdfr ret = KRB5KDC_ERR_POLICY; /* ? */ 1053178825Sdfr goto out; 1054178825Sdfr } 1055178825Sdfr 1056178825Sdfr _krb5_principalname2krb5_principal(context, 1057178825Sdfr &princ, 1058178825Sdfr ap_req.ticket.sname, 1059178825Sdfr ap_req.ticket.realm); 1060178825Sdfr 1061178825Sdfr ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt); 1062178825Sdfr 1063178825Sdfr if(ret) { 1064178825Sdfr char *p; 1065178825Sdfr ret = krb5_unparse_name(context, princ, &p); 1066178825Sdfr if (ret != 0) 1067178825Sdfr p = "<unparse_name failed>"; 1068178825Sdfr krb5_free_principal(context, princ); 1069178825Sdfr kdc_log(context, config, 0, 1070178825Sdfr "Ticket-granting ticket not found in database: %s: %s", 1071178825Sdfr p, krb5_get_err_text(context, ret)); 1072178825Sdfr if (ret == 0) 1073178825Sdfr free(p); 1074178825Sdfr ret = KRB5KRB_AP_ERR_NOT_US; 1075178825Sdfr goto out; 1076178825Sdfr } 1077178825Sdfr 1078178825Sdfr if(ap_req.ticket.enc_part.kvno && 1079178825Sdfr *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){ 1080178825Sdfr char *p; 1081178825Sdfr 1082178825Sdfr ret = krb5_unparse_name (context, princ, &p); 1083178825Sdfr krb5_free_principal(context, princ); 1084178825Sdfr if (ret != 0) 1085178825Sdfr p = "<unparse_name failed>"; 1086178825Sdfr kdc_log(context, config, 0, 1087178825Sdfr "Ticket kvno = %d, DB kvno = %d (%s)", 1088178825Sdfr *ap_req.ticket.enc_part.kvno, 1089178825Sdfr (*krbtgt)->entry.kvno, 1090178825Sdfr p); 1091178825Sdfr if (ret == 0) 1092178825Sdfr free (p); 1093178825Sdfr ret = KRB5KRB_AP_ERR_BADKEYVER; 1094178825Sdfr goto out; 1095178825Sdfr } 1096178825Sdfr 1097178825Sdfr *krbtgt_etype = ap_req.ticket.enc_part.etype; 1098178825Sdfr 1099178825Sdfr ret = hdb_enctype2key(context, &(*krbtgt)->entry, 1100178825Sdfr ap_req.ticket.enc_part.etype, &tkey); 1101178825Sdfr if(ret){ 1102178825Sdfr char *str = NULL, *p = NULL; 1103178825Sdfr 1104178825Sdfr krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str); 1105178825Sdfr krb5_unparse_name(context, princ, &p); 1106178825Sdfr kdc_log(context, config, 0, 1107178825Sdfr "No server key with enctype %s found for %s", 1108178825Sdfr str ? str : "<unknown enctype>", 1109178825Sdfr p ? p : "<unparse_name failed>"); 1110178825Sdfr free(str); 1111178825Sdfr free(p); 1112178825Sdfr ret = KRB5KRB_AP_ERR_BADKEYVER; 1113178825Sdfr goto out; 1114178825Sdfr } 1115178825Sdfr 1116178825Sdfr if (b->kdc_options.validate) 1117178825Sdfr verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; 1118178825Sdfr else 1119178825Sdfr verify_ap_req_flags = 0; 1120178825Sdfr 1121178825Sdfr ret = krb5_verify_ap_req2(context, 1122178825Sdfr &ac, 1123178825Sdfr &ap_req, 1124178825Sdfr princ, 1125178825Sdfr &tkey->key, 1126178825Sdfr verify_ap_req_flags, 1127178825Sdfr &ap_req_options, 1128178825Sdfr ticket, 1129178825Sdfr KRB5_KU_TGS_REQ_AUTH); 1130178825Sdfr 1131178825Sdfr krb5_free_principal(context, princ); 1132178825Sdfr if(ret) { 1133178825Sdfr kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", 1134178825Sdfr krb5_get_err_text(context, ret)); 1135178825Sdfr goto out; 1136178825Sdfr } 1137178825Sdfr 1138178825Sdfr { 1139178825Sdfr krb5_authenticator auth; 1140178825Sdfr 1141178825Sdfr ret = krb5_auth_con_getauthenticator(context, ac, &auth); 1142178825Sdfr if (ret == 0) { 1143178825Sdfr *csec = malloc(sizeof(**csec)); 1144178825Sdfr if (*csec == NULL) { 1145178825Sdfr krb5_free_authenticator(context, &auth); 1146178825Sdfr kdc_log(context, config, 0, "malloc failed"); 1147178825Sdfr goto out; 1148178825Sdfr } 1149178825Sdfr **csec = auth->ctime; 1150178825Sdfr *cusec = malloc(sizeof(**cusec)); 1151178825Sdfr if (*cusec == NULL) { 1152178825Sdfr krb5_free_authenticator(context, &auth); 1153178825Sdfr kdc_log(context, config, 0, "malloc failed"); 1154178825Sdfr goto out; 1155178825Sdfr } 1156178825Sdfr **cusec = auth->cusec; 1157178825Sdfr krb5_free_authenticator(context, &auth); 1158178825Sdfr } 1159178825Sdfr } 1160178825Sdfr 1161178825Sdfr ret = tgs_check_authenticator(context, config, 1162178825Sdfr ac, b, e_text, &(*ticket)->ticket.key); 1163178825Sdfr if (ret) { 1164178825Sdfr krb5_auth_con_free(context, ac); 1165178825Sdfr goto out; 1166178825Sdfr } 1167178825Sdfr 1168178825Sdfr if (b->enc_authorization_data) { 1169178825Sdfr unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; 1170178825Sdfr krb5_keyblock *subkey; 1171178825Sdfr krb5_data ad; 1172178825Sdfr 1173178825Sdfr ret = krb5_auth_con_getremotesubkey(context, 1174178825Sdfr ac, 1175178825Sdfr &subkey); 1176178825Sdfr if(ret){ 1177178825Sdfr krb5_auth_con_free(context, ac); 1178178825Sdfr kdc_log(context, config, 0, "Failed to get remote subkey: %s", 1179178825Sdfr krb5_get_err_text(context, ret)); 1180178825Sdfr goto out; 1181178825Sdfr } 1182178825Sdfr if(subkey == NULL){ 1183178825Sdfr usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; 1184178825Sdfr ret = krb5_auth_con_getkey(context, ac, &subkey); 1185178825Sdfr if(ret) { 1186178825Sdfr krb5_auth_con_free(context, ac); 1187178825Sdfr kdc_log(context, config, 0, "Failed to get session key: %s", 1188178825Sdfr krb5_get_err_text(context, ret)); 1189178825Sdfr goto out; 1190178825Sdfr } 1191178825Sdfr } 1192178825Sdfr if(subkey == NULL){ 1193178825Sdfr krb5_auth_con_free(context, ac); 1194178825Sdfr kdc_log(context, config, 0, 1195178825Sdfr "Failed to get key for enc-authorization-data"); 1196178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1197178825Sdfr goto out; 1198178825Sdfr } 1199178825Sdfr ret = krb5_crypto_init(context, subkey, 0, &crypto); 1200178825Sdfr if (ret) { 1201178825Sdfr krb5_auth_con_free(context, ac); 1202178825Sdfr kdc_log(context, config, 0, "krb5_crypto_init failed: %s", 1203178825Sdfr krb5_get_err_text(context, ret)); 1204178825Sdfr goto out; 1205178825Sdfr } 1206178825Sdfr ret = krb5_decrypt_EncryptedData (context, 1207178825Sdfr crypto, 1208178825Sdfr usage, 1209178825Sdfr b->enc_authorization_data, 1210178825Sdfr &ad); 1211178825Sdfr krb5_crypto_destroy(context, crypto); 1212178825Sdfr if(ret){ 1213178825Sdfr krb5_auth_con_free(context, ac); 1214178825Sdfr kdc_log(context, config, 0, 1215178825Sdfr "Failed to decrypt enc-authorization-data"); 1216178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1217178825Sdfr goto out; 1218178825Sdfr } 1219178825Sdfr krb5_free_keyblock(context, subkey); 1220178825Sdfr ALLOC(*auth_data); 1221178825Sdfr if (*auth_data == NULL) { 1222178825Sdfr krb5_auth_con_free(context, ac); 1223178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1224178825Sdfr goto out; 1225178825Sdfr } 1226178825Sdfr ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL); 1227178825Sdfr if(ret){ 1228178825Sdfr krb5_auth_con_free(context, ac); 1229178825Sdfr free(*auth_data); 1230178825Sdfr *auth_data = NULL; 1231178825Sdfr kdc_log(context, config, 0, "Failed to decode authorization data"); 1232178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1233178825Sdfr goto out; 1234178825Sdfr } 1235178825Sdfr } 1236178825Sdfr 1237178825Sdfr krb5_auth_con_free(context, ac); 1238178825Sdfr 1239178825Sdfrout: 1240178825Sdfr free_AP_REQ(&ap_req); 1241178825Sdfr 1242178825Sdfr return ret; 1243178825Sdfr} 1244178825Sdfr 1245178825Sdfrstatic krb5_error_code 1246178825Sdfrtgs_build_reply(krb5_context context, 1247178825Sdfr krb5_kdc_configuration *config, 1248178825Sdfr KDC_REQ *req, 1249178825Sdfr KDC_REQ_BODY *b, 1250178825Sdfr hdb_entry_ex *krbtgt, 1251178825Sdfr krb5_enctype krbtgt_etype, 1252178825Sdfr krb5_ticket *ticket, 1253178825Sdfr krb5_data *reply, 1254178825Sdfr const char *from, 1255178825Sdfr const char **e_text, 1256178825Sdfr AuthorizationData *auth_data, 1257178825Sdfr const struct sockaddr *from_addr, 1258178825Sdfr int datagram_reply) 1259178825Sdfr{ 1260178825Sdfr krb5_error_code ret; 1261178825Sdfr krb5_principal cp = NULL, sp = NULL; 1262178825Sdfr krb5_principal client_principal = NULL; 1263178825Sdfr char *spn = NULL, *cpn = NULL; 1264178825Sdfr hdb_entry_ex *server = NULL, *client = NULL; 1265178825Sdfr EncTicketPart *tgt = &ticket->ticket; 1266178825Sdfr KRB5SignedPathPrincipals *spp = NULL; 1267178825Sdfr const EncryptionKey *ekey; 1268178825Sdfr krb5_keyblock sessionkey; 1269178825Sdfr krb5_kvno kvno; 1270178825Sdfr krb5_data rspac; 1271178825Sdfr int cross_realm = 0; 1272178825Sdfr 1273178825Sdfr PrincipalName *s; 1274178825Sdfr Realm r; 1275178825Sdfr int nloop = 0; 1276178825Sdfr EncTicketPart adtkt; 1277178825Sdfr char opt_str[128]; 1278178825Sdfr int require_signedpath = 0; 1279178825Sdfr 1280178825Sdfr memset(&sessionkey, 0, sizeof(sessionkey)); 1281178825Sdfr memset(&adtkt, 0, sizeof(adtkt)); 1282178825Sdfr krb5_data_zero(&rspac); 1283178825Sdfr 1284178825Sdfr s = b->sname; 1285178825Sdfr r = b->realm; 1286178825Sdfr 1287178825Sdfr if(b->kdc_options.enc_tkt_in_skey){ 1288178825Sdfr Ticket *t; 1289178825Sdfr hdb_entry_ex *uu; 1290178825Sdfr krb5_principal p; 1291178825Sdfr Key *uukey; 1292178825Sdfr 1293178825Sdfr if(b->additional_tickets == NULL || 1294178825Sdfr b->additional_tickets->len == 0){ 1295178825Sdfr ret = KRB5KDC_ERR_BADOPTION; /* ? */ 1296178825Sdfr kdc_log(context, config, 0, 1297178825Sdfr "No second ticket present in request"); 1298178825Sdfr goto out; 1299178825Sdfr } 1300178825Sdfr t = &b->additional_tickets->val[0]; 1301178825Sdfr if(!get_krbtgt_realm(&t->sname)){ 1302178825Sdfr kdc_log(context, config, 0, 1303178825Sdfr "Additional ticket is not a ticket-granting ticket"); 1304178825Sdfr ret = KRB5KDC_ERR_POLICY; 1305178825Sdfr goto out; 1306178825Sdfr } 1307178825Sdfr _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); 1308178825Sdfr ret = _kdc_db_fetch(context, config, p, 1309178825Sdfr HDB_F_GET_CLIENT|HDB_F_GET_SERVER, 1310178825Sdfr NULL, &uu); 1311178825Sdfr krb5_free_principal(context, p); 1312178825Sdfr if(ret){ 1313178825Sdfr if (ret == HDB_ERR_NOENTRY) 1314178825Sdfr ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1315178825Sdfr goto out; 1316178825Sdfr } 1317178825Sdfr ret = hdb_enctype2key(context, &uu->entry, 1318178825Sdfr t->enc_part.etype, &uukey); 1319178825Sdfr if(ret){ 1320178825Sdfr _kdc_free_ent(context, uu); 1321178825Sdfr ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1322178825Sdfr goto out; 1323178825Sdfr } 1324178825Sdfr ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0); 1325178825Sdfr _kdc_free_ent(context, uu); 1326178825Sdfr if(ret) 1327178825Sdfr goto out; 1328178825Sdfr 1329178825Sdfr ret = verify_flags(context, config, &adtkt, spn); 1330178825Sdfr if (ret) 1331178825Sdfr goto out; 1332178825Sdfr 1333178825Sdfr s = &adtkt.cname; 1334178825Sdfr r = adtkt.crealm; 1335178825Sdfr } 1336178825Sdfr 1337178825Sdfr _krb5_principalname2krb5_principal(context, &sp, *s, r); 1338178825Sdfr ret = krb5_unparse_name(context, sp, &spn); 1339178825Sdfr if (ret) 1340178825Sdfr goto out; 1341178825Sdfr _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); 1342178825Sdfr ret = krb5_unparse_name(context, cp, &cpn); 1343178825Sdfr if (ret) 1344178825Sdfr goto out; 1345178825Sdfr unparse_flags (KDCOptions2int(b->kdc_options), 1346178825Sdfr asn1_KDCOptions_units(), 1347178825Sdfr opt_str, sizeof(opt_str)); 1348178825Sdfr if(*opt_str) 1349178825Sdfr kdc_log(context, config, 0, 1350178825Sdfr "TGS-REQ %s from %s for %s [%s]", 1351178825Sdfr cpn, from, spn, opt_str); 1352178825Sdfr else 1353178825Sdfr kdc_log(context, config, 0, 1354178825Sdfr "TGS-REQ %s from %s for %s", cpn, from, spn); 1355178825Sdfr 1356178825Sdfr /* 1357178825Sdfr * Fetch server 1358178825Sdfr */ 1359178825Sdfr 1360178825Sdfrserver_lookup: 1361178825Sdfr ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server); 1362178825Sdfr 1363178825Sdfr if(ret){ 1364178825Sdfr const char *new_rlm; 1365178825Sdfr Realm req_rlm; 1366178825Sdfr krb5_realm *realms; 1367178825Sdfr 1368178825Sdfr if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) { 1369178825Sdfr if(nloop++ < 2) { 1370178825Sdfr new_rlm = find_rpath(context, tgt->crealm, req_rlm); 1371178825Sdfr if(new_rlm) { 1372178825Sdfr kdc_log(context, config, 5, "krbtgt for realm %s " 1373178825Sdfr "not found, trying %s", 1374178825Sdfr req_rlm, new_rlm); 1375178825Sdfr krb5_free_principal(context, sp); 1376178825Sdfr free(spn); 1377178825Sdfr krb5_make_principal(context, &sp, r, 1378178825Sdfr KRB5_TGS_NAME, new_rlm, NULL); 1379178825Sdfr ret = krb5_unparse_name(context, sp, &spn); 1380178825Sdfr if (ret) 1381178825Sdfr goto out; 1382178825Sdfr auth_data = NULL; /* ms don't handle AD in referals */ 1383178825Sdfr goto server_lookup; 1384178825Sdfr } 1385178825Sdfr } 1386178825Sdfr } else if(need_referral(context, sp, &realms)) { 1387178825Sdfr if (strcmp(realms[0], sp->realm) != 0) { 1388178825Sdfr kdc_log(context, config, 5, 1389178825Sdfr "Returning a referral to realm %s for " 1390178825Sdfr "server %s that was not found", 1391178825Sdfr realms[0], spn); 1392178825Sdfr krb5_free_principal(context, sp); 1393178825Sdfr free(spn); 1394178825Sdfr krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, 1395178825Sdfr realms[0], NULL); 1396178825Sdfr ret = krb5_unparse_name(context, sp, &spn); 1397178825Sdfr if (ret) 1398178825Sdfr goto out; 1399178825Sdfr krb5_free_host_realm(context, realms); 1400178825Sdfr auth_data = NULL; /* ms don't handle AD in referals */ 1401178825Sdfr goto server_lookup; 1402178825Sdfr } 1403178825Sdfr krb5_free_host_realm(context, realms); 1404178825Sdfr } 1405178825Sdfr kdc_log(context, config, 0, 1406178825Sdfr "Server not found in database: %s: %s", spn, 1407178825Sdfr krb5_get_err_text(context, ret)); 1408178825Sdfr if (ret == HDB_ERR_NOENTRY) 1409178825Sdfr ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1410178825Sdfr goto out; 1411178825Sdfr } 1412178825Sdfr 1413178825Sdfr ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client); 1414178825Sdfr if(ret) { 1415178825Sdfr const char *krbtgt_realm; 1416178825Sdfr 1417178825Sdfr /* 1418178825Sdfr * If the client belongs to the same realm as our krbtgt, it 1419178825Sdfr * should exist in the local database. 1420178825Sdfr * 1421178825Sdfr */ 1422178825Sdfr 1423178825Sdfr krbtgt_realm = 1424178825Sdfr krb5_principal_get_comp_string(context, 1425178825Sdfr krbtgt->entry.principal, 1); 1426178825Sdfr 1427178825Sdfr if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { 1428178825Sdfr if (ret == HDB_ERR_NOENTRY) 1429178825Sdfr ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1430178825Sdfr kdc_log(context, config, 1, "Client no longer in database: %s", 1431178825Sdfr cpn); 1432178825Sdfr goto out; 1433178825Sdfr } 1434178825Sdfr 1435178825Sdfr kdc_log(context, config, 1, "Client not found in database: %s: %s", 1436178825Sdfr cpn, krb5_get_err_text(context, ret)); 1437178825Sdfr 1438178825Sdfr cross_realm = 1; 1439178825Sdfr } 1440178825Sdfr 1441178825Sdfr /* 1442178825Sdfr * Check that service is in the same realm as the krbtgt. If it's 1443178825Sdfr * not the same, it's someone that is using a uni-directional trust 1444178825Sdfr * backward. 1445178825Sdfr */ 1446178825Sdfr 1447178825Sdfr if (strcmp(krb5_principal_get_realm(context, sp), 1448178825Sdfr krb5_principal_get_comp_string(context, 1449178825Sdfr krbtgt->entry.principal, 1450178825Sdfr 1)) != 0) { 1451178825Sdfr char *tpn; 1452178825Sdfr ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn); 1453178825Sdfr kdc_log(context, config, 0, 1454178825Sdfr "Request with wrong krbtgt: %s", 1455178825Sdfr (ret == 0) ? tpn : "<unknown>"); 1456178825Sdfr if(ret == 0) 1457178825Sdfr free(tpn); 1458178825Sdfr ret = KRB5KRB_AP_ERR_NOT_US; 1459178825Sdfr goto out; 1460178825Sdfr } 1461178825Sdfr 1462178825Sdfr /* 1463178825Sdfr * 1464178825Sdfr */ 1465178825Sdfr 1466178825Sdfr client_principal = cp; 1467178825Sdfr 1468178825Sdfr if (client) { 1469178825Sdfr const PA_DATA *sdata; 1470178825Sdfr int i = 0; 1471178825Sdfr 1472178825Sdfr sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF); 1473178825Sdfr if (sdata) { 1474178825Sdfr krb5_crypto crypto; 1475178825Sdfr krb5_data datack; 1476178825Sdfr PA_S4U2Self self; 1477178825Sdfr char *selfcpn = NULL; 1478178825Sdfr const char *str; 1479178825Sdfr 1480178825Sdfr ret = decode_PA_S4U2Self(sdata->padata_value.data, 1481178825Sdfr sdata->padata_value.length, 1482178825Sdfr &self, NULL); 1483178825Sdfr if (ret) { 1484178825Sdfr kdc_log(context, config, 0, "Failed to decode PA-S4U2Self"); 1485178825Sdfr goto out; 1486178825Sdfr } 1487178825Sdfr 1488178825Sdfr ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); 1489178825Sdfr if (ret) 1490178825Sdfr goto out; 1491178825Sdfr 1492178825Sdfr ret = krb5_crypto_init(context, &tgt->key, 0, &crypto); 1493178825Sdfr if (ret) { 1494178825Sdfr free_PA_S4U2Self(&self); 1495178825Sdfr krb5_data_free(&datack); 1496178825Sdfr kdc_log(context, config, 0, "krb5_crypto_init failed: %s", 1497178825Sdfr krb5_get_err_text(context, ret)); 1498178825Sdfr goto out; 1499178825Sdfr } 1500178825Sdfr 1501178825Sdfr ret = krb5_verify_checksum(context, 1502178825Sdfr crypto, 1503178825Sdfr KRB5_KU_OTHER_CKSUM, 1504178825Sdfr datack.data, 1505178825Sdfr datack.length, 1506178825Sdfr &self.cksum); 1507178825Sdfr krb5_data_free(&datack); 1508178825Sdfr krb5_crypto_destroy(context, crypto); 1509178825Sdfr if (ret) { 1510178825Sdfr free_PA_S4U2Self(&self); 1511178825Sdfr kdc_log(context, config, 0, 1512178825Sdfr "krb5_verify_checksum failed for S4U2Self: %s", 1513178825Sdfr krb5_get_err_text(context, ret)); 1514178825Sdfr goto out; 1515178825Sdfr } 1516178825Sdfr 1517178825Sdfr ret = _krb5_principalname2krb5_principal(context, 1518178825Sdfr &client_principal, 1519178825Sdfr self.name, 1520178825Sdfr self.realm); 1521178825Sdfr free_PA_S4U2Self(&self); 1522178825Sdfr if (ret) 1523178825Sdfr goto out; 1524178825Sdfr 1525178825Sdfr ret = krb5_unparse_name(context, client_principal, &selfcpn); 1526178825Sdfr if (ret) 1527178825Sdfr goto out; 1528178825Sdfr 1529178825Sdfr /* 1530178825Sdfr * Check that service doing the impersonating is 1531178825Sdfr * requesting a ticket to it-self. 1532178825Sdfr */ 1533178825Sdfr if (krb5_principal_compare(context, cp, sp) != TRUE) { 1534178825Sdfr kdc_log(context, config, 0, "S4U2Self: %s is not allowed " 1535178825Sdfr "to impersonate some other user " 1536178825Sdfr "(tried for user %s to service %s)", 1537178825Sdfr cpn, selfcpn, spn); 1538178825Sdfr free(selfcpn); 1539178825Sdfr ret = KRB5KDC_ERR_BADOPTION; /* ? */ 1540178825Sdfr goto out; 1541178825Sdfr } 1542178825Sdfr 1543178825Sdfr /* 1544178825Sdfr * If the service isn't trusted for authentication to 1545178825Sdfr * delegation, remove the forward flag. 1546178825Sdfr */ 1547178825Sdfr 1548178825Sdfr if (client->entry.flags.trusted_for_delegation) { 1549178825Sdfr str = "[forwardable]"; 1550178825Sdfr } else { 1551178825Sdfr b->kdc_options.forwardable = 0; 1552178825Sdfr str = ""; 1553178825Sdfr } 1554178825Sdfr kdc_log(context, config, 0, "s4u2self %s impersonating %s to " 1555178825Sdfr "service %s %s", cpn, selfcpn, spn, str); 1556178825Sdfr free(selfcpn); 1557178825Sdfr } 1558178825Sdfr } 1559178825Sdfr 1560178825Sdfr /* 1561178825Sdfr * Constrained delegation 1562178825Sdfr */ 1563178825Sdfr 1564178825Sdfr if (client != NULL 1565178825Sdfr && b->additional_tickets != NULL 1566178825Sdfr && b->additional_tickets->len != 0 1567178825Sdfr && b->kdc_options.enc_tkt_in_skey == 0) 1568178825Sdfr { 1569178825Sdfr Key *clientkey; 1570178825Sdfr Ticket *t; 1571178825Sdfr char *str; 1572178825Sdfr 1573178825Sdfr t = &b->additional_tickets->val[0]; 1574178825Sdfr 1575178825Sdfr ret = hdb_enctype2key(context, &client->entry, 1576178825Sdfr t->enc_part.etype, &clientkey); 1577178825Sdfr if(ret){ 1578178825Sdfr ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1579178825Sdfr goto out; 1580178825Sdfr } 1581178825Sdfr 1582178825Sdfr ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0); 1583178825Sdfr if (ret) { 1584178825Sdfr kdc_log(context, config, 0, 1585178825Sdfr "failed to decrypt ticket for " 1586178825Sdfr "constrained delegation from %s to %s ", spn, cpn); 1587178825Sdfr goto out; 1588178825Sdfr } 1589178825Sdfr 1590178825Sdfr /* check that ticket is valid */ 1591178825Sdfr 1592178825Sdfr if (adtkt.flags.forwardable == 0) { 1593178825Sdfr kdc_log(context, config, 0, 1594178825Sdfr "Missing forwardable flag on ticket for " 1595178825Sdfr "constrained delegation from %s to %s ", spn, cpn); 1596178825Sdfr ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1597178825Sdfr goto out; 1598178825Sdfr } 1599178825Sdfr 1600178825Sdfr ret = check_constrained_delegation(context, config, client, sp); 1601178825Sdfr if (ret) { 1602178825Sdfr kdc_log(context, config, 0, 1603178825Sdfr "constrained delegation from %s to %s not allowed", 1604178825Sdfr spn, cpn); 1605178825Sdfr goto out; 1606178825Sdfr } 1607178825Sdfr 1608178825Sdfr ret = _krb5_principalname2krb5_principal(context, 1609178825Sdfr &client_principal, 1610178825Sdfr adtkt.cname, 1611178825Sdfr adtkt.crealm); 1612178825Sdfr if (ret) 1613178825Sdfr goto out; 1614178825Sdfr 1615178825Sdfr ret = krb5_unparse_name(context, client_principal, &str); 1616178825Sdfr if (ret) 1617178825Sdfr goto out; 1618178825Sdfr 1619178825Sdfr ret = verify_flags(context, config, &adtkt, str); 1620178825Sdfr if (ret) { 1621178825Sdfr free(str); 1622178825Sdfr goto out; 1623178825Sdfr } 1624178825Sdfr 1625178825Sdfr /* 1626178825Sdfr * Check KRB5SignedPath in authorization data and add new entry to 1627178825Sdfr * make sure servers can't fake a ticket to us. 1628178825Sdfr */ 1629178825Sdfr 1630178825Sdfr ret = check_KRB5SignedPath(context, 1631178825Sdfr config, 1632178825Sdfr krbtgt, 1633178825Sdfr &adtkt, 1634178825Sdfr &spp, 1635178825Sdfr 1); 1636178825Sdfr if (ret) { 1637178825Sdfr kdc_log(context, config, 0, 1638178825Sdfr "KRB5SignedPath check from service %s failed " 1639178825Sdfr "for delegation to %s for client %s " 1640178825Sdfr "from %s failed with %s", 1641178825Sdfr spn, str, cpn, from, krb5_get_err_text(context, ret)); 1642178825Sdfr free(str); 1643178825Sdfr goto out; 1644178825Sdfr } 1645178825Sdfr 1646178825Sdfr kdc_log(context, config, 0, "constrained delegation for %s " 1647178825Sdfr "from %s to %s", str, cpn, spn); 1648178825Sdfr free(str); 1649178825Sdfr 1650178825Sdfr /* 1651178825Sdfr * Also require that the KDC have issue the service's krbtgt 1652178825Sdfr * used to do the request. 1653178825Sdfr */ 1654178825Sdfr require_signedpath = 1; 1655178825Sdfr } 1656178825Sdfr 1657178825Sdfr /* 1658178825Sdfr * Check flags 1659178825Sdfr */ 1660178825Sdfr 1661178825Sdfr ret = _kdc_check_flags(context, config, 1662178825Sdfr client, cpn, 1663178825Sdfr server, spn, 1664178825Sdfr FALSE); 1665178825Sdfr if(ret) 1666178825Sdfr goto out; 1667178825Sdfr 1668178825Sdfr if((b->kdc_options.validate || b->kdc_options.renew) && 1669178825Sdfr !krb5_principal_compare(context, 1670178825Sdfr krbtgt->entry.principal, 1671178825Sdfr server->entry.principal)){ 1672178825Sdfr kdc_log(context, config, 0, "Inconsistent request."); 1673178825Sdfr ret = KRB5KDC_ERR_SERVER_NOMATCH; 1674178825Sdfr goto out; 1675178825Sdfr } 1676178825Sdfr 1677178825Sdfr /* check for valid set of addresses */ 1678178825Sdfr if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) { 1679178825Sdfr ret = KRB5KRB_AP_ERR_BADADDR; 1680178825Sdfr kdc_log(context, config, 0, "Request from wrong address"); 1681178825Sdfr goto out; 1682178825Sdfr } 1683178825Sdfr 1684178825Sdfr /* 1685178825Sdfr * Select enctype, return key and kvno. 1686178825Sdfr */ 1687178825Sdfr 1688178825Sdfr { 1689178825Sdfr krb5_enctype etype; 1690178825Sdfr 1691178825Sdfr if(b->kdc_options.enc_tkt_in_skey) { 1692178825Sdfr int i; 1693178825Sdfr ekey = &adtkt.key; 1694178825Sdfr for(i = 0; i < b->etype.len; i++) 1695178825Sdfr if (b->etype.val[i] == adtkt.key.keytype) 1696178825Sdfr break; 1697178825Sdfr if(i == b->etype.len) { 1698178825Sdfr krb5_clear_error_string(context); 1699178825Sdfr return KRB5KDC_ERR_ETYPE_NOSUPP; 1700178825Sdfr } 1701178825Sdfr etype = b->etype.val[i]; 1702178825Sdfr kvno = 0; 1703178825Sdfr } else { 1704178825Sdfr Key *skey; 1705178825Sdfr 1706178825Sdfr ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, 1707178825Sdfr &skey, &etype); 1708178825Sdfr if(ret) { 1709178825Sdfr kdc_log(context, config, 0, 1710178825Sdfr "Server (%s) has no support for etypes", spp); 1711178825Sdfr return ret; 1712178825Sdfr } 1713178825Sdfr ekey = &skey->key; 1714178825Sdfr kvno = server->entry.kvno; 1715178825Sdfr } 1716178825Sdfr 1717178825Sdfr ret = krb5_generate_random_keyblock(context, etype, &sessionkey); 1718178825Sdfr if (ret) 1719178825Sdfr goto out; 1720178825Sdfr } 1721178825Sdfr 1722178825Sdfr /* check PAC if not cross realm and if there is one */ 1723178825Sdfr if (!cross_realm) { 1724178825Sdfr Key *tkey; 1725178825Sdfr 1726178825Sdfr ret = hdb_enctype2key(context, &krbtgt->entry, 1727178825Sdfr krbtgt_etype, &tkey); 1728178825Sdfr if(ret) { 1729178825Sdfr kdc_log(context, config, 0, 1730178825Sdfr "Failed to find key for krbtgt PAC check"); 1731178825Sdfr goto out; 1732178825Sdfr } 1733178825Sdfr 1734178825Sdfr ret = check_PAC(context, config, client_principal, 1735178825Sdfr client, server, ekey, &tkey->key, 1736178825Sdfr tgt, &rspac, &require_signedpath); 1737178825Sdfr if (ret) { 1738178825Sdfr kdc_log(context, config, 0, 1739178825Sdfr "Verify PAC failed for %s (%s) from %s with %s", 1740178825Sdfr spn, cpn, from, krb5_get_err_text(context, ret)); 1741178825Sdfr goto out; 1742178825Sdfr } 1743178825Sdfr } 1744178825Sdfr 1745178825Sdfr /* also check the krbtgt for signature */ 1746178825Sdfr ret = check_KRB5SignedPath(context, 1747178825Sdfr config, 1748178825Sdfr krbtgt, 1749178825Sdfr tgt, 1750178825Sdfr &spp, 1751178825Sdfr require_signedpath); 1752178825Sdfr if (ret) { 1753178825Sdfr kdc_log(context, config, 0, 1754178825Sdfr "KRB5SignedPath check failed for %s (%s) from %s with %s", 1755178825Sdfr spn, cpn, from, krb5_get_err_text(context, ret)); 1756178825Sdfr goto out; 1757178825Sdfr } 1758178825Sdfr 1759178825Sdfr /* 1760178825Sdfr * 1761178825Sdfr */ 1762178825Sdfr 1763178825Sdfr ret = tgs_make_reply(context, 1764178825Sdfr config, 1765178825Sdfr b, 1766178825Sdfr client_principal, 1767178825Sdfr tgt, 1768178825Sdfr ekey, 1769178825Sdfr &sessionkey, 1770178825Sdfr kvno, 1771178825Sdfr auth_data, 1772178825Sdfr server, 1773178825Sdfr spn, 1774178825Sdfr client, 1775178825Sdfr cp, 1776178825Sdfr krbtgt, 1777178825Sdfr krbtgt_etype, 1778178825Sdfr spp, 1779178825Sdfr &rspac, 1780178825Sdfr e_text, 1781178825Sdfr reply); 1782178825Sdfr 1783178825Sdfrout: 1784178825Sdfr free(spn); 1785178825Sdfr free(cpn); 1786178825Sdfr 1787178825Sdfr krb5_data_free(&rspac); 1788178825Sdfr krb5_free_keyblock_contents(context, &sessionkey); 1789178825Sdfr if(server) 1790178825Sdfr _kdc_free_ent(context, server); 1791178825Sdfr if(client) 1792178825Sdfr _kdc_free_ent(context, client); 1793178825Sdfr 1794178825Sdfr if (client_principal && client_principal != cp) 1795178825Sdfr krb5_free_principal(context, client_principal); 1796178825Sdfr if (cp) 1797178825Sdfr krb5_free_principal(context, cp); 1798178825Sdfr if (sp) 1799178825Sdfr krb5_free_principal(context, sp); 1800178825Sdfr 1801178825Sdfr free_EncTicketPart(&adtkt); 1802178825Sdfr 1803178825Sdfr return ret; 1804178825Sdfr} 1805178825Sdfr 1806178825Sdfr/* 1807178825Sdfr * 1808178825Sdfr */ 1809178825Sdfr 1810178825Sdfrkrb5_error_code 1811178825Sdfr_kdc_tgs_rep(krb5_context context, 1812178825Sdfr krb5_kdc_configuration *config, 1813178825Sdfr KDC_REQ *req, 1814178825Sdfr krb5_data *data, 1815178825Sdfr const char *from, 1816178825Sdfr struct sockaddr *from_addr, 1817178825Sdfr int datagram_reply) 1818178825Sdfr{ 1819178825Sdfr AuthorizationData *auth_data = NULL; 1820178825Sdfr krb5_error_code ret; 1821178825Sdfr int i = 0; 1822178825Sdfr const PA_DATA *tgs_req; 1823178825Sdfr 1824178825Sdfr hdb_entry_ex *krbtgt = NULL; 1825178825Sdfr krb5_ticket *ticket = NULL; 1826178825Sdfr const char *e_text = NULL; 1827178825Sdfr krb5_enctype krbtgt_etype = ETYPE_NULL; 1828178825Sdfr 1829178825Sdfr time_t *csec = NULL; 1830178825Sdfr int *cusec = NULL; 1831178825Sdfr 1832178825Sdfr if(req->padata == NULL){ 1833178825Sdfr ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */ 1834178825Sdfr kdc_log(context, config, 0, 1835178825Sdfr "TGS-REQ from %s without PA-DATA", from); 1836178825Sdfr goto out; 1837178825Sdfr } 1838178825Sdfr 1839178825Sdfr tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ); 1840178825Sdfr 1841178825Sdfr if(tgs_req == NULL){ 1842178825Sdfr ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 1843178825Sdfr 1844178825Sdfr kdc_log(context, config, 0, 1845178825Sdfr "TGS-REQ from %s without PA-TGS-REQ", from); 1846178825Sdfr goto out; 1847178825Sdfr } 1848178825Sdfr ret = tgs_parse_request(context, config, 1849178825Sdfr &req->req_body, tgs_req, 1850178825Sdfr &krbtgt, 1851178825Sdfr &krbtgt_etype, 1852178825Sdfr &ticket, 1853178825Sdfr &e_text, 1854178825Sdfr from, from_addr, 1855178825Sdfr &csec, &cusec, 1856178825Sdfr &auth_data); 1857178825Sdfr if (ret) { 1858178825Sdfr kdc_log(context, config, 0, 1859178825Sdfr "Failed parsing TGS-REQ from %s", from); 1860178825Sdfr goto out; 1861178825Sdfr } 1862178825Sdfr 1863178825Sdfr ret = tgs_build_reply(context, 1864178825Sdfr config, 1865178825Sdfr req, 1866178825Sdfr &req->req_body, 1867178825Sdfr krbtgt, 1868178825Sdfr krbtgt_etype, 1869178825Sdfr ticket, 1870178825Sdfr data, 1871178825Sdfr from, 1872178825Sdfr &e_text, 1873178825Sdfr auth_data, 1874178825Sdfr from_addr, 1875178825Sdfr datagram_reply); 1876178825Sdfr if (ret) { 1877178825Sdfr kdc_log(context, config, 0, 1878178825Sdfr "Failed building TGS-REP to %s", from); 1879178825Sdfr goto out; 1880178825Sdfr } 1881178825Sdfr 1882178825Sdfr /* */ 1883178825Sdfr if (datagram_reply && data->length > config->max_datagram_reply_length) { 1884178825Sdfr krb5_data_free(data); 1885178825Sdfr ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; 1886178825Sdfr e_text = "Reply packet too large"; 1887178825Sdfr } 1888178825Sdfr 1889178825Sdfrout: 1890178825Sdfr if(ret && data->data == NULL){ 1891178825Sdfr krb5_mk_error(context, 1892178825Sdfr ret, 1893178825Sdfr NULL, 1894178825Sdfr NULL, 1895178825Sdfr NULL, 1896178825Sdfr NULL, 1897178825Sdfr csec, 1898178825Sdfr cusec, 1899178825Sdfr data); 1900178825Sdfr } 1901178825Sdfr free(csec); 1902178825Sdfr free(cusec); 1903178825Sdfr if (ticket) 1904178825Sdfr krb5_free_ticket(context, ticket); 1905178825Sdfr if(krbtgt) 1906178825Sdfr _kdc_free_ent(context, krbtgt); 1907178825Sdfr 1908178825Sdfr if (auth_data) { 1909178825Sdfr free_AuthorizationData(auth_data); 1910178825Sdfr free(auth_data); 1911178825Sdfr } 1912178825Sdfr 1913178825Sdfr return 0; 1914178825Sdfr} 1915