acache.c revision 178825
1132451Sroberto/* 2182007Sroberto * Copyright (c) 2004 - 2007 Kungliga Tekniska H�gskolan 3182007Sroberto * (Royal Institute of Technology, Stockholm, Sweden). 4132451Sroberto * All rights reserved. 5132451Sroberto * 6132451Sroberto * Redistribution and use in source and binary forms, with or without 7132451Sroberto * modification, are permitted provided that the following conditions 8132451Sroberto * are met: 9182007Sroberto * 10182007Sroberto * 1. Redistributions of source code must retain the above copyright 11182007Sroberto * notice, this list of conditions and the following disclaimer. 12182007Sroberto * 13182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright 14182007Sroberto * notice, this list of conditions and the following disclaimer in the 15182007Sroberto * documentation and/or other materials provided with the distribution. 16132451Sroberto * 17132451Sroberto * 3. Neither the name of the Institute nor the names of its contributors 18182007Sroberto * may be used to endorse or promote products derived from this software 19132451Sroberto * without specific prior written permission. 20132451Sroberto * 21132451Sroberto * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22132451Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23132451Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24132451Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25132451Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26132451Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27132451Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28132451Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29132451Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30132451Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31132451Sroberto * SUCH DAMAGE. 32132451Sroberto */ 33132451Sroberto 34132451Sroberto#include "krb5_locl.h" 35132451Sroberto#include <krb5_ccapi.h> 36132451Sroberto#ifdef HAVE_DLFCN_H 37132451Sroberto#include <dlfcn.h> 38132451Sroberto#endif 39132451Sroberto 40132451SrobertoRCSID("$Id: acache.c 22099 2007-12-03 17:14:34Z lha $"); 41132451Sroberto 42132451Sroberto/* XXX should we fetch these for each open ? */ 43182007Srobertostatic HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; 44132451Srobertostatic cc_initialize_func init_func; 45132451Sroberto 46132451Sroberto#ifdef HAVE_DLOPEN 47132451Srobertostatic void *cc_handle; 48132451Sroberto#endif 49132451Sroberto 50132451Srobertotypedef struct krb5_acc { 51132451Sroberto char *cache_name; 52132451Sroberto cc_context_t context; 53132451Sroberto cc_ccache_t ccache; 54182007Sroberto} krb5_acc; 55182007Sroberto 56182007Srobertostatic krb5_error_code acc_close(krb5_context, krb5_ccache); 57132451Sroberto 58132451Sroberto#define ACACHE(X) ((krb5_acc *)(X)->data.data) 59132451Sroberto 60182007Srobertostatic const struct { 61132451Sroberto cc_int32 error; 62132451Sroberto krb5_error_code ret; 63182007Sroberto} cc_errors[] = { 64182007Sroberto { ccErrBadName, KRB5_CC_BADNAME }, 65182007Sroberto { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND }, 66182007Sroberto { ccErrCCacheNotFound, KRB5_FCC_NOFILE }, 67132451Sroberto { ccErrContextNotFound, KRB5_CC_NOTFOUND }, 68182007Sroberto { ccIteratorEnd, KRB5_CC_END }, 69132451Sroberto { ccErrNoMem, KRB5_CC_NOMEM }, 70182007Sroberto { ccErrServerUnavailable, KRB5_CC_NOSUPP }, 71182007Sroberto { ccNoError, 0 } 72182007Sroberto}; 73182007Sroberto 74182007Srobertostatic krb5_error_code 75182007Srobertotranslate_cc_error(krb5_context context, cc_int32 error) 76132451Sroberto{ 77132451Sroberto int i; 78132451Sroberto krb5_clear_error_string(context); 79182007Sroberto for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++) 80182007Sroberto if (cc_errors[i].error == error) 81132451Sroberto return cc_errors[i].ret; 82182007Sroberto return KRB5_FCC_INTERNAL; 83182007Sroberto} 84182007Sroberto 85182007Srobertostatic krb5_error_code 86182007Srobertoinit_ccapi(krb5_context context) 87182007Sroberto{ 88132451Sroberto const char *lib; 89132451Sroberto 90132451Sroberto HEIMDAL_MUTEX_lock(&acc_mutex); 91132451Sroberto if (init_func) { 92132451Sroberto HEIMDAL_MUTEX_unlock(&acc_mutex); 93132451Sroberto krb5_clear_error_string(context); 94132451Sroberto return 0; 95132451Sroberto } 96132451Sroberto 97132451Sroberto lib = krb5_config_get_string(context, NULL, 98132451Sroberto "libdefaults", "ccapi_library", 99132451Sroberto NULL); 100132451Sroberto if (lib == NULL) { 101132451Sroberto#ifdef __APPLE__ 102132451Sroberto lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos"; 103132451Sroberto#else 104132451Sroberto lib = "/usr/lib/libkrb5_cc.so"; 105182007Sroberto#endif 106182007Sroberto } 107182007Sroberto 108182007Sroberto#ifdef HAVE_DLOPEN 109182007Sroberto 110182007Sroberto#ifndef RTLD_LAZY 111182007Sroberto#define RTLD_LAZY 0 112182007Sroberto#endif 113182007Sroberto 114182007Sroberto cc_handle = dlopen(lib, RTLD_LAZY); 115132451Sroberto if (cc_handle == NULL) { 116132451Sroberto HEIMDAL_MUTEX_unlock(&acc_mutex); 117132451Sroberto krb5_set_error_string(context, "Failed to load %s", lib); 118132451Sroberto return KRB5_CC_NOSUPP; 119132451Sroberto } 120132451Sroberto 121132451Sroberto init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize"); 122132451Sroberto HEIMDAL_MUTEX_unlock(&acc_mutex); 123132451Sroberto if (init_func == NULL) { 124132451Sroberto krb5_set_error_string(context, "Failed to find cc_initialize" 125132451Sroberto "in %s: %s", lib, dlerror()); 126132451Sroberto dlclose(cc_handle); 127132451Sroberto return KRB5_CC_NOSUPP; 128132451Sroberto } 129132451Sroberto 130132451Sroberto return 0; 131132451Sroberto#else 132132451Sroberto HEIMDAL_MUTEX_unlock(&acc_mutex); 133132451Sroberto krb5_set_error_string(context, "no support for shared object"); 134132451Sroberto return KRB5_CC_NOSUPP; 135132451Sroberto#endif 136132451Sroberto} 137132451Sroberto 138132451Srobertostatic krb5_error_code 139132451Srobertomake_cred_from_ccred(krb5_context context, 140132451Sroberto const cc_credentials_v5_t *incred, 141132451Sroberto krb5_creds *cred) 142132451Sroberto{ 143132451Sroberto krb5_error_code ret; 144132451Sroberto int i; 145132451Sroberto 146132451Sroberto memset(cred, 0, sizeof(*cred)); 147132451Sroberto 148132451Sroberto ret = krb5_parse_name(context, incred->client, &cred->client); 149132451Sroberto if (ret) 150132451Sroberto goto fail; 151132451Sroberto 152132451Sroberto ret = krb5_parse_name(context, incred->server, &cred->server); 153132451Sroberto if (ret) 154132451Sroberto goto fail; 155132451Sroberto 156132451Sroberto cred->session.keytype = incred->keyblock.type; 157132451Sroberto cred->session.keyvalue.length = incred->keyblock.length; 158132451Sroberto cred->session.keyvalue.data = malloc(incred->keyblock.length); 159132451Sroberto if (cred->session.keyvalue.data == NULL) 160132451Sroberto goto nomem; 161132451Sroberto memcpy(cred->session.keyvalue.data, incred->keyblock.data, 162132451Sroberto incred->keyblock.length); 163132451Sroberto 164132451Sroberto cred->times.authtime = incred->authtime; 165132451Sroberto cred->times.starttime = incred->starttime; 166132451Sroberto cred->times.endtime = incred->endtime; 167132451Sroberto cred->times.renew_till = incred->renew_till; 168132451Sroberto 169132451Sroberto ret = krb5_data_copy(&cred->ticket, 170132451Sroberto incred->ticket.data, 171132451Sroberto incred->ticket.length); 172132451Sroberto if (ret) 173132451Sroberto goto nomem; 174132451Sroberto 175132451Sroberto ret = krb5_data_copy(&cred->second_ticket, 176132451Sroberto incred->second_ticket.data, 177132451Sroberto incred->second_ticket.length); 178132451Sroberto if (ret) 179132451Sroberto goto nomem; 180132451Sroberto 181132451Sroberto cred->authdata.val = NULL; 182132451Sroberto cred->authdata.len = 0; 183132451Sroberto 184132451Sroberto cred->addresses.val = NULL; 185132451Sroberto cred->addresses.len = 0; 186132451Sroberto 187182007Sroberto for (i = 0; incred->authdata && incred->authdata[i]; i++) 188132451Sroberto ; 189132451Sroberto 190132451Sroberto if (i) { 191132451Sroberto cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0])); 192132451Sroberto if (cred->authdata.val == NULL) 193182007Sroberto goto nomem; 194132451Sroberto cred->authdata.len = i; 195132451Sroberto for (i = 0; i < cred->authdata.len; i++) { 196182007Sroberto cred->authdata.val[i].ad_type = incred->authdata[i]->type; 197182007Sroberto ret = krb5_data_copy(&cred->authdata.val[i].ad_data, 198132451Sroberto incred->authdata[i]->data, 199132451Sroberto incred->authdata[i]->length); 200182007Sroberto if (ret) 201132451Sroberto goto nomem; 202182007Sroberto } 203132451Sroberto } 204132451Sroberto 205132451Sroberto for (i = 0; incred->addresses && incred->addresses[i]; i++) 206132451Sroberto ; 207182007Sroberto 208182007Sroberto if (i) { 209132451Sroberto cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0])); 210132451Sroberto if (cred->addresses.val == NULL) 211132451Sroberto goto nomem; 212132451Sroberto cred->addresses.len = i; 213132451Sroberto 214182007Sroberto for (i = 0; i < cred->addresses.len; i++) { 215132451Sroberto cred->addresses.val[i].addr_type = incred->addresses[i]->type; 216132451Sroberto ret = krb5_data_copy(&cred->addresses.val[i].address, 217132451Sroberto incred->addresses[i]->data, 218132451Sroberto incred->addresses[i]->length); 219132451Sroberto if (ret) 220132451Sroberto goto nomem; 221132451Sroberto } 222132451Sroberto } 223132451Sroberto 224132451Sroberto cred->flags.i = 0; 225132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE) 226132451Sroberto cred->flags.b.forwardable = 1; 227132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED) 228132451Sroberto cred->flags.b.forwarded = 1; 229132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE) 230132451Sroberto cred->flags.b.proxiable = 1; 231132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY) 232132451Sroberto cred->flags.b.proxy = 1; 233132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE) 234132451Sroberto cred->flags.b.may_postdate = 1; 235132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED) 236132451Sroberto cred->flags.b.postdated = 1; 237132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID) 238132451Sroberto cred->flags.b.invalid = 1; 239132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE) 240132451Sroberto cred->flags.b.renewable = 1; 241132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL) 242132451Sroberto cred->flags.b.initial = 1; 243132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH) 244132451Sroberto cred->flags.b.pre_authent = 1; 245132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH) 246132451Sroberto cred->flags.b.hw_authent = 1; 247132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED) 248132451Sroberto cred->flags.b.transited_policy_checked = 1; 249132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE) 250132451Sroberto cred->flags.b.ok_as_delegate = 1; 251132451Sroberto if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS) 252132451Sroberto cred->flags.b.anonymous = 1; 253132451Sroberto 254132451Sroberto return 0; 255132451Sroberto 256132451Srobertonomem: 257132451Sroberto ret = ENOMEM; 258132451Sroberto krb5_set_error_string(context, "malloc - out of memory"); 259132451Sroberto 260182007Srobertofail: 261132451Sroberto krb5_free_cred_contents(context, cred); 262132451Sroberto return ret; 263182007Sroberto} 264132451Sroberto 265132451Srobertostatic void 266132451Srobertofree_ccred(cc_credentials_v5_t *cred) 267132451Sroberto{ 268132451Sroberto int i; 269132451Sroberto 270132451Sroberto if (cred->addresses) { 271132451Sroberto for (i = 0; cred->addresses[i] != 0; i++) { 272132451Sroberto if (cred->addresses[i]->data) 273132451Sroberto free(cred->addresses[i]->data); 274132451Sroberto free(cred->addresses[i]); 275182007Sroberto } 276132451Sroberto free(cred->addresses); 277182007Sroberto } 278132451Sroberto if (cred->server) 279132451Sroberto free(cred->server); 280182007Sroberto if (cred->client) 281182007Sroberto free(cred->client); 282132451Sroberto memset(cred, 0, sizeof(*cred)); 283132451Sroberto} 284132451Sroberto 285182007Srobertostatic krb5_error_code 286182007Srobertomake_ccred_from_cred(krb5_context context, 287132451Sroberto const krb5_creds *incred, 288182007Sroberto cc_credentials_v5_t *cred) 289132451Sroberto{ 290132451Sroberto krb5_error_code ret; 291132451Sroberto int i; 292132451Sroberto 293132451Sroberto memset(cred, 0, sizeof(*cred)); 294132451Sroberto 295132451Sroberto ret = krb5_unparse_name(context, incred->client, &cred->client); 296132451Sroberto if (ret) 297132451Sroberto goto fail; 298132451Sroberto 299132451Sroberto ret = krb5_unparse_name(context, incred->server, &cred->server); 300132451Sroberto if (ret) 301132451Sroberto goto fail; 302132451Sroberto 303132451Sroberto cred->keyblock.type = incred->session.keytype; 304132451Sroberto cred->keyblock.length = incred->session.keyvalue.length; 305182007Sroberto cred->keyblock.data = incred->session.keyvalue.data; 306132451Sroberto 307182007Sroberto cred->authtime = incred->times.authtime; 308182007Sroberto cred->starttime = incred->times.starttime; 309182007Sroberto cred->endtime = incred->times.endtime; 310182007Sroberto cred->renew_till = incred->times.renew_till; 311182007Sroberto 312182007Sroberto cred->ticket.length = incred->ticket.length; 313182007Sroberto cred->ticket.data = incred->ticket.data; 314182007Sroberto 315132451Sroberto cred->second_ticket.length = incred->second_ticket.length; 316132451Sroberto cred->second_ticket.data = incred->second_ticket.data; 317182007Sroberto 318182007Sroberto /* XXX this one should also be filled in */ 319132451Sroberto cred->authdata = NULL; 320182007Sroberto 321182007Sroberto cred->addresses = calloc(incred->addresses.len + 1, 322182007Sroberto sizeof(cred->addresses[0])); 323182007Sroberto if (cred->addresses == NULL) { 324182007Sroberto 325182007Sroberto ret = ENOMEM; 326182007Sroberto goto fail; 327182007Sroberto } 328182007Sroberto 329182007Sroberto for (i = 0; i < incred->addresses.len; i++) { 330182007Sroberto cc_data *addr; 331182007Sroberto addr = malloc(sizeof(*addr)); 332182007Sroberto if (addr == NULL) { 333182007Sroberto ret = ENOMEM; 334182007Sroberto goto fail; 335182007Sroberto } 336182007Sroberto addr->type = incred->addresses.val[i].addr_type; 337182007Sroberto addr->length = incred->addresses.val[i].address.length; 338182007Sroberto addr->data = malloc(addr->length); 339182007Sroberto if (addr->data == NULL) { 340182007Sroberto ret = ENOMEM; 341182007Sroberto goto fail; 342182007Sroberto } 343182007Sroberto memcpy(addr->data, incred->addresses.val[i].address.data, 344182007Sroberto addr->length); 345182007Sroberto cred->addresses[i] = addr; 346182007Sroberto } 347132451Sroberto cred->addresses[i] = NULL; 348132451Sroberto 349132451Sroberto cred->ticket_flags = 0; 350132451Sroberto if (incred->flags.b.forwardable) 351132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE; 352132451Sroberto if (incred->flags.b.forwarded) 353132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED; 354132451Sroberto if (incred->flags.b.proxiable) 355132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE; 356132451Sroberto if (incred->flags.b.proxy) 357132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY; 358132451Sroberto if (incred->flags.b.may_postdate) 359182007Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE; 360132451Sroberto if (incred->flags.b.postdated) 361132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED; 362132451Sroberto if (incred->flags.b.invalid) 363132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID; 364132451Sroberto if (incred->flags.b.renewable) 365132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE; 366132451Sroberto if (incred->flags.b.initial) 367132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL; 368132451Sroberto if (incred->flags.b.pre_authent) 369182007Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH; 370132451Sroberto if (incred->flags.b.hw_authent) 371182007Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH; 372182007Sroberto if (incred->flags.b.transited_policy_checked) 373182007Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED; 374182007Sroberto if (incred->flags.b.ok_as_delegate) 375182007Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE; 376132451Sroberto if (incred->flags.b.anonymous) 377132451Sroberto cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS; 378132451Sroberto 379132451Sroberto return 0; 380132451Sroberto 381132451Srobertofail: 382132451Sroberto free_ccred(cred); 383132451Sroberto 384132451Sroberto krb5_clear_error_string(context); 385132451Sroberto return ret; 386132451Sroberto} 387132451Sroberto 388182007Srobertostatic char * 389182007Srobertoget_cc_name(cc_ccache_t cache) 390182007Sroberto{ 391182007Sroberto cc_string_t name; 392182007Sroberto cc_int32 error; 393182007Sroberto char *str; 394182007Sroberto 395182007Sroberto error = (*cache->func->get_name)(cache, &name); 396182007Sroberto if (error) 397132451Sroberto return NULL; 398132451Sroberto 399132451Sroberto str = strdup(name->data); 400132451Sroberto (*name->func->release)(name); 401132451Sroberto return str; 402132451Sroberto} 403132451Sroberto 404132451Sroberto 405132451Srobertostatic const char* 406132451Srobertoacc_get_name(krb5_context context, 407132451Sroberto krb5_ccache id) 408132451Sroberto{ 409132451Sroberto krb5_acc *a = ACACHE(id); 410132451Sroberto static char n[255]; 411182007Sroberto char *name; 412182007Sroberto 413182007Sroberto name = get_cc_name(a->ccache); 414182007Sroberto if (name == NULL) { 415182007Sroberto krb5_set_error_string(context, "malloc: out of memory"); 416182007Sroberto return NULL; 417182007Sroberto } 418182007Sroberto strlcpy(n, name, sizeof(n)); 419182007Sroberto free(name); 420182007Sroberto return n; 421182007Sroberto} 422182007Sroberto 423182007Srobertostatic krb5_error_code 424182007Srobertoacc_alloc(krb5_context context, krb5_ccache *id) 425182007Sroberto{ 426182007Sroberto krb5_error_code ret; 427182007Sroberto cc_int32 error; 428182007Sroberto krb5_acc *a; 429182007Sroberto 430182007Sroberto ret = init_ccapi(context); 431182007Sroberto if (ret) 432182007Sroberto return ret; 433182007Sroberto 434182007Sroberto ret = krb5_data_alloc(&(*id)->data, sizeof(*a)); 435182007Sroberto if (ret) { 436182007Sroberto krb5_clear_error_string(context); 437182007Sroberto return ret; 438182007Sroberto } 439182007Sroberto 440182007Sroberto a = ACACHE(*id); 441182007Sroberto 442182007Sroberto error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL); 443182007Sroberto if (error) { 444182007Sroberto krb5_data_free(&(*id)->data); 445182007Sroberto return translate_cc_error(context, error); 446182007Sroberto } 447182007Sroberto 448182007Sroberto a->cache_name = NULL; 449182007Sroberto 450182007Sroberto return 0; 451182007Sroberto} 452182007Sroberto 453182007Srobertostatic krb5_error_code 454182007Srobertoacc_resolve(krb5_context context, krb5_ccache *id, const char *res) 455182007Sroberto{ 456182007Sroberto krb5_error_code ret; 457182007Sroberto cc_int32 error; 458182007Sroberto krb5_acc *a; 459182007Sroberto 460182007Sroberto ret = acc_alloc(context, id); 461182007Sroberto if (ret) 462132451Sroberto return ret; 463182007Sroberto 464182007Sroberto a = ACACHE(*id); 465182007Sroberto 466182007Sroberto error = (*a->context->func->open_ccache)(a->context, res, 467182007Sroberto &a->ccache); 468182007Sroberto if (error == 0) { 469182007Sroberto a->cache_name = get_cc_name(a->ccache); 470182007Sroberto if (a->cache_name == NULL) { 471182007Sroberto acc_close(context, *id); 472182007Sroberto *id = NULL; 473182007Sroberto krb5_set_error_string(context, "malloc: out of memory"); 474182007Sroberto return ENOMEM; 475182007Sroberto } 476182007Sroberto } else if (error == ccErrCCacheNotFound) { 477182007Sroberto a->ccache = NULL; 478182007Sroberto a->cache_name = NULL; 479182007Sroberto error = 0; 480182007Sroberto } else { 481182007Sroberto *id = NULL; 482182007Sroberto return translate_cc_error(context, error); 483182007Sroberto } 484182007Sroberto 485182007Sroberto return 0; 486182007Sroberto} 487182007Sroberto 488182007Srobertostatic krb5_error_code 489182007Srobertoacc_gen_new(krb5_context context, krb5_ccache *id) 490182007Sroberto{ 491182007Sroberto krb5_error_code ret; 492182007Sroberto krb5_acc *a; 493182007Sroberto 494182007Sroberto ret = acc_alloc(context, id); 495182007Sroberto if (ret) 496182007Sroberto return ret; 497182007Sroberto 498182007Sroberto a = ACACHE(*id); 499182007Sroberto 500182007Sroberto a->ccache = NULL; 501182007Sroberto a->cache_name = NULL; 502182007Sroberto 503182007Sroberto return 0; 504182007Sroberto} 505182007Sroberto 506182007Srobertostatic krb5_error_code 507182007Srobertoacc_initialize(krb5_context context, 508182007Sroberto krb5_ccache id, 509182007Sroberto krb5_principal primary_principal) 510182007Sroberto{ 511182007Sroberto krb5_acc *a = ACACHE(id); 512182007Sroberto krb5_error_code ret; 513182007Sroberto int32_t error; 514182007Sroberto char *name; 515182007Sroberto 516182007Sroberto ret = krb5_unparse_name(context, primary_principal, &name); 517182007Sroberto if (ret) 518182007Sroberto return ret; 519182007Sroberto 520182007Sroberto error = (*a->context->func->create_new_ccache)(a->context, 521182007Sroberto cc_credentials_v5, 522182007Sroberto name, 523182007Sroberto &a->ccache); 524182007Sroberto free(name); 525182007Sroberto 526182007Sroberto return translate_cc_error(context, error); 527182007Sroberto} 528182007Sroberto 529182007Srobertostatic krb5_error_code 530182007Srobertoacc_close(krb5_context context, 531182007Sroberto krb5_ccache id) 532182007Sroberto{ 533182007Sroberto krb5_acc *a = ACACHE(id); 534182007Sroberto 535182007Sroberto if (a->ccache) { 536182007Sroberto (*a->ccache->func->release)(a->ccache); 537182007Sroberto a->ccache = NULL; 538182007Sroberto } 539132451Sroberto if (a->cache_name) { 540132451Sroberto free(a->cache_name); 541132451Sroberto a->cache_name = NULL; 542132451Sroberto } 543132451Sroberto (*a->context->func->release)(a->context); 544132451Sroberto a->context = NULL; 545132451Sroberto krb5_data_free(&id->data); 546132451Sroberto return 0; 547132451Sroberto} 548132451Sroberto 549132451Srobertostatic krb5_error_code 550132451Srobertoacc_destroy(krb5_context context, 551132451Sroberto krb5_ccache id) 552132451Sroberto{ 553132451Sroberto krb5_acc *a = ACACHE(id); 554132451Sroberto cc_int32 error = 0; 555132451Sroberto 556182007Sroberto if (a->ccache) { 557182007Sroberto error = (*a->ccache->func->destroy)(a->ccache); 558182007Sroberto a->ccache = NULL; 559182007Sroberto } 560132451Sroberto if (a->context) { 561182007Sroberto error = (a->context->func->release)(a->context); 562182007Sroberto a->context = NULL; 563182007Sroberto } 564182007Sroberto return translate_cc_error(context, error); 565132451Sroberto} 566132451Sroberto 567132451Srobertostatic krb5_error_code 568132451Srobertoacc_store_cred(krb5_context context, 569182007Sroberto krb5_ccache id, 570182007Sroberto krb5_creds *creds) 571182007Sroberto{ 572182007Sroberto krb5_acc *a = ACACHE(id); 573182007Sroberto cc_credentials_union cred; 574182007Sroberto cc_credentials_v5_t v5cred; 575182007Sroberto krb5_error_code ret; 576132451Sroberto cc_int32 error; 577132451Sroberto 578132451Sroberto if (a->ccache == NULL) { 579132451Sroberto krb5_set_error_string(context, "No API credential found"); 580132451Sroberto return KRB5_CC_NOTFOUND; 581132451Sroberto } 582182007Sroberto 583132451Sroberto cred.version = cc_credentials_v5; 584132451Sroberto cred.credentials.credentials_v5 = &v5cred; 585132451Sroberto 586132451Sroberto ret = make_ccred_from_cred(context, 587132451Sroberto creds, 588132451Sroberto &v5cred); 589132451Sroberto if (ret) 590132451Sroberto return ret; 591132451Sroberto 592132451Sroberto error = (*a->ccache->func->store_credentials)(a->ccache, &cred); 593132451Sroberto if (error) 594132451Sroberto ret = translate_cc_error(context, error); 595132451Sroberto 596132451Sroberto free_ccred(&v5cred); 597182007Sroberto 598132451Sroberto return ret; 599132451Sroberto} 600132451Sroberto 601132451Srobertostatic krb5_error_code 602132451Srobertoacc_get_principal(krb5_context context, 603132451Sroberto krb5_ccache id, 604132451Sroberto krb5_principal *principal) 605132451Sroberto{ 606132451Sroberto krb5_acc *a = ACACHE(id); 607182007Sroberto krb5_error_code ret; 608132451Sroberto int32_t error; 609132451Sroberto cc_string_t name; 610132451Sroberto 611132451Sroberto if (a->ccache == NULL) { 612132451Sroberto krb5_set_error_string(context, "No API credential found"); 613182007Sroberto return KRB5_CC_NOTFOUND; 614132451Sroberto } 615132451Sroberto 616132451Sroberto error = (*a->ccache->func->get_principal)(a->ccache, 617132451Sroberto cc_credentials_v5, 618132451Sroberto &name); 619132451Sroberto if (error) 620132451Sroberto return translate_cc_error(context, error); 621132451Sroberto 622132451Sroberto ret = krb5_parse_name(context, name->data, principal); 623132451Sroberto 624132451Sroberto (*name->func->release)(name); 625132451Sroberto return ret; 626132451Sroberto} 627132451Sroberto 628132451Srobertostatic krb5_error_code 629132451Srobertoacc_get_first (krb5_context context, 630132451Sroberto krb5_ccache id, 631132451Sroberto krb5_cc_cursor *cursor) 632132451Sroberto{ 633132451Sroberto cc_credentials_iterator_t iter; 634132451Sroberto krb5_acc *a = ACACHE(id); 635132451Sroberto int32_t error; 636132451Sroberto 637132451Sroberto if (a->ccache == NULL) { 638182007Sroberto krb5_set_error_string(context, "No API credential found"); 639132451Sroberto return KRB5_CC_NOTFOUND; 640132451Sroberto } 641182007Sroberto 642132451Sroberto error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); 643132451Sroberto if (error) { 644132451Sroberto krb5_clear_error_string(context); 645132451Sroberto return ENOENT; 646132451Sroberto } 647132451Sroberto *cursor = iter; 648132451Sroberto return 0; 649132451Sroberto} 650132451Sroberto 651132451Sroberto 652132451Srobertostatic krb5_error_code 653132451Srobertoacc_get_next (krb5_context context, 654132451Sroberto krb5_ccache id, 655132451Sroberto krb5_cc_cursor *cursor, 656182007Sroberto krb5_creds *creds) 657132451Sroberto{ 658132451Sroberto cc_credentials_iterator_t iter = *cursor; 659182007Sroberto cc_credentials_t cred; 660182007Sroberto krb5_error_code ret; 661182007Sroberto int32_t error; 662182007Sroberto 663132451Sroberto while (1) { 664132451Sroberto error = (*iter->func->next)(iter, &cred); 665182007Sroberto if (error) 666132451Sroberto return translate_cc_error(context, error); 667132451Sroberto if (cred->data->version == cc_credentials_v5) 668132451Sroberto break; 669132451Sroberto (*cred->func->release)(cred); 670132451Sroberto } 671132451Sroberto 672182007Sroberto ret = make_cred_from_ccred(context, 673182007Sroberto cred->data->credentials.credentials_v5, 674182007Sroberto creds); 675182007Sroberto (*cred->func->release)(cred); 676182007Sroberto return ret; 677182007Sroberto} 678182007Sroberto 679182007Srobertostatic krb5_error_code 680182007Srobertoacc_end_get (krb5_context context, 681182007Sroberto krb5_ccache id, 682182007Sroberto krb5_cc_cursor *cursor) 683132451Sroberto{ 684132451Sroberto cc_credentials_iterator_t iter = *cursor; 685132451Sroberto (*iter->func->release)(iter); 686132451Sroberto return 0; 687132451Sroberto} 688132451Sroberto 689182007Srobertostatic krb5_error_code 690132451Srobertoacc_remove_cred(krb5_context context, 691182007Sroberto krb5_ccache id, 692132451Sroberto krb5_flags which, 693182007Sroberto krb5_creds *cred) 694182007Sroberto{ 695132451Sroberto cc_credentials_iterator_t iter; 696132451Sroberto krb5_acc *a = ACACHE(id); 697132451Sroberto cc_credentials_t ccred; 698132451Sroberto krb5_error_code ret; 699132451Sroberto cc_int32 error; 700132451Sroberto char *client, *server; 701132451Sroberto 702132451Sroberto if (a->ccache == NULL) { 703182007Sroberto krb5_set_error_string(context, "No API credential found"); 704132451Sroberto return KRB5_CC_NOTFOUND; 705132451Sroberto } 706132451Sroberto 707132451Sroberto if (cred->client) { 708132451Sroberto ret = krb5_unparse_name(context, cred->client, &client); 709132451Sroberto if (ret) 710132451Sroberto return ret; 711132451Sroberto } else 712132451Sroberto client = NULL; 713132451Sroberto 714132451Sroberto ret = krb5_unparse_name(context, cred->server, &server); 715132451Sroberto if (ret) { 716132451Sroberto free(client); 717132451Sroberto return ret; 718132451Sroberto } 719132451Sroberto 720132451Sroberto error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); 721132451Sroberto if (error) { 722132451Sroberto free(server); 723132451Sroberto free(client); 724132451Sroberto return translate_cc_error(context, error); 725132451Sroberto } 726182007Sroberto 727132451Sroberto ret = KRB5_CC_NOTFOUND; 728182007Sroberto while (1) { 729132451Sroberto cc_credentials_v5_t *v5cred; 730132451Sroberto 731132451Sroberto error = (*iter->func->next)(iter, &ccred); 732132451Sroberto if (error) 733132451Sroberto break; 734132451Sroberto 735132451Sroberto if (ccred->data->version != cc_credentials_v5) 736132451Sroberto goto next; 737132451Sroberto 738132451Sroberto v5cred = ccred->data->credentials.credentials_v5; 739132451Sroberto 740132451Sroberto if (client && strcmp(v5cred->client, client) != 0) 741132451Sroberto goto next; 742132451Sroberto 743132451Sroberto if (strcmp(v5cred->server, server) != 0) 744132451Sroberto goto next; 745132451Sroberto 746132451Sroberto (*a->ccache->func->remove_credentials)(a->ccache, ccred); 747132451Sroberto ret = 0; 748182007Sroberto next: 749132451Sroberto (*ccred->func->release)(ccred); 750182007Sroberto } 751132451Sroberto 752132451Sroberto (*iter->func->release)(iter); 753132451Sroberto 754132451Sroberto if (ret) 755132451Sroberto krb5_set_error_string(context, "Can't find credential %s in cache", 756132451Sroberto server); 757132451Sroberto free(server); 758132451Sroberto free(client); 759132451Sroberto 760132451Sroberto return ret; 761182007Sroberto} 762132451Sroberto 763132451Srobertostatic krb5_error_code 764132451Srobertoacc_set_flags(krb5_context context, 765132451Sroberto krb5_ccache id, 766132451Sroberto krb5_flags flags) 767132451Sroberto{ 768132451Sroberto return 0; 769132451Sroberto} 770132451Sroberto 771132451Srobertostatic krb5_error_code 772182007Srobertoacc_get_version(krb5_context context, 773132451Sroberto krb5_ccache id) 774132451Sroberto{ 775132451Sroberto return 0; 776182007Sroberto} 777132451Sroberto 778132451Srobertostruct cache_iter { 779132451Sroberto cc_context_t context; 780132451Sroberto cc_ccache_iterator_t iter; 781132451Sroberto}; 782132451Sroberto 783182007Srobertostatic krb5_error_code 784132451Srobertoacc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) 785132451Sroberto{ 786182007Sroberto struct cache_iter *iter; 787182007Sroberto krb5_error_code ret; 788182007Sroberto cc_int32 error; 789132451Sroberto 790182007Sroberto ret = init_ccapi(context); 791132451Sroberto if (ret) 792132451Sroberto return ret; 793132451Sroberto 794132451Sroberto iter = calloc(1, sizeof(*iter)); 795132451Sroberto if (iter == NULL) { 796132451Sroberto krb5_set_error_string(context, "malloc - out of memory"); 797132451Sroberto return ENOMEM; 798132451Sroberto } 799132451Sroberto 800132451Sroberto error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL); 801132451Sroberto if (error) { 802132451Sroberto free(iter); 803132451Sroberto return translate_cc_error(context, error); 804132451Sroberto } 805132451Sroberto 806132451Sroberto error = (*iter->context->func->new_ccache_iterator)(iter->context, 807132451Sroberto &iter->iter); 808132451Sroberto if (error) { 809132451Sroberto free(iter); 810132451Sroberto krb5_clear_error_string(context); 811182007Sroberto return ENOENT; 812132451Sroberto } 813132451Sroberto *cursor = iter; 814132451Sroberto return 0; 815132451Sroberto} 816132451Sroberto 817132451Srobertostatic krb5_error_code 818132451Srobertoacc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) 819132451Sroberto{ 820132451Sroberto struct cache_iter *iter = cursor; 821182007Sroberto cc_ccache_t cache; 822132451Sroberto krb5_acc *a; 823132451Sroberto krb5_error_code ret; 824132451Sroberto int32_t error; 825132451Sroberto 826132451Sroberto error = (*iter->iter->func->next)(iter->iter, &cache); 827182007Sroberto if (error) 828132451Sroberto return translate_cc_error(context, error); 829132451Sroberto 830132451Sroberto ret = _krb5_cc_allocate(context, &krb5_acc_ops, id); 831132451Sroberto if (ret) { 832132451Sroberto (*cache->func->release)(cache); 833132451Sroberto return ret; 834132451Sroberto } 835132451Sroberto 836182007Sroberto ret = acc_alloc(context, id); 837182007Sroberto if (ret) { 838182007Sroberto (*cache->func->release)(cache); 839182007Sroberto free(*id); 840182007Sroberto return ret; 841132451Sroberto } 842132451Sroberto 843132451Sroberto a = ACACHE(*id); 844132451Sroberto a->ccache = cache; 845132451Sroberto 846182007Sroberto a->cache_name = get_cc_name(a->ccache); 847182007Sroberto if (a->cache_name == NULL) { 848182007Sroberto acc_close(context, *id); 849132451Sroberto *id = NULL; 850132451Sroberto krb5_set_error_string(context, "malloc: out of memory"); 851182007Sroberto return ENOMEM; 852132451Sroberto } 853132451Sroberto return 0; 854132451Sroberto} 855132451Sroberto 856132451Srobertostatic krb5_error_code 857182007Srobertoacc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) 858132451Sroberto{ 859132451Sroberto struct cache_iter *iter = cursor; 860182007Sroberto 861132451Sroberto (*iter->iter->func->release)(iter->iter); 862132451Sroberto iter->iter = NULL; 863132451Sroberto (*iter->context->func->release)(iter->context); 864132451Sroberto iter->context = NULL; 865182007Sroberto free(iter); 866182007Sroberto return 0; 867182007Sroberto} 868132451Sroberto 869132451Srobertostatic krb5_error_code 870132451Srobertoacc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 871132451Sroberto{ 872132451Sroberto krb5_acc *afrom = ACACHE(from); 873132451Sroberto krb5_acc *ato = ACACHE(to); 874132451Sroberto int32_t error; 875182007Sroberto 876132451Sroberto if (ato->ccache == NULL) { 877132451Sroberto cc_string_t name; 878132451Sroberto 879132451Sroberto error = (*afrom->ccache->func->get_principal)(afrom->ccache, 880132451Sroberto cc_credentials_v5, 881132451Sroberto &name); 882132451Sroberto if (error) 883132451Sroberto return translate_cc_error(context, error); 884132451Sroberto 885182007Sroberto error = (*ato->context->func->create_new_ccache)(ato->context, 886132451Sroberto cc_credentials_v5, 887132451Sroberto name->data, 888132451Sroberto &ato->ccache); 889132451Sroberto (*name->func->release)(name); 890132451Sroberto if (error) 891132451Sroberto return translate_cc_error(context, error); 892132451Sroberto } 893132451Sroberto 894132451Sroberto 895132451Sroberto error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache); 896132451Sroberto return translate_cc_error(context, error); 897132451Sroberto} 898182007Sroberto 899182007Srobertostatic krb5_error_code 900132451Srobertoacc_default_name(krb5_context context, char **str) 901182007Sroberto{ 902132451Sroberto krb5_error_code ret; 903182007Sroberto cc_context_t cc; 904182007Sroberto cc_string_t name; 905132451Sroberto int32_t error; 906132451Sroberto 907132451Sroberto ret = init_ccapi(context); 908132451Sroberto if (ret) 909132451Sroberto return ret; 910182007Sroberto 911132451Sroberto error = (*init_func)(&cc, ccapi_version_3, NULL, NULL); 912132451Sroberto if (error) 913132451Sroberto return translate_cc_error(context, error); 914132451Sroberto 915132451Sroberto error = (*cc->func->get_default_ccache_name)(cc, &name); 916182007Sroberto if (error) { 917182007Sroberto (*cc->func->release)(cc); 918182007Sroberto return translate_cc_error(context, error); 919132451Sroberto } 920132451Sroberto 921132451Sroberto asprintf(str, "API:%s", name->data); 922182007Sroberto (*name->func->release)(name); 923182007Sroberto (*cc->func->release)(cc); 924182007Sroberto 925182007Sroberto if (*str == NULL) { 926182007Sroberto krb5_set_error_string(context, "out of memory"); 927182007Sroberto return ENOMEM; 928182007Sroberto } 929182007Sroberto return 0; 930182007Sroberto} 931182007Sroberto 932182007Sroberto 933182007Sroberto/** 934132451Sroberto * Variable containing the API based credential cache implemention. 935182007Sroberto * 936182007Sroberto * @ingroup krb5_ccache 937182007Sroberto */ 938182007Sroberto 939182007Srobertoconst krb5_cc_ops krb5_acc_ops = { 940182007Sroberto "API", 941132451Sroberto acc_get_name, 942132451Sroberto acc_resolve, 943132451Sroberto acc_gen_new, 944132451Sroberto acc_initialize, 945132451Sroberto acc_destroy, 946132451Sroberto acc_close, 947132451Sroberto acc_store_cred, 948132451Sroberto NULL, /* acc_retrieve */ 949132451Sroberto acc_get_principal, 950182007Sroberto acc_get_first, 951182007Sroberto acc_get_next, 952182007Sroberto acc_end_get, 953132451Sroberto acc_remove_cred, 954182007Sroberto acc_set_flags, 955182007Sroberto acc_get_version, 956182007Sroberto acc_get_cache_first, 957182007Sroberto acc_get_cache_next, 958182007Sroberto acc_end_cache_get, 959182007Sroberto acc_move, 960182007Sroberto acc_default_name 961182007Sroberto}; 962182007Sroberto