get_in_tkt.c revision 1.1.1.1.22.1
1/* $NetBSD: get_in_tkt.c,v 1.1.1.1.22.1 2014/08/10 06:47:30 tls Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#define KRB5_DEPRECATED_FUNCTION(x) 37 38#include "krb5_locl.h" 39 40#ifndef HEIMDAL_SMALLER 41 42static krb5_error_code 43make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, 44 krb5_enctype etype, krb5_keyblock *key) 45{ 46 PA_ENC_TS_ENC p; 47 unsigned char *buf; 48 size_t buf_size; 49 size_t len = 0; 50 EncryptedData encdata; 51 krb5_error_code ret; 52 int32_t usec; 53 int usec2; 54 krb5_crypto crypto; 55 56 krb5_us_timeofday (context, &p.patimestamp, &usec); 57 usec2 = usec; 58 p.pausec = &usec2; 59 60 ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); 61 if (ret) 62 return ret; 63 if(buf_size != len) 64 krb5_abortx(context, "internal error in ASN.1 encoder"); 65 ret = krb5_crypto_init(context, key, 0, &crypto); 66 if (ret) { 67 free(buf); 68 return ret; 69 } 70 ret = krb5_encrypt_EncryptedData(context, 71 crypto, 72 KRB5_KU_PA_ENC_TIMESTAMP, 73 buf, 74 len, 75 0, 76 &encdata); 77 free(buf); 78 krb5_crypto_destroy(context, crypto); 79 if (ret) 80 return ret; 81 82 ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); 83 free_EncryptedData(&encdata); 84 if (ret) 85 return ret; 86 if(buf_size != len) 87 krb5_abortx(context, "internal error in ASN.1 encoder"); 88 pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP; 89 pa->padata_value.length = len; 90 pa->padata_value.data = buf; 91 return 0; 92} 93 94static krb5_error_code 95add_padata(krb5_context context, 96 METHOD_DATA *md, 97 krb5_principal client, 98 krb5_key_proc key_proc, 99 krb5_const_pointer keyseed, 100 krb5_enctype *enctypes, 101 unsigned netypes, 102 krb5_salt *salt) 103{ 104 krb5_error_code ret; 105 PA_DATA *pa2; 106 krb5_salt salt2; 107 krb5_enctype *ep; 108 size_t i; 109 110 if(salt == NULL) { 111 /* default to standard salt */ 112 ret = krb5_get_pw_salt (context, client, &salt2); 113 if (ret) 114 return ret; 115 salt = &salt2; 116 } 117 if (!enctypes) { 118 enctypes = context->etypes; 119 netypes = 0; 120 for (ep = enctypes; *ep != ETYPE_NULL; ep++) 121 netypes++; 122 } 123 pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val)); 124 if (pa2 == NULL) { 125 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 126 return ENOMEM; 127 } 128 md->val = pa2; 129 130 for (i = 0; i < netypes; ++i) { 131 krb5_keyblock *key; 132 133 ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key); 134 if (ret) 135 continue; 136 ret = make_pa_enc_timestamp (context, &md->val[md->len], 137 enctypes[i], key); 138 krb5_free_keyblock (context, key); 139 if (ret) 140 return ret; 141 ++md->len; 142 } 143 if(salt == &salt2) 144 krb5_free_salt(context, salt2); 145 return 0; 146} 147 148static krb5_error_code 149init_as_req (krb5_context context, 150 KDCOptions opts, 151 krb5_creds *creds, 152 const krb5_addresses *addrs, 153 const krb5_enctype *etypes, 154 const krb5_preauthtype *ptypes, 155 const krb5_preauthdata *preauth, 156 krb5_key_proc key_proc, 157 krb5_const_pointer keyseed, 158 unsigned nonce, 159 AS_REQ *a) 160{ 161 krb5_error_code ret; 162 krb5_salt salt; 163 164 memset(a, 0, sizeof(*a)); 165 166 a->pvno = 5; 167 a->msg_type = krb_as_req; 168 a->req_body.kdc_options = opts; 169 a->req_body.cname = malloc(sizeof(*a->req_body.cname)); 170 if (a->req_body.cname == NULL) { 171 ret = ENOMEM; 172 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 173 goto fail; 174 } 175 a->req_body.sname = malloc(sizeof(*a->req_body.sname)); 176 if (a->req_body.sname == NULL) { 177 ret = ENOMEM; 178 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 179 goto fail; 180 } 181 ret = _krb5_principal2principalname (a->req_body.cname, creds->client); 182 if (ret) 183 goto fail; 184 ret = _krb5_principal2principalname (a->req_body.sname, creds->server); 185 if (ret) 186 goto fail; 187 ret = copy_Realm(&creds->client->realm, &a->req_body.realm); 188 if (ret) 189 goto fail; 190 191 if(creds->times.starttime) { 192 a->req_body.from = malloc(sizeof(*a->req_body.from)); 193 if (a->req_body.from == NULL) { 194 ret = ENOMEM; 195 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 196 goto fail; 197 } 198 *a->req_body.from = creds->times.starttime; 199 } 200 if(creds->times.endtime){ 201 ALLOC(a->req_body.till, 1); 202 *a->req_body.till = creds->times.endtime; 203 } 204 if(creds->times.renew_till){ 205 a->req_body.rtime = malloc(sizeof(*a->req_body.rtime)); 206 if (a->req_body.rtime == NULL) { 207 ret = ENOMEM; 208 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 209 goto fail; 210 } 211 *a->req_body.rtime = creds->times.renew_till; 212 } 213 a->req_body.nonce = nonce; 214 ret = _krb5_init_etype(context, 215 KRB5_PDU_AS_REQUEST, 216 &a->req_body.etype.len, 217 &a->req_body.etype.val, 218 etypes); 219 if (ret) 220 goto fail; 221 222 /* 223 * This means no addresses 224 */ 225 226 if (addrs && addrs->len == 0) { 227 a->req_body.addresses = NULL; 228 } else { 229 a->req_body.addresses = malloc(sizeof(*a->req_body.addresses)); 230 if (a->req_body.addresses == NULL) { 231 ret = ENOMEM; 232 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 233 goto fail; 234 } 235 236 if (addrs) 237 ret = krb5_copy_addresses(context, addrs, a->req_body.addresses); 238 else { 239 ret = krb5_get_all_client_addrs (context, a->req_body.addresses); 240 if(ret == 0 && a->req_body.addresses->len == 0) { 241 free(a->req_body.addresses); 242 a->req_body.addresses = NULL; 243 } 244 } 245 if (ret) 246 return ret; 247 } 248 249 a->req_body.enc_authorization_data = NULL; 250 a->req_body.additional_tickets = NULL; 251 252 if(preauth != NULL) { 253 size_t i; 254 ALLOC(a->padata, 1); 255 if(a->padata == NULL) { 256 ret = ENOMEM; 257 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 258 goto fail; 259 } 260 a->padata->val = NULL; 261 a->padata->len = 0; 262 for(i = 0; i < preauth->len; i++) { 263 if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){ 264 size_t j; 265 266 for(j = 0; j < preauth->val[i].info.len; j++) { 267 krb5_salt *sp = &salt; 268 if(preauth->val[i].info.val[j].salttype) 269 salt.salttype = *preauth->val[i].info.val[j].salttype; 270 else 271 salt.salttype = KRB5_PW_SALT; 272 if(preauth->val[i].info.val[j].salt) 273 salt.saltvalue = *preauth->val[i].info.val[j].salt; 274 else 275 if(salt.salttype == KRB5_PW_SALT) 276 sp = NULL; 277 else 278 krb5_data_zero(&salt.saltvalue); 279 ret = add_padata(context, a->padata, creds->client, 280 key_proc, keyseed, 281 &preauth->val[i].info.val[j].etype, 1, 282 sp); 283 if (ret == 0) 284 break; 285 } 286 } 287 } 288 } else 289 /* not sure this is the way to use `ptypes' */ 290 if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE) 291 a->padata = NULL; 292 else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) { 293 ALLOC(a->padata, 1); 294 if (a->padata == NULL) { 295 ret = ENOMEM; 296 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 297 goto fail; 298 } 299 a->padata->len = 0; 300 a->padata->val = NULL; 301 302 /* make a v5 salted pa-data */ 303 add_padata(context, a->padata, creds->client, 304 key_proc, keyseed, a->req_body.etype.val, 305 a->req_body.etype.len, NULL); 306 307 /* make a v4 salted pa-data */ 308 salt.salttype = KRB5_PW_SALT; 309 krb5_data_zero(&salt.saltvalue); 310 add_padata(context, a->padata, creds->client, 311 key_proc, keyseed, a->req_body.etype.val, 312 a->req_body.etype.len, &salt); 313 } else { 314 ret = KRB5_PREAUTH_BAD_TYPE; 315 krb5_set_error_message (context, ret, 316 N_("pre-auth type %d not supported", ""), 317 *ptypes); 318 goto fail; 319 } 320 return 0; 321fail: 322 free_AS_REQ(a); 323 return ret; 324} 325 326static int 327set_ptypes(krb5_context context, 328 KRB_ERROR *error, 329 const krb5_preauthtype **ptypes, 330 krb5_preauthdata **preauth) 331{ 332 static krb5_preauthdata preauth2; 333 static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE }; 334 335 if(error->e_data) { 336 METHOD_DATA md; 337 size_t i; 338 decode_METHOD_DATA(error->e_data->data, 339 error->e_data->length, 340 &md, 341 NULL); 342 for(i = 0; i < md.len; i++){ 343 switch(md.val[i].padata_type){ 344 case KRB5_PADATA_ENC_TIMESTAMP: 345 *ptypes = ptypes2; 346 break; 347 case KRB5_PADATA_ETYPE_INFO: 348 *preauth = &preauth2; 349 ALLOC_SEQ(*preauth, 1); 350 (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP; 351 decode_ETYPE_INFO(md.val[i].padata_value.data, 352 md.val[i].padata_value.length, 353 &(*preauth)->val[0].info, 354 NULL); 355 break; 356 default: 357 break; 358 } 359 } 360 free_METHOD_DATA(&md); 361 } else { 362 *ptypes = ptypes2; 363 } 364 return(1); 365} 366 367KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 368krb5_get_in_cred(krb5_context context, 369 krb5_flags options, 370 const krb5_addresses *addrs, 371 const krb5_enctype *etypes, 372 const krb5_preauthtype *ptypes, 373 const krb5_preauthdata *preauth, 374 krb5_key_proc key_proc, 375 krb5_const_pointer keyseed, 376 krb5_decrypt_proc decrypt_proc, 377 krb5_const_pointer decryptarg, 378 krb5_creds *creds, 379 krb5_kdc_rep *ret_as_reply) 380 KRB5_DEPRECATED_FUNCTION("Use X instead") 381{ 382 krb5_error_code ret; 383 AS_REQ a; 384 krb5_kdc_rep rep; 385 krb5_data req, resp; 386 size_t len = 0; 387 krb5_salt salt; 388 krb5_keyblock *key; 389 size_t size; 390 KDCOptions opts; 391 PA_DATA *pa; 392 krb5_enctype etype; 393 krb5_preauthdata *my_preauth = NULL; 394 unsigned nonce; 395 int done; 396 397 opts = int2KDCOptions(options); 398 399 krb5_generate_random_block (&nonce, sizeof(nonce)); 400 nonce &= 0xffffffff; 401 402 do { 403 done = 1; 404 ret = init_as_req (context, 405 opts, 406 creds, 407 addrs, 408 etypes, 409 ptypes, 410 preauth, 411 key_proc, 412 keyseed, 413 nonce, 414 &a); 415 if (my_preauth) { 416 free_ETYPE_INFO(&my_preauth->val[0].info); 417 free (my_preauth->val); 418 my_preauth = NULL; 419 } 420 if (ret) 421 return ret; 422 423 ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret); 424 free_AS_REQ(&a); 425 if (ret) 426 return ret; 427 if(len != req.length) 428 krb5_abortx(context, "internal error in ASN.1 encoder"); 429 430 ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp); 431 krb5_data_free(&req); 432 if (ret) 433 return ret; 434 435 memset (&rep, 0, sizeof(rep)); 436 ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size); 437 if(ret) { 438 /* let's try to parse it as a KRB-ERROR */ 439 KRB_ERROR error; 440 int ret2; 441 442 ret2 = krb5_rd_error(context, &resp, &error); 443 if(ret2 && resp.data && ((char*)resp.data)[0] == 4) 444 ret = KRB5KRB_AP_ERR_V4_REPLY; 445 krb5_data_free(&resp); 446 if (ret2 == 0) { 447 ret = krb5_error_from_rd_error(context, &error, creds); 448 /* if no preauth was set and KDC requires it, give it 449 one more try */ 450 if (!ptypes && !preauth 451 && ret == KRB5KDC_ERR_PREAUTH_REQUIRED 452#if 0 453 || ret == KRB5KDC_ERR_BADOPTION 454#endif 455 && set_ptypes(context, &error, &ptypes, &my_preauth)) { 456 done = 0; 457 preauth = my_preauth; 458 krb5_free_error_contents(context, &error); 459 krb5_clear_error_message(context); 460 continue; 461 } 462 if(ret_as_reply) 463 ret_as_reply->error = error; 464 else 465 free_KRB_ERROR (&error); 466 return ret; 467 } 468 return ret; 469 } 470 krb5_data_free(&resp); 471 } while(!done); 472 473 pa = NULL; 474 etype = rep.kdc_rep.enc_part.etype; 475 if(rep.kdc_rep.padata){ 476 int i = 0; 477 pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len, 478 KRB5_PADATA_PW_SALT, &i); 479 if(pa == NULL) { 480 i = 0; 481 pa = krb5_find_padata(rep.kdc_rep.padata->val, 482 rep.kdc_rep.padata->len, 483 KRB5_PADATA_AFS3_SALT, &i); 484 } 485 } 486 if(pa) { 487 salt.salttype = (krb5_salttype)pa->padata_type; 488 salt.saltvalue = pa->padata_value; 489 490 ret = (*key_proc)(context, etype, salt, keyseed, &key); 491 } else { 492 /* make a v5 salted pa-data */ 493 ret = krb5_get_pw_salt (context, creds->client, &salt); 494 495 if (ret) 496 goto out; 497 ret = (*key_proc)(context, etype, salt, keyseed, &key); 498 krb5_free_salt(context, salt); 499 } 500 if (ret) 501 goto out; 502 503 { 504 unsigned flags = EXTRACT_TICKET_TIMESYNC; 505 if (opts.request_anonymous) 506 flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; 507 508 ret = _krb5_extract_ticket(context, 509 &rep, 510 creds, 511 key, 512 keyseed, 513 KRB5_KU_AS_REP_ENC_PART, 514 NULL, 515 nonce, 516 flags, 517 decrypt_proc, 518 decryptarg); 519 } 520 memset (key->keyvalue.data, 0, key->keyvalue.length); 521 krb5_free_keyblock_contents (context, key); 522 free (key); 523 524out: 525 if (ret == 0 && ret_as_reply) 526 *ret_as_reply = rep; 527 else 528 krb5_free_kdc_rep (context, &rep); 529 return ret; 530} 531 532KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 533krb5_get_in_tkt(krb5_context context, 534 krb5_flags options, 535 const krb5_addresses *addrs, 536 const krb5_enctype *etypes, 537 const krb5_preauthtype *ptypes, 538 krb5_key_proc key_proc, 539 krb5_const_pointer keyseed, 540 krb5_decrypt_proc decrypt_proc, 541 krb5_const_pointer decryptarg, 542 krb5_creds *creds, 543 krb5_ccache ccache, 544 krb5_kdc_rep *ret_as_reply) 545 KRB5_DEPRECATED_FUNCTION("Use X instead") 546{ 547 krb5_error_code ret; 548 549 ret = krb5_get_in_cred (context, 550 options, 551 addrs, 552 etypes, 553 ptypes, 554 NULL, 555 key_proc, 556 keyseed, 557 decrypt_proc, 558 decryptarg, 559 creds, 560 ret_as_reply); 561 if(ret) 562 return ret; 563 if (ccache) 564 ret = krb5_cc_store_cred (context, ccache, creds); 565 return ret; 566} 567 568#endif /* HEIMDAL_SMALLER */ 569