1c19800e8SDoug Rabson /* 2c19800e8SDoug Rabson * Copyright (c) 1997-2007 Kungliga Tekniska H�gskolan 3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden). 4c19800e8SDoug Rabson * All rights reserved. 5c19800e8SDoug Rabson * 6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without 7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions 8c19800e8SDoug Rabson * are met: 9c19800e8SDoug Rabson * 10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright 11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer. 12c19800e8SDoug Rabson * 13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the 15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution. 16c19800e8SDoug Rabson * 17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors 18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software 19c19800e8SDoug Rabson * without specific prior written permission. 20c19800e8SDoug Rabson * 21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c19800e8SDoug Rabson * SUCH DAMAGE. 32c19800e8SDoug Rabson */ 33c19800e8SDoug Rabson 34c19800e8SDoug Rabson #include "kdc_locl.h" 35c19800e8SDoug Rabson 36c19800e8SDoug Rabson RCSID("$Id: krb5tgs.c 22071 2007-11-14 20:04:50Z lha $"); 37c19800e8SDoug Rabson 38c19800e8SDoug Rabson /* 39c19800e8SDoug Rabson * return the realm of a krbtgt-ticket or NULL 40c19800e8SDoug Rabson */ 41c19800e8SDoug Rabson 42c19800e8SDoug Rabson static Realm 43c19800e8SDoug Rabson get_krbtgt_realm(const PrincipalName *p) 44c19800e8SDoug Rabson { 45c19800e8SDoug Rabson if(p->name_string.len == 2 46c19800e8SDoug Rabson && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0) 47c19800e8SDoug Rabson return p->name_string.val[1]; 48c19800e8SDoug Rabson else 49c19800e8SDoug Rabson return NULL; 50c19800e8SDoug Rabson } 51c19800e8SDoug Rabson 52c19800e8SDoug Rabson /* 53c19800e8SDoug Rabson * The KDC might add a signed path to the ticket authorization data 54c19800e8SDoug Rabson * field. This is to avoid server impersonating clients and the 55c19800e8SDoug Rabson * request constrained delegation. 56c19800e8SDoug Rabson * 57c19800e8SDoug Rabson * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single 58c19800e8SDoug Rabson * entry of type KRB5SignedPath. 59c19800e8SDoug Rabson */ 60c19800e8SDoug Rabson 61c19800e8SDoug Rabson static krb5_error_code 62c19800e8SDoug Rabson find_KRB5SignedPath(krb5_context context, 63c19800e8SDoug Rabson const AuthorizationData *ad, 64c19800e8SDoug Rabson krb5_data *data) 65c19800e8SDoug Rabson { 66c19800e8SDoug Rabson AuthorizationData child; 67c19800e8SDoug Rabson krb5_error_code ret; 68c19800e8SDoug Rabson int pos; 69c19800e8SDoug Rabson 70c19800e8SDoug Rabson if (ad == NULL || ad->len == 0) 71c19800e8SDoug Rabson return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 72c19800e8SDoug Rabson 73c19800e8SDoug Rabson pos = ad->len - 1; 74c19800e8SDoug Rabson 75c19800e8SDoug Rabson if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 76c19800e8SDoug Rabson return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 77c19800e8SDoug Rabson 78c19800e8SDoug Rabson ret = decode_AuthorizationData(ad->val[pos].ad_data.data, 79c19800e8SDoug Rabson ad->val[pos].ad_data.length, 80c19800e8SDoug Rabson &child, 81c19800e8SDoug Rabson NULL); 82c19800e8SDoug Rabson if (ret) { 83c19800e8SDoug Rabson krb5_set_error_string(context, "Failed to decode " 84c19800e8SDoug Rabson "IF_RELEVANT with %d", ret); 85c19800e8SDoug Rabson return ret; 86c19800e8SDoug Rabson } 87c19800e8SDoug Rabson 88c19800e8SDoug Rabson if (child.len != 1) { 89c19800e8SDoug Rabson free_AuthorizationData(&child); 90c19800e8SDoug Rabson return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 91c19800e8SDoug Rabson } 92c19800e8SDoug Rabson 93c19800e8SDoug Rabson if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { 94c19800e8SDoug Rabson free_AuthorizationData(&child); 95c19800e8SDoug Rabson return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 96c19800e8SDoug Rabson } 97c19800e8SDoug Rabson 98c19800e8SDoug Rabson if (data) 99c19800e8SDoug Rabson ret = der_copy_octet_string(&child.val[0].ad_data, data); 100c19800e8SDoug Rabson free_AuthorizationData(&child); 101c19800e8SDoug Rabson return ret; 102c19800e8SDoug Rabson } 103c19800e8SDoug Rabson 104c19800e8SDoug Rabson krb5_error_code 105c19800e8SDoug Rabson _kdc_add_KRB5SignedPath(krb5_context context, 106c19800e8SDoug Rabson krb5_kdc_configuration *config, 107c19800e8SDoug Rabson hdb_entry_ex *krbtgt, 108c19800e8SDoug Rabson krb5_enctype enctype, 109c19800e8SDoug Rabson krb5_const_principal server, 110c19800e8SDoug Rabson KRB5SignedPathPrincipals *principals, 111c19800e8SDoug Rabson EncTicketPart *tkt) 112c19800e8SDoug Rabson { 113c19800e8SDoug Rabson krb5_error_code ret; 114c19800e8SDoug Rabson KRB5SignedPath sp; 115c19800e8SDoug Rabson krb5_data data; 116c19800e8SDoug Rabson krb5_crypto crypto = NULL; 117c19800e8SDoug Rabson size_t size; 118c19800e8SDoug Rabson 119c19800e8SDoug Rabson if (server && principals) { 120c19800e8SDoug Rabson ret = add_KRB5SignedPathPrincipals(principals, server); 121c19800e8SDoug Rabson if (ret) 122c19800e8SDoug Rabson return ret; 123c19800e8SDoug Rabson } 124c19800e8SDoug Rabson 125c19800e8SDoug Rabson { 126c19800e8SDoug Rabson KRB5SignedPathData spd; 127c19800e8SDoug Rabson 128c19800e8SDoug Rabson spd.encticket = *tkt; 129c19800e8SDoug Rabson spd.delegated = principals; 130c19800e8SDoug Rabson 131c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 132c19800e8SDoug Rabson &spd, &size, ret); 133c19800e8SDoug Rabson if (ret) 134c19800e8SDoug Rabson return ret; 135c19800e8SDoug Rabson if (data.length != size) 136c19800e8SDoug Rabson krb5_abortx(context, "internal asn.1 encoder error"); 137c19800e8SDoug Rabson } 138c19800e8SDoug Rabson 139c19800e8SDoug Rabson { 140c19800e8SDoug Rabson Key *key; 141c19800e8SDoug Rabson ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key); 142c19800e8SDoug Rabson if (ret == 0) 143c19800e8SDoug Rabson ret = krb5_crypto_init(context, &key->key, 0, &crypto); 144c19800e8SDoug Rabson if (ret) { 145c19800e8SDoug Rabson free(data.data); 146c19800e8SDoug Rabson return ret; 147c19800e8SDoug Rabson } 148c19800e8SDoug Rabson } 149c19800e8SDoug Rabson 150c19800e8SDoug Rabson /* 151c19800e8SDoug Rabson * Fill in KRB5SignedPath 152c19800e8SDoug Rabson */ 153c19800e8SDoug Rabson 154c19800e8SDoug Rabson sp.etype = enctype; 155c19800e8SDoug Rabson sp.delegated = principals; 156c19800e8SDoug Rabson 157c19800e8SDoug Rabson ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0, 158c19800e8SDoug Rabson data.data, data.length, &sp.cksum); 159c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 160c19800e8SDoug Rabson free(data.data); 161c19800e8SDoug Rabson if (ret) 162c19800e8SDoug Rabson return ret; 163c19800e8SDoug Rabson 164c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); 165c19800e8SDoug Rabson free_Checksum(&sp.cksum); 166c19800e8SDoug Rabson if (ret) 167c19800e8SDoug Rabson return ret; 168c19800e8SDoug Rabson if (data.length != size) 169c19800e8SDoug Rabson krb5_abortx(context, "internal asn.1 encoder error"); 170c19800e8SDoug Rabson 171c19800e8SDoug Rabson 172c19800e8SDoug Rabson /* 173c19800e8SDoug Rabson * Add IF-RELEVANT(KRB5SignedPath) to the last slot in 174c19800e8SDoug Rabson * authorization data field. 175c19800e8SDoug Rabson */ 176c19800e8SDoug Rabson 177c19800e8SDoug Rabson ret = _kdc_tkt_add_if_relevant_ad(context, tkt, 178c19800e8SDoug Rabson KRB5_AUTHDATA_SIGNTICKET, &data); 179c19800e8SDoug Rabson krb5_data_free(&data); 180c19800e8SDoug Rabson 181c19800e8SDoug Rabson return ret; 182c19800e8SDoug Rabson } 183c19800e8SDoug Rabson 184c19800e8SDoug Rabson static krb5_error_code 185c19800e8SDoug Rabson check_KRB5SignedPath(krb5_context context, 186c19800e8SDoug Rabson krb5_kdc_configuration *config, 187c19800e8SDoug Rabson hdb_entry_ex *krbtgt, 188c19800e8SDoug Rabson EncTicketPart *tkt, 189c19800e8SDoug Rabson KRB5SignedPathPrincipals **delegated, 190c19800e8SDoug Rabson int require_signedpath) 191c19800e8SDoug Rabson { 192c19800e8SDoug Rabson krb5_error_code ret; 193c19800e8SDoug Rabson krb5_data data; 194c19800e8SDoug Rabson krb5_crypto crypto = NULL; 195c19800e8SDoug Rabson 196c19800e8SDoug Rabson *delegated = NULL; 197c19800e8SDoug Rabson 198c19800e8SDoug Rabson ret = find_KRB5SignedPath(context, tkt->authorization_data, &data); 199c19800e8SDoug Rabson if (ret == 0) { 200c19800e8SDoug Rabson KRB5SignedPathData spd; 201c19800e8SDoug Rabson KRB5SignedPath sp; 202c19800e8SDoug Rabson AuthorizationData *ad; 203c19800e8SDoug Rabson size_t size; 204c19800e8SDoug Rabson 205c19800e8SDoug Rabson ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL); 206c19800e8SDoug Rabson krb5_data_free(&data); 207c19800e8SDoug Rabson if (ret) 208c19800e8SDoug Rabson return ret; 209c19800e8SDoug Rabson 210c19800e8SDoug Rabson spd.encticket = *tkt; 211c19800e8SDoug Rabson /* the KRB5SignedPath is the last entry */ 212c19800e8SDoug Rabson ad = spd.encticket.authorization_data; 213c19800e8SDoug Rabson if (--ad->len == 0) 214c19800e8SDoug Rabson spd.encticket.authorization_data = NULL; 215c19800e8SDoug Rabson spd.delegated = sp.delegated; 216c19800e8SDoug Rabson 217c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 218c19800e8SDoug Rabson &spd, &size, ret); 219c19800e8SDoug Rabson ad->len++; 220c19800e8SDoug Rabson spd.encticket.authorization_data = ad; 221c19800e8SDoug Rabson if (ret) { 222c19800e8SDoug Rabson free_KRB5SignedPath(&sp); 223c19800e8SDoug Rabson return ret; 224c19800e8SDoug Rabson } 225c19800e8SDoug Rabson if (data.length != size) 226c19800e8SDoug Rabson krb5_abortx(context, "internal asn.1 encoder error"); 227c19800e8SDoug Rabson 228c19800e8SDoug Rabson { 229c19800e8SDoug Rabson Key *key; 230c19800e8SDoug Rabson ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key); 231c19800e8SDoug Rabson if (ret == 0) 232c19800e8SDoug Rabson ret = krb5_crypto_init(context, &key->key, 0, &crypto); 233c19800e8SDoug Rabson if (ret) { 234c19800e8SDoug Rabson free(data.data); 235c19800e8SDoug Rabson free_KRB5SignedPath(&sp); 236c19800e8SDoug Rabson return ret; 237c19800e8SDoug Rabson } 238c19800e8SDoug Rabson } 239c19800e8SDoug Rabson ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 240c19800e8SDoug Rabson data.data, data.length, 241c19800e8SDoug Rabson &sp.cksum); 242c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 243c19800e8SDoug Rabson free(data.data); 244c19800e8SDoug Rabson if (ret) { 245c19800e8SDoug Rabson free_KRB5SignedPath(&sp); 246c19800e8SDoug Rabson return ret; 247c19800e8SDoug Rabson } 248c19800e8SDoug Rabson 249c19800e8SDoug Rabson if (sp.delegated) { 250c19800e8SDoug Rabson 251c19800e8SDoug Rabson *delegated = malloc(sizeof(*sp.delegated)); 252c19800e8SDoug Rabson if (*delegated == NULL) { 253c19800e8SDoug Rabson free_KRB5SignedPath(&sp); 254c19800e8SDoug Rabson return ENOMEM; 255c19800e8SDoug Rabson } 256c19800e8SDoug Rabson 257c19800e8SDoug Rabson ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated); 258c19800e8SDoug Rabson if (ret) { 259c19800e8SDoug Rabson free_KRB5SignedPath(&sp); 260c19800e8SDoug Rabson free(*delegated); 261c19800e8SDoug Rabson *delegated = NULL; 262c19800e8SDoug Rabson return ret; 263c19800e8SDoug Rabson } 264c19800e8SDoug Rabson } 265c19800e8SDoug Rabson free_KRB5SignedPath(&sp); 266c19800e8SDoug Rabson 267c19800e8SDoug Rabson } else { 268c19800e8SDoug Rabson if (require_signedpath) 269c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 270c19800e8SDoug Rabson } 271c19800e8SDoug Rabson 272c19800e8SDoug Rabson return 0; 273c19800e8SDoug Rabson } 274c19800e8SDoug Rabson 275c19800e8SDoug Rabson /* 276c19800e8SDoug Rabson * 277c19800e8SDoug Rabson */ 278c19800e8SDoug Rabson 279c19800e8SDoug Rabson static krb5_error_code 280c19800e8SDoug Rabson check_PAC(krb5_context context, 281c19800e8SDoug Rabson krb5_kdc_configuration *config, 282c19800e8SDoug Rabson const krb5_principal client_principal, 283c19800e8SDoug Rabson hdb_entry_ex *client, 284c19800e8SDoug Rabson hdb_entry_ex *server, 285c19800e8SDoug Rabson const EncryptionKey *server_key, 286c19800e8SDoug Rabson const EncryptionKey *krbtgt_key, 287c19800e8SDoug Rabson EncTicketPart *tkt, 288c19800e8SDoug Rabson krb5_data *rspac, 289c19800e8SDoug Rabson int *require_signedpath) 290c19800e8SDoug Rabson { 291c19800e8SDoug Rabson AuthorizationData *ad = tkt->authorization_data; 292c19800e8SDoug Rabson unsigned i, j; 293c19800e8SDoug Rabson krb5_error_code ret; 294c19800e8SDoug Rabson 295c19800e8SDoug Rabson if (ad == NULL || ad->len == 0) 296c19800e8SDoug Rabson return 0; 297c19800e8SDoug Rabson 298c19800e8SDoug Rabson for (i = 0; i < ad->len; i++) { 299c19800e8SDoug Rabson AuthorizationData child; 300c19800e8SDoug Rabson 301c19800e8SDoug Rabson if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 302c19800e8SDoug Rabson continue; 303c19800e8SDoug Rabson 304c19800e8SDoug Rabson ret = decode_AuthorizationData(ad->val[i].ad_data.data, 305c19800e8SDoug Rabson ad->val[i].ad_data.length, 306c19800e8SDoug Rabson &child, 307c19800e8SDoug Rabson NULL); 308c19800e8SDoug Rabson if (ret) { 309c19800e8SDoug Rabson krb5_set_error_string(context, "Failed to decode " 310c19800e8SDoug Rabson "IF_RELEVANT with %d", ret); 311c19800e8SDoug Rabson return ret; 312c19800e8SDoug Rabson } 313c19800e8SDoug Rabson for (j = 0; j < child.len; j++) { 314c19800e8SDoug Rabson 315c19800e8SDoug Rabson if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { 316c19800e8SDoug Rabson krb5_pac pac; 317c19800e8SDoug Rabson 318c19800e8SDoug Rabson /* Found PAC */ 319c19800e8SDoug Rabson ret = krb5_pac_parse(context, 320c19800e8SDoug Rabson child.val[j].ad_data.data, 321c19800e8SDoug Rabson child.val[j].ad_data.length, 322c19800e8SDoug Rabson &pac); 323c19800e8SDoug Rabson free_AuthorizationData(&child); 324c19800e8SDoug Rabson if (ret) 325c19800e8SDoug Rabson return ret; 326c19800e8SDoug Rabson 327c19800e8SDoug Rabson ret = krb5_pac_verify(context, pac, tkt->authtime, 328c19800e8SDoug Rabson client_principal, 329c19800e8SDoug Rabson krbtgt_key, NULL); 330c19800e8SDoug Rabson if (ret) { 331c19800e8SDoug Rabson krb5_pac_free(context, pac); 332c19800e8SDoug Rabson return ret; 333c19800e8SDoug Rabson } 334c19800e8SDoug Rabson 335c19800e8SDoug Rabson ret = _kdc_pac_verify(context, client_principal, 336c19800e8SDoug Rabson client, server, &pac); 337c19800e8SDoug Rabson if (ret) { 338c19800e8SDoug Rabson krb5_pac_free(context, pac); 339c19800e8SDoug Rabson return ret; 340c19800e8SDoug Rabson } 341c19800e8SDoug Rabson *require_signedpath = 0; 342c19800e8SDoug Rabson 343c19800e8SDoug Rabson ret = _krb5_pac_sign(context, pac, tkt->authtime, 344c19800e8SDoug Rabson client_principal, 345c19800e8SDoug Rabson server_key, krbtgt_key, rspac); 346c19800e8SDoug Rabson 347c19800e8SDoug Rabson krb5_pac_free(context, pac); 348c19800e8SDoug Rabson 349c19800e8SDoug Rabson return ret; 350c19800e8SDoug Rabson } 351c19800e8SDoug Rabson } 352c19800e8SDoug Rabson free_AuthorizationData(&child); 353c19800e8SDoug Rabson } 354c19800e8SDoug Rabson return 0; 355c19800e8SDoug Rabson } 356c19800e8SDoug Rabson 357c19800e8SDoug Rabson /* 358c19800e8SDoug Rabson * 359c19800e8SDoug Rabson */ 360c19800e8SDoug Rabson 361c19800e8SDoug Rabson static krb5_error_code 362c19800e8SDoug Rabson check_tgs_flags(krb5_context context, 363c19800e8SDoug Rabson krb5_kdc_configuration *config, 364c19800e8SDoug Rabson KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et) 365c19800e8SDoug Rabson { 366c19800e8SDoug Rabson KDCOptions f = b->kdc_options; 367c19800e8SDoug Rabson 368c19800e8SDoug Rabson if(f.validate){ 369c19800e8SDoug Rabson if(!tgt->flags.invalid || tgt->starttime == NULL){ 370c19800e8SDoug Rabson kdc_log(context, config, 0, 371c19800e8SDoug Rabson "Bad request to validate ticket"); 372c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 373c19800e8SDoug Rabson } 374c19800e8SDoug Rabson if(*tgt->starttime > kdc_time){ 375c19800e8SDoug Rabson kdc_log(context, config, 0, 376c19800e8SDoug Rabson "Early request to validate ticket"); 377c19800e8SDoug Rabson return KRB5KRB_AP_ERR_TKT_NYV; 378c19800e8SDoug Rabson } 379c19800e8SDoug Rabson /* XXX tkt = tgt */ 380c19800e8SDoug Rabson et->flags.invalid = 0; 381c19800e8SDoug Rabson }else if(tgt->flags.invalid){ 382c19800e8SDoug Rabson kdc_log(context, config, 0, 383c19800e8SDoug Rabson "Ticket-granting ticket has INVALID flag set"); 384c19800e8SDoug Rabson return KRB5KRB_AP_ERR_TKT_INVALID; 385c19800e8SDoug Rabson } 386c19800e8SDoug Rabson 387c19800e8SDoug Rabson if(f.forwardable){ 388c19800e8SDoug Rabson if(!tgt->flags.forwardable){ 389c19800e8SDoug Rabson kdc_log(context, config, 0, 390c19800e8SDoug Rabson "Bad request for forwardable ticket"); 391c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 392c19800e8SDoug Rabson } 393c19800e8SDoug Rabson et->flags.forwardable = 1; 394c19800e8SDoug Rabson } 395c19800e8SDoug Rabson if(f.forwarded){ 396c19800e8SDoug Rabson if(!tgt->flags.forwardable){ 397c19800e8SDoug Rabson kdc_log(context, config, 0, 398c19800e8SDoug Rabson "Request to forward non-forwardable ticket"); 399c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 400c19800e8SDoug Rabson } 401c19800e8SDoug Rabson et->flags.forwarded = 1; 402c19800e8SDoug Rabson et->caddr = b->addresses; 403c19800e8SDoug Rabson } 404c19800e8SDoug Rabson if(tgt->flags.forwarded) 405c19800e8SDoug Rabson et->flags.forwarded = 1; 406c19800e8SDoug Rabson 407c19800e8SDoug Rabson if(f.proxiable){ 408c19800e8SDoug Rabson if(!tgt->flags.proxiable){ 409c19800e8SDoug Rabson kdc_log(context, config, 0, 410c19800e8SDoug Rabson "Bad request for proxiable ticket"); 411c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 412c19800e8SDoug Rabson } 413c19800e8SDoug Rabson et->flags.proxiable = 1; 414c19800e8SDoug Rabson } 415c19800e8SDoug Rabson if(f.proxy){ 416c19800e8SDoug Rabson if(!tgt->flags.proxiable){ 417c19800e8SDoug Rabson kdc_log(context, config, 0, 418c19800e8SDoug Rabson "Request to proxy non-proxiable ticket"); 419c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 420c19800e8SDoug Rabson } 421c19800e8SDoug Rabson et->flags.proxy = 1; 422c19800e8SDoug Rabson et->caddr = b->addresses; 423c19800e8SDoug Rabson } 424c19800e8SDoug Rabson if(tgt->flags.proxy) 425c19800e8SDoug Rabson et->flags.proxy = 1; 426c19800e8SDoug Rabson 427c19800e8SDoug Rabson if(f.allow_postdate){ 428c19800e8SDoug Rabson if(!tgt->flags.may_postdate){ 429c19800e8SDoug Rabson kdc_log(context, config, 0, 430c19800e8SDoug Rabson "Bad request for post-datable ticket"); 431c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 432c19800e8SDoug Rabson } 433c19800e8SDoug Rabson et->flags.may_postdate = 1; 434c19800e8SDoug Rabson } 435c19800e8SDoug Rabson if(f.postdated){ 436c19800e8SDoug Rabson if(!tgt->flags.may_postdate){ 437c19800e8SDoug Rabson kdc_log(context, config, 0, 438c19800e8SDoug Rabson "Bad request for postdated ticket"); 439c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 440c19800e8SDoug Rabson } 441c19800e8SDoug Rabson if(b->from) 442c19800e8SDoug Rabson *et->starttime = *b->from; 443c19800e8SDoug Rabson et->flags.postdated = 1; 444c19800e8SDoug Rabson et->flags.invalid = 1; 445c19800e8SDoug Rabson }else if(b->from && *b->from > kdc_time + context->max_skew){ 446c19800e8SDoug Rabson kdc_log(context, config, 0, "Ticket cannot be postdated"); 447c19800e8SDoug Rabson return KRB5KDC_ERR_CANNOT_POSTDATE; 448c19800e8SDoug Rabson } 449c19800e8SDoug Rabson 450c19800e8SDoug Rabson if(f.renewable){ 451c19800e8SDoug Rabson if(!tgt->flags.renewable){ 452c19800e8SDoug Rabson kdc_log(context, config, 0, 453c19800e8SDoug Rabson "Bad request for renewable ticket"); 454c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 455c19800e8SDoug Rabson } 456c19800e8SDoug Rabson et->flags.renewable = 1; 457c19800e8SDoug Rabson ALLOC(et->renew_till); 458c19800e8SDoug Rabson _kdc_fix_time(&b->rtime); 459c19800e8SDoug Rabson *et->renew_till = *b->rtime; 460c19800e8SDoug Rabson } 461c19800e8SDoug Rabson if(f.renew){ 462c19800e8SDoug Rabson time_t old_life; 463c19800e8SDoug Rabson if(!tgt->flags.renewable || tgt->renew_till == NULL){ 464c19800e8SDoug Rabson kdc_log(context, config, 0, 465c19800e8SDoug Rabson "Request to renew non-renewable ticket"); 466c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 467c19800e8SDoug Rabson } 468c19800e8SDoug Rabson old_life = tgt->endtime; 469c19800e8SDoug Rabson if(tgt->starttime) 470c19800e8SDoug Rabson old_life -= *tgt->starttime; 471c19800e8SDoug Rabson else 472c19800e8SDoug Rabson old_life -= tgt->authtime; 473c19800e8SDoug Rabson et->endtime = *et->starttime + old_life; 474c19800e8SDoug Rabson if (et->renew_till != NULL) 475c19800e8SDoug Rabson et->endtime = min(*et->renew_till, et->endtime); 476c19800e8SDoug Rabson } 477c19800e8SDoug Rabson 478c19800e8SDoug Rabson #if 0 479c19800e8SDoug Rabson /* checks for excess flags */ 480c19800e8SDoug Rabson if(f.request_anonymous && !config->allow_anonymous){ 481c19800e8SDoug Rabson kdc_log(context, config, 0, 482c19800e8SDoug Rabson "Request for anonymous ticket"); 483c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 484c19800e8SDoug Rabson } 485c19800e8SDoug Rabson #endif 486c19800e8SDoug Rabson return 0; 487c19800e8SDoug Rabson } 488c19800e8SDoug Rabson 489c19800e8SDoug Rabson /* 490c19800e8SDoug Rabson * 491c19800e8SDoug Rabson */ 492c19800e8SDoug Rabson 493c19800e8SDoug Rabson static krb5_error_code 494c19800e8SDoug Rabson check_constrained_delegation(krb5_context context, 495c19800e8SDoug Rabson krb5_kdc_configuration *config, 496c19800e8SDoug Rabson hdb_entry_ex *client, 497c19800e8SDoug Rabson krb5_const_principal server) 498c19800e8SDoug Rabson { 499c19800e8SDoug Rabson const HDB_Ext_Constrained_delegation_acl *acl; 500c19800e8SDoug Rabson krb5_error_code ret; 501c19800e8SDoug Rabson int i; 502c19800e8SDoug Rabson 503c19800e8SDoug Rabson ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl); 504c19800e8SDoug Rabson if (ret) { 505c19800e8SDoug Rabson krb5_clear_error_string(context); 506c19800e8SDoug Rabson return ret; 507c19800e8SDoug Rabson } 508c19800e8SDoug Rabson 509c19800e8SDoug Rabson if (acl) { 510c19800e8SDoug Rabson for (i = 0; i < acl->len; i++) { 511c19800e8SDoug Rabson if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE) 512c19800e8SDoug Rabson return 0; 513c19800e8SDoug Rabson } 514c19800e8SDoug Rabson } 515c19800e8SDoug Rabson kdc_log(context, config, 0, 516c19800e8SDoug Rabson "Bad request for constrained delegation"); 517c19800e8SDoug Rabson return KRB5KDC_ERR_BADOPTION; 518c19800e8SDoug Rabson } 519c19800e8SDoug Rabson 520c19800e8SDoug Rabson /* 521c19800e8SDoug Rabson * 522c19800e8SDoug Rabson */ 523c19800e8SDoug Rabson 524c19800e8SDoug Rabson static krb5_error_code 525c19800e8SDoug Rabson verify_flags (krb5_context context, 526c19800e8SDoug Rabson krb5_kdc_configuration *config, 527c19800e8SDoug Rabson const EncTicketPart *et, 528c19800e8SDoug Rabson const char *pstr) 529c19800e8SDoug Rabson { 530c19800e8SDoug Rabson if(et->endtime < kdc_time){ 531c19800e8SDoug Rabson kdc_log(context, config, 0, "Ticket expired (%s)", pstr); 532c19800e8SDoug Rabson return KRB5KRB_AP_ERR_TKT_EXPIRED; 533c19800e8SDoug Rabson } 534c19800e8SDoug Rabson if(et->flags.invalid){ 535c19800e8SDoug Rabson kdc_log(context, config, 0, "Ticket not valid (%s)", pstr); 536c19800e8SDoug Rabson return KRB5KRB_AP_ERR_TKT_NYV; 537c19800e8SDoug Rabson } 538c19800e8SDoug Rabson return 0; 539c19800e8SDoug Rabson } 540c19800e8SDoug Rabson 541c19800e8SDoug Rabson /* 542c19800e8SDoug Rabson * 543c19800e8SDoug Rabson */ 544c19800e8SDoug Rabson 545c19800e8SDoug Rabson static krb5_error_code 546c19800e8SDoug Rabson fix_transited_encoding(krb5_context context, 547c19800e8SDoug Rabson krb5_kdc_configuration *config, 548c19800e8SDoug Rabson krb5_boolean check_policy, 549c19800e8SDoug Rabson const TransitedEncoding *tr, 550c19800e8SDoug Rabson EncTicketPart *et, 551c19800e8SDoug Rabson const char *client_realm, 552c19800e8SDoug Rabson const char *server_realm, 553c19800e8SDoug Rabson const char *tgt_realm) 554c19800e8SDoug Rabson { 555c19800e8SDoug Rabson krb5_error_code ret = 0; 556c19800e8SDoug Rabson char **realms, **tmp; 557c19800e8SDoug Rabson int num_realms; 558c19800e8SDoug Rabson int i; 559c19800e8SDoug Rabson 560c19800e8SDoug Rabson switch (tr->tr_type) { 561c19800e8SDoug Rabson case DOMAIN_X500_COMPRESS: 562c19800e8SDoug Rabson break; 563c19800e8SDoug Rabson case 0: 564c19800e8SDoug Rabson /* 565c19800e8SDoug Rabson * Allow empty content of type 0 because that is was Microsoft 566c19800e8SDoug Rabson * generates in their TGT. 567c19800e8SDoug Rabson */ 568c19800e8SDoug Rabson if (tr->contents.length == 0) 569c19800e8SDoug Rabson break; 570c19800e8SDoug Rabson kdc_log(context, config, 0, 571c19800e8SDoug Rabson "Transited type 0 with non empty content"); 572c19800e8SDoug Rabson return KRB5KDC_ERR_TRTYPE_NOSUPP; 573c19800e8SDoug Rabson default: 574c19800e8SDoug Rabson kdc_log(context, config, 0, 575c19800e8SDoug Rabson "Unknown transited type: %u", tr->tr_type); 576c19800e8SDoug Rabson return KRB5KDC_ERR_TRTYPE_NOSUPP; 577c19800e8SDoug Rabson } 578c19800e8SDoug Rabson 579c19800e8SDoug Rabson ret = krb5_domain_x500_decode(context, 580c19800e8SDoug Rabson tr->contents, 581c19800e8SDoug Rabson &realms, 582c19800e8SDoug Rabson &num_realms, 583c19800e8SDoug Rabson client_realm, 584c19800e8SDoug Rabson server_realm); 585c19800e8SDoug Rabson if(ret){ 586c19800e8SDoug Rabson krb5_warn(context, ret, 587c19800e8SDoug Rabson "Decoding transited encoding"); 588c19800e8SDoug Rabson return ret; 589c19800e8SDoug Rabson } 590c19800e8SDoug Rabson if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) { 591c19800e8SDoug Rabson /* not us, so add the previous realm to transited set */ 592c19800e8SDoug Rabson if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) { 593c19800e8SDoug Rabson ret = ERANGE; 594c19800e8SDoug Rabson goto free_realms; 595c19800e8SDoug Rabson } 596c19800e8SDoug Rabson tmp = realloc(realms, (num_realms + 1) * sizeof(*realms)); 597c19800e8SDoug Rabson if(tmp == NULL){ 598c19800e8SDoug Rabson ret = ENOMEM; 599c19800e8SDoug Rabson goto free_realms; 600c19800e8SDoug Rabson } 601c19800e8SDoug Rabson realms = tmp; 602c19800e8SDoug Rabson realms[num_realms] = strdup(tgt_realm); 603c19800e8SDoug Rabson if(realms[num_realms] == NULL){ 604c19800e8SDoug Rabson ret = ENOMEM; 605c19800e8SDoug Rabson goto free_realms; 606c19800e8SDoug Rabson } 607c19800e8SDoug Rabson num_realms++; 608c19800e8SDoug Rabson } 609c19800e8SDoug Rabson if(num_realms == 0) { 610c19800e8SDoug Rabson if(strcmp(client_realm, server_realm)) 611c19800e8SDoug Rabson kdc_log(context, config, 0, 612c19800e8SDoug Rabson "cross-realm %s -> %s", client_realm, server_realm); 613c19800e8SDoug Rabson } else { 614c19800e8SDoug Rabson size_t l = 0; 615c19800e8SDoug Rabson char *rs; 616c19800e8SDoug Rabson for(i = 0; i < num_realms; i++) 617c19800e8SDoug Rabson l += strlen(realms[i]) + 2; 618c19800e8SDoug Rabson rs = malloc(l); 619c19800e8SDoug Rabson if(rs != NULL) { 620c19800e8SDoug Rabson *rs = '\0'; 621c19800e8SDoug Rabson for(i = 0; i < num_realms; i++) { 622c19800e8SDoug Rabson if(i > 0) 623c19800e8SDoug Rabson strlcat(rs, ", ", l); 624c19800e8SDoug Rabson strlcat(rs, realms[i], l); 625c19800e8SDoug Rabson } 626c19800e8SDoug Rabson kdc_log(context, config, 0, 627c19800e8SDoug Rabson "cross-realm %s -> %s via [%s]", 628c19800e8SDoug Rabson client_realm, server_realm, rs); 629c19800e8SDoug Rabson free(rs); 630c19800e8SDoug Rabson } 631c19800e8SDoug Rabson } 632c19800e8SDoug Rabson if(check_policy) { 633c19800e8SDoug Rabson ret = krb5_check_transited(context, client_realm, 634c19800e8SDoug Rabson server_realm, 635c19800e8SDoug Rabson realms, num_realms, NULL); 636c19800e8SDoug Rabson if(ret) { 637c19800e8SDoug Rabson krb5_warn(context, ret, "cross-realm %s -> %s", 638c19800e8SDoug Rabson client_realm, server_realm); 639c19800e8SDoug Rabson goto free_realms; 640c19800e8SDoug Rabson } 641c19800e8SDoug Rabson et->flags.transited_policy_checked = 1; 642c19800e8SDoug Rabson } 643c19800e8SDoug Rabson et->transited.tr_type = DOMAIN_X500_COMPRESS; 644c19800e8SDoug Rabson ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents); 645c19800e8SDoug Rabson if(ret) 646c19800e8SDoug Rabson krb5_warn(context, ret, "Encoding transited encoding"); 647c19800e8SDoug Rabson free_realms: 648c19800e8SDoug Rabson for(i = 0; i < num_realms; i++) 649c19800e8SDoug Rabson free(realms[i]); 650c19800e8SDoug Rabson free(realms); 651c19800e8SDoug Rabson return ret; 652c19800e8SDoug Rabson } 653c19800e8SDoug Rabson 654c19800e8SDoug Rabson 655c19800e8SDoug Rabson static krb5_error_code 656c19800e8SDoug Rabson tgs_make_reply(krb5_context context, 657c19800e8SDoug Rabson krb5_kdc_configuration *config, 658c19800e8SDoug Rabson KDC_REQ_BODY *b, 659c19800e8SDoug Rabson krb5_const_principal tgt_name, 660c19800e8SDoug Rabson const EncTicketPart *tgt, 661c19800e8SDoug Rabson const EncryptionKey *serverkey, 662c19800e8SDoug Rabson const krb5_keyblock *sessionkey, 663c19800e8SDoug Rabson krb5_kvno kvno, 664c19800e8SDoug Rabson AuthorizationData *auth_data, 665c19800e8SDoug Rabson hdb_entry_ex *server, 666c19800e8SDoug Rabson const char *server_name, 667c19800e8SDoug Rabson hdb_entry_ex *client, 668c19800e8SDoug Rabson krb5_principal client_principal, 669c19800e8SDoug Rabson hdb_entry_ex *krbtgt, 670c19800e8SDoug Rabson krb5_enctype krbtgt_etype, 671c19800e8SDoug Rabson KRB5SignedPathPrincipals *spp, 672c19800e8SDoug Rabson const krb5_data *rspac, 673c19800e8SDoug Rabson const char **e_text, 674c19800e8SDoug Rabson krb5_data *reply) 675c19800e8SDoug Rabson { 676c19800e8SDoug Rabson KDC_REP rep; 677c19800e8SDoug Rabson EncKDCRepPart ek; 678c19800e8SDoug Rabson EncTicketPart et; 679c19800e8SDoug Rabson KDCOptions f = b->kdc_options; 680c19800e8SDoug Rabson krb5_error_code ret; 681c19800e8SDoug Rabson 682c19800e8SDoug Rabson memset(&rep, 0, sizeof(rep)); 683c19800e8SDoug Rabson memset(&et, 0, sizeof(et)); 684c19800e8SDoug Rabson memset(&ek, 0, sizeof(ek)); 685c19800e8SDoug Rabson 686c19800e8SDoug Rabson rep.pvno = 5; 687c19800e8SDoug Rabson rep.msg_type = krb_tgs_rep; 688c19800e8SDoug Rabson 689c19800e8SDoug Rabson et.authtime = tgt->authtime; 690c19800e8SDoug Rabson _kdc_fix_time(&b->till); 691c19800e8SDoug Rabson et.endtime = min(tgt->endtime, *b->till); 692c19800e8SDoug Rabson ALLOC(et.starttime); 693c19800e8SDoug Rabson *et.starttime = kdc_time; 694c19800e8SDoug Rabson 695c19800e8SDoug Rabson ret = check_tgs_flags(context, config, b, tgt, &et); 696c19800e8SDoug Rabson if(ret) 697c19800e8SDoug Rabson goto out; 698c19800e8SDoug Rabson 699c19800e8SDoug Rabson /* We should check the transited encoding if: 700c19800e8SDoug Rabson 1) the request doesn't ask not to be checked 701c19800e8SDoug Rabson 2) globally enforcing a check 702c19800e8SDoug Rabson 3) principal requires checking 703c19800e8SDoug Rabson 4) we allow non-check per-principal, but principal isn't marked as allowing this 704c19800e8SDoug Rabson 5) we don't globally allow this 705c19800e8SDoug Rabson */ 706c19800e8SDoug Rabson 707c19800e8SDoug Rabson #define GLOBAL_FORCE_TRANSITED_CHECK \ 708c19800e8SDoug Rabson (config->trpolicy == TRPOLICY_ALWAYS_CHECK) 709c19800e8SDoug Rabson #define GLOBAL_ALLOW_PER_PRINCIPAL \ 710c19800e8SDoug Rabson (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) 711c19800e8SDoug Rabson #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \ 712c19800e8SDoug Rabson (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) 713c19800e8SDoug Rabson 714c19800e8SDoug Rabson /* these will consult the database in future release */ 715c19800e8SDoug Rabson #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0 716c19800e8SDoug Rabson #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0 717c19800e8SDoug Rabson 718c19800e8SDoug Rabson ret = fix_transited_encoding(context, config, 719c19800e8SDoug Rabson !f.disable_transited_check || 720c19800e8SDoug Rabson GLOBAL_FORCE_TRANSITED_CHECK || 721c19800e8SDoug Rabson PRINCIPAL_FORCE_TRANSITED_CHECK(server) || 722c19800e8SDoug Rabson !((GLOBAL_ALLOW_PER_PRINCIPAL && 723c19800e8SDoug Rabson PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || 724c19800e8SDoug Rabson GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), 725c19800e8SDoug Rabson &tgt->transited, &et, 726c19800e8SDoug Rabson *krb5_princ_realm(context, client_principal), 727c19800e8SDoug Rabson *krb5_princ_realm(context, server->entry.principal), 728c19800e8SDoug Rabson *krb5_princ_realm(context, krbtgt->entry.principal)); 729c19800e8SDoug Rabson if(ret) 730c19800e8SDoug Rabson goto out; 731c19800e8SDoug Rabson 732c19800e8SDoug Rabson copy_Realm(krb5_princ_realm(context, server->entry.principal), 733c19800e8SDoug Rabson &rep.ticket.realm); 734c19800e8SDoug Rabson _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal); 735c19800e8SDoug Rabson copy_Realm(&tgt_name->realm, &rep.crealm); 736c19800e8SDoug Rabson /* 737c19800e8SDoug Rabson if (f.request_anonymous) 738c19800e8SDoug Rabson _kdc_make_anonymous_principalname (&rep.cname); 739c19800e8SDoug Rabson else */ 740c19800e8SDoug Rabson 741c19800e8SDoug Rabson copy_PrincipalName(&tgt_name->name, &rep.cname); 742c19800e8SDoug Rabson rep.ticket.tkt_vno = 5; 743c19800e8SDoug Rabson 744c19800e8SDoug Rabson ek.caddr = et.caddr; 745c19800e8SDoug Rabson if(et.caddr == NULL) 746c19800e8SDoug Rabson et.caddr = tgt->caddr; 747c19800e8SDoug Rabson 748c19800e8SDoug Rabson { 749c19800e8SDoug Rabson time_t life; 750c19800e8SDoug Rabson life = et.endtime - *et.starttime; 751c19800e8SDoug Rabson if(client && client->entry.max_life) 752c19800e8SDoug Rabson life = min(life, *client->entry.max_life); 753c19800e8SDoug Rabson if(server->entry.max_life) 754c19800e8SDoug Rabson life = min(life, *server->entry.max_life); 755c19800e8SDoug Rabson et.endtime = *et.starttime + life; 756c19800e8SDoug Rabson } 757c19800e8SDoug Rabson if(f.renewable_ok && tgt->flags.renewable && 758c19800e8SDoug Rabson et.renew_till == NULL && et.endtime < *b->till){ 759c19800e8SDoug Rabson et.flags.renewable = 1; 760c19800e8SDoug Rabson ALLOC(et.renew_till); 761c19800e8SDoug Rabson *et.renew_till = *b->till; 762c19800e8SDoug Rabson } 763c19800e8SDoug Rabson if(et.renew_till){ 764c19800e8SDoug Rabson time_t renew; 765c19800e8SDoug Rabson renew = *et.renew_till - et.authtime; 766c19800e8SDoug Rabson if(client && client->entry.max_renew) 767c19800e8SDoug Rabson renew = min(renew, *client->entry.max_renew); 768c19800e8SDoug Rabson if(server->entry.max_renew) 769c19800e8SDoug Rabson renew = min(renew, *server->entry.max_renew); 770c19800e8SDoug Rabson *et.renew_till = et.authtime + renew; 771c19800e8SDoug Rabson } 772c19800e8SDoug Rabson 773c19800e8SDoug Rabson if(et.renew_till){ 774c19800e8SDoug Rabson *et.renew_till = min(*et.renew_till, *tgt->renew_till); 775c19800e8SDoug Rabson *et.starttime = min(*et.starttime, *et.renew_till); 776c19800e8SDoug Rabson et.endtime = min(et.endtime, *et.renew_till); 777c19800e8SDoug Rabson } 778c19800e8SDoug Rabson 779c19800e8SDoug Rabson *et.starttime = min(*et.starttime, et.endtime); 780c19800e8SDoug Rabson 781c19800e8SDoug Rabson if(*et.starttime == et.endtime){ 782c19800e8SDoug Rabson ret = KRB5KDC_ERR_NEVER_VALID; 783c19800e8SDoug Rabson goto out; 784c19800e8SDoug Rabson } 785c19800e8SDoug Rabson if(et.renew_till && et.endtime == *et.renew_till){ 786c19800e8SDoug Rabson free(et.renew_till); 787c19800e8SDoug Rabson et.renew_till = NULL; 788c19800e8SDoug Rabson et.flags.renewable = 0; 789c19800e8SDoug Rabson } 790c19800e8SDoug Rabson 791c19800e8SDoug Rabson et.flags.pre_authent = tgt->flags.pre_authent; 792c19800e8SDoug Rabson et.flags.hw_authent = tgt->flags.hw_authent; 793c19800e8SDoug Rabson et.flags.anonymous = tgt->flags.anonymous; 794c19800e8SDoug Rabson et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate; 795c19800e8SDoug Rabson 796c19800e8SDoug Rabson if (auth_data) { 797c19800e8SDoug Rabson /* XXX Check enc-authorization-data */ 798c19800e8SDoug Rabson et.authorization_data = calloc(1, sizeof(*et.authorization_data)); 799c19800e8SDoug Rabson if (et.authorization_data == NULL) { 800c19800e8SDoug Rabson ret = ENOMEM; 801c19800e8SDoug Rabson goto out; 802c19800e8SDoug Rabson } 803c19800e8SDoug Rabson ret = copy_AuthorizationData(auth_data, et.authorization_data); 804c19800e8SDoug Rabson if (ret) 805c19800e8SDoug Rabson goto out; 806c19800e8SDoug Rabson 807c19800e8SDoug Rabson /* Filter out type KRB5SignedPath */ 808c19800e8SDoug Rabson ret = find_KRB5SignedPath(context, et.authorization_data, NULL); 809c19800e8SDoug Rabson if (ret == 0) { 810c19800e8SDoug Rabson if (et.authorization_data->len == 1) { 811c19800e8SDoug Rabson free_AuthorizationData(et.authorization_data); 812c19800e8SDoug Rabson free(et.authorization_data); 813c19800e8SDoug Rabson et.authorization_data = NULL; 814c19800e8SDoug Rabson } else { 815c19800e8SDoug Rabson AuthorizationData *ad = et.authorization_data; 816c19800e8SDoug Rabson free_AuthorizationDataElement(&ad->val[ad->len - 1]); 817c19800e8SDoug Rabson ad->len--; 818c19800e8SDoug Rabson } 819c19800e8SDoug Rabson } 820c19800e8SDoug Rabson } 821c19800e8SDoug Rabson 822c19800e8SDoug Rabson if(rspac->length) { 823c19800e8SDoug Rabson /* 824c19800e8SDoug Rabson * No not need to filter out the any PAC from the 825c19800e8SDoug Rabson * auth_data since it's signed by the KDC. 826c19800e8SDoug Rabson */ 827c19800e8SDoug Rabson ret = _kdc_tkt_add_if_relevant_ad(context, &et, 828c19800e8SDoug Rabson KRB5_AUTHDATA_WIN2K_PAC, 829c19800e8SDoug Rabson rspac); 830c19800e8SDoug Rabson if (ret) 831c19800e8SDoug Rabson goto out; 832c19800e8SDoug Rabson } 833c19800e8SDoug Rabson 834c19800e8SDoug Rabson ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); 835c19800e8SDoug Rabson if (ret) 836c19800e8SDoug Rabson goto out; 837c19800e8SDoug Rabson et.crealm = tgt->crealm; 838c19800e8SDoug Rabson et.cname = tgt_name->name; 839c19800e8SDoug Rabson 840c19800e8SDoug Rabson ek.key = et.key; 841c19800e8SDoug Rabson /* MIT must have at least one last_req */ 842c19800e8SDoug Rabson ek.last_req.len = 1; 843c19800e8SDoug Rabson ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); 844c19800e8SDoug Rabson if (ek.last_req.val == NULL) { 845c19800e8SDoug Rabson ret = ENOMEM; 846c19800e8SDoug Rabson goto out; 847c19800e8SDoug Rabson } 848c19800e8SDoug Rabson ek.nonce = b->nonce; 849c19800e8SDoug Rabson ek.flags = et.flags; 850c19800e8SDoug Rabson ek.authtime = et.authtime; 851c19800e8SDoug Rabson ek.starttime = et.starttime; 852c19800e8SDoug Rabson ek.endtime = et.endtime; 853c19800e8SDoug Rabson ek.renew_till = et.renew_till; 854c19800e8SDoug Rabson ek.srealm = rep.ticket.realm; 855c19800e8SDoug Rabson ek.sname = rep.ticket.sname; 856c19800e8SDoug Rabson 857c19800e8SDoug Rabson _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 858c19800e8SDoug Rabson et.endtime, et.renew_till); 859c19800e8SDoug Rabson 860c19800e8SDoug Rabson /* Don't sign cross realm tickets, they can't be checked anyway */ 861c19800e8SDoug Rabson { 862c19800e8SDoug Rabson char *r = get_krbtgt_realm(&ek.sname); 863c19800e8SDoug Rabson 864c19800e8SDoug Rabson if (r == NULL || strcmp(r, ek.srealm) == 0) { 865c19800e8SDoug Rabson ret = _kdc_add_KRB5SignedPath(context, 866c19800e8SDoug Rabson config, 867c19800e8SDoug Rabson krbtgt, 868c19800e8SDoug Rabson krbtgt_etype, 869c19800e8SDoug Rabson NULL, 870c19800e8SDoug Rabson spp, 871c19800e8SDoug Rabson &et); 872c19800e8SDoug Rabson if (ret) 873c19800e8SDoug Rabson goto out; 874c19800e8SDoug Rabson } 875c19800e8SDoug Rabson } 876c19800e8SDoug Rabson 877c19800e8SDoug Rabson /* It is somewhat unclear where the etype in the following 878c19800e8SDoug Rabson encryption should come from. What we have is a session 879c19800e8SDoug Rabson key in the passed tgt, and a list of preferred etypes 880c19800e8SDoug Rabson *for the new ticket*. Should we pick the best possible 881c19800e8SDoug Rabson etype, given the keytype in the tgt, or should we look 882c19800e8SDoug Rabson at the etype list here as well? What if the tgt 883c19800e8SDoug Rabson session key is DES3 and we want a ticket with a (say) 884c19800e8SDoug Rabson CAST session key. Should the DES3 etype be added to the 885c19800e8SDoug Rabson etype list, even if we don't want a session key with 886c19800e8SDoug Rabson DES3? */ 887c19800e8SDoug Rabson ret = _kdc_encode_reply(context, config, 888c19800e8SDoug Rabson &rep, &et, &ek, et.key.keytype, 889c19800e8SDoug Rabson kvno, 890c19800e8SDoug Rabson serverkey, 0, &tgt->key, e_text, reply); 891c19800e8SDoug Rabson out: 892c19800e8SDoug Rabson free_TGS_REP(&rep); 893c19800e8SDoug Rabson free_TransitedEncoding(&et.transited); 894c19800e8SDoug Rabson if(et.starttime) 895c19800e8SDoug Rabson free(et.starttime); 896c19800e8SDoug Rabson if(et.renew_till) 897c19800e8SDoug Rabson free(et.renew_till); 898c19800e8SDoug Rabson if(et.authorization_data) { 899c19800e8SDoug Rabson free_AuthorizationData(et.authorization_data); 900c19800e8SDoug Rabson free(et.authorization_data); 901c19800e8SDoug Rabson } 902c19800e8SDoug Rabson free_LastReq(&ek.last_req); 903c19800e8SDoug Rabson memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); 904c19800e8SDoug Rabson free_EncryptionKey(&et.key); 905c19800e8SDoug Rabson return ret; 906c19800e8SDoug Rabson } 907c19800e8SDoug Rabson 908c19800e8SDoug Rabson static krb5_error_code 909c19800e8SDoug Rabson tgs_check_authenticator(krb5_context context, 910c19800e8SDoug Rabson krb5_kdc_configuration *config, 911c19800e8SDoug Rabson krb5_auth_context ac, 912c19800e8SDoug Rabson KDC_REQ_BODY *b, 913c19800e8SDoug Rabson const char **e_text, 914c19800e8SDoug Rabson krb5_keyblock *key) 915c19800e8SDoug Rabson { 916c19800e8SDoug Rabson krb5_authenticator auth; 917c19800e8SDoug Rabson size_t len; 918c19800e8SDoug Rabson unsigned char *buf; 919c19800e8SDoug Rabson size_t buf_size; 920c19800e8SDoug Rabson krb5_error_code ret; 921c19800e8SDoug Rabson krb5_crypto crypto; 922c19800e8SDoug Rabson 923c19800e8SDoug Rabson krb5_auth_con_getauthenticator(context, ac, &auth); 924c19800e8SDoug Rabson if(auth->cksum == NULL){ 925c19800e8SDoug Rabson kdc_log(context, config, 0, "No authenticator in request"); 926c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 927c19800e8SDoug Rabson goto out; 928c19800e8SDoug Rabson } 929c19800e8SDoug Rabson /* 930c19800e8SDoug Rabson * according to RFC1510 it doesn't need to be keyed, 931c19800e8SDoug Rabson * but according to the latest draft it needs to. 932c19800e8SDoug Rabson */ 933c19800e8SDoug Rabson if ( 934c19800e8SDoug Rabson #if 0 935c19800e8SDoug Rabson !krb5_checksum_is_keyed(context, auth->cksum->cksumtype) 936c19800e8SDoug Rabson || 937c19800e8SDoug Rabson #endif 938c19800e8SDoug Rabson !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) { 939c19800e8SDoug Rabson kdc_log(context, config, 0, "Bad checksum type in authenticator: %d", 940c19800e8SDoug Rabson auth->cksum->cksumtype); 941c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 942c19800e8SDoug Rabson goto out; 943c19800e8SDoug Rabson } 944c19800e8SDoug Rabson 945c19800e8SDoug Rabson /* XXX should not re-encode this */ 946c19800e8SDoug Rabson ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret); 947c19800e8SDoug Rabson if(ret){ 948c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", 949c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 950c19800e8SDoug Rabson goto out; 951c19800e8SDoug Rabson } 952c19800e8SDoug Rabson if(buf_size != len) { 953c19800e8SDoug Rabson free(buf); 954c19800e8SDoug Rabson kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); 955c19800e8SDoug Rabson *e_text = "KDC internal error"; 956c19800e8SDoug Rabson ret = KRB5KRB_ERR_GENERIC; 957c19800e8SDoug Rabson goto out; 958c19800e8SDoug Rabson } 959c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto); 960c19800e8SDoug Rabson if (ret) { 961c19800e8SDoug Rabson free(buf); 962c19800e8SDoug Rabson kdc_log(context, config, 0, "krb5_crypto_init failed: %s", 963c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 964c19800e8SDoug Rabson goto out; 965c19800e8SDoug Rabson } 966c19800e8SDoug Rabson ret = krb5_verify_checksum(context, 967c19800e8SDoug Rabson crypto, 968c19800e8SDoug Rabson KRB5_KU_TGS_REQ_AUTH_CKSUM, 969c19800e8SDoug Rabson buf, 970c19800e8SDoug Rabson len, 971c19800e8SDoug Rabson auth->cksum); 972c19800e8SDoug Rabson free(buf); 973c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 974c19800e8SDoug Rabson if(ret){ 975c19800e8SDoug Rabson kdc_log(context, config, 0, 976c19800e8SDoug Rabson "Failed to verify authenticator checksum: %s", 977c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 978c19800e8SDoug Rabson } 979c19800e8SDoug Rabson out: 980c19800e8SDoug Rabson free_Authenticator(auth); 981c19800e8SDoug Rabson free(auth); 982c19800e8SDoug Rabson return ret; 983c19800e8SDoug Rabson } 984c19800e8SDoug Rabson 985c19800e8SDoug Rabson /* 986c19800e8SDoug Rabson * 987c19800e8SDoug Rabson */ 988c19800e8SDoug Rabson 989c19800e8SDoug Rabson static const char * 990c19800e8SDoug Rabson find_rpath(krb5_context context, Realm crealm, Realm srealm) 991c19800e8SDoug Rabson { 992c19800e8SDoug Rabson const char *new_realm = krb5_config_get_string(context, 993c19800e8SDoug Rabson NULL, 994c19800e8SDoug Rabson "capaths", 995c19800e8SDoug Rabson crealm, 996c19800e8SDoug Rabson srealm, 997c19800e8SDoug Rabson NULL); 998c19800e8SDoug Rabson return new_realm; 999c19800e8SDoug Rabson } 1000c19800e8SDoug Rabson 1001c19800e8SDoug Rabson 1002c19800e8SDoug Rabson static krb5_boolean 1003c19800e8SDoug Rabson need_referral(krb5_context context, krb5_principal server, krb5_realm **realms) 1004c19800e8SDoug Rabson { 1005c19800e8SDoug Rabson if(server->name.name_type != KRB5_NT_SRV_INST || 1006c19800e8SDoug Rabson server->name.name_string.len != 2) 1007c19800e8SDoug Rabson return FALSE; 1008c19800e8SDoug Rabson 1009c19800e8SDoug Rabson return _krb5_get_host_realm_int(context, server->name.name_string.val[1], 1010c19800e8SDoug Rabson FALSE, realms) == 0; 1011c19800e8SDoug Rabson } 1012c19800e8SDoug Rabson 1013c19800e8SDoug Rabson static krb5_error_code 1014c19800e8SDoug Rabson tgs_parse_request(krb5_context context, 1015c19800e8SDoug Rabson krb5_kdc_configuration *config, 1016c19800e8SDoug Rabson KDC_REQ_BODY *b, 1017c19800e8SDoug Rabson const PA_DATA *tgs_req, 1018c19800e8SDoug Rabson hdb_entry_ex **krbtgt, 1019c19800e8SDoug Rabson krb5_enctype *krbtgt_etype, 1020c19800e8SDoug Rabson krb5_ticket **ticket, 1021c19800e8SDoug Rabson const char **e_text, 1022c19800e8SDoug Rabson const char *from, 1023c19800e8SDoug Rabson const struct sockaddr *from_addr, 1024c19800e8SDoug Rabson time_t **csec, 1025c19800e8SDoug Rabson int **cusec, 1026c19800e8SDoug Rabson AuthorizationData **auth_data) 1027c19800e8SDoug Rabson { 1028c19800e8SDoug Rabson krb5_ap_req ap_req; 1029c19800e8SDoug Rabson krb5_error_code ret; 1030c19800e8SDoug Rabson krb5_principal princ; 1031c19800e8SDoug Rabson krb5_auth_context ac = NULL; 1032c19800e8SDoug Rabson krb5_flags ap_req_options; 1033c19800e8SDoug Rabson krb5_flags verify_ap_req_flags; 1034c19800e8SDoug Rabson krb5_crypto crypto; 1035c19800e8SDoug Rabson Key *tkey; 1036c19800e8SDoug Rabson 1037c19800e8SDoug Rabson *auth_data = NULL; 1038c19800e8SDoug Rabson *csec = NULL; 1039c19800e8SDoug Rabson *cusec = NULL; 1040c19800e8SDoug Rabson 1041c19800e8SDoug Rabson memset(&ap_req, 0, sizeof(ap_req)); 1042c19800e8SDoug Rabson ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req); 1043c19800e8SDoug Rabson if(ret){ 1044c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", 1045c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1046c19800e8SDoug Rabson goto out; 1047c19800e8SDoug Rabson } 1048c19800e8SDoug Rabson 1049c19800e8SDoug Rabson if(!get_krbtgt_realm(&ap_req.ticket.sname)){ 1050c19800e8SDoug Rabson /* XXX check for ticket.sname == req.sname */ 1051c19800e8SDoug Rabson kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket"); 1052c19800e8SDoug Rabson ret = KRB5KDC_ERR_POLICY; /* ? */ 1053c19800e8SDoug Rabson goto out; 1054c19800e8SDoug Rabson } 1055c19800e8SDoug Rabson 1056c19800e8SDoug Rabson _krb5_principalname2krb5_principal(context, 1057c19800e8SDoug Rabson &princ, 1058c19800e8SDoug Rabson ap_req.ticket.sname, 1059c19800e8SDoug Rabson ap_req.ticket.realm); 1060c19800e8SDoug Rabson 1061c19800e8SDoug Rabson ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt); 1062c19800e8SDoug Rabson 1063c19800e8SDoug Rabson if(ret) { 1064c19800e8SDoug Rabson char *p; 1065c19800e8SDoug Rabson ret = krb5_unparse_name(context, princ, &p); 1066c19800e8SDoug Rabson if (ret != 0) 1067c19800e8SDoug Rabson p = "<unparse_name failed>"; 1068c19800e8SDoug Rabson krb5_free_principal(context, princ); 1069c19800e8SDoug Rabson kdc_log(context, config, 0, 1070c19800e8SDoug Rabson "Ticket-granting ticket not found in database: %s: %s", 1071c19800e8SDoug Rabson p, krb5_get_err_text(context, ret)); 1072c19800e8SDoug Rabson if (ret == 0) 1073c19800e8SDoug Rabson free(p); 1074c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_NOT_US; 1075c19800e8SDoug Rabson goto out; 1076c19800e8SDoug Rabson } 1077c19800e8SDoug Rabson 1078c19800e8SDoug Rabson if(ap_req.ticket.enc_part.kvno && 1079c19800e8SDoug Rabson *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){ 1080c19800e8SDoug Rabson char *p; 1081c19800e8SDoug Rabson 1082c19800e8SDoug Rabson ret = krb5_unparse_name (context, princ, &p); 1083c19800e8SDoug Rabson krb5_free_principal(context, princ); 1084c19800e8SDoug Rabson if (ret != 0) 1085c19800e8SDoug Rabson p = "<unparse_name failed>"; 1086c19800e8SDoug Rabson kdc_log(context, config, 0, 1087c19800e8SDoug Rabson "Ticket kvno = %d, DB kvno = %d (%s)", 1088c19800e8SDoug Rabson *ap_req.ticket.enc_part.kvno, 1089c19800e8SDoug Rabson (*krbtgt)->entry.kvno, 1090c19800e8SDoug Rabson p); 1091c19800e8SDoug Rabson if (ret == 0) 1092c19800e8SDoug Rabson free (p); 1093c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BADKEYVER; 1094c19800e8SDoug Rabson goto out; 1095c19800e8SDoug Rabson } 1096c19800e8SDoug Rabson 1097c19800e8SDoug Rabson *krbtgt_etype = ap_req.ticket.enc_part.etype; 1098c19800e8SDoug Rabson 1099c19800e8SDoug Rabson ret = hdb_enctype2key(context, &(*krbtgt)->entry, 1100c19800e8SDoug Rabson ap_req.ticket.enc_part.etype, &tkey); 1101c19800e8SDoug Rabson if(ret){ 1102c19800e8SDoug Rabson char *str = NULL, *p = NULL; 1103c19800e8SDoug Rabson 1104c19800e8SDoug Rabson krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str); 1105c19800e8SDoug Rabson krb5_unparse_name(context, princ, &p); 1106c19800e8SDoug Rabson kdc_log(context, config, 0, 1107c19800e8SDoug Rabson "No server key with enctype %s found for %s", 1108c19800e8SDoug Rabson str ? str : "<unknown enctype>", 1109c19800e8SDoug Rabson p ? p : "<unparse_name failed>"); 1110c19800e8SDoug Rabson free(str); 1111c19800e8SDoug Rabson free(p); 1112c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BADKEYVER; 1113c19800e8SDoug Rabson goto out; 1114c19800e8SDoug Rabson } 1115c19800e8SDoug Rabson 1116c19800e8SDoug Rabson if (b->kdc_options.validate) 1117c19800e8SDoug Rabson verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; 1118c19800e8SDoug Rabson else 1119c19800e8SDoug Rabson verify_ap_req_flags = 0; 1120c19800e8SDoug Rabson 1121c19800e8SDoug Rabson ret = krb5_verify_ap_req2(context, 1122c19800e8SDoug Rabson &ac, 1123c19800e8SDoug Rabson &ap_req, 1124c19800e8SDoug Rabson princ, 1125c19800e8SDoug Rabson &tkey->key, 1126c19800e8SDoug Rabson verify_ap_req_flags, 1127c19800e8SDoug Rabson &ap_req_options, 1128c19800e8SDoug Rabson ticket, 1129c19800e8SDoug Rabson KRB5_KU_TGS_REQ_AUTH); 1130c19800e8SDoug Rabson 1131c19800e8SDoug Rabson krb5_free_principal(context, princ); 1132c19800e8SDoug Rabson if(ret) { 1133c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", 1134c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1135c19800e8SDoug Rabson goto out; 1136c19800e8SDoug Rabson } 1137c19800e8SDoug Rabson 1138c19800e8SDoug Rabson { 1139c19800e8SDoug Rabson krb5_authenticator auth; 1140c19800e8SDoug Rabson 1141c19800e8SDoug Rabson ret = krb5_auth_con_getauthenticator(context, ac, &auth); 1142c19800e8SDoug Rabson if (ret == 0) { 1143c19800e8SDoug Rabson *csec = malloc(sizeof(**csec)); 1144c19800e8SDoug Rabson if (*csec == NULL) { 1145c19800e8SDoug Rabson krb5_free_authenticator(context, &auth); 1146c19800e8SDoug Rabson kdc_log(context, config, 0, "malloc failed"); 1147c19800e8SDoug Rabson goto out; 1148c19800e8SDoug Rabson } 1149c19800e8SDoug Rabson **csec = auth->ctime; 1150c19800e8SDoug Rabson *cusec = malloc(sizeof(**cusec)); 1151c19800e8SDoug Rabson if (*cusec == NULL) { 1152c19800e8SDoug Rabson krb5_free_authenticator(context, &auth); 1153c19800e8SDoug Rabson kdc_log(context, config, 0, "malloc failed"); 1154c19800e8SDoug Rabson goto out; 1155c19800e8SDoug Rabson } 1156c19800e8SDoug Rabson **cusec = auth->cusec; 1157c19800e8SDoug Rabson krb5_free_authenticator(context, &auth); 1158c19800e8SDoug Rabson } 1159c19800e8SDoug Rabson } 1160c19800e8SDoug Rabson 1161c19800e8SDoug Rabson ret = tgs_check_authenticator(context, config, 1162c19800e8SDoug Rabson ac, b, e_text, &(*ticket)->ticket.key); 1163c19800e8SDoug Rabson if (ret) { 1164c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1165c19800e8SDoug Rabson goto out; 1166c19800e8SDoug Rabson } 1167c19800e8SDoug Rabson 1168c19800e8SDoug Rabson if (b->enc_authorization_data) { 1169c19800e8SDoug Rabson unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; 1170c19800e8SDoug Rabson krb5_keyblock *subkey; 1171c19800e8SDoug Rabson krb5_data ad; 1172c19800e8SDoug Rabson 1173c19800e8SDoug Rabson ret = krb5_auth_con_getremotesubkey(context, 1174c19800e8SDoug Rabson ac, 1175c19800e8SDoug Rabson &subkey); 1176c19800e8SDoug Rabson if(ret){ 1177c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1178c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to get remote subkey: %s", 1179c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1180c19800e8SDoug Rabson goto out; 1181c19800e8SDoug Rabson } 1182c19800e8SDoug Rabson if(subkey == NULL){ 1183c19800e8SDoug Rabson usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; 1184c19800e8SDoug Rabson ret = krb5_auth_con_getkey(context, ac, &subkey); 1185c19800e8SDoug Rabson if(ret) { 1186c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1187c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to get session key: %s", 1188c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1189c19800e8SDoug Rabson goto out; 1190c19800e8SDoug Rabson } 1191c19800e8SDoug Rabson } 1192c19800e8SDoug Rabson if(subkey == NULL){ 1193c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1194c19800e8SDoug Rabson kdc_log(context, config, 0, 1195c19800e8SDoug Rabson "Failed to get key for enc-authorization-data"); 1196c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1197c19800e8SDoug Rabson goto out; 1198c19800e8SDoug Rabson } 1199c19800e8SDoug Rabson ret = krb5_crypto_init(context, subkey, 0, &crypto); 1200c19800e8SDoug Rabson if (ret) { 1201c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1202c19800e8SDoug Rabson kdc_log(context, config, 0, "krb5_crypto_init failed: %s", 1203c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1204c19800e8SDoug Rabson goto out; 1205c19800e8SDoug Rabson } 1206c19800e8SDoug Rabson ret = krb5_decrypt_EncryptedData (context, 1207c19800e8SDoug Rabson crypto, 1208c19800e8SDoug Rabson usage, 1209c19800e8SDoug Rabson b->enc_authorization_data, 1210c19800e8SDoug Rabson &ad); 1211c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 1212c19800e8SDoug Rabson if(ret){ 1213c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1214c19800e8SDoug Rabson kdc_log(context, config, 0, 1215c19800e8SDoug Rabson "Failed to decrypt enc-authorization-data"); 1216c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1217c19800e8SDoug Rabson goto out; 1218c19800e8SDoug Rabson } 1219c19800e8SDoug Rabson krb5_free_keyblock(context, subkey); 1220c19800e8SDoug Rabson ALLOC(*auth_data); 1221c19800e8SDoug Rabson if (*auth_data == NULL) { 1222c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1223c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1224c19800e8SDoug Rabson goto out; 1225c19800e8SDoug Rabson } 1226c19800e8SDoug Rabson ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL); 1227c19800e8SDoug Rabson if(ret){ 1228c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1229c19800e8SDoug Rabson free(*auth_data); 1230c19800e8SDoug Rabson *auth_data = NULL; 1231c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to decode authorization data"); 1232c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1233c19800e8SDoug Rabson goto out; 1234c19800e8SDoug Rabson } 1235c19800e8SDoug Rabson } 1236c19800e8SDoug Rabson 1237c19800e8SDoug Rabson krb5_auth_con_free(context, ac); 1238c19800e8SDoug Rabson 1239c19800e8SDoug Rabson out: 1240c19800e8SDoug Rabson free_AP_REQ(&ap_req); 1241c19800e8SDoug Rabson 1242c19800e8SDoug Rabson return ret; 1243c19800e8SDoug Rabson } 1244c19800e8SDoug Rabson 1245c19800e8SDoug Rabson static krb5_error_code 1246c19800e8SDoug Rabson tgs_build_reply(krb5_context context, 1247c19800e8SDoug Rabson krb5_kdc_configuration *config, 1248c19800e8SDoug Rabson KDC_REQ *req, 1249c19800e8SDoug Rabson KDC_REQ_BODY *b, 1250c19800e8SDoug Rabson hdb_entry_ex *krbtgt, 1251c19800e8SDoug Rabson krb5_enctype krbtgt_etype, 1252c19800e8SDoug Rabson krb5_ticket *ticket, 1253c19800e8SDoug Rabson krb5_data *reply, 1254c19800e8SDoug Rabson const char *from, 1255c19800e8SDoug Rabson const char **e_text, 1256c19800e8SDoug Rabson AuthorizationData *auth_data, 1257c19800e8SDoug Rabson const struct sockaddr *from_addr, 1258c19800e8SDoug Rabson int datagram_reply) 1259c19800e8SDoug Rabson { 1260c19800e8SDoug Rabson krb5_error_code ret; 1261c19800e8SDoug Rabson krb5_principal cp = NULL, sp = NULL; 1262c19800e8SDoug Rabson krb5_principal client_principal = NULL; 1263c19800e8SDoug Rabson char *spn = NULL, *cpn = NULL; 1264c19800e8SDoug Rabson hdb_entry_ex *server = NULL, *client = NULL; 1265c19800e8SDoug Rabson EncTicketPart *tgt = &ticket->ticket; 1266c19800e8SDoug Rabson KRB5SignedPathPrincipals *spp = NULL; 1267c19800e8SDoug Rabson const EncryptionKey *ekey; 1268c19800e8SDoug Rabson krb5_keyblock sessionkey; 1269c19800e8SDoug Rabson krb5_kvno kvno; 1270c19800e8SDoug Rabson krb5_data rspac; 1271c19800e8SDoug Rabson int cross_realm = 0; 1272c19800e8SDoug Rabson 1273c19800e8SDoug Rabson PrincipalName *s; 1274c19800e8SDoug Rabson Realm r; 1275c19800e8SDoug Rabson int nloop = 0; 1276c19800e8SDoug Rabson EncTicketPart adtkt; 1277c19800e8SDoug Rabson char opt_str[128]; 1278c19800e8SDoug Rabson int require_signedpath = 0; 1279c19800e8SDoug Rabson 1280c19800e8SDoug Rabson memset(&sessionkey, 0, sizeof(sessionkey)); 1281c19800e8SDoug Rabson memset(&adtkt, 0, sizeof(adtkt)); 1282c19800e8SDoug Rabson krb5_data_zero(&rspac); 1283c19800e8SDoug Rabson 1284c19800e8SDoug Rabson s = b->sname; 1285c19800e8SDoug Rabson r = b->realm; 1286c19800e8SDoug Rabson 1287c19800e8SDoug Rabson if(b->kdc_options.enc_tkt_in_skey){ 1288c19800e8SDoug Rabson Ticket *t; 1289c19800e8SDoug Rabson hdb_entry_ex *uu; 1290c19800e8SDoug Rabson krb5_principal p; 1291c19800e8SDoug Rabson Key *uukey; 1292c19800e8SDoug Rabson 1293c19800e8SDoug Rabson if(b->additional_tickets == NULL || 1294c19800e8SDoug Rabson b->additional_tickets->len == 0){ 1295c19800e8SDoug Rabson ret = KRB5KDC_ERR_BADOPTION; /* ? */ 1296c19800e8SDoug Rabson kdc_log(context, config, 0, 1297c19800e8SDoug Rabson "No second ticket present in request"); 1298c19800e8SDoug Rabson goto out; 1299c19800e8SDoug Rabson } 1300c19800e8SDoug Rabson t = &b->additional_tickets->val[0]; 1301c19800e8SDoug Rabson if(!get_krbtgt_realm(&t->sname)){ 1302c19800e8SDoug Rabson kdc_log(context, config, 0, 1303c19800e8SDoug Rabson "Additional ticket is not a ticket-granting ticket"); 1304c19800e8SDoug Rabson ret = KRB5KDC_ERR_POLICY; 1305c19800e8SDoug Rabson goto out; 1306c19800e8SDoug Rabson } 1307c19800e8SDoug Rabson _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); 1308c19800e8SDoug Rabson ret = _kdc_db_fetch(context, config, p, 1309c19800e8SDoug Rabson HDB_F_GET_CLIENT|HDB_F_GET_SERVER, 1310c19800e8SDoug Rabson NULL, &uu); 1311c19800e8SDoug Rabson krb5_free_principal(context, p); 1312c19800e8SDoug Rabson if(ret){ 1313c19800e8SDoug Rabson if (ret == HDB_ERR_NOENTRY) 1314c19800e8SDoug Rabson ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1315c19800e8SDoug Rabson goto out; 1316c19800e8SDoug Rabson } 1317c19800e8SDoug Rabson ret = hdb_enctype2key(context, &uu->entry, 1318c19800e8SDoug Rabson t->enc_part.etype, &uukey); 1319c19800e8SDoug Rabson if(ret){ 1320c19800e8SDoug Rabson _kdc_free_ent(context, uu); 1321c19800e8SDoug Rabson ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1322c19800e8SDoug Rabson goto out; 1323c19800e8SDoug Rabson } 1324c19800e8SDoug Rabson ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0); 1325c19800e8SDoug Rabson _kdc_free_ent(context, uu); 1326c19800e8SDoug Rabson if(ret) 1327c19800e8SDoug Rabson goto out; 1328c19800e8SDoug Rabson 1329c19800e8SDoug Rabson ret = verify_flags(context, config, &adtkt, spn); 1330c19800e8SDoug Rabson if (ret) 1331c19800e8SDoug Rabson goto out; 1332c19800e8SDoug Rabson 1333c19800e8SDoug Rabson s = &adtkt.cname; 1334c19800e8SDoug Rabson r = adtkt.crealm; 1335c19800e8SDoug Rabson } 1336c19800e8SDoug Rabson 1337c19800e8SDoug Rabson _krb5_principalname2krb5_principal(context, &sp, *s, r); 1338c19800e8SDoug Rabson ret = krb5_unparse_name(context, sp, &spn); 1339c19800e8SDoug Rabson if (ret) 1340c19800e8SDoug Rabson goto out; 1341c19800e8SDoug Rabson _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); 1342c19800e8SDoug Rabson ret = krb5_unparse_name(context, cp, &cpn); 1343c19800e8SDoug Rabson if (ret) 1344c19800e8SDoug Rabson goto out; 1345c19800e8SDoug Rabson unparse_flags (KDCOptions2int(b->kdc_options), 1346c19800e8SDoug Rabson asn1_KDCOptions_units(), 1347c19800e8SDoug Rabson opt_str, sizeof(opt_str)); 1348c19800e8SDoug Rabson if(*opt_str) 1349c19800e8SDoug Rabson kdc_log(context, config, 0, 1350c19800e8SDoug Rabson "TGS-REQ %s from %s for %s [%s]", 1351c19800e8SDoug Rabson cpn, from, spn, opt_str); 1352c19800e8SDoug Rabson else 1353c19800e8SDoug Rabson kdc_log(context, config, 0, 1354c19800e8SDoug Rabson "TGS-REQ %s from %s for %s", cpn, from, spn); 1355c19800e8SDoug Rabson 1356c19800e8SDoug Rabson /* 1357c19800e8SDoug Rabson * Fetch server 1358c19800e8SDoug Rabson */ 1359c19800e8SDoug Rabson 1360c19800e8SDoug Rabson server_lookup: 1361c19800e8SDoug Rabson ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server); 1362c19800e8SDoug Rabson 1363c19800e8SDoug Rabson if(ret){ 1364c19800e8SDoug Rabson const char *new_rlm; 1365c19800e8SDoug Rabson Realm req_rlm; 1366c19800e8SDoug Rabson krb5_realm *realms; 1367c19800e8SDoug Rabson 1368c19800e8SDoug Rabson if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) { 1369c19800e8SDoug Rabson if(nloop++ < 2) { 1370c19800e8SDoug Rabson new_rlm = find_rpath(context, tgt->crealm, req_rlm); 1371c19800e8SDoug Rabson if(new_rlm) { 1372c19800e8SDoug Rabson kdc_log(context, config, 5, "krbtgt for realm %s " 1373c19800e8SDoug Rabson "not found, trying %s", 1374c19800e8SDoug Rabson req_rlm, new_rlm); 1375c19800e8SDoug Rabson krb5_free_principal(context, sp); 1376c19800e8SDoug Rabson free(spn); 1377c19800e8SDoug Rabson krb5_make_principal(context, &sp, r, 1378c19800e8SDoug Rabson KRB5_TGS_NAME, new_rlm, NULL); 1379c19800e8SDoug Rabson ret = krb5_unparse_name(context, sp, &spn); 1380c19800e8SDoug Rabson if (ret) 1381c19800e8SDoug Rabson goto out; 1382c19800e8SDoug Rabson auth_data = NULL; /* ms don't handle AD in referals */ 1383c19800e8SDoug Rabson goto server_lookup; 1384c19800e8SDoug Rabson } 1385c19800e8SDoug Rabson } 1386c19800e8SDoug Rabson } else if(need_referral(context, sp, &realms)) { 1387c19800e8SDoug Rabson if (strcmp(realms[0], sp->realm) != 0) { 1388c19800e8SDoug Rabson kdc_log(context, config, 5, 1389c19800e8SDoug Rabson "Returning a referral to realm %s for " 1390c19800e8SDoug Rabson "server %s that was not found", 1391c19800e8SDoug Rabson realms[0], spn); 1392c19800e8SDoug Rabson krb5_free_principal(context, sp); 1393c19800e8SDoug Rabson free(spn); 1394c19800e8SDoug Rabson krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, 1395c19800e8SDoug Rabson realms[0], NULL); 1396c19800e8SDoug Rabson ret = krb5_unparse_name(context, sp, &spn); 1397c19800e8SDoug Rabson if (ret) 1398c19800e8SDoug Rabson goto out; 1399c19800e8SDoug Rabson krb5_free_host_realm(context, realms); 1400c19800e8SDoug Rabson auth_data = NULL; /* ms don't handle AD in referals */ 1401c19800e8SDoug Rabson goto server_lookup; 1402c19800e8SDoug Rabson } 1403c19800e8SDoug Rabson krb5_free_host_realm(context, realms); 1404c19800e8SDoug Rabson } 1405c19800e8SDoug Rabson kdc_log(context, config, 0, 1406c19800e8SDoug Rabson "Server not found in database: %s: %s", spn, 1407c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1408c19800e8SDoug Rabson if (ret == HDB_ERR_NOENTRY) 1409c19800e8SDoug Rabson ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1410c19800e8SDoug Rabson goto out; 1411c19800e8SDoug Rabson } 1412c19800e8SDoug Rabson 1413c19800e8SDoug Rabson ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client); 1414c19800e8SDoug Rabson if(ret) { 1415c19800e8SDoug Rabson const char *krbtgt_realm; 1416c19800e8SDoug Rabson 1417c19800e8SDoug Rabson /* 1418c19800e8SDoug Rabson * If the client belongs to the same realm as our krbtgt, it 1419c19800e8SDoug Rabson * should exist in the local database. 1420c19800e8SDoug Rabson * 1421c19800e8SDoug Rabson */ 1422c19800e8SDoug Rabson 1423c19800e8SDoug Rabson krbtgt_realm = 1424c19800e8SDoug Rabson krb5_principal_get_comp_string(context, 1425c19800e8SDoug Rabson krbtgt->entry.principal, 1); 1426c19800e8SDoug Rabson 1427c19800e8SDoug Rabson if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { 1428c19800e8SDoug Rabson if (ret == HDB_ERR_NOENTRY) 1429c19800e8SDoug Rabson ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1430c19800e8SDoug Rabson kdc_log(context, config, 1, "Client no longer in database: %s", 1431c19800e8SDoug Rabson cpn); 1432c19800e8SDoug Rabson goto out; 1433c19800e8SDoug Rabson } 1434c19800e8SDoug Rabson 1435c19800e8SDoug Rabson kdc_log(context, config, 1, "Client not found in database: %s: %s", 1436c19800e8SDoug Rabson cpn, krb5_get_err_text(context, ret)); 1437c19800e8SDoug Rabson 1438c19800e8SDoug Rabson cross_realm = 1; 1439c19800e8SDoug Rabson } 1440c19800e8SDoug Rabson 1441c19800e8SDoug Rabson /* 1442c19800e8SDoug Rabson * Check that service is in the same realm as the krbtgt. If it's 1443c19800e8SDoug Rabson * not the same, it's someone that is using a uni-directional trust 1444c19800e8SDoug Rabson * backward. 1445c19800e8SDoug Rabson */ 1446c19800e8SDoug Rabson 1447c19800e8SDoug Rabson if (strcmp(krb5_principal_get_realm(context, sp), 1448c19800e8SDoug Rabson krb5_principal_get_comp_string(context, 1449c19800e8SDoug Rabson krbtgt->entry.principal, 1450c19800e8SDoug Rabson 1)) != 0) { 1451c19800e8SDoug Rabson char *tpn; 1452c19800e8SDoug Rabson ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn); 1453c19800e8SDoug Rabson kdc_log(context, config, 0, 1454c19800e8SDoug Rabson "Request with wrong krbtgt: %s", 1455c19800e8SDoug Rabson (ret == 0) ? tpn : "<unknown>"); 1456c19800e8SDoug Rabson if(ret == 0) 1457c19800e8SDoug Rabson free(tpn); 1458c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_NOT_US; 1459c19800e8SDoug Rabson goto out; 1460c19800e8SDoug Rabson } 1461c19800e8SDoug Rabson 1462c19800e8SDoug Rabson /* 1463c19800e8SDoug Rabson * 1464c19800e8SDoug Rabson */ 1465c19800e8SDoug Rabson 1466c19800e8SDoug Rabson client_principal = cp; 1467c19800e8SDoug Rabson 1468c19800e8SDoug Rabson if (client) { 1469c19800e8SDoug Rabson const PA_DATA *sdata; 1470c19800e8SDoug Rabson int i = 0; 1471c19800e8SDoug Rabson 1472c19800e8SDoug Rabson sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF); 1473c19800e8SDoug Rabson if (sdata) { 1474c19800e8SDoug Rabson krb5_crypto crypto; 1475c19800e8SDoug Rabson krb5_data datack; 1476c19800e8SDoug Rabson PA_S4U2Self self; 1477c19800e8SDoug Rabson char *selfcpn = NULL; 1478c19800e8SDoug Rabson const char *str; 1479c19800e8SDoug Rabson 1480c19800e8SDoug Rabson ret = decode_PA_S4U2Self(sdata->padata_value.data, 1481c19800e8SDoug Rabson sdata->padata_value.length, 1482c19800e8SDoug Rabson &self, NULL); 1483c19800e8SDoug Rabson if (ret) { 1484c19800e8SDoug Rabson kdc_log(context, config, 0, "Failed to decode PA-S4U2Self"); 1485c19800e8SDoug Rabson goto out; 1486c19800e8SDoug Rabson } 1487c19800e8SDoug Rabson 1488c19800e8SDoug Rabson ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); 1489c19800e8SDoug Rabson if (ret) 1490c19800e8SDoug Rabson goto out; 1491c19800e8SDoug Rabson 1492c19800e8SDoug Rabson ret = krb5_crypto_init(context, &tgt->key, 0, &crypto); 1493c19800e8SDoug Rabson if (ret) { 1494c19800e8SDoug Rabson free_PA_S4U2Self(&self); 1495c19800e8SDoug Rabson krb5_data_free(&datack); 1496c19800e8SDoug Rabson kdc_log(context, config, 0, "krb5_crypto_init failed: %s", 1497c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1498c19800e8SDoug Rabson goto out; 1499c19800e8SDoug Rabson } 1500c19800e8SDoug Rabson 1501c19800e8SDoug Rabson ret = krb5_verify_checksum(context, 1502c19800e8SDoug Rabson crypto, 1503c19800e8SDoug Rabson KRB5_KU_OTHER_CKSUM, 1504c19800e8SDoug Rabson datack.data, 1505c19800e8SDoug Rabson datack.length, 1506c19800e8SDoug Rabson &self.cksum); 1507c19800e8SDoug Rabson krb5_data_free(&datack); 1508c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 1509c19800e8SDoug Rabson if (ret) { 1510c19800e8SDoug Rabson free_PA_S4U2Self(&self); 1511c19800e8SDoug Rabson kdc_log(context, config, 0, 1512c19800e8SDoug Rabson "krb5_verify_checksum failed for S4U2Self: %s", 1513c19800e8SDoug Rabson krb5_get_err_text(context, ret)); 1514c19800e8SDoug Rabson goto out; 1515c19800e8SDoug Rabson } 1516c19800e8SDoug Rabson 1517c19800e8SDoug Rabson ret = _krb5_principalname2krb5_principal(context, 1518c19800e8SDoug Rabson &client_principal, 1519c19800e8SDoug Rabson self.name, 1520c19800e8SDoug Rabson self.realm); 1521c19800e8SDoug Rabson free_PA_S4U2Self(&self); 1522c19800e8SDoug Rabson if (ret) 1523c19800e8SDoug Rabson goto out; 1524c19800e8SDoug Rabson 1525c19800e8SDoug Rabson ret = krb5_unparse_name(context, client_principal, &selfcpn); 1526c19800e8SDoug Rabson if (ret) 1527c19800e8SDoug Rabson goto out; 1528c19800e8SDoug Rabson 1529c19800e8SDoug Rabson /* 1530c19800e8SDoug Rabson * Check that service doing the impersonating is 1531c19800e8SDoug Rabson * requesting a ticket to it-self. 1532c19800e8SDoug Rabson */ 1533c19800e8SDoug Rabson if (krb5_principal_compare(context, cp, sp) != TRUE) { 1534c19800e8SDoug Rabson kdc_log(context, config, 0, "S4U2Self: %s is not allowed " 1535c19800e8SDoug Rabson "to impersonate some other user " 1536c19800e8SDoug Rabson "(tried for user %s to service %s)", 1537c19800e8SDoug Rabson cpn, selfcpn, spn); 1538c19800e8SDoug Rabson free(selfcpn); 1539c19800e8SDoug Rabson ret = KRB5KDC_ERR_BADOPTION; /* ? */ 1540c19800e8SDoug Rabson goto out; 1541c19800e8SDoug Rabson } 1542c19800e8SDoug Rabson 1543c19800e8SDoug Rabson /* 1544c19800e8SDoug Rabson * If the service isn't trusted for authentication to 1545c19800e8SDoug Rabson * delegation, remove the forward flag. 1546c19800e8SDoug Rabson */ 1547c19800e8SDoug Rabson 1548c19800e8SDoug Rabson if (client->entry.flags.trusted_for_delegation) { 1549c19800e8SDoug Rabson str = "[forwardable]"; 1550c19800e8SDoug Rabson } else { 1551c19800e8SDoug Rabson b->kdc_options.forwardable = 0; 1552c19800e8SDoug Rabson str = ""; 1553c19800e8SDoug Rabson } 1554c19800e8SDoug Rabson kdc_log(context, config, 0, "s4u2self %s impersonating %s to " 1555c19800e8SDoug Rabson "service %s %s", cpn, selfcpn, spn, str); 1556c19800e8SDoug Rabson free(selfcpn); 1557c19800e8SDoug Rabson } 1558c19800e8SDoug Rabson } 1559c19800e8SDoug Rabson 1560c19800e8SDoug Rabson /* 1561c19800e8SDoug Rabson * Constrained delegation 1562c19800e8SDoug Rabson */ 1563c19800e8SDoug Rabson 1564c19800e8SDoug Rabson if (client != NULL 1565c19800e8SDoug Rabson && b->additional_tickets != NULL 1566c19800e8SDoug Rabson && b->additional_tickets->len != 0 1567c19800e8SDoug Rabson && b->kdc_options.enc_tkt_in_skey == 0) 1568c19800e8SDoug Rabson { 1569c19800e8SDoug Rabson Key *clientkey; 1570c19800e8SDoug Rabson Ticket *t; 1571c19800e8SDoug Rabson char *str; 1572c19800e8SDoug Rabson 1573c19800e8SDoug Rabson t = &b->additional_tickets->val[0]; 1574c19800e8SDoug Rabson 1575c19800e8SDoug Rabson ret = hdb_enctype2key(context, &client->entry, 1576c19800e8SDoug Rabson t->enc_part.etype, &clientkey); 1577c19800e8SDoug Rabson if(ret){ 1578c19800e8SDoug Rabson ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1579c19800e8SDoug Rabson goto out; 1580c19800e8SDoug Rabson } 1581c19800e8SDoug Rabson 1582c19800e8SDoug Rabson ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0); 1583c19800e8SDoug Rabson if (ret) { 1584c19800e8SDoug Rabson kdc_log(context, config, 0, 1585c19800e8SDoug Rabson "failed to decrypt ticket for " 1586c19800e8SDoug Rabson "constrained delegation from %s to %s ", spn, cpn); 1587c19800e8SDoug Rabson goto out; 1588c19800e8SDoug Rabson } 1589c19800e8SDoug Rabson 1590c19800e8SDoug Rabson /* check that ticket is valid */ 1591c19800e8SDoug Rabson 1592c19800e8SDoug Rabson if (adtkt.flags.forwardable == 0) { 1593c19800e8SDoug Rabson kdc_log(context, config, 0, 1594c19800e8SDoug Rabson "Missing forwardable flag on ticket for " 1595c19800e8SDoug Rabson "constrained delegation from %s to %s ", spn, cpn); 1596c19800e8SDoug Rabson ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1597c19800e8SDoug Rabson goto out; 1598c19800e8SDoug Rabson } 1599c19800e8SDoug Rabson 1600c19800e8SDoug Rabson ret = check_constrained_delegation(context, config, client, sp); 1601c19800e8SDoug Rabson if (ret) { 1602c19800e8SDoug Rabson kdc_log(context, config, 0, 1603c19800e8SDoug Rabson "constrained delegation from %s to %s not allowed", 1604c19800e8SDoug Rabson spn, cpn); 1605c19800e8SDoug Rabson goto out; 1606c19800e8SDoug Rabson } 1607c19800e8SDoug Rabson 1608c19800e8SDoug Rabson ret = _krb5_principalname2krb5_principal(context, 1609c19800e8SDoug Rabson &client_principal, 1610c19800e8SDoug Rabson adtkt.cname, 1611c19800e8SDoug Rabson adtkt.crealm); 1612c19800e8SDoug Rabson if (ret) 1613c19800e8SDoug Rabson goto out; 1614c19800e8SDoug Rabson 1615c19800e8SDoug Rabson ret = krb5_unparse_name(context, client_principal, &str); 1616c19800e8SDoug Rabson if (ret) 1617c19800e8SDoug Rabson goto out; 1618c19800e8SDoug Rabson 1619c19800e8SDoug Rabson ret = verify_flags(context, config, &adtkt, str); 1620c19800e8SDoug Rabson if (ret) { 1621c19800e8SDoug Rabson free(str); 1622c19800e8SDoug Rabson goto out; 1623c19800e8SDoug Rabson } 1624c19800e8SDoug Rabson 1625c19800e8SDoug Rabson /* 1626c19800e8SDoug Rabson * Check KRB5SignedPath in authorization data and add new entry to 1627c19800e8SDoug Rabson * make sure servers can't fake a ticket to us. 1628c19800e8SDoug Rabson */ 1629c19800e8SDoug Rabson 1630c19800e8SDoug Rabson ret = check_KRB5SignedPath(context, 1631c19800e8SDoug Rabson config, 1632c19800e8SDoug Rabson krbtgt, 1633c19800e8SDoug Rabson &adtkt, 1634c19800e8SDoug Rabson &spp, 1635c19800e8SDoug Rabson 1); 1636c19800e8SDoug Rabson if (ret) { 1637c19800e8SDoug Rabson kdc_log(context, config, 0, 1638c19800e8SDoug Rabson "KRB5SignedPath check from service %s failed " 1639c19800e8SDoug Rabson "for delegation to %s for client %s " 1640c19800e8SDoug Rabson "from %s failed with %s", 1641c19800e8SDoug Rabson spn, str, cpn, from, krb5_get_err_text(context, ret)); 1642c19800e8SDoug Rabson free(str); 1643c19800e8SDoug Rabson goto out; 1644c19800e8SDoug Rabson } 1645c19800e8SDoug Rabson 1646c19800e8SDoug Rabson kdc_log(context, config, 0, "constrained delegation for %s " 1647c19800e8SDoug Rabson "from %s to %s", str, cpn, spn); 1648c19800e8SDoug Rabson free(str); 1649c19800e8SDoug Rabson 1650c19800e8SDoug Rabson /* 1651c19800e8SDoug Rabson * Also require that the KDC have issue the service's krbtgt 1652c19800e8SDoug Rabson * used to do the request. 1653c19800e8SDoug Rabson */ 1654c19800e8SDoug Rabson require_signedpath = 1; 1655c19800e8SDoug Rabson } 1656c19800e8SDoug Rabson 1657c19800e8SDoug Rabson /* 1658c19800e8SDoug Rabson * Check flags 1659c19800e8SDoug Rabson */ 1660c19800e8SDoug Rabson 1661c19800e8SDoug Rabson ret = _kdc_check_flags(context, config, 1662c19800e8SDoug Rabson client, cpn, 1663c19800e8SDoug Rabson server, spn, 1664c19800e8SDoug Rabson FALSE); 1665c19800e8SDoug Rabson if(ret) 1666c19800e8SDoug Rabson goto out; 1667c19800e8SDoug Rabson 1668c19800e8SDoug Rabson if((b->kdc_options.validate || b->kdc_options.renew) && 1669c19800e8SDoug Rabson !krb5_principal_compare(context, 1670c19800e8SDoug Rabson krbtgt->entry.principal, 1671c19800e8SDoug Rabson server->entry.principal)){ 1672c19800e8SDoug Rabson kdc_log(context, config, 0, "Inconsistent request."); 1673c19800e8SDoug Rabson ret = KRB5KDC_ERR_SERVER_NOMATCH; 1674c19800e8SDoug Rabson goto out; 1675c19800e8SDoug Rabson } 1676c19800e8SDoug Rabson 1677c19800e8SDoug Rabson /* check for valid set of addresses */ 1678c19800e8SDoug Rabson if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) { 1679c19800e8SDoug Rabson ret = KRB5KRB_AP_ERR_BADADDR; 1680c19800e8SDoug Rabson kdc_log(context, config, 0, "Request from wrong address"); 1681c19800e8SDoug Rabson goto out; 1682c19800e8SDoug Rabson } 1683c19800e8SDoug Rabson 1684c19800e8SDoug Rabson /* 1685c19800e8SDoug Rabson * Select enctype, return key and kvno. 1686c19800e8SDoug Rabson */ 1687c19800e8SDoug Rabson 1688c19800e8SDoug Rabson { 1689c19800e8SDoug Rabson krb5_enctype etype; 1690c19800e8SDoug Rabson 1691c19800e8SDoug Rabson if(b->kdc_options.enc_tkt_in_skey) { 1692c19800e8SDoug Rabson int i; 1693c19800e8SDoug Rabson ekey = &adtkt.key; 1694c19800e8SDoug Rabson for(i = 0; i < b->etype.len; i++) 1695c19800e8SDoug Rabson if (b->etype.val[i] == adtkt.key.keytype) 1696c19800e8SDoug Rabson break; 1697c19800e8SDoug Rabson if(i == b->etype.len) { 1698c19800e8SDoug Rabson krb5_clear_error_string(context); 1699c19800e8SDoug Rabson return KRB5KDC_ERR_ETYPE_NOSUPP; 1700c19800e8SDoug Rabson } 1701c19800e8SDoug Rabson etype = b->etype.val[i]; 1702c19800e8SDoug Rabson kvno = 0; 1703c19800e8SDoug Rabson } else { 1704c19800e8SDoug Rabson Key *skey; 1705c19800e8SDoug Rabson 1706c19800e8SDoug Rabson ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, 1707c19800e8SDoug Rabson &skey, &etype); 1708c19800e8SDoug Rabson if(ret) { 1709c19800e8SDoug Rabson kdc_log(context, config, 0, 1710c19800e8SDoug Rabson "Server (%s) has no support for etypes", spp); 1711c19800e8SDoug Rabson return ret; 1712c19800e8SDoug Rabson } 1713c19800e8SDoug Rabson ekey = &skey->key; 1714c19800e8SDoug Rabson kvno = server->entry.kvno; 1715c19800e8SDoug Rabson } 1716c19800e8SDoug Rabson 1717c19800e8SDoug Rabson ret = krb5_generate_random_keyblock(context, etype, &sessionkey); 1718c19800e8SDoug Rabson if (ret) 1719c19800e8SDoug Rabson goto out; 1720c19800e8SDoug Rabson } 1721c19800e8SDoug Rabson 1722c19800e8SDoug Rabson /* check PAC if not cross realm and if there is one */ 1723c19800e8SDoug Rabson if (!cross_realm) { 1724c19800e8SDoug Rabson Key *tkey; 1725c19800e8SDoug Rabson 1726c19800e8SDoug Rabson ret = hdb_enctype2key(context, &krbtgt->entry, 1727c19800e8SDoug Rabson krbtgt_etype, &tkey); 1728c19800e8SDoug Rabson if(ret) { 1729c19800e8SDoug Rabson kdc_log(context, config, 0, 1730c19800e8SDoug Rabson "Failed to find key for krbtgt PAC check"); 1731c19800e8SDoug Rabson goto out; 1732c19800e8SDoug Rabson } 1733c19800e8SDoug Rabson 1734c19800e8SDoug Rabson ret = check_PAC(context, config, client_principal, 1735c19800e8SDoug Rabson client, server, ekey, &tkey->key, 1736c19800e8SDoug Rabson tgt, &rspac, &require_signedpath); 1737c19800e8SDoug Rabson if (ret) { 1738c19800e8SDoug Rabson kdc_log(context, config, 0, 1739c19800e8SDoug Rabson "Verify PAC failed for %s (%s) from %s with %s", 1740c19800e8SDoug Rabson spn, cpn, from, krb5_get_err_text(context, ret)); 1741c19800e8SDoug Rabson goto out; 1742c19800e8SDoug Rabson } 1743c19800e8SDoug Rabson } 1744c19800e8SDoug Rabson 1745c19800e8SDoug Rabson /* also check the krbtgt for signature */ 1746c19800e8SDoug Rabson ret = check_KRB5SignedPath(context, 1747c19800e8SDoug Rabson config, 1748c19800e8SDoug Rabson krbtgt, 1749c19800e8SDoug Rabson tgt, 1750c19800e8SDoug Rabson &spp, 1751c19800e8SDoug Rabson require_signedpath); 1752c19800e8SDoug Rabson if (ret) { 1753c19800e8SDoug Rabson kdc_log(context, config, 0, 1754c19800e8SDoug Rabson "KRB5SignedPath check failed for %s (%s) from %s with %s", 1755c19800e8SDoug Rabson spn, cpn, from, krb5_get_err_text(context, ret)); 1756c19800e8SDoug Rabson goto out; 1757c19800e8SDoug Rabson } 1758c19800e8SDoug Rabson 1759c19800e8SDoug Rabson /* 1760c19800e8SDoug Rabson * 1761c19800e8SDoug Rabson */ 1762c19800e8SDoug Rabson 1763c19800e8SDoug Rabson ret = tgs_make_reply(context, 1764c19800e8SDoug Rabson config, 1765c19800e8SDoug Rabson b, 1766c19800e8SDoug Rabson client_principal, 1767c19800e8SDoug Rabson tgt, 1768c19800e8SDoug Rabson ekey, 1769c19800e8SDoug Rabson &sessionkey, 1770c19800e8SDoug Rabson kvno, 1771c19800e8SDoug Rabson auth_data, 1772c19800e8SDoug Rabson server, 1773c19800e8SDoug Rabson spn, 1774c19800e8SDoug Rabson client, 1775c19800e8SDoug Rabson cp, 1776c19800e8SDoug Rabson krbtgt, 1777c19800e8SDoug Rabson krbtgt_etype, 1778c19800e8SDoug Rabson spp, 1779c19800e8SDoug Rabson &rspac, 1780c19800e8SDoug Rabson e_text, 1781c19800e8SDoug Rabson reply); 1782c19800e8SDoug Rabson 1783c19800e8SDoug Rabson out: 1784c19800e8SDoug Rabson free(spn); 1785c19800e8SDoug Rabson free(cpn); 1786c19800e8SDoug Rabson 1787c19800e8SDoug Rabson krb5_data_free(&rspac); 1788c19800e8SDoug Rabson krb5_free_keyblock_contents(context, &sessionkey); 1789c19800e8SDoug Rabson if(server) 1790c19800e8SDoug Rabson _kdc_free_ent(context, server); 1791c19800e8SDoug Rabson if(client) 1792c19800e8SDoug Rabson _kdc_free_ent(context, client); 1793c19800e8SDoug Rabson 1794c19800e8SDoug Rabson if (client_principal && client_principal != cp) 1795c19800e8SDoug Rabson krb5_free_principal(context, client_principal); 1796c19800e8SDoug Rabson if (cp) 1797c19800e8SDoug Rabson krb5_free_principal(context, cp); 1798c19800e8SDoug Rabson if (sp) 1799c19800e8SDoug Rabson krb5_free_principal(context, sp); 1800c19800e8SDoug Rabson 1801c19800e8SDoug Rabson free_EncTicketPart(&adtkt); 1802c19800e8SDoug Rabson 1803c19800e8SDoug Rabson return ret; 1804c19800e8SDoug Rabson } 1805c19800e8SDoug Rabson 1806c19800e8SDoug Rabson /* 1807c19800e8SDoug Rabson * 1808c19800e8SDoug Rabson */ 1809c19800e8SDoug Rabson 1810c19800e8SDoug Rabson krb5_error_code 1811c19800e8SDoug Rabson _kdc_tgs_rep(krb5_context context, 1812c19800e8SDoug Rabson krb5_kdc_configuration *config, 1813c19800e8SDoug Rabson KDC_REQ *req, 1814c19800e8SDoug Rabson krb5_data *data, 1815c19800e8SDoug Rabson const char *from, 1816c19800e8SDoug Rabson struct sockaddr *from_addr, 1817c19800e8SDoug Rabson int datagram_reply) 1818c19800e8SDoug Rabson { 1819c19800e8SDoug Rabson AuthorizationData *auth_data = NULL; 1820c19800e8SDoug Rabson krb5_error_code ret; 1821c19800e8SDoug Rabson int i = 0; 1822c19800e8SDoug Rabson const PA_DATA *tgs_req; 1823c19800e8SDoug Rabson 1824c19800e8SDoug Rabson hdb_entry_ex *krbtgt = NULL; 1825c19800e8SDoug Rabson krb5_ticket *ticket = NULL; 1826c19800e8SDoug Rabson const char *e_text = NULL; 1827c19800e8SDoug Rabson krb5_enctype krbtgt_etype = ETYPE_NULL; 1828c19800e8SDoug Rabson 1829c19800e8SDoug Rabson time_t *csec = NULL; 1830c19800e8SDoug Rabson int *cusec = NULL; 1831c19800e8SDoug Rabson 1832c19800e8SDoug Rabson if(req->padata == NULL){ 1833c19800e8SDoug Rabson ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */ 1834c19800e8SDoug Rabson kdc_log(context, config, 0, 1835c19800e8SDoug Rabson "TGS-REQ from %s without PA-DATA", from); 1836c19800e8SDoug Rabson goto out; 1837c19800e8SDoug Rabson } 1838c19800e8SDoug Rabson 1839c19800e8SDoug Rabson tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ); 1840c19800e8SDoug Rabson 1841c19800e8SDoug Rabson if(tgs_req == NULL){ 1842c19800e8SDoug Rabson ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 1843c19800e8SDoug Rabson 1844c19800e8SDoug Rabson kdc_log(context, config, 0, 1845c19800e8SDoug Rabson "TGS-REQ from %s without PA-TGS-REQ", from); 1846c19800e8SDoug Rabson goto out; 1847c19800e8SDoug Rabson } 1848c19800e8SDoug Rabson ret = tgs_parse_request(context, config, 1849c19800e8SDoug Rabson &req->req_body, tgs_req, 1850c19800e8SDoug Rabson &krbtgt, 1851c19800e8SDoug Rabson &krbtgt_etype, 1852c19800e8SDoug Rabson &ticket, 1853c19800e8SDoug Rabson &e_text, 1854c19800e8SDoug Rabson from, from_addr, 1855c19800e8SDoug Rabson &csec, &cusec, 1856c19800e8SDoug Rabson &auth_data); 1857c19800e8SDoug Rabson if (ret) { 1858c19800e8SDoug Rabson kdc_log(context, config, 0, 1859c19800e8SDoug Rabson "Failed parsing TGS-REQ from %s", from); 1860c19800e8SDoug Rabson goto out; 1861c19800e8SDoug Rabson } 1862c19800e8SDoug Rabson 1863c19800e8SDoug Rabson ret = tgs_build_reply(context, 1864c19800e8SDoug Rabson config, 1865c19800e8SDoug Rabson req, 1866c19800e8SDoug Rabson &req->req_body, 1867c19800e8SDoug Rabson krbtgt, 1868c19800e8SDoug Rabson krbtgt_etype, 1869c19800e8SDoug Rabson ticket, 1870c19800e8SDoug Rabson data, 1871c19800e8SDoug Rabson from, 1872c19800e8SDoug Rabson &e_text, 1873c19800e8SDoug Rabson auth_data, 1874c19800e8SDoug Rabson from_addr, 1875c19800e8SDoug Rabson datagram_reply); 1876c19800e8SDoug Rabson if (ret) { 1877c19800e8SDoug Rabson kdc_log(context, config, 0, 1878c19800e8SDoug Rabson "Failed building TGS-REP to %s", from); 1879c19800e8SDoug Rabson goto out; 1880c19800e8SDoug Rabson } 1881c19800e8SDoug Rabson 1882c19800e8SDoug Rabson /* */ 1883c19800e8SDoug Rabson if (datagram_reply && data->length > config->max_datagram_reply_length) { 1884c19800e8SDoug Rabson krb5_data_free(data); 1885c19800e8SDoug Rabson ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; 1886c19800e8SDoug Rabson e_text = "Reply packet too large"; 1887c19800e8SDoug Rabson } 1888c19800e8SDoug Rabson 1889c19800e8SDoug Rabson out: 1890c19800e8SDoug Rabson if(ret && data->data == NULL){ 1891c19800e8SDoug Rabson krb5_mk_error(context, 1892c19800e8SDoug Rabson ret, 1893c19800e8SDoug Rabson NULL, 1894c19800e8SDoug Rabson NULL, 1895c19800e8SDoug Rabson NULL, 1896c19800e8SDoug Rabson NULL, 1897c19800e8SDoug Rabson csec, 1898c19800e8SDoug Rabson cusec, 1899c19800e8SDoug Rabson data); 1900c19800e8SDoug Rabson } 1901c19800e8SDoug Rabson free(csec); 1902c19800e8SDoug Rabson free(cusec); 1903c19800e8SDoug Rabson if (ticket) 1904c19800e8SDoug Rabson krb5_free_ticket(context, ticket); 1905c19800e8SDoug Rabson if(krbtgt) 1906c19800e8SDoug Rabson _kdc_free_ent(context, krbtgt); 1907c19800e8SDoug Rabson 1908c19800e8SDoug Rabson if (auth_data) { 1909c19800e8SDoug Rabson free_AuthorizationData(auth_data); 1910c19800e8SDoug Rabson free(auth_data); 1911c19800e8SDoug Rabson } 1912c19800e8SDoug Rabson 1913c19800e8SDoug Rabson return 0; 1914c19800e8SDoug Rabson } 1915