root/source4/heimdal/lib/gssapi/krb5/acquire_cred.c

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

DEFINITIONS

This source file includes following definitions.
  1. __gsskrb5_ccache_lifetime
  2. get_keytab

   1 /*
   2  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "krb5/gsskrb5_locl.h"
  35 
  36 RCSID("$Id$");
  37 
  38 OM_uint32
  39 __gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
  40                           krb5_context context,
  41                           krb5_ccache id,
  42                           krb5_principal principal,
  43                           OM_uint32 *lifetime)
  44 {
  45     krb5_creds in_cred, *out_cred;
  46     krb5_const_realm realm;
  47     krb5_error_code kret;
  48 
  49     memset(&in_cred, 0, sizeof(in_cred));
  50     in_cred.client = principal;
  51         
  52     realm = krb5_principal_get_realm(context,  principal);
  53     if (realm == NULL) {
  54         _gsskrb5_clear_status ();
  55         *minor_status = KRB5_PRINC_NOMATCH; /* XXX */
  56         return GSS_S_FAILURE;
  57     }
  58 
  59     kret = krb5_make_principal(context, &in_cred.server,
  60                                realm, KRB5_TGS_NAME, realm, NULL);
  61     if (kret) {
  62         *minor_status = kret;
  63         return GSS_S_FAILURE;
  64     }
  65 
  66     kret = krb5_get_credentials(context, 0,
  67                                 id, &in_cred, &out_cred);
  68     krb5_free_principal(context, in_cred.server);
  69     if (kret) {
  70         *minor_status = kret;
  71         return GSS_S_FAILURE;
  72     }
  73 
  74     *lifetime = out_cred->times.endtime;
  75     krb5_free_creds(context, out_cred);
  76 
  77     return GSS_S_COMPLETE;
  78 }
  79 
  80 
  81 
  82 
  83 static krb5_error_code
  84 get_keytab(krb5_context context, krb5_keytab *keytab)
     /* [<][>][^][v][top][bottom][index][help] */
  85 {
  86     char kt_name[256];
  87     krb5_error_code kret;
  88 
  89     HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
  90 
  91     if (_gsskrb5_keytab != NULL) {
  92         kret = krb5_kt_get_name(context,
  93                                 _gsskrb5_keytab,
  94                                 kt_name, sizeof(kt_name));
  95         if (kret == 0)
  96             kret = krb5_kt_resolve(context, kt_name, keytab);
  97     } else
  98         kret = krb5_kt_default(context, keytab);
  99 
 100     HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
 101 
 102     return (kret);
 103 }
 104 
 105 static OM_uint32 acquire_initiator_cred
 106                   (OM_uint32 * minor_status,
 107                    krb5_context context,
 108                    const gss_name_t desired_name,
 109                    OM_uint32 time_req,
 110                    const gss_OID_set desired_mechs,
 111                    gss_cred_usage_t cred_usage,
 112                    gsskrb5_cred handle,
 113                    gss_OID_set * actual_mechs,
 114                    OM_uint32 * time_rec
 115                   )
 116 {
 117     OM_uint32 ret;
 118     krb5_creds cred;
 119     krb5_principal def_princ;
 120     krb5_get_init_creds_opt *opt;
 121     krb5_ccache ccache;
 122     krb5_keytab keytab;
 123     krb5_error_code kret;
 124 
 125     keytab = NULL;
 126     ccache = NULL;
 127     def_princ = NULL;
 128     ret = GSS_S_FAILURE;
 129     memset(&cred, 0, sizeof(cred));
 130 
 131     /*
 132      * If we have a preferred principal, lets try to find it in all
 133      * caches, otherwise, fall back to default cache, ignore all
 134      * errors while searching.
 135      */
 136 
 137     if (handle->principal) {
 138         kret = krb5_cc_cache_match (context,
 139                                     handle->principal,
 140                                     &ccache);
 141         if (kret == 0) {
 142             ret = GSS_S_COMPLETE;
 143             goto found;
 144         }
 145     }
 146 
 147     if (ccache == NULL) {
 148         kret = krb5_cc_default(context, &ccache);
 149         if (kret)
 150             goto end;
 151     }
 152     kret = krb5_cc_get_principal(context, ccache, &def_princ);
 153     if (kret != 0) {
 154         /* we'll try to use a keytab below */
 155         krb5_cc_close(context, ccache);
 156         def_princ = NULL;
 157         kret = 0;
 158     } else if (handle->principal == NULL)  {
 159         kret = krb5_copy_principal(context, def_princ, &handle->principal);
 160         if (kret)
 161             goto end;
 162     } else if (handle->principal != NULL &&
 163                krb5_principal_compare(context, handle->principal,
 164                                       def_princ) == FALSE) {
 165         krb5_free_principal(context, def_princ);
 166         def_princ = NULL;
 167         krb5_cc_close(context, ccache);
 168         ccache = NULL;
 169     }
 170     if (def_princ == NULL) {
 171         /* We have no existing credentials cache,
 172          * so attempt to get a TGT using a keytab.
 173          */
 174         if (handle->principal == NULL) {
 175             kret = krb5_get_default_principal(context, &handle->principal);
 176             if (kret)
 177                 goto end;
 178         }
 179         kret = get_keytab(context, &keytab);
 180         if (kret)
 181             goto end;
 182         kret = krb5_get_init_creds_opt_alloc(context, &opt);
 183         if (kret)
 184             goto end;
 185         kret = krb5_get_init_creds_keytab(context, &cred,
 186             handle->principal, keytab, 0, NULL, opt);
 187         krb5_get_init_creds_opt_free(context, opt);
 188         if (kret)
 189             goto end;
 190         kret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
 191         if (kret)
 192             goto end;
 193         kret = krb5_cc_initialize(context, ccache, cred.client);
 194         if (kret) {
 195             krb5_cc_destroy(context, ccache);
 196             goto end;
 197         }
 198         kret = krb5_cc_store_cred(context, ccache, &cred);
 199         if (kret) {
 200             krb5_cc_destroy(context, ccache);
 201             goto end;
 202         }
 203         handle->lifetime = cred.times.endtime;
 204         handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
 205     } else {
 206 
 207         ret = __gsskrb5_ccache_lifetime(minor_status,
 208                                         context,
 209                                         ccache,
 210                                         handle->principal,
 211                                         &handle->lifetime);
 212         if (ret != GSS_S_COMPLETE) {
 213             krb5_cc_close(context, ccache);
 214             goto end;
 215         }
 216         kret = 0;
 217     }
 218  found:
 219     handle->ccache = ccache;
 220     ret = GSS_S_COMPLETE;
 221 
 222 end:
 223     if (cred.client != NULL)
 224         krb5_free_cred_contents(context, &cred);
 225     if (def_princ != NULL)
 226         krb5_free_principal(context, def_princ);
 227     if (keytab != NULL)
 228         krb5_kt_close(context, keytab);
 229     if (ret != GSS_S_COMPLETE && kret != 0)
 230         *minor_status = kret;
 231     return (ret);
 232 }
 233 
 234 static OM_uint32 acquire_acceptor_cred
 235                   (OM_uint32 * minor_status,
 236                    krb5_context context,
 237                    const gss_name_t desired_name,
 238                    OM_uint32 time_req,
 239                    const gss_OID_set desired_mechs,
 240                    gss_cred_usage_t cred_usage,
 241                    gsskrb5_cred handle,
 242                    gss_OID_set * actual_mechs,
 243                    OM_uint32 * time_rec
 244                   )
 245 {
 246     OM_uint32 ret;
 247     krb5_error_code kret;
 248 
 249     ret = GSS_S_FAILURE;
 250     kret = get_keytab(context, &handle->keytab);
 251     if (kret)
 252         goto end;
 253 
 254     /* check that the requested principal exists in the keytab */
 255     if (handle->principal) {
 256         krb5_keytab_entry entry;
 257 
 258         kret = krb5_kt_get_entry(context, handle->keytab,
 259                                  handle->principal, 0, 0, &entry);
 260         if (kret)
 261             goto end;
 262         krb5_kt_free_entry(context, &entry);
 263         ret = GSS_S_COMPLETE;
 264     } else {
 265         /*
 266          * Check if there is at least one entry in the keytab before
 267          * declaring it as an useful keytab.
 268          */
 269         krb5_keytab_entry tmp;
 270         krb5_kt_cursor c;
 271 
 272         kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
 273         if (kret)
 274             goto end;
 275         if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
 276             krb5_kt_free_entry(context, &tmp);
 277             ret = GSS_S_COMPLETE; /* ok found one entry */
 278         }
 279         krb5_kt_end_seq_get (context, handle->keytab, &c);
 280     }
 281 end:
 282     if (ret != GSS_S_COMPLETE) {
 283         if (handle->keytab != NULL)
 284             krb5_kt_close(context, handle->keytab);
 285         if (kret != 0) {
 286             *minor_status = kret;
 287         }
 288     }
 289     return (ret);
 290 }
 291 
 292 OM_uint32 _gsskrb5_acquire_cred
 293 (OM_uint32 * minor_status,
 294  const gss_name_t desired_name,
 295  OM_uint32 time_req,
 296  const gss_OID_set desired_mechs,
 297  gss_cred_usage_t cred_usage,
 298  gss_cred_id_t * output_cred_handle,
 299  gss_OID_set * actual_mechs,
 300  OM_uint32 * time_rec
 301     )
 302 {
 303     krb5_context context;
 304     gsskrb5_cred handle;
 305     OM_uint32 ret;
 306 
 307     if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
 308         *minor_status = GSS_KRB5_S_G_BAD_USAGE;
 309         return GSS_S_FAILURE;
 310     }
 311 
 312     GSSAPI_KRB5_INIT(&context);
 313 
 314     *output_cred_handle = NULL;
 315     if (time_rec)
 316         *time_rec = 0;
 317     if (actual_mechs)
 318         *actual_mechs = GSS_C_NO_OID_SET;
 319 
 320     if (desired_mechs) {
 321         int present = 0;
 322 
 323         ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
 324                                       desired_mechs, &present);
 325         if (ret)
 326             return ret;
 327         if (!present) {
 328             *minor_status = 0;
 329             return GSS_S_BAD_MECH;
 330         }
 331     }
 332 
 333     handle = calloc(1, sizeof(*handle));
 334     if (handle == NULL) {
 335         *minor_status = ENOMEM;
 336         return (GSS_S_FAILURE);
 337     }
 338 
 339     HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
 340 
 341     if (desired_name != GSS_C_NO_NAME) {
 342 
 343         ret = _gsskrb5_canon_name(minor_status, context, 0, desired_name,
 344                                   &handle->principal);
 345         if (ret) {
 346             HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
 347             free(handle);
 348             return ret;
 349         }
 350     }
 351     if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
 352         ret = acquire_initiator_cred(minor_status, context,
 353                                      desired_name, time_req,
 354                                      desired_mechs, cred_usage, handle,
 355                                      actual_mechs, time_rec);
 356         if (ret != GSS_S_COMPLETE) {
 357             HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
 358             krb5_free_principal(context, handle->principal);
 359             free(handle);
 360             return (ret);
 361         }
 362     }
 363     if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
 364         ret = acquire_acceptor_cred(minor_status, context,
 365                                     desired_name, time_req,
 366                                     desired_mechs, cred_usage, handle, actual_mechs, time_rec);
 367         if (ret != GSS_S_COMPLETE) {
 368             HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
 369             krb5_free_principal(context, handle->principal);
 370             free(handle);
 371             return (ret);
 372         }
 373     }
 374     ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
 375     if (ret == GSS_S_COMPLETE)
 376         ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
 377                                      &handle->mechanisms);
 378     if (ret == GSS_S_COMPLETE)
 379         ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle,
 380                                     NULL, time_rec, NULL, actual_mechs);
 381     if (ret != GSS_S_COMPLETE) {
 382         if (handle->mechanisms != NULL)
 383             gss_release_oid_set(NULL, &handle->mechanisms);
 384         HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
 385         krb5_free_principal(context, handle->principal);
 386         free(handle);
 387         return (ret);
 388     }
 389     *minor_status = 0;
 390     if (time_rec) {
 391         ret = _gsskrb5_lifetime_left(minor_status,
 392                                      context,
 393                                      handle->lifetime,
 394                                      time_rec);
 395 
 396         if (ret)
 397             return ret;
 398     }
 399     handle->usage = cred_usage;
 400     *output_cred_handle = (gss_cred_id_t)handle;
 401     return (GSS_S_COMPLETE);
 402 }

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