1178825Sdfr/* 2233294Sstas * Copyright (c) 1997-2008 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "kdc_locl.h" 35178825Sdfr 36178825Sdfr/* 37178825Sdfr * return the realm of a krbtgt-ticket or NULL 38178825Sdfr */ 39178825Sdfr 40233294Sstasstatic Realm 41178825Sdfrget_krbtgt_realm(const PrincipalName *p) 42178825Sdfr{ 43178825Sdfr if(p->name_string.len == 2 44178825Sdfr && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0) 45178825Sdfr return p->name_string.val[1]; 46178825Sdfr else 47178825Sdfr return NULL; 48178825Sdfr} 49178825Sdfr 50178825Sdfr/* 51178825Sdfr * The KDC might add a signed path to the ticket authorization data 52178825Sdfr * field. This is to avoid server impersonating clients and the 53178825Sdfr * request constrained delegation. 54178825Sdfr * 55178825Sdfr * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single 56178825Sdfr * entry of type KRB5SignedPath. 57178825Sdfr */ 58178825Sdfr 59178825Sdfrstatic krb5_error_code 60178825Sdfrfind_KRB5SignedPath(krb5_context context, 61178825Sdfr const AuthorizationData *ad, 62178825Sdfr krb5_data *data) 63178825Sdfr{ 64178825Sdfr AuthorizationData child; 65178825Sdfr krb5_error_code ret; 66178825Sdfr int pos; 67233294Sstas 68178825Sdfr if (ad == NULL || ad->len == 0) 69178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 70178825Sdfr 71178825Sdfr pos = ad->len - 1; 72178825Sdfr 73178825Sdfr if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 74178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 75178825Sdfr 76178825Sdfr ret = decode_AuthorizationData(ad->val[pos].ad_data.data, 77178825Sdfr ad->val[pos].ad_data.length, 78178825Sdfr &child, 79178825Sdfr NULL); 80178825Sdfr if (ret) { 81233294Sstas krb5_set_error_message(context, ret, "Failed to decode " 82233294Sstas "IF_RELEVANT with %d", ret); 83178825Sdfr return ret; 84178825Sdfr } 85178825Sdfr 86178825Sdfr if (child.len != 1) { 87178825Sdfr free_AuthorizationData(&child); 88178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 89178825Sdfr } 90178825Sdfr 91178825Sdfr if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { 92178825Sdfr free_AuthorizationData(&child); 93178825Sdfr return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 94178825Sdfr } 95178825Sdfr 96178825Sdfr if (data) 97178825Sdfr ret = der_copy_octet_string(&child.val[0].ad_data, data); 98178825Sdfr free_AuthorizationData(&child); 99178825Sdfr return ret; 100178825Sdfr} 101178825Sdfr 102178825Sdfrkrb5_error_code 103178825Sdfr_kdc_add_KRB5SignedPath(krb5_context context, 104178825Sdfr krb5_kdc_configuration *config, 105178825Sdfr hdb_entry_ex *krbtgt, 106178825Sdfr krb5_enctype enctype, 107233294Sstas krb5_principal client, 108178825Sdfr krb5_const_principal server, 109233294Sstas krb5_principals principals, 110178825Sdfr EncTicketPart *tkt) 111178825Sdfr{ 112178825Sdfr krb5_error_code ret; 113178825Sdfr KRB5SignedPath sp; 114178825Sdfr krb5_data data; 115178825Sdfr krb5_crypto crypto = NULL; 116233294Sstas size_t size = 0; 117178825Sdfr 118178825Sdfr if (server && principals) { 119233294Sstas ret = add_Principals(principals, server); 120178825Sdfr if (ret) 121178825Sdfr return ret; 122178825Sdfr } 123178825Sdfr 124178825Sdfr { 125178825Sdfr KRB5SignedPathData spd; 126233294Sstas 127233294Sstas spd.client = client; 128233294Sstas spd.authtime = tkt->authtime; 129178825Sdfr spd.delegated = principals; 130233294Sstas spd.method_data = NULL; 131233294Sstas 132178825Sdfr ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 133178825Sdfr &spd, &size, ret); 134178825Sdfr if (ret) 135178825Sdfr return ret; 136178825Sdfr if (data.length != size) 137178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 138178825Sdfr } 139178825Sdfr 140178825Sdfr { 141178825Sdfr Key *key; 142178825Sdfr ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key); 143178825Sdfr if (ret == 0) 144178825Sdfr ret = krb5_crypto_init(context, &key->key, 0, &crypto); 145178825Sdfr if (ret) { 146178825Sdfr free(data.data); 147178825Sdfr return ret; 148178825Sdfr } 149178825Sdfr } 150178825Sdfr 151178825Sdfr /* 152178825Sdfr * Fill in KRB5SignedPath 153178825Sdfr */ 154178825Sdfr 155178825Sdfr sp.etype = enctype; 156178825Sdfr sp.delegated = principals; 157233294Sstas sp.method_data = NULL; 158178825Sdfr 159178825Sdfr ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0, 160178825Sdfr data.data, data.length, &sp.cksum); 161178825Sdfr krb5_crypto_destroy(context, crypto); 162178825Sdfr free(data.data); 163178825Sdfr if (ret) 164178825Sdfr return ret; 165178825Sdfr 166178825Sdfr ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); 167178825Sdfr free_Checksum(&sp.cksum); 168178825Sdfr if (ret) 169178825Sdfr return ret; 170178825Sdfr if (data.length != size) 171178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 172178825Sdfr 173233294Sstas 174178825Sdfr /* 175178825Sdfr * Add IF-RELEVANT(KRB5SignedPath) to the last slot in 176178825Sdfr * authorization data field. 177178825Sdfr */ 178178825Sdfr 179178825Sdfr ret = _kdc_tkt_add_if_relevant_ad(context, tkt, 180178825Sdfr KRB5_AUTHDATA_SIGNTICKET, &data); 181178825Sdfr krb5_data_free(&data); 182178825Sdfr 183178825Sdfr return ret; 184178825Sdfr} 185178825Sdfr 186178825Sdfrstatic krb5_error_code 187178825Sdfrcheck_KRB5SignedPath(krb5_context context, 188178825Sdfr krb5_kdc_configuration *config, 189178825Sdfr hdb_entry_ex *krbtgt, 190233294Sstas krb5_principal cp, 191178825Sdfr EncTicketPart *tkt, 192233294Sstas krb5_principals *delegated, 193233294Sstas int *signedpath) 194178825Sdfr{ 195178825Sdfr krb5_error_code ret; 196178825Sdfr krb5_data data; 197178825Sdfr krb5_crypto crypto = NULL; 198178825Sdfr 199233294Sstas if (delegated) 200233294Sstas *delegated = NULL; 201178825Sdfr 202178825Sdfr ret = find_KRB5SignedPath(context, tkt->authorization_data, &data); 203178825Sdfr if (ret == 0) { 204178825Sdfr KRB5SignedPathData spd; 205178825Sdfr KRB5SignedPath sp; 206233294Sstas size_t size = 0; 207178825Sdfr 208178825Sdfr ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL); 209178825Sdfr krb5_data_free(&data); 210178825Sdfr if (ret) 211178825Sdfr return ret; 212178825Sdfr 213233294Sstas spd.client = cp; 214233294Sstas spd.authtime = tkt->authtime; 215178825Sdfr spd.delegated = sp.delegated; 216233294Sstas spd.method_data = sp.method_data; 217178825Sdfr 218178825Sdfr ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 219178825Sdfr &spd, &size, ret); 220178825Sdfr if (ret) { 221178825Sdfr free_KRB5SignedPath(&sp); 222178825Sdfr return ret; 223178825Sdfr } 224178825Sdfr if (data.length != size) 225178825Sdfr krb5_abortx(context, "internal asn.1 encoder error"); 226178825Sdfr 227178825Sdfr { 228178825Sdfr Key *key; 229178825Sdfr ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key); 230178825Sdfr if (ret == 0) 231178825Sdfr ret = krb5_crypto_init(context, &key->key, 0, &crypto); 232178825Sdfr if (ret) { 233178825Sdfr free(data.data); 234178825Sdfr free_KRB5SignedPath(&sp); 235178825Sdfr return ret; 236178825Sdfr } 237178825Sdfr } 238233294Sstas ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 239233294Sstas data.data, data.length, 240178825Sdfr &sp.cksum); 241178825Sdfr krb5_crypto_destroy(context, crypto); 242178825Sdfr free(data.data); 243178825Sdfr if (ret) { 244178825Sdfr free_KRB5SignedPath(&sp); 245233294Sstas kdc_log(context, config, 5, 246233294Sstas "KRB5SignedPath not signed correctly, not marking as signed"); 247233294Sstas return 0; 248178825Sdfr } 249178825Sdfr 250233294Sstas if (delegated && sp.delegated) { 251178825Sdfr 252178825Sdfr *delegated = malloc(sizeof(*sp.delegated)); 253178825Sdfr if (*delegated == NULL) { 254178825Sdfr free_KRB5SignedPath(&sp); 255178825Sdfr return ENOMEM; 256178825Sdfr } 257178825Sdfr 258233294Sstas ret = copy_Principals(*delegated, sp.delegated); 259178825Sdfr if (ret) { 260178825Sdfr free_KRB5SignedPath(&sp); 261178825Sdfr free(*delegated); 262178825Sdfr *delegated = NULL; 263178825Sdfr return ret; 264178825Sdfr } 265178825Sdfr } 266178825Sdfr free_KRB5SignedPath(&sp); 267233294Sstas 268233294Sstas *signedpath = 1; 269178825Sdfr } 270178825Sdfr 271178825Sdfr return 0; 272178825Sdfr} 273178825Sdfr 274178825Sdfr/* 275178825Sdfr * 276178825Sdfr */ 277178825Sdfr 278178825Sdfrstatic krb5_error_code 279178825Sdfrcheck_PAC(krb5_context context, 280178825Sdfr krb5_kdc_configuration *config, 281178825Sdfr const krb5_principal client_principal, 282233294Sstas const krb5_principal delegated_proxy_principal, 283178825Sdfr hdb_entry_ex *client, 284178825Sdfr hdb_entry_ex *server, 285233294Sstas hdb_entry_ex *krbtgt, 286233294Sstas const EncryptionKey *server_check_key, 287233294Sstas const EncryptionKey *krbtgt_check_key, 288233294Sstas const EncryptionKey *server_sign_key, 289233294Sstas const EncryptionKey *krbtgt_sign_key, 290178825Sdfr EncTicketPart *tkt, 291178825Sdfr krb5_data *rspac, 292233294Sstas int *signedpath) 293178825Sdfr{ 294178825Sdfr AuthorizationData *ad = tkt->authorization_data; 295178825Sdfr unsigned i, j; 296178825Sdfr krb5_error_code ret; 297178825Sdfr 298178825Sdfr if (ad == NULL || ad->len == 0) 299178825Sdfr return 0; 300178825Sdfr 301178825Sdfr for (i = 0; i < ad->len; i++) { 302178825Sdfr AuthorizationData child; 303178825Sdfr 304178825Sdfr if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 305178825Sdfr continue; 306178825Sdfr 307178825Sdfr ret = decode_AuthorizationData(ad->val[i].ad_data.data, 308178825Sdfr ad->val[i].ad_data.length, 309178825Sdfr &child, 310178825Sdfr NULL); 311178825Sdfr if (ret) { 312233294Sstas krb5_set_error_message(context, ret, "Failed to decode " 313233294Sstas "IF_RELEVANT with %d", ret); 314178825Sdfr return ret; 315178825Sdfr } 316178825Sdfr for (j = 0; j < child.len; j++) { 317178825Sdfr 318178825Sdfr if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { 319233294Sstas int signed_pac = 0; 320178825Sdfr krb5_pac pac; 321178825Sdfr 322178825Sdfr /* Found PAC */ 323178825Sdfr ret = krb5_pac_parse(context, 324178825Sdfr child.val[j].ad_data.data, 325178825Sdfr child.val[j].ad_data.length, 326178825Sdfr &pac); 327178825Sdfr free_AuthorizationData(&child); 328178825Sdfr if (ret) 329178825Sdfr return ret; 330178825Sdfr 331233294Sstas ret = krb5_pac_verify(context, pac, tkt->authtime, 332178825Sdfr client_principal, 333233294Sstas server_check_key, krbtgt_check_key); 334178825Sdfr if (ret) { 335178825Sdfr krb5_pac_free(context, pac); 336178825Sdfr return ret; 337178825Sdfr } 338178825Sdfr 339233294Sstas ret = _kdc_pac_verify(context, client_principal, 340233294Sstas delegated_proxy_principal, 341233294Sstas client, server, krbtgt, &pac, &signed_pac); 342178825Sdfr if (ret) { 343178825Sdfr krb5_pac_free(context, pac); 344178825Sdfr return ret; 345178825Sdfr } 346178825Sdfr 347233294Sstas /* 348233294Sstas * Only re-sign PAC if we could verify it with the PAC 349233294Sstas * function. The no-verify case happens when we get in 350233294Sstas * a PAC from cross realm from a Windows domain and 351233294Sstas * that there is no PAC verification function. 352233294Sstas */ 353233294Sstas if (signed_pac) { 354233294Sstas *signedpath = 1; 355233294Sstas ret = _krb5_pac_sign(context, pac, tkt->authtime, 356233294Sstas client_principal, 357233294Sstas server_sign_key, krbtgt_sign_key, rspac); 358233294Sstas } 359178825Sdfr krb5_pac_free(context, pac); 360178825Sdfr 361178825Sdfr return ret; 362178825Sdfr } 363178825Sdfr } 364178825Sdfr free_AuthorizationData(&child); 365178825Sdfr } 366178825Sdfr return 0; 367178825Sdfr} 368178825Sdfr 369178825Sdfr/* 370178825Sdfr * 371178825Sdfr */ 372178825Sdfr 373178825Sdfrstatic krb5_error_code 374233294Sstascheck_tgs_flags(krb5_context context, 375178825Sdfr krb5_kdc_configuration *config, 376178825Sdfr KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et) 377178825Sdfr{ 378178825Sdfr KDCOptions f = b->kdc_options; 379233294Sstas 380178825Sdfr if(f.validate){ 381178825Sdfr if(!tgt->flags.invalid || tgt->starttime == NULL){ 382178825Sdfr kdc_log(context, config, 0, 383178825Sdfr "Bad request to validate ticket"); 384178825Sdfr return KRB5KDC_ERR_BADOPTION; 385178825Sdfr } 386178825Sdfr if(*tgt->starttime > kdc_time){ 387178825Sdfr kdc_log(context, config, 0, 388178825Sdfr "Early request to validate ticket"); 389178825Sdfr return KRB5KRB_AP_ERR_TKT_NYV; 390178825Sdfr } 391178825Sdfr /* XXX tkt = tgt */ 392178825Sdfr et->flags.invalid = 0; 393178825Sdfr }else if(tgt->flags.invalid){ 394233294Sstas kdc_log(context, config, 0, 395178825Sdfr "Ticket-granting ticket has INVALID flag set"); 396178825Sdfr return KRB5KRB_AP_ERR_TKT_INVALID; 397178825Sdfr } 398178825Sdfr 399178825Sdfr if(f.forwardable){ 400178825Sdfr if(!tgt->flags.forwardable){ 401178825Sdfr kdc_log(context, config, 0, 402178825Sdfr "Bad request for forwardable ticket"); 403178825Sdfr return KRB5KDC_ERR_BADOPTION; 404178825Sdfr } 405178825Sdfr et->flags.forwardable = 1; 406178825Sdfr } 407178825Sdfr if(f.forwarded){ 408178825Sdfr if(!tgt->flags.forwardable){ 409178825Sdfr kdc_log(context, config, 0, 410178825Sdfr "Request to forward non-forwardable ticket"); 411178825Sdfr return KRB5KDC_ERR_BADOPTION; 412178825Sdfr } 413178825Sdfr et->flags.forwarded = 1; 414178825Sdfr et->caddr = b->addresses; 415178825Sdfr } 416178825Sdfr if(tgt->flags.forwarded) 417178825Sdfr et->flags.forwarded = 1; 418233294Sstas 419178825Sdfr if(f.proxiable){ 420178825Sdfr if(!tgt->flags.proxiable){ 421178825Sdfr kdc_log(context, config, 0, 422178825Sdfr "Bad request for proxiable ticket"); 423178825Sdfr return KRB5KDC_ERR_BADOPTION; 424178825Sdfr } 425178825Sdfr et->flags.proxiable = 1; 426178825Sdfr } 427178825Sdfr if(f.proxy){ 428178825Sdfr if(!tgt->flags.proxiable){ 429178825Sdfr kdc_log(context, config, 0, 430178825Sdfr "Request to proxy non-proxiable ticket"); 431178825Sdfr return KRB5KDC_ERR_BADOPTION; 432178825Sdfr } 433178825Sdfr et->flags.proxy = 1; 434178825Sdfr et->caddr = b->addresses; 435178825Sdfr } 436178825Sdfr if(tgt->flags.proxy) 437178825Sdfr et->flags.proxy = 1; 438178825Sdfr 439178825Sdfr if(f.allow_postdate){ 440178825Sdfr if(!tgt->flags.may_postdate){ 441178825Sdfr kdc_log(context, config, 0, 442178825Sdfr "Bad request for post-datable ticket"); 443178825Sdfr return KRB5KDC_ERR_BADOPTION; 444178825Sdfr } 445178825Sdfr et->flags.may_postdate = 1; 446178825Sdfr } 447178825Sdfr if(f.postdated){ 448178825Sdfr if(!tgt->flags.may_postdate){ 449178825Sdfr kdc_log(context, config, 0, 450178825Sdfr "Bad request for postdated ticket"); 451178825Sdfr return KRB5KDC_ERR_BADOPTION; 452178825Sdfr } 453178825Sdfr if(b->from) 454178825Sdfr *et->starttime = *b->from; 455178825Sdfr et->flags.postdated = 1; 456178825Sdfr et->flags.invalid = 1; 457178825Sdfr }else if(b->from && *b->from > kdc_time + context->max_skew){ 458178825Sdfr kdc_log(context, config, 0, "Ticket cannot be postdated"); 459178825Sdfr return KRB5KDC_ERR_CANNOT_POSTDATE; 460178825Sdfr } 461178825Sdfr 462178825Sdfr if(f.renewable){ 463233294Sstas if(!tgt->flags.renewable || tgt->renew_till == NULL){ 464178825Sdfr kdc_log(context, config, 0, 465178825Sdfr "Bad request for renewable ticket"); 466178825Sdfr return KRB5KDC_ERR_BADOPTION; 467178825Sdfr } 468178825Sdfr et->flags.renewable = 1; 469178825Sdfr ALLOC(et->renew_till); 470178825Sdfr _kdc_fix_time(&b->rtime); 471178825Sdfr *et->renew_till = *b->rtime; 472178825Sdfr } 473178825Sdfr if(f.renew){ 474178825Sdfr time_t old_life; 475178825Sdfr if(!tgt->flags.renewable || tgt->renew_till == NULL){ 476178825Sdfr kdc_log(context, config, 0, 477178825Sdfr "Request to renew non-renewable ticket"); 478178825Sdfr return KRB5KDC_ERR_BADOPTION; 479178825Sdfr } 480178825Sdfr old_life = tgt->endtime; 481178825Sdfr if(tgt->starttime) 482178825Sdfr old_life -= *tgt->starttime; 483178825Sdfr else 484178825Sdfr old_life -= tgt->authtime; 485178825Sdfr et->endtime = *et->starttime + old_life; 486178825Sdfr if (et->renew_till != NULL) 487178825Sdfr et->endtime = min(*et->renew_till, et->endtime); 488233294Sstas } 489233294Sstas 490178825Sdfr#if 0 491178825Sdfr /* checks for excess flags */ 492178825Sdfr if(f.request_anonymous && !config->allow_anonymous){ 493178825Sdfr kdc_log(context, config, 0, 494178825Sdfr "Request for anonymous ticket"); 495178825Sdfr return KRB5KDC_ERR_BADOPTION; 496178825Sdfr } 497178825Sdfr#endif 498178825Sdfr return 0; 499178825Sdfr} 500178825Sdfr 501178825Sdfr/* 502233294Sstas * Determine if constrained delegation is allowed from this client to this server 503178825Sdfr */ 504178825Sdfr 505178825Sdfrstatic krb5_error_code 506233294Sstascheck_constrained_delegation(krb5_context context, 507178825Sdfr krb5_kdc_configuration *config, 508233294Sstas HDB *clientdb, 509178825Sdfr hdb_entry_ex *client, 510233294Sstas hdb_entry_ex *server, 511233294Sstas krb5_const_principal target) 512178825Sdfr{ 513178825Sdfr const HDB_Ext_Constrained_delegation_acl *acl; 514178825Sdfr krb5_error_code ret; 515233294Sstas size_t i; 516178825Sdfr 517233294Sstas /* 518233294Sstas * constrained_delegation (S4U2Proxy) only works within 519233294Sstas * the same realm. We use the already canonicalized version 520233294Sstas * of the principals here, while "target" is the principal 521233294Sstas * provided by the client. 522233294Sstas */ 523233294Sstas if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) { 524233294Sstas ret = KRB5KDC_ERR_BADOPTION; 525233294Sstas kdc_log(context, config, 0, 526233294Sstas "Bad request for constrained delegation"); 527178825Sdfr return ret; 528178825Sdfr } 529178825Sdfr 530233294Sstas if (clientdb->hdb_check_constrained_delegation) { 531233294Sstas ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target); 532233294Sstas if (ret == 0) 533233294Sstas return 0; 534233294Sstas } else { 535233294Sstas /* if client delegates to itself, that ok */ 536233294Sstas if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE) 537233294Sstas return 0; 538233294Sstas 539233294Sstas ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl); 540233294Sstas if (ret) { 541233294Sstas krb5_clear_error_message(context); 542233294Sstas return ret; 543178825Sdfr } 544233294Sstas 545233294Sstas if (acl) { 546233294Sstas for (i = 0; i < acl->len; i++) { 547233294Sstas if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE) 548233294Sstas return 0; 549233294Sstas } 550233294Sstas } 551233294Sstas ret = KRB5KDC_ERR_BADOPTION; 552178825Sdfr } 553178825Sdfr kdc_log(context, config, 0, 554178825Sdfr "Bad request for constrained delegation"); 555233294Sstas return ret; 556178825Sdfr} 557178825Sdfr 558178825Sdfr/* 559233294Sstas * Determine if s4u2self is allowed from this client to this server 560178825Sdfr * 561233294Sstas * For example, regardless of the principal being impersonated, if the 562233294Sstas * 'client' and 'server' are the same, then it's safe. 563178825Sdfr */ 564178825Sdfr 565178825Sdfrstatic krb5_error_code 566233294Sstascheck_s4u2self(krb5_context context, 567233294Sstas krb5_kdc_configuration *config, 568233294Sstas HDB *clientdb, 569233294Sstas hdb_entry_ex *client, 570233294Sstas krb5_const_principal server) 571233294Sstas{ 572233294Sstas krb5_error_code ret; 573233294Sstas 574233294Sstas /* if client does a s4u2self to itself, that ok */ 575233294Sstas if (krb5_principal_compare(context, client->entry.principal, server) == TRUE) 576233294Sstas return 0; 577233294Sstas 578233294Sstas if (clientdb->hdb_check_s4u2self) { 579233294Sstas ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server); 580233294Sstas if (ret == 0) 581233294Sstas return 0; 582233294Sstas } else { 583233294Sstas ret = KRB5KDC_ERR_BADOPTION; 584233294Sstas } 585233294Sstas return ret; 586233294Sstas} 587233294Sstas 588233294Sstas/* 589233294Sstas * 590233294Sstas */ 591233294Sstas 592233294Sstasstatic krb5_error_code 593233294Sstasverify_flags (krb5_context context, 594178825Sdfr krb5_kdc_configuration *config, 595178825Sdfr const EncTicketPart *et, 596178825Sdfr const char *pstr) 597178825Sdfr{ 598178825Sdfr if(et->endtime < kdc_time){ 599178825Sdfr kdc_log(context, config, 0, "Ticket expired (%s)", pstr); 600178825Sdfr return KRB5KRB_AP_ERR_TKT_EXPIRED; 601178825Sdfr } 602178825Sdfr if(et->flags.invalid){ 603178825Sdfr kdc_log(context, config, 0, "Ticket not valid (%s)", pstr); 604178825Sdfr return KRB5KRB_AP_ERR_TKT_NYV; 605178825Sdfr } 606178825Sdfr return 0; 607178825Sdfr} 608178825Sdfr 609178825Sdfr/* 610178825Sdfr * 611178825Sdfr */ 612178825Sdfr 613178825Sdfrstatic krb5_error_code 614233294Sstasfix_transited_encoding(krb5_context context, 615178825Sdfr krb5_kdc_configuration *config, 616178825Sdfr krb5_boolean check_policy, 617233294Sstas const TransitedEncoding *tr, 618233294Sstas EncTicketPart *et, 619233294Sstas const char *client_realm, 620233294Sstas const char *server_realm, 621178825Sdfr const char *tgt_realm) 622178825Sdfr{ 623178825Sdfr krb5_error_code ret = 0; 624178825Sdfr char **realms, **tmp; 625233294Sstas unsigned int num_realms; 626233294Sstas size_t i; 627178825Sdfr 628178825Sdfr switch (tr->tr_type) { 629178825Sdfr case DOMAIN_X500_COMPRESS: 630178825Sdfr break; 631178825Sdfr case 0: 632178825Sdfr /* 633178825Sdfr * Allow empty content of type 0 because that is was Microsoft 634178825Sdfr * generates in their TGT. 635178825Sdfr */ 636178825Sdfr if (tr->contents.length == 0) 637178825Sdfr break; 638178825Sdfr kdc_log(context, config, 0, 639178825Sdfr "Transited type 0 with non empty content"); 640178825Sdfr return KRB5KDC_ERR_TRTYPE_NOSUPP; 641178825Sdfr default: 642178825Sdfr kdc_log(context, config, 0, 643178825Sdfr "Unknown transited type: %u", tr->tr_type); 644178825Sdfr return KRB5KDC_ERR_TRTYPE_NOSUPP; 645178825Sdfr } 646178825Sdfr 647233294Sstas ret = krb5_domain_x500_decode(context, 648178825Sdfr tr->contents, 649233294Sstas &realms, 650178825Sdfr &num_realms, 651178825Sdfr client_realm, 652178825Sdfr server_realm); 653178825Sdfr if(ret){ 654178825Sdfr krb5_warn(context, ret, 655178825Sdfr "Decoding transited encoding"); 656178825Sdfr return ret; 657178825Sdfr } 658178825Sdfr if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) { 659178825Sdfr /* not us, so add the previous realm to transited set */ 660233294Sstas if (num_realms + 1 > UINT_MAX/sizeof(*realms)) { 661178825Sdfr ret = ERANGE; 662178825Sdfr goto free_realms; 663178825Sdfr } 664178825Sdfr tmp = realloc(realms, (num_realms + 1) * sizeof(*realms)); 665178825Sdfr if(tmp == NULL){ 666178825Sdfr ret = ENOMEM; 667178825Sdfr goto free_realms; 668178825Sdfr } 669178825Sdfr realms = tmp; 670178825Sdfr realms[num_realms] = strdup(tgt_realm); 671178825Sdfr if(realms[num_realms] == NULL){ 672178825Sdfr ret = ENOMEM; 673178825Sdfr goto free_realms; 674178825Sdfr } 675178825Sdfr num_realms++; 676178825Sdfr } 677178825Sdfr if(num_realms == 0) { 678233294Sstas if(strcmp(client_realm, server_realm)) 679178825Sdfr kdc_log(context, config, 0, 680178825Sdfr "cross-realm %s -> %s", client_realm, server_realm); 681178825Sdfr } else { 682178825Sdfr size_t l = 0; 683178825Sdfr char *rs; 684178825Sdfr for(i = 0; i < num_realms; i++) 685178825Sdfr l += strlen(realms[i]) + 2; 686178825Sdfr rs = malloc(l); 687178825Sdfr if(rs != NULL) { 688178825Sdfr *rs = '\0'; 689178825Sdfr for(i = 0; i < num_realms; i++) { 690178825Sdfr if(i > 0) 691178825Sdfr strlcat(rs, ", ", l); 692178825Sdfr strlcat(rs, realms[i], l); 693178825Sdfr } 694178825Sdfr kdc_log(context, config, 0, 695178825Sdfr "cross-realm %s -> %s via [%s]", 696178825Sdfr client_realm, server_realm, rs); 697178825Sdfr free(rs); 698178825Sdfr } 699178825Sdfr } 700178825Sdfr if(check_policy) { 701233294Sstas ret = krb5_check_transited(context, client_realm, 702233294Sstas server_realm, 703178825Sdfr realms, num_realms, NULL); 704178825Sdfr if(ret) { 705233294Sstas krb5_warn(context, ret, "cross-realm %s -> %s", 706178825Sdfr client_realm, server_realm); 707178825Sdfr goto free_realms; 708178825Sdfr } 709178825Sdfr et->flags.transited_policy_checked = 1; 710178825Sdfr } 711178825Sdfr et->transited.tr_type = DOMAIN_X500_COMPRESS; 712178825Sdfr ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents); 713178825Sdfr if(ret) 714178825Sdfr krb5_warn(context, ret, "Encoding transited encoding"); 715178825Sdfr free_realms: 716178825Sdfr for(i = 0; i < num_realms; i++) 717178825Sdfr free(realms[i]); 718178825Sdfr free(realms); 719178825Sdfr return ret; 720178825Sdfr} 721178825Sdfr 722178825Sdfr 723178825Sdfrstatic krb5_error_code 724233294Sstastgs_make_reply(krb5_context context, 725178825Sdfr krb5_kdc_configuration *config, 726233294Sstas KDC_REQ_BODY *b, 727178825Sdfr krb5_const_principal tgt_name, 728233294Sstas const EncTicketPart *tgt, 729233294Sstas const krb5_keyblock *replykey, 730233294Sstas int rk_is_subkey, 731178825Sdfr const EncryptionKey *serverkey, 732178825Sdfr const krb5_keyblock *sessionkey, 733178825Sdfr krb5_kvno kvno, 734178825Sdfr AuthorizationData *auth_data, 735233294Sstas hdb_entry_ex *server, 736233294Sstas krb5_principal server_principal, 737233294Sstas const char *server_name, 738233294Sstas hdb_entry_ex *client, 739233294Sstas krb5_principal client_principal, 740178825Sdfr hdb_entry_ex *krbtgt, 741178825Sdfr krb5_enctype krbtgt_etype, 742233294Sstas krb5_principals spp, 743178825Sdfr const krb5_data *rspac, 744233294Sstas const METHOD_DATA *enc_pa_data, 745178825Sdfr const char **e_text, 746178825Sdfr krb5_data *reply) 747178825Sdfr{ 748178825Sdfr KDC_REP rep; 749178825Sdfr EncKDCRepPart ek; 750178825Sdfr EncTicketPart et; 751178825Sdfr KDCOptions f = b->kdc_options; 752178825Sdfr krb5_error_code ret; 753233294Sstas int is_weak = 0; 754233294Sstas 755178825Sdfr memset(&rep, 0, sizeof(rep)); 756178825Sdfr memset(&et, 0, sizeof(et)); 757178825Sdfr memset(&ek, 0, sizeof(ek)); 758233294Sstas 759178825Sdfr rep.pvno = 5; 760178825Sdfr rep.msg_type = krb_tgs_rep; 761178825Sdfr 762178825Sdfr et.authtime = tgt->authtime; 763178825Sdfr _kdc_fix_time(&b->till); 764178825Sdfr et.endtime = min(tgt->endtime, *b->till); 765178825Sdfr ALLOC(et.starttime); 766178825Sdfr *et.starttime = kdc_time; 767233294Sstas 768178825Sdfr ret = check_tgs_flags(context, config, b, tgt, &et); 769178825Sdfr if(ret) 770178825Sdfr goto out; 771178825Sdfr 772178825Sdfr /* We should check the transited encoding if: 773178825Sdfr 1) the request doesn't ask not to be checked 774178825Sdfr 2) globally enforcing a check 775178825Sdfr 3) principal requires checking 776178825Sdfr 4) we allow non-check per-principal, but principal isn't marked as allowing this 777178825Sdfr 5) we don't globally allow this 778178825Sdfr */ 779178825Sdfr 780178825Sdfr#define GLOBAL_FORCE_TRANSITED_CHECK \ 781178825Sdfr (config->trpolicy == TRPOLICY_ALWAYS_CHECK) 782178825Sdfr#define GLOBAL_ALLOW_PER_PRINCIPAL \ 783178825Sdfr (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) 784178825Sdfr#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \ 785178825Sdfr (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) 786178825Sdfr 787178825Sdfr/* these will consult the database in future release */ 788178825Sdfr#define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0 789178825Sdfr#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0 790178825Sdfr 791233294Sstas ret = fix_transited_encoding(context, config, 792178825Sdfr !f.disable_transited_check || 793178825Sdfr GLOBAL_FORCE_TRANSITED_CHECK || 794178825Sdfr PRINCIPAL_FORCE_TRANSITED_CHECK(server) || 795233294Sstas !((GLOBAL_ALLOW_PER_PRINCIPAL && 796178825Sdfr PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || 797178825Sdfr GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), 798178825Sdfr &tgt->transited, &et, 799233294Sstas krb5_principal_get_realm(context, client_principal), 800233294Sstas krb5_principal_get_realm(context, server->entry.principal), 801233294Sstas krb5_principal_get_realm(context, krbtgt->entry.principal)); 802178825Sdfr if(ret) 803178825Sdfr goto out; 804178825Sdfr 805233294Sstas copy_Realm(&server_principal->realm, &rep.ticket.realm); 806233294Sstas _krb5_principal2principalname(&rep.ticket.sname, server_principal); 807178825Sdfr copy_Realm(&tgt_name->realm, &rep.crealm); 808178825Sdfr/* 809178825Sdfr if (f.request_anonymous) 810178825Sdfr _kdc_make_anonymous_principalname (&rep.cname); 811178825Sdfr else */ 812178825Sdfr 813178825Sdfr copy_PrincipalName(&tgt_name->name, &rep.cname); 814178825Sdfr rep.ticket.tkt_vno = 5; 815178825Sdfr 816178825Sdfr ek.caddr = et.caddr; 817178825Sdfr if(et.caddr == NULL) 818178825Sdfr et.caddr = tgt->caddr; 819178825Sdfr 820178825Sdfr { 821178825Sdfr time_t life; 822178825Sdfr life = et.endtime - *et.starttime; 823178825Sdfr if(client && client->entry.max_life) 824178825Sdfr life = min(life, *client->entry.max_life); 825178825Sdfr if(server->entry.max_life) 826178825Sdfr life = min(life, *server->entry.max_life); 827178825Sdfr et.endtime = *et.starttime + life; 828178825Sdfr } 829233294Sstas if(f.renewable_ok && tgt->flags.renewable && 830233294Sstas et.renew_till == NULL && et.endtime < *b->till && 831233294Sstas tgt->renew_till != NULL) 832233294Sstas { 833178825Sdfr et.flags.renewable = 1; 834178825Sdfr ALLOC(et.renew_till); 835178825Sdfr *et.renew_till = *b->till; 836178825Sdfr } 837178825Sdfr if(et.renew_till){ 838178825Sdfr time_t renew; 839178825Sdfr renew = *et.renew_till - et.authtime; 840178825Sdfr if(client && client->entry.max_renew) 841178825Sdfr renew = min(renew, *client->entry.max_renew); 842178825Sdfr if(server->entry.max_renew) 843178825Sdfr renew = min(renew, *server->entry.max_renew); 844178825Sdfr *et.renew_till = et.authtime + renew; 845178825Sdfr } 846233294Sstas 847178825Sdfr if(et.renew_till){ 848178825Sdfr *et.renew_till = min(*et.renew_till, *tgt->renew_till); 849178825Sdfr *et.starttime = min(*et.starttime, *et.renew_till); 850178825Sdfr et.endtime = min(et.endtime, *et.renew_till); 851178825Sdfr } 852233294Sstas 853178825Sdfr *et.starttime = min(*et.starttime, et.endtime); 854178825Sdfr 855178825Sdfr if(*et.starttime == et.endtime){ 856178825Sdfr ret = KRB5KDC_ERR_NEVER_VALID; 857178825Sdfr goto out; 858178825Sdfr } 859178825Sdfr if(et.renew_till && et.endtime == *et.renew_till){ 860178825Sdfr free(et.renew_till); 861178825Sdfr et.renew_till = NULL; 862178825Sdfr et.flags.renewable = 0; 863178825Sdfr } 864233294Sstas 865178825Sdfr et.flags.pre_authent = tgt->flags.pre_authent; 866178825Sdfr et.flags.hw_authent = tgt->flags.hw_authent; 867178825Sdfr et.flags.anonymous = tgt->flags.anonymous; 868178825Sdfr et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate; 869233294Sstas 870233294Sstas if(rspac->length) { 871233294Sstas /* 872233294Sstas * No not need to filter out the any PAC from the 873233294Sstas * auth_data since it's signed by the KDC. 874233294Sstas */ 875233294Sstas ret = _kdc_tkt_add_if_relevant_ad(context, &et, 876233294Sstas KRB5_AUTHDATA_WIN2K_PAC, rspac); 877233294Sstas if (ret) 878233294Sstas goto out; 879233294Sstas } 880233294Sstas 881178825Sdfr if (auth_data) { 882233294Sstas unsigned int i = 0; 883233294Sstas 884233294Sstas /* XXX check authdata */ 885233294Sstas 886178825Sdfr if (et.authorization_data == NULL) { 887233294Sstas et.authorization_data = calloc(1, sizeof(*et.authorization_data)); 888233294Sstas if (et.authorization_data == NULL) { 889233294Sstas ret = ENOMEM; 890233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 891233294Sstas goto out; 892233294Sstas } 893178825Sdfr } 894233294Sstas for(i = 0; i < auth_data->len ; i++) { 895233294Sstas ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]); 896233294Sstas if (ret) { 897233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 898233294Sstas goto out; 899233294Sstas } 900233294Sstas } 901178825Sdfr 902178825Sdfr /* Filter out type KRB5SignedPath */ 903178825Sdfr ret = find_KRB5SignedPath(context, et.authorization_data, NULL); 904178825Sdfr if (ret == 0) { 905178825Sdfr if (et.authorization_data->len == 1) { 906178825Sdfr free_AuthorizationData(et.authorization_data); 907178825Sdfr free(et.authorization_data); 908178825Sdfr et.authorization_data = NULL; 909178825Sdfr } else { 910178825Sdfr AuthorizationData *ad = et.authorization_data; 911178825Sdfr free_AuthorizationDataElement(&ad->val[ad->len - 1]); 912178825Sdfr ad->len--; 913178825Sdfr } 914178825Sdfr } 915178825Sdfr } 916178825Sdfr 917178825Sdfr ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); 918178825Sdfr if (ret) 919178825Sdfr goto out; 920233294Sstas et.crealm = tgt_name->realm; 921178825Sdfr et.cname = tgt_name->name; 922233294Sstas 923178825Sdfr ek.key = et.key; 924178825Sdfr /* MIT must have at least one last_req */ 925178825Sdfr ek.last_req.len = 1; 926178825Sdfr ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); 927178825Sdfr if (ek.last_req.val == NULL) { 928178825Sdfr ret = ENOMEM; 929178825Sdfr goto out; 930178825Sdfr } 931178825Sdfr ek.nonce = b->nonce; 932178825Sdfr ek.flags = et.flags; 933178825Sdfr ek.authtime = et.authtime; 934178825Sdfr ek.starttime = et.starttime; 935178825Sdfr ek.endtime = et.endtime; 936178825Sdfr ek.renew_till = et.renew_till; 937178825Sdfr ek.srealm = rep.ticket.realm; 938178825Sdfr ek.sname = rep.ticket.sname; 939233294Sstas 940233294Sstas _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 941178825Sdfr et.endtime, et.renew_till); 942178825Sdfr 943178825Sdfr /* Don't sign cross realm tickets, they can't be checked anyway */ 944178825Sdfr { 945178825Sdfr char *r = get_krbtgt_realm(&ek.sname); 946178825Sdfr 947178825Sdfr if (r == NULL || strcmp(r, ek.srealm) == 0) { 948178825Sdfr ret = _kdc_add_KRB5SignedPath(context, 949178825Sdfr config, 950178825Sdfr krbtgt, 951178825Sdfr krbtgt_etype, 952233294Sstas client_principal, 953178825Sdfr NULL, 954178825Sdfr spp, 955178825Sdfr &et); 956178825Sdfr if (ret) 957178825Sdfr goto out; 958178825Sdfr } 959178825Sdfr } 960178825Sdfr 961233294Sstas if (enc_pa_data->len) { 962233294Sstas rep.padata = calloc(1, sizeof(*rep.padata)); 963233294Sstas if (rep.padata == NULL) { 964233294Sstas ret = ENOMEM; 965233294Sstas goto out; 966233294Sstas } 967233294Sstas ret = copy_METHOD_DATA(enc_pa_data, rep.padata); 968233294Sstas if (ret) 969233294Sstas goto out; 970233294Sstas } 971233294Sstas 972233294Sstas if (krb5_enctype_valid(context, et.key.keytype) != 0 973233294Sstas && _kdc_is_weak_exception(server->entry.principal, et.key.keytype)) 974233294Sstas { 975233294Sstas krb5_enctype_enable(context, et.key.keytype); 976233294Sstas is_weak = 1; 977233294Sstas } 978233294Sstas 979233294Sstas 980178825Sdfr /* It is somewhat unclear where the etype in the following 981178825Sdfr encryption should come from. What we have is a session 982178825Sdfr key in the passed tgt, and a list of preferred etypes 983178825Sdfr *for the new ticket*. Should we pick the best possible 984178825Sdfr etype, given the keytype in the tgt, or should we look 985178825Sdfr at the etype list here as well? What if the tgt 986178825Sdfr session key is DES3 and we want a ticket with a (say) 987178825Sdfr CAST session key. Should the DES3 etype be added to the 988178825Sdfr etype list, even if we don't want a session key with 989178825Sdfr DES3? */ 990233294Sstas ret = _kdc_encode_reply(context, config, 991178825Sdfr &rep, &et, &ek, et.key.keytype, 992233294Sstas kvno, 993233294Sstas serverkey, 0, replykey, rk_is_subkey, 994233294Sstas e_text, reply); 995233294Sstas if (is_weak) 996233294Sstas krb5_enctype_disable(context, et.key.keytype); 997233294Sstas 998178825Sdfrout: 999178825Sdfr free_TGS_REP(&rep); 1000178825Sdfr free_TransitedEncoding(&et.transited); 1001178825Sdfr if(et.starttime) 1002178825Sdfr free(et.starttime); 1003178825Sdfr if(et.renew_till) 1004178825Sdfr free(et.renew_till); 1005178825Sdfr if(et.authorization_data) { 1006178825Sdfr free_AuthorizationData(et.authorization_data); 1007178825Sdfr free(et.authorization_data); 1008178825Sdfr } 1009178825Sdfr free_LastReq(&ek.last_req); 1010178825Sdfr memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); 1011178825Sdfr free_EncryptionKey(&et.key); 1012178825Sdfr return ret; 1013178825Sdfr} 1014178825Sdfr 1015178825Sdfrstatic krb5_error_code 1016233294Sstastgs_check_authenticator(krb5_context context, 1017178825Sdfr krb5_kdc_configuration *config, 1018178825Sdfr krb5_auth_context ac, 1019233294Sstas KDC_REQ_BODY *b, 1020178825Sdfr const char **e_text, 1021178825Sdfr krb5_keyblock *key) 1022178825Sdfr{ 1023178825Sdfr krb5_authenticator auth; 1024233294Sstas size_t len = 0; 1025178825Sdfr unsigned char *buf; 1026178825Sdfr size_t buf_size; 1027178825Sdfr krb5_error_code ret; 1028178825Sdfr krb5_crypto crypto; 1029233294Sstas 1030178825Sdfr krb5_auth_con_getauthenticator(context, ac, &auth); 1031178825Sdfr if(auth->cksum == NULL){ 1032178825Sdfr kdc_log(context, config, 0, "No authenticator in request"); 1033178825Sdfr ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 1034178825Sdfr goto out; 1035178825Sdfr } 1036178825Sdfr /* 1037178825Sdfr * according to RFC1510 it doesn't need to be keyed, 1038178825Sdfr * but according to the latest draft it needs to. 1039178825Sdfr */ 1040178825Sdfr if ( 1041178825Sdfr#if 0 1042178825Sdfr!krb5_checksum_is_keyed(context, auth->cksum->cksumtype) 1043178825Sdfr || 1044178825Sdfr#endif 1045178825Sdfr !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) { 1046233294Sstas kdc_log(context, config, 0, "Bad checksum type in authenticator: %d", 1047178825Sdfr auth->cksum->cksumtype); 1048178825Sdfr ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 1049178825Sdfr goto out; 1050178825Sdfr } 1051233294Sstas 1052178825Sdfr /* XXX should not re-encode this */ 1053178825Sdfr ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret); 1054178825Sdfr if(ret){ 1055233294Sstas const char *msg = krb5_get_error_message(context, ret); 1056233294Sstas kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg); 1057233294Sstas krb5_free_error_message(context, msg); 1058178825Sdfr goto out; 1059178825Sdfr } 1060178825Sdfr if(buf_size != len) { 1061178825Sdfr free(buf); 1062178825Sdfr kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); 1063178825Sdfr *e_text = "KDC internal error"; 1064178825Sdfr ret = KRB5KRB_ERR_GENERIC; 1065178825Sdfr goto out; 1066178825Sdfr } 1067178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 1068178825Sdfr if (ret) { 1069233294Sstas const char *msg = krb5_get_error_message(context, ret); 1070178825Sdfr free(buf); 1071233294Sstas kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); 1072233294Sstas krb5_free_error_message(context, msg); 1073178825Sdfr goto out; 1074178825Sdfr } 1075178825Sdfr ret = krb5_verify_checksum(context, 1076178825Sdfr crypto, 1077178825Sdfr KRB5_KU_TGS_REQ_AUTH_CKSUM, 1078233294Sstas buf, 1079178825Sdfr len, 1080178825Sdfr auth->cksum); 1081178825Sdfr free(buf); 1082178825Sdfr krb5_crypto_destroy(context, crypto); 1083178825Sdfr if(ret){ 1084233294Sstas const char *msg = krb5_get_error_message(context, ret); 1085178825Sdfr kdc_log(context, config, 0, 1086233294Sstas "Failed to verify authenticator checksum: %s", msg); 1087233294Sstas krb5_free_error_message(context, msg); 1088178825Sdfr } 1089178825Sdfrout: 1090178825Sdfr free_Authenticator(auth); 1091178825Sdfr free(auth); 1092178825Sdfr return ret; 1093178825Sdfr} 1094178825Sdfr 1095178825Sdfr/* 1096178825Sdfr * 1097178825Sdfr */ 1098178825Sdfr 1099178825Sdfrstatic const char * 1100178825Sdfrfind_rpath(krb5_context context, Realm crealm, Realm srealm) 1101178825Sdfr{ 1102178825Sdfr const char *new_realm = krb5_config_get_string(context, 1103178825Sdfr NULL, 1104233294Sstas "capaths", 1105178825Sdfr crealm, 1106178825Sdfr srealm, 1107178825Sdfr NULL); 1108178825Sdfr return new_realm; 1109178825Sdfr} 1110178825Sdfr 1111233294Sstas 1112178825Sdfrstatic krb5_boolean 1113233294Sstasneed_referral(krb5_context context, krb5_kdc_configuration *config, 1114233294Sstas const KDCOptions * const options, krb5_principal server, 1115233294Sstas krb5_realm **realms) 1116178825Sdfr{ 1117233294Sstas const char *name; 1118233294Sstas 1119233294Sstas if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST) 1120178825Sdfr return FALSE; 1121233294Sstas 1122233294Sstas if (server->name.name_string.len == 1) 1123233294Sstas name = server->name.name_string.val[0]; 1124233294Sstas else if (server->name.name_string.len > 1) 1125233294Sstas name = server->name.name_string.val[1]; 1126233294Sstas else 1127233294Sstas return FALSE; 1128233294Sstas 1129233294Sstas kdc_log(context, config, 0, "Searching referral for %s", name); 1130233294Sstas 1131233294Sstas return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0; 1132178825Sdfr} 1133178825Sdfr 1134178825Sdfrstatic krb5_error_code 1135233294Sstastgs_parse_request(krb5_context context, 1136178825Sdfr krb5_kdc_configuration *config, 1137178825Sdfr KDC_REQ_BODY *b, 1138178825Sdfr const PA_DATA *tgs_req, 1139178825Sdfr hdb_entry_ex **krbtgt, 1140178825Sdfr krb5_enctype *krbtgt_etype, 1141178825Sdfr krb5_ticket **ticket, 1142178825Sdfr const char **e_text, 1143178825Sdfr const char *from, 1144178825Sdfr const struct sockaddr *from_addr, 1145178825Sdfr time_t **csec, 1146178825Sdfr int **cusec, 1147233294Sstas AuthorizationData **auth_data, 1148233294Sstas krb5_keyblock **replykey, 1149233294Sstas int *rk_is_subkey) 1150178825Sdfr{ 1151233294Sstas static char failed[] = "<unparse_name failed>"; 1152178825Sdfr krb5_ap_req ap_req; 1153178825Sdfr krb5_error_code ret; 1154178825Sdfr krb5_principal princ; 1155178825Sdfr krb5_auth_context ac = NULL; 1156178825Sdfr krb5_flags ap_req_options; 1157178825Sdfr krb5_flags verify_ap_req_flags; 1158178825Sdfr krb5_crypto crypto; 1159178825Sdfr Key *tkey; 1160233294Sstas krb5_keyblock *subkey = NULL; 1161233294Sstas unsigned usage; 1162178825Sdfr 1163178825Sdfr *auth_data = NULL; 1164178825Sdfr *csec = NULL; 1165178825Sdfr *cusec = NULL; 1166233294Sstas *replykey = NULL; 1167178825Sdfr 1168178825Sdfr memset(&ap_req, 0, sizeof(ap_req)); 1169178825Sdfr ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req); 1170178825Sdfr if(ret){ 1171233294Sstas const char *msg = krb5_get_error_message(context, ret); 1172233294Sstas kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg); 1173233294Sstas krb5_free_error_message(context, msg); 1174178825Sdfr goto out; 1175178825Sdfr } 1176178825Sdfr 1177178825Sdfr if(!get_krbtgt_realm(&ap_req.ticket.sname)){ 1178178825Sdfr /* XXX check for ticket.sname == req.sname */ 1179178825Sdfr kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket"); 1180178825Sdfr ret = KRB5KDC_ERR_POLICY; /* ? */ 1181178825Sdfr goto out; 1182178825Sdfr } 1183233294Sstas 1184178825Sdfr _krb5_principalname2krb5_principal(context, 1185178825Sdfr &princ, 1186178825Sdfr ap_req.ticket.sname, 1187178825Sdfr ap_req.ticket.realm); 1188178825Sdfr 1189233294Sstas ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt); 1190233294Sstas 1191233294Sstas if(ret == HDB_ERR_NOT_FOUND_HERE) { 1192178825Sdfr char *p; 1193178825Sdfr ret = krb5_unparse_name(context, princ, &p); 1194178825Sdfr if (ret != 0) 1195233294Sstas p = failed; 1196178825Sdfr krb5_free_principal(context, princ); 1197233294Sstas kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p); 1198233294Sstas if (ret == 0) 1199233294Sstas free(p); 1200233294Sstas ret = HDB_ERR_NOT_FOUND_HERE; 1201233294Sstas goto out; 1202233294Sstas } else if(ret){ 1203233294Sstas const char *msg = krb5_get_error_message(context, ret); 1204233294Sstas char *p; 1205233294Sstas ret = krb5_unparse_name(context, princ, &p); 1206233294Sstas if (ret != 0) 1207233294Sstas p = failed; 1208233294Sstas krb5_free_principal(context, princ); 1209178825Sdfr kdc_log(context, config, 0, 1210233294Sstas "Ticket-granting ticket not found in database: %s", msg); 1211233294Sstas krb5_free_error_message(context, msg); 1212178825Sdfr if (ret == 0) 1213178825Sdfr free(p); 1214178825Sdfr ret = KRB5KRB_AP_ERR_NOT_US; 1215178825Sdfr goto out; 1216178825Sdfr } 1217233294Sstas 1218233294Sstas if(ap_req.ticket.enc_part.kvno && 1219178825Sdfr *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){ 1220178825Sdfr char *p; 1221178825Sdfr 1222178825Sdfr ret = krb5_unparse_name (context, princ, &p); 1223178825Sdfr krb5_free_principal(context, princ); 1224178825Sdfr if (ret != 0) 1225233294Sstas p = failed; 1226178825Sdfr kdc_log(context, config, 0, 1227233294Sstas "Ticket kvno = %d, DB kvno = %d (%s)", 1228178825Sdfr *ap_req.ticket.enc_part.kvno, 1229178825Sdfr (*krbtgt)->entry.kvno, 1230178825Sdfr p); 1231178825Sdfr if (ret == 0) 1232178825Sdfr free (p); 1233178825Sdfr ret = KRB5KRB_AP_ERR_BADKEYVER; 1234178825Sdfr goto out; 1235178825Sdfr } 1236178825Sdfr 1237178825Sdfr *krbtgt_etype = ap_req.ticket.enc_part.etype; 1238178825Sdfr 1239233294Sstas ret = hdb_enctype2key(context, &(*krbtgt)->entry, 1240178825Sdfr ap_req.ticket.enc_part.etype, &tkey); 1241178825Sdfr if(ret){ 1242178825Sdfr char *str = NULL, *p = NULL; 1243178825Sdfr 1244178825Sdfr krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str); 1245178825Sdfr krb5_unparse_name(context, princ, &p); 1246178825Sdfr kdc_log(context, config, 0, 1247178825Sdfr "No server key with enctype %s found for %s", 1248178825Sdfr str ? str : "<unknown enctype>", 1249178825Sdfr p ? p : "<unparse_name failed>"); 1250178825Sdfr free(str); 1251178825Sdfr free(p); 1252178825Sdfr ret = KRB5KRB_AP_ERR_BADKEYVER; 1253178825Sdfr goto out; 1254178825Sdfr } 1255233294Sstas 1256178825Sdfr if (b->kdc_options.validate) 1257178825Sdfr verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; 1258178825Sdfr else 1259178825Sdfr verify_ap_req_flags = 0; 1260178825Sdfr 1261178825Sdfr ret = krb5_verify_ap_req2(context, 1262178825Sdfr &ac, 1263178825Sdfr &ap_req, 1264178825Sdfr princ, 1265178825Sdfr &tkey->key, 1266178825Sdfr verify_ap_req_flags, 1267178825Sdfr &ap_req_options, 1268178825Sdfr ticket, 1269178825Sdfr KRB5_KU_TGS_REQ_AUTH); 1270233294Sstas 1271178825Sdfr krb5_free_principal(context, princ); 1272178825Sdfr if(ret) { 1273233294Sstas const char *msg = krb5_get_error_message(context, ret); 1274233294Sstas kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg); 1275233294Sstas krb5_free_error_message(context, msg); 1276178825Sdfr goto out; 1277178825Sdfr } 1278178825Sdfr 1279178825Sdfr { 1280178825Sdfr krb5_authenticator auth; 1281178825Sdfr 1282178825Sdfr ret = krb5_auth_con_getauthenticator(context, ac, &auth); 1283178825Sdfr if (ret == 0) { 1284178825Sdfr *csec = malloc(sizeof(**csec)); 1285178825Sdfr if (*csec == NULL) { 1286178825Sdfr krb5_free_authenticator(context, &auth); 1287178825Sdfr kdc_log(context, config, 0, "malloc failed"); 1288178825Sdfr goto out; 1289178825Sdfr } 1290178825Sdfr **csec = auth->ctime; 1291178825Sdfr *cusec = malloc(sizeof(**cusec)); 1292178825Sdfr if (*cusec == NULL) { 1293178825Sdfr krb5_free_authenticator(context, &auth); 1294178825Sdfr kdc_log(context, config, 0, "malloc failed"); 1295178825Sdfr goto out; 1296178825Sdfr } 1297178825Sdfr **cusec = auth->cusec; 1298178825Sdfr krb5_free_authenticator(context, &auth); 1299178825Sdfr } 1300178825Sdfr } 1301178825Sdfr 1302233294Sstas ret = tgs_check_authenticator(context, config, 1303178825Sdfr ac, b, e_text, &(*ticket)->ticket.key); 1304178825Sdfr if (ret) { 1305178825Sdfr krb5_auth_con_free(context, ac); 1306178825Sdfr goto out; 1307178825Sdfr } 1308178825Sdfr 1309233294Sstas usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; 1310233294Sstas *rk_is_subkey = 1; 1311178825Sdfr 1312233294Sstas ret = krb5_auth_con_getremotesubkey(context, ac, &subkey); 1313233294Sstas if(ret){ 1314233294Sstas const char *msg = krb5_get_error_message(context, ret); 1315233294Sstas krb5_auth_con_free(context, ac); 1316233294Sstas kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg); 1317233294Sstas krb5_free_error_message(context, msg); 1318233294Sstas goto out; 1319233294Sstas } 1320233294Sstas if(subkey == NULL){ 1321233294Sstas usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; 1322233294Sstas *rk_is_subkey = 0; 1323233294Sstas 1324233294Sstas ret = krb5_auth_con_getkey(context, ac, &subkey); 1325233294Sstas if(ret) { 1326233294Sstas const char *msg = krb5_get_error_message(context, ret); 1327178825Sdfr krb5_auth_con_free(context, ac); 1328233294Sstas kdc_log(context, config, 0, "Failed to get session key: %s", msg); 1329233294Sstas krb5_free_error_message(context, msg); 1330178825Sdfr goto out; 1331178825Sdfr } 1332233294Sstas } 1333233294Sstas if(subkey == NULL){ 1334233294Sstas krb5_auth_con_free(context, ac); 1335233294Sstas kdc_log(context, config, 0, 1336233294Sstas "Failed to get key for enc-authorization-data"); 1337233294Sstas ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1338233294Sstas goto out; 1339233294Sstas } 1340233294Sstas 1341233294Sstas *replykey = subkey; 1342233294Sstas 1343233294Sstas if (b->enc_authorization_data) { 1344233294Sstas krb5_data ad; 1345233294Sstas 1346178825Sdfr ret = krb5_crypto_init(context, subkey, 0, &crypto); 1347178825Sdfr if (ret) { 1348233294Sstas const char *msg = krb5_get_error_message(context, ret); 1349178825Sdfr krb5_auth_con_free(context, ac); 1350233294Sstas kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); 1351233294Sstas krb5_free_error_message(context, msg); 1352178825Sdfr goto out; 1353178825Sdfr } 1354178825Sdfr ret = krb5_decrypt_EncryptedData (context, 1355178825Sdfr crypto, 1356178825Sdfr usage, 1357178825Sdfr b->enc_authorization_data, 1358178825Sdfr &ad); 1359178825Sdfr krb5_crypto_destroy(context, crypto); 1360178825Sdfr if(ret){ 1361178825Sdfr krb5_auth_con_free(context, ac); 1362233294Sstas kdc_log(context, config, 0, 1363178825Sdfr "Failed to decrypt enc-authorization-data"); 1364178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1365178825Sdfr goto out; 1366178825Sdfr } 1367178825Sdfr ALLOC(*auth_data); 1368178825Sdfr if (*auth_data == NULL) { 1369178825Sdfr krb5_auth_con_free(context, ac); 1370178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1371178825Sdfr goto out; 1372178825Sdfr } 1373178825Sdfr ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL); 1374178825Sdfr if(ret){ 1375178825Sdfr krb5_auth_con_free(context, ac); 1376178825Sdfr free(*auth_data); 1377178825Sdfr *auth_data = NULL; 1378178825Sdfr kdc_log(context, config, 0, "Failed to decode authorization data"); 1379178825Sdfr ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1380178825Sdfr goto out; 1381178825Sdfr } 1382178825Sdfr } 1383178825Sdfr 1384178825Sdfr krb5_auth_con_free(context, ac); 1385233294Sstas 1386178825Sdfrout: 1387178825Sdfr free_AP_REQ(&ap_req); 1388233294Sstas 1389178825Sdfr return ret; 1390178825Sdfr} 1391178825Sdfr 1392178825Sdfrstatic krb5_error_code 1393233294Sstasbuild_server_referral(krb5_context context, 1394233294Sstas krb5_kdc_configuration *config, 1395233294Sstas krb5_crypto session, 1396233294Sstas krb5_const_realm referred_realm, 1397233294Sstas const PrincipalName *true_principal_name, 1398233294Sstas const PrincipalName *requested_principal, 1399233294Sstas krb5_data *outdata) 1400233294Sstas{ 1401233294Sstas PA_ServerReferralData ref; 1402233294Sstas krb5_error_code ret; 1403233294Sstas EncryptedData ed; 1404233294Sstas krb5_data data; 1405233294Sstas size_t size = 0; 1406233294Sstas 1407233294Sstas memset(&ref, 0, sizeof(ref)); 1408233294Sstas 1409233294Sstas if (referred_realm) { 1410233294Sstas ALLOC(ref.referred_realm); 1411233294Sstas if (ref.referred_realm == NULL) 1412233294Sstas goto eout; 1413233294Sstas *ref.referred_realm = strdup(referred_realm); 1414233294Sstas if (*ref.referred_realm == NULL) 1415233294Sstas goto eout; 1416233294Sstas } 1417233294Sstas if (true_principal_name) { 1418233294Sstas ALLOC(ref.true_principal_name); 1419233294Sstas if (ref.true_principal_name == NULL) 1420233294Sstas goto eout; 1421233294Sstas ret = copy_PrincipalName(true_principal_name, ref.true_principal_name); 1422233294Sstas if (ret) 1423233294Sstas goto eout; 1424233294Sstas } 1425233294Sstas if (requested_principal) { 1426233294Sstas ALLOC(ref.requested_principal_name); 1427233294Sstas if (ref.requested_principal_name == NULL) 1428233294Sstas goto eout; 1429233294Sstas ret = copy_PrincipalName(requested_principal, 1430233294Sstas ref.requested_principal_name); 1431233294Sstas if (ret) 1432233294Sstas goto eout; 1433233294Sstas } 1434233294Sstas 1435233294Sstas ASN1_MALLOC_ENCODE(PA_ServerReferralData, 1436233294Sstas data.data, data.length, 1437233294Sstas &ref, &size, ret); 1438233294Sstas free_PA_ServerReferralData(&ref); 1439233294Sstas if (ret) 1440233294Sstas return ret; 1441233294Sstas if (data.length != size) 1442233294Sstas krb5_abortx(context, "internal asn.1 encoder error"); 1443233294Sstas 1444233294Sstas ret = krb5_encrypt_EncryptedData(context, session, 1445233294Sstas KRB5_KU_PA_SERVER_REFERRAL, 1446233294Sstas data.data, data.length, 1447233294Sstas 0 /* kvno */, &ed); 1448233294Sstas free(data.data); 1449233294Sstas if (ret) 1450233294Sstas return ret; 1451233294Sstas 1452233294Sstas ASN1_MALLOC_ENCODE(EncryptedData, 1453233294Sstas outdata->data, outdata->length, 1454233294Sstas &ed, &size, ret); 1455233294Sstas free_EncryptedData(&ed); 1456233294Sstas if (ret) 1457233294Sstas return ret; 1458233294Sstas if (outdata->length != size) 1459233294Sstas krb5_abortx(context, "internal asn.1 encoder error"); 1460233294Sstas 1461233294Sstas return 0; 1462233294Sstaseout: 1463233294Sstas free_PA_ServerReferralData(&ref); 1464233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1465233294Sstas return ENOMEM; 1466233294Sstas} 1467233294Sstas 1468233294Sstasstatic krb5_error_code 1469233294Sstastgs_build_reply(krb5_context context, 1470178825Sdfr krb5_kdc_configuration *config, 1471233294Sstas KDC_REQ *req, 1472178825Sdfr KDC_REQ_BODY *b, 1473178825Sdfr hdb_entry_ex *krbtgt, 1474178825Sdfr krb5_enctype krbtgt_etype, 1475233294Sstas const krb5_keyblock *replykey, 1476233294Sstas int rk_is_subkey, 1477178825Sdfr krb5_ticket *ticket, 1478178825Sdfr krb5_data *reply, 1479178825Sdfr const char *from, 1480178825Sdfr const char **e_text, 1481233294Sstas AuthorizationData **auth_data, 1482233294Sstas const struct sockaddr *from_addr) 1483178825Sdfr{ 1484178825Sdfr krb5_error_code ret; 1485233294Sstas krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL; 1486233294Sstas krb5_principal krbtgt_principal = NULL; 1487233294Sstas char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL; 1488233294Sstas hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL; 1489233294Sstas HDB *clientdb, *s4u2self_impersonated_clientdb; 1490233294Sstas krb5_realm ref_realm = NULL; 1491178825Sdfr EncTicketPart *tgt = &ticket->ticket; 1492233294Sstas krb5_principals spp = NULL; 1493178825Sdfr const EncryptionKey *ekey; 1494178825Sdfr krb5_keyblock sessionkey; 1495178825Sdfr krb5_kvno kvno; 1496178825Sdfr krb5_data rspac; 1497178825Sdfr 1498233294Sstas hdb_entry_ex *krbtgt_out = NULL; 1499233294Sstas 1500233294Sstas METHOD_DATA enc_pa_data; 1501233294Sstas 1502178825Sdfr PrincipalName *s; 1503178825Sdfr Realm r; 1504178825Sdfr int nloop = 0; 1505178825Sdfr EncTicketPart adtkt; 1506178825Sdfr char opt_str[128]; 1507233294Sstas int signedpath = 0; 1508178825Sdfr 1509233294Sstas Key *tkey_check; 1510233294Sstas Key *tkey_sign; 1511233294Sstas int flags = HDB_F_FOR_TGS_REQ; 1512233294Sstas 1513178825Sdfr memset(&sessionkey, 0, sizeof(sessionkey)); 1514178825Sdfr memset(&adtkt, 0, sizeof(adtkt)); 1515178825Sdfr krb5_data_zero(&rspac); 1516233294Sstas memset(&enc_pa_data, 0, sizeof(enc_pa_data)); 1517178825Sdfr 1518178825Sdfr s = b->sname; 1519178825Sdfr r = b->realm; 1520178825Sdfr 1521233294Sstas /* 1522233294Sstas * Always to do CANON, see comment below about returned server principal (rsp). 1523233294Sstas */ 1524233294Sstas flags |= HDB_F_CANON; 1525233294Sstas 1526178825Sdfr if(b->kdc_options.enc_tkt_in_skey){ 1527178825Sdfr Ticket *t; 1528178825Sdfr hdb_entry_ex *uu; 1529178825Sdfr krb5_principal p; 1530178825Sdfr Key *uukey; 1531233294Sstas 1532233294Sstas if(b->additional_tickets == NULL || 1533178825Sdfr b->additional_tickets->len == 0){ 1534178825Sdfr ret = KRB5KDC_ERR_BADOPTION; /* ? */ 1535178825Sdfr kdc_log(context, config, 0, 1536178825Sdfr "No second ticket present in request"); 1537178825Sdfr goto out; 1538178825Sdfr } 1539178825Sdfr t = &b->additional_tickets->val[0]; 1540178825Sdfr if(!get_krbtgt_realm(&t->sname)){ 1541178825Sdfr kdc_log(context, config, 0, 1542178825Sdfr "Additional ticket is not a ticket-granting ticket"); 1543178825Sdfr ret = KRB5KDC_ERR_POLICY; 1544178825Sdfr goto out; 1545178825Sdfr } 1546178825Sdfr _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); 1547233294Sstas ret = _kdc_db_fetch(context, config, p, 1548233294Sstas HDB_F_GET_KRBTGT, t->enc_part.kvno, 1549178825Sdfr NULL, &uu); 1550178825Sdfr krb5_free_principal(context, p); 1551178825Sdfr if(ret){ 1552178825Sdfr if (ret == HDB_ERR_NOENTRY) 1553178825Sdfr ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1554178825Sdfr goto out; 1555178825Sdfr } 1556233294Sstas ret = hdb_enctype2key(context, &uu->entry, 1557178825Sdfr t->enc_part.etype, &uukey); 1558178825Sdfr if(ret){ 1559178825Sdfr _kdc_free_ent(context, uu); 1560178825Sdfr ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1561178825Sdfr goto out; 1562178825Sdfr } 1563178825Sdfr ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0); 1564178825Sdfr _kdc_free_ent(context, uu); 1565178825Sdfr if(ret) 1566178825Sdfr goto out; 1567178825Sdfr 1568178825Sdfr ret = verify_flags(context, config, &adtkt, spn); 1569178825Sdfr if (ret) 1570178825Sdfr goto out; 1571178825Sdfr 1572178825Sdfr s = &adtkt.cname; 1573178825Sdfr r = adtkt.crealm; 1574178825Sdfr } 1575178825Sdfr 1576178825Sdfr _krb5_principalname2krb5_principal(context, &sp, *s, r); 1577233294Sstas ret = krb5_unparse_name(context, sp, &spn); 1578178825Sdfr if (ret) 1579178825Sdfr goto out; 1580178825Sdfr _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); 1581178825Sdfr ret = krb5_unparse_name(context, cp, &cpn); 1582178825Sdfr if (ret) 1583178825Sdfr goto out; 1584178825Sdfr unparse_flags (KDCOptions2int(b->kdc_options), 1585178825Sdfr asn1_KDCOptions_units(), 1586178825Sdfr opt_str, sizeof(opt_str)); 1587178825Sdfr if(*opt_str) 1588178825Sdfr kdc_log(context, config, 0, 1589233294Sstas "TGS-REQ %s from %s for %s [%s]", 1590178825Sdfr cpn, from, spn, opt_str); 1591178825Sdfr else 1592178825Sdfr kdc_log(context, config, 0, 1593178825Sdfr "TGS-REQ %s from %s for %s", cpn, from, spn); 1594178825Sdfr 1595178825Sdfr /* 1596178825Sdfr * Fetch server 1597178825Sdfr */ 1598178825Sdfr 1599178825Sdfrserver_lookup: 1600233294Sstas ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags, 1601233294Sstas NULL, NULL, &server); 1602178825Sdfr 1603233294Sstas if(ret == HDB_ERR_NOT_FOUND_HERE) { 1604233294Sstas kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp); 1605233294Sstas goto out; 1606233294Sstas } else if(ret){ 1607233294Sstas const char *new_rlm, *msg; 1608178825Sdfr Realm req_rlm; 1609178825Sdfr krb5_realm *realms; 1610178825Sdfr 1611178825Sdfr if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) { 1612178825Sdfr if(nloop++ < 2) { 1613178825Sdfr new_rlm = find_rpath(context, tgt->crealm, req_rlm); 1614178825Sdfr if(new_rlm) { 1615178825Sdfr kdc_log(context, config, 5, "krbtgt for realm %s " 1616233294Sstas "not found, trying %s", 1617178825Sdfr req_rlm, new_rlm); 1618178825Sdfr krb5_free_principal(context, sp); 1619178825Sdfr free(spn); 1620233294Sstas krb5_make_principal(context, &sp, r, 1621178825Sdfr KRB5_TGS_NAME, new_rlm, NULL); 1622233294Sstas ret = krb5_unparse_name(context, sp, &spn); 1623178825Sdfr if (ret) 1624178825Sdfr goto out; 1625233294Sstas 1626233294Sstas if (ref_realm) 1627233294Sstas free(ref_realm); 1628233294Sstas ref_realm = strdup(new_rlm); 1629178825Sdfr goto server_lookup; 1630178825Sdfr } 1631178825Sdfr } 1632233294Sstas } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) { 1633178825Sdfr if (strcmp(realms[0], sp->realm) != 0) { 1634178825Sdfr kdc_log(context, config, 5, 1635178825Sdfr "Returning a referral to realm %s for " 1636178825Sdfr "server %s that was not found", 1637178825Sdfr realms[0], spn); 1638178825Sdfr krb5_free_principal(context, sp); 1639178825Sdfr free(spn); 1640178825Sdfr krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, 1641178825Sdfr realms[0], NULL); 1642178825Sdfr ret = krb5_unparse_name(context, sp, &spn); 1643178825Sdfr if (ret) 1644178825Sdfr goto out; 1645233294Sstas 1646233294Sstas if (ref_realm) 1647233294Sstas free(ref_realm); 1648233294Sstas ref_realm = strdup(realms[0]); 1649233294Sstas 1650178825Sdfr krb5_free_host_realm(context, realms); 1651178825Sdfr goto server_lookup; 1652178825Sdfr } 1653178825Sdfr krb5_free_host_realm(context, realms); 1654178825Sdfr } 1655233294Sstas msg = krb5_get_error_message(context, ret); 1656178825Sdfr kdc_log(context, config, 0, 1657233294Sstas "Server not found in database: %s: %s", spn, msg); 1658233294Sstas krb5_free_error_message(context, msg); 1659178825Sdfr if (ret == HDB_ERR_NOENTRY) 1660178825Sdfr ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1661178825Sdfr goto out; 1662178825Sdfr } 1663178825Sdfr 1664233294Sstas /* the name returned to the client depend on what was asked for, 1665233294Sstas * return canonical name if kdc_options.canonicalize was set, the 1666233294Sstas * client wants the true name of the principal, if not it just 1667233294Sstas * wants the name its asked for. 1668233294Sstas */ 1669233294Sstas 1670233294Sstas if (b->kdc_options.canonicalize) 1671233294Sstas rsp = server->entry.principal; 1672233294Sstas else 1673233294Sstas rsp = sp; 1674233294Sstas 1675233294Sstas 1676233294Sstas /* 1677233294Sstas * Select enctype, return key and kvno. 1678233294Sstas */ 1679233294Sstas 1680233294Sstas { 1681233294Sstas krb5_enctype etype; 1682233294Sstas 1683233294Sstas if(b->kdc_options.enc_tkt_in_skey) { 1684233294Sstas size_t i; 1685233294Sstas ekey = &adtkt.key; 1686233294Sstas for(i = 0; i < b->etype.len; i++) 1687233294Sstas if (b->etype.val[i] == adtkt.key.keytype) 1688233294Sstas break; 1689233294Sstas if(i == b->etype.len) { 1690233294Sstas kdc_log(context, config, 0, 1691233294Sstas "Addition ticket have not matching etypes"); 1692233294Sstas krb5_clear_error_message(context); 1693233294Sstas ret = KRB5KDC_ERR_ETYPE_NOSUPP; 1694233294Sstas goto out; 1695233294Sstas } 1696233294Sstas etype = b->etype.val[i]; 1697233294Sstas kvno = 0; 1698233294Sstas } else { 1699233294Sstas Key *skey; 1700233294Sstas 1701233294Sstas ret = _kdc_find_etype(context, 1702234027Sstas krb5_principal_is_krbtgt(context, sp) ? 1703234027Sstas config->tgt_use_strongest_session_key : 1704234027Sstas config->svc_use_strongest_session_key, FALSE, 1705233294Sstas server, b->etype.val, b->etype.len, NULL, 1706233294Sstas &skey); 1707233294Sstas if(ret) { 1708233294Sstas kdc_log(context, config, 0, 1709233294Sstas "Server (%s) has no support for etypes", spn); 1710233294Sstas goto out; 1711233294Sstas } 1712233294Sstas ekey = &skey->key; 1713233294Sstas etype = skey->key.keytype; 1714233294Sstas kvno = server->entry.kvno; 1715233294Sstas } 1716233294Sstas 1717233294Sstas ret = krb5_generate_random_keyblock(context, etype, &sessionkey); 1718233294Sstas if (ret) 1719233294Sstas goto out; 1720233294Sstas } 1721233294Sstas 1722233294Sstas /* 1723233294Sstas * Check that service is in the same realm as the krbtgt. If it's 1724233294Sstas * not the same, it's someone that is using a uni-directional trust 1725233294Sstas * backward. 1726233294Sstas */ 1727233294Sstas 1728233294Sstas /* 1729233294Sstas * Validate authoriation data 1730233294Sstas */ 1731233294Sstas 1732233294Sstas ret = hdb_enctype2key(context, &krbtgt->entry, 1733233294Sstas krbtgt_etype, &tkey_check); 1734178825Sdfr if(ret) { 1735233294Sstas kdc_log(context, config, 0, 1736233294Sstas "Failed to find key for krbtgt PAC check"); 1737233294Sstas goto out; 1738233294Sstas } 1739178825Sdfr 1740233294Sstas /* Now refetch the primary krbtgt, and get the current kvno (the 1741233294Sstas * sign check may have been on an old kvno, and the server may 1742233294Sstas * have been an incoming trust) */ 1743233294Sstas ret = krb5_make_principal(context, &krbtgt_principal, 1744233294Sstas krb5_principal_get_comp_string(context, 1745233294Sstas krbtgt->entry.principal, 1746233294Sstas 1), 1747233294Sstas KRB5_TGS_NAME, 1748233294Sstas krb5_principal_get_comp_string(context, 1749233294Sstas krbtgt->entry.principal, 1750233294Sstas 1), NULL); 1751233294Sstas if(ret) { 1752233294Sstas kdc_log(context, config, 0, 1753233294Sstas "Failed to generate krbtgt principal"); 1754233294Sstas goto out; 1755233294Sstas } 1756233294Sstas 1757233294Sstas ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out); 1758233294Sstas krb5_free_principal(context, krbtgt_principal); 1759233294Sstas if (ret) { 1760233294Sstas krb5_error_code ret2; 1761233294Sstas char *ktpn, *ktpn2; 1762233294Sstas ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn); 1763233294Sstas ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2); 1764233294Sstas kdc_log(context, config, 0, 1765233294Sstas "Request with wrong krbtgt: %s, %s not found in our database", 1766233294Sstas (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>"); 1767233294Sstas if(ret == 0) 1768233294Sstas free(ktpn); 1769233294Sstas if(ret2 == 0) 1770233294Sstas free(ktpn2); 1771233294Sstas ret = KRB5KRB_AP_ERR_NOT_US; 1772233294Sstas goto out; 1773233294Sstas } 1774233294Sstas 1775233294Sstas /* The first realm is the realm of the service, the second is 1776233294Sstas * krbtgt/<this>/@REALM component of the krbtgt DN the request was 1777233294Sstas * encrypted to. The redirection via the krbtgt_out entry allows 1778233294Sstas * the DB to possibly correct the case of the realm (Samba4 does 1779233294Sstas * this) before the strcmp() */ 1780233294Sstas if (strcmp(krb5_principal_get_realm(context, server->entry.principal), 1781233294Sstas krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) { 1782233294Sstas char *ktpn; 1783233294Sstas ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn); 1784233294Sstas kdc_log(context, config, 0, 1785233294Sstas "Request with wrong krbtgt: %s", 1786233294Sstas (ret == 0) ? ktpn : "<unknown>"); 1787233294Sstas if(ret == 0) 1788233294Sstas free(ktpn); 1789233294Sstas ret = KRB5KRB_AP_ERR_NOT_US; 1790233294Sstas } 1791233294Sstas 1792233294Sstas ret = hdb_enctype2key(context, &krbtgt_out->entry, 1793233294Sstas krbtgt_etype, &tkey_sign); 1794233294Sstas if(ret) { 1795233294Sstas kdc_log(context, config, 0, 1796233294Sstas "Failed to find key for krbtgt PAC signature"); 1797233294Sstas goto out; 1798233294Sstas } 1799233294Sstas 1800233294Sstas ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags, 1801233294Sstas NULL, &clientdb, &client); 1802233294Sstas if(ret == HDB_ERR_NOT_FOUND_HERE) { 1803233294Sstas /* This is OK, we are just trying to find out if they have 1804233294Sstas * been disabled or deleted in the meantime, missing secrets 1805233294Sstas * is OK */ 1806233294Sstas } else if(ret){ 1807233294Sstas const char *krbtgt_realm, *msg; 1808233294Sstas 1809178825Sdfr /* 1810178825Sdfr * If the client belongs to the same realm as our krbtgt, it 1811178825Sdfr * should exist in the local database. 1812178825Sdfr * 1813178825Sdfr */ 1814178825Sdfr 1815233294Sstas krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal); 1816178825Sdfr 1817178825Sdfr if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { 1818178825Sdfr if (ret == HDB_ERR_NOENTRY) 1819178825Sdfr ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1820178825Sdfr kdc_log(context, config, 1, "Client no longer in database: %s", 1821178825Sdfr cpn); 1822178825Sdfr goto out; 1823178825Sdfr } 1824178825Sdfr 1825233294Sstas msg = krb5_get_error_message(context, ret); 1826233294Sstas kdc_log(context, config, 1, "Client not found in database: %s", msg); 1827233294Sstas krb5_free_error_message(context, msg); 1828178825Sdfr } 1829233294Sstas 1830233294Sstas ret = check_PAC(context, config, cp, NULL, 1831233294Sstas client, server, krbtgt, 1832233294Sstas &tkey_check->key, &tkey_check->key, 1833233294Sstas ekey, &tkey_sign->key, 1834233294Sstas tgt, &rspac, &signedpath); 1835233294Sstas if (ret) { 1836233294Sstas const char *msg = krb5_get_error_message(context, ret); 1837178825Sdfr kdc_log(context, config, 0, 1838233294Sstas "Verify PAC failed for %s (%s) from %s with %s", 1839233294Sstas spn, cpn, from, msg); 1840233294Sstas krb5_free_error_message(context, msg); 1841178825Sdfr goto out; 1842178825Sdfr } 1843178825Sdfr 1844233294Sstas /* also check the krbtgt for signature */ 1845233294Sstas ret = check_KRB5SignedPath(context, 1846233294Sstas config, 1847233294Sstas krbtgt, 1848233294Sstas cp, 1849233294Sstas tgt, 1850233294Sstas &spp, 1851233294Sstas &signedpath); 1852233294Sstas if (ret) { 1853233294Sstas const char *msg = krb5_get_error_message(context, ret); 1854233294Sstas kdc_log(context, config, 0, 1855233294Sstas "KRB5SignedPath check failed for %s (%s) from %s with %s", 1856233294Sstas spn, cpn, from, msg); 1857233294Sstas krb5_free_error_message(context, msg); 1858233294Sstas goto out; 1859233294Sstas } 1860233294Sstas 1861178825Sdfr /* 1862233294Sstas * Process request 1863178825Sdfr */ 1864178825Sdfr 1865233294Sstas /* by default the tgt principal matches the client principal */ 1866233294Sstas tp = cp; 1867233294Sstas tpn = cpn; 1868178825Sdfr 1869178825Sdfr if (client) { 1870178825Sdfr const PA_DATA *sdata; 1871178825Sdfr int i = 0; 1872178825Sdfr 1873233294Sstas sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER); 1874178825Sdfr if (sdata) { 1875178825Sdfr krb5_crypto crypto; 1876178825Sdfr krb5_data datack; 1877178825Sdfr PA_S4U2Self self; 1878178825Sdfr const char *str; 1879178825Sdfr 1880233294Sstas ret = decode_PA_S4U2Self(sdata->padata_value.data, 1881178825Sdfr sdata->padata_value.length, 1882178825Sdfr &self, NULL); 1883178825Sdfr if (ret) { 1884178825Sdfr kdc_log(context, config, 0, "Failed to decode PA-S4U2Self"); 1885178825Sdfr goto out; 1886178825Sdfr } 1887178825Sdfr 1888178825Sdfr ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); 1889178825Sdfr if (ret) 1890178825Sdfr goto out; 1891178825Sdfr 1892178825Sdfr ret = krb5_crypto_init(context, &tgt->key, 0, &crypto); 1893178825Sdfr if (ret) { 1894233294Sstas const char *msg = krb5_get_error_message(context, ret); 1895178825Sdfr free_PA_S4U2Self(&self); 1896178825Sdfr krb5_data_free(&datack); 1897233294Sstas kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); 1898233294Sstas krb5_free_error_message(context, msg); 1899178825Sdfr goto out; 1900178825Sdfr } 1901178825Sdfr 1902178825Sdfr ret = krb5_verify_checksum(context, 1903178825Sdfr crypto, 1904178825Sdfr KRB5_KU_OTHER_CKSUM, 1905233294Sstas datack.data, 1906233294Sstas datack.length, 1907178825Sdfr &self.cksum); 1908178825Sdfr krb5_data_free(&datack); 1909178825Sdfr krb5_crypto_destroy(context, crypto); 1910178825Sdfr if (ret) { 1911233294Sstas const char *msg = krb5_get_error_message(context, ret); 1912178825Sdfr free_PA_S4U2Self(&self); 1913233294Sstas kdc_log(context, config, 0, 1914233294Sstas "krb5_verify_checksum failed for S4U2Self: %s", msg); 1915233294Sstas krb5_free_error_message(context, msg); 1916178825Sdfr goto out; 1917178825Sdfr } 1918178825Sdfr 1919178825Sdfr ret = _krb5_principalname2krb5_principal(context, 1920233294Sstas &tp, 1921178825Sdfr self.name, 1922178825Sdfr self.realm); 1923178825Sdfr free_PA_S4U2Self(&self); 1924178825Sdfr if (ret) 1925178825Sdfr goto out; 1926178825Sdfr 1927233294Sstas ret = krb5_unparse_name(context, tp, &tpn); 1928178825Sdfr if (ret) 1929178825Sdfr goto out; 1930178825Sdfr 1931233294Sstas /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */ 1932233294Sstas if(rspac.data) { 1933233294Sstas krb5_pac p = NULL; 1934233294Sstas krb5_data_free(&rspac); 1935233294Sstas ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags, 1936233294Sstas NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client); 1937233294Sstas if (ret) { 1938233294Sstas const char *msg; 1939233294Sstas 1940233294Sstas /* 1941233294Sstas * If the client belongs to the same realm as our krbtgt, it 1942233294Sstas * should exist in the local database. 1943233294Sstas * 1944233294Sstas */ 1945233294Sstas 1946233294Sstas if (ret == HDB_ERR_NOENTRY) 1947233294Sstas ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1948233294Sstas msg = krb5_get_error_message(context, ret); 1949233294Sstas kdc_log(context, config, 1, 1950233294Sstas "S2U4Self principal to impersonate %s not found in database: %s", 1951233294Sstas tpn, msg); 1952233294Sstas krb5_free_error_message(context, msg); 1953233294Sstas goto out; 1954233294Sstas } 1955233294Sstas ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p); 1956233294Sstas if (ret) { 1957233294Sstas kdc_log(context, config, 0, "PAC generation failed for -- %s", 1958233294Sstas tpn); 1959233294Sstas goto out; 1960233294Sstas } 1961233294Sstas if (p != NULL) { 1962233294Sstas ret = _krb5_pac_sign(context, p, ticket->ticket.authtime, 1963233294Sstas s4u2self_impersonated_client->entry.principal, 1964233294Sstas ekey, &tkey_sign->key, 1965233294Sstas &rspac); 1966233294Sstas krb5_pac_free(context, p); 1967233294Sstas if (ret) { 1968233294Sstas kdc_log(context, config, 0, "PAC signing failed for -- %s", 1969233294Sstas tpn); 1970233294Sstas goto out; 1971233294Sstas } 1972233294Sstas } 1973233294Sstas } 1974233294Sstas 1975178825Sdfr /* 1976178825Sdfr * Check that service doing the impersonating is 1977178825Sdfr * requesting a ticket to it-self. 1978178825Sdfr */ 1979233294Sstas ret = check_s4u2self(context, config, clientdb, client, sp); 1980233294Sstas if (ret) { 1981178825Sdfr kdc_log(context, config, 0, "S4U2Self: %s is not allowed " 1982233294Sstas "to impersonate to service " 1983178825Sdfr "(tried for user %s to service %s)", 1984233294Sstas cpn, tpn, spn); 1985178825Sdfr goto out; 1986178825Sdfr } 1987178825Sdfr 1988178825Sdfr /* 1989178825Sdfr * If the service isn't trusted for authentication to 1990178825Sdfr * delegation, remove the forward flag. 1991178825Sdfr */ 1992178825Sdfr 1993178825Sdfr if (client->entry.flags.trusted_for_delegation) { 1994178825Sdfr str = "[forwardable]"; 1995178825Sdfr } else { 1996178825Sdfr b->kdc_options.forwardable = 0; 1997178825Sdfr str = ""; 1998178825Sdfr } 1999178825Sdfr kdc_log(context, config, 0, "s4u2self %s impersonating %s to " 2000233294Sstas "service %s %s", cpn, tpn, spn, str); 2001178825Sdfr } 2002178825Sdfr } 2003178825Sdfr 2004178825Sdfr /* 2005178825Sdfr * Constrained delegation 2006178825Sdfr */ 2007178825Sdfr 2008178825Sdfr if (client != NULL 2009178825Sdfr && b->additional_tickets != NULL 2010178825Sdfr && b->additional_tickets->len != 0 2011178825Sdfr && b->kdc_options.enc_tkt_in_skey == 0) 2012178825Sdfr { 2013233294Sstas int ad_signedpath = 0; 2014178825Sdfr Key *clientkey; 2015178825Sdfr Ticket *t; 2016178825Sdfr 2017233294Sstas /* 2018233294Sstas * Require that the KDC have issued the service's krbtgt (not 2019233294Sstas * self-issued ticket with kimpersonate(1). 2020233294Sstas */ 2021233294Sstas if (!signedpath) { 2022233294Sstas ret = KRB5KDC_ERR_BADOPTION; 2023233294Sstas kdc_log(context, config, 0, 2024233294Sstas "Constrained delegation done on service ticket %s/%s", 2025233294Sstas cpn, spn); 2026233294Sstas goto out; 2027233294Sstas } 2028233294Sstas 2029178825Sdfr t = &b->additional_tickets->val[0]; 2030178825Sdfr 2031233294Sstas ret = hdb_enctype2key(context, &client->entry, 2032178825Sdfr t->enc_part.etype, &clientkey); 2033178825Sdfr if(ret){ 2034178825Sdfr ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 2035178825Sdfr goto out; 2036178825Sdfr } 2037178825Sdfr 2038178825Sdfr ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0); 2039178825Sdfr if (ret) { 2040178825Sdfr kdc_log(context, config, 0, 2041178825Sdfr "failed to decrypt ticket for " 2042233294Sstas "constrained delegation from %s to %s ", cpn, spn); 2043178825Sdfr goto out; 2044178825Sdfr } 2045178825Sdfr 2046233294Sstas ret = _krb5_principalname2krb5_principal(context, 2047233294Sstas &tp, 2048233294Sstas adtkt.cname, 2049233294Sstas adtkt.crealm); 2050233294Sstas if (ret) 2051233294Sstas goto out; 2052233294Sstas 2053233294Sstas ret = krb5_unparse_name(context, tp, &tpn); 2054233294Sstas if (ret) 2055233294Sstas goto out; 2056233294Sstas 2057233294Sstas ret = _krb5_principalname2krb5_principal(context, 2058233294Sstas &dp, 2059233294Sstas t->sname, 2060233294Sstas t->realm); 2061233294Sstas if (ret) 2062233294Sstas goto out; 2063233294Sstas 2064233294Sstas ret = krb5_unparse_name(context, dp, &dpn); 2065233294Sstas if (ret) 2066233294Sstas goto out; 2067233294Sstas 2068178825Sdfr /* check that ticket is valid */ 2069178825Sdfr if (adtkt.flags.forwardable == 0) { 2070178825Sdfr kdc_log(context, config, 0, 2071178825Sdfr "Missing forwardable flag on ticket for " 2072233294Sstas "constrained delegation from %s (%s) as %s to %s ", 2073233294Sstas cpn, dpn, tpn, spn); 2074233294Sstas ret = KRB5KDC_ERR_BADOPTION; 2075178825Sdfr goto out; 2076178825Sdfr } 2077178825Sdfr 2078233294Sstas ret = check_constrained_delegation(context, config, clientdb, 2079233294Sstas client, server, sp); 2080178825Sdfr if (ret) { 2081178825Sdfr kdc_log(context, config, 0, 2082233294Sstas "constrained delegation from %s (%s) as %s to %s not allowed", 2083233294Sstas cpn, dpn, tpn, spn); 2084178825Sdfr goto out; 2085178825Sdfr } 2086178825Sdfr 2087233294Sstas ret = verify_flags(context, config, &adtkt, tpn); 2088233294Sstas if (ret) { 2089178825Sdfr goto out; 2090233294Sstas } 2091178825Sdfr 2092233294Sstas krb5_data_free(&rspac); 2093178825Sdfr 2094233294Sstas /* 2095233294Sstas * generate the PAC for the user. 2096233294Sstas * 2097233294Sstas * TODO: pass in t->sname and t->realm and build 2098233294Sstas * a S4U_DELEGATION_INFO blob to the PAC. 2099233294Sstas */ 2100233294Sstas ret = check_PAC(context, config, tp, dp, 2101233294Sstas client, server, krbtgt, 2102233294Sstas &clientkey->key, &tkey_check->key, 2103233294Sstas ekey, &tkey_sign->key, 2104233294Sstas &adtkt, &rspac, &ad_signedpath); 2105178825Sdfr if (ret) { 2106233294Sstas const char *msg = krb5_get_error_message(context, ret); 2107233294Sstas kdc_log(context, config, 0, 2108233294Sstas "Verify delegated PAC failed to %s for client" 2109233294Sstas "%s (%s) as %s from %s with %s", 2110233294Sstas spn, cpn, dpn, tpn, from, msg); 2111233294Sstas krb5_free_error_message(context, msg); 2112178825Sdfr goto out; 2113178825Sdfr } 2114178825Sdfr 2115178825Sdfr /* 2116233294Sstas * Check that the KDC issued the user's ticket. 2117178825Sdfr */ 2118178825Sdfr ret = check_KRB5SignedPath(context, 2119178825Sdfr config, 2120178825Sdfr krbtgt, 2121233294Sstas cp, 2122178825Sdfr &adtkt, 2123233294Sstas NULL, 2124233294Sstas &ad_signedpath); 2125178825Sdfr if (ret) { 2126233294Sstas const char *msg = krb5_get_error_message(context, ret); 2127178825Sdfr kdc_log(context, config, 0, 2128178825Sdfr "KRB5SignedPath check from service %s failed " 2129233294Sstas "for delegation to %s for client %s (%s)" 2130178825Sdfr "from %s failed with %s", 2131233294Sstas spn, tpn, dpn, cpn, from, msg); 2132233294Sstas krb5_free_error_message(context, msg); 2133178825Sdfr goto out; 2134178825Sdfr } 2135178825Sdfr 2136233294Sstas if (!ad_signedpath) { 2137233294Sstas ret = KRB5KDC_ERR_BADOPTION; 2138233294Sstas kdc_log(context, config, 0, 2139233294Sstas "Ticket not signed with PAC nor SignedPath service %s failed " 2140233294Sstas "for delegation to %s for client %s (%s)" 2141233294Sstas "from %s", 2142233294Sstas spn, tpn, dpn, cpn, from); 2143233294Sstas goto out; 2144233294Sstas } 2145233294Sstas 2146178825Sdfr kdc_log(context, config, 0, "constrained delegation for %s " 2147233294Sstas "from %s (%s) to %s", tpn, cpn, dpn, spn); 2148178825Sdfr } 2149178825Sdfr 2150178825Sdfr /* 2151178825Sdfr * Check flags 2152178825Sdfr */ 2153178825Sdfr 2154233294Sstas ret = kdc_check_flags(context, config, 2155233294Sstas client, cpn, 2156233294Sstas server, spn, 2157233294Sstas FALSE); 2158178825Sdfr if(ret) 2159178825Sdfr goto out; 2160178825Sdfr 2161233294Sstas if((b->kdc_options.validate || b->kdc_options.renew) && 2162233294Sstas !krb5_principal_compare(context, 2163178825Sdfr krbtgt->entry.principal, 2164178825Sdfr server->entry.principal)){ 2165178825Sdfr kdc_log(context, config, 0, "Inconsistent request."); 2166178825Sdfr ret = KRB5KDC_ERR_SERVER_NOMATCH; 2167178825Sdfr goto out; 2168178825Sdfr } 2169178825Sdfr 2170178825Sdfr /* check for valid set of addresses */ 2171178825Sdfr if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) { 2172178825Sdfr ret = KRB5KRB_AP_ERR_BADADDR; 2173178825Sdfr kdc_log(context, config, 0, "Request from wrong address"); 2174178825Sdfr goto out; 2175178825Sdfr } 2176233294Sstas 2177178825Sdfr /* 2178233294Sstas * If this is an referral, add server referral data to the 2179233294Sstas * auth_data reply . 2180178825Sdfr */ 2181233294Sstas if (ref_realm) { 2182233294Sstas PA_DATA pa; 2183233294Sstas krb5_crypto crypto; 2184178825Sdfr 2185233294Sstas kdc_log(context, config, 0, 2186233294Sstas "Adding server referral to %s", ref_realm); 2187178825Sdfr 2188233294Sstas ret = krb5_crypto_init(context, &sessionkey, 0, &crypto); 2189178825Sdfr if (ret) 2190178825Sdfr goto out; 2191178825Sdfr 2192233294Sstas ret = build_server_referral(context, config, crypto, ref_realm, 2193233294Sstas NULL, s, &pa.padata_value); 2194233294Sstas krb5_crypto_destroy(context, crypto); 2195233294Sstas if (ret) { 2196178825Sdfr kdc_log(context, config, 0, 2197233294Sstas "Failed building server referral"); 2198178825Sdfr goto out; 2199178825Sdfr } 2200233294Sstas pa.padata_type = KRB5_PADATA_SERVER_REFERRAL; 2201178825Sdfr 2202233294Sstas ret = add_METHOD_DATA(&enc_pa_data, &pa); 2203233294Sstas krb5_data_free(&pa.padata_value); 2204178825Sdfr if (ret) { 2205178825Sdfr kdc_log(context, config, 0, 2206233294Sstas "Add server referral METHOD-DATA failed"); 2207178825Sdfr goto out; 2208178825Sdfr } 2209178825Sdfr } 2210178825Sdfr 2211178825Sdfr /* 2212178825Sdfr * 2213178825Sdfr */ 2214178825Sdfr 2215178825Sdfr ret = tgs_make_reply(context, 2216233294Sstas config, 2217233294Sstas b, 2218233294Sstas tp, 2219233294Sstas tgt, 2220233294Sstas replykey, 2221233294Sstas rk_is_subkey, 2222178825Sdfr ekey, 2223178825Sdfr &sessionkey, 2224178825Sdfr kvno, 2225233294Sstas *auth_data, 2226233294Sstas server, 2227233294Sstas rsp, 2228178825Sdfr spn, 2229233294Sstas client, 2230233294Sstas cp, 2231233294Sstas krbtgt_out, 2232178825Sdfr krbtgt_etype, 2233178825Sdfr spp, 2234178825Sdfr &rspac, 2235233294Sstas &enc_pa_data, 2236178825Sdfr e_text, 2237178825Sdfr reply); 2238233294Sstas 2239178825Sdfrout: 2240233294Sstas if (tpn != cpn) 2241233294Sstas free(tpn); 2242178825Sdfr free(spn); 2243178825Sdfr free(cpn); 2244233294Sstas if (dpn) 2245233294Sstas free(dpn); 2246233294Sstas 2247178825Sdfr krb5_data_free(&rspac); 2248178825Sdfr krb5_free_keyblock_contents(context, &sessionkey); 2249233294Sstas if(krbtgt_out) 2250233294Sstas _kdc_free_ent(context, krbtgt_out); 2251178825Sdfr if(server) 2252178825Sdfr _kdc_free_ent(context, server); 2253178825Sdfr if(client) 2254178825Sdfr _kdc_free_ent(context, client); 2255233294Sstas if(s4u2self_impersonated_client) 2256233294Sstas _kdc_free_ent(context, s4u2self_impersonated_client); 2257178825Sdfr 2258233294Sstas if (tp && tp != cp) 2259233294Sstas krb5_free_principal(context, tp); 2260178825Sdfr if (cp) 2261178825Sdfr krb5_free_principal(context, cp); 2262233294Sstas if (dp) 2263233294Sstas krb5_free_principal(context, dp); 2264178825Sdfr if (sp) 2265178825Sdfr krb5_free_principal(context, sp); 2266233294Sstas if (ref_realm) 2267233294Sstas free(ref_realm); 2268233294Sstas free_METHOD_DATA(&enc_pa_data); 2269178825Sdfr 2270178825Sdfr free_EncTicketPart(&adtkt); 2271178825Sdfr 2272178825Sdfr return ret; 2273178825Sdfr} 2274178825Sdfr 2275178825Sdfr/* 2276178825Sdfr * 2277178825Sdfr */ 2278178825Sdfr 2279178825Sdfrkrb5_error_code 2280233294Sstas_kdc_tgs_rep(krb5_context context, 2281178825Sdfr krb5_kdc_configuration *config, 2282233294Sstas KDC_REQ *req, 2283178825Sdfr krb5_data *data, 2284178825Sdfr const char *from, 2285178825Sdfr struct sockaddr *from_addr, 2286178825Sdfr int datagram_reply) 2287178825Sdfr{ 2288178825Sdfr AuthorizationData *auth_data = NULL; 2289178825Sdfr krb5_error_code ret; 2290178825Sdfr int i = 0; 2291178825Sdfr const PA_DATA *tgs_req; 2292178825Sdfr 2293178825Sdfr hdb_entry_ex *krbtgt = NULL; 2294178825Sdfr krb5_ticket *ticket = NULL; 2295178825Sdfr const char *e_text = NULL; 2296178825Sdfr krb5_enctype krbtgt_etype = ETYPE_NULL; 2297178825Sdfr 2298233294Sstas krb5_keyblock *replykey = NULL; 2299233294Sstas int rk_is_subkey = 0; 2300178825Sdfr time_t *csec = NULL; 2301178825Sdfr int *cusec = NULL; 2302178825Sdfr 2303178825Sdfr if(req->padata == NULL){ 2304178825Sdfr ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */ 2305178825Sdfr kdc_log(context, config, 0, 2306178825Sdfr "TGS-REQ from %s without PA-DATA", from); 2307178825Sdfr goto out; 2308178825Sdfr } 2309233294Sstas 2310178825Sdfr tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ); 2311178825Sdfr 2312178825Sdfr if(tgs_req == NULL){ 2313178825Sdfr ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 2314233294Sstas 2315233294Sstas kdc_log(context, config, 0, 2316178825Sdfr "TGS-REQ from %s without PA-TGS-REQ", from); 2317178825Sdfr goto out; 2318178825Sdfr } 2319233294Sstas ret = tgs_parse_request(context, config, 2320178825Sdfr &req->req_body, tgs_req, 2321178825Sdfr &krbtgt, 2322178825Sdfr &krbtgt_etype, 2323178825Sdfr &ticket, 2324178825Sdfr &e_text, 2325178825Sdfr from, from_addr, 2326178825Sdfr &csec, &cusec, 2327233294Sstas &auth_data, 2328233294Sstas &replykey, 2329233294Sstas &rk_is_subkey); 2330233294Sstas if (ret == HDB_ERR_NOT_FOUND_HERE) { 2331233294Sstas /* kdc_log() is called in tgs_parse_request() */ 2332233294Sstas goto out; 2333233294Sstas } 2334178825Sdfr if (ret) { 2335233294Sstas kdc_log(context, config, 0, 2336178825Sdfr "Failed parsing TGS-REQ from %s", from); 2337178825Sdfr goto out; 2338178825Sdfr } 2339178825Sdfr 2340178825Sdfr ret = tgs_build_reply(context, 2341178825Sdfr config, 2342178825Sdfr req, 2343178825Sdfr &req->req_body, 2344178825Sdfr krbtgt, 2345178825Sdfr krbtgt_etype, 2346233294Sstas replykey, 2347233294Sstas rk_is_subkey, 2348178825Sdfr ticket, 2349178825Sdfr data, 2350178825Sdfr from, 2351178825Sdfr &e_text, 2352233294Sstas &auth_data, 2353233294Sstas from_addr); 2354178825Sdfr if (ret) { 2355233294Sstas kdc_log(context, config, 0, 2356178825Sdfr "Failed building TGS-REP to %s", from); 2357178825Sdfr goto out; 2358178825Sdfr } 2359178825Sdfr 2360178825Sdfr /* */ 2361178825Sdfr if (datagram_reply && data->length > config->max_datagram_reply_length) { 2362178825Sdfr krb5_data_free(data); 2363178825Sdfr ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; 2364178825Sdfr e_text = "Reply packet too large"; 2365178825Sdfr } 2366178825Sdfr 2367178825Sdfrout: 2368233294Sstas if (replykey) 2369233294Sstas krb5_free_keyblock(context, replykey); 2370233294Sstas if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){ 2371178825Sdfr krb5_mk_error(context, 2372178825Sdfr ret, 2373178825Sdfr NULL, 2374178825Sdfr NULL, 2375178825Sdfr NULL, 2376178825Sdfr NULL, 2377178825Sdfr csec, 2378178825Sdfr cusec, 2379178825Sdfr data); 2380233294Sstas ret = 0; 2381178825Sdfr } 2382178825Sdfr free(csec); 2383178825Sdfr free(cusec); 2384178825Sdfr if (ticket) 2385178825Sdfr krb5_free_ticket(context, ticket); 2386178825Sdfr if(krbtgt) 2387178825Sdfr _kdc_free_ent(context, krbtgt); 2388178825Sdfr 2389178825Sdfr if (auth_data) { 2390178825Sdfr free_AuthorizationData(auth_data); 2391178825Sdfr free(auth_data); 2392178825Sdfr } 2393178825Sdfr 2394233294Sstas return ret; 2395178825Sdfr} 2396