1 1.1 elric /* $NetBSD: get_cred.c,v 1.4 2023/06/19 21:41:44 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 1997 - 2008 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 9 1.1 elric * 10 1.1 elric * Redistribution and use in source and binary forms, with or without 11 1.1 elric * modification, are permitted provided that the following conditions 12 1.1 elric * are met: 13 1.1 elric * 14 1.1 elric * 1. Redistributions of source code must retain the above copyright 15 1.1 elric * notice, this list of conditions and the following disclaimer. 16 1.1 elric * 17 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 elric * notice, this list of conditions and the following disclaimer in the 19 1.1 elric * documentation and/or other materials provided with the distribution. 20 1.1 elric * 21 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 22 1.1 elric * may be used to endorse or promote products derived from this software 23 1.1 elric * without specific prior written permission. 24 1.1 elric * 25 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 1.1 elric * SUCH DAMAGE. 36 1.1 elric */ 37 1.1 elric 38 1.1 elric #include "krb5_locl.h" 39 1.1 elric #include <assert.h> 40 1.1 elric 41 1.1 elric static krb5_error_code 42 1.1 elric get_cred_kdc_capath(krb5_context, krb5_kdc_flags, 43 1.1 elric krb5_ccache, krb5_creds *, krb5_principal, 44 1.1 elric Ticket *, krb5_creds **, krb5_creds ***); 45 1.1 elric 46 1.1 elric /* 47 1.1 elric * Take the `body' and encode it into `padata' using the credentials 48 1.1 elric * in `creds'. 49 1.1 elric */ 50 1.1 elric 51 1.1 elric static krb5_error_code 52 1.1 elric make_pa_tgs_req(krb5_context context, 53 1.1 elric krb5_auth_context ac, 54 1.1 elric KDC_REQ_BODY *body, 55 1.1 elric PA_DATA *padata, 56 1.1 elric krb5_creds *creds) 57 1.1 elric { 58 1.1 elric u_char *buf; 59 1.1 elric size_t buf_size; 60 1.2 christos size_t len = 0; 61 1.1 elric krb5_data in_data; 62 1.1 elric krb5_error_code ret; 63 1.1 elric 64 1.1 elric ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); 65 1.1 elric if (ret) 66 1.1 elric goto out; 67 1.1 elric if(buf_size != len) 68 1.1 elric krb5_abortx(context, "internal error in ASN.1 encoder"); 69 1.1 elric 70 1.1 elric in_data.length = len; 71 1.1 elric in_data.data = buf; 72 1.1 elric ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds, 73 1.1 elric &padata->padata_value, 74 1.1 elric KRB5_KU_TGS_REQ_AUTH_CKSUM, 75 1.1 elric KRB5_KU_TGS_REQ_AUTH); 76 1.1 elric out: 77 1.1 elric free (buf); 78 1.1 elric if(ret) 79 1.1 elric return ret; 80 1.1 elric padata->padata_type = KRB5_PADATA_TGS_REQ; 81 1.1 elric return 0; 82 1.1 elric } 83 1.1 elric 84 1.1 elric /* 85 1.1 elric * Set the `enc-authorization-data' in `req_body' based on `authdata' 86 1.1 elric */ 87 1.1 elric 88 1.1 elric static krb5_error_code 89 1.1 elric set_auth_data (krb5_context context, 90 1.1 elric KDC_REQ_BODY *req_body, 91 1.1 elric krb5_authdata *authdata, 92 1.1 elric krb5_keyblock *subkey) 93 1.1 elric { 94 1.1 elric if(authdata->len) { 95 1.2 christos size_t len = 0, buf_size; 96 1.1 elric unsigned char *buf; 97 1.1 elric krb5_crypto crypto; 98 1.1 elric krb5_error_code ret; 99 1.1 elric 100 1.1 elric ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, 101 1.1 elric &len, ret); 102 1.1 elric if (ret) 103 1.1 elric return ret; 104 1.1 elric if (buf_size != len) 105 1.1 elric krb5_abortx(context, "internal error in ASN.1 encoder"); 106 1.1 elric 107 1.1 elric ALLOC(req_body->enc_authorization_data, 1); 108 1.1 elric if (req_body->enc_authorization_data == NULL) { 109 1.1 elric free (buf); 110 1.2 christos return krb5_enomem(context); 111 1.1 elric } 112 1.1 elric ret = krb5_crypto_init(context, subkey, 0, &crypto); 113 1.1 elric if (ret) { 114 1.1 elric free (buf); 115 1.1 elric free (req_body->enc_authorization_data); 116 1.1 elric req_body->enc_authorization_data = NULL; 117 1.1 elric return ret; 118 1.1 elric } 119 1.1 elric krb5_encrypt_EncryptedData(context, 120 1.1 elric crypto, 121 1.1 elric KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, 122 1.1 elric buf, 123 1.1 elric len, 124 1.1 elric 0, 125 1.1 elric req_body->enc_authorization_data); 126 1.1 elric free (buf); 127 1.1 elric krb5_crypto_destroy(context, crypto); 128 1.1 elric } else { 129 1.1 elric req_body->enc_authorization_data = NULL; 130 1.1 elric } 131 1.1 elric return 0; 132 1.1 elric } 133 1.1 elric 134 1.1 elric /* 135 1.1 elric * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' 136 1.1 elric * (if not-NULL), `in_creds', `krbtgt', and returning the generated 137 1.1 elric * subkey in `subkey'. 138 1.1 elric */ 139 1.1 elric 140 1.1 elric static krb5_error_code 141 1.1 elric init_tgs_req (krb5_context context, 142 1.1 elric krb5_ccache ccache, 143 1.1 elric krb5_addresses *addresses, 144 1.1 elric krb5_kdc_flags flags, 145 1.1 elric Ticket *second_ticket, 146 1.1 elric krb5_creds *in_creds, 147 1.1 elric krb5_creds *krbtgt, 148 1.1 elric unsigned nonce, 149 1.1 elric const METHOD_DATA *padata, 150 1.1 elric krb5_keyblock **subkey, 151 1.1 elric TGS_REQ *t) 152 1.1 elric { 153 1.1 elric krb5_auth_context ac = NULL; 154 1.1 elric krb5_error_code ret = 0; 155 1.1 elric 156 1.1 elric memset(t, 0, sizeof(*t)); 157 1.1 elric t->pvno = 5; 158 1.1 elric t->msg_type = krb_tgs_req; 159 1.1 elric if (in_creds->session.keytype) { 160 1.1 elric ALLOC_SEQ(&t->req_body.etype, 1); 161 1.1 elric if(t->req_body.etype.val == NULL) { 162 1.2 christos ret = krb5_enomem(context); 163 1.1 elric goto fail; 164 1.1 elric } 165 1.1 elric t->req_body.etype.val[0] = in_creds->session.keytype; 166 1.1 elric } else { 167 1.2 christos ret = _krb5_init_etype(context, 168 1.2 christos KRB5_PDU_TGS_REQUEST, 169 1.2 christos &t->req_body.etype.len, 170 1.2 christos &t->req_body.etype.val, 171 1.2 christos NULL); 172 1.1 elric } 173 1.1 elric if (ret) 174 1.1 elric goto fail; 175 1.1 elric t->req_body.addresses = addresses; 176 1.1 elric t->req_body.kdc_options = flags.b; 177 1.2 christos t->req_body.kdc_options.forwardable = krbtgt->flags.b.forwardable; 178 1.2 christos t->req_body.kdc_options.renewable = krbtgt->flags.b.renewable; 179 1.2 christos t->req_body.kdc_options.proxiable = krbtgt->flags.b.proxiable; 180 1.1 elric ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); 181 1.1 elric if (ret) 182 1.1 elric goto fail; 183 1.1 elric ALLOC(t->req_body.sname, 1); 184 1.1 elric if (t->req_body.sname == NULL) { 185 1.2 christos ret = krb5_enomem(context); 186 1.1 elric goto fail; 187 1.1 elric } 188 1.1 elric 189 1.1 elric /* some versions of some code might require that the client be 190 1.1 elric present in TGS-REQs, but this is clearly against the spec */ 191 1.1 elric 192 1.1 elric ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); 193 1.1 elric if (ret) 194 1.1 elric goto fail; 195 1.1 elric 196 1.2 christos if (krbtgt->times.starttime) { 197 1.2 christos ALLOC(t->req_body.from, 1); 198 1.2 christos if(t->req_body.from == NULL){ 199 1.2 christos ret = krb5_enomem(context); 200 1.2 christos goto fail; 201 1.2 christos } 202 1.2 christos *t->req_body.from = in_creds->times.starttime; 203 1.2 christos } 204 1.2 christos 205 1.1 elric /* req_body.till should be NULL if there is no endtime specified, 206 1.1 elric but old MIT code (like DCE secd) doesn't like that */ 207 1.1 elric ALLOC(t->req_body.till, 1); 208 1.1 elric if(t->req_body.till == NULL){ 209 1.2 christos ret = krb5_enomem(context); 210 1.1 elric goto fail; 211 1.1 elric } 212 1.1 elric *t->req_body.till = in_creds->times.endtime; 213 1.1 elric 214 1.2 christos if (t->req_body.kdc_options.renewable && krbtgt->times.renew_till) { 215 1.2 christos ALLOC(t->req_body.rtime, 1); 216 1.2 christos if(t->req_body.rtime == NULL){ 217 1.2 christos ret = krb5_enomem(context); 218 1.2 christos goto fail; 219 1.2 christos } 220 1.2 christos *t->req_body.rtime = in_creds->times.renew_till; 221 1.2 christos } 222 1.2 christos 223 1.1 elric t->req_body.nonce = nonce; 224 1.1 elric if(second_ticket){ 225 1.1 elric ALLOC(t->req_body.additional_tickets, 1); 226 1.1 elric if (t->req_body.additional_tickets == NULL) { 227 1.2 christos ret = krb5_enomem(context); 228 1.1 elric goto fail; 229 1.1 elric } 230 1.1 elric ALLOC_SEQ(t->req_body.additional_tickets, 1); 231 1.1 elric if (t->req_body.additional_tickets->val == NULL) { 232 1.2 christos ret = krb5_enomem(context); 233 1.1 elric goto fail; 234 1.1 elric } 235 1.1 elric ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); 236 1.1 elric if (ret) 237 1.1 elric goto fail; 238 1.1 elric } 239 1.1 elric ALLOC(t->padata, 1); 240 1.1 elric if (t->padata == NULL) { 241 1.2 christos ret = krb5_enomem(context); 242 1.1 elric goto fail; 243 1.1 elric } 244 1.1 elric ALLOC_SEQ(t->padata, 1 + padata->len); 245 1.1 elric if (t->padata->val == NULL) { 246 1.2 christos ret = krb5_enomem(context); 247 1.1 elric goto fail; 248 1.1 elric } 249 1.1 elric { 250 1.2 christos size_t i; 251 1.1 elric for (i = 0; i < padata->len; i++) { 252 1.1 elric ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); 253 1.1 elric if (ret) { 254 1.1 elric krb5_set_error_message(context, ret, 255 1.1 elric N_("malloc: out of memory", "")); 256 1.1 elric goto fail; 257 1.1 elric } 258 1.1 elric } 259 1.1 elric } 260 1.1 elric 261 1.1 elric ret = krb5_auth_con_init(context, &ac); 262 1.1 elric if(ret) 263 1.1 elric goto fail; 264 1.2 christos 265 1.1 elric ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); 266 1.1 elric if (ret) 267 1.1 elric goto fail; 268 1.2 christos 269 1.1 elric ret = set_auth_data (context, &t->req_body, &in_creds->authdata, 270 1.1 elric ac->local_subkey); 271 1.1 elric if (ret) 272 1.1 elric goto fail; 273 1.2 christos 274 1.1 elric ret = make_pa_tgs_req(context, 275 1.1 elric ac, 276 1.1 elric &t->req_body, 277 1.1 elric &t->padata->val[0], 278 1.1 elric krbtgt); 279 1.1 elric if(ret) 280 1.1 elric goto fail; 281 1.1 elric 282 1.1 elric ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); 283 1.1 elric if (ret) 284 1.1 elric goto fail; 285 1.1 elric 286 1.1 elric fail: 287 1.1 elric if (ac) 288 1.1 elric krb5_auth_con_free(context, ac); 289 1.1 elric if (ret) { 290 1.1 elric t->req_body.addresses = NULL; 291 1.1 elric free_TGS_REQ (t); 292 1.1 elric } 293 1.1 elric return ret; 294 1.1 elric } 295 1.1 elric 296 1.2 christos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 297 1.1 elric _krb5_get_krbtgt(krb5_context context, 298 1.1 elric krb5_ccache id, 299 1.1 elric krb5_realm realm, 300 1.1 elric krb5_creds **cred) 301 1.1 elric { 302 1.1 elric krb5_error_code ret; 303 1.1 elric krb5_creds tmp_cred; 304 1.1 elric 305 1.1 elric memset(&tmp_cred, 0, sizeof(tmp_cred)); 306 1.1 elric 307 1.1 elric ret = krb5_cc_get_principal(context, id, &tmp_cred.client); 308 1.1 elric if (ret) 309 1.1 elric return ret; 310 1.1 elric 311 1.1 elric ret = krb5_make_principal(context, 312 1.1 elric &tmp_cred.server, 313 1.1 elric realm, 314 1.1 elric KRB5_TGS_NAME, 315 1.1 elric realm, 316 1.1 elric NULL); 317 1.1 elric if(ret) { 318 1.1 elric krb5_free_principal(context, tmp_cred.client); 319 1.1 elric return ret; 320 1.1 elric } 321 1.2 christos /* 322 1.2 christos * The forwardable TGT might not be the start TGT, in which case, it is 323 1.2 christos * generally, but not always already cached. Just in case, get it again if 324 1.2 christos * lost. 325 1.2 christos */ 326 1.1 elric ret = krb5_get_credentials(context, 327 1.2 christos 0, 328 1.1 elric id, 329 1.1 elric &tmp_cred, 330 1.1 elric cred); 331 1.1 elric krb5_free_principal(context, tmp_cred.client); 332 1.1 elric krb5_free_principal(context, tmp_cred.server); 333 1.1 elric if(ret) 334 1.1 elric return ret; 335 1.1 elric return 0; 336 1.1 elric } 337 1.1 elric 338 1.1 elric /* DCE compatible decrypt proc */ 339 1.1 elric static krb5_error_code KRB5_CALLCONV 340 1.1 elric decrypt_tkt_with_subkey (krb5_context context, 341 1.1 elric krb5_keyblock *key, 342 1.1 elric krb5_key_usage usage, 343 1.1 elric krb5_const_pointer skey, 344 1.1 elric krb5_kdc_rep *dec_rep) 345 1.1 elric { 346 1.1 elric const krb5_keyblock *subkey = skey; 347 1.1 elric krb5_error_code ret = 0; 348 1.1 elric krb5_data data; 349 1.1 elric size_t size; 350 1.1 elric krb5_crypto crypto; 351 1.1 elric 352 1.1 elric assert(usage == 0); 353 1.1 elric 354 1.2 christos krb5_data_zero(&data); 355 1.2 christos 356 1.1 elric /* 357 1.1 elric * start out with trying with subkey if we have one 358 1.1 elric */ 359 1.1 elric if (subkey) { 360 1.1 elric ret = krb5_crypto_init(context, subkey, 0, &crypto); 361 1.1 elric if (ret) 362 1.1 elric return ret; 363 1.1 elric ret = krb5_decrypt_EncryptedData (context, 364 1.1 elric crypto, 365 1.1 elric KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 366 1.1 elric &dec_rep->kdc_rep.enc_part, 367 1.1 elric &data); 368 1.1 elric /* 369 1.1 elric * If the is Windows 2000 DC, we need to retry with key usage 370 1.1 elric * 8 when doing ARCFOUR. 371 1.1 elric */ 372 1.1 elric if (ret && subkey->keytype == ETYPE_ARCFOUR_HMAC_MD5) { 373 1.1 elric ret = krb5_decrypt_EncryptedData(context, 374 1.1 elric crypto, 375 1.1 elric 8, 376 1.1 elric &dec_rep->kdc_rep.enc_part, 377 1.1 elric &data); 378 1.1 elric } 379 1.1 elric krb5_crypto_destroy(context, crypto); 380 1.1 elric } 381 1.1 elric if (subkey == NULL || ret) { 382 1.1 elric ret = krb5_crypto_init(context, key, 0, &crypto); 383 1.1 elric if (ret) 384 1.1 elric return ret; 385 1.1 elric ret = krb5_decrypt_EncryptedData (context, 386 1.1 elric crypto, 387 1.1 elric KRB5_KU_TGS_REP_ENC_PART_SESSION, 388 1.1 elric &dec_rep->kdc_rep.enc_part, 389 1.1 elric &data); 390 1.1 elric krb5_crypto_destroy(context, crypto); 391 1.1 elric } 392 1.1 elric if (ret) 393 1.1 elric return ret; 394 1.1 elric 395 1.1 elric ret = decode_EncASRepPart(data.data, 396 1.1 elric data.length, 397 1.1 elric &dec_rep->enc_part, 398 1.1 elric &size); 399 1.1 elric if (ret) 400 1.1 elric ret = decode_EncTGSRepPart(data.data, 401 1.1 elric data.length, 402 1.1 elric &dec_rep->enc_part, 403 1.1 elric &size); 404 1.1 elric if (ret) 405 1.2 christos krb5_set_error_message(context, ret, 406 1.1 elric N_("Failed to decode encpart in ticket", "")); 407 1.1 elric krb5_data_free (&data); 408 1.1 elric return ret; 409 1.1 elric } 410 1.1 elric 411 1.1 elric static krb5_error_code 412 1.1 elric get_cred_kdc(krb5_context context, 413 1.1 elric krb5_ccache id, 414 1.1 elric krb5_kdc_flags flags, 415 1.1 elric krb5_addresses *addresses, 416 1.1 elric krb5_creds *in_creds, 417 1.1 elric krb5_creds *krbtgt, 418 1.1 elric krb5_principal impersonate_principal, 419 1.1 elric Ticket *second_ticket, 420 1.1 elric krb5_creds *out_creds) 421 1.1 elric { 422 1.1 elric TGS_REQ req; 423 1.1 elric krb5_data enc; 424 1.1 elric krb5_data resp; 425 1.4 christos krb5_kdc_rep rep = {0}; 426 1.1 elric KRB_ERROR error; 427 1.1 elric krb5_error_code ret; 428 1.1 elric unsigned nonce; 429 1.1 elric krb5_keyblock *subkey = NULL; 430 1.2 christos size_t len = 0; 431 1.1 elric Ticket second_ticket_data; 432 1.1 elric METHOD_DATA padata; 433 1.1 elric 434 1.1 elric krb5_data_zero(&resp); 435 1.1 elric krb5_data_zero(&enc); 436 1.1 elric padata.val = NULL; 437 1.1 elric padata.len = 0; 438 1.1 elric 439 1.1 elric krb5_generate_random_block(&nonce, sizeof(nonce)); 440 1.1 elric nonce &= 0xffffffff; 441 1.1 elric 442 1.1 elric if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ 443 1.1 elric ret = decode_Ticket(in_creds->second_ticket.data, 444 1.1 elric in_creds->second_ticket.length, 445 1.1 elric &second_ticket_data, &len); 446 1.1 elric if(ret) 447 1.1 elric return ret; 448 1.1 elric second_ticket = &second_ticket_data; 449 1.1 elric } 450 1.1 elric 451 1.1 elric 452 1.1 elric if (impersonate_principal) { 453 1.1 elric krb5_crypto crypto; 454 1.1 elric PA_S4U2Self self; 455 1.1 elric krb5_data data; 456 1.1 elric void *buf; 457 1.2 christos size_t size = 0; 458 1.1 elric 459 1.1 elric self.name = impersonate_principal->name; 460 1.1 elric self.realm = impersonate_principal->realm; 461 1.1 elric self.auth = estrdup("Kerberos"); 462 1.2 christos 463 1.1 elric ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); 464 1.1 elric if (ret) { 465 1.1 elric free(self.auth); 466 1.1 elric goto out; 467 1.1 elric } 468 1.1 elric 469 1.1 elric ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); 470 1.1 elric if (ret) { 471 1.1 elric free(self.auth); 472 1.1 elric krb5_data_free(&data); 473 1.1 elric goto out; 474 1.1 elric } 475 1.1 elric 476 1.1 elric ret = krb5_create_checksum(context, 477 1.1 elric crypto, 478 1.1 elric KRB5_KU_OTHER_CKSUM, 479 1.1 elric 0, 480 1.1 elric data.data, 481 1.1 elric data.length, 482 1.1 elric &self.cksum); 483 1.1 elric krb5_crypto_destroy(context, crypto); 484 1.1 elric krb5_data_free(&data); 485 1.1 elric if (ret) { 486 1.1 elric free(self.auth); 487 1.1 elric goto out; 488 1.1 elric } 489 1.1 elric 490 1.1 elric ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); 491 1.1 elric free(self.auth); 492 1.1 elric free_Checksum(&self.cksum); 493 1.1 elric if (ret) 494 1.1 elric goto out; 495 1.1 elric if (len != size) 496 1.1 elric krb5_abortx(context, "internal asn1 error"); 497 1.2 christos 498 1.1 elric ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); 499 1.1 elric if (ret) 500 1.1 elric goto out; 501 1.1 elric } 502 1.1 elric 503 1.1 elric ret = init_tgs_req (context, 504 1.1 elric id, 505 1.1 elric addresses, 506 1.1 elric flags, 507 1.1 elric second_ticket, 508 1.1 elric in_creds, 509 1.1 elric krbtgt, 510 1.1 elric nonce, 511 1.1 elric &padata, 512 1.1 elric &subkey, 513 1.1 elric &req); 514 1.1 elric if (ret) 515 1.1 elric goto out; 516 1.1 elric 517 1.1 elric ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); 518 1.1 elric if (ret) 519 1.1 elric goto out; 520 1.1 elric if(enc.length != len) 521 1.1 elric krb5_abortx(context, "internal error in ASN.1 encoder"); 522 1.1 elric 523 1.1 elric /* don't free addresses */ 524 1.1 elric req.req_body.addresses = NULL; 525 1.1 elric free_TGS_REQ(&req); 526 1.1 elric 527 1.1 elric /* 528 1.1 elric * Send and receive 529 1.1 elric */ 530 1.1 elric { 531 1.1 elric krb5_sendto_ctx stctx; 532 1.1 elric ret = krb5_sendto_ctx_alloc(context, &stctx); 533 1.1 elric if (ret) 534 1.1 elric return ret; 535 1.1 elric krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); 536 1.1 elric 537 1.1 elric ret = krb5_sendto_context (context, stctx, &enc, 538 1.1 elric krbtgt->server->name.name_string.val[1], 539 1.1 elric &resp); 540 1.1 elric krb5_sendto_ctx_free(context, stctx); 541 1.1 elric } 542 1.1 elric if(ret) 543 1.1 elric goto out; 544 1.1 elric 545 1.1 elric if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) { 546 1.1 elric unsigned eflags = 0; 547 1.1 elric 548 1.1 elric ret = krb5_copy_principal(context, 549 1.1 elric in_creds->client, 550 1.1 elric &out_creds->client); 551 1.1 elric if(ret) 552 1.1 elric goto out2; 553 1.1 elric ret = krb5_copy_principal(context, 554 1.1 elric in_creds->server, 555 1.1 elric &out_creds->server); 556 1.1 elric if(ret) 557 1.1 elric goto out2; 558 1.1 elric /* this should go someplace else */ 559 1.1 elric out_creds->times.endtime = in_creds->times.endtime; 560 1.1 elric 561 1.1 elric /* XXX should do better testing */ 562 1.3 christos if (flags.b.cname_in_addl_tkt || impersonate_principal) 563 1.1 elric eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; 564 1.3 christos if (flags.b.request_anonymous) 565 1.3 christos eflags |= EXTRACT_TICKET_MATCH_ANON; 566 1.1 elric 567 1.1 elric ret = _krb5_extract_ticket(context, 568 1.1 elric &rep, 569 1.1 elric out_creds, 570 1.1 elric &krbtgt->session, 571 1.1 elric NULL, 572 1.1 elric 0, 573 1.1 elric &krbtgt->addresses, 574 1.1 elric nonce, 575 1.1 elric eflags, 576 1.2 christos NULL, 577 1.1 elric decrypt_tkt_with_subkey, 578 1.1 elric subkey); 579 1.1 elric out2: 580 1.1 elric krb5_free_kdc_rep(context, &rep); 581 1.1 elric } else if(krb5_rd_error(context, &resp, &error) == 0) { 582 1.1 elric ret = krb5_error_from_rd_error(context, &error, in_creds); 583 1.1 elric krb5_free_error_contents(context, &error); 584 1.1 elric } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { 585 1.1 elric ret = KRB5KRB_AP_ERR_V4_REPLY; 586 1.1 elric krb5_clear_error_message(context); 587 1.1 elric } else { 588 1.1 elric ret = KRB5KRB_AP_ERR_MSG_TYPE; 589 1.1 elric krb5_clear_error_message(context); 590 1.1 elric } 591 1.1 elric 592 1.1 elric out: 593 1.1 elric if (second_ticket == &second_ticket_data) 594 1.1 elric free_Ticket(&second_ticket_data); 595 1.1 elric free_METHOD_DATA(&padata); 596 1.1 elric krb5_data_free(&resp); 597 1.1 elric krb5_data_free(&enc); 598 1.1 elric if(subkey) 599 1.1 elric krb5_free_keyblock(context, subkey); 600 1.1 elric return ret; 601 1.1 elric 602 1.1 elric } 603 1.1 elric 604 1.1 elric /* 605 1.1 elric * same as above, just get local addresses first if the krbtgt have 606 1.1 elric * them and the realm is not addressless 607 1.1 elric */ 608 1.1 elric 609 1.1 elric static krb5_error_code 610 1.1 elric get_cred_kdc_address(krb5_context context, 611 1.1 elric krb5_ccache id, 612 1.1 elric krb5_kdc_flags flags, 613 1.1 elric krb5_addresses *addrs, 614 1.1 elric krb5_creds *in_creds, 615 1.1 elric krb5_creds *krbtgt, 616 1.1 elric krb5_principal impersonate_principal, 617 1.1 elric Ticket *second_ticket, 618 1.1 elric krb5_creds *out_creds) 619 1.1 elric { 620 1.1 elric krb5_error_code ret; 621 1.1 elric krb5_addresses addresses = { 0, NULL }; 622 1.1 elric 623 1.1 elric /* 624 1.1 elric * Inherit the address-ness of the krbtgt if the address is not 625 1.1 elric * specified. 626 1.1 elric */ 627 1.1 elric 628 1.1 elric if (addrs == NULL && krbtgt->addresses.len != 0) { 629 1.1 elric krb5_boolean noaddr; 630 1.1 elric 631 1.1 elric krb5_appdefault_boolean(context, NULL, krbtgt->server->realm, 632 1.1 elric "no-addresses", FALSE, &noaddr); 633 1.2 christos 634 1.1 elric if (!noaddr) { 635 1.1 elric krb5_get_all_client_addrs(context, &addresses); 636 1.1 elric /* XXX this sucks. */ 637 1.1 elric addrs = &addresses; 638 1.1 elric if(addresses.len == 0) 639 1.1 elric addrs = NULL; 640 1.1 elric } 641 1.1 elric } 642 1.1 elric ret = get_cred_kdc(context, id, flags, addrs, in_creds, 643 1.1 elric krbtgt, impersonate_principal, 644 1.1 elric second_ticket, out_creds); 645 1.1 elric krb5_free_addresses(context, &addresses); 646 1.1 elric return ret; 647 1.1 elric } 648 1.1 elric 649 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 650 1.1 elric krb5_get_kdc_cred(krb5_context context, 651 1.1 elric krb5_ccache id, 652 1.1 elric krb5_kdc_flags flags, 653 1.1 elric krb5_addresses *addresses, 654 1.1 elric Ticket *second_ticket, 655 1.1 elric krb5_creds *in_creds, 656 1.1 elric krb5_creds **out_creds 657 1.1 elric ) 658 1.1 elric { 659 1.1 elric krb5_error_code ret; 660 1.1 elric krb5_creds *krbtgt; 661 1.1 elric 662 1.1 elric *out_creds = calloc(1, sizeof(**out_creds)); 663 1.2 christos if(*out_creds == NULL) 664 1.2 christos return krb5_enomem(context); 665 1.1 elric ret = _krb5_get_krbtgt (context, 666 1.1 elric id, 667 1.1 elric in_creds->server->realm, 668 1.1 elric &krbtgt); 669 1.1 elric if(ret) { 670 1.1 elric free(*out_creds); 671 1.1 elric *out_creds = NULL; 672 1.1 elric return ret; 673 1.1 elric } 674 1.1 elric ret = get_cred_kdc(context, id, flags, addresses, 675 1.1 elric in_creds, krbtgt, NULL, NULL, *out_creds); 676 1.1 elric krb5_free_creds (context, krbtgt); 677 1.1 elric if(ret) { 678 1.1 elric free(*out_creds); 679 1.1 elric *out_creds = NULL; 680 1.1 elric } 681 1.1 elric return ret; 682 1.1 elric } 683 1.1 elric 684 1.1 elric static int 685 1.1 elric not_found(krb5_context context, krb5_const_principal p, krb5_error_code code) 686 1.1 elric { 687 1.1 elric krb5_error_code ret; 688 1.4 christos const char *err; 689 1.1 elric char *str; 690 1.1 elric 691 1.4 christos err = krb5_get_error_message(context, code); 692 1.1 elric ret = krb5_unparse_name(context, p, &str); 693 1.1 elric if(ret) { 694 1.1 elric krb5_clear_error_message(context); 695 1.1 elric return code; 696 1.1 elric } 697 1.4 christos krb5_set_error_message(context, code, N_("%s (%s)", ""), err, str); 698 1.1 elric free(str); 699 1.1 elric return code; 700 1.1 elric } 701 1.1 elric 702 1.1 elric static krb5_error_code 703 1.1 elric find_cred(krb5_context context, 704 1.1 elric krb5_ccache id, 705 1.1 elric krb5_principal server, 706 1.1 elric krb5_creds **tgts, 707 1.1 elric krb5_creds *out_creds) 708 1.1 elric { 709 1.1 elric krb5_error_code ret; 710 1.1 elric krb5_creds mcreds; 711 1.1 elric 712 1.1 elric krb5_cc_clear_mcred(&mcreds); 713 1.1 elric mcreds.server = server; 714 1.2 christos krb5_timeofday(context, &mcreds.times.endtime); 715 1.2 christos ret = krb5_cc_retrieve_cred(context, id, 716 1.2 christos KRB5_TC_DONT_MATCH_REALM | 717 1.2 christos KRB5_TC_MATCH_TIMES, 718 1.1 elric &mcreds, out_creds); 719 1.1 elric if(ret == 0) 720 1.1 elric return 0; 721 1.1 elric while(tgts && *tgts){ 722 1.1 elric if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 723 1.1 elric &mcreds, *tgts)){ 724 1.1 elric ret = krb5_copy_creds_contents(context, *tgts, out_creds); 725 1.1 elric return ret; 726 1.1 elric } 727 1.1 elric tgts++; 728 1.1 elric } 729 1.1 elric return not_found(context, server, KRB5_CC_NOTFOUND); 730 1.1 elric } 731 1.1 elric 732 1.1 elric static krb5_error_code 733 1.1 elric add_cred(krb5_context context, krb5_creds const *tkt, krb5_creds ***tgts) 734 1.1 elric { 735 1.1 elric int i; 736 1.1 elric krb5_error_code ret; 737 1.1 elric krb5_creds **tmp = *tgts; 738 1.1 elric 739 1.1 elric for(i = 0; tmp && tmp[i]; i++); /* XXX */ 740 1.1 elric tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 741 1.2 christos if(tmp == NULL) 742 1.2 christos return krb5_enomem(context); 743 1.1 elric *tgts = tmp; 744 1.1 elric ret = krb5_copy_creds(context, tkt, &tmp[i]); 745 1.1 elric tmp[i+1] = NULL; 746 1.1 elric return ret; 747 1.1 elric } 748 1.1 elric 749 1.1 elric static krb5_error_code 750 1.1 elric get_cred_kdc_capath_worker(krb5_context context, 751 1.1 elric krb5_kdc_flags flags, 752 1.1 elric krb5_ccache ccache, 753 1.1 elric krb5_creds *in_creds, 754 1.1 elric krb5_const_realm try_realm, 755 1.1 elric krb5_principal impersonate_principal, 756 1.2 christos Ticket *second_ticket, 757 1.1 elric krb5_creds **out_creds, 758 1.1 elric krb5_creds ***ret_tgts) 759 1.1 elric { 760 1.1 elric krb5_error_code ret; 761 1.2 christos krb5_creds *tgt = NULL; 762 1.2 christos krb5_creds tmp_creds; 763 1.1 elric krb5_const_realm client_realm, server_realm; 764 1.1 elric int ok_as_delegate = 1; 765 1.1 elric 766 1.2 christos *out_creds = calloc(1, sizeof(**out_creds)); 767 1.2 christos if (*out_creds == NULL) 768 1.2 christos return krb5_enomem(context); 769 1.2 christos 770 1.2 christos memset(&tmp_creds, 0, sizeof(tmp_creds)); 771 1.1 elric 772 1.1 elric client_realm = krb5_principal_get_realm(context, in_creds->client); 773 1.1 elric server_realm = krb5_principal_get_realm(context, in_creds->server); 774 1.1 elric ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 775 1.2 christos if (ret) 776 1.2 christos goto out; 777 1.1 elric 778 1.1 elric ret = krb5_make_principal(context, 779 1.1 elric &tmp_creds.server, 780 1.1 elric try_realm, 781 1.1 elric KRB5_TGS_NAME, 782 1.1 elric server_realm, 783 1.1 elric NULL); 784 1.2 christos if (ret) 785 1.2 christos goto out; 786 1.2 christos 787 1.1 elric { 788 1.1 elric krb5_creds tgts; 789 1.1 elric 790 1.2 christos /* 791 1.2 christos * If we have krbtgt/server_realm@try_realm cached, use it and we're 792 1.2 christos * done. 793 1.2 christos */ 794 1.1 elric ret = find_cred(context, ccache, tmp_creds.server, 795 1.1 elric *ret_tgts, &tgts); 796 1.2 christos if (ret == 0) { 797 1.1 elric /* only allow implicit ok_as_delegate if the realm is the clients realm */ 798 1.2 christos if (strcmp(try_realm, client_realm) != 0 799 1.2 christos || strcmp(try_realm, server_realm) != 0) { 800 1.1 elric ok_as_delegate = tgts.flags.b.ok_as_delegate; 801 1.2 christos } 802 1.1 elric 803 1.2 christos ret = get_cred_kdc_address(context, ccache, flags, NULL, 804 1.2 christos in_creds, &tgts, 805 1.2 christos impersonate_principal, 806 1.2 christos second_ticket, 807 1.2 christos *out_creds); 808 1.2 christos krb5_free_cred_contents(context, &tgts); 809 1.2 christos if (ret == 0 && 810 1.2 christos !krb5_principal_compare(context, in_creds->server, 811 1.2 christos (*out_creds)->server)) { 812 1.2 christos ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 813 1.1 elric } 814 1.2 christos if (ret == 0 && ok_as_delegate == 0) 815 1.2 christos (*out_creds)->flags.b.ok_as_delegate = 0; 816 1.2 christos 817 1.2 christos goto out; 818 1.1 elric } 819 1.1 elric } 820 1.1 elric 821 1.2 christos if (krb5_realm_compare(context, in_creds->client, in_creds->server)) { 822 1.2 christos ret = not_found(context, in_creds->server, KRB5_CC_NOTFOUND); 823 1.2 christos goto out; 824 1.2 christos } 825 1.2 christos 826 1.2 christos /* 827 1.2 christos * XXX This can loop forever, plus we recurse, so we can't just keep a 828 1.2 christos * count here. The count would have to get passed around by reference. 829 1.2 christos * 830 1.2 christos * The KDCs check for transit loops for us, and capath data is finite, so 831 1.2 christos * in fact we'll fall out of this loop at some point. We should do our own 832 1.2 christos * transit loop checking (like get_cred_kdc_referral()), and we should 833 1.2 christos * impose a max number of iterations altogether. But barring malicious or 834 1.2 christos * broken KDCs, this is good enough. 835 1.2 christos */ 836 1.2 christos while (1) { 837 1.1 elric heim_general_string tgt_inst; 838 1.1 elric 839 1.1 elric ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds, 840 1.1 elric NULL, NULL, &tgt, ret_tgts); 841 1.2 christos if (ret) 842 1.2 christos goto out; 843 1.2 christos 844 1.2 christos /* 845 1.1 elric * if either of the chain or the ok_as_delegate was stripped 846 1.1 elric * by the kdc, make sure we strip it too. 847 1.1 elric */ 848 1.1 elric if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) { 849 1.1 elric ok_as_delegate = 0; 850 1.1 elric tgt->flags.b.ok_as_delegate = 0; 851 1.1 elric } 852 1.1 elric 853 1.1 elric ret = add_cred(context, tgt, ret_tgts); 854 1.2 christos if (ret) 855 1.2 christos goto out; 856 1.1 elric tgt_inst = tgt->server->name.name_string.val[1]; 857 1.2 christos if (strcmp(tgt_inst, server_realm) == 0) 858 1.1 elric break; 859 1.1 elric krb5_free_principal(context, tmp_creds.server); 860 1.2 christos tmp_creds.server = NULL; 861 1.1 elric ret = krb5_make_principal(context, &tmp_creds.server, 862 1.1 elric tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 863 1.2 christos if (ret) 864 1.2 christos goto out; 865 1.1 elric ret = krb5_free_creds(context, tgt); 866 1.2 christos tgt = NULL; 867 1.2 christos if (ret) 868 1.2 christos goto out; 869 1.2 christos } 870 1.2 christos 871 1.2 christos ret = get_cred_kdc_address(context, ccache, flags, NULL, 872 1.2 christos in_creds, tgt, impersonate_principal, 873 1.2 christos second_ticket, *out_creds); 874 1.2 christos if (ret == 0 && 875 1.2 christos !krb5_principal_compare(context, in_creds->server, 876 1.2 christos (*out_creds)->server)) { 877 1.2 christos krb5_free_cred_contents(context, *out_creds); 878 1.2 christos ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 879 1.1 elric } 880 1.2 christos if (ret == 0 && ok_as_delegate == 0) 881 1.2 christos (*out_creds)->flags.b.ok_as_delegate = 0; 882 1.2 christos 883 1.2 christos out: 884 1.2 christos if (ret) { 885 1.2 christos krb5_free_creds(context, *out_creds); 886 1.2 christos *out_creds = NULL; 887 1.1 elric } 888 1.2 christos if (tmp_creds.server) 889 1.2 christos krb5_free_principal(context, tmp_creds.server); 890 1.2 christos if (tmp_creds.client) 891 1.2 christos krb5_free_principal(context, tmp_creds.client); 892 1.2 christos if (tgt) 893 1.2 christos krb5_free_creds(context, tgt); 894 1.1 elric return ret; 895 1.2 christos } 896 1.1 elric 897 1.1 elric /* 898 1.1 elric get_cred(server) 899 1.1 elric creds = cc_get_cred(server) 900 1.1 elric if(creds) return creds 901 1.1 elric tgt = cc_get_cred(krbtgt/server_realm@any_realm) 902 1.1 elric if(tgt) 903 1.1 elric return get_cred_tgt(server, tgt) 904 1.1 elric if(client_realm == server_realm) 905 1.1 elric return NULL 906 1.1 elric tgt = get_cred(krbtgt/server_realm@client_realm) 907 1.1 elric while(tgt_inst != server_realm) 908 1.1 elric tgt = get_cred(krbtgt/server_realm@tgt_inst) 909 1.1 elric return get_cred_tgt(server, tgt) 910 1.1 elric */ 911 1.1 elric 912 1.1 elric static krb5_error_code 913 1.1 elric get_cred_kdc_capath(krb5_context context, 914 1.1 elric krb5_kdc_flags flags, 915 1.1 elric krb5_ccache ccache, 916 1.1 elric krb5_creds *in_creds, 917 1.1 elric krb5_principal impersonate_principal, 918 1.2 christos Ticket *second_ticket, 919 1.1 elric krb5_creds **out_creds, 920 1.1 elric krb5_creds ***ret_tgts) 921 1.1 elric { 922 1.1 elric krb5_error_code ret; 923 1.1 elric krb5_const_realm client_realm, server_realm, try_realm; 924 1.1 elric 925 1.1 elric client_realm = krb5_principal_get_realm(context, in_creds->client); 926 1.1 elric server_realm = krb5_principal_get_realm(context, in_creds->server); 927 1.1 elric 928 1.1 elric try_realm = client_realm; 929 1.1 elric ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, try_realm, 930 1.1 elric impersonate_principal, second_ticket, out_creds, 931 1.1 elric ret_tgts); 932 1.1 elric 933 1.1 elric if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { 934 1.1 elric try_realm = krb5_config_get_string(context, NULL, "capaths", 935 1.1 elric client_realm, server_realm, NULL); 936 1.1 elric 937 1.1 elric if (try_realm != NULL && strcmp(try_realm, client_realm)) { 938 1.1 elric ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, 939 1.1 elric try_realm, impersonate_principal, 940 1.1 elric second_ticket, out_creds, ret_tgts); 941 1.1 elric } 942 1.1 elric } 943 1.1 elric 944 1.1 elric return ret; 945 1.1 elric } 946 1.1 elric 947 1.2 christos /* 948 1.2 christos * Get a service ticket from a KDC by chasing referrals from a start realm. 949 1.2 christos * 950 1.2 christos * All referral TGTs produced in the process are thrown away when we're done. 951 1.2 christos * We don't store them, and we don't allow other search mechanisms (capaths) to 952 1.2 christos * use referral TGTs produced here. 953 1.2 christos */ 954 1.1 elric static krb5_error_code 955 1.1 elric get_cred_kdc_referral(krb5_context context, 956 1.1 elric krb5_kdc_flags flags, 957 1.1 elric krb5_ccache ccache, 958 1.1 elric krb5_creds *in_creds, 959 1.1 elric krb5_principal impersonate_principal, 960 1.2 christos Ticket *second_ticket, 961 1.2 christos krb5_creds **out_creds) 962 1.1 elric { 963 1.2 christos krb5_realm start_realm = NULL; 964 1.2 christos krb5_data config_start_realm; 965 1.1 elric krb5_error_code ret; 966 1.1 elric krb5_creds tgt, referral, ticket; 967 1.2 christos krb5_creds **referral_tgts = NULL; /* used for loop detection */ 968 1.1 elric int loop = 0; 969 1.1 elric int ok_as_delegate = 1; 970 1.2 christos size_t i; 971 1.1 elric 972 1.1 elric if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) { 973 1.1 elric krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED, 974 1.1 elric N_("Name too short to do referals, skipping", "")); 975 1.1 elric return KRB5KDC_ERR_PATH_NOT_ACCEPTED; 976 1.1 elric } 977 1.1 elric 978 1.1 elric memset(&tgt, 0, sizeof(tgt)); 979 1.1 elric memset(&ticket, 0, sizeof(ticket)); 980 1.1 elric 981 1.1 elric flags.b.canonicalize = 1; 982 1.1 elric 983 1.1 elric *out_creds = NULL; 984 1.1 elric 985 1.2 christos 986 1.2 christos ret = krb5_cc_get_config(context, ccache, NULL, "start_realm", &config_start_realm); 987 1.2 christos if (ret == 0) { 988 1.2 christos start_realm = strndup(config_start_realm.data, config_start_realm.length); 989 1.2 christos krb5_data_free(&config_start_realm); 990 1.2 christos } else { 991 1.2 christos start_realm = strdup(krb5_principal_get_realm(context, in_creds->client)); 992 1.2 christos } 993 1.2 christos if (start_realm == NULL) 994 1.2 christos return krb5_enomem(context); 995 1.1 elric 996 1.1 elric /* find tgt for the clients base realm */ 997 1.1 elric { 998 1.1 elric krb5_principal tgtname; 999 1.2 christos 1000 1.1 elric ret = krb5_make_principal(context, &tgtname, 1001 1.2 christos start_realm, 1002 1.1 elric KRB5_TGS_NAME, 1003 1.2 christos start_realm, 1004 1.1 elric NULL); 1005 1.2 christos if (ret) { 1006 1.2 christos free(start_realm); 1007 1.1 elric return ret; 1008 1.2 christos } 1009 1.2 christos 1010 1.2 christos ret = find_cred(context, ccache, tgtname, NULL, &tgt); 1011 1.1 elric krb5_free_principal(context, tgtname); 1012 1.2 christos if (ret) { 1013 1.2 christos free(start_realm); 1014 1.1 elric return ret; 1015 1.2 christos } 1016 1.1 elric } 1017 1.1 elric 1018 1.1 elric referral = *in_creds; 1019 1.1 elric ret = krb5_copy_principal(context, in_creds->server, &referral.server); 1020 1.1 elric if (ret) { 1021 1.1 elric krb5_free_cred_contents(context, &tgt); 1022 1.2 christos free(start_realm); 1023 1.1 elric return ret; 1024 1.1 elric } 1025 1.2 christos ret = krb5_principal_set_realm(context, referral.server, start_realm); 1026 1.2 christos free(start_realm); 1027 1.2 christos start_realm = NULL; 1028 1.1 elric if (ret) { 1029 1.1 elric krb5_free_cred_contents(context, &tgt); 1030 1.1 elric krb5_free_principal(context, referral.server); 1031 1.1 elric return ret; 1032 1.1 elric } 1033 1.1 elric 1034 1.1 elric while (loop++ < 17) { 1035 1.1 elric krb5_creds **tickets; 1036 1.1 elric krb5_creds mcreds; 1037 1.1 elric char *referral_realm; 1038 1.1 elric 1039 1.2 christos /* Use cache if we are not doing impersonation or contrained deleg */ 1040 1.3 christos if (impersonate_principal == NULL || flags.b.cname_in_addl_tkt) { 1041 1.1 elric krb5_cc_clear_mcred(&mcreds); 1042 1.1 elric mcreds.server = referral.server; 1043 1.2 christos krb5_timeofday(context, &mcreds.times.endtime); 1044 1.2 christos ret = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_TIMES, 1045 1.2 christos &mcreds, &ticket); 1046 1.1 elric } else 1047 1.1 elric ret = EINVAL; 1048 1.1 elric 1049 1.1 elric if (ret) { 1050 1.1 elric ret = get_cred_kdc_address(context, ccache, flags, NULL, 1051 1.1 elric &referral, &tgt, impersonate_principal, 1052 1.1 elric second_ticket, &ticket); 1053 1.1 elric if (ret) 1054 1.1 elric goto out; 1055 1.1 elric } 1056 1.1 elric 1057 1.1 elric /* Did we get the right ticket ? */ 1058 1.1 elric if (krb5_principal_compare_any_realm(context, 1059 1.1 elric referral.server, 1060 1.1 elric ticket.server)) 1061 1.1 elric break; 1062 1.1 elric 1063 1.1 elric if (!krb5_principal_is_krbtgt(context, ticket.server)) { 1064 1.1 elric krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US, 1065 1.1 elric N_("Got back an non krbtgt " 1066 1.1 elric "ticket referrals", "")); 1067 1.1 elric ret = KRB5KRB_AP_ERR_NOT_US; 1068 1.1 elric goto out; 1069 1.1 elric } 1070 1.1 elric 1071 1.1 elric referral_realm = ticket.server->name.name_string.val[1]; 1072 1.1 elric 1073 1.1 elric /* check that there are no referrals loops */ 1074 1.2 christos tickets = referral_tgts; 1075 1.1 elric 1076 1.1 elric krb5_cc_clear_mcred(&mcreds); 1077 1.1 elric mcreds.server = ticket.server; 1078 1.1 elric 1079 1.2 christos while (tickets && *tickets){ 1080 1.2 christos if (krb5_compare_creds(context, 1081 1.1 elric KRB5_TC_DONT_MATCH_REALM, 1082 1.1 elric &mcreds, 1083 1.2 christos *tickets)) { 1084 1.1 elric krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1085 1.1 elric N_("Referral from %s " 1086 1.1 elric "loops back to realm %s", ""), 1087 1.1 elric tgt.server->realm, 1088 1.1 elric referral_realm); 1089 1.1 elric ret = KRB5_GET_IN_TKT_LOOP; 1090 1.1 elric goto out; 1091 1.1 elric } 1092 1.1 elric tickets++; 1093 1.2 christos } 1094 1.1 elric 1095 1.2 christos /* 1096 1.1 elric * if either of the chain or the ok_as_delegate was stripped 1097 1.1 elric * by the kdc, make sure we strip it too. 1098 1.1 elric */ 1099 1.1 elric 1100 1.1 elric if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) { 1101 1.1 elric ok_as_delegate = 0; 1102 1.1 elric ticket.flags.b.ok_as_delegate = 0; 1103 1.1 elric } 1104 1.1 elric 1105 1.2 christos _krb5_debug(context, 6, "get_cred_kdc_referral: got referral " 1106 1.2 christos "to %s from %s", referral_realm, referral.server->realm); 1107 1.2 christos ret = add_cred(context, &ticket, &referral_tgts); 1108 1.1 elric if (ret) 1109 1.1 elric goto out; 1110 1.1 elric 1111 1.1 elric /* try realm in the referral */ 1112 1.1 elric ret = krb5_principal_set_realm(context, 1113 1.1 elric referral.server, 1114 1.1 elric referral_realm); 1115 1.1 elric krb5_free_cred_contents(context, &tgt); 1116 1.1 elric tgt = ticket; 1117 1.1 elric memset(&ticket, 0, sizeof(ticket)); 1118 1.1 elric if (ret) 1119 1.1 elric goto out; 1120 1.1 elric } 1121 1.1 elric 1122 1.1 elric ret = krb5_copy_creds(context, &ticket, out_creds); 1123 1.1 elric 1124 1.1 elric out: 1125 1.2 christos for (i = 0; referral_tgts && referral_tgts[i]; i++) 1126 1.2 christos krb5_free_creds(context, referral_tgts[i]); 1127 1.2 christos free(referral_tgts); 1128 1.1 elric krb5_free_principal(context, referral.server); 1129 1.1 elric krb5_free_cred_contents(context, &tgt); 1130 1.1 elric krb5_free_cred_contents(context, &ticket); 1131 1.1 elric return ret; 1132 1.1 elric } 1133 1.1 elric 1134 1.1 elric 1135 1.1 elric /* 1136 1.1 elric * Glue function between referrals version and old client chasing 1137 1.1 elric * codebase. 1138 1.1 elric */ 1139 1.1 elric 1140 1.2 christos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1141 1.1 elric _krb5_get_cred_kdc_any(krb5_context context, 1142 1.1 elric krb5_kdc_flags flags, 1143 1.1 elric krb5_ccache ccache, 1144 1.1 elric krb5_creds *in_creds, 1145 1.1 elric krb5_principal impersonate_principal, 1146 1.2 christos Ticket *second_ticket, 1147 1.1 elric krb5_creds **out_creds, 1148 1.1 elric krb5_creds ***ret_tgts) 1149 1.1 elric { 1150 1.1 elric krb5_error_code ret; 1151 1.1 elric krb5_deltat offset; 1152 1.1 elric 1153 1.1 elric ret = krb5_cc_get_kdc_offset(context, ccache, &offset); 1154 1.2 christos if (ret == 0) { 1155 1.1 elric context->kdc_sec_offset = offset; 1156 1.1 elric context->kdc_usec_offset = 0; 1157 1.1 elric } 1158 1.1 elric 1159 1.2 christos if (strcmp(in_creds->server->realm, "") != 0) { 1160 1.2 christos /* 1161 1.2 christos * Non-empty realm? Try capaths first. We might have local 1162 1.2 christos * policy (capaths) to honor. 1163 1.2 christos */ 1164 1.2 christos ret = get_cred_kdc_capath(context, 1165 1.2 christos flags, 1166 1.2 christos ccache, 1167 1.2 christos in_creds, 1168 1.2 christos impersonate_principal, 1169 1.2 christos second_ticket, 1170 1.2 christos out_creds, 1171 1.2 christos ret_tgts); 1172 1.2 christos if (ret == 0) 1173 1.2 christos return ret; 1174 1.2 christos } 1175 1.2 christos 1176 1.2 christos /* Otherwise try referrals */ 1177 1.2 christos return get_cred_kdc_referral(context, 1178 1.2 christos flags, 1179 1.2 christos ccache, 1180 1.2 christos in_creds, 1181 1.2 christos impersonate_principal, 1182 1.2 christos second_ticket, 1183 1.2 christos out_creds); 1184 1.2 christos } 1185 1.2 christos 1186 1.2 christos static krb5_error_code 1187 1.2 christos check_cc(krb5_context context, krb5_flags options, krb5_ccache ccache, 1188 1.2 christos krb5_creds *in_creds, krb5_creds *out_creds) 1189 1.2 christos { 1190 1.2 christos krb5_error_code ret; 1191 1.2 christos krb5_timestamp now; 1192 1.3 christos krb5_creds mcreds = *in_creds; 1193 1.2 christos 1194 1.2 christos krb5_timeofday(context, &now); 1195 1.2 christos 1196 1.2 christos if (!(options & KRB5_GC_EXPIRED_OK) && 1197 1.3 christos mcreds.times.endtime < now) { 1198 1.3 christos mcreds.times.renew_till = 0; 1199 1.3 christos krb5_timeofday(context, &mcreds.times.endtime); 1200 1.2 christos options |= KRB5_TC_MATCH_TIMES; 1201 1.2 christos } 1202 1.2 christos 1203 1.3 christos if (mcreds.server->name.name_type == KRB5_NT_SRV_HST_NEEDS_CANON) { 1204 1.2 christos /* Avoid name canonicalization in krb5_cc_retrieve_cred() */ 1205 1.3 christos krb5_principal_set_type(context, mcreds.server, KRB5_NT_SRV_HST); 1206 1.3 christos } 1207 1.3 christos 1208 1.3 christos if (options & KRB5_GC_ANONYMOUS) { 1209 1.3 christos ret = krb5_make_principal(context, 1210 1.3 christos &mcreds.client, 1211 1.3 christos krb5_principal_get_realm(context, mcreds.client), 1212 1.3 christos KRB5_WELLKNOWN_NAME, 1213 1.3 christos KRB5_ANON_NAME, 1214 1.3 christos NULL); 1215 1.3 christos if (ret) 1216 1.3 christos return ret; 1217 1.2 christos } 1218 1.2 christos 1219 1.2 christos ret = krb5_cc_retrieve_cred(context, ccache, 1220 1.2 christos (options & 1221 1.2 christos (KRB5_TC_DONT_MATCH_REALM | 1222 1.2 christos KRB5_TC_MATCH_KEYTYPE | 1223 1.2 christos KRB5_TC_MATCH_TIMES)), 1224 1.3 christos &mcreds, out_creds); 1225 1.3 christos 1226 1.3 christos if (options & KRB5_GC_ANONYMOUS) 1227 1.3 christos krb5_free_principal(context, mcreds.client); 1228 1.2 christos 1229 1.2 christos return ret; 1230 1.2 christos } 1231 1.2 christos 1232 1.2 christos static void 1233 1.2 christos store_cred(krb5_context context, krb5_ccache ccache, 1234 1.2 christos krb5_const_principal server_princ, krb5_creds *creds) 1235 1.2 christos { 1236 1.2 christos if (!krb5_principal_compare(context, creds->server, server_princ)) { 1237 1.2 christos krb5_principal tmp_princ = creds->server; 1238 1.2 christos /* 1239 1.2 christos * Store the cred with the pre-canon server princ first so it 1240 1.2 christos * can be found quickly in the future. 1241 1.2 christos */ 1242 1.2 christos creds->server = (krb5_principal)server_princ; 1243 1.2 christos krb5_cc_store_cred(context, ccache, creds); 1244 1.2 christos creds->server = tmp_princ; 1245 1.2 christos /* Then store again with the canonicalized server princ */ 1246 1.2 christos } 1247 1.2 christos krb5_cc_store_cred(context, ccache, creds); 1248 1.1 elric } 1249 1.1 elric 1250 1.1 elric 1251 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1252 1.1 elric krb5_get_credentials_with_flags(krb5_context context, 1253 1.1 elric krb5_flags options, 1254 1.1 elric krb5_kdc_flags flags, 1255 1.1 elric krb5_ccache ccache, 1256 1.1 elric krb5_creds *in_creds, 1257 1.1 elric krb5_creds **out_creds) 1258 1.1 elric { 1259 1.1 elric krb5_error_code ret; 1260 1.2 christos krb5_name_canon_iterator name_canon_iter = NULL; 1261 1.2 christos krb5_name_canon_rule_options rule_opts; 1262 1.2 christos krb5_const_principal try_princ = NULL; 1263 1.2 christos krb5_principal save_princ = in_creds->server; 1264 1.1 elric krb5_creds **tgts; 1265 1.1 elric krb5_creds *res_creds; 1266 1.1 elric int i; 1267 1.1 elric 1268 1.2 christos if (_krb5_have_debug(context, 5)) { 1269 1.2 christos char *unparsed; 1270 1.2 christos 1271 1.2 christos ret = krb5_unparse_name(context, in_creds->server, &unparsed); 1272 1.2 christos if (ret) { 1273 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: unable to display " 1274 1.2 christos "requested service principal"); 1275 1.2 christos } else { 1276 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: requesting a ticket " 1277 1.2 christos "for %s", unparsed); 1278 1.2 christos free(unparsed); 1279 1.2 christos } 1280 1.2 christos } 1281 1.2 christos 1282 1.1 elric if (in_creds->session.keytype) { 1283 1.1 elric ret = krb5_enctype_valid(context, in_creds->session.keytype); 1284 1.1 elric if (ret) 1285 1.1 elric return ret; 1286 1.2 christos options |= KRB5_TC_MATCH_KEYTYPE; 1287 1.1 elric } 1288 1.1 elric 1289 1.1 elric *out_creds = NULL; 1290 1.1 elric res_creds = calloc(1, sizeof(*res_creds)); 1291 1.2 christos if (res_creds == NULL) 1292 1.2 christos return krb5_enomem(context); 1293 1.1 elric 1294 1.2 christos ret = krb5_name_canon_iterator_start(context, in_creds->server, 1295 1.2 christos &name_canon_iter); 1296 1.2 christos if (ret) 1297 1.2 christos return ret; 1298 1.1 elric 1299 1.2 christos next_rule: 1300 1.2 christos krb5_free_cred_contents(context, res_creds); 1301 1.2 christos memset(res_creds, 0, sizeof (*res_creds)); 1302 1.2 christos ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ, 1303 1.2 christos &rule_opts); 1304 1.2 christos in_creds->server = rk_UNCONST(try_princ); 1305 1.2 christos if (ret) 1306 1.2 christos goto out; 1307 1.1 elric 1308 1.2 christos if (name_canon_iter == NULL) { 1309 1.2 christos if (options & KRB5_GC_CACHED) 1310 1.2 christos ret = KRB5_CC_NOTFOUND; 1311 1.2 christos else 1312 1.2 christos ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1313 1.2 christos goto out; 1314 1.2 christos } 1315 1.1 elric 1316 1.2 christos ret = check_cc(context, options, ccache, in_creds, res_creds); 1317 1.2 christos if (ret == 0) { 1318 1.2 christos *out_creds = res_creds; 1319 1.2 christos res_creds = NULL; 1320 1.2 christos goto out; 1321 1.1 elric } else if(ret != KRB5_CC_END) { 1322 1.2 christos goto out; 1323 1.1 elric } 1324 1.2 christos if (options & KRB5_GC_CACHED) 1325 1.2 christos goto next_rule; 1326 1.1 elric 1327 1.1 elric if(options & KRB5_GC_USER_USER) 1328 1.1 elric flags.b.enc_tkt_in_skey = 1; 1329 1.1 elric if (flags.b.enc_tkt_in_skey) 1330 1.1 elric options |= KRB5_GC_NO_STORE; 1331 1.1 elric 1332 1.1 elric tgts = NULL; 1333 1.1 elric ret = _krb5_get_cred_kdc_any(context, flags, ccache, 1334 1.1 elric in_creds, NULL, NULL, out_creds, &tgts); 1335 1.2 christos for (i = 0; tgts && tgts[i]; i++) { 1336 1.2 christos if ((options & KRB5_GC_NO_STORE) == 0) 1337 1.2 christos krb5_cc_store_cred(context, ccache, tgts[i]); 1338 1.1 elric krb5_free_creds(context, tgts[i]); 1339 1.1 elric } 1340 1.1 elric free(tgts); 1341 1.2 christos 1342 1.2 christos /* We don't yet have TGS w/ FAST, so we can't protect KBR-ERRORs */ 1343 1.2 christos if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN && 1344 1.2 christos !(rule_opts & KRB5_NCRO_USE_FAST)) 1345 1.2 christos goto next_rule; 1346 1.2 christos 1347 1.1 elric if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) 1348 1.2 christos store_cred(context, ccache, in_creds->server, *out_creds); 1349 1.2 christos 1350 1.2 christos if (ret == 0 && _krb5_have_debug(context, 5)) { 1351 1.2 christos char *unparsed; 1352 1.2 christos 1353 1.2 christos ret = krb5_unparse_name(context, (*out_creds)->server, &unparsed); 1354 1.2 christos if (ret) { 1355 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: unable to display " 1356 1.2 christos "service principal"); 1357 1.2 christos } else { 1358 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: got a ticket for %s", 1359 1.2 christos unparsed); 1360 1.2 christos free(unparsed); 1361 1.2 christos } 1362 1.2 christos } 1363 1.2 christos 1364 1.2 christos out: 1365 1.2 christos in_creds->server = save_princ; 1366 1.2 christos krb5_free_creds(context, res_creds); 1367 1.2 christos krb5_free_name_canon_iterator(context, name_canon_iter); 1368 1.2 christos if (ret) 1369 1.2 christos return not_found(context, in_creds->server, ret); 1370 1.2 christos return 0; 1371 1.1 elric } 1372 1.1 elric 1373 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1374 1.1 elric krb5_get_credentials(krb5_context context, 1375 1.1 elric krb5_flags options, 1376 1.1 elric krb5_ccache ccache, 1377 1.1 elric krb5_creds *in_creds, 1378 1.1 elric krb5_creds **out_creds) 1379 1.1 elric { 1380 1.1 elric krb5_kdc_flags flags; 1381 1.1 elric flags.i = 0; 1382 1.1 elric return krb5_get_credentials_with_flags(context, options, flags, 1383 1.1 elric ccache, in_creds, out_creds); 1384 1.1 elric } 1385 1.1 elric 1386 1.1 elric struct krb5_get_creds_opt_data { 1387 1.1 elric krb5_principal self; 1388 1.1 elric krb5_flags options; 1389 1.1 elric krb5_enctype enctype; 1390 1.1 elric Ticket *ticket; 1391 1.1 elric }; 1392 1.1 elric 1393 1.1 elric 1394 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1395 1.1 elric krb5_get_creds_opt_alloc(krb5_context context, krb5_get_creds_opt *opt) 1396 1.1 elric { 1397 1.1 elric *opt = calloc(1, sizeof(**opt)); 1398 1.2 christos if (*opt == NULL) 1399 1.2 christos return krb5_enomem(context); 1400 1.1 elric return 0; 1401 1.1 elric } 1402 1.1 elric 1403 1.1 elric KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1404 1.1 elric krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) 1405 1.1 elric { 1406 1.1 elric if (opt->self) 1407 1.1 elric krb5_free_principal(context, opt->self); 1408 1.1 elric if (opt->ticket) { 1409 1.1 elric free_Ticket(opt->ticket); 1410 1.1 elric free(opt->ticket); 1411 1.1 elric } 1412 1.1 elric memset(opt, 0, sizeof(*opt)); 1413 1.1 elric free(opt); 1414 1.1 elric } 1415 1.1 elric 1416 1.1 elric KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1417 1.1 elric krb5_get_creds_opt_set_options(krb5_context context, 1418 1.1 elric krb5_get_creds_opt opt, 1419 1.1 elric krb5_flags options) 1420 1.1 elric { 1421 1.1 elric opt->options = options; 1422 1.1 elric } 1423 1.1 elric 1424 1.1 elric KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1425 1.1 elric krb5_get_creds_opt_add_options(krb5_context context, 1426 1.1 elric krb5_get_creds_opt opt, 1427 1.1 elric krb5_flags options) 1428 1.1 elric { 1429 1.1 elric opt->options |= options; 1430 1.1 elric } 1431 1.1 elric 1432 1.1 elric KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1433 1.1 elric krb5_get_creds_opt_set_enctype(krb5_context context, 1434 1.1 elric krb5_get_creds_opt opt, 1435 1.1 elric krb5_enctype enctype) 1436 1.1 elric { 1437 1.1 elric opt->enctype = enctype; 1438 1.1 elric } 1439 1.1 elric 1440 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1441 1.1 elric krb5_get_creds_opt_set_impersonate(krb5_context context, 1442 1.1 elric krb5_get_creds_opt opt, 1443 1.1 elric krb5_const_principal self) 1444 1.1 elric { 1445 1.1 elric if (opt->self) 1446 1.1 elric krb5_free_principal(context, opt->self); 1447 1.1 elric return krb5_copy_principal(context, self, &opt->self); 1448 1.1 elric } 1449 1.1 elric 1450 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1451 1.1 elric krb5_get_creds_opt_set_ticket(krb5_context context, 1452 1.1 elric krb5_get_creds_opt opt, 1453 1.1 elric const Ticket *ticket) 1454 1.1 elric { 1455 1.1 elric if (opt->ticket) { 1456 1.1 elric free_Ticket(opt->ticket); 1457 1.1 elric free(opt->ticket); 1458 1.1 elric opt->ticket = NULL; 1459 1.1 elric } 1460 1.1 elric if (ticket) { 1461 1.1 elric krb5_error_code ret; 1462 1.1 elric 1463 1.1 elric opt->ticket = malloc(sizeof(*ticket)); 1464 1.2 christos if (opt->ticket == NULL) 1465 1.2 christos return krb5_enomem(context); 1466 1.1 elric ret = copy_Ticket(ticket, opt->ticket); 1467 1.1 elric if (ret) { 1468 1.1 elric free(opt->ticket); 1469 1.1 elric opt->ticket = NULL; 1470 1.1 elric krb5_set_error_message(context, ret, 1471 1.1 elric N_("malloc: out of memory", "")); 1472 1.1 elric return ret; 1473 1.1 elric } 1474 1.1 elric } 1475 1.1 elric return 0; 1476 1.1 elric } 1477 1.1 elric 1478 1.1 elric 1479 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1480 1.1 elric krb5_get_creds(krb5_context context, 1481 1.1 elric krb5_get_creds_opt opt, 1482 1.1 elric krb5_ccache ccache, 1483 1.1 elric krb5_const_principal inprinc, 1484 1.1 elric krb5_creds **out_creds) 1485 1.1 elric { 1486 1.1 elric krb5_kdc_flags flags; 1487 1.1 elric krb5_flags options; 1488 1.1 elric krb5_creds in_creds; 1489 1.1 elric krb5_error_code ret; 1490 1.1 elric krb5_creds **tgts; 1491 1.1 elric krb5_creds *res_creds; 1492 1.2 christos krb5_const_principal try_princ = NULL; 1493 1.2 christos krb5_name_canon_iterator name_canon_iter = NULL; 1494 1.2 christos krb5_name_canon_rule_options rule_opts; 1495 1.1 elric int i; 1496 1.2 christos int type; 1497 1.2 christos const char *comp; 1498 1.2 christos 1499 1.2 christos memset(&in_creds, 0, sizeof(in_creds)); 1500 1.2 christos in_creds.server = rk_UNCONST(inprinc); 1501 1.2 christos 1502 1.2 christos if (_krb5_have_debug(context, 5)) { 1503 1.2 christos char *unparsed; 1504 1.2 christos 1505 1.2 christos ret = krb5_unparse_name(context, in_creds.server, &unparsed); 1506 1.2 christos if (ret) { 1507 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: unable to display " 1508 1.2 christos "requested service principal"); 1509 1.2 christos } else { 1510 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: requesting a ticket " 1511 1.2 christos "for %s", unparsed); 1512 1.2 christos free(unparsed); 1513 1.2 christos } 1514 1.2 christos } 1515 1.1 elric 1516 1.1 elric if (opt && opt->enctype) { 1517 1.1 elric ret = krb5_enctype_valid(context, opt->enctype); 1518 1.1 elric if (ret) 1519 1.1 elric return ret; 1520 1.1 elric } 1521 1.1 elric 1522 1.1 elric ret = krb5_cc_get_principal(context, ccache, &in_creds.client); 1523 1.1 elric if (ret) 1524 1.1 elric return ret; 1525 1.1 elric 1526 1.1 elric if (opt) 1527 1.1 elric options = opt->options; 1528 1.1 elric else 1529 1.1 elric options = 0; 1530 1.1 elric flags.i = 0; 1531 1.1 elric 1532 1.1 elric *out_creds = NULL; 1533 1.1 elric res_creds = calloc(1, sizeof(*res_creds)); 1534 1.1 elric if (res_creds == NULL) { 1535 1.1 elric krb5_free_principal(context, in_creds.client); 1536 1.2 christos return krb5_enomem(context); 1537 1.1 elric } 1538 1.1 elric 1539 1.1 elric if (opt && opt->enctype) { 1540 1.1 elric in_creds.session.keytype = opt->enctype; 1541 1.1 elric options |= KRB5_TC_MATCH_KEYTYPE; 1542 1.1 elric } 1543 1.1 elric 1544 1.2 christos ret = krb5_name_canon_iterator_start(context, in_creds.server, 1545 1.2 christos &name_canon_iter); 1546 1.2 christos if (ret) 1547 1.2 christos goto out; 1548 1.1 elric 1549 1.2 christos next_rule: 1550 1.2 christos ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ, 1551 1.2 christos &rule_opts); 1552 1.2 christos in_creds.server = rk_UNCONST(try_princ); 1553 1.2 christos if (ret) 1554 1.2 christos goto out; 1555 1.1 elric 1556 1.2 christos if (name_canon_iter == NULL) { 1557 1.2 christos if (options & KRB5_GC_CACHED) 1558 1.2 christos ret = KRB5_CC_NOTFOUND; 1559 1.2 christos else 1560 1.2 christos ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1561 1.1 elric goto out; 1562 1.1 elric } 1563 1.2 christos 1564 1.2 christos ret = check_cc(context, options, ccache, &in_creds, res_creds); 1565 1.2 christos if (ret == 0) { 1566 1.2 christos *out_creds = res_creds; 1567 1.2 christos res_creds = NULL; 1568 1.2 christos goto out; 1569 1.2 christos } else if (ret != KRB5_CC_END) { 1570 1.1 elric goto out; 1571 1.1 elric } 1572 1.2 christos if (options & KRB5_GC_CACHED) 1573 1.2 christos goto next_rule; 1574 1.2 christos 1575 1.2 christos type = krb5_principal_get_type(context, try_princ); 1576 1.2 christos comp = krb5_principal_get_comp_string(context, try_princ, 0); 1577 1.2 christos if ((type == KRB5_NT_SRV_HST || type == KRB5_NT_UNKNOWN) && 1578 1.2 christos comp != NULL && strcmp(comp, "host") == 0) 1579 1.2 christos flags.b.canonicalize = 1; 1580 1.2 christos if (rule_opts & KRB5_NCRO_NO_REFERRALS) 1581 1.2 christos flags.b.canonicalize = 0; 1582 1.2 christos else 1583 1.2 christos flags.b.canonicalize = (options & KRB5_GC_CANONICALIZE) ? 1 : 0; 1584 1.2 christos if (options & KRB5_GC_USER_USER) { 1585 1.1 elric flags.b.enc_tkt_in_skey = 1; 1586 1.1 elric options |= KRB5_GC_NO_STORE; 1587 1.1 elric } 1588 1.1 elric if (options & KRB5_GC_FORWARDABLE) 1589 1.1 elric flags.b.forwardable = 1; 1590 1.1 elric if (options & KRB5_GC_NO_TRANSIT_CHECK) 1591 1.1 elric flags.b.disable_transited_check = 1; 1592 1.3 christos if (options & KRB5_GC_CONSTRAINED_DELEGATION) 1593 1.3 christos flags.b.cname_in_addl_tkt = 1; 1594 1.3 christos if (options & KRB5_GC_ANONYMOUS) 1595 1.3 christos flags.b.request_anonymous = 1; 1596 1.1 elric 1597 1.1 elric tgts = NULL; 1598 1.1 elric ret = _krb5_get_cred_kdc_any(context, flags, ccache, 1599 1.2 christos &in_creds, opt ? opt->self : 0, 1600 1.2 christos opt ? opt->ticket : 0, out_creds, 1601 1.2 christos &tgts); 1602 1.2 christos for (i = 0; tgts && tgts[i]; i++) { 1603 1.2 christos if ((options & KRB5_GC_NO_STORE) == 0) 1604 1.2 christos krb5_cc_store_cred(context, ccache, tgts[i]); 1605 1.1 elric krb5_free_creds(context, tgts[i]); 1606 1.1 elric } 1607 1.1 elric free(tgts); 1608 1.1 elric 1609 1.2 christos /* We don't yet have TGS w/ FAST, so we can't protect KBR-ERRORs */ 1610 1.2 christos if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN && 1611 1.2 christos !(rule_opts & KRB5_NCRO_USE_FAST)) 1612 1.2 christos goto next_rule; 1613 1.2 christos 1614 1.2 christos if (ret == 0 && (options & KRB5_GC_NO_STORE) == 0) 1615 1.2 christos store_cred(context, ccache, inprinc, *out_creds); 1616 1.2 christos 1617 1.2 christos if (ret == 0 && _krb5_have_debug(context, 5)) { 1618 1.2 christos char *unparsed; 1619 1.2 christos 1620 1.2 christos ret = krb5_unparse_name(context, (*out_creds)->server, &unparsed); 1621 1.2 christos if (ret) { 1622 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: unable to display " 1623 1.2 christos "service principal"); 1624 1.2 christos } else { 1625 1.2 christos _krb5_debug(context, 5, "krb5_get_creds: got a ticket for %s", 1626 1.2 christos unparsed); 1627 1.2 christos free(unparsed); 1628 1.2 christos } 1629 1.2 christos } 1630 1.1 elric 1631 1.2 christos out: 1632 1.2 christos krb5_free_creds(context, res_creds); 1633 1.2 christos krb5_free_principal(context, in_creds.client); 1634 1.2 christos krb5_free_name_canon_iterator(context, name_canon_iter); 1635 1.2 christos if (ret) 1636 1.2 christos return not_found(context, inprinc, ret); 1637 1.1 elric return ret; 1638 1.1 elric } 1639 1.1 elric 1640 1.1 elric /* 1641 1.1 elric * 1642 1.1 elric */ 1643 1.1 elric 1644 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1645 1.1 elric krb5_get_renewed_creds(krb5_context context, 1646 1.1 elric krb5_creds *creds, 1647 1.1 elric krb5_const_principal client, 1648 1.1 elric krb5_ccache ccache, 1649 1.1 elric const char *in_tkt_service) 1650 1.1 elric { 1651 1.1 elric krb5_error_code ret; 1652 1.1 elric krb5_kdc_flags flags; 1653 1.1 elric krb5_creds in, *template, *out = NULL; 1654 1.1 elric 1655 1.1 elric memset(&in, 0, sizeof(in)); 1656 1.1 elric memset(creds, 0, sizeof(*creds)); 1657 1.1 elric 1658 1.1 elric ret = krb5_copy_principal(context, client, &in.client); 1659 1.1 elric if (ret) 1660 1.1 elric return ret; 1661 1.1 elric 1662 1.1 elric if (in_tkt_service) { 1663 1.1 elric ret = krb5_parse_name(context, in_tkt_service, &in.server); 1664 1.1 elric if (ret) { 1665 1.1 elric krb5_free_principal(context, in.client); 1666 1.1 elric return ret; 1667 1.1 elric } 1668 1.1 elric } else { 1669 1.1 elric const char *realm = krb5_principal_get_realm(context, client); 1670 1.2 christos 1671 1.1 elric ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, 1672 1.1 elric realm, NULL); 1673 1.1 elric if (ret) { 1674 1.1 elric krb5_free_principal(context, in.client); 1675 1.1 elric return ret; 1676 1.1 elric } 1677 1.1 elric } 1678 1.1 elric 1679 1.1 elric flags.i = 0; 1680 1.1 elric flags.b.renewable = flags.b.renew = 1; 1681 1.1 elric 1682 1.1 elric /* 1683 1.1 elric * Get template from old credential cache for the same entry, if 1684 1.1 elric * this failes, no worries. 1685 1.1 elric */ 1686 1.1 elric ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template); 1687 1.1 elric if (ret == 0) { 1688 1.1 elric flags.b.forwardable = template->flags.b.forwardable; 1689 1.1 elric flags.b.proxiable = template->flags.b.proxiable; 1690 1.1 elric krb5_free_creds (context, template); 1691 1.1 elric } 1692 1.1 elric 1693 1.1 elric ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &out); 1694 1.1 elric krb5_free_principal(context, in.client); 1695 1.1 elric krb5_free_principal(context, in.server); 1696 1.1 elric if (ret) 1697 1.1 elric return ret; 1698 1.1 elric 1699 1.1 elric ret = krb5_copy_creds_contents(context, out, creds); 1700 1.1 elric krb5_free_creds(context, out); 1701 1.1 elric 1702 1.1 elric return ret; 1703 1.1 elric } 1704