root/source4/heimdal/lib/gssapi/mech/gss_krb5.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gss_krb5_copy_ccache
  2. gss_krb5_import_cred
  3. gsskrb5_register_acceptor_identity
  4. krb5_gss_register_acceptor_identity
  5. gsskrb5_set_dns_canonicalize
  6. set_key
  7. free_key
  8. gss_krb5_export_lucid_sec_context
  9. gss_krb5_free_lucid_sec_context
  10. gss_krb5_set_allowable_enctypes
  11. gsskrb5_set_send_to_kdc
  12. gss_krb5_ccache_name
  13. gsskrb5_extract_authtime_from_sec_context
  14. gsskrb5_extract_authz_data_from_sec_context
  15. gsskrb5_extract_key
  16. gsskrb5_extract_service_keyblock
  17. gsskrb5_get_initiator_subkey
  18. gsskrb5_get_subkey
  19. gsskrb5_set_default_realm
  20. gss_krb5_get_tkt_flags
  21. gsskrb5_set_time_offset
  22. gsskrb5_get_time_offset
  23. gsskrb5_plugin_register

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

/* [<][>][^][v][top][bottom][index][help] */