root/source4/heimdal/lib/krb5/acache.c

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

DEFINITIONS

This source file includes following definitions.
  1. translate_cc_error
  2. init_ccapi
  3. make_cred_from_ccred
  4. free_ccred
  5. make_ccred_from_cred
  6. get_cc_name
  7. acc_get_name
  8. acc_alloc
  9. acc_resolve
  10. acc_gen_new
  11. acc_initialize
  12. acc_close
  13. acc_destroy
  14. acc_store_cred
  15. acc_get_principal
  16. acc_get_first
  17. acc_get_next
  18. acc_end_get
  19. acc_remove_cred
  20. acc_set_flags
  21. acc_get_version
  22. acc_get_cache_first
  23. acc_get_cache_next
  24. acc_end_cache_get
  25. acc_move
  26. acc_get_default_name
  27. acc_set_default
  28. acc_lastchange

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

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