1 /*- 2 * Copyright (c) 2005 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libgssapi/gss_krb5.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ 27 */ 28 29 #include "mech_locl.h" 30 31 #include <krb5.h> 32 #include <roken.h> 33 34 35 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 36 gss_krb5_copy_ccache(OM_uint32 *minor_status, 37 gss_cred_id_t cred, 38 krb5_ccache out) 39 { 40 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 41 krb5_context context; 42 krb5_error_code kret; 43 krb5_ccache id; 44 OM_uint32 ret; 45 char *str = NULL; 46 47 ret = gss_inquire_cred_by_oid(minor_status, 48 cred, 49 GSS_KRB5_COPY_CCACHE_X, 50 &data_set); 51 if (ret) 52 return ret; 53 54 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count < 1) { 55 gss_release_buffer_set(minor_status, &data_set); 56 *minor_status = EINVAL; 57 return GSS_S_FAILURE; 58 } 59 60 kret = krb5_init_context(&context); 61 if (kret) { 62 *minor_status = kret; 63 gss_release_buffer_set(minor_status, &data_set); 64 return GSS_S_FAILURE; 65 } 66 67 kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length, 68 (char *)data_set->elements[0].value); 69 gss_release_buffer_set(minor_status, &data_set); 70 if (kret < 0 || str == NULL) { 71 *minor_status = ENOMEM; 72 return GSS_S_FAILURE; 73 } 74 75 kret = krb5_cc_resolve(context, str, &id); 76 free(str); 77 if (kret) { 78 *minor_status = kret; 79 return GSS_S_FAILURE; 80 } 81 82 kret = krb5_cc_copy_cache(context, id, out); 83 krb5_cc_close(context, id); 84 krb5_free_context(context); 85 if (kret) { 86 *minor_status = kret; 87 return GSS_S_FAILURE; 88 } 89 90 return ret; 91 } 92 93 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 94 gss_krb5_import_cred(OM_uint32 *minor_status, 95 krb5_ccache id, 96 krb5_principal keytab_principal, 97 krb5_keytab keytab, 98 gss_cred_id_t *cred) 99 { 100 gss_buffer_desc buffer; 101 OM_uint32 major_status; 102 krb5_context context; 103 krb5_error_code ret; 104 krb5_storage *sp; 105 krb5_data data; 106 char *str; 107 108 *cred = GSS_C_NO_CREDENTIAL; 109 110 ret = krb5_init_context(&context); 111 if (ret) { 112 *minor_status = ret; 113 return GSS_S_FAILURE; 114 } 115 116 sp = krb5_storage_emem(); 117 if (sp == NULL) { 118 *minor_status = ENOMEM; 119 major_status = GSS_S_FAILURE; 120 goto out; 121 } 122 123 if (id) { 124 ret = krb5_cc_get_full_name(context, id, &str); 125 if (ret == 0) { 126 ret = krb5_store_string(sp, str); 127 free(str); 128 } 129 } else 130 ret = krb5_store_string(sp, ""); 131 if (ret) { 132 *minor_status = ret; 133 major_status = GSS_S_FAILURE; 134 goto out; 135 } 136 137 if (keytab_principal) { 138 ret = krb5_unparse_name(context, keytab_principal, &str); 139 if (ret == 0) { 140 ret = krb5_store_string(sp, str); 141 free(str); 142 } 143 } else 144 krb5_store_string(sp, ""); 145 if (ret) { 146 *minor_status = ret; 147 major_status = GSS_S_FAILURE; 148 goto out; 149 } 150 151 152 if (keytab) { 153 ret = krb5_kt_get_full_name(context, keytab, &str); 154 if (ret == 0) { 155 ret = krb5_store_string(sp, str); 156 free(str); 157 } 158 } else 159 krb5_store_string(sp, ""); 160 if (ret) { 161 *minor_status = ret; 162 major_status = GSS_S_FAILURE; 163 goto out; 164 } 165 166 ret = krb5_storage_to_data(sp, &data); 167 if (ret) { 168 *minor_status = ret; 169 major_status = GSS_S_FAILURE; 170 goto out; 171 } 172 173 buffer.value = data.data; 174 buffer.length = data.length; 175 176 major_status = gss_set_cred_option(minor_status, 177 cred, 178 GSS_KRB5_IMPORT_CRED_X, 179 &buffer); 180 krb5_data_free(&data); 181 out: 182 if (sp) 183 krb5_storage_free(sp); 184 krb5_free_context(context); 185 return major_status; 186 } 187 188 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 189 gsskrb5_register_acceptor_identity(const char *identity) 190 { 191 gssapi_mech_interface m; 192 gss_buffer_desc buffer; 193 OM_uint32 junk; 194 195 _gss_load_mech(); 196 197 buffer.value = rk_UNCONST(identity); 198 buffer.length = strlen(identity); 199 200 m = __gss_get_mechanism(GSS_KRB5_MECHANISM); 201 if (m == NULL || m->gm_set_sec_context_option == NULL) 202 return GSS_S_FAILURE; 203 204 return m->gm_set_sec_context_option(&junk, NULL, 205 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer); 206 } 207 208 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 209 krb5_gss_register_acceptor_identity(const char *identity) 210 { 211 return gsskrb5_register_acceptor_identity(identity); 212 } 213 214 215 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 216 gsskrb5_set_dns_canonicalize(int flag) 217 { 218 struct _gss_mech_switch *m; 219 gss_buffer_desc buffer; 220 OM_uint32 junk; 221 char b = (flag != 0); 222 223 _gss_load_mech(); 224 225 buffer.value = &b; 226 buffer.length = sizeof(b); 227 228 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 229 if (m->gm_mech.gm_set_sec_context_option == NULL) 230 continue; 231 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 232 GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer); 233 } 234 235 return (GSS_S_COMPLETE); 236 } 237 238 239 240 static krb5_error_code 241 set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key) 242 { 243 key->type = keyblock->keytype; 244 key->length = keyblock->keyvalue.length; 245 key->data = malloc(key->length); 246 if (key->data == NULL && key->length != 0) 247 return ENOMEM; 248 memcpy(key->data, keyblock->keyvalue.data, key->length); 249 return 0; 250 } 251 252 static void 253 free_key(gss_krb5_lucid_key_t *key) 254 { 255 memset(key->data, 0, key->length); 256 free(key->data); 257 memset(key, 0, sizeof(*key)); 258 } 259 260 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 261 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, 262 gss_ctx_id_t *context_handle, 263 OM_uint32 version, 264 void **rctx) 265 { 266 krb5_context context = NULL; 267 krb5_error_code ret; 268 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 269 OM_uint32 major_status; 270 gss_krb5_lucid_context_v1_t *ctx = NULL; 271 krb5_storage *sp = NULL; 272 uint32_t num; 273 274 if (context_handle == NULL 275 || *context_handle == GSS_C_NO_CONTEXT 276 || version != 1) 277 { 278 *minor_status = EINVAL; 279 return GSS_S_FAILURE; 280 } 281 282 major_status = 283 gss_inquire_sec_context_by_oid (minor_status, 284 *context_handle, 285 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, 286 &data_set); 287 if (major_status) 288 return major_status; 289 290 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 291 gss_release_buffer_set(minor_status, &data_set); 292 *minor_status = EINVAL; 293 return GSS_S_FAILURE; 294 } 295 296 ret = krb5_init_context(&context); 297 if (ret) 298 goto out; 299 300 ctx = calloc(1, sizeof(*ctx)); 301 if (ctx == NULL) { 302 ret = ENOMEM; 303 goto out; 304 } 305 306 sp = krb5_storage_from_mem(data_set->elements[0].value, 307 data_set->elements[0].length); 308 if (sp == NULL) { 309 ret = ENOMEM; 310 goto out; 311 } 312 313 ret = krb5_ret_uint32(sp, &num); 314 if (ret) goto out; 315 if (num != 1) { 316 ret = EINVAL; 317 goto out; 318 } 319 ctx->version = 1; 320 /* initiator */ 321 ret = krb5_ret_uint32(sp, &ctx->initiate); 322 if (ret) goto out; 323 /* endtime */ 324 ret = krb5_ret_uint32(sp, &ctx->endtime); 325 if (ret) goto out; 326 /* send_seq */ 327 ret = krb5_ret_uint32(sp, &num); 328 if (ret) goto out; 329 ctx->send_seq = ((uint64_t)num) << 32; 330 ret = krb5_ret_uint32(sp, &num); 331 if (ret) goto out; 332 ctx->send_seq |= num; 333 /* recv_seq */ 334 ret = krb5_ret_uint32(sp, &num); 335 if (ret) goto out; 336 ctx->recv_seq = ((uint64_t)num) << 32; 337 ret = krb5_ret_uint32(sp, &num); 338 if (ret) goto out; 339 ctx->recv_seq |= num; 340 /* protocol */ 341 ret = krb5_ret_uint32(sp, &ctx->protocol); 342 if (ret) goto out; 343 if (ctx->protocol == 0) { 344 krb5_keyblock key; 345 346 /* sign_alg */ 347 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); 348 if (ret) goto out; 349 /* seal_alg */ 350 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); 351 if (ret) goto out; 352 /* ctx_key */ 353 ret = krb5_ret_keyblock(sp, &key); 354 if (ret) goto out; 355 ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); 356 krb5_free_keyblock_contents(context, &key); 357 if (ret) goto out; 358 } else if (ctx->protocol == 1) { 359 krb5_keyblock key; 360 361 /* acceptor_subkey */ 362 ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); 363 if (ret) goto out; 364 /* ctx_key */ 365 ret = krb5_ret_keyblock(sp, &key); 366 if (ret) goto out; 367 ret = set_key(&key, &ctx->cfx_kd.ctx_key); 368 krb5_free_keyblock_contents(context, &key); 369 if (ret) goto out; 370 /* acceptor_subkey */ 371 if (ctx->cfx_kd.have_acceptor_subkey) { 372 ret = krb5_ret_keyblock(sp, &key); 373 if (ret) goto out; 374 ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); 375 krb5_free_keyblock_contents(context, &key); 376 if (ret) goto out; 377 } 378 } else { 379 ret = EINVAL; 380 goto out; 381 } 382 383 *rctx = ctx; 384 385 out: 386 gss_release_buffer_set(minor_status, &data_set); 387 if (sp) 388 krb5_storage_free(sp); 389 if (context) 390 krb5_free_context(context); 391 392 if (ret) { 393 if (ctx) 394 gss_krb5_free_lucid_sec_context(NULL, ctx); 395 396 *minor_status = ret; 397 return GSS_S_FAILURE; 398 } 399 *minor_status = 0; 400 return GSS_S_COMPLETE; 401 } 402 403 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 404 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c) 405 { 406 gss_krb5_lucid_context_v1_t *ctx = c; 407 408 if (ctx->version != 1) { 409 if (minor_status) 410 *minor_status = 0; 411 return GSS_S_FAILURE; 412 } 413 414 if (ctx->protocol == 0) { 415 free_key(&ctx->rfc1964_kd.ctx_key); 416 } else if (ctx->protocol == 1) { 417 free_key(&ctx->cfx_kd.ctx_key); 418 if (ctx->cfx_kd.have_acceptor_subkey) 419 free_key(&ctx->cfx_kd.acceptor_subkey); 420 } 421 free(ctx); 422 if (minor_status) 423 *minor_status = 0; 424 return GSS_S_COMPLETE; 425 } 426 427 /* 428 * 429 */ 430 431 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 432 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 433 gss_cred_id_t cred, 434 OM_uint32 num_enctypes, 435 int32_t *enctypes) 436 { 437 krb5_error_code ret; 438 OM_uint32 maj_status; 439 gss_buffer_desc buffer; 440 krb5_storage *sp; 441 krb5_data data; 442 size_t i; 443 444 sp = krb5_storage_emem(); 445 if (sp == NULL) { 446 *minor_status = ENOMEM; 447 maj_status = GSS_S_FAILURE; 448 goto out; 449 } 450 451 for (i = 0; i < num_enctypes; i++) { 452 ret = krb5_store_int32(sp, enctypes[i]); 453 if (ret) { 454 *minor_status = ret; 455 maj_status = GSS_S_FAILURE; 456 goto out; 457 } 458 } 459 460 ret = krb5_storage_to_data(sp, &data); 461 if (ret) { 462 *minor_status = ret; 463 maj_status = GSS_S_FAILURE; 464 goto out; 465 } 466 467 buffer.value = data.data; 468 buffer.length = data.length; 469 470 maj_status = gss_set_cred_option(minor_status, 471 &cred, 472 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, 473 &buffer); 474 krb5_data_free(&data); 475 out: 476 if (sp) 477 krb5_storage_free(sp); 478 return maj_status; 479 } 480 481 /* 482 * 483 */ 484 485 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 486 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c) 487 { 488 struct _gss_mech_switch *m; 489 gss_buffer_desc buffer; 490 OM_uint32 junk; 491 492 _gss_load_mech(); 493 494 if (c) { 495 buffer.value = c; 496 buffer.length = sizeof(*c); 497 } else { 498 buffer.value = NULL; 499 buffer.length = 0; 500 } 501 502 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 503 if (m->gm_mech.gm_set_sec_context_option == NULL) 504 continue; 505 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 506 GSS_KRB5_SEND_TO_KDC_X, &buffer); 507 } 508 509 return (GSS_S_COMPLETE); 510 } 511 512 /* 513 * 514 */ 515 516 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 517 gss_krb5_ccache_name(OM_uint32 *minor_status, 518 const char *name, 519 const char **out_name) 520 { 521 struct _gss_mech_switch *m; 522 gss_buffer_desc buffer; 523 OM_uint32 junk; 524 525 _gss_load_mech(); 526 527 if (out_name) 528 *out_name = NULL; 529 530 buffer.value = rk_UNCONST(name); 531 buffer.length = strlen(name); 532 533 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 534 if (m->gm_mech.gm_set_sec_context_option == NULL) 535 continue; 536 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 537 GSS_KRB5_CCACHE_NAME_X, &buffer); 538 } 539 540 return (GSS_S_COMPLETE); 541 } 542 543 544 /* 545 * 546 */ 547 548 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 549 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, 550 gss_ctx_id_t context_handle, 551 time_t *authtime) 552 { 553 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 554 OM_uint32 maj_stat; 555 556 if (context_handle == GSS_C_NO_CONTEXT) { 557 *minor_status = EINVAL; 558 return GSS_S_FAILURE; 559 } 560 561 maj_stat = 562 gss_inquire_sec_context_by_oid (minor_status, 563 context_handle, 564 GSS_KRB5_GET_AUTHTIME_X, 565 &data_set); 566 if (maj_stat) 567 return maj_stat; 568 569 if (data_set == GSS_C_NO_BUFFER_SET) { 570 gss_release_buffer_set(minor_status, &data_set); 571 *minor_status = EINVAL; 572 return GSS_S_FAILURE; 573 } 574 575 if (data_set->count != 1) { 576 gss_release_buffer_set(minor_status, &data_set); 577 *minor_status = EINVAL; 578 return GSS_S_FAILURE; 579 } 580 581 if (data_set->elements[0].length != 4) { 582 gss_release_buffer_set(minor_status, &data_set); 583 *minor_status = EINVAL; 584 return GSS_S_FAILURE; 585 } 586 587 { 588 unsigned char *buf = data_set->elements[0].value; 589 *authtime = (buf[3] <<24) | (buf[2] << 16) | 590 (buf[1] << 8) | (buf[0] << 0); 591 } 592 593 gss_release_buffer_set(minor_status, &data_set); 594 595 *minor_status = 0; 596 return GSS_S_COMPLETE; 597 } 598 599 /* 600 * 601 */ 602 603 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 604 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, 605 gss_ctx_id_t context_handle, 606 int ad_type, 607 gss_buffer_t ad_data) 608 { 609 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 610 OM_uint32 maj_stat; 611 gss_OID_desc oid_flat; 612 heim_oid baseoid, oid; 613 size_t size; 614 615 if (context_handle == GSS_C_NO_CONTEXT) { 616 *minor_status = EINVAL; 617 return GSS_S_FAILURE; 618 } 619 620 /* All this to append an integer to an oid... */ 621 622 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, 623 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, 624 &baseoid, NULL) != 0) { 625 *minor_status = EINVAL; 626 return GSS_S_FAILURE; 627 } 628 629 oid.length = baseoid.length + 1; 630 oid.components = calloc(oid.length, sizeof(*oid.components)); 631 if (oid.components == NULL) { 632 der_free_oid(&baseoid); 633 634 *minor_status = ENOMEM; 635 return GSS_S_FAILURE; 636 } 637 638 memcpy(oid.components, baseoid.components, 639 baseoid.length * sizeof(*baseoid.components)); 640 641 der_free_oid(&baseoid); 642 643 oid.components[oid.length - 1] = ad_type; 644 645 oid_flat.length = der_length_oid(&oid); 646 oid_flat.elements = malloc(oid_flat.length); 647 if (oid_flat.elements == NULL) { 648 free(oid.components); 649 *minor_status = ENOMEM; 650 return GSS_S_FAILURE; 651 } 652 653 if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 654 oid_flat.length, &oid, &size) != 0) { 655 free(oid.components); 656 free(oid_flat.elements); 657 *minor_status = EINVAL; 658 return GSS_S_FAILURE; 659 } 660 if (oid_flat.length != size) 661 abort(); 662 663 free(oid.components); 664 665 /* FINALLY, we have the OID */ 666 667 maj_stat = gss_inquire_sec_context_by_oid (minor_status, 668 context_handle, 669 &oid_flat, 670 &data_set); 671 672 free(oid_flat.elements); 673 674 if (maj_stat) 675 return maj_stat; 676 677 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 678 gss_release_buffer_set(minor_status, &data_set); 679 *minor_status = EINVAL; 680 return GSS_S_FAILURE; 681 } 682 683 ad_data->value = malloc(data_set->elements[0].length); 684 if (ad_data->value == NULL) { 685 gss_release_buffer_set(minor_status, &data_set); 686 *minor_status = ENOMEM; 687 return GSS_S_FAILURE; 688 } 689 690 ad_data->length = data_set->elements[0].length; 691 memcpy(ad_data->value, data_set->elements[0].value, ad_data->length); 692 gss_release_buffer_set(minor_status, &data_set); 693 694 *minor_status = 0; 695 return GSS_S_COMPLETE; 696 } 697 698 /* 699 * 700 */ 701 702 static OM_uint32 703 gsskrb5_extract_key(OM_uint32 *minor_status, 704 gss_ctx_id_t context_handle, 705 const gss_OID oid, 706 krb5_keyblock **keyblock) 707 { 708 krb5_error_code ret; 709 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 710 OM_uint32 major_status; 711 krb5_context context = NULL; 712 krb5_storage *sp = NULL; 713 714 if (context_handle == GSS_C_NO_CONTEXT) { 715 *minor_status = EINVAL; 716 return GSS_S_FAILURE; 717 } 718 719 ret = krb5_init_context(&context); 720 if(ret) { 721 *minor_status = ret; 722 return GSS_S_FAILURE; 723 } 724 725 major_status = 726 gss_inquire_sec_context_by_oid (minor_status, 727 context_handle, 728 oid, 729 &data_set); 730 if (major_status) 731 return major_status; 732 733 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 734 gss_release_buffer_set(minor_status, &data_set); 735 *minor_status = EINVAL; 736 return GSS_S_FAILURE; 737 } 738 739 sp = krb5_storage_from_mem(data_set->elements[0].value, 740 data_set->elements[0].length); 741 if (sp == NULL) { 742 ret = ENOMEM; 743 goto out; 744 } 745 746 *keyblock = calloc(1, sizeof(**keyblock)); 747 if (keyblock == NULL) { 748 ret = ENOMEM; 749 goto out; 750 } 751 752 ret = krb5_ret_keyblock(sp, *keyblock); 753 754 out: 755 gss_release_buffer_set(minor_status, &data_set); 756 if (sp) 757 krb5_storage_free(sp); 758 if (ret && keyblock) { 759 krb5_free_keyblock(context, *keyblock); 760 *keyblock = NULL; 761 } 762 if (context) 763 krb5_free_context(context); 764 765 *minor_status = ret; 766 if (ret) 767 return GSS_S_FAILURE; 768 769 return GSS_S_COMPLETE; 770 } 771 772 /* 773 * 774 */ 775 776 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 777 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status, 778 gss_ctx_id_t context_handle, 779 krb5_keyblock **keyblock) 780 { 781 return gsskrb5_extract_key(minor_status, 782 context_handle, 783 GSS_KRB5_GET_SERVICE_KEYBLOCK_X, 784 keyblock); 785 } 786 787 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 788 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status, 789 gss_ctx_id_t context_handle, 790 krb5_keyblock **keyblock) 791 { 792 return gsskrb5_extract_key(minor_status, 793 context_handle, 794 GSS_KRB5_GET_INITIATOR_SUBKEY_X, 795 keyblock); 796 } 797 798 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 799 gsskrb5_get_subkey(OM_uint32 *minor_status, 800 gss_ctx_id_t context_handle, 801 krb5_keyblock **keyblock) 802 { 803 return gsskrb5_extract_key(minor_status, 804 context_handle, 805 GSS_KRB5_GET_SUBKEY_X, 806 keyblock); 807 } 808 809 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 810 gsskrb5_set_default_realm(const char *realm) 811 { 812 struct _gss_mech_switch *m; 813 gss_buffer_desc buffer; 814 OM_uint32 junk; 815 816 _gss_load_mech(); 817 818 buffer.value = rk_UNCONST(realm); 819 buffer.length = strlen(realm); 820 821 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 822 if (m->gm_mech.gm_set_sec_context_option == NULL) 823 continue; 824 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 825 GSS_KRB5_SET_DEFAULT_REALM_X, &buffer); 826 } 827 828 return (GSS_S_COMPLETE); 829 } 830 831 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 832 gss_krb5_get_tkt_flags(OM_uint32 *minor_status, 833 gss_ctx_id_t context_handle, 834 OM_uint32 *tkt_flags) 835 { 836 837 OM_uint32 major_status; 838 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 839 840 if (context_handle == GSS_C_NO_CONTEXT) { 841 *minor_status = EINVAL; 842 return GSS_S_FAILURE; 843 } 844 845 major_status = 846 gss_inquire_sec_context_by_oid (minor_status, 847 context_handle, 848 GSS_KRB5_GET_TKT_FLAGS_X, 849 &data_set); 850 if (major_status) 851 return major_status; 852 853 if (data_set == GSS_C_NO_BUFFER_SET || 854 data_set->count != 1 || 855 data_set->elements[0].length < 4) { 856 gss_release_buffer_set(minor_status, &data_set); 857 *minor_status = EINVAL; 858 return GSS_S_FAILURE; 859 } 860 861 { 862 const u_char *p = data_set->elements[0].value; 863 *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 864 } 865 866 gss_release_buffer_set(minor_status, &data_set); 867 return GSS_S_COMPLETE; 868 } 869 870 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 871 gsskrb5_set_time_offset(int offset) 872 { 873 struct _gss_mech_switch *m; 874 gss_buffer_desc buffer; 875 OM_uint32 junk; 876 int32_t o = offset; 877 878 _gss_load_mech(); 879 880 buffer.value = &o; 881 buffer.length = sizeof(o); 882 883 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 884 if (m->gm_mech.gm_set_sec_context_option == NULL) 885 continue; 886 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 887 GSS_KRB5_SET_TIME_OFFSET_X, &buffer); 888 } 889 890 return (GSS_S_COMPLETE); 891 } 892 893 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 894 gsskrb5_get_time_offset(int *offset) 895 { 896 struct _gss_mech_switch *m; 897 gss_buffer_desc buffer; 898 OM_uint32 maj_stat, junk; 899 int32_t o; 900 901 _gss_load_mech(); 902 903 buffer.value = &o; 904 buffer.length = sizeof(o); 905 906 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 907 if (m->gm_mech.gm_set_sec_context_option == NULL) 908 continue; 909 maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL, 910 GSS_KRB5_GET_TIME_OFFSET_X, &buffer); 911 912 if (maj_stat == GSS_S_COMPLETE) { 913 *offset = o; 914 return maj_stat; 915 } 916 } 917 918 return (GSS_S_UNAVAILABLE); 919 } 920 921 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 922 gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c) 923 { 924 struct _gss_mech_switch *m; 925 gss_buffer_desc buffer; 926 OM_uint32 junk; 927 928 _gss_load_mech(); 929 930 buffer.value = c; 931 buffer.length = sizeof(*c); 932 933 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 934 if (m->gm_mech.gm_set_sec_context_option == NULL) 935 continue; 936 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 937 GSS_KRB5_PLUGIN_REGISTER_X, &buffer); 938 } 939 940 return (GSS_S_COMPLETE); 941 } 942