1226031Sstas/*- 2226031Sstas * Copyright (c) 2005 Doug Rabson 3226031Sstas * All rights reserved. 4226031Sstas * 5226031Sstas * Redistribution and use in source and binary forms, with or without 6226031Sstas * modification, are permitted provided that the following conditions 7226031Sstas * are met: 8226031Sstas * 1. Redistributions of source code must retain the above copyright 9226031Sstas * notice, this list of conditions and the following disclaimer. 10226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer in the 12226031Sstas * documentation and/or other materials provided with the distribution. 13226031Sstas * 14226031Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24226031Sstas * SUCH DAMAGE. 25226031Sstas * 26226031Sstas * $FreeBSD: src/lib/libgssapi/gss_krb5.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ 27226031Sstas */ 28226031Sstas 29226031Sstas#include "mech_locl.h" 30226031Sstas 31226031Sstas#include <krb5.h> 32226031Sstas#include <roken.h> 33226031Sstas 34226031Sstas 35226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 36226031Sstasgss_krb5_copy_ccache(OM_uint32 *minor_status, 37226031Sstas gss_cred_id_t cred, 38226031Sstas krb5_ccache out) 39226031Sstas{ 40226031Sstas gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 41226031Sstas krb5_context context; 42226031Sstas krb5_error_code kret; 43226031Sstas krb5_ccache id; 44226031Sstas OM_uint32 ret; 45226031Sstas char *str = NULL; 46226031Sstas 47226031Sstas ret = gss_inquire_cred_by_oid(minor_status, 48226031Sstas cred, 49226031Sstas GSS_KRB5_COPY_CCACHE_X, 50226031Sstas &data_set); 51226031Sstas if (ret) 52226031Sstas return ret; 53226031Sstas 54226031Sstas if (data_set == GSS_C_NO_BUFFER_SET || data_set->count < 1) { 55226031Sstas gss_release_buffer_set(minor_status, &data_set); 56226031Sstas *minor_status = EINVAL; 57226031Sstas return GSS_S_FAILURE; 58226031Sstas } 59226031Sstas 60226031Sstas kret = krb5_init_context(&context); 61226031Sstas if (kret) { 62226031Sstas *minor_status = kret; 63226031Sstas gss_release_buffer_set(minor_status, &data_set); 64226031Sstas return GSS_S_FAILURE; 65226031Sstas } 66226031Sstas 67226031Sstas kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length, 68226031Sstas (char *)data_set->elements[0].value); 69226031Sstas gss_release_buffer_set(minor_status, &data_set); 70226031Sstas if (kret < 0 || str == NULL) { 71226031Sstas *minor_status = ENOMEM; 72226031Sstas return GSS_S_FAILURE; 73226031Sstas } 74226031Sstas 75226031Sstas kret = krb5_cc_resolve(context, str, &id); 76226031Sstas free(str); 77226031Sstas if (kret) { 78226031Sstas *minor_status = kret; 79226031Sstas return GSS_S_FAILURE; 80226031Sstas } 81226031Sstas 82226031Sstas kret = krb5_cc_copy_cache(context, id, out); 83226031Sstas krb5_cc_close(context, id); 84226031Sstas krb5_free_context(context); 85226031Sstas if (kret) { 86226031Sstas *minor_status = kret; 87226031Sstas return GSS_S_FAILURE; 88226031Sstas } 89226031Sstas 90226031Sstas return ret; 91226031Sstas} 92226031Sstas 93226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 94226031Sstasgss_krb5_import_cred(OM_uint32 *minor_status, 95226031Sstas krb5_ccache id, 96226031Sstas krb5_principal keytab_principal, 97226031Sstas krb5_keytab keytab, 98226031Sstas gss_cred_id_t *cred) 99226031Sstas{ 100226031Sstas gss_buffer_desc buffer; 101226031Sstas OM_uint32 major_status; 102226031Sstas krb5_context context; 103226031Sstas krb5_error_code ret; 104226031Sstas krb5_storage *sp; 105226031Sstas krb5_data data; 106226031Sstas char *str; 107226031Sstas 108226031Sstas *cred = GSS_C_NO_CREDENTIAL; 109226031Sstas 110226031Sstas ret = krb5_init_context(&context); 111226031Sstas if (ret) { 112226031Sstas *minor_status = ret; 113226031Sstas return GSS_S_FAILURE; 114226031Sstas } 115226031Sstas 116226031Sstas sp = krb5_storage_emem(); 117226031Sstas if (sp == NULL) { 118226031Sstas *minor_status = ENOMEM; 119226031Sstas major_status = GSS_S_FAILURE; 120226031Sstas goto out; 121226031Sstas } 122226031Sstas 123226031Sstas if (id) { 124226031Sstas ret = krb5_cc_get_full_name(context, id, &str); 125226031Sstas if (ret == 0) { 126226031Sstas ret = krb5_store_string(sp, str); 127226031Sstas free(str); 128226031Sstas } 129226031Sstas } else 130226031Sstas ret = krb5_store_string(sp, ""); 131226031Sstas if (ret) { 132226031Sstas *minor_status = ret; 133226031Sstas major_status = GSS_S_FAILURE; 134226031Sstas goto out; 135226031Sstas } 136226031Sstas 137226031Sstas if (keytab_principal) { 138226031Sstas ret = krb5_unparse_name(context, keytab_principal, &str); 139226031Sstas if (ret == 0) { 140226031Sstas ret = krb5_store_string(sp, str); 141226031Sstas free(str); 142226031Sstas } 143226031Sstas } else 144226031Sstas krb5_store_string(sp, ""); 145226031Sstas if (ret) { 146226031Sstas *minor_status = ret; 147226031Sstas major_status = GSS_S_FAILURE; 148226031Sstas goto out; 149226031Sstas } 150226031Sstas 151226031Sstas 152226031Sstas if (keytab) { 153226031Sstas ret = krb5_kt_get_full_name(context, keytab, &str); 154226031Sstas if (ret == 0) { 155226031Sstas ret = krb5_store_string(sp, str); 156226031Sstas free(str); 157226031Sstas } 158226031Sstas } else 159226031Sstas krb5_store_string(sp, ""); 160226031Sstas if (ret) { 161226031Sstas *minor_status = ret; 162226031Sstas major_status = GSS_S_FAILURE; 163226031Sstas goto out; 164226031Sstas } 165226031Sstas 166226031Sstas ret = krb5_storage_to_data(sp, &data); 167226031Sstas if (ret) { 168226031Sstas *minor_status = ret; 169226031Sstas major_status = GSS_S_FAILURE; 170226031Sstas goto out; 171226031Sstas } 172226031Sstas 173226031Sstas buffer.value = data.data; 174226031Sstas buffer.length = data.length; 175226031Sstas 176226031Sstas major_status = gss_set_cred_option(minor_status, 177226031Sstas cred, 178226031Sstas GSS_KRB5_IMPORT_CRED_X, 179226031Sstas &buffer); 180226031Sstas krb5_data_free(&data); 181226031Sstasout: 182226031Sstas if (sp) 183226031Sstas krb5_storage_free(sp); 184226031Sstas krb5_free_context(context); 185226031Sstas return major_status; 186226031Sstas} 187226031Sstas 188226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 189226031Sstasgsskrb5_register_acceptor_identity(const char *identity) 190226031Sstas{ 191226031Sstas gssapi_mech_interface m; 192226031Sstas gss_buffer_desc buffer; 193226031Sstas OM_uint32 junk; 194226031Sstas 195226031Sstas _gss_load_mech(); 196226031Sstas 197226031Sstas buffer.value = rk_UNCONST(identity); 198226031Sstas buffer.length = strlen(identity); 199226031Sstas 200226031Sstas m = __gss_get_mechanism(GSS_KRB5_MECHANISM); 201226031Sstas if (m == NULL || m->gm_set_sec_context_option == NULL) 202226031Sstas return GSS_S_FAILURE; 203226031Sstas 204226031Sstas return m->gm_set_sec_context_option(&junk, NULL, 205226031Sstas GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer); 206226031Sstas} 207226031Sstas 208226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 209226031Sstaskrb5_gss_register_acceptor_identity(const char *identity) 210226031Sstas{ 211226031Sstas return gsskrb5_register_acceptor_identity(identity); 212226031Sstas} 213226031Sstas 214226031Sstas 215226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 216226031Sstasgsskrb5_set_dns_canonicalize(int flag) 217226031Sstas{ 218226031Sstas struct _gss_mech_switch *m; 219226031Sstas gss_buffer_desc buffer; 220226031Sstas OM_uint32 junk; 221226031Sstas char b = (flag != 0); 222226031Sstas 223226031Sstas _gss_load_mech(); 224226031Sstas 225226031Sstas buffer.value = &b; 226226031Sstas buffer.length = sizeof(b); 227226031Sstas 228226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 229226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 230226031Sstas continue; 231226031Sstas m->gm_mech.gm_set_sec_context_option(&junk, NULL, 232226031Sstas GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer); 233226031Sstas } 234226031Sstas 235226031Sstas return (GSS_S_COMPLETE); 236226031Sstas} 237226031Sstas 238226031Sstas 239226031Sstas 240226031Sstasstatic krb5_error_code 241226031Sstasset_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key) 242226031Sstas{ 243226031Sstas key->type = keyblock->keytype; 244226031Sstas key->length = keyblock->keyvalue.length; 245226031Sstas key->data = malloc(key->length); 246226031Sstas if (key->data == NULL && key->length != 0) 247226031Sstas return ENOMEM; 248226031Sstas memcpy(key->data, keyblock->keyvalue.data, key->length); 249226031Sstas return 0; 250226031Sstas} 251226031Sstas 252226031Sstasstatic void 253226031Sstasfree_key(gss_krb5_lucid_key_t *key) 254226031Sstas{ 255226031Sstas memset(key->data, 0, key->length); 256226031Sstas free(key->data); 257226031Sstas memset(key, 0, sizeof(*key)); 258226031Sstas} 259226031Sstas 260226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 261226031Sstasgss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, 262226031Sstas gss_ctx_id_t *context_handle, 263226031Sstas OM_uint32 version, 264226031Sstas void **rctx) 265226031Sstas{ 266226031Sstas krb5_context context = NULL; 267226031Sstas krb5_error_code ret; 268226031Sstas gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 269226031Sstas OM_uint32 major_status; 270226031Sstas gss_krb5_lucid_context_v1_t *ctx = NULL; 271226031Sstas krb5_storage *sp = NULL; 272226031Sstas uint32_t num; 273226031Sstas 274226031Sstas if (context_handle == NULL 275226031Sstas || *context_handle == GSS_C_NO_CONTEXT 276226031Sstas || version != 1) 277226031Sstas { 278226031Sstas *minor_status = EINVAL; 279226031Sstas return GSS_S_FAILURE; 280226031Sstas } 281226031Sstas 282226031Sstas major_status = 283226031Sstas gss_inquire_sec_context_by_oid (minor_status, 284226031Sstas *context_handle, 285226031Sstas GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, 286226031Sstas &data_set); 287226031Sstas if (major_status) 288226031Sstas return major_status; 289226031Sstas 290226031Sstas if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 291226031Sstas gss_release_buffer_set(minor_status, &data_set); 292226031Sstas *minor_status = EINVAL; 293226031Sstas return GSS_S_FAILURE; 294226031Sstas } 295226031Sstas 296226031Sstas ret = krb5_init_context(&context); 297226031Sstas if (ret) 298226031Sstas goto out; 299226031Sstas 300226031Sstas ctx = calloc(1, sizeof(*ctx)); 301226031Sstas if (ctx == NULL) { 302226031Sstas ret = ENOMEM; 303226031Sstas goto out; 304226031Sstas } 305226031Sstas 306226031Sstas sp = krb5_storage_from_mem(data_set->elements[0].value, 307226031Sstas data_set->elements[0].length); 308226031Sstas if (sp == NULL) { 309226031Sstas ret = ENOMEM; 310226031Sstas goto out; 311226031Sstas } 312226031Sstas 313226031Sstas ret = krb5_ret_uint32(sp, &num); 314226031Sstas if (ret) goto out; 315226031Sstas if (num != 1) { 316226031Sstas ret = EINVAL; 317226031Sstas goto out; 318226031Sstas } 319226031Sstas ctx->version = 1; 320226031Sstas /* initiator */ 321226031Sstas ret = krb5_ret_uint32(sp, &ctx->initiate); 322226031Sstas if (ret) goto out; 323226031Sstas /* endtime */ 324226031Sstas ret = krb5_ret_uint32(sp, &ctx->endtime); 325226031Sstas if (ret) goto out; 326226031Sstas /* send_seq */ 327226031Sstas ret = krb5_ret_uint32(sp, &num); 328226031Sstas if (ret) goto out; 329226031Sstas ctx->send_seq = ((uint64_t)num) << 32; 330226031Sstas ret = krb5_ret_uint32(sp, &num); 331226031Sstas if (ret) goto out; 332226031Sstas ctx->send_seq |= num; 333226031Sstas /* recv_seq */ 334226031Sstas ret = krb5_ret_uint32(sp, &num); 335226031Sstas if (ret) goto out; 336226031Sstas ctx->recv_seq = ((uint64_t)num) << 32; 337226031Sstas ret = krb5_ret_uint32(sp, &num); 338226031Sstas if (ret) goto out; 339226031Sstas ctx->recv_seq |= num; 340226031Sstas /* protocol */ 341226031Sstas ret = krb5_ret_uint32(sp, &ctx->protocol); 342226031Sstas if (ret) goto out; 343226031Sstas if (ctx->protocol == 0) { 344226031Sstas krb5_keyblock key; 345226031Sstas 346226031Sstas /* sign_alg */ 347226031Sstas ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); 348226031Sstas if (ret) goto out; 349226031Sstas /* seal_alg */ 350226031Sstas ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); 351226031Sstas if (ret) goto out; 352226031Sstas /* ctx_key */ 353226031Sstas ret = krb5_ret_keyblock(sp, &key); 354226031Sstas if (ret) goto out; 355226031Sstas ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); 356226031Sstas krb5_free_keyblock_contents(context, &key); 357226031Sstas if (ret) goto out; 358226031Sstas } else if (ctx->protocol == 1) { 359226031Sstas krb5_keyblock key; 360226031Sstas 361226031Sstas /* acceptor_subkey */ 362226031Sstas ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); 363226031Sstas if (ret) goto out; 364226031Sstas /* ctx_key */ 365226031Sstas ret = krb5_ret_keyblock(sp, &key); 366226031Sstas if (ret) goto out; 367226031Sstas ret = set_key(&key, &ctx->cfx_kd.ctx_key); 368226031Sstas krb5_free_keyblock_contents(context, &key); 369226031Sstas if (ret) goto out; 370226031Sstas /* acceptor_subkey */ 371226031Sstas if (ctx->cfx_kd.have_acceptor_subkey) { 372226031Sstas ret = krb5_ret_keyblock(sp, &key); 373226031Sstas if (ret) goto out; 374226031Sstas ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); 375226031Sstas krb5_free_keyblock_contents(context, &key); 376226031Sstas if (ret) goto out; 377226031Sstas } 378226031Sstas } else { 379226031Sstas ret = EINVAL; 380226031Sstas goto out; 381226031Sstas } 382226031Sstas 383226031Sstas *rctx = ctx; 384226031Sstas 385226031Sstasout: 386226031Sstas gss_release_buffer_set(minor_status, &data_set); 387226031Sstas if (sp) 388226031Sstas krb5_storage_free(sp); 389226031Sstas if (context) 390226031Sstas krb5_free_context(context); 391226031Sstas 392226031Sstas if (ret) { 393226031Sstas if (ctx) 394226031Sstas gss_krb5_free_lucid_sec_context(NULL, ctx); 395226031Sstas 396226031Sstas *minor_status = ret; 397226031Sstas return GSS_S_FAILURE; 398226031Sstas } 399226031Sstas *minor_status = 0; 400226031Sstas return GSS_S_COMPLETE; 401226031Sstas} 402226031Sstas 403226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 404226031Sstasgss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c) 405226031Sstas{ 406226031Sstas gss_krb5_lucid_context_v1_t *ctx = c; 407226031Sstas 408226031Sstas if (ctx->version != 1) { 409226031Sstas if (minor_status) 410226031Sstas *minor_status = 0; 411226031Sstas return GSS_S_FAILURE; 412226031Sstas } 413226031Sstas 414226031Sstas if (ctx->protocol == 0) { 415226031Sstas free_key(&ctx->rfc1964_kd.ctx_key); 416226031Sstas } else if (ctx->protocol == 1) { 417226031Sstas free_key(&ctx->cfx_kd.ctx_key); 418226031Sstas if (ctx->cfx_kd.have_acceptor_subkey) 419226031Sstas free_key(&ctx->cfx_kd.acceptor_subkey); 420226031Sstas } 421226031Sstas free(ctx); 422226031Sstas if (minor_status) 423226031Sstas *minor_status = 0; 424226031Sstas return GSS_S_COMPLETE; 425226031Sstas} 426226031Sstas 427226031Sstas/* 428226031Sstas * 429226031Sstas */ 430226031Sstas 431226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 432226031Sstasgss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 433226031Sstas gss_cred_id_t cred, 434226031Sstas OM_uint32 num_enctypes, 435226031Sstas int32_t *enctypes) 436226031Sstas{ 437226031Sstas krb5_error_code ret; 438226031Sstas OM_uint32 maj_status; 439226031Sstas gss_buffer_desc buffer; 440226031Sstas krb5_storage *sp; 441226031Sstas krb5_data data; 442226031Sstas size_t i; 443226031Sstas 444226031Sstas sp = krb5_storage_emem(); 445226031Sstas if (sp == NULL) { 446226031Sstas *minor_status = ENOMEM; 447226031Sstas maj_status = GSS_S_FAILURE; 448226031Sstas goto out; 449226031Sstas } 450226031Sstas 451226031Sstas for (i = 0; i < num_enctypes; i++) { 452226031Sstas ret = krb5_store_int32(sp, enctypes[i]); 453226031Sstas if (ret) { 454226031Sstas *minor_status = ret; 455226031Sstas maj_status = GSS_S_FAILURE; 456226031Sstas goto out; 457226031Sstas } 458226031Sstas } 459226031Sstas 460226031Sstas ret = krb5_storage_to_data(sp, &data); 461226031Sstas if (ret) { 462226031Sstas *minor_status = ret; 463226031Sstas maj_status = GSS_S_FAILURE; 464226031Sstas goto out; 465226031Sstas } 466226031Sstas 467226031Sstas buffer.value = data.data; 468226031Sstas buffer.length = data.length; 469226031Sstas 470226031Sstas maj_status = gss_set_cred_option(minor_status, 471226031Sstas &cred, 472226031Sstas GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, 473226031Sstas &buffer); 474226031Sstas krb5_data_free(&data); 475226031Sstasout: 476226031Sstas if (sp) 477226031Sstas krb5_storage_free(sp); 478226031Sstas return maj_status; 479226031Sstas} 480226031Sstas 481226031Sstas/* 482226031Sstas * 483226031Sstas */ 484226031Sstas 485226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 486226031Sstasgsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c) 487226031Sstas{ 488226031Sstas struct _gss_mech_switch *m; 489226031Sstas gss_buffer_desc buffer; 490226031Sstas OM_uint32 junk; 491226031Sstas 492226031Sstas _gss_load_mech(); 493226031Sstas 494226031Sstas if (c) { 495226031Sstas buffer.value = c; 496226031Sstas buffer.length = sizeof(*c); 497226031Sstas } else { 498226031Sstas buffer.value = NULL; 499226031Sstas buffer.length = 0; 500226031Sstas } 501226031Sstas 502226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 503226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 504226031Sstas continue; 505226031Sstas m->gm_mech.gm_set_sec_context_option(&junk, NULL, 506226031Sstas GSS_KRB5_SEND_TO_KDC_X, &buffer); 507226031Sstas } 508226031Sstas 509226031Sstas return (GSS_S_COMPLETE); 510226031Sstas} 511226031Sstas 512226031Sstas/* 513226031Sstas * 514226031Sstas */ 515226031Sstas 516226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 517226031Sstasgss_krb5_ccache_name(OM_uint32 *minor_status, 518226031Sstas const char *name, 519226031Sstas const char **out_name) 520226031Sstas{ 521226031Sstas struct _gss_mech_switch *m; 522226031Sstas gss_buffer_desc buffer; 523226031Sstas OM_uint32 junk; 524226031Sstas 525226031Sstas _gss_load_mech(); 526226031Sstas 527226031Sstas if (out_name) 528226031Sstas *out_name = NULL; 529226031Sstas 530226031Sstas buffer.value = rk_UNCONST(name); 531226031Sstas buffer.length = strlen(name); 532226031Sstas 533226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 534226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 535226031Sstas continue; 536226031Sstas m->gm_mech.gm_set_sec_context_option(&junk, NULL, 537226031Sstas GSS_KRB5_CCACHE_NAME_X, &buffer); 538226031Sstas } 539226031Sstas 540226031Sstas return (GSS_S_COMPLETE); 541226031Sstas} 542226031Sstas 543226031Sstas 544226031Sstas/* 545226031Sstas * 546226031Sstas */ 547226031Sstas 548226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 549226031Sstasgsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, 550226031Sstas gss_ctx_id_t context_handle, 551226031Sstas time_t *authtime) 552226031Sstas{ 553226031Sstas gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 554226031Sstas OM_uint32 maj_stat; 555226031Sstas 556226031Sstas if (context_handle == GSS_C_NO_CONTEXT) { 557226031Sstas *minor_status = EINVAL; 558226031Sstas return GSS_S_FAILURE; 559226031Sstas } 560226031Sstas 561226031Sstas maj_stat = 562226031Sstas gss_inquire_sec_context_by_oid (minor_status, 563226031Sstas context_handle, 564226031Sstas GSS_KRB5_GET_AUTHTIME_X, 565226031Sstas &data_set); 566226031Sstas if (maj_stat) 567226031Sstas return maj_stat; 568226031Sstas 569226031Sstas if (data_set == GSS_C_NO_BUFFER_SET) { 570226031Sstas gss_release_buffer_set(minor_status, &data_set); 571226031Sstas *minor_status = EINVAL; 572226031Sstas return GSS_S_FAILURE; 573226031Sstas } 574226031Sstas 575226031Sstas if (data_set->count != 1) { 576226031Sstas gss_release_buffer_set(minor_status, &data_set); 577226031Sstas *minor_status = EINVAL; 578226031Sstas return GSS_S_FAILURE; 579226031Sstas } 580226031Sstas 581226031Sstas if (data_set->elements[0].length != 4) { 582226031Sstas gss_release_buffer_set(minor_status, &data_set); 583226031Sstas *minor_status = EINVAL; 584226031Sstas return GSS_S_FAILURE; 585226031Sstas } 586226031Sstas 587226031Sstas { 588226031Sstas unsigned char *buf = data_set->elements[0].value; 589226031Sstas *authtime = (buf[3] <<24) | (buf[2] << 16) | 590226031Sstas (buf[1] << 8) | (buf[0] << 0); 591226031Sstas } 592226031Sstas 593226031Sstas gss_release_buffer_set(minor_status, &data_set); 594226031Sstas 595226031Sstas *minor_status = 0; 596226031Sstas return GSS_S_COMPLETE; 597226031Sstas} 598226031Sstas 599226031Sstas/* 600226031Sstas * 601226031Sstas */ 602226031Sstas 603226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 604226031Sstasgsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, 605226031Sstas gss_ctx_id_t context_handle, 606226031Sstas int ad_type, 607226031Sstas gss_buffer_t ad_data) 608226031Sstas{ 609226031Sstas gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 610226031Sstas OM_uint32 maj_stat; 611226031Sstas gss_OID_desc oid_flat; 612226031Sstas heim_oid baseoid, oid; 613226031Sstas size_t size; 614226031Sstas 615226031Sstas if (context_handle == GSS_C_NO_CONTEXT) { 616226031Sstas *minor_status = EINVAL; 617226031Sstas return GSS_S_FAILURE; 618226031Sstas } 619226031Sstas 620226031Sstas /* All this to append an integer to an oid... */ 621226031Sstas 622226031Sstas if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, 623226031Sstas GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, 624226031Sstas &baseoid, NULL) != 0) { 625226031Sstas *minor_status = EINVAL; 626226031Sstas return GSS_S_FAILURE; 627226031Sstas } 628226031Sstas 629226031Sstas oid.length = baseoid.length + 1; 630226031Sstas oid.components = calloc(oid.length, sizeof(*oid.components)); 631226031Sstas if (oid.components == NULL) { 632226031Sstas der_free_oid(&baseoid); 633226031Sstas 634226031Sstas *minor_status = ENOMEM; 635226031Sstas return GSS_S_FAILURE; 636226031Sstas } 637226031Sstas 638226031Sstas memcpy(oid.components, baseoid.components, 639226031Sstas baseoid.length * sizeof(*baseoid.components)); 640226031Sstas 641226031Sstas der_free_oid(&baseoid); 642226031Sstas 643226031Sstas oid.components[oid.length - 1] = ad_type; 644226031Sstas 645226031Sstas oid_flat.length = der_length_oid(&oid); 646226031Sstas oid_flat.elements = malloc(oid_flat.length); 647226031Sstas if (oid_flat.elements == NULL) { 648226031Sstas free(oid.components); 649226031Sstas *minor_status = ENOMEM; 650226031Sstas return GSS_S_FAILURE; 651226031Sstas } 652226031Sstas 653226031Sstas if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 654226031Sstas oid_flat.length, &oid, &size) != 0) { 655226031Sstas free(oid.components); 656226031Sstas free(oid_flat.elements); 657226031Sstas *minor_status = EINVAL; 658226031Sstas return GSS_S_FAILURE; 659226031Sstas } 660226031Sstas if (oid_flat.length != size) 661226031Sstas abort(); 662226031Sstas 663226031Sstas free(oid.components); 664226031Sstas 665226031Sstas /* FINALLY, we have the OID */ 666226031Sstas 667226031Sstas maj_stat = gss_inquire_sec_context_by_oid (minor_status, 668226031Sstas context_handle, 669226031Sstas &oid_flat, 670226031Sstas &data_set); 671226031Sstas 672226031Sstas free(oid_flat.elements); 673226031Sstas 674226031Sstas if (maj_stat) 675226031Sstas return maj_stat; 676226031Sstas 677226031Sstas if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 678226031Sstas gss_release_buffer_set(minor_status, &data_set); 679226031Sstas *minor_status = EINVAL; 680226031Sstas return GSS_S_FAILURE; 681226031Sstas } 682226031Sstas 683226031Sstas ad_data->value = malloc(data_set->elements[0].length); 684226031Sstas if (ad_data->value == NULL) { 685226031Sstas gss_release_buffer_set(minor_status, &data_set); 686226031Sstas *minor_status = ENOMEM; 687226031Sstas return GSS_S_FAILURE; 688226031Sstas } 689226031Sstas 690226031Sstas ad_data->length = data_set->elements[0].length; 691226031Sstas memcpy(ad_data->value, data_set->elements[0].value, ad_data->length); 692226031Sstas gss_release_buffer_set(minor_status, &data_set); 693226031Sstas 694226031Sstas *minor_status = 0; 695226031Sstas return GSS_S_COMPLETE; 696226031Sstas} 697226031Sstas 698226031Sstas/* 699226031Sstas * 700226031Sstas */ 701226031Sstas 702226031Sstasstatic OM_uint32 703226031Sstasgsskrb5_extract_key(OM_uint32 *minor_status, 704226031Sstas gss_ctx_id_t context_handle, 705226031Sstas const gss_OID oid, 706226031Sstas krb5_keyblock **keyblock) 707226031Sstas{ 708226031Sstas krb5_error_code ret; 709226031Sstas gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 710226031Sstas OM_uint32 major_status; 711226031Sstas krb5_context context = NULL; 712226031Sstas krb5_storage *sp = NULL; 713226031Sstas 714226031Sstas if (context_handle == GSS_C_NO_CONTEXT) { 715226031Sstas *minor_status = EINVAL; 716226031Sstas return GSS_S_FAILURE; 717226031Sstas } 718226031Sstas 719226031Sstas ret = krb5_init_context(&context); 720226031Sstas if(ret) { 721226031Sstas *minor_status = ret; 722226031Sstas return GSS_S_FAILURE; 723226031Sstas } 724226031Sstas 725226031Sstas major_status = 726226031Sstas gss_inquire_sec_context_by_oid (minor_status, 727226031Sstas context_handle, 728226031Sstas oid, 729226031Sstas &data_set); 730226031Sstas if (major_status) 731226031Sstas return major_status; 732226031Sstas 733226031Sstas if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 734226031Sstas gss_release_buffer_set(minor_status, &data_set); 735226031Sstas *minor_status = EINVAL; 736226031Sstas return GSS_S_FAILURE; 737226031Sstas } 738226031Sstas 739226031Sstas sp = krb5_storage_from_mem(data_set->elements[0].value, 740226031Sstas data_set->elements[0].length); 741226031Sstas if (sp == NULL) { 742226031Sstas ret = ENOMEM; 743226031Sstas goto out; 744226031Sstas } 745226031Sstas 746226031Sstas *keyblock = calloc(1, sizeof(**keyblock)); 747226031Sstas if (keyblock == NULL) { 748226031Sstas ret = ENOMEM; 749226031Sstas goto out; 750226031Sstas } 751226031Sstas 752226031Sstas ret = krb5_ret_keyblock(sp, *keyblock); 753226031Sstas 754226031Sstasout: 755226031Sstas gss_release_buffer_set(minor_status, &data_set); 756226031Sstas if (sp) 757226031Sstas krb5_storage_free(sp); 758226031Sstas if (ret && keyblock) { 759226031Sstas krb5_free_keyblock(context, *keyblock); 760226031Sstas *keyblock = NULL; 761226031Sstas } 762226031Sstas if (context) 763226031Sstas krb5_free_context(context); 764226031Sstas 765226031Sstas *minor_status = ret; 766226031Sstas if (ret) 767226031Sstas return GSS_S_FAILURE; 768226031Sstas 769226031Sstas return GSS_S_COMPLETE; 770226031Sstas} 771226031Sstas 772226031Sstas/* 773226031Sstas * 774226031Sstas */ 775226031Sstas 776226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 777226031Sstasgsskrb5_extract_service_keyblock(OM_uint32 *minor_status, 778226031Sstas gss_ctx_id_t context_handle, 779226031Sstas krb5_keyblock **keyblock) 780226031Sstas{ 781226031Sstas return gsskrb5_extract_key(minor_status, 782226031Sstas context_handle, 783226031Sstas GSS_KRB5_GET_SERVICE_KEYBLOCK_X, 784226031Sstas keyblock); 785226031Sstas} 786226031Sstas 787226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 788226031Sstasgsskrb5_get_initiator_subkey(OM_uint32 *minor_status, 789226031Sstas gss_ctx_id_t context_handle, 790226031Sstas krb5_keyblock **keyblock) 791226031Sstas{ 792226031Sstas return gsskrb5_extract_key(minor_status, 793226031Sstas context_handle, 794226031Sstas GSS_KRB5_GET_INITIATOR_SUBKEY_X, 795226031Sstas keyblock); 796226031Sstas} 797226031Sstas 798226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 799226031Sstasgsskrb5_get_subkey(OM_uint32 *minor_status, 800226031Sstas gss_ctx_id_t context_handle, 801226031Sstas krb5_keyblock **keyblock) 802226031Sstas{ 803226031Sstas return gsskrb5_extract_key(minor_status, 804226031Sstas context_handle, 805226031Sstas GSS_KRB5_GET_SUBKEY_X, 806226031Sstas keyblock); 807226031Sstas} 808226031Sstas 809226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 810226031Sstasgsskrb5_set_default_realm(const char *realm) 811226031Sstas{ 812226031Sstas struct _gss_mech_switch *m; 813226031Sstas gss_buffer_desc buffer; 814226031Sstas OM_uint32 junk; 815226031Sstas 816226031Sstas _gss_load_mech(); 817226031Sstas 818226031Sstas buffer.value = rk_UNCONST(realm); 819226031Sstas buffer.length = strlen(realm); 820226031Sstas 821226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 822226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 823226031Sstas continue; 824226031Sstas m->gm_mech.gm_set_sec_context_option(&junk, NULL, 825226031Sstas GSS_KRB5_SET_DEFAULT_REALM_X, &buffer); 826226031Sstas } 827226031Sstas 828226031Sstas return (GSS_S_COMPLETE); 829226031Sstas} 830226031Sstas 831226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 832226031Sstasgss_krb5_get_tkt_flags(OM_uint32 *minor_status, 833226031Sstas gss_ctx_id_t context_handle, 834226031Sstas OM_uint32 *tkt_flags) 835226031Sstas{ 836226031Sstas 837226031Sstas OM_uint32 major_status; 838226031Sstas gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 839226031Sstas 840226031Sstas if (context_handle == GSS_C_NO_CONTEXT) { 841226031Sstas *minor_status = EINVAL; 842226031Sstas return GSS_S_FAILURE; 843226031Sstas } 844226031Sstas 845226031Sstas major_status = 846226031Sstas gss_inquire_sec_context_by_oid (minor_status, 847226031Sstas context_handle, 848226031Sstas GSS_KRB5_GET_TKT_FLAGS_X, 849226031Sstas &data_set); 850226031Sstas if (major_status) 851226031Sstas return major_status; 852226031Sstas 853226031Sstas if (data_set == GSS_C_NO_BUFFER_SET || 854226031Sstas data_set->count != 1 || 855226031Sstas data_set->elements[0].length < 4) { 856226031Sstas gss_release_buffer_set(minor_status, &data_set); 857226031Sstas *minor_status = EINVAL; 858226031Sstas return GSS_S_FAILURE; 859226031Sstas } 860226031Sstas 861226031Sstas { 862226031Sstas const u_char *p = data_set->elements[0].value; 863226031Sstas *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 864226031Sstas } 865226031Sstas 866226031Sstas gss_release_buffer_set(minor_status, &data_set); 867226031Sstas return GSS_S_COMPLETE; 868226031Sstas} 869226031Sstas 870226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 871226031Sstasgsskrb5_set_time_offset(int offset) 872226031Sstas{ 873226031Sstas struct _gss_mech_switch *m; 874226031Sstas gss_buffer_desc buffer; 875226031Sstas OM_uint32 junk; 876226031Sstas int32_t o = offset; 877226031Sstas 878226031Sstas _gss_load_mech(); 879226031Sstas 880226031Sstas buffer.value = &o; 881226031Sstas buffer.length = sizeof(o); 882226031Sstas 883226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 884226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 885226031Sstas continue; 886226031Sstas m->gm_mech.gm_set_sec_context_option(&junk, NULL, 887226031Sstas GSS_KRB5_SET_TIME_OFFSET_X, &buffer); 888226031Sstas } 889226031Sstas 890226031Sstas return (GSS_S_COMPLETE); 891226031Sstas} 892226031Sstas 893226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 894226031Sstasgsskrb5_get_time_offset(int *offset) 895226031Sstas{ 896226031Sstas struct _gss_mech_switch *m; 897226031Sstas gss_buffer_desc buffer; 898226031Sstas OM_uint32 maj_stat, junk; 899226031Sstas int32_t o; 900226031Sstas 901226031Sstas _gss_load_mech(); 902226031Sstas 903226031Sstas buffer.value = &o; 904226031Sstas buffer.length = sizeof(o); 905226031Sstas 906226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 907226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 908226031Sstas continue; 909226031Sstas maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL, 910226031Sstas GSS_KRB5_GET_TIME_OFFSET_X, &buffer); 911226031Sstas 912226031Sstas if (maj_stat == GSS_S_COMPLETE) { 913226031Sstas *offset = o; 914226031Sstas return maj_stat; 915226031Sstas } 916226031Sstas } 917226031Sstas 918226031Sstas return (GSS_S_UNAVAILABLE); 919226031Sstas} 920226031Sstas 921226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 922226031Sstasgsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c) 923226031Sstas{ 924226031Sstas struct _gss_mech_switch *m; 925226031Sstas gss_buffer_desc buffer; 926226031Sstas OM_uint32 junk; 927226031Sstas 928226031Sstas _gss_load_mech(); 929226031Sstas 930226031Sstas buffer.value = c; 931226031Sstas buffer.length = sizeof(*c); 932226031Sstas 933226031Sstas HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 934226031Sstas if (m->gm_mech.gm_set_sec_context_option == NULL) 935226031Sstas continue; 936226031Sstas m->gm_mech.gm_set_sec_context_option(&junk, NULL, 937226031Sstas GSS_KRB5_PLUGIN_REGISTER_X, &buffer); 938226031Sstas } 939226031Sstas 940226031Sstas return (GSS_S_COMPLETE); 941226031Sstas} 942