1/*- 2 * Copyright (c) 2005 Doug Rabson 3 * All rights reserved. 4 * 5 * Portions Copyright (c) 2009 Apple Inc. 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.h> 34#include <roken.h> 35 36 37GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 38gss_krb5_copy_ccache(OM_uint32 *minor_status, 39 gss_cred_id_t cred, 40 struct krb5_ccache_data *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 95GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 96gss_krb5_import_cred(OM_uint32 *minor_status, 97 struct krb5_ccache_data *id, 98 struct Principal *keytab_principal, 99 struct krb5_keytab_data *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); 183out: 184 if (sp) 185 krb5_storage_free(sp); 186 krb5_free_context(context); 187 return major_status; 188} 189 190GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 191gsskrb5_register_acceptor_identity(const char *identity) 192{ 193 gssapi_mech_interface 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 m = __gss_get_mechanism(GSS_KRB5_MECHANISM); 203 if (m == NULL || m->gm_set_sec_context_option == NULL) 204 return GSS_S_FAILURE; 205 206 return m->gm_set_sec_context_option(&junk, NULL, 207 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer); 208} 209 210GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 211krb5_gss_register_acceptor_identity(const char *identity) 212{ 213 return gsskrb5_register_acceptor_identity(identity); 214} 215 216 217GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 218gsskrb5_set_dns_canonicalize(int flag) 219{ 220 struct _gss_mech_switch *m; 221 gss_buffer_desc buffer; 222 OM_uint32 junk; 223 char b = (flag != 0); 224 225 _gss_load_mech(); 226 227 buffer.value = &b; 228 buffer.length = sizeof(b); 229 230 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 231 if (m->gm_mech.gm_set_sec_context_option == NULL) 232 continue; 233 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 234 GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer); 235 } 236 237 return (GSS_S_COMPLETE); 238} 239 240 241 242static krb5_error_code 243set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key) 244{ 245 key->type = keyblock->keytype; 246 key->length = (OM_uint32)keyblock->keyvalue.length; 247 key->data = malloc(key->length); 248 if (key->data == NULL && key->length != 0) 249 return ENOMEM; 250 memcpy(key->data, keyblock->keyvalue.data, key->length); 251 return 0; 252} 253 254static void 255free_key(gss_krb5_lucid_key_t *key) 256{ 257 memset(key->data, 0, key->length); 258 free(key->data); 259 memset(key, 0, sizeof(*key)); 260} 261 262GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 263gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, 264 gss_ctx_id_t *context_handle, 265 OM_uint32 version, 266 void **rctx) 267{ 268 krb5_context context = NULL; 269 krb5_error_code ret; 270 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 271 OM_uint32 major_status; 272 gss_krb5_lucid_context_v1_t *ctx = NULL; 273 krb5_storage *sp = NULL; 274 uint32_t num; 275 276 if (context_handle == NULL 277 || *context_handle == GSS_C_NO_CONTEXT 278 || version != 1) 279 { 280 *minor_status = EINVAL; 281 return GSS_S_FAILURE; 282 } 283 284 major_status = 285 gss_inquire_sec_context_by_oid (minor_status, 286 *context_handle, 287 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, 288 &data_set); 289 if (major_status) 290 return major_status; 291 292 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 293 gss_release_buffer_set(minor_status, &data_set); 294 *minor_status = EINVAL; 295 return GSS_S_FAILURE; 296 } 297 298 ret = krb5_init_context(&context); 299 if (ret) 300 goto out; 301 302 ctx = calloc(1, sizeof(*ctx)); 303 if (ctx == NULL) { 304 ret = ENOMEM; 305 goto out; 306 } 307 308 sp = krb5_storage_from_mem(data_set->elements[0].value, 309 data_set->elements[0].length); 310 if (sp == NULL) { 311 ret = ENOMEM; 312 goto out; 313 } 314 315 ret = krb5_ret_uint32(sp, &num); 316 if (ret) goto out; 317 if (num != 1) { 318 ret = EINVAL; 319 goto out; 320 } 321 ctx->version = 1; 322 /* initiator */ 323 ret = krb5_ret_uint32(sp, &ctx->initiate); 324 if (ret) goto out; 325 /* endtime */ 326 ret = krb5_ret_uint32(sp, &ctx->endtime); 327 if (ret) goto out; 328 /* send_seq */ 329 ret = krb5_ret_uint32(sp, &num); 330 if (ret) goto out; 331 ctx->send_seq = ((uint64_t)num) << 32; 332 ret = krb5_ret_uint32(sp, &num); 333 if (ret) goto out; 334 ctx->send_seq |= num; 335 /* recv_seq */ 336 ret = krb5_ret_uint32(sp, &num); 337 if (ret) goto out; 338 ctx->recv_seq = ((uint64_t)num) << 32; 339 ret = krb5_ret_uint32(sp, &num); 340 if (ret) goto out; 341 ctx->recv_seq |= num; 342 /* protocol */ 343 ret = krb5_ret_uint32(sp, &ctx->protocol); 344 if (ret) goto out; 345 if (ctx->protocol == 0) { 346 krb5_keyblock key; 347 348 /* sign_alg */ 349 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); 350 if (ret) goto out; 351 /* seal_alg */ 352 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); 353 if (ret) goto out; 354 /* ctx_key */ 355 ret = krb5_ret_keyblock(sp, &key); 356 if (ret) goto out; 357 ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); 358 krb5_free_keyblock_contents(context, &key); 359 if (ret) goto out; 360 } else if (ctx->protocol == 1) { 361 krb5_keyblock key; 362 363 /* acceptor_subkey */ 364 ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); 365 if (ret) goto out; 366 /* ctx_key */ 367 ret = krb5_ret_keyblock(sp, &key); 368 if (ret) goto out; 369 ret = set_key(&key, &ctx->cfx_kd.ctx_key); 370 krb5_free_keyblock_contents(context, &key); 371 if (ret) goto out; 372 /* acceptor_subkey */ 373 if (ctx->cfx_kd.have_acceptor_subkey) { 374 ret = krb5_ret_keyblock(sp, &key); 375 if (ret) goto out; 376 ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); 377 krb5_free_keyblock_contents(context, &key); 378 if (ret) goto out; 379 } 380 } else { 381 ret = EINVAL; 382 goto out; 383 } 384 385 *rctx = ctx; 386 387out: 388 gss_release_buffer_set(minor_status, &data_set); 389 if (sp) 390 krb5_storage_free(sp); 391 if (context) 392 krb5_free_context(context); 393 394 if (ret) { 395 if (ctx) 396 gss_krb5_free_lucid_sec_context(NULL, ctx); 397 398 *minor_status = ret; 399 return GSS_S_FAILURE; 400 } 401 *minor_status = 0; 402 return GSS_S_COMPLETE; 403} 404 405GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 406gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c) 407{ 408 gss_krb5_lucid_context_v1_t *ctx = c; 409 410 if (ctx->version != 1) { 411 if (minor_status) 412 *minor_status = 0; 413 return GSS_S_FAILURE; 414 } 415 416 if (ctx->protocol == 0) { 417 free_key(&ctx->rfc1964_kd.ctx_key); 418 } else if (ctx->protocol == 1) { 419 free_key(&ctx->cfx_kd.ctx_key); 420 if (ctx->cfx_kd.have_acceptor_subkey) 421 free_key(&ctx->cfx_kd.acceptor_subkey); 422 } 423 free(ctx); 424 if (minor_status) 425 *minor_status = 0; 426 return GSS_S_COMPLETE; 427} 428 429/* 430 * 431 */ 432 433GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 434gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 435 gss_cred_id_t cred, 436 OM_uint32 num_enctypes, 437 int32_t *enctypes) 438{ 439 krb5_error_code ret; 440 OM_uint32 maj_status; 441 gss_buffer_desc buffer; 442 krb5_storage *sp; 443 krb5_data data; 444 size_t i; 445 446 sp = krb5_storage_emem(); 447 if (sp == NULL) { 448 *minor_status = ENOMEM; 449 maj_status = GSS_S_FAILURE; 450 goto out; 451 } 452 453 for (i = 0; i < num_enctypes; i++) { 454 ret = krb5_store_int32(sp, enctypes[i]); 455 if (ret) { 456 *minor_status = ret; 457 maj_status = GSS_S_FAILURE; 458 goto out; 459 } 460 } 461 462 ret = krb5_storage_to_data(sp, &data); 463 if (ret) { 464 *minor_status = ret; 465 maj_status = GSS_S_FAILURE; 466 goto out; 467 } 468 469 buffer.value = data.data; 470 buffer.length = data.length; 471 472 maj_status = gss_set_cred_option(minor_status, 473 &cred, 474 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, 475 &buffer); 476 krb5_data_free(&data); 477out: 478 if (sp) 479 krb5_storage_free(sp); 480 return maj_status; 481} 482 483/* 484 * 485 */ 486 487GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 488gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c) 489{ 490 struct _gss_mech_switch *m; 491 gss_buffer_desc buffer; 492 OM_uint32 junk; 493 494 _gss_load_mech(); 495 496 if (c) { 497 buffer.value = c; 498 buffer.length = sizeof(*c); 499 } else { 500 buffer.value = NULL; 501 buffer.length = 0; 502 } 503 504 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 505 if (m->gm_mech.gm_set_sec_context_option == NULL) 506 continue; 507 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 508 GSS_KRB5_SEND_TO_KDC_X, &buffer); 509 } 510 511 return (GSS_S_COMPLETE); 512} 513 514/* 515 * 516 */ 517 518GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 519gss_krb5_ccache_name(OM_uint32 *minor_status, 520 const char *name, 521 const char **out_name) 522{ 523 struct _gss_mech_switch *m; 524 gss_buffer_desc buffer; 525 OM_uint32 junk; 526 527 _gss_load_mech(); 528 529 if (out_name) 530 *out_name = NULL; 531 532 if (name) { 533 buffer.value = rk_UNCONST(name); 534 buffer.length = strlen(name); 535 } else { 536 _mg_buffer_zero(&buffer); 537 } 538 539 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 540 if (m->gm_mech.gm_set_sec_context_option == NULL) 541 continue; 542 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 543 GSS_KRB5_CCACHE_NAME_X, &buffer); 544 } 545 546 return (GSS_S_COMPLETE); 547} 548 549 550/* 551 * 552 */ 553 554GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 555gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, 556 gss_ctx_id_t context_handle, 557 time_t *authtime) 558{ 559 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 560 OM_uint32 maj_stat; 561 562 if (context_handle == GSS_C_NO_CONTEXT) { 563 *minor_status = EINVAL; 564 return GSS_S_FAILURE; 565 } 566 567 maj_stat = 568 gss_inquire_sec_context_by_oid (minor_status, 569 context_handle, 570 GSS_KRB5_GET_AUTHTIME_X, 571 &data_set); 572 if (maj_stat) 573 return maj_stat; 574 575 if (data_set == GSS_C_NO_BUFFER_SET) { 576 gss_release_buffer_set(minor_status, &data_set); 577 *minor_status = EINVAL; 578 return GSS_S_FAILURE; 579 } 580 581 if (data_set->count != 1) { 582 gss_release_buffer_set(minor_status, &data_set); 583 *minor_status = EINVAL; 584 return GSS_S_FAILURE; 585 } 586 587 if (data_set->elements[0].length != 4) { 588 gss_release_buffer_set(minor_status, &data_set); 589 *minor_status = EINVAL; 590 return GSS_S_FAILURE; 591 } 592 593 { 594 unsigned char *buf = data_set->elements[0].value; 595 *authtime = (buf[3] <<24) | (buf[2] << 16) | 596 (buf[1] << 8) | (buf[0] << 0); 597 } 598 599 gss_release_buffer_set(minor_status, &data_set); 600 601 *minor_status = 0; 602 return GSS_S_COMPLETE; 603} 604 605/* 606 * 607 */ 608 609GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 610gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, 611 gss_ctx_id_t context_handle, 612 int ad_type, 613 gss_buffer_t ad_data) 614{ 615 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 616 OM_uint32 maj_stat; 617 gss_OID_desc oid_flat; 618 heim_oid baseoid, oid; 619 size_t size; 620 621 if (context_handle == GSS_C_NO_CONTEXT) { 622 *minor_status = EINVAL; 623 return GSS_S_FAILURE; 624 } 625 626 /* All this to append an integer to an oid... */ 627 628 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, 629 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, 630 &baseoid, NULL) != 0) { 631 *minor_status = EINVAL; 632 return GSS_S_FAILURE; 633 } 634 635 oid.length = baseoid.length + 1; 636 oid.components = calloc(oid.length, sizeof(*oid.components)); 637 if (oid.components == NULL) { 638 der_free_oid(&baseoid); 639 640 *minor_status = ENOMEM; 641 return GSS_S_FAILURE; 642 } 643 644 memcpy(oid.components, baseoid.components, 645 baseoid.length * sizeof(*baseoid.components)); 646 647 der_free_oid(&baseoid); 648 649 oid.components[oid.length - 1] = ad_type; 650 651 oid_flat.length = (OM_uint32)der_length_oid(&oid); 652 oid_flat.elements = malloc(oid_flat.length); 653 if (oid_flat.elements == NULL) { 654 free(oid.components); 655 *minor_status = ENOMEM; 656 return GSS_S_FAILURE; 657 } 658 659 if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 660 oid_flat.length, &oid, &size) != 0) { 661 free(oid.components); 662 free(oid_flat.elements); 663 *minor_status = EINVAL; 664 return GSS_S_FAILURE; 665 } 666 if (oid_flat.length != size) 667 abort(); 668 669 free(oid.components); 670 671 /* FINALLY, we have the OID */ 672 673 maj_stat = gss_inquire_sec_context_by_oid (minor_status, 674 context_handle, 675 &oid_flat, 676 &data_set); 677 678 free(oid_flat.elements); 679 680 if (maj_stat) 681 return maj_stat; 682 683 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 684 gss_release_buffer_set(minor_status, &data_set); 685 *minor_status = EINVAL; 686 return GSS_S_FAILURE; 687 } 688 689 ad_data->value = malloc(data_set->elements[0].length); 690 if (ad_data->value == NULL) { 691 gss_release_buffer_set(minor_status, &data_set); 692 *minor_status = ENOMEM; 693 return GSS_S_FAILURE; 694 } 695 696 ad_data->length = data_set->elements[0].length; 697 memcpy(ad_data->value, data_set->elements[0].value, ad_data->length); 698 gss_release_buffer_set(minor_status, &data_set); 699 700 *minor_status = 0; 701 return GSS_S_COMPLETE; 702} 703 704/* 705 * 706 */ 707 708static OM_uint32 709gsskrb5_extract_key(OM_uint32 *minor_status, 710 gss_ctx_id_t context_handle, 711 const gss_OID oid, 712 krb5_keyblock **keyblock) 713{ 714 krb5_error_code ret; 715 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 716 OM_uint32 major_status; 717 krb5_context context = NULL; 718 krb5_storage *sp = NULL; 719 720 if (context_handle == GSS_C_NO_CONTEXT) { 721 *minor_status = EINVAL; 722 return GSS_S_FAILURE; 723 } 724 725 ret = krb5_init_context(&context); 726 if(ret) { 727 *minor_status = ret; 728 return GSS_S_FAILURE; 729 } 730 731 major_status = 732 gss_inquire_sec_context_by_oid (minor_status, 733 context_handle, 734 oid, 735 &data_set); 736 if (major_status) 737 return major_status; 738 739 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 740 gss_release_buffer_set(minor_status, &data_set); 741 *minor_status = EINVAL; 742 return GSS_S_FAILURE; 743 } 744 745 sp = krb5_storage_from_mem(data_set->elements[0].value, 746 data_set->elements[0].length); 747 if (sp == NULL) { 748 ret = ENOMEM; 749 goto out; 750 } 751 752 *keyblock = calloc(1, sizeof(**keyblock)); 753 if (keyblock == NULL) { 754 ret = ENOMEM; 755 goto out; 756 } 757 758 ret = krb5_ret_keyblock(sp, *keyblock); 759 760out: 761 gss_release_buffer_set(minor_status, &data_set); 762 if (sp) 763 krb5_storage_free(sp); 764 if (ret && keyblock) { 765 krb5_free_keyblock(context, *keyblock); 766 *keyblock = NULL; 767 } 768 if (context) 769 krb5_free_context(context); 770 771 *minor_status = ret; 772 if (ret) 773 return GSS_S_FAILURE; 774 775 return GSS_S_COMPLETE; 776} 777 778/* 779 * 780 */ 781 782GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 783gsskrb5_extract_service_keyblock(OM_uint32 *minor_status, 784 gss_ctx_id_t context_handle, 785 struct EncryptionKey **keyblock) 786{ 787 return gsskrb5_extract_key(minor_status, 788 context_handle, 789 GSS_KRB5_GET_SERVICE_KEYBLOCK_X, 790 keyblock); 791} 792 793GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 794gsskrb5_get_initiator_subkey(OM_uint32 *minor_status, 795 gss_ctx_id_t context_handle, 796 struct EncryptionKey **keyblock) 797{ 798 return gsskrb5_extract_key(minor_status, 799 context_handle, 800 GSS_KRB5_GET_INITIATOR_SUBKEY_X, 801 keyblock); 802} 803 804GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 805gsskrb5_get_subkey(OM_uint32 *minor_status, 806 gss_ctx_id_t context_handle, 807 struct EncryptionKey **keyblock) 808{ 809 return gsskrb5_extract_key(minor_status, 810 context_handle, 811 GSS_KRB5_GET_SUBKEY_X, 812 keyblock); 813} 814 815GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 816gsskrb5_set_default_realm(const char *realm) 817{ 818 struct _gss_mech_switch *m; 819 gss_buffer_desc buffer; 820 OM_uint32 junk; 821 822 _gss_load_mech(); 823 824 buffer.value = rk_UNCONST(realm); 825 buffer.length = strlen(realm); 826 827 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 828 if (m->gm_mech.gm_set_sec_context_option == NULL) 829 continue; 830 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 831 GSS_KRB5_SET_DEFAULT_REALM_X, &buffer); 832 } 833 834 return (GSS_S_COMPLETE); 835} 836 837GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 838gss_krb5_get_tkt_flags(OM_uint32 *minor_status, 839 gss_ctx_id_t context_handle, 840 OM_uint32 *tkt_flags) 841{ 842 843 OM_uint32 major_status; 844 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 845 846 if (context_handle == GSS_C_NO_CONTEXT) { 847 *minor_status = EINVAL; 848 return GSS_S_FAILURE; 849 } 850 851 major_status = 852 gss_inquire_sec_context_by_oid (minor_status, 853 context_handle, 854 GSS_KRB5_GET_TKT_FLAGS_X, 855 &data_set); 856 if (major_status) 857 return major_status; 858 859 if (data_set == GSS_C_NO_BUFFER_SET || 860 data_set->count != 1 || 861 data_set->elements[0].length < 4) { 862 gss_release_buffer_set(minor_status, &data_set); 863 *minor_status = EINVAL; 864 return GSS_S_FAILURE; 865 } 866 867 { 868 const u_char *p = data_set->elements[0].value; 869 *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 870 } 871 872 gss_release_buffer_set(minor_status, &data_set); 873 return GSS_S_COMPLETE; 874} 875 876GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 877gsskrb5_set_time_offset(int offset) 878{ 879 struct _gss_mech_switch *m; 880 gss_buffer_desc buffer; 881 OM_uint32 junk; 882 int32_t o = offset; 883 884 _gss_load_mech(); 885 886 buffer.value = &o; 887 buffer.length = sizeof(o); 888 889 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 890 if (m->gm_mech.gm_set_sec_context_option == NULL) 891 continue; 892 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 893 GSS_KRB5_SET_TIME_OFFSET_X, &buffer); 894 } 895 896 return (GSS_S_COMPLETE); 897} 898 899GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 900gsskrb5_get_time_offset(int *offset) 901{ 902 struct _gss_mech_switch *m; 903 gss_buffer_desc buffer; 904 OM_uint32 maj_stat, junk; 905 int32_t o; 906 907 _gss_load_mech(); 908 909 buffer.value = &o; 910 buffer.length = sizeof(o); 911 912 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 913 if (m->gm_mech.gm_set_sec_context_option == NULL) 914 continue; 915 maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL, 916 GSS_KRB5_GET_TIME_OFFSET_X, &buffer); 917 918 if (maj_stat == GSS_S_COMPLETE) { 919 *offset = o; 920 return maj_stat; 921 } 922 } 923 924 return (GSS_S_UNAVAILABLE); 925} 926 927GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 928gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c) 929{ 930 struct _gss_mech_switch *m; 931 gss_buffer_desc buffer; 932 OM_uint32 junk; 933 934 _gss_load_mech(); 935 936 buffer.value = c; 937 buffer.length = sizeof(*c); 938 939 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 940 if (m->gm_mech.gm_set_sec_context_option == NULL) 941 continue; 942 m->gm_mech.gm_set_sec_context_option(&junk, NULL, 943 GSS_KRB5_PLUGIN_REGISTER_X, &buffer); 944 } 945 946 return (GSS_S_COMPLETE); 947} 948