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