gss_krb5.c revision 330449
1178828Sdfr/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4178828Sdfr * Copyright (c) 2005 Doug Rabson 5178828Sdfr * All rights reserved. 6178828Sdfr * 7178828Sdfr * Redistribution and use in source and binary forms, with or without 8178828Sdfr * modification, are permitted provided that the following conditions 9178828Sdfr * are met: 10178828Sdfr * 1. Redistributions of source code must retain the above copyright 11178828Sdfr * notice, this list of conditions and the following disclaimer. 12178828Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13178828Sdfr * notice, this list of conditions and the following disclaimer in the 14178828Sdfr * documentation and/or other materials provided with the distribution. 15178828Sdfr * 16178828Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17178828Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18178828Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19178828Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20178828Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21178828Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22178828Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23178828Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24178828Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25178828Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26178828Sdfr * SUCH DAMAGE. 27178828Sdfr * 28178828Sdfr * $FreeBSD: stable/11/kerberos5/lib/libgssapi_krb5/gss_krb5.c 330449 2018-03-05 07:26:05Z eadler $ 29178828Sdfr */ 30178828Sdfr 31178828Sdfr#include <gssapi/gssapi.h> 32178828Sdfr#include <gssapi/gssapi_krb5.h> 33178828Sdfr 34178828Sdfr/* RCSID("$Id: gss_krb5.c 21889 2007-08-09 07:43:24Z lha $"); */ 35178828Sdfr 36178828Sdfr#include <krb5.h> 37178828Sdfr#include <roken.h> 38233294Sstas#include <der.h> 39178828Sdfr 40178828SdfrOM_uint32 41178828Sdfrgss_krb5_copy_ccache(OM_uint32 *minor_status, 42178828Sdfr gss_cred_id_t cred, 43178828Sdfr krb5_ccache out) 44178828Sdfr{ 45178828Sdfr gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 46178828Sdfr krb5_context context; 47178828Sdfr krb5_error_code kret; 48178828Sdfr krb5_ccache id; 49178828Sdfr OM_uint32 ret; 50178828Sdfr char *str; 51178828Sdfr 52178828Sdfr ret = gss_inquire_cred_by_oid(minor_status, 53178828Sdfr cred, 54178828Sdfr GSS_KRB5_COPY_CCACHE_X, 55178828Sdfr &data_set); 56178828Sdfr if (ret) 57178828Sdfr return ret; 58178828Sdfr 59178828Sdfr if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 60178828Sdfr gss_release_buffer_set(minor_status, &data_set); 61178828Sdfr *minor_status = EINVAL; 62178828Sdfr return GSS_S_FAILURE; 63178828Sdfr } 64178828Sdfr 65178828Sdfr kret = krb5_init_context(&context); 66178828Sdfr if (kret) { 67178828Sdfr *minor_status = kret; 68178828Sdfr gss_release_buffer_set(minor_status, &data_set); 69178828Sdfr return GSS_S_FAILURE; 70178828Sdfr } 71178828Sdfr 72178828Sdfr kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length, 73178828Sdfr (char *)data_set->elements[0].value); 74178828Sdfr gss_release_buffer_set(minor_status, &data_set); 75178828Sdfr if (kret == -1) { 76178828Sdfr *minor_status = ENOMEM; 77178828Sdfr return GSS_S_FAILURE; 78178828Sdfr } 79178828Sdfr 80178828Sdfr kret = krb5_cc_resolve(context, str, &id); 81178828Sdfr free(str); 82178828Sdfr if (kret) { 83178828Sdfr *minor_status = kret; 84178828Sdfr return GSS_S_FAILURE; 85178828Sdfr } 86178828Sdfr 87178828Sdfr kret = krb5_cc_copy_cache(context, id, out); 88178828Sdfr krb5_cc_close(context, id); 89178828Sdfr krb5_free_context(context); 90178828Sdfr if (kret) { 91178828Sdfr *minor_status = kret; 92178828Sdfr return GSS_S_FAILURE; 93178828Sdfr } 94178828Sdfr 95178828Sdfr return ret; 96178828Sdfr} 97178828Sdfr 98178828SdfrOM_uint32 99178828Sdfrgss_krb5_import_cred(OM_uint32 *minor_status, 100178828Sdfr krb5_ccache id, 101178828Sdfr krb5_principal keytab_principal, 102178828Sdfr krb5_keytab keytab, 103178828Sdfr gss_cred_id_t *cred) 104178828Sdfr{ 105178828Sdfr gss_buffer_desc buffer; 106178828Sdfr OM_uint32 major_status; 107178828Sdfr krb5_context context; 108178828Sdfr krb5_error_code ret; 109178828Sdfr krb5_storage *sp; 110178828Sdfr krb5_data data; 111178828Sdfr char *str; 112178828Sdfr 113178828Sdfr *cred = GSS_C_NO_CREDENTIAL; 114178828Sdfr 115178828Sdfr ret = krb5_init_context(&context); 116178828Sdfr if (ret) { 117178828Sdfr *minor_status = ret; 118178828Sdfr return GSS_S_FAILURE; 119178828Sdfr } 120178828Sdfr 121178828Sdfr sp = krb5_storage_emem(); 122178828Sdfr if (sp == NULL) { 123178828Sdfr *minor_status = ENOMEM; 124178828Sdfr major_status = GSS_S_FAILURE; 125178828Sdfr goto out; 126178828Sdfr } 127178828Sdfr 128178828Sdfr if (id) { 129178828Sdfr ret = krb5_cc_get_full_name(context, id, &str); 130178828Sdfr if (ret == 0) { 131178828Sdfr ret = krb5_store_string(sp, str); 132178828Sdfr free(str); 133178828Sdfr } 134178828Sdfr } else 135178828Sdfr ret = krb5_store_string(sp, ""); 136178828Sdfr if (ret) { 137178828Sdfr *minor_status = ret; 138178828Sdfr major_status = GSS_S_FAILURE; 139178828Sdfr goto out; 140178828Sdfr } 141178828Sdfr 142178828Sdfr if (keytab_principal) { 143178828Sdfr ret = krb5_unparse_name(context, keytab_principal, &str); 144178828Sdfr if (ret == 0) { 145178828Sdfr ret = krb5_store_string(sp, str); 146178828Sdfr free(str); 147178828Sdfr } 148178828Sdfr } else 149178828Sdfr krb5_store_string(sp, ""); 150178828Sdfr if (ret) { 151178828Sdfr *minor_status = ret; 152178828Sdfr major_status = GSS_S_FAILURE; 153178828Sdfr goto out; 154178828Sdfr } 155178828Sdfr 156178828Sdfr 157178828Sdfr if (keytab) { 158178828Sdfr ret = krb5_kt_get_full_name(context, keytab, &str); 159178828Sdfr if (ret == 0) { 160178828Sdfr ret = krb5_store_string(sp, str); 161178828Sdfr free(str); 162178828Sdfr } 163178828Sdfr } else 164178828Sdfr krb5_store_string(sp, ""); 165178828Sdfr if (ret) { 166178828Sdfr *minor_status = ret; 167178828Sdfr major_status = GSS_S_FAILURE; 168178828Sdfr goto out; 169178828Sdfr } 170178828Sdfr 171178828Sdfr ret = krb5_storage_to_data(sp, &data); 172178828Sdfr if (ret) { 173178828Sdfr *minor_status = ret; 174178828Sdfr major_status = GSS_S_FAILURE; 175178828Sdfr goto out; 176178828Sdfr } 177178828Sdfr 178178828Sdfr buffer.value = data.data; 179178828Sdfr buffer.length = data.length; 180178828Sdfr 181178828Sdfr major_status = gss_set_cred_option(minor_status, 182178828Sdfr cred, 183178828Sdfr GSS_KRB5_IMPORT_CRED_X, 184178828Sdfr &buffer); 185178828Sdfr krb5_data_free(&data); 186178828Sdfrout: 187178828Sdfr if (sp) 188178828Sdfr krb5_storage_free(sp); 189178828Sdfr krb5_free_context(context); 190178828Sdfr return major_status; 191178828Sdfr} 192178828Sdfr 193178828SdfrOM_uint32 194178828Sdfrgsskrb5_register_acceptor_identity(const char *identity) 195178828Sdfr{ 196178828Sdfr gss_buffer_desc buffer; 197178828Sdfr OM_uint32 junk; 198178828Sdfr 199178828Sdfr buffer.value = rk_UNCONST(identity); 200178828Sdfr buffer.length = strlen(identity); 201178828Sdfr 202178828Sdfr gss_set_sec_context_option(&junk, NULL, 203178828Sdfr GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer); 204178828Sdfr 205178828Sdfr return (GSS_S_COMPLETE); 206178828Sdfr} 207178828Sdfr 208178828SdfrOM_uint32 209178828Sdfrgsskrb5_set_dns_canonicalize(int flag) 210178828Sdfr{ 211178828Sdfr gss_buffer_desc buffer; 212178828Sdfr OM_uint32 junk; 213178828Sdfr char b = (flag != 0); 214178828Sdfr 215178828Sdfr buffer.value = &b; 216178828Sdfr buffer.length = sizeof(b); 217178828Sdfr 218178828Sdfr gss_set_sec_context_option(&junk, NULL, 219178828Sdfr GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer); 220178828Sdfr 221178828Sdfr return (GSS_S_COMPLETE); 222178828Sdfr} 223178828Sdfr 224178828Sdfr 225178828Sdfr 226178828Sdfrstatic krb5_error_code 227178828Sdfrset_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key) 228178828Sdfr{ 229178828Sdfr key->type = keyblock->keytype; 230178828Sdfr key->length = keyblock->keyvalue.length; 231178828Sdfr key->data = malloc(key->length); 232178828Sdfr if (key->data == NULL && key->length != 0) 233178828Sdfr return ENOMEM; 234178828Sdfr memcpy(key->data, keyblock->keyvalue.data, key->length); 235178828Sdfr return 0; 236178828Sdfr} 237178828Sdfr 238178828Sdfrstatic void 239178828Sdfrfree_key(gss_krb5_lucid_key_t *key) 240178828Sdfr{ 241178828Sdfr memset(key->data, 0, key->length); 242178828Sdfr free(key->data); 243178828Sdfr memset(key, 0, sizeof(*key)); 244178828Sdfr} 245178828Sdfr 246178828SdfrOM_uint32 247178828Sdfrgss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, 248178828Sdfr gss_ctx_id_t *context_handle, 249178828Sdfr OM_uint32 version, 250178828Sdfr void **rctx) 251178828Sdfr{ 252178828Sdfr krb5_context context = NULL; 253178828Sdfr krb5_error_code ret; 254178828Sdfr gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 255178828Sdfr OM_uint32 major_status; 256178828Sdfr gss_krb5_lucid_context_v1_t *ctx = NULL; 257178828Sdfr krb5_storage *sp = NULL; 258178828Sdfr uint32_t num; 259178828Sdfr 260178828Sdfr if (context_handle == NULL 261178828Sdfr || *context_handle == GSS_C_NO_CONTEXT 262178828Sdfr || version != 1) 263178828Sdfr { 264178828Sdfr ret = EINVAL; 265178828Sdfr return GSS_S_FAILURE; 266178828Sdfr } 267178828Sdfr 268178828Sdfr major_status = 269178828Sdfr gss_inquire_sec_context_by_oid (minor_status, 270178828Sdfr *context_handle, 271178828Sdfr GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, 272178828Sdfr &data_set); 273178828Sdfr if (major_status) 274178828Sdfr return major_status; 275178828Sdfr 276178828Sdfr if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 277178828Sdfr gss_release_buffer_set(minor_status, &data_set); 278178828Sdfr *minor_status = EINVAL; 279178828Sdfr return GSS_S_FAILURE; 280178828Sdfr } 281178828Sdfr 282178828Sdfr ret = krb5_init_context(&context); 283178828Sdfr if (ret) 284178828Sdfr goto out; 285178828Sdfr 286178828Sdfr ctx = calloc(1, sizeof(*ctx)); 287178828Sdfr if (ctx == NULL) { 288178828Sdfr ret = ENOMEM; 289178828Sdfr goto out; 290178828Sdfr } 291178828Sdfr 292178828Sdfr sp = krb5_storage_from_mem(data_set->elements[0].value, 293178828Sdfr data_set->elements[0].length); 294178828Sdfr if (sp == NULL) { 295178828Sdfr ret = ENOMEM; 296178828Sdfr goto out; 297178828Sdfr } 298178828Sdfr 299178828Sdfr ret = krb5_ret_uint32(sp, &num); 300178828Sdfr if (ret) goto out; 301178828Sdfr if (num != 1) { 302178828Sdfr ret = EINVAL; 303178828Sdfr goto out; 304178828Sdfr } 305178828Sdfr ctx->version = 1; 306178828Sdfr /* initiator */ 307178828Sdfr ret = krb5_ret_uint32(sp, &ctx->initiate); 308178828Sdfr if (ret) goto out; 309178828Sdfr /* endtime */ 310178828Sdfr ret = krb5_ret_uint32(sp, &ctx->endtime); 311178828Sdfr if (ret) goto out; 312178828Sdfr /* send_seq */ 313178828Sdfr ret = krb5_ret_uint32(sp, &num); 314178828Sdfr if (ret) goto out; 315178828Sdfr ctx->send_seq = ((uint64_t)num) << 32; 316178828Sdfr ret = krb5_ret_uint32(sp, &num); 317178828Sdfr if (ret) goto out; 318178828Sdfr ctx->send_seq |= num; 319178828Sdfr /* recv_seq */ 320178828Sdfr ret = krb5_ret_uint32(sp, &num); 321178828Sdfr if (ret) goto out; 322178828Sdfr ctx->recv_seq = ((uint64_t)num) << 32; 323178828Sdfr ret = krb5_ret_uint32(sp, &num); 324178828Sdfr if (ret) goto out; 325178828Sdfr ctx->recv_seq |= num; 326178828Sdfr /* protocol */ 327178828Sdfr ret = krb5_ret_uint32(sp, &ctx->protocol); 328178828Sdfr if (ret) goto out; 329178828Sdfr if (ctx->protocol == 0) { 330178828Sdfr krb5_keyblock key; 331178828Sdfr 332178828Sdfr /* sign_alg */ 333178828Sdfr ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); 334178828Sdfr if (ret) goto out; 335178828Sdfr /* seal_alg */ 336178828Sdfr ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); 337178828Sdfr if (ret) goto out; 338178828Sdfr /* ctx_key */ 339178828Sdfr ret = krb5_ret_keyblock(sp, &key); 340178828Sdfr if (ret) goto out; 341178828Sdfr ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); 342178828Sdfr krb5_free_keyblock_contents(context, &key); 343178828Sdfr if (ret) goto out; 344178828Sdfr } else if (ctx->protocol == 1) { 345178828Sdfr krb5_keyblock key; 346178828Sdfr 347178828Sdfr /* acceptor_subkey */ 348178828Sdfr ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); 349178828Sdfr if (ret) goto out; 350178828Sdfr /* ctx_key */ 351178828Sdfr ret = krb5_ret_keyblock(sp, &key); 352178828Sdfr if (ret) goto out; 353178828Sdfr ret = set_key(&key, &ctx->cfx_kd.ctx_key); 354178828Sdfr krb5_free_keyblock_contents(context, &key); 355178828Sdfr if (ret) goto out; 356178828Sdfr /* acceptor_subkey */ 357178828Sdfr if (ctx->cfx_kd.have_acceptor_subkey) { 358178828Sdfr ret = krb5_ret_keyblock(sp, &key); 359178828Sdfr if (ret) goto out; 360178828Sdfr ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); 361178828Sdfr krb5_free_keyblock_contents(context, &key); 362178828Sdfr if (ret) goto out; 363178828Sdfr } 364178828Sdfr } else { 365178828Sdfr ret = EINVAL; 366178828Sdfr goto out; 367178828Sdfr } 368178828Sdfr 369178828Sdfr *rctx = ctx; 370178828Sdfr 371178828Sdfrout: 372178828Sdfr gss_release_buffer_set(minor_status, &data_set); 373178828Sdfr if (sp) 374178828Sdfr krb5_storage_free(sp); 375178828Sdfr if (context) 376178828Sdfr krb5_free_context(context); 377178828Sdfr 378178828Sdfr if (ret) { 379178828Sdfr if (ctx) 380178828Sdfr gss_krb5_free_lucid_sec_context(NULL, ctx); 381178828Sdfr 382178828Sdfr *minor_status = ret; 383178828Sdfr return GSS_S_FAILURE; 384178828Sdfr } 385178828Sdfr *minor_status = 0; 386178828Sdfr return GSS_S_COMPLETE; 387178828Sdfr} 388178828Sdfr 389178828SdfrOM_uint32 390178828Sdfrgss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c) 391178828Sdfr{ 392178828Sdfr gss_krb5_lucid_context_v1_t *ctx = c; 393178828Sdfr 394178828Sdfr if (ctx->version != 1) { 395178828Sdfr if (minor_status) 396178828Sdfr *minor_status = 0; 397178828Sdfr return GSS_S_FAILURE; 398178828Sdfr } 399178828Sdfr 400178828Sdfr if (ctx->protocol == 0) { 401178828Sdfr free_key(&ctx->rfc1964_kd.ctx_key); 402178828Sdfr } else if (ctx->protocol == 1) { 403178828Sdfr free_key(&ctx->cfx_kd.ctx_key); 404178828Sdfr if (ctx->cfx_kd.have_acceptor_subkey) 405178828Sdfr free_key(&ctx->cfx_kd.acceptor_subkey); 406178828Sdfr } 407178828Sdfr free(ctx); 408178828Sdfr if (minor_status) 409178828Sdfr *minor_status = 0; 410178828Sdfr return GSS_S_COMPLETE; 411178828Sdfr} 412178828Sdfr 413178828Sdfr/* 414178828Sdfr * 415178828Sdfr */ 416178828Sdfr 417178828SdfrOM_uint32 418178828Sdfrgss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 419178828Sdfr gss_cred_id_t cred, 420178828Sdfr OM_uint32 num_enctypes, 421178828Sdfr int32_t *enctypes) 422178828Sdfr{ 423178828Sdfr krb5_error_code ret; 424178828Sdfr OM_uint32 maj_status; 425178828Sdfr gss_buffer_desc buffer; 426178828Sdfr krb5_storage *sp; 427178828Sdfr krb5_data data; 428178828Sdfr int i; 429178828Sdfr 430178828Sdfr sp = krb5_storage_emem(); 431178828Sdfr if (sp == NULL) { 432178828Sdfr *minor_status = ENOMEM; 433178828Sdfr maj_status = GSS_S_FAILURE; 434178828Sdfr goto out; 435178828Sdfr } 436178828Sdfr 437178828Sdfr for (i = 0; i < num_enctypes; i++) { 438178828Sdfr ret = krb5_store_int32(sp, enctypes[i]); 439178828Sdfr if (ret) { 440178828Sdfr *minor_status = ret; 441178828Sdfr maj_status = GSS_S_FAILURE; 442178828Sdfr goto out; 443178828Sdfr } 444178828Sdfr } 445178828Sdfr 446178828Sdfr ret = krb5_storage_to_data(sp, &data); 447178828Sdfr if (ret) { 448178828Sdfr *minor_status = ret; 449178828Sdfr maj_status = GSS_S_FAILURE; 450178828Sdfr goto out; 451178828Sdfr } 452178828Sdfr 453178828Sdfr buffer.value = data.data; 454178828Sdfr buffer.length = data.length; 455178828Sdfr 456178828Sdfr maj_status = gss_set_cred_option(minor_status, 457178828Sdfr &cred, 458178828Sdfr GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, 459178828Sdfr &buffer); 460178828Sdfr krb5_data_free(&data); 461178828Sdfrout: 462178828Sdfr if (sp) 463178828Sdfr krb5_storage_free(sp); 464178828Sdfr return maj_status; 465178828Sdfr} 466178828Sdfr 467178828Sdfr/* 468178828Sdfr * 469178828Sdfr */ 470178828Sdfr 471178828SdfrOM_uint32 472178828Sdfrgsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c) 473178828Sdfr{ 474178828Sdfr gss_buffer_desc buffer; 475178828Sdfr OM_uint32 junk; 476178828Sdfr 477178828Sdfr if (c) { 478178828Sdfr buffer.value = c; 479178828Sdfr buffer.length = sizeof(*c); 480178828Sdfr } else { 481178828Sdfr buffer.value = NULL; 482178828Sdfr buffer.length = 0; 483178828Sdfr } 484178828Sdfr 485178828Sdfr gss_set_sec_context_option(&junk, NULL, 486178828Sdfr GSS_KRB5_SEND_TO_KDC_X, &buffer); 487178828Sdfr 488178828Sdfr return (GSS_S_COMPLETE); 489178828Sdfr} 490178828Sdfr 491178828Sdfr/* 492178828Sdfr * 493178828Sdfr */ 494178828Sdfr 495178828SdfrOM_uint32 496178828Sdfrgss_krb5_ccache_name(OM_uint32 *minor_status, 497178828Sdfr const char *name, 498178828Sdfr const char **out_name) 499178828Sdfr{ 500178828Sdfr gss_buffer_desc buffer; 501178828Sdfr OM_uint32 junk; 502178828Sdfr 503178828Sdfr if (out_name) 504178828Sdfr *out_name = NULL; 505178828Sdfr 506178828Sdfr buffer.value = rk_UNCONST(name); 507178828Sdfr buffer.length = strlen(name); 508178828Sdfr 509178828Sdfr gss_set_sec_context_option(&junk, NULL, 510178828Sdfr GSS_KRB5_CCACHE_NAME_X, &buffer); 511178828Sdfr 512178828Sdfr return (GSS_S_COMPLETE); 513178828Sdfr} 514178828Sdfr 515178828Sdfr 516178828Sdfr/* 517178828Sdfr * 518178828Sdfr */ 519178828Sdfr 520178828SdfrOM_uint32 521178828Sdfrgsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, 522178828Sdfr gss_ctx_id_t context_handle, 523178828Sdfr time_t *authtime) 524178828Sdfr{ 525178828Sdfr gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 526178828Sdfr OM_uint32 maj_stat; 527178828Sdfr 528178828Sdfr if (context_handle == GSS_C_NO_CONTEXT) { 529178828Sdfr *minor_status = EINVAL; 530178828Sdfr return GSS_S_FAILURE; 531178828Sdfr } 532178828Sdfr 533178828Sdfr maj_stat = 534178828Sdfr gss_inquire_sec_context_by_oid (minor_status, 535178828Sdfr context_handle, 536178828Sdfr GSS_KRB5_GET_AUTHTIME_X, 537178828Sdfr &data_set); 538178828Sdfr if (maj_stat) 539178828Sdfr return maj_stat; 540178828Sdfr 541178828Sdfr if (data_set == GSS_C_NO_BUFFER_SET) { 542178828Sdfr gss_release_buffer_set(minor_status, &data_set); 543178828Sdfr *minor_status = EINVAL; 544178828Sdfr return GSS_S_FAILURE; 545178828Sdfr } 546178828Sdfr 547178828Sdfr if (data_set->count != 1) { 548178828Sdfr gss_release_buffer_set(minor_status, &data_set); 549178828Sdfr *minor_status = EINVAL; 550178828Sdfr return GSS_S_FAILURE; 551178828Sdfr } 552178828Sdfr 553178828Sdfr if (data_set->elements[0].length != 4) { 554178828Sdfr gss_release_buffer_set(minor_status, &data_set); 555178828Sdfr *minor_status = EINVAL; 556178828Sdfr return GSS_S_FAILURE; 557178828Sdfr } 558178828Sdfr 559178828Sdfr { 560178828Sdfr unsigned char *buf = data_set->elements[0].value; 561178828Sdfr *authtime = (buf[3] <<24) | (buf[2] << 16) | 562178828Sdfr (buf[1] << 8) | (buf[0] << 0); 563178828Sdfr } 564178828Sdfr 565178828Sdfr gss_release_buffer_set(minor_status, &data_set); 566178828Sdfr 567178828Sdfr *minor_status = 0; 568178828Sdfr return GSS_S_COMPLETE; 569178828Sdfr} 570178828Sdfr 571178828Sdfr/* 572178828Sdfr * 573178828Sdfr */ 574178828Sdfr 575178828SdfrOM_uint32 576178828Sdfrgsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, 577178828Sdfr gss_ctx_id_t context_handle, 578178828Sdfr int ad_type, 579178828Sdfr gss_buffer_t ad_data) 580178828Sdfr{ 581178828Sdfr gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 582178828Sdfr OM_uint32 maj_stat; 583178828Sdfr gss_OID_desc oid_flat; 584178828Sdfr heim_oid baseoid, oid; 585178828Sdfr size_t size; 586178828Sdfr 587178828Sdfr if (context_handle == GSS_C_NO_CONTEXT) { 588178828Sdfr *minor_status = EINVAL; 589178828Sdfr return GSS_S_FAILURE; 590178828Sdfr } 591178828Sdfr 592178828Sdfr /* All this to append an integer to an oid... */ 593178828Sdfr 594178828Sdfr if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, 595178828Sdfr GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, 596178828Sdfr &baseoid, NULL) != 0) { 597178828Sdfr *minor_status = EINVAL; 598178828Sdfr return GSS_S_FAILURE; 599178828Sdfr } 600178828Sdfr 601178828Sdfr oid.length = baseoid.length + 1; 602178828Sdfr oid.components = calloc(oid.length, sizeof(*oid.components)); 603178828Sdfr if (oid.components == NULL) { 604178828Sdfr der_free_oid(&baseoid); 605178828Sdfr 606178828Sdfr *minor_status = ENOMEM; 607178828Sdfr return GSS_S_FAILURE; 608178828Sdfr } 609178828Sdfr 610178828Sdfr memcpy(oid.components, baseoid.components, 611178828Sdfr baseoid.length * sizeof(*baseoid.components)); 612178828Sdfr 613178828Sdfr der_free_oid(&baseoid); 614178828Sdfr 615178828Sdfr oid.components[oid.length - 1] = ad_type; 616178828Sdfr 617178828Sdfr oid_flat.length = der_length_oid(&oid); 618178828Sdfr oid_flat.elements = malloc(oid_flat.length); 619178828Sdfr if (oid_flat.elements == NULL) { 620178828Sdfr free(oid.components); 621178828Sdfr *minor_status = ENOMEM; 622178828Sdfr return GSS_S_FAILURE; 623178828Sdfr } 624178828Sdfr 625178828Sdfr if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 626178828Sdfr oid_flat.length, &oid, &size) != 0) { 627178828Sdfr free(oid.components); 628178828Sdfr free(oid_flat.elements); 629178828Sdfr *minor_status = EINVAL; 630178828Sdfr return GSS_S_FAILURE; 631178828Sdfr } 632178828Sdfr if (oid_flat.length != size) 633178828Sdfr abort(); 634178828Sdfr 635178828Sdfr free(oid.components); 636178828Sdfr 637178828Sdfr /* FINALLY, we have the OID */ 638178828Sdfr 639178828Sdfr maj_stat = gss_inquire_sec_context_by_oid (minor_status, 640178828Sdfr context_handle, 641178828Sdfr &oid_flat, 642178828Sdfr &data_set); 643178828Sdfr 644178828Sdfr free(oid_flat.elements); 645178828Sdfr 646178828Sdfr if (maj_stat) 647178828Sdfr return maj_stat; 648178828Sdfr 649178828Sdfr if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 650178828Sdfr gss_release_buffer_set(minor_status, &data_set); 651178828Sdfr *minor_status = EINVAL; 652178828Sdfr return GSS_S_FAILURE; 653178828Sdfr } 654178828Sdfr 655178828Sdfr ad_data->value = malloc(data_set->elements[0].length); 656178828Sdfr if (ad_data->value == NULL) { 657178828Sdfr gss_release_buffer_set(minor_status, &data_set); 658178828Sdfr *minor_status = ENOMEM; 659178828Sdfr return GSS_S_FAILURE; 660178828Sdfr } 661178828Sdfr 662178828Sdfr ad_data->length = data_set->elements[0].length; 663178828Sdfr memcpy(ad_data->value, data_set->elements[0].value, ad_data->length); 664178828Sdfr gss_release_buffer_set(minor_status, &data_set); 665178828Sdfr 666178828Sdfr *minor_status = 0; 667178828Sdfr return GSS_S_COMPLETE; 668178828Sdfr} 669178828Sdfr 670178828Sdfr/* 671178828Sdfr * 672178828Sdfr */ 673178828Sdfr 674178828Sdfrstatic OM_uint32 675178828Sdfrgsskrb5_extract_key(OM_uint32 *minor_status, 676178828Sdfr gss_ctx_id_t context_handle, 677178828Sdfr const gss_OID oid, 678178828Sdfr krb5_keyblock **keyblock) 679178828Sdfr{ 680178828Sdfr krb5_error_code ret; 681178828Sdfr gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 682178828Sdfr OM_uint32 major_status; 683178828Sdfr krb5_context context = NULL; 684178828Sdfr krb5_storage *sp = NULL; 685178828Sdfr 686178828Sdfr if (context_handle == GSS_C_NO_CONTEXT) { 687178828Sdfr ret = EINVAL; 688178828Sdfr return GSS_S_FAILURE; 689178828Sdfr } 690178828Sdfr 691178828Sdfr ret = krb5_init_context(&context); 692178828Sdfr if(ret) { 693178828Sdfr *minor_status = ret; 694178828Sdfr return GSS_S_FAILURE; 695178828Sdfr } 696178828Sdfr 697178828Sdfr major_status = 698178828Sdfr gss_inquire_sec_context_by_oid (minor_status, 699178828Sdfr context_handle, 700178828Sdfr oid, 701178828Sdfr &data_set); 702178828Sdfr if (major_status) 703178828Sdfr return major_status; 704178828Sdfr 705178828Sdfr if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { 706178828Sdfr gss_release_buffer_set(minor_status, &data_set); 707178828Sdfr *minor_status = EINVAL; 708178828Sdfr return GSS_S_FAILURE; 709178828Sdfr } 710178828Sdfr 711178828Sdfr sp = krb5_storage_from_mem(data_set->elements[0].value, 712178828Sdfr data_set->elements[0].length); 713178828Sdfr if (sp == NULL) { 714178828Sdfr ret = ENOMEM; 715178828Sdfr goto out; 716178828Sdfr } 717178828Sdfr 718178828Sdfr *keyblock = calloc(1, sizeof(**keyblock)); 719178828Sdfr if (keyblock == NULL) { 720178828Sdfr ret = ENOMEM; 721178828Sdfr goto out; 722178828Sdfr } 723178828Sdfr 724178828Sdfr ret = krb5_ret_keyblock(sp, *keyblock); 725178828Sdfr 726178828Sdfrout: 727178828Sdfr gss_release_buffer_set(minor_status, &data_set); 728178828Sdfr if (sp) 729178828Sdfr krb5_storage_free(sp); 730178828Sdfr if (ret && keyblock) { 731178828Sdfr krb5_free_keyblock(context, *keyblock); 732178828Sdfr *keyblock = NULL; 733178828Sdfr } 734178828Sdfr if (context) 735178828Sdfr krb5_free_context(context); 736178828Sdfr 737178828Sdfr *minor_status = ret; 738178828Sdfr if (ret) 739178828Sdfr return GSS_S_FAILURE; 740178828Sdfr 741178828Sdfr return GSS_S_COMPLETE; 742178828Sdfr} 743178828Sdfr 744178828Sdfr/* 745178828Sdfr * 746178828Sdfr */ 747178828Sdfr 748178828SdfrOM_uint32 749178828Sdfrgsskrb5_extract_service_keyblock(OM_uint32 *minor_status, 750178828Sdfr gss_ctx_id_t context_handle, 751178828Sdfr krb5_keyblock **keyblock) 752178828Sdfr{ 753178828Sdfr return gsskrb5_extract_key(minor_status, 754178828Sdfr context_handle, 755178828Sdfr GSS_KRB5_GET_SERVICE_KEYBLOCK_X, 756178828Sdfr keyblock); 757178828Sdfr} 758178828Sdfr 759178828SdfrOM_uint32 760178828Sdfrgsskrb5_get_initiator_subkey(OM_uint32 *minor_status, 761178828Sdfr gss_ctx_id_t context_handle, 762178828Sdfr krb5_keyblock **keyblock) 763178828Sdfr{ 764178828Sdfr return gsskrb5_extract_key(minor_status, 765178828Sdfr context_handle, 766178828Sdfr GSS_KRB5_GET_INITIATOR_SUBKEY_X, 767178828Sdfr keyblock); 768178828Sdfr} 769178828Sdfr 770178828SdfrOM_uint32 771178828Sdfrgsskrb5_get_subkey(OM_uint32 *minor_status, 772178828Sdfr gss_ctx_id_t context_handle, 773178828Sdfr krb5_keyblock **keyblock) 774178828Sdfr{ 775178828Sdfr return gsskrb5_extract_key(minor_status, 776178828Sdfr context_handle, 777178828Sdfr GSS_KRB5_GET_SUBKEY_X, 778178828Sdfr keyblock); 779178828Sdfr} 780178828Sdfr 781178828SdfrOM_uint32 782178828Sdfrgsskrb5_set_default_realm(const char *realm) 783178828Sdfr{ 784178828Sdfr gss_buffer_desc buffer; 785178828Sdfr OM_uint32 junk; 786178828Sdfr 787178828Sdfr buffer.value = rk_UNCONST(realm); 788178828Sdfr buffer.length = strlen(realm); 789178828Sdfr 790178828Sdfr gss_set_sec_context_option(&junk, NULL, 791178828Sdfr GSS_KRB5_SET_DEFAULT_REALM_X, &buffer); 792178828Sdfr 793178828Sdfr return (GSS_S_COMPLETE); 794178828Sdfr} 795178828Sdfr 796178828SdfrOM_uint32 797178828Sdfrgss_krb5_get_tkt_flags(OM_uint32 *minor_status, 798178828Sdfr gss_ctx_id_t context_handle, 799178828Sdfr OM_uint32 *tkt_flags) 800178828Sdfr{ 801178828Sdfr 802178828Sdfr OM_uint32 major_status; 803178828Sdfr gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; 804178828Sdfr 805178828Sdfr if (context_handle == GSS_C_NO_CONTEXT) { 806178828Sdfr *minor_status = EINVAL; 807178828Sdfr return GSS_S_FAILURE; 808178828Sdfr } 809178828Sdfr 810178828Sdfr major_status = 811178828Sdfr gss_inquire_sec_context_by_oid (minor_status, 812178828Sdfr context_handle, 813178828Sdfr GSS_KRB5_GET_TKT_FLAGS_X, 814178828Sdfr &data_set); 815178828Sdfr if (major_status) 816178828Sdfr return major_status; 817178828Sdfr 818178828Sdfr if (data_set == GSS_C_NO_BUFFER_SET || 819178828Sdfr data_set->count != 1 || 820178828Sdfr data_set->elements[0].length < 4) { 821178828Sdfr gss_release_buffer_set(minor_status, &data_set); 822178828Sdfr *minor_status = EINVAL; 823178828Sdfr return GSS_S_FAILURE; 824178828Sdfr } 825178828Sdfr 826178828Sdfr { 827178828Sdfr const u_char *p = data_set->elements[0].value; 828178828Sdfr *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 829178828Sdfr } 830178828Sdfr 831178828Sdfr gss_release_buffer_set(minor_status, &data_set); 832178828Sdfr return GSS_S_COMPLETE; 833178828Sdfr} 834178828Sdfr 835