LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - acache.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 15 557 2.7 %
Date: 2024-06-13 04:01:37 Functions: 2 30 6.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "krb5_locl.h"
      37             : #include <krb5_ccapi.h>
      38             : 
      39             : #ifndef KCM_IS_API_CACHE
      40             : 
      41             : static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
      42             : static cc_initialize_func init_func;
      43             : static void (KRB5_CALLCONV *set_target_uid)(uid_t);
      44             : static void (KRB5_CALLCONV *clear_target)(void);
      45             : 
      46             : #ifdef HAVE_DLOPEN
      47             : static void *cc_handle;
      48             : #endif
      49             : 
      50             : typedef struct krb5_acc {
      51             :     char *cache_name;
      52             :     char *cache_subsidiary;
      53             :     cc_context_t context;
      54             :     cc_ccache_t ccache;
      55             : } krb5_acc;
      56             : 
      57             : static krb5_error_code KRB5_CALLCONV acc_close(krb5_context, krb5_ccache);
      58             : 
      59             : #define ACACHE(X) ((krb5_acc *)(X)->data.data)
      60             : 
      61             : static const struct {
      62             :     cc_int32 error;
      63             :     krb5_error_code ret;
      64             : } cc_errors[] = {
      65             :     { ccErrBadName,             KRB5_CC_BADNAME },
      66             :     { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
      67             :     { ccErrCCacheNotFound,      KRB5_FCC_NOFILE },
      68             :     { ccErrContextNotFound,     KRB5_CC_NOTFOUND },
      69             :     { ccIteratorEnd,            KRB5_CC_END },
      70             :     { ccErrNoMem,               KRB5_CC_NOMEM },
      71             :     { ccErrServerUnavailable,   KRB5_CC_NOSUPP },
      72             :     { ccErrInvalidCCache,       KRB5_CC_BADNAME },
      73             :     { ccNoError,                0 }
      74             : };
      75             : 
      76             : static krb5_error_code
      77           0 : translate_cc_error(krb5_context context, cc_int32 error)
      78             : {
      79             :     size_t i;
      80           0 :     krb5_clear_error_message(context);
      81           0 :     for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++)
      82           0 :         if (cc_errors[i].error == error)
      83           0 :             return cc_errors[i].ret;
      84           0 :     return KRB5_FCC_INTERNAL;
      85             : }
      86             : 
      87             : static krb5_error_code
      88           1 : init_ccapi(krb5_context context)
      89             : {
      90           1 :     const char *lib = NULL;
      91           1 :     char *explib = NULL;
      92             : 
      93             :     HEIMDAL_MUTEX_lock(&acc_mutex);
      94           1 :     if (init_func) {
      95             :         HEIMDAL_MUTEX_unlock(&acc_mutex);
      96           0 :         if (context)
      97           0 :             krb5_clear_error_message(context);
      98           0 :         return 0;
      99             :     }
     100             : 
     101           1 :     if (context)
     102           1 :         lib = krb5_config_get_string(context, NULL,
     103             :                                      "libdefaults", "ccapi_library",
     104             :                                      NULL);
     105           1 :     if (lib == NULL) {
     106             : #ifdef __APPLE__
     107             :         lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos";
     108             : #elif defined(_WIN32)
     109             :         lib = "%{LIBDIR}/libkrb5_cc.dll";
     110             : #else
     111           1 :         lib = "%{LIBDIR}/libkrb5_cc.so";
     112             : #endif
     113             :     }
     114             : 
     115             : #ifdef HAVE_DLOPEN
     116             : 
     117             :     if (_krb5_expand_path_tokens(context, lib, 0, &explib) == 0) {
     118             :         cc_handle = dlopen(explib, RTLD_LAZY|RTLD_LOCAL|RTLD_GROUP);
     119             :         free(explib);
     120             :     }
     121             : 
     122             :     if (cc_handle == NULL) {
     123             :         HEIMDAL_MUTEX_unlock(&acc_mutex);
     124             :         krb5_set_error_message(context, KRB5_CC_NOSUPP,
     125             :                                N_("Failed to load API cache module %s", "file"),
     126             :                                lib);
     127             :         return KRB5_CC_NOSUPP;
     128             :     }
     129             : 
     130             :     init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize");
     131             :     set_target_uid = (void (KRB5_CALLCONV *)(uid_t))
     132             :         dlsym(cc_handle, "krb5_ipc_client_set_target_uid");
     133             :     clear_target = (void (KRB5_CALLCONV *)(void))
     134             :         dlsym(cc_handle, "krb5_ipc_client_clear_target");
     135             :     HEIMDAL_MUTEX_unlock(&acc_mutex);
     136             :     if (init_func == NULL) {
     137             :         krb5_set_error_message(context, KRB5_CC_NOSUPP,
     138             :                                N_("Failed to find cc_initialize"
     139             :                                   "in %s: %s", "file, error"), lib, dlerror());
     140             :         dlclose(cc_handle);
     141             :         return KRB5_CC_NOSUPP;
     142             :     }
     143             : 
     144             :     return 0;
     145             : #else
     146             :     HEIMDAL_MUTEX_unlock(&acc_mutex);
     147           1 :     krb5_set_error_message(context, KRB5_CC_NOSUPP,
     148           1 :                            N_("no support for shared object", ""));
     149           1 :     return KRB5_CC_NOSUPP;
     150             : #endif
     151             : }
     152             : 
     153             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     154           0 : _heim_krb5_ipc_client_set_target_uid(uid_t uid)
     155             : {
     156           0 :     init_ccapi(NULL);
     157           0 :     if (set_target_uid != NULL)
     158           0 :         (*set_target_uid)(uid);
     159           0 : }
     160             : 
     161             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     162           0 : _heim_krb5_ipc_client_clear_target(void)
     163             : {
     164           0 :     init_ccapi(NULL);
     165           0 :     if (clear_target != NULL)
     166           0 :         (*clear_target)();
     167           0 : }
     168             : 
     169             : static krb5_error_code
     170           0 : make_cred_from_ccred(krb5_context context,
     171             :                      const cc_credentials_v5_t *incred,
     172             :                      krb5_creds *cred)
     173             : {
     174             :     krb5_error_code ret;
     175             :     unsigned int i;
     176             : 
     177           0 :     memset(cred, 0, sizeof(*cred));
     178             : 
     179           0 :     ret = krb5_parse_name(context, incred->client, &cred->client);
     180           0 :     if (ret)
     181           0 :         goto fail;
     182             : 
     183           0 :     ret = krb5_parse_name(context, incred->server, &cred->server);
     184           0 :     if (ret)
     185           0 :         goto fail;
     186             : 
     187           0 :     cred->session.keytype = incred->keyblock.type;
     188           0 :     cred->session.keyvalue.length = incred->keyblock.length;
     189           0 :     cred->session.keyvalue.data = malloc(incred->keyblock.length);
     190           0 :     if (cred->session.keyvalue.data == NULL)
     191           0 :         goto nomem;
     192           0 :     memcpy(cred->session.keyvalue.data, incred->keyblock.data,
     193           0 :            incred->keyblock.length);
     194             : 
     195           0 :     cred->times.authtime = incred->authtime;
     196           0 :     cred->times.starttime = incred->starttime;
     197           0 :     cred->times.endtime = incred->endtime;
     198           0 :     cred->times.renew_till = incred->renew_till;
     199             : 
     200           0 :     ret = krb5_data_copy(&cred->ticket,
     201           0 :                          incred->ticket.data,
     202           0 :                          incred->ticket.length);
     203           0 :     if (ret)
     204           0 :         goto nomem;
     205             : 
     206           0 :     ret = krb5_data_copy(&cred->second_ticket,
     207           0 :                          incred->second_ticket.data,
     208           0 :                          incred->second_ticket.length);
     209           0 :     if (ret)
     210           0 :         goto nomem;
     211             : 
     212           0 :     cred->authdata.val = NULL;
     213           0 :     cred->authdata.len = 0;
     214             : 
     215           0 :     cred->addresses.val = NULL;
     216           0 :     cred->addresses.len = 0;
     217             : 
     218           0 :     for (i = 0; incred->authdata && incred->authdata[i]; i++)
     219             :         ;
     220             : 
     221           0 :     if (i) {
     222           0 :         cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0]));
     223           0 :         if (cred->authdata.val == NULL)
     224           0 :             goto nomem;
     225           0 :         cred->authdata.len = i;
     226           0 :         for (i = 0; i < cred->authdata.len; i++) {
     227           0 :             cred->authdata.val[i].ad_type = incred->authdata[i]->type;
     228           0 :             ret = krb5_data_copy(&cred->authdata.val[i].ad_data,
     229           0 :                                  incred->authdata[i]->data,
     230           0 :                                  incred->authdata[i]->length);
     231           0 :             if (ret)
     232           0 :                 goto nomem;
     233             :         }
     234             :     }
     235             : 
     236           0 :     for (i = 0; incred->addresses && incred->addresses[i]; i++)
     237             :         ;
     238             : 
     239           0 :     if (i) {
     240           0 :         cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0]));
     241           0 :         if (cred->addresses.val == NULL)
     242           0 :             goto nomem;
     243           0 :         cred->addresses.len = i;
     244             : 
     245           0 :         for (i = 0; i < cred->addresses.len; i++) {
     246           0 :             cred->addresses.val[i].addr_type = incred->addresses[i]->type;
     247           0 :             ret = krb5_data_copy(&cred->addresses.val[i].address,
     248           0 :                                  incred->addresses[i]->data,
     249           0 :                                  incred->addresses[i]->length);
     250           0 :             if (ret)
     251           0 :                 goto nomem;
     252             :         }
     253             :     }
     254             : 
     255           0 :     cred->flags.i = 0;
     256           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE)
     257           0 :         cred->flags.b.forwardable = 1;
     258           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED)
     259           0 :         cred->flags.b.forwarded = 1;
     260           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE)
     261           0 :         cred->flags.b.proxiable = 1;
     262           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY)
     263           0 :         cred->flags.b.proxy = 1;
     264           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE)
     265           0 :         cred->flags.b.may_postdate = 1;
     266           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED)
     267           0 :         cred->flags.b.postdated = 1;
     268           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID)
     269           0 :         cred->flags.b.invalid = 1;
     270           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE)
     271           0 :         cred->flags.b.renewable = 1;
     272           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL)
     273           0 :         cred->flags.b.initial = 1;
     274           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH)
     275           0 :         cred->flags.b.pre_authent = 1;
     276           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH)
     277           0 :         cred->flags.b.hw_authent = 1;
     278           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED)
     279           0 :         cred->flags.b.transited_policy_checked = 1;
     280           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE)
     281           0 :         cred->flags.b.ok_as_delegate = 1;
     282           0 :     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS)
     283           0 :         cred->flags.b.anonymous = 1;
     284             : 
     285           0 :     return 0;
     286             : 
     287           0 : nomem:
     288           0 :     ret = krb5_enomem(context);
     289             : 
     290           0 : fail:
     291           0 :     krb5_free_cred_contents(context, cred);
     292           0 :     return ret;
     293             : }
     294             : 
     295             : static void
     296           0 : free_ccred(cc_credentials_v5_t *cred)
     297             : {
     298             :     int i;
     299             : 
     300           0 :     if (cred->addresses) {
     301           0 :         for (i = 0; cred->addresses[i] != 0; i++) {
     302           0 :             if (cred->addresses[i]->data)
     303           0 :                 free(cred->addresses[i]->data);
     304           0 :             free(cred->addresses[i]);
     305             :         }
     306           0 :         free(cred->addresses);
     307             :     }
     308           0 :     if (cred->server)
     309           0 :         free(cred->server);
     310           0 :     if (cred->client)
     311           0 :         free(cred->client);
     312           0 :     memset(cred, 0, sizeof(*cred));
     313           0 : }
     314             : 
     315             : static krb5_error_code
     316           0 : make_ccred_from_cred(krb5_context context,
     317             :                      const krb5_creds *incred,
     318             :                      cc_credentials_v5_t *cred)
     319             : {
     320             :     krb5_error_code ret;
     321             :     size_t i;
     322             : 
     323           0 :     memset(cred, 0, sizeof(*cred));
     324             : 
     325           0 :     ret = krb5_unparse_name(context, incred->client, &cred->client);
     326           0 :     if (ret)
     327           0 :         goto fail;
     328             : 
     329           0 :     ret = krb5_unparse_name(context, incred->server, &cred->server);
     330           0 :     if (ret)
     331           0 :         goto fail;
     332             : 
     333           0 :     cred->keyblock.type = incred->session.keytype;
     334           0 :     cred->keyblock.length = incred->session.keyvalue.length;
     335           0 :     cred->keyblock.data = incred->session.keyvalue.data;
     336             : 
     337           0 :     cred->authtime = incred->times.authtime;
     338           0 :     cred->starttime = incred->times.starttime;
     339           0 :     cred->endtime = incred->times.endtime;
     340           0 :     cred->renew_till = incred->times.renew_till;
     341             : 
     342           0 :     cred->ticket.length = incred->ticket.length;
     343           0 :     cred->ticket.data = incred->ticket.data;
     344             : 
     345           0 :     cred->second_ticket.length = incred->second_ticket.length;
     346           0 :     cred->second_ticket.data = incred->second_ticket.data;
     347             : 
     348             :     /* XXX this one should also be filled in */
     349           0 :     cred->authdata = NULL;
     350             : 
     351           0 :     cred->addresses = calloc(incred->addresses.len + 1,
     352             :                              sizeof(cred->addresses[0]));
     353           0 :     if (cred->addresses == NULL) {
     354             : 
     355           0 :         ret = ENOMEM;
     356           0 :         goto fail;
     357             :     }
     358             : 
     359           0 :     for (i = 0; i < incred->addresses.len; i++) {
     360             :         cc_data *addr;
     361           0 :         addr = malloc(sizeof(*addr));
     362           0 :         if (addr == NULL) {
     363           0 :             ret = ENOMEM;
     364           0 :             goto fail;
     365             :         }
     366           0 :         addr->type = incred->addresses.val[i].addr_type;
     367           0 :         addr->length = incred->addresses.val[i].address.length;
     368           0 :         addr->data = malloc(addr->length);
     369           0 :         if (addr->data == NULL) {
     370           0 :             free(addr);
     371           0 :             ret = ENOMEM;
     372           0 :             goto fail;
     373             :         }
     374           0 :         memcpy(addr->data, incred->addresses.val[i].address.data,
     375           0 :                addr->length);
     376           0 :         cred->addresses[i] = addr;
     377             :     }
     378           0 :     cred->addresses[i] = NULL;
     379             : 
     380           0 :     cred->ticket_flags = 0;
     381           0 :     if (incred->flags.b.forwardable)
     382           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE;
     383           0 :     if (incred->flags.b.forwarded)
     384           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED;
     385           0 :     if (incred->flags.b.proxiable)
     386           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE;
     387           0 :     if (incred->flags.b.proxy)
     388           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY;
     389           0 :     if (incred->flags.b.may_postdate)
     390           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE;
     391           0 :     if (incred->flags.b.postdated)
     392           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED;
     393           0 :     if (incred->flags.b.invalid)
     394           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID;
     395           0 :     if (incred->flags.b.renewable)
     396           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE;
     397           0 :     if (incred->flags.b.initial)
     398           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL;
     399           0 :     if (incred->flags.b.pre_authent)
     400           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH;
     401           0 :     if (incred->flags.b.hw_authent)
     402           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH;
     403           0 :     if (incred->flags.b.transited_policy_checked)
     404           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED;
     405           0 :     if (incred->flags.b.ok_as_delegate)
     406           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE;
     407           0 :     if (incred->flags.b.anonymous)
     408           0 :         cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS;
     409             : 
     410           0 :     return 0;
     411             : 
     412           0 : fail:
     413           0 :     free_ccred(cred);
     414             : 
     415           0 :     krb5_clear_error_message(context);
     416           0 :     return ret;
     417             : }
     418             : 
     419             : static cc_int32
     420           0 : get_cc_name(krb5_acc *a)
     421             : {
     422             :     cc_string_t name;
     423             :     cc_int32 error;
     424             : 
     425           0 :     error = (*a->ccache->func->get_name)(a->ccache, &name);
     426           0 :     if (error)
     427           0 :         return error;
     428             : 
     429           0 :     a->cache_name = strdup(name->data);
     430           0 :     (*name->func->release)(name);
     431           0 :     if (a->cache_name == NULL)
     432           0 :         return ccErrNoMem;
     433           0 :     return ccNoError;
     434             : }
     435             : 
     436             : 
     437             : static krb5_error_code KRB5_CALLCONV
     438           0 : acc_get_name_2(krb5_context context,
     439             :                krb5_ccache id,
     440             :                const char **name,
     441             :                const char **colname,
     442             :                const char **subsidiary)
     443             : {
     444           0 :     krb5_error_code ret = 0;
     445           0 :     krb5_acc *a = ACACHE(id);
     446             :     int32_t error;
     447             : 
     448           0 :     if (name)
     449           0 :         *name = NULL;
     450           0 :     if (colname)
     451           0 :         *colname = NULL;
     452           0 :     if (subsidiary)
     453           0 :         *subsidiary = NULL;
     454           0 :     if (a->cache_subsidiary == NULL) {
     455           0 :         krb5_principal principal = NULL;
     456             : 
     457           0 :         ret = _krb5_get_default_principal_local(context, &principal);
     458           0 :         if (ret == 0)
     459           0 :             ret = krb5_unparse_name(context, principal, &a->cache_subsidiary);
     460           0 :         krb5_free_principal(context, principal);
     461           0 :         if (ret)
     462           0 :             return ret;
     463             :     }
     464             : 
     465           0 :     if (a->cache_name == NULL) {
     466           0 :         error = (*a->context->func->create_new_ccache)(a->context,
     467             :                                                        cc_credentials_v5,
     468           0 :                                                        a->cache_subsidiary,
     469             :                                                        &a->ccache);
     470           0 :         if (error == ccNoError)
     471           0 :             error = get_cc_name(a);
     472           0 :         if (error != ccNoError)
     473           0 :             ret = translate_cc_error(context, error);
     474             :     }
     475           0 :     if (name)
     476           0 :         *name = a->cache_name;
     477           0 :     if (colname)
     478           0 :         *colname = "";
     479           0 :     if (subsidiary)
     480           0 :         *subsidiary = a->cache_subsidiary;
     481           0 :     return ret;
     482             : }
     483             : 
     484             : static krb5_error_code KRB5_CALLCONV
     485           0 : acc_alloc(krb5_context context, krb5_ccache *id)
     486             : {
     487             :     krb5_error_code ret;
     488             :     cc_int32 error;
     489             :     krb5_acc *a;
     490             : 
     491           0 :     ret = init_ccapi(context);
     492           0 :     if (ret)
     493           0 :         return ret;
     494             : 
     495           0 :     ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
     496           0 :     if (ret) {
     497           0 :         krb5_clear_error_message(context);
     498           0 :         return ret;
     499             :     }
     500             : 
     501           0 :     a = ACACHE(*id);
     502           0 :     a->cache_subsidiary = NULL;
     503           0 :     a->cache_name = NULL;
     504           0 :     a->context = NULL;
     505           0 :     a->ccache = NULL;
     506             : 
     507           0 :     error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
     508           0 :     if (error) {
     509           0 :         krb5_data_free(&(*id)->data);
     510           0 :         return translate_cc_error(context, error);
     511             :     }
     512             : 
     513           0 :     return 0;
     514             : }
     515             : 
     516             : static krb5_error_code KRB5_CALLCONV
     517           0 : acc_resolve_2(krb5_context context, krb5_ccache *id, const char *res, const char *sub)
     518             : {
     519             :     krb5_error_code ret;
     520             :     cc_time_t offset;
     521             :     cc_int32 error;
     522             :     krb5_acc *a;
     523           0 :     char *s = NULL;
     524             : 
     525           0 :     ret = acc_alloc(context, id);
     526           0 :     if (ret)
     527           0 :         return ret;
     528             : 
     529           0 :     a = ACACHE(*id);
     530             : 
     531           0 :     if (sub) {
     532             :         /*
     533             :          * For API there's no such thing as a collection name, there's only the
     534             :          * default collection.  Though we could perhaps put a CCAPI shared
     535             :          * object path in the collection name.
     536             :          *
     537             :          * So we'll treat (res && !sub) and (!res && sub) as the same cases.
     538             :          *
     539             :          * See also the KCM ccache type, where we have similar considerations.
     540             :          */
     541           0 :         if (asprintf(&s, "%s%s%s", res && *res ? res : "",
     542           0 :                      res && *res ? ":" : "", sub) == -1 || s == NULL ||
     543           0 :             (a->cache_subsidiary = strdup(sub)) == NULL) {
     544           0 :             acc_close(context, *id);
     545           0 :             free(s);
     546           0 :             return krb5_enomem(context);
     547             :         }
     548           0 :         res = s;
     549             :         /*
     550             :          * XXX With a bit of extra refactoring we could use the collection name
     551             :          * as the path to the shared object implementing CCAPI...  For now we
     552             :          * ignore the collection name.
     553             :          */
     554             :     }
     555             : 
     556           0 :     error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
     557           0 :     if (error == ccErrCCacheNotFound) {
     558           0 :         a->ccache = NULL;
     559           0 :         a->cache_name = NULL;
     560           0 :         free(s);
     561           0 :         return 0;
     562             :     }
     563           0 :     if (error == ccNoError)
     564           0 :         error = get_cc_name(a);
     565           0 :     if (error != ccNoError) {
     566           0 :         acc_close(context, *id);
     567           0 :         *id = NULL;
     568           0 :         free(s);
     569           0 :         return translate_cc_error(context, error);
     570             :     }
     571             : 
     572           0 :     error = (*a->ccache->func->get_kdc_time_offset)(a->ccache,
     573             :                                                     cc_credentials_v5,
     574             :                                                     &offset);
     575           0 :     if (error == 0)
     576           0 :         context->kdc_sec_offset = offset;
     577           0 :     free(s);
     578           0 :     return 0;
     579             : }
     580             : 
     581             : static krb5_error_code KRB5_CALLCONV
     582           0 : acc_gen_new(krb5_context context, krb5_ccache *id)
     583             : {
     584           0 :     return acc_alloc(context, id);
     585             : }
     586             : 
     587             : static krb5_error_code KRB5_CALLCONV
     588           0 : acc_initialize(krb5_context context,
     589             :                krb5_ccache id,
     590             :                krb5_principal primary_principal)
     591             : {
     592           0 :     krb5_acc *a = ACACHE(id);
     593             :     krb5_error_code ret;
     594             :     int32_t error;
     595             :     char *name;
     596             : 
     597           0 :     ret = krb5_unparse_name(context, primary_principal, &name);
     598           0 :     if (ret)
     599           0 :         return ret;
     600             : 
     601           0 :     if (a->cache_name == NULL) {
     602           0 :         error = (*a->context->func->create_new_ccache)(a->context,
     603             :                                                        cc_credentials_v5,
     604             :                                                        name,
     605             :                                                        &a->ccache);
     606           0 :         free(name);
     607           0 :         if (error == ccNoError)
     608           0 :             error = get_cc_name(a);
     609             :     } else {
     610             :         cc_credentials_iterator_t iter;
     611             :         cc_credentials_t ccred;
     612             : 
     613           0 :         error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
     614           0 :         if (error) {
     615           0 :             free(name);
     616           0 :             return translate_cc_error(context, error);
     617             :         }
     618             : 
     619             :         while (1) {
     620           0 :             error = (*iter->func->next)(iter, &ccred);
     621           0 :             if (error)
     622           0 :                 break;
     623           0 :             (*a->ccache->func->remove_credentials)(a->ccache, ccred);
     624           0 :             (*ccred->func->release)(ccred);
     625             :         }
     626           0 :         (*iter->func->release)(iter);
     627             : 
     628           0 :         error = (*a->ccache->func->set_principal)(a->ccache,
     629             :                                                   cc_credentials_v5,
     630             :                                                   name);
     631             :     }
     632             : 
     633           0 :     if (error == 0 && context->kdc_sec_offset)
     634           0 :         error = (*a->ccache->func->set_kdc_time_offset)(a->ccache,
     635             :                                                         cc_credentials_v5,
     636           0 :                                                         context->kdc_sec_offset);
     637             : 
     638           0 :     return translate_cc_error(context, error);
     639             : }
     640             : 
     641             : static krb5_error_code KRB5_CALLCONV
     642           0 : acc_close(krb5_context context,
     643             :           krb5_ccache id)
     644             : {
     645           0 :     krb5_acc *a = ACACHE(id);
     646             : 
     647           0 :     if (a->ccache) {
     648           0 :         (*a->ccache->func->release)(a->ccache);
     649           0 :         a->ccache = NULL;
     650             :     }
     651           0 :     if (a->cache_name) {
     652           0 :         free(a->cache_name);
     653           0 :         a->cache_name = NULL;
     654             :     }
     655           0 :     if (a->context) {
     656           0 :         (*a->context->func->release)(a->context);
     657           0 :         a->context = NULL;
     658             :     }
     659           0 :     krb5_data_free(&id->data);
     660           0 :     return 0;
     661             : }
     662             : 
     663             : static krb5_error_code KRB5_CALLCONV
     664           0 : acc_destroy(krb5_context context,
     665             :             krb5_ccache id)
     666             : {
     667           0 :     krb5_acc *a = ACACHE(id);
     668           0 :     cc_int32 error = 0;
     669             : 
     670           0 :     if (a->ccache) {
     671           0 :         error = (*a->ccache->func->destroy)(a->ccache);
     672           0 :         a->ccache = NULL;
     673             :     }
     674           0 :     if (a->context) {
     675           0 :         error = (a->context->func->release)(a->context);
     676           0 :         a->context = NULL;
     677             :     }
     678           0 :     return translate_cc_error(context, error);
     679             : }
     680             : 
     681             : static krb5_error_code KRB5_CALLCONV
     682           0 : acc_store_cred(krb5_context context,
     683             :                krb5_ccache id,
     684             :                krb5_creds *creds)
     685             : {
     686           0 :     krb5_acc *a = ACACHE(id);
     687             :     cc_credentials_union cred;
     688             :     cc_credentials_v5_t v5cred;
     689             :     krb5_error_code ret;
     690             :     cc_int32 error;
     691             : 
     692           0 :     if (a->ccache == NULL) {
     693           0 :         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
     694           0 :                                N_("No API credential found", ""));
     695           0 :         return KRB5_CC_NOTFOUND;
     696             :     }
     697             : 
     698           0 :     cred.version = cc_credentials_v5;
     699           0 :     cred.credentials.credentials_v5 = &v5cred;
     700             : 
     701           0 :     ret = make_ccred_from_cred(context,
     702             :                                creds,
     703             :                                &v5cred);
     704           0 :     if (ret)
     705           0 :         return ret;
     706             : 
     707           0 :     error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
     708           0 :     if (error)
     709           0 :         ret = translate_cc_error(context, error);
     710             : 
     711           0 :     free_ccred(&v5cred);
     712             : 
     713           0 :     return ret;
     714             : }
     715             : 
     716             : static krb5_error_code KRB5_CALLCONV
     717           0 : acc_get_principal(krb5_context context,
     718             :                   krb5_ccache id,
     719             :                   krb5_principal *principal)
     720             : {
     721           0 :     krb5_acc *a = ACACHE(id);
     722             :     krb5_error_code ret;
     723             :     int32_t error;
     724             :     cc_string_t name;
     725             : 
     726           0 :     if (a->ccache == NULL) {
     727           0 :         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
     728           0 :                                N_("No API credential found", ""));
     729           0 :         return KRB5_CC_NOTFOUND;
     730             :     }
     731             : 
     732           0 :     error = (*a->ccache->func->get_principal)(a->ccache,
     733             :                                               cc_credentials_v5,
     734             :                                               &name);
     735           0 :     if (error)
     736           0 :         return translate_cc_error(context, error);
     737             : 
     738           0 :     ret = krb5_parse_name(context, name->data, principal);
     739             : 
     740           0 :     (*name->func->release)(name);
     741           0 :     return ret;
     742             : }
     743             : 
     744             : static krb5_error_code KRB5_CALLCONV
     745           0 : acc_get_first (krb5_context context,
     746             :                krb5_ccache id,
     747             :                krb5_cc_cursor *cursor)
     748             : {
     749             :     cc_credentials_iterator_t iter;
     750           0 :     krb5_acc *a = ACACHE(id);
     751             :     int32_t error;
     752             : 
     753           0 :     if (a->ccache == NULL) {
     754           0 :         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
     755           0 :                                N_("No API credential found", ""));
     756           0 :         return KRB5_CC_NOTFOUND;
     757             :     }
     758             : 
     759           0 :     error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
     760           0 :     if (error) {
     761           0 :         krb5_clear_error_message(context);
     762           0 :         return ENOENT;
     763             :     }
     764           0 :     *cursor = iter;
     765           0 :     return 0;
     766             : }
     767             : 
     768             : 
     769             : static krb5_error_code KRB5_CALLCONV
     770           0 : acc_get_next (krb5_context context,
     771             :               krb5_ccache id,
     772             :               krb5_cc_cursor *cursor,
     773             :               krb5_creds *creds)
     774             : {
     775           0 :     cc_credentials_iterator_t iter = *cursor;
     776             :     cc_credentials_t cred;
     777             :     krb5_error_code ret;
     778             :     int32_t error;
     779             : 
     780             :     while (1) {
     781           0 :         error = (*iter->func->next)(iter, &cred);
     782           0 :         if (error)
     783           0 :             return translate_cc_error(context, error);
     784           0 :         if (cred->data->version == cc_credentials_v5)
     785           0 :             break;
     786           0 :         (*cred->func->release)(cred);
     787             :     }
     788             : 
     789           0 :     ret = make_cred_from_ccred(context,
     790           0 :                                cred->data->credentials.credentials_v5,
     791             :                                creds);
     792           0 :     (*cred->func->release)(cred);
     793           0 :     return ret;
     794             : }
     795             : 
     796             : static krb5_error_code KRB5_CALLCONV
     797           0 : acc_end_get (krb5_context context,
     798             :              krb5_ccache id,
     799             :              krb5_cc_cursor *cursor)
     800             : {
     801           0 :     cc_credentials_iterator_t iter = *cursor;
     802           0 :     (*iter->func->release)(iter);
     803           0 :     return 0;
     804             : }
     805             : 
     806             : static krb5_error_code KRB5_CALLCONV
     807           0 : acc_remove_cred(krb5_context context,
     808             :                 krb5_ccache id,
     809             :                 krb5_flags which,
     810             :                 krb5_creds *cred)
     811             : {
     812             :     cc_credentials_iterator_t iter;
     813           0 :     krb5_acc *a = ACACHE(id);
     814             :     cc_credentials_t ccred;
     815             :     krb5_error_code ret;
     816             :     cc_int32 error;
     817             :     char *client, *server;
     818             : 
     819           0 :     if (a->ccache == NULL) {
     820           0 :         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
     821           0 :                                N_("No API credential found", ""));
     822           0 :         return KRB5_CC_NOTFOUND;
     823             :     }
     824             : 
     825           0 :     if (cred->client) {
     826           0 :         ret = krb5_unparse_name(context, cred->client, &client);
     827           0 :         if (ret)
     828           0 :             return ret;
     829             :     } else
     830           0 :         client = NULL;
     831             : 
     832           0 :     ret = krb5_unparse_name(context, cred->server, &server);
     833           0 :     if (ret) {
     834           0 :         free(client);
     835           0 :         return ret;
     836             :     }
     837             : 
     838           0 :     error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
     839           0 :     if (error) {
     840           0 :         free(server);
     841           0 :         free(client);
     842           0 :         return translate_cc_error(context, error);
     843             :     }
     844             : 
     845           0 :     ret = KRB5_CC_NOTFOUND;
     846           0 :     while (1) {
     847             :         cc_credentials_v5_t *v5cred;
     848             : 
     849           0 :         error = (*iter->func->next)(iter, &ccred);
     850           0 :         if (error)
     851           0 :             break;
     852             : 
     853           0 :         if (ccred->data->version != cc_credentials_v5)
     854           0 :             goto next;
     855             : 
     856           0 :         v5cred = ccred->data->credentials.credentials_v5;
     857             : 
     858           0 :         if (client && strcmp(v5cred->client, client) != 0)
     859           0 :             goto next;
     860             : 
     861           0 :         if (strcmp(v5cred->server, server) != 0)
     862           0 :             goto next;
     863             : 
     864           0 :         (*a->ccache->func->remove_credentials)(a->ccache, ccred);
     865           0 :         ret = 0;
     866           0 :     next:
     867           0 :         (*ccred->func->release)(ccred);
     868             :     }
     869             : 
     870           0 :     (*iter->func->release)(iter);
     871             : 
     872           0 :     if (ret)
     873           0 :         krb5_set_error_message(context, ret,
     874           0 :                                N_("Can't find credential %s in cache",
     875             :                                  "principal"), server);
     876           0 :     free(server);
     877           0 :     free(client);
     878             : 
     879           0 :     return ret;
     880             : }
     881             : 
     882             : static krb5_error_code KRB5_CALLCONV
     883           0 : acc_set_flags(krb5_context context,
     884             :               krb5_ccache id,
     885             :               krb5_flags flags)
     886             : {
     887           0 :     return 0;
     888             : }
     889             : 
     890             : static int KRB5_CALLCONV
     891           0 : acc_get_version(krb5_context context,
     892             :                 krb5_ccache id)
     893             : {
     894           0 :     return 0;
     895             : }
     896             : 
     897             : struct cache_iter {
     898             :     cc_context_t context;
     899             :     cc_ccache_iterator_t iter;
     900             : };
     901             : 
     902             : static krb5_error_code KRB5_CALLCONV
     903           1 : acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
     904             : {
     905             :     struct cache_iter *iter;
     906             :     krb5_error_code ret;
     907             :     cc_int32 error;
     908             : 
     909           1 :     ret = init_ccapi(context);
     910           1 :     if (ret)
     911           1 :         return ret;
     912             : 
     913           0 :     iter = calloc(1, sizeof(*iter));
     914           0 :     if (iter == NULL)
     915           0 :         return krb5_enomem(context);
     916             : 
     917           0 :     error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL);
     918           0 :     if (error) {
     919           0 :         free(iter);
     920           0 :         return translate_cc_error(context, error);
     921             :     }
     922             : 
     923           0 :     error = (*iter->context->func->new_ccache_iterator)(iter->context,
     924             :                                                         &iter->iter);
     925           0 :     if (error) {
     926           0 :         free(iter);
     927           0 :         krb5_clear_error_message(context);
     928           0 :         return ENOENT;
     929             :     }
     930           0 :     *cursor = iter;
     931           0 :     return 0;
     932             : }
     933             : 
     934             : static krb5_error_code KRB5_CALLCONV
     935           0 : acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
     936             : {
     937           0 :     struct cache_iter *iter = cursor;
     938             :     cc_ccache_t cache;
     939             :     krb5_acc *a;
     940             :     krb5_error_code ret;
     941             :     int32_t error;
     942             : 
     943           0 :     error = (*iter->iter->func->next)(iter->iter, &cache);
     944           0 :     if (error)
     945           0 :         return translate_cc_error(context, error);
     946             : 
     947           0 :     ret = _krb5_cc_allocate(context, &krb5_acc_ops, id);
     948           0 :     if (ret) {
     949           0 :         (*cache->func->release)(cache);
     950           0 :         return ret;
     951             :     }
     952             : 
     953           0 :     ret = acc_alloc(context, id);
     954           0 :     if (ret) {
     955           0 :         (*cache->func->release)(cache);
     956           0 :         free(*id);
     957           0 :         return ret;
     958             :     }
     959             : 
     960           0 :     a = ACACHE(*id);
     961           0 :     a->ccache = cache;
     962             : 
     963           0 :     error = get_cc_name(a);
     964           0 :     if (error) {
     965           0 :         acc_close(context, *id);
     966           0 :         *id = NULL;
     967           0 :         return translate_cc_error(context, error);
     968             :     }
     969           0 :     return 0;
     970             : }
     971             : 
     972             : static krb5_error_code KRB5_CALLCONV
     973           0 : acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
     974             : {
     975           0 :     struct cache_iter *iter = cursor;
     976             : 
     977           0 :     (*iter->iter->func->release)(iter->iter);
     978           0 :     iter->iter = NULL;
     979           0 :     (*iter->context->func->release)(iter->context);
     980           0 :     iter->context = NULL;
     981           0 :     free(iter);
     982           0 :     return 0;
     983             : }
     984             : 
     985             : static krb5_error_code KRB5_CALLCONV
     986           0 : acc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
     987             : {
     988             :     krb5_error_code ret;
     989           0 :     krb5_acc *afrom = ACACHE(from);
     990           0 :     krb5_acc *ato = ACACHE(to);
     991             :     int32_t error;
     992             : 
     993           0 :     if (ato->ccache == NULL) {
     994             :         cc_string_t name;
     995             : 
     996           0 :         error = (*afrom->ccache->func->get_principal)(afrom->ccache,
     997             :                                                       cc_credentials_v5,
     998             :                                                       &name);
     999           0 :         if (error)
    1000           0 :             return translate_cc_error(context, error);
    1001             : 
    1002           0 :         error = (*ato->context->func->create_new_ccache)(ato->context,
    1003             :                                                          cc_credentials_v5,
    1004           0 :                                                          name->data,
    1005             :                                                          &ato->ccache);
    1006           0 :         (*name->func->release)(name);
    1007           0 :         if (error)
    1008           0 :             return translate_cc_error(context, error);
    1009             :     }
    1010             : 
    1011           0 :     error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache);
    1012           0 :     ret = translate_cc_error(context, error);
    1013           0 :     if (ret == 0)
    1014           0 :         krb5_cc_destroy(context, from);
    1015           0 :     return ret;
    1016             : }
    1017             : 
    1018             : static krb5_error_code KRB5_CALLCONV
    1019           0 : acc_get_default_name(krb5_context context, char **str)
    1020             : {
    1021             :     krb5_error_code ret;
    1022             :     cc_context_t cc;
    1023             :     cc_string_t name;
    1024             :     int32_t error;
    1025             : 
    1026           0 :     ret = init_ccapi(context);
    1027           0 :     if (ret)
    1028           0 :         return ret;
    1029             : 
    1030           0 :     error = (*init_func)(&cc, ccapi_version_3, NULL, NULL);
    1031           0 :     if (error)
    1032           0 :         return translate_cc_error(context, error);
    1033             : 
    1034           0 :     error = (*cc->func->get_default_ccache_name)(cc, &name);
    1035           0 :     if (error) {
    1036           0 :         (*cc->func->release)(cc);
    1037           0 :         return translate_cc_error(context, error);
    1038             :     }
    1039             : 
    1040           0 :     error = asprintf(str, "API:%s", name->data);
    1041           0 :     (*name->func->release)(name);
    1042           0 :     (*cc->func->release)(cc);
    1043             : 
    1044           0 :     if (error < 0 || *str == NULL)
    1045           0 :         return krb5_enomem(context);
    1046           0 :     return 0;
    1047             : }
    1048             : 
    1049             : static krb5_error_code KRB5_CALLCONV
    1050           0 : acc_set_default(krb5_context context, krb5_ccache id)
    1051             : {
    1052           0 :     krb5_acc *a = ACACHE(id);
    1053             :     cc_int32 error;
    1054             : 
    1055           0 :     if (a->ccache == NULL) {
    1056           0 :         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
    1057           0 :                                N_("No API credential found", ""));
    1058           0 :         return KRB5_CC_NOTFOUND;
    1059             :     }
    1060             : 
    1061           0 :     error = (*a->ccache->func->set_default)(a->ccache);
    1062           0 :     if (error)
    1063           0 :         return translate_cc_error(context, error);
    1064             : 
    1065           0 :     return 0;
    1066             : }
    1067             : 
    1068             : static krb5_error_code KRB5_CALLCONV
    1069           0 : acc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
    1070             : {
    1071           0 :     krb5_acc *a = ACACHE(id);
    1072             :     cc_int32 error;
    1073             :     cc_time_t t;
    1074             : 
    1075           0 :     if (a->ccache == NULL) {
    1076           0 :         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
    1077           0 :                                N_("No API credential found", ""));
    1078           0 :         return KRB5_CC_NOTFOUND;
    1079             :     }
    1080             : 
    1081           0 :     error = (*a->ccache->func->get_change_time)(a->ccache, &t);
    1082           0 :     if (error)
    1083           0 :         return translate_cc_error(context, error);
    1084             : 
    1085           0 :     *mtime = t;
    1086             : 
    1087           0 :     return 0;
    1088             : }
    1089             : 
    1090             : /**
    1091             :  * Variable containing the API based credential cache implemention.
    1092             :  *
    1093             :  * @ingroup krb5_ccache
    1094             :  */
    1095             : 
    1096             : KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = {
    1097             :     KRB5_CC_OPS_VERSION_5,
    1098             :     "API",
    1099             :     NULL,
    1100             :     NULL,
    1101             :     acc_gen_new,
    1102             :     acc_initialize,
    1103             :     acc_destroy,
    1104             :     acc_close,
    1105             :     acc_store_cred,
    1106             :     NULL, /* acc_retrieve */
    1107             :     acc_get_principal,
    1108             :     acc_get_first,
    1109             :     acc_get_next,
    1110             :     acc_end_get,
    1111             :     acc_remove_cred,
    1112             :     acc_set_flags,
    1113             :     acc_get_version,
    1114             :     acc_get_cache_first,
    1115             :     acc_get_cache_next,
    1116             :     acc_end_cache_get,
    1117             :     acc_move,
    1118             :     acc_get_default_name,
    1119             :     acc_set_default,
    1120             :     acc_lastchange,
    1121             :     NULL,
    1122             :     NULL,
    1123             :     acc_get_name_2,
    1124             :     acc_resolve_2
    1125             : };
    1126             : 
    1127             : #endif

Generated by: LCOV version 1.13