LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/gssapi/krb5 - acquire_cred.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 17 343 5.0 %
Date: 2024-04-21 15:09:00 Functions: 2 9 22.2 %

          Line data    Source code
       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 "gsskrb5_locl.h"
      35             : 
      36             : /*
      37             :  * Find an element in a cred store. Returns GSS_S_COMPLETE if the cred store
      38             :  * is absent or well formed, irrespective of whether the element exists. The
      39             :  * caller should check for *value != NULL before using; values are typically
      40             :  * optional, hence this behavior. (The caller should validate the return
      41             :  * value at least once though, to check it is well-formed.)
      42             :  */
      43             : OM_uint32
      44      287464 : __gsskrb5_cred_store_find(OM_uint32 *minor_status,
      45             :                           gss_const_key_value_set_t cred_store,
      46             :                           const char *key,
      47             :                           const char **value)
      48             : {
      49        3524 :     size_t i;
      50             : 
      51      287464 :     *value = NULL;
      52             : 
      53      287464 :     if (cred_store == GSS_C_NO_CRED_STORE)
      54           0 :         return GSS_S_COMPLETE;
      55      287464 :     else if (cred_store->count == 0) {
      56           0 :         *minor_status = GSS_KRB5_S_G_BAD_USAGE;
      57           0 :         return GSS_S_NO_CRED;
      58             :     }
      59             : 
      60      574928 :     for (i = 0; i < cred_store->count; i++) {
      61      287464 :         if (strcmp(key, cred_store->elements[i].key) == 0) {
      62       71866 :             if (*value) {
      63           0 :                 *value = NULL;
      64           0 :                 *minor_status = GSS_KRB5_S_G_BAD_USAGE;
      65           0 :                 return GSS_S_DUPLICATE_ELEMENT;
      66             :             }
      67       71866 :             *value = cred_store->elements[i].value;
      68             :         }
      69             :     }
      70             : 
      71      283940 :     return GSS_S_COMPLETE;
      72             : }
      73             : 
      74             : OM_uint32
      75       63240 : __gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
      76             :                           krb5_context context,
      77             :                           krb5_ccache id,
      78             :                           krb5_principal principal,
      79             :                           OM_uint32 *lifetime)
      80             : {
      81        1466 :     krb5_error_code kret;
      82        1466 :     time_t left;
      83             : 
      84       63240 :     kret = krb5_cc_get_lifetime(context, id, &left);
      85       63240 :     if (kret) {
      86           0 :         *minor_status = kret;
      87           0 :         return GSS_S_FAILURE;
      88             :     }
      89             : 
      90       63240 :     *lifetime = left;
      91             : 
      92       63240 :     return GSS_S_COMPLETE;
      93             : }
      94             : 
      95             : 
      96             : 
      97             : 
      98             : static krb5_error_code
      99           0 : get_system_keytab(krb5_context context,
     100             :                   gss_const_key_value_set_t cred_store,
     101             :                   krb5_keytab *keytab)
     102             : {
     103           0 :     krb5_error_code kret;
     104           0 :     const char *cs_ktname;
     105           0 :     OM_uint32 tmp;
     106             : 
     107           0 :     __gsskrb5_cred_store_find(&tmp, cred_store, "keytab", &cs_ktname);
     108             : 
     109           0 :     HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
     110             : 
     111           0 :     if (cs_ktname)
     112           0 :         kret = krb5_kt_resolve(context, cs_ktname, keytab);
     113           0 :     else if (_gsskrb5_keytab != NULL) {
     114           0 :         char *name = NULL;
     115             : 
     116           0 :         kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);
     117           0 :         if (kret == 0) {
     118           0 :             kret = krb5_kt_resolve(context, name, keytab);
     119           0 :             krb5_xfree(name);
     120             :         }
     121             :     } else
     122           0 :         kret = krb5_kt_default(context, keytab);
     123             : 
     124           0 :     HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
     125             : 
     126           0 :     return (kret);
     127             : }
     128             : 
     129             : static krb5_error_code
     130           0 : get_client_keytab(krb5_context context,
     131             :                   gss_const_key_value_set_t cred_store,
     132             :                   krb5_const_principal principal,
     133             :                   krb5_keytab *keytab)
     134             : {
     135           0 :     krb5_error_code ret;
     136           0 :     const char *cs_ktname;
     137           0 :     OM_uint32 tmp;
     138             : 
     139           0 :     __gsskrb5_cred_store_find(&tmp, cred_store, "client_keytab", &cs_ktname);
     140             : 
     141           0 :     if (cs_ktname)
     142           0 :         ret = krb5_kt_resolve(context, cs_ktname, keytab);
     143             :     else {
     144           0 :         char *name = NULL;
     145           0 :         ret = _krb5_kt_client_default_name(context, &name);
     146           0 :         if (ret == 0)
     147           0 :             ret = krb5_kt_resolve(context, name, keytab);
     148           0 :         krb5_xfree(name);
     149             :     }
     150             : 
     151           0 :     if (ret == 0 && principal) {
     152           0 :         krb5_keytab_entry entry;
     153             : 
     154           0 :         ret = krb5_kt_get_entry(context, *keytab, principal,
     155             :                                  0, 0, &entry);
     156           0 :         if (ret == 0)
     157           0 :             krb5_kt_free_entry(context, &entry);
     158             :     }
     159             : 
     160           0 :     if (ret) {
     161           0 :         if (*keytab) {
     162           0 :             krb5_kt_close(context, *keytab);
     163           0 :             *keytab = NULL;
     164             :         }
     165             : 
     166           0 :         ret = get_system_keytab(context, GSS_C_NO_CRED_STORE, keytab);
     167             :     }
     168             : 
     169           0 :     return ret;
     170             : }
     171             : 
     172             : static krb5_boolean
     173           0 : is_valid_password_cred_store(gss_const_key_value_set_t cred_store)
     174             : {
     175           0 :     size_t i;
     176             : 
     177           0 :     if (cred_store == GSS_C_NO_CRED_STORE)
     178           0 :         return TRUE;
     179             : 
     180             :     /* XXX don't check keytab, someday we will allow password+acceptor creds */
     181           0 :     for (i = 0; i < cred_store->count; i++) {
     182           0 :         if (strcmp(cred_store->elements[i].key, "ccache") == 0 ||
     183           0 :             strcmp(cred_store->elements[i].key, "client_keytab") == 0)
     184           0 :             return FALSE;
     185             :     }
     186             : 
     187           0 :     return TRUE;
     188             : }
     189             : 
     190             : /*
     191             :  * This function produces a cred with a MEMORY ccache containing a TGT
     192             :  * acquired with a password.
     193             :  */
     194             : static OM_uint32
     195           0 : acquire_cred_with_password(OM_uint32 *minor_status,
     196             :                            krb5_context context,
     197             :                            const char *password,
     198             :                            OM_uint32 time_req,
     199             :                            gss_OID_set desired_mechs,
     200             :                            gss_cred_usage_t cred_usage,
     201             :                            gss_const_key_value_set_t cred_store,
     202             :                            gsskrb5_cred handle)
     203             : {
     204           0 :     OM_uint32 ret = GSS_S_FAILURE;
     205           0 :     krb5_creds cred;
     206           0 :     krb5_init_creds_context ctx = NULL;
     207           0 :     krb5_get_init_creds_opt *opt = NULL;
     208           0 :     krb5_ccache ccache = NULL;
     209           0 :     krb5_error_code kret;
     210           0 :     time_t now;
     211           0 :     OM_uint32 left;
     212           0 :     const char *realm;
     213             : 
     214           0 :     if (!is_valid_password_cred_store(cred_store)) {
     215           0 :         *minor_status = GSS_KRB5_S_G_BAD_PASSWORD_CRED_STORE;
     216           0 :         return GSS_S_NO_CRED;
     217             :     }
     218             : 
     219           0 :     if (cred_usage == GSS_C_ACCEPT) {
     220             :         /*
     221             :          * TODO: Here we should eventually support user2user (when we get
     222             :          *       support for that via an extension to the mechanism
     223             :          *       allowing for more than two security context tokens),
     224             :          *       and/or new unique MEMORY keytabs (we have MEMORY keytab
     225             :          *       support, but we don't have a keytab equivalent of
     226             :          *       krb5_cc_new_unique()).  Either way, for now we can't
     227             :          *       support this.
     228             :          */
     229           0 :         *minor_status = ENOTSUP; /* XXX Better error? */
     230           0 :         return GSS_S_FAILURE;
     231             :     }
     232             : 
     233           0 :     memset(&cred, 0, sizeof(cred));
     234             : 
     235           0 :     if (handle->principal == NULL) {
     236           0 :         kret = krb5_get_default_principal(context, &handle->principal);
     237           0 :         if (kret)
     238           0 :             goto end;
     239             :     }
     240           0 :     realm = krb5_principal_get_realm(context, handle->principal);
     241             : 
     242           0 :     kret = krb5_get_init_creds_opt_alloc(context, &opt);
     243           0 :     if (kret == 0) {
     244           0 :         krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm,
     245             :                                                   opt);
     246           0 :         kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, 0,
     247             :                                     opt, &ctx);
     248             :     }
     249           0 :     if (kret == 0)
     250           0 :         kret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx);
     251           0 :     if (kret == 0)
     252           0 :         kret = krb5_init_creds_set_password(context, ctx, password);
     253             : 
     254             :     /*
     255             :      * Get the current time before the AS exchange so we don't
     256             :      * accidentally end up returning a value that puts advertised
     257             :      * expiration past the real expiration.
     258             :      *
     259             :      * We need to do this because krb5_cc_get_lifetime() returns a
     260             :      * relative time that we need to add to the current time.  We ought
     261             :      * to have a version of krb5_cc_get_lifetime() that returns absolute
     262             :      * time...
     263             :      */
     264           0 :     krb5_timeofday(context, &now);
     265             : 
     266           0 :     if (kret == 0)
     267           0 :         kret = krb5_init_creds_get(context, ctx);
     268           0 :     if (kret == 0)
     269           0 :         kret = krb5_init_creds_get_creds(context, ctx, &cred);
     270           0 :     if (kret == 0)
     271           0 :         kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
     272           0 :     if (kret == 0)
     273           0 :         kret = krb5_cc_initialize(context, ccache, cred.client);
     274           0 :     if (kret == 0)
     275           0 :         kret = krb5_init_creds_store(context, ctx, ccache);
     276           0 :     if (kret == 0)
     277           0 :         kret = krb5_cc_store_cred(context, ccache, &cred);
     278           0 :     if (kret)
     279           0 :         goto end;
     280             : 
     281           0 :     handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
     282             : 
     283           0 :     ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache,
     284             :                                     handle->principal, &left);
     285           0 :     if (ret != GSS_S_COMPLETE)
     286           0 :         goto end;
     287           0 :     handle->endtime = now + left;
     288           0 :     handle->ccache = ccache;
     289           0 :     ccache = NULL;
     290           0 :     ret = GSS_S_COMPLETE;
     291             : 
     292           0 : end:
     293           0 :     krb5_get_init_creds_opt_free(context, opt);
     294           0 :     if (ctx)
     295           0 :         krb5_init_creds_free(context, ctx);
     296           0 :     if (ccache != NULL)
     297           0 :         krb5_cc_destroy(context, ccache);
     298           0 :     if (cred.client != NULL)
     299           0 :         krb5_free_cred_contents(context, &cred);
     300           0 :     if (ret != GSS_S_COMPLETE)
     301           0 :         *minor_status = kret;
     302           0 :     return (ret);
     303             : }
     304             : 
     305             : /*
     306             :  * Acquires an initiator credential from a ccache or using a keytab.
     307             :  */
     308             : static OM_uint32
     309           0 : acquire_initiator_cred(OM_uint32 *minor_status,
     310             :                        krb5_context context,
     311             :                        OM_uint32 time_req,
     312             :                        gss_OID_set desired_mechs,
     313             :                        gss_cred_usage_t cred_usage,
     314             :                        gss_const_key_value_set_t cred_store,
     315             :                        gsskrb5_cred handle)
     316             : {
     317           0 :     OM_uint32 ret;
     318           0 :     krb5_creds cred;
     319           0 :     krb5_get_init_creds_opt *opt;
     320           0 :     krb5_principal def_princ = NULL;
     321           0 :     krb5_ccache def_ccache = NULL;
     322           0 :     krb5_ccache ccache = NULL;  /* we may store into this ccache */
     323           0 :     krb5_keytab keytab = NULL;
     324           0 :     krb5_error_code kret = 0;
     325           0 :     OM_uint32 left;
     326           0 :     const char *cs_ccache_name;
     327           0 :     time_t lifetime = 0;
     328           0 :     time_t now;
     329             : 
     330           0 :     memset(&cred, 0, sizeof(cred));
     331             : 
     332           0 :     ret = __gsskrb5_cred_store_find(minor_status, cred_store,
     333             :                                     "ccache", &cs_ccache_name);
     334           0 :     if (GSS_ERROR(ret))
     335           0 :         return ret;
     336             : 
     337           0 :     ret = GSS_S_FAILURE;
     338             : 
     339             :     /*
     340             :      * Get current time early so we can set handle->endtime to a value that
     341             :      * cannot accidentally be past the real endtime.  We need a variant of
     342             :      * krb5_cc_get_lifetime() that returns absolute endtime.
     343             :      */
     344           0 :     krb5_timeofday(context, &now);
     345             : 
     346             :     /*
     347             :      * First look for a ccache that has the desired_name (which may be
     348             :      * the default credential name), unless a specific credential cache
     349             :      * was included in cred_store.
     350             :      *
     351             :      * If we don't have an unexpired credential, acquire one with a
     352             :      * keytab.
     353             :      *
     354             :      * If we acquire one with a keytab, save it in the ccache we found
     355             :      * with the expired credential, if any.
     356             :      *
     357             :      * If we don't have any such ccache, then use a MEMORY ccache.
     358             :      */
     359             : 
     360           0 :     if (handle->principal != NULL && cs_ccache_name == NULL) {
     361             :         /*
     362             :          * Not default credential case.  See if we can find a ccache in
     363             :          * the cccol for the desired_name.
     364             :          */
     365           0 :         kret = krb5_cc_cache_match(context,
     366             :                                    handle->principal,
     367             :                                    &ccache);
     368           0 :         if (kret == 0) {
     369           0 :             kret = krb5_cc_get_lifetime(context, ccache, &lifetime);
     370           0 :             if (kret == 0) {
     371           0 :                 if (lifetime > 0)
     372           0 :                     goto found;
     373             :                 else
     374           0 :                     goto try_keytab;
     375             :             }
     376             :         }
     377             :         /*
     378             :          * Fall through.  We shouldn't find this in the default ccache
     379             :          * either, but we'll give it a try, then we'll try using a keytab.
     380             :          */
     381             :     }
     382             : 
     383             :     /*
     384             :      * Either desired_name was GSS_C_NO_NAME (default cred) or
     385             :      * krb5_cc_cache_match() failed (or found expired).
     386             :      */
     387           0 :     if (cs_ccache_name)
     388           0 :         kret = krb5_cc_resolve(context, cs_ccache_name, &def_ccache);
     389             :     else
     390           0 :         kret = krb5_cc_default(context, &def_ccache);
     391           0 :     if (kret != 0)
     392           0 :         goto try_keytab;
     393           0 :     kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime);
     394           0 :     if (kret != 0)
     395           0 :         lifetime = 0;
     396           0 :     kret = krb5_cc_get_principal(context, def_ccache, &def_princ);
     397           0 :     if (kret != 0)
     398           0 :         goto try_keytab;
     399             :     /*
     400             :      * Have a default ccache; see if it matches desired_name.
     401             :      */
     402           0 :     if (handle->principal == NULL ||
     403           0 :         krb5_principal_compare(context, handle->principal,
     404             :                                def_princ) == TRUE) {
     405             :         /*
     406             :          * It matches.
     407             :          *
     408             :          * If we end up trying a keytab then we can write the result to
     409             :          * the default ccache.
     410             :          */
     411           0 :         if (handle->principal == NULL) {
     412           0 :             kret = krb5_copy_principal(context, def_princ, &handle->principal);
     413           0 :             if (kret)
     414           0 :                 goto end;
     415             :         }
     416           0 :         if (ccache != NULL)
     417           0 :             krb5_cc_close(context, ccache);
     418           0 :         ccache = def_ccache;
     419           0 :         def_ccache = NULL;
     420           0 :         if (lifetime > 0)
     421           0 :             goto found;
     422             :         /* else we fall through and try using a keytab */
     423             :     }
     424             : 
     425           0 : try_keytab:
     426           0 :     if (handle->principal == NULL) {
     427             :         /* We need to know what client principal to use */
     428           0 :         kret = krb5_get_default_principal(context, &handle->principal);
     429           0 :         if (kret)
     430           0 :             goto end;
     431             :     }
     432           0 :     kret = get_client_keytab(context, cred_store, handle->principal, &keytab);
     433           0 :     if (kret)
     434           0 :         goto end;
     435             : 
     436           0 :     kret = krb5_get_init_creds_opt_alloc(context, &opt);
     437           0 :     if (kret)
     438           0 :         goto end;
     439           0 :     krb5_timeofday(context, &now);
     440           0 :     kret = krb5_get_init_creds_keytab(context, &cred, handle->principal,
     441             :                                       keytab, 0, NULL, opt);
     442           0 :     krb5_get_init_creds_opt_free(context, opt);
     443           0 :     if (kret)
     444           0 :         goto end;
     445             : 
     446             :     /*
     447             :      * We got a credential with a keytab.  Save it if we can.
     448             :      */
     449           0 :     if (ccache == NULL) {
     450             :         /*
     451             :          * There's no ccache we can overwrite with the credentials we acquired
     452             :          * with a keytab.  We'll use a MEMORY ccache then.
     453             :          *
     454             :          * Note that an application that falls into this repeatedly will do an
     455             :          * AS exchange every time it acquires a credential handle.  Hopefully
     456             :          * this doesn't happen much.  A workaround is to kinit -k once so that
     457             :          * we always re-initialize the matched/default ccache here.  I.e., once
     458             :          * there's a FILE/DIR ccache, we'll keep it frash automatically if we
     459             :          * have a keytab, but if there's no FILE/DIR ccache, then we'll
     460             :          * get a fresh credential *every* time we're asked.
     461             :          */
     462           0 :         kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
     463           0 :         if (kret)
     464           0 :             goto end;
     465           0 :         handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
     466             :     } /* else we'll re-initialize whichever ccache we matched above */
     467             : 
     468           0 :     kret = krb5_cc_initialize(context, ccache, cred.client);
     469           0 :     if (kret)
     470           0 :         goto end;
     471           0 :     kret = krb5_cc_store_cred(context, ccache, &cred);
     472           0 :     if (kret)
     473           0 :         goto end;
     474             : 
     475           0 : found:
     476           0 :     assert(handle->principal != NULL);
     477           0 :     ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache,
     478             :                                     handle->principal, &left);
     479           0 :     if (ret != GSS_S_COMPLETE)
     480           0 :         goto end;
     481           0 :     handle->endtime = now + left;
     482           0 :     handle->ccache = ccache;
     483           0 :     ccache = NULL;
     484           0 :     ret = GSS_S_COMPLETE;
     485           0 :     kret = 0;
     486             : 
     487           0 : end:
     488           0 :     if (ccache != NULL) {
     489           0 :         if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0)
     490           0 :             krb5_cc_destroy(context, ccache);
     491             :         else
     492           0 :             krb5_cc_close(context, ccache);
     493             :     }
     494           0 :     if (def_ccache != NULL)
     495           0 :         krb5_cc_close(context, def_ccache);
     496           0 :     if (cred.client != NULL)
     497           0 :         krb5_free_cred_contents(context, &cred);
     498           0 :     if (def_princ != NULL)
     499           0 :         krb5_free_principal(context, def_princ);
     500           0 :     if (keytab != NULL)
     501           0 :         krb5_kt_close(context, keytab);
     502           0 :     if (ret != GSS_S_COMPLETE && kret != 0)
     503           0 :         *minor_status = kret;
     504           0 :     return (ret);
     505             : }
     506             : 
     507             : static OM_uint32
     508           0 : acquire_acceptor_cred(OM_uint32 * minor_status,
     509             :                       krb5_context context,
     510             :                       OM_uint32 time_req,
     511             :                       gss_OID_set desired_mechs,
     512             :                       gss_cred_usage_t cred_usage,
     513             :                       gss_const_key_value_set_t cred_store,
     514             :                       gsskrb5_cred handle)
     515             : {
     516           0 :     OM_uint32 ret;
     517           0 :     krb5_error_code kret;
     518             : 
     519           0 :     ret = GSS_S_FAILURE;
     520             : 
     521           0 :     kret = get_system_keytab(context, cred_store, &handle->keytab);
     522           0 :     if (kret)
     523           0 :         goto end;
     524             : 
     525             :     /* check that the requested principal exists in the keytab */
     526           0 :     if (handle->principal) {
     527           0 :         krb5_keytab_entry entry;
     528             : 
     529           0 :         kret = krb5_kt_get_entry(context, handle->keytab,
     530           0 :                                  handle->principal, 0, 0, &entry);
     531           0 :         if (kret)
     532           0 :             goto end;
     533           0 :         krb5_kt_free_entry(context, &entry);
     534           0 :         ret = GSS_S_COMPLETE;
     535             :     } else {
     536             :         /*
     537             :          * Check if there is at least one entry in the keytab before
     538             :          * declaring it as an useful keytab.
     539             :          */
     540           0 :         krb5_keytab_entry tmp;
     541           0 :         krb5_kt_cursor c;
     542             : 
     543           0 :         kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
     544           0 :         if (kret)
     545           0 :             goto end;
     546           0 :         if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
     547           0 :             krb5_kt_free_entry(context, &tmp);
     548           0 :             ret = GSS_S_COMPLETE; /* ok found one entry */
     549             :         }
     550           0 :         krb5_kt_end_seq_get (context, handle->keytab, &c);
     551             :     }
     552           0 : end:
     553           0 :     if (ret != GSS_S_COMPLETE) {
     554           0 :         if (handle->keytab != NULL)
     555           0 :             krb5_kt_close(context, handle->keytab);
     556           0 :         if (kret != 0) {
     557           0 :             *minor_status = kret;
     558             :         }
     559             :     }
     560           0 :     return (ret);
     561             : }
     562             : 
     563             : 
     564           0 : OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_from
     565             : (OM_uint32 * minor_status,
     566             :  gss_const_name_t desired_name,
     567             :  OM_uint32 time_req,
     568             :  gss_OID_set desired_mechs,
     569             :  gss_cred_usage_t cred_usage,
     570             :  gss_const_key_value_set_t cred_store,
     571             :  gss_cred_id_t * output_cred_handle,
     572             :  gss_OID_set *actual_mechs,
     573             :  OM_uint32 *time_rec
     574             :     )
     575             : {
     576           0 :     krb5_context context;
     577           0 :     gsskrb5_cred handle;
     578           0 :     OM_uint32 ret;
     579           0 :     const char *password = NULL;
     580             : 
     581           0 :     if (desired_mechs) {
     582           0 :         int present = 0;
     583             : 
     584           0 :         ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
     585             :                                       desired_mechs, &present);
     586           0 :         if (ret)
     587           0 :             return ret;
     588           0 :         if (!present) {
     589           0 :             *minor_status = 0;
     590           0 :             return GSS_S_BAD_MECH;
     591             :         }
     592             :     }
     593             : 
     594           0 :     cred_usage &= GSS_C_OPTION_MASK;
     595             : 
     596           0 :     if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE &&
     597             :         cred_usage != GSS_C_BOTH) {
     598           0 :         *minor_status = GSS_KRB5_S_G_BAD_USAGE;
     599           0 :         return GSS_S_FAILURE;
     600             :     }
     601             : 
     602           0 :     ret = __gsskrb5_cred_store_find(minor_status, cred_store,
     603             :                                     "password", &password);
     604           0 :     if (GSS_ERROR(ret))
     605           0 :         return ret;
     606             : 
     607           0 :     GSSAPI_KRB5_INIT(&context);
     608             : 
     609           0 :     *output_cred_handle = GSS_C_NO_CREDENTIAL;
     610             : 
     611           0 :     handle = calloc(1, sizeof(*handle));
     612           0 :     if (handle == NULL) {
     613           0 :         *minor_status = ENOMEM;
     614           0 :         return GSS_S_FAILURE;
     615             :     }
     616             : 
     617           0 :     handle->destination_realm = NULL;
     618           0 :     HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
     619             : 
     620           0 :     if (desired_name != GSS_C_NO_NAME) {
     621           0 :         ret = _gsskrb5_canon_name(minor_status, context,
     622             :                                   desired_name, &handle->principal);
     623           0 :         if (ret) {
     624           0 :             HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
     625           0 :             free(handle);
     626           0 :             return ret;
     627             :         }
     628             :     }
     629             : 
     630           0 :     if (password) {
     631           0 :         ret = acquire_cred_with_password(minor_status, context, password, time_req,
     632             :                                          desired_mechs, cred_usage, cred_store, handle);
     633           0 :         if (ret != GSS_S_COMPLETE) {
     634           0 :             HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
     635           0 :             krb5_free_principal(context, handle->principal);
     636           0 :             free(handle);
     637           0 :             return (ret);
     638             :         }
     639             :     } else {
     640             :         /*
     641             :          * Acquire a credential from the specified or background credential
     642             :          * store (ccache, keytab).
     643             :          */
     644           0 :         if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
     645           0 :             ret = acquire_initiator_cred(minor_status, context, time_req,
     646             :                                          desired_mechs, cred_usage,
     647             :                                          cred_store, handle);
     648           0 :             if (ret != GSS_S_COMPLETE) {
     649           0 :                 HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
     650           0 :                 krb5_free_principal(context, handle->principal);
     651           0 :                 free(handle);
     652           0 :                 return (ret);
     653             :             }
     654             :         }
     655           0 :         if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
     656           0 :             ret = acquire_acceptor_cred(minor_status, context, time_req,
     657             :                                         desired_mechs, cred_usage,
     658             :                                         cred_store, handle);
     659           0 :             if (ret != GSS_S_COMPLETE) {
     660           0 :                 HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
     661           0 :                 krb5_free_principal(context, handle->principal);
     662           0 :                 free(handle);
     663           0 :                 return (ret);
     664             :             }
     665             :         }
     666             :     }
     667           0 :     ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
     668           0 :     if (ret == GSS_S_COMPLETE)
     669           0 :         ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
     670             :                                      &handle->mechanisms);
     671           0 :     handle->usage = cred_usage;
     672           0 :     if (ret == GSS_S_COMPLETE)
     673           0 :         ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle,
     674             :                                     NULL, time_rec, NULL, actual_mechs);
     675           0 :     if (ret != GSS_S_COMPLETE) {
     676           0 :         if (handle->mechanisms != NULL)
     677           0 :             gss_release_oid_set(NULL, &handle->mechanisms);
     678           0 :         HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
     679           0 :         krb5_free_principal(context, handle->principal);
     680           0 :         free(handle);
     681           0 :         return (ret);
     682             :     }
     683           0 :     *minor_status = 0;
     684           0 :     *output_cred_handle = (gss_cred_id_t)handle;
     685           0 :     return (GSS_S_COMPLETE);
     686             : }

Generated by: LCOV version 1.14