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

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

DEFINITIONS

This source file includes following definitions.
  1. krb5_cc_register
  2. _krb5_cc_allocate
  3. allocate_ccache
  4. krb5_cc_resolve
  5. krb5_cc_gen_new
  6. krb5_cc_new_unique
  7. krb5_cc_get_name
  8. krb5_cc_get_type
  9. krb5_cc_get_full_name
  10. krb5_cc_get_ops
  11. _krb5_expand_default_cc_name
  12. environment_changed
  13. krb5_cc_switch
  14. krb5_cc_set_default_name
  15. krb5_cc_default_name
  16. krb5_cc_default
  17. krb5_cc_initialize
  18. krb5_cc_destroy
  19. krb5_cc_close
  20. krb5_cc_store_cred
  21. krb5_cc_retrieve_cred
  22. krb5_cc_get_principal
  23. krb5_cc_start_seq_get
  24. krb5_cc_next_cred
  25. krb5_cc_next_cred_match
  26. krb5_cc_end_seq_get
  27. krb5_cc_remove_cred
  28. krb5_cc_set_flags
  29. krb5_cc_get_flags
  30. krb5_cc_copy_cache_match
  31. krb5_cc_copy_cache
  32. krb5_cc_copy_creds
  33. krb5_cc_get_version
  34. krb5_cc_clear_mcred
  35. krb5_cc_get_prefix_ops
  36. krb5_cc_cache_get_first
  37. krb5_cc_cache_next
  38. krb5_cc_cache_end_seq_get
  39. krb5_cc_cache_match
  40. krb5_cc_move
  41. build_conf_principals
  42. krb5_is_config_principal
  43. krb5_cc_set_config
  44. krb5_cc_get_config
  45. krb5_cccol_cursor_new
  46. krb5_cccol_cursor_next
  47. krb5_cccol_cursor_free
  48. krb5_cc_last_change_time
  49. krb5_cccol_last_change_time

   1 /*
   2  * Copyright (c) 1997 - 2008 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 
  36 RCSID("$Id$");
  37 
  38 /**
  39  * Add a new ccache type with operations `ops', overwriting any
  40  * existing one if `override'.
  41  *
  42  * @param context a Keberos context
  43  * @param ops type of plugin symbol
  44  * @param override flag to select if the registration is to overide
  45  * an existing ops with the same name.
  46  *
  47  * @return Return an error code or 0, see krb5_get_error_message().
  48  *
  49  * @ingroup krb5_ccache
  50  */
  51 
  52 krb5_error_code KRB5_LIB_FUNCTION
  53 krb5_cc_register(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  54                  const krb5_cc_ops *ops,
  55                  krb5_boolean override)
  56 {
  57     int i;
  58 
  59     for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
  60         if(strcmp(context->cc_ops[i].prefix, ops->prefix) == 0) {
  61             if(!override) {
  62                 krb5_set_error_message(context,
  63                                        KRB5_CC_TYPE_EXISTS,
  64                                        N_("cache type %s already exists", "type"),
  65                                        ops->prefix);
  66                 return KRB5_CC_TYPE_EXISTS;
  67             }
  68             break;
  69         }
  70     }
  71     if(i == context->num_cc_ops) {
  72         krb5_cc_ops *o = realloc(context->cc_ops,
  73                                  (context->num_cc_ops + 1) *
  74                                  sizeof(*context->cc_ops));
  75         if(o == NULL) {
  76             krb5_set_error_message(context, KRB5_CC_NOMEM,
  77                                    N_("malloc: out of memory", ""));
  78             return KRB5_CC_NOMEM;
  79         }
  80         context->num_cc_ops++;
  81         context->cc_ops = o;
  82         memset(context->cc_ops + i, 0,
  83                (context->num_cc_ops - i) * sizeof(*context->cc_ops));
  84     }
  85     memcpy(&context->cc_ops[i], ops, sizeof(context->cc_ops[i]));
  86     return 0;
  87 }
  88 
  89 /*
  90  * Allocate the memory for a `id' and the that function table to
  91  * `ops'. Returns 0 or and error code.
  92  */
  93 
  94 krb5_error_code
  95 _krb5_cc_allocate(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  96                   const krb5_cc_ops *ops,
  97                   krb5_ccache *id)
  98 {
  99     krb5_ccache p;
 100 
 101     p = malloc (sizeof(*p));
 102     if(p == NULL) {
 103         krb5_set_error_message(context, KRB5_CC_NOMEM,
 104                                N_("malloc: out of memory", ""));
 105         return KRB5_CC_NOMEM;
 106     }
 107     p->ops = ops;
 108     *id = p;
 109 
 110     return 0;
 111 }
 112 
 113 /*
 114  * Allocate memory for a new ccache in `id' with operations `ops'
 115  * and name `residual'. Return 0 or an error code.
 116  */
 117 
 118 static krb5_error_code
 119 allocate_ccache (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 120                  const krb5_cc_ops *ops,
 121                  const char *residual,
 122                  krb5_ccache *id)
 123 {
 124     krb5_error_code ret;
 125 
 126     ret = _krb5_cc_allocate(context, ops, id);
 127     if (ret)
 128         return ret;
 129     ret = (*id)->ops->resolve(context, id, residual);
 130     if(ret)
 131         free(*id);
 132     return ret;
 133 }
 134 
 135 /**
 136  * Find and allocate a ccache in `id' from the specification in `residual'.
 137  * If the ccache name doesn't contain any colon, interpret it as a file name.
 138  *
 139  * @param context a Keberos context.
 140  * @param name string name of a credential cache.
 141  * @param id return pointer to a found credential cache.
 142  *
 143  * @return Return 0 or an error code. In case of an error, id is set
 144  * to NULL, see krb5_get_error_message().
 145  *
 146  * @ingroup krb5_ccache
 147  */
 148 
 149 
 150 krb5_error_code KRB5_LIB_FUNCTION
 151 krb5_cc_resolve(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 152                 const char *name,
 153                 krb5_ccache *id)
 154 {
 155     int i;
 156 
 157     *id = NULL;
 158 
 159     for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
 160         size_t prefix_len = strlen(context->cc_ops[i].prefix);
 161 
 162         if(strncmp(context->cc_ops[i].prefix, name, prefix_len) == 0
 163            && name[prefix_len] == ':') {
 164             return allocate_ccache (context, &context->cc_ops[i],
 165                                     name + prefix_len + 1,
 166                                     id);
 167         }
 168     }
 169     if (strchr (name, ':') == NULL)
 170         return allocate_ccache (context, &krb5_fcc_ops, name, id);
 171     else {
 172         krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
 173                                N_("unknown ccache type %s", "name"), name);
 174         return KRB5_CC_UNKNOWN_TYPE;
 175     }
 176 }
 177 
 178 /**
 179  * Generate a new ccache of type `ops' in `id'.
 180  *
 181  * @return Return an error code or 0, see krb5_get_error_message().
 182  *
 183  * @ingroup krb5_ccache
 184  */
 185 
 186 
 187 krb5_error_code KRB5_LIB_FUNCTION
 188 krb5_cc_gen_new(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 189                 const krb5_cc_ops *ops,
 190                 krb5_ccache *id)
 191 {
 192     return krb5_cc_new_unique(context, ops->prefix, NULL, id);
 193 }
 194 
 195 /**
 196  * Generates a new unique ccache of `type` in `id'. If `type' is NULL,
 197  * the library chooses the default credential cache type. The supplied
 198  * `hint' (that can be NULL) is a string that the credential cache
 199  * type can use to base the name of the credential on, this is to make
 200  * it easier for the user to differentiate the credentials.
 201  *
 202  * @return Return an error code or 0, see krb5_get_error_message().
 203  *
 204  * @ingroup krb5_ccache
 205  */
 206 
 207 krb5_error_code KRB5_LIB_FUNCTION
 208 krb5_cc_new_unique(krb5_context context, const char *type,
     /* [<][>][^][v][top][bottom][index][help] */
 209                    const char *hint, krb5_ccache *id)
 210 {
 211     const krb5_cc_ops *ops;
 212     krb5_error_code ret;
 213 
 214     ops = krb5_cc_get_prefix_ops(context, type);
 215     if (ops == NULL) {
 216         krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
 217                               "Credential cache type %s is unknown", type);
 218         return KRB5_CC_UNKNOWN_TYPE;
 219     }
 220 
 221     ret = _krb5_cc_allocate(context, ops, id);
 222     if (ret)
 223         return ret;
 224     return (*id)->ops->gen_new(context, id);
 225 }
 226 
 227 /**
 228  * Return the name of the ccache `id'
 229  *
 230  * @ingroup krb5_ccache
 231  */
 232 
 233 
 234 const char* KRB5_LIB_FUNCTION
 235 krb5_cc_get_name(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 236                  krb5_ccache id)
 237 {
 238     return id->ops->get_name(context, id);
 239 }
 240 
 241 /**
 242  * Return the type of the ccache `id'.
 243  *
 244  * @ingroup krb5_ccache
 245  */
 246 
 247 
 248 const char* KRB5_LIB_FUNCTION
 249 krb5_cc_get_type(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 250                  krb5_ccache id)
 251 {
 252     return id->ops->prefix;
 253 }
 254 
 255 /**
 256  * Return the complete resolvable name the ccache `id' in `str´.
 257  * `str` should be freed with free(3).
 258  * Returns 0 or an error (and then *str is set to NULL).
 259  *
 260  * @ingroup krb5_ccache
 261  */
 262 
 263 
 264 krb5_error_code KRB5_LIB_FUNCTION
 265 krb5_cc_get_full_name(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 266                       krb5_ccache id,
 267                       char **str)
 268 {
 269     const char *type, *name;
 270 
 271     *str = NULL;
 272 
 273     type = krb5_cc_get_type(context, id);
 274     if (type == NULL) {
 275         krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
 276                                "cache have no name of type");
 277         return KRB5_CC_UNKNOWN_TYPE;
 278     }
 279 
 280     name = krb5_cc_get_name(context, id);
 281     if (name == NULL) {
 282         krb5_set_error_message(context, KRB5_CC_BADNAME,
 283                                "cache of type %s have no name", type);
 284         return KRB5_CC_BADNAME;
 285     }
 286 
 287     if (asprintf(str, "%s:%s", type, name) == -1) {
 288         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 289         *str = NULL;
 290         return ENOMEM;
 291     }
 292     return 0;
 293 }
 294 
 295 /**
 296  * Return krb5_cc_ops of a the ccache `id'.
 297  *
 298  * @ingroup krb5_ccache
 299  */
 300 
 301 
 302 const krb5_cc_ops *
 303 krb5_cc_get_ops(krb5_context context, krb5_ccache id)
     /* [<][>][^][v][top][bottom][index][help] */
 304 {
 305     return id->ops;
 306 }
 307 
 308 /*
 309  * Expand variables in `str' into `res'
 310  */
 311 
 312 krb5_error_code
 313 _krb5_expand_default_cc_name(krb5_context context, const char *str, char **res)
     /* [<][>][^][v][top][bottom][index][help] */
 314 {
 315     size_t tlen, len = 0;
 316     char *tmp, *tmp2, *append;
 317 
 318     *res = NULL;
 319 
 320     while (str && *str) {
 321         tmp = strstr(str, "%{");
 322         if (tmp && tmp != str) {
 323             append = malloc((tmp - str) + 1);
 324             if (append) {
 325                 memcpy(append, str, tmp - str);
 326                 append[tmp - str] = '\0';
 327             }
 328             str = tmp;
 329         } else if (tmp) {
 330             tmp2 = strchr(tmp, '}');
 331             if (tmp2 == NULL) {
 332                 free(*res);
 333                 *res = NULL;
 334                 krb5_set_error_message(context, KRB5_CONFIG_BADFORMAT,
 335                                        "variable missing }");
 336                 return KRB5_CONFIG_BADFORMAT;
 337             }
 338             if (strncasecmp(tmp, "%{uid}", 6) == 0)
 339                 asprintf(&append, "%u", (unsigned)getuid());
 340             else if (strncasecmp(tmp, "%{null}", 7) == 0)
 341                 append = strdup("");
 342             else {
 343                 free(*res);
 344                 *res = NULL;
 345                 krb5_set_error_message(context,
 346                                        KRB5_CONFIG_BADFORMAT,
 347                                        "expand default cache unknown "
 348                                        "variable \"%.*s\"",
 349                                        (int)(tmp2 - tmp) - 2, tmp + 2);
 350                 return KRB5_CONFIG_BADFORMAT;
 351             }
 352             str = tmp2 + 1;
 353         } else {
 354             append = strdup(str);
 355             str = NULL;
 356         }
 357         if (append == NULL) {
 358             free(*res);
 359             *res = NULL;
 360             krb5_set_error_message(context, ENOMEM,
 361                                    N_("malloc: out of memory", ""));
 362             return ENOMEM;
 363         }
 364         
 365         tlen = strlen(append);
 366         tmp = realloc(*res, len + tlen + 1);
 367         if (tmp == NULL) {
 368             free(append);
 369             free(*res);
 370             *res = NULL;
 371             krb5_set_error_message(context, ENOMEM,
 372                                    N_("malloc: out of memory", ""));
 373             return ENOMEM;
 374         }
 375         *res = tmp;
 376         memcpy(*res + len, append, tlen + 1);
 377         len = len + tlen;
 378         free(append);
 379     }
 380     return 0;
 381 }
 382 
 383 /*
 384  * Return non-zero if envirnoment that will determine default krb5cc
 385  * name has changed.
 386  */
 387 
 388 static int
 389 environment_changed(krb5_context context)
     /* [<][>][^][v][top][bottom][index][help] */
 390 {
 391     const char *e;
 392 
 393     /* if the cc name was set, don't change it */
 394     if (context->default_cc_name_set)
 395         return 0;
 396 
 397     if(issuid())
 398         return 0;
 399 
 400     e = getenv("KRB5CCNAME");
 401     if (e == NULL) {
 402         if (context->default_cc_name_env) {
 403             free(context->default_cc_name_env);
 404             context->default_cc_name_env = NULL;
 405             return 1;
 406         }
 407     } else {
 408         if (context->default_cc_name_env == NULL)
 409             return 1;
 410         if (strcmp(e, context->default_cc_name_env) != 0)
 411             return 1;
 412     }
 413     return 0;
 414 }
 415 
 416 /**
 417  * Switch the default default credential cache for a specific
 418  * credcache type (and name for some implementations).
 419  *
 420  * @return Return an error code or 0, see krb5_get_error_message().
 421  *
 422  * @ingroup krb5_ccache
 423  */
 424 
 425 krb5_error_code
 426 krb5_cc_switch(krb5_context context, krb5_ccache id)
     /* [<][>][^][v][top][bottom][index][help] */
 427 {
 428 
 429     if (id->ops->set_default == NULL)
 430         return 0;
 431 
 432     return (*id->ops->set_default)(context, id);
 433 }
 434 
 435 /**
 436  * Set the default cc name for `context' to `name'.
 437  *
 438  * @ingroup krb5_ccache
 439  */
 440 
 441 krb5_error_code KRB5_LIB_FUNCTION
 442 krb5_cc_set_default_name(krb5_context context, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 443 {
 444     krb5_error_code ret = 0;
 445     char *p;
 446 
 447     if (name == NULL) {
 448         const char *e = NULL;
 449 
 450         if(!issuid()) {
 451             e = getenv("KRB5CCNAME");
 452             if (e) {
 453                 p = strdup(e);
 454                 if (context->default_cc_name_env)
 455                     free(context->default_cc_name_env);
 456                 context->default_cc_name_env = strdup(e);
 457             }
 458         }
 459         if (e == NULL) {
 460             e = krb5_config_get_string(context, NULL, "libdefaults",
 461                                        "default_cc_name", NULL);
 462             if (e) {
 463                 ret = _krb5_expand_default_cc_name(context, e, &p);
 464                 if (ret)
 465                     return ret;
 466             }
 467             if (e == NULL) {
 468                 const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE;
 469                 e = krb5_config_get_string(context, NULL, "libdefaults",
 470                                            "default_cc_type", NULL);
 471                 if (e) {
 472                     ops = krb5_cc_get_prefix_ops(context, e);
 473                     if (ops == NULL) {
 474                         krb5_set_error_message(context,
 475                                                KRB5_CC_UNKNOWN_TYPE,
 476                                                "Credential cache type %s "
 477                                               "is unknown", e);
 478                         return KRB5_CC_UNKNOWN_TYPE;
 479                     }
 480                 }
 481                 ret = (*ops->get_default_name)(context, &p);
 482                 if (ret)
 483                     return ret;
 484             }
 485         }
 486         context->default_cc_name_set = 0;
 487     } else {
 488         p = strdup(name);
 489         context->default_cc_name_set = 1;
 490     }
 491 
 492     if (p == NULL) {
 493         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 494         return ENOMEM;
 495     }
 496 
 497     if (context->default_cc_name)
 498         free(context->default_cc_name);
 499 
 500     context->default_cc_name = p;
 501 
 502     return ret;
 503 }
 504 
 505 /**
 506  * Return a pointer to a context static string containing the default
 507  * ccache name.
 508  *
 509  * @return String to the default credential cache name.
 510  *
 511  * @ingroup krb5_ccache
 512  */
 513 
 514 
 515 const char* KRB5_LIB_FUNCTION
 516 krb5_cc_default_name(krb5_context context)
     /* [<][>][^][v][top][bottom][index][help] */
 517 {
 518     if (context->default_cc_name == NULL || environment_changed(context))
 519         krb5_cc_set_default_name(context, NULL);
 520 
 521     return context->default_cc_name;
 522 }
 523 
 524 /**
 525  * Open the default ccache in `id'.
 526  *
 527  * @return Return an error code or 0, see krb5_get_error_message().
 528  *
 529  * @ingroup krb5_ccache
 530  */
 531 
 532 
 533 krb5_error_code KRB5_LIB_FUNCTION
 534 krb5_cc_default(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 535                 krb5_ccache *id)
 536 {
 537     const char *p = krb5_cc_default_name(context);
 538 
 539     if (p == NULL) {
 540         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 541         return ENOMEM;
 542     }
 543     return krb5_cc_resolve(context, p, id);
 544 }
 545 
 546 /**
 547  * Create a new ccache in `id' for `primary_principal'.
 548  *
 549  * @return Return an error code or 0, see krb5_get_error_message().
 550  *
 551  * @ingroup krb5_ccache
 552  */
 553 
 554 
 555 krb5_error_code KRB5_LIB_FUNCTION
 556 krb5_cc_initialize(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 557                    krb5_ccache id,
 558                    krb5_principal primary_principal)
 559 {
 560     return (*id->ops->init)(context, id, primary_principal);
 561 }
 562 
 563 
 564 /**
 565  * Remove the ccache `id'.
 566  *
 567  * @return Return an error code or 0, see krb5_get_error_message().
 568  *
 569  * @ingroup krb5_ccache
 570  */
 571 
 572 
 573 krb5_error_code KRB5_LIB_FUNCTION
 574 krb5_cc_destroy(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 575                 krb5_ccache id)
 576 {
 577     krb5_error_code ret;
 578 
 579     ret = (*id->ops->destroy)(context, id);
 580     krb5_cc_close (context, id);
 581     return ret;
 582 }
 583 
 584 /**
 585  * Stop using the ccache `id' and free the related resources.
 586  *
 587  * @return Return an error code or 0, see krb5_get_error_message().
 588  *
 589  * @ingroup krb5_ccache
 590  */
 591 
 592 
 593 krb5_error_code KRB5_LIB_FUNCTION
 594 krb5_cc_close(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 595               krb5_ccache id)
 596 {
 597     krb5_error_code ret;
 598     ret = (*id->ops->close)(context, id);
 599     free(id);
 600     return ret;
 601 }
 602 
 603 /**
 604  * Store `creds' in the ccache `id'.
 605  *
 606  * @return Return an error code or 0, see krb5_get_error_message().
 607  *
 608  * @ingroup krb5_ccache
 609  */
 610 
 611 
 612 krb5_error_code KRB5_LIB_FUNCTION
 613 krb5_cc_store_cred(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 614                    krb5_ccache id,
 615                    krb5_creds *creds)
 616 {
 617     return (*id->ops->store)(context, id, creds);
 618 }
 619 
 620 /**
 621  * Retrieve the credential identified by `mcreds' (and `whichfields')
 622  * from `id' in `creds'. 'creds' must be free by the caller using
 623  * krb5_free_cred_contents.
 624  *
 625  * @return Return an error code or 0, see krb5_get_error_message().
 626  *
 627  * @ingroup krb5_ccache
 628  */
 629 
 630 
 631 krb5_error_code KRB5_LIB_FUNCTION
 632 krb5_cc_retrieve_cred(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 633                       krb5_ccache id,
 634                       krb5_flags whichfields,
 635                       const krb5_creds *mcreds,
 636                       krb5_creds *creds)
 637 {
 638     krb5_error_code ret;
 639     krb5_cc_cursor cursor;
 640 
 641     if (id->ops->retrieve != NULL) {
 642         return (*id->ops->retrieve)(context, id, whichfields,
 643                                     mcreds, creds);
 644     }
 645 
 646     ret = krb5_cc_start_seq_get(context, id, &cursor);
 647     if (ret)
 648         return ret;
 649     while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){
 650         if(krb5_compare_creds(context, whichfields, mcreds, creds)){
 651             ret = 0;
 652             break;
 653         }
 654         krb5_free_cred_contents (context, creds);
 655     }
 656     krb5_cc_end_seq_get(context, id, &cursor);
 657     return ret;
 658 }
 659 
 660 /**
 661  * Return the principal of `id' in `principal'.
 662  *
 663  * @return Return an error code or 0, see krb5_get_error_message().
 664  *
 665  * @ingroup krb5_ccache
 666  */
 667 
 668 
 669 krb5_error_code KRB5_LIB_FUNCTION
 670 krb5_cc_get_principal(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 671                       krb5_ccache id,
 672                       krb5_principal *principal)
 673 {
 674     return (*id->ops->get_princ)(context, id, principal);
 675 }
 676 
 677 /**
 678  * Start iterating over `id', `cursor' is initialized to the
 679  * beginning.
 680  *
 681  * @return Return an error code or 0, see krb5_get_error_message().
 682  *
 683  * @ingroup krb5_ccache
 684  */
 685 
 686 
 687 krb5_error_code KRB5_LIB_FUNCTION
 688 krb5_cc_start_seq_get (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 689                        const krb5_ccache id,
 690                        krb5_cc_cursor *cursor)
 691 {
 692     return (*id->ops->get_first)(context, id, cursor);
 693 }
 694 
 695 /**
 696  * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
 697  * and advance `cursor'.
 698  *
 699  * @return Return an error code or 0, see krb5_get_error_message().
 700  *
 701  * @ingroup krb5_ccache
 702  */
 703 
 704 
 705 krb5_error_code KRB5_LIB_FUNCTION
 706 krb5_cc_next_cred (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 707                    const krb5_ccache id,
 708                    krb5_cc_cursor *cursor,
 709                    krb5_creds *creds)
 710 {
 711     return (*id->ops->get_next)(context, id, cursor, creds);
 712 }
 713 
 714 /**
 715  * Like krb5_cc_next_cred, but allow for selective retrieval
 716  *
 717  * @ingroup krb5_ccache
 718  */
 719 
 720 
 721 krb5_error_code KRB5_LIB_FUNCTION
 722 krb5_cc_next_cred_match(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 723                         const krb5_ccache id,
 724                         krb5_cc_cursor * cursor,
 725                         krb5_creds * creds,
 726                         krb5_flags whichfields,
 727                         const krb5_creds * mcreds)
 728 {
 729     krb5_error_code ret;
 730     while (1) {
 731         ret = krb5_cc_next_cred(context, id, cursor, creds);
 732         if (ret)
 733             return ret;
 734         if (mcreds == NULL || krb5_compare_creds(context, whichfields, mcreds, creds))
 735             return 0;
 736         krb5_free_cred_contents(context, creds);
 737     }
 738 }
 739 
 740 /**
 741  * Destroy the cursor `cursor'.
 742  *
 743  * @ingroup krb5_ccache
 744  */
 745 
 746 
 747 krb5_error_code KRB5_LIB_FUNCTION
 748 krb5_cc_end_seq_get (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 749                      const krb5_ccache id,
 750                      krb5_cc_cursor *cursor)
 751 {
 752     return (*id->ops->end_get)(context, id, cursor);
 753 }
 754 
 755 /**
 756  * Remove the credential identified by `cred', `which' from `id'.
 757  *
 758  * @ingroup krb5_ccache
 759  */
 760 
 761 
 762 krb5_error_code KRB5_LIB_FUNCTION
 763 krb5_cc_remove_cred(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 764                     krb5_ccache id,
 765                     krb5_flags which,
 766                     krb5_creds *cred)
 767 {
 768     if(id->ops->remove_cred == NULL) {
 769         krb5_set_error_message(context,
 770                                EACCES,
 771                                "ccache %s does not support remove_cred",
 772                                id->ops->prefix);
 773         return EACCES; /* XXX */
 774     }
 775     return (*id->ops->remove_cred)(context, id, which, cred);
 776 }
 777 
 778 /**
 779  * Set the flags of `id' to `flags'.
 780  *
 781  * @ingroup krb5_ccache
 782  */
 783 
 784 
 785 krb5_error_code KRB5_LIB_FUNCTION
 786 krb5_cc_set_flags(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 787                   krb5_ccache id,
 788                   krb5_flags flags)
 789 {
 790     return (*id->ops->set_flags)(context, id, flags);
 791 }
 792                 
 793 /**
 794  * Get the flags of `id', store them in `flags'.
 795  *
 796  * @ingroup krb5_ccache
 797  */
 798 
 799 krb5_error_code KRB5_LIB_FUNCTION
 800 krb5_cc_get_flags(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 801                   krb5_ccache id,
 802                   krb5_flags *flags)
 803 {
 804     *flags = 0;
 805     return 0;
 806 }
 807 
 808 /**
 809  * Copy the contents of `from' to `to'.
 810  *
 811  * @ingroup krb5_ccache
 812  */
 813 
 814 
 815 krb5_error_code KRB5_LIB_FUNCTION
 816 krb5_cc_copy_cache_match(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 817                          const krb5_ccache from,
 818                          krb5_ccache to,
 819                          krb5_flags whichfields,
 820                          const krb5_creds * mcreds,
 821                          unsigned int *matched)
 822 {
 823     krb5_error_code ret;
 824     krb5_cc_cursor cursor;
 825     krb5_creds cred;
 826     krb5_principal princ;
 827 
 828     ret = krb5_cc_get_principal(context, from, &princ);
 829     if (ret)
 830         return ret;
 831     ret = krb5_cc_initialize(context, to, princ);
 832     if (ret) {
 833         krb5_free_principal(context, princ);
 834         return ret;
 835     }
 836     ret = krb5_cc_start_seq_get(context, from, &cursor);
 837     if (ret) {
 838         krb5_free_principal(context, princ);
 839         return ret;
 840     }
 841     if (matched)
 842         *matched = 0;
 843     while (ret == 0 &&
 844            krb5_cc_next_cred_match(context, from, &cursor, &cred,
 845                                    whichfields, mcreds) == 0) {
 846         if (matched)
 847             (*matched)++;
 848         ret = krb5_cc_store_cred(context, to, &cred);
 849         krb5_free_cred_contents(context, &cred);
 850     }
 851     krb5_cc_end_seq_get(context, from, &cursor);
 852     krb5_free_principal(context, princ);
 853     return ret;
 854 }
 855 
 856 
 857 /**
 858  * Just like krb5_cc_copy_cache_match, but copy everything.
 859  *
 860  * @ingroup @krb5_ccache
 861  */
 862 
 863 krb5_error_code KRB5_LIB_FUNCTION
 864 krb5_cc_copy_cache(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 865                    const krb5_ccache from,
 866                    krb5_ccache to)
 867 {
 868     return krb5_cc_copy_cache_match(context, from, to, 0, NULL, NULL);
 869 }
 870 
 871 /**
 872  * MIT compat glue
 873  *
 874  * @ingroup krb5_ccache
 875  */
 876 
 877 krb5_error_code KRB5_LIB_FUNCTION
 878 krb5_cc_copy_creds(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 879                    const krb5_ccache from,
 880                    krb5_ccache to)
 881 {
 882     return krb5_cc_copy_cache(context, from, to);
 883 }
 884 
 885 /**
 886  * Return the version of `id'.
 887  *
 888  * @ingroup krb5_ccache
 889  */
 890 
 891 
 892 krb5_error_code KRB5_LIB_FUNCTION
 893 krb5_cc_get_version(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 894                     const krb5_ccache id)
 895 {
 896     if(id->ops->get_version)
 897         return (*id->ops->get_version)(context, id);
 898     else
 899         return 0;
 900 }
 901 
 902 /**
 903  * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
 904  *
 905  * @ingroup krb5_ccache
 906  */
 907 
 908 
 909 void KRB5_LIB_FUNCTION
 910 krb5_cc_clear_mcred(krb5_creds *mcred)
     /* [<][>][^][v][top][bottom][index][help] */
 911 {
 912     memset(mcred, 0, sizeof(*mcred));
 913 }
 914 
 915 /**
 916  * Get the cc ops that is registered in `context' to handle the
 917  * prefix. prefix can be a complete credential cache name or a
 918  * prefix, the function will only use part up to the first colon (:)
 919  * if there is one. If prefix the argument is NULL, the default ccache
 920  * implemtation is returned.
 921  *
 922  * @return Returns NULL if ops not found.
 923  *
 924  * @ingroup krb5_ccache
 925  */
 926 
 927 
 928 const krb5_cc_ops *
 929 krb5_cc_get_prefix_ops(krb5_context context, const char *prefix)
     /* [<][>][^][v][top][bottom][index][help] */
 930 {
 931     char *p, *p1;
 932     int i;
 933 
 934     if (prefix == NULL)
 935         return KRB5_DEFAULT_CCTYPE;
 936     if (prefix[0] == '/')
 937         return &krb5_fcc_ops;
 938 
 939     p = strdup(prefix);
 940     if (p == NULL) {
 941         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 942         return NULL;
 943     }
 944     p1 = strchr(p, ':');
 945     if (p1)
 946         *p1 = '\0';
 947 
 948     for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) {
 949         if(strcmp(context->cc_ops[i].prefix, p) == 0) {
 950             free(p);
 951             return &context->cc_ops[i];
 952         }
 953     }
 954     free(p);
 955     return NULL;
 956 }
 957 
 958 struct krb5_cc_cache_cursor_data {
 959     const krb5_cc_ops *ops;
 960     krb5_cc_cursor cursor;
 961 };
 962 
 963 /**
 964  * Start iterating over all caches of specified type. See also
 965  * krb5_cccol_cursor_new().
 966 
 967  * @param context A Kerberos 5 context
 968  * @param type optional type to iterate over, if NULL, the default cache is used.
 969  * @param cursor cursor should be freed with krb5_cc_cache_end_seq_get().
 970  *
 971  * @return Return an error code or 0, see krb5_get_error_message().
 972  *
 973  * @ingroup krb5_ccache
 974  */
 975 
 976 
 977 krb5_error_code KRB5_LIB_FUNCTION
 978 krb5_cc_cache_get_first (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 979                          const char *type,
 980                          krb5_cc_cache_cursor *cursor)
 981 {
 982     const krb5_cc_ops *ops;
 983     krb5_error_code ret;
 984 
 985     if (type == NULL)
 986         type = krb5_cc_default_name(context);
 987 
 988     ops = krb5_cc_get_prefix_ops(context, type);
 989     if (ops == NULL) {
 990         krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
 991                                "Unknown type \"%s\" when iterating "
 992                                "trying to iterate the credential caches", type);
 993         return KRB5_CC_UNKNOWN_TYPE;
 994     }
 995 
 996     if (ops->get_cache_first == NULL) {
 997         krb5_set_error_message(context, KRB5_CC_NOSUPP,
 998                                N_("Credential cache type %s doesn't support "
 999                                  "iterations over caches", "type"),
1000                                ops->prefix);
1001         return KRB5_CC_NOSUPP;
1002     }
1003 
1004     *cursor = calloc(1, sizeof(**cursor));
1005     if (*cursor == NULL) {
1006         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1007         return ENOMEM;
1008     }
1009 
1010     (*cursor)->ops = ops;
1011 
1012     ret = ops->get_cache_first(context, &(*cursor)->cursor);
1013     if (ret) {
1014         free(*cursor);
1015         *cursor = NULL;
1016     }
1017     return ret;
1018 }
1019 
1020 /**
1021  * Retrieve the next cache pointed to by (`cursor') in `id'
1022  * and advance `cursor'.
1023  *
1024  * @return Return 0 or an error code. Returns KRB5_CC_END when the end
1025  *         of caches is reached, see krb5_get_error_message().
1026  *
1027  * @ingroup krb5_ccache
1028  */
1029 
1030 
1031 krb5_error_code KRB5_LIB_FUNCTION
1032 krb5_cc_cache_next (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1033                    krb5_cc_cache_cursor cursor,
1034                    krb5_ccache *id)
1035 {
1036     return cursor->ops->get_cache_next(context, cursor->cursor, id);
1037 }
1038 
1039 /**
1040  * Destroy the cursor `cursor'.
1041  *
1042  * @return Return an error code or 0, see krb5_get_error_message().
1043  *
1044  * @ingroup krb5_ccache
1045  */
1046 
1047 
1048 krb5_error_code KRB5_LIB_FUNCTION
1049 krb5_cc_cache_end_seq_get (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1050                            krb5_cc_cache_cursor cursor)
1051 {
1052     krb5_error_code ret;
1053     ret = cursor->ops->end_cache_get(context, cursor->cursor);
1054     cursor->ops = NULL;
1055     free(cursor);
1056     return ret;
1057 }
1058 
1059 /**
1060  * Search for a matching credential cache of type `type' that have the
1061  * `principal' as the default principal. On success, `id' needs to be
1062  * freed with krb5_cc_close() or krb5_cc_destroy().
1063  *
1064  * @return On failure, error code is returned and `id' is set to NULL.
1065  *
1066  * @ingroup krb5_ccache
1067  */
1068 
1069 
1070 krb5_error_code KRB5_LIB_FUNCTION
1071 krb5_cc_cache_match (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1072                      krb5_principal client,
1073                      krb5_ccache *id)
1074 {
1075     krb5_cccol_cursor cursor;
1076     krb5_error_code ret;
1077     krb5_ccache cache = NULL;
1078 
1079     *id = NULL;
1080 
1081     ret = krb5_cccol_cursor_new (context, &cursor);
1082     if (ret)
1083         return ret;
1084 
1085     while ((ret = krb5_cccol_cursor_next (context, cursor, &cache)) == 0) {
1086         krb5_principal principal;
1087 
1088         ret = krb5_cc_get_principal(context, cache, &principal);
1089         if (ret == 0) {
1090             krb5_boolean match;
1091         
1092             match = krb5_principal_compare(context, principal, client);
1093             krb5_free_principal(context, principal);
1094             if (match)
1095                 break;
1096         }
1097 
1098         krb5_cc_close(context, cache);
1099         cache = NULL;
1100     }
1101 
1102     krb5_cccol_cursor_free(context, &cursor);
1103 
1104     if (cache == NULL) {
1105         char *str;
1106 
1107         krb5_unparse_name(context, client, &str);
1108 
1109         krb5_set_error_message(context, KRB5_CC_NOTFOUND,
1110                                N_("Principal %s not found in a "
1111                                   "credential cache", ""),
1112                                str ? str : "<out of memory>");
1113         if (str)
1114             free(str);
1115         return KRB5_CC_NOTFOUND;
1116     }
1117     *id = cache;
1118 
1119     return 0;
1120 }
1121 
1122 /**
1123  * Move the content from one credential cache to another. The
1124  * operation is an atomic switch.
1125  *
1126  * @param context a Keberos context
1127  * @param from the credential cache to move the content from
1128  * @param to the credential cache to move the content to
1129 
1130  * @return On sucess, from is freed. On failure, error code is
1131  * returned and from and to are both still allocated, see krb5_get_error_message().
1132  *
1133  * @ingroup krb5_ccache
1134  */
1135 
1136 krb5_error_code
1137 krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
     /* [<][>][^][v][top][bottom][index][help] */
1138 {
1139     krb5_error_code ret;
1140 
1141     if (strcmp(from->ops->prefix, to->ops->prefix) != 0) {
1142         krb5_set_error_message(context, KRB5_CC_NOSUPP,
1143                                N_("Moving credentials between diffrent "
1144                                  "types not yet supported", ""));
1145         return KRB5_CC_NOSUPP;
1146     }
1147 
1148     ret = (*to->ops->move)(context, from, to);
1149     if (ret == 0) {
1150         memset(from, 0, sizeof(*from));
1151         free(from);
1152     }
1153     return ret;
1154 }
1155 
1156 #define KRB5_CONF_NAME "krb5_ccache_conf_data"
1157 #define KRB5_REALM_NAME "X-CACHECONF:"
1158 
1159 static krb5_error_code
1160 build_conf_principals(krb5_context context, krb5_ccache id,
     /* [<][>][^][v][top][bottom][index][help] */
1161                       krb5_const_principal principal,
1162                       const char *name, krb5_creds *cred)
1163 {
1164     krb5_principal client;
1165     krb5_error_code ret;
1166     char *pname = NULL;
1167 
1168     memset(cred, 0, sizeof(*cred));
1169 
1170     ret = krb5_cc_get_principal(context, id, &client);
1171     if (ret)
1172         return ret;
1173 
1174     if (principal) {
1175         ret = krb5_unparse_name(context, principal, &pname);
1176         if (ret)
1177             return ret;
1178     }
1179 
1180     ret = krb5_make_principal(context, &cred->server,
1181                               krb5_principal_get_realm(context, client),
1182                               KRB5_CONF_NAME, name, pname, NULL);
1183     free(pname);
1184     if (ret) {
1185         krb5_free_principal(context, client);
1186         return ret;
1187     }
1188     ret = krb5_copy_principal(context, client, &cred->client);
1189     krb5_free_principal(context, client);
1190     return ret;
1191 }
1192                 
1193 /**
1194  * Return TRUE (non zero) if the principal is a configuration
1195  * principal (generated part of krb5_cc_set_config()). Returns FALSE
1196  * (zero) if not a configuration principal.
1197  *
1198  * @param context a Keberos context
1199  * @param principal principal to check if it a configuration principal
1200  *
1201  * @ingroup krb5_ccache
1202  */
1203 
1204 krb5_boolean KRB5_LIB_FUNCTION
1205 krb5_is_config_principal(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1206                          krb5_const_principal principal)
1207 {
1208     if (strcmp(principal->realm, KRB5_REALM_NAME) != 0)
1209         return FALSE;
1210 
1211     if (principal->name.name_string.len == 0 ||
1212         strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0)
1213         return FALSE;
1214         
1215     return TRUE;
1216 }
1217 
1218 /**
1219  * Store some configuration for the credential cache in the cache.
1220  * Existing configuration under the same name is over-written.
1221  *
1222  * @param context a Keberos context
1223  * @param id the credential cache to store the data for
1224  * @param principal configuration for a specific principal, if
1225  * NULL, global for the whole cache.
1226  * @param name name under which the configuraion is stored.
1227  * @param data data to store
1228  *
1229  * @ingroup krb5_ccache
1230  */
1231 
1232 krb5_error_code KRB5_LIB_FUNCTION
1233 krb5_cc_set_config(krb5_context context, krb5_ccache id,
     /* [<][>][^][v][top][bottom][index][help] */
1234                    krb5_const_principal principal,
1235                    const char *name, krb5_data *data)
1236 {
1237     krb5_error_code ret;
1238     krb5_creds cred;
1239 
1240     ret = build_conf_principals(context, id, principal, name, &cred);
1241     if (ret)
1242         goto out;
1243 
1244     /* Remove old configuration */
1245     ret = krb5_cc_remove_cred(context, id, 0, &cred);
1246     if (ret && ret != KRB5_CC_NOTFOUND)
1247         goto out;
1248 
1249     /* not that anyone care when this expire */
1250     cred.times.authtime = time(NULL);
1251     cred.times.endtime = cred.times.authtime + 3600 * 24 * 30;
1252 
1253     ret = krb5_data_copy(&cred.ticket, data->data, data->length);
1254     if (ret)
1255         goto out;
1256 
1257     ret = krb5_cc_store_cred(context, id, &cred);
1258 
1259 out:
1260     krb5_free_cred_contents (context, &cred);
1261     return ret;
1262 }
1263 
1264 /**
1265  * Get some configuration for the credential cache in the cache.
1266  *
1267  * @param context a Keberos context
1268  * @param id the credential cache to store the data for
1269  * @param principal configuration for a specific principal, if
1270  * NULL, global for the whole cache.
1271  * @param name name under which the configuraion is stored.
1272  * @param data data to fetched, free with krb5_data_free()
1273  *
1274  * @ingroup krb5_ccache
1275  */
1276 
1277 
1278 krb5_error_code KRB5_LIB_FUNCTION
1279 krb5_cc_get_config(krb5_context context, krb5_ccache id,
     /* [<][>][^][v][top][bottom][index][help] */
1280                    krb5_const_principal principal,
1281                    const char *name, krb5_data *data)
1282 {
1283     krb5_creds mcred, cred;
1284     krb5_error_code ret;
1285 
1286     memset(&cred, 0, sizeof(cred));
1287     krb5_data_zero(data);
1288 
1289     ret = build_conf_principals(context, id, principal, name, &mcred);
1290     if (ret)
1291         goto out;
1292 
1293     ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred);
1294     if (ret)
1295         goto out;
1296 
1297     ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length);
1298 
1299 out:
1300     krb5_free_cred_contents (context, &cred);
1301     krb5_free_cred_contents (context, &mcred);
1302     return ret;
1303 }
1304 
1305 /*
1306  *
1307  */
1308 
1309 struct krb5_cccol_cursor {
1310     int idx;
1311     krb5_cc_cache_cursor cursor;
1312 };
1313 
1314 /**
1315  * Get a new cache interation cursor that will interate over all
1316  * credentials caches independent of type.
1317  *
1318  * @param context a Keberos context
1319  * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
1320  *
1321  * @return Returns 0 or and error code, see krb5_get_error_message().
1322  *
1323  * @ingroup krb5_ccache
1324  */
1325 
1326 krb5_error_code KRB5_LIB_FUNCTION
1327 krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor)
     /* [<][>][^][v][top][bottom][index][help] */
1328 {
1329     *cursor = calloc(1, sizeof(**cursor));
1330     if (*cursor == NULL) {
1331         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1332         return ENOMEM;
1333     }
1334     (*cursor)->idx = 0;
1335     (*cursor)->cursor = NULL;
1336 
1337     return 0;
1338 }
1339 
1340 /**
1341  * Get next credential cache from the iteration. 
1342  *
1343  * @param context A Kerberos 5 context
1344  * @param cursor the iteration cursor
1345  * @param cache the returned cursor, pointer is set to NULL on failure
1346  *        and a cache on success. The returned cache needs to be freed
1347  *        with krb5_cc_close() or destroyed with krb5_cc_destroy().
1348  *
1349  * @return Return 0 or and error, KRB5_CC_END is returned at the end
1350  *        of iteration. See krb5_get_error_message().
1351  *
1352  * @ingroup krb5_ccache
1353  */
1354 
1355 
1356 krb5_error_code KRB5_LIB_FUNCTION
1357 krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor,
     /* [<][>][^][v][top][bottom][index][help] */
1358                        krb5_ccache *cache)
1359 {
1360     krb5_error_code ret;
1361     
1362     *cache = NULL;
1363 
1364     while (cursor->idx < context->num_cc_ops) {
1365 
1366         if (cursor->cursor == NULL) {
1367             ret = krb5_cc_cache_get_first (context, 
1368                                            context->cc_ops[cursor->idx].prefix,
1369                                            &cursor->cursor);
1370             if (ret) {
1371                 cursor->idx++;
1372                 continue;
1373             }
1374         }
1375         ret = krb5_cc_cache_next(context, cursor->cursor, cache);
1376         if (ret == 0)
1377             break;
1378 
1379         krb5_cc_cache_end_seq_get(context, cursor->cursor);
1380         cursor->cursor = NULL;
1381         if (ret != KRB5_CC_END)
1382             break;
1383         
1384         cursor->idx++;
1385     }
1386     if (cursor->idx >= context->num_cc_ops) {
1387         krb5_set_error_message(context, KRB5_CC_END,
1388                                N_("Reached end of credential caches", ""));
1389         return KRB5_CC_END;
1390     }
1391 
1392     return 0;
1393 }
1394 
1395 /**
1396  * End an iteration and free all resources, can be done before end is reached.
1397  *
1398  * @param context A Kerberos 5 context
1399  * @param cursor the iteration cursor to be freed.
1400  *
1401  * @return Return 0 or and error, KRB5_CC_END is returned at the end
1402  *        of iteration. See krb5_get_error_message().
1403  *
1404  * @ingroup krb5_ccache
1405  */
1406 
1407 krb5_error_code KRB5_LIB_FUNCTION
1408 krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor)
     /* [<][>][^][v][top][bottom][index][help] */
1409 {
1410     krb5_cccol_cursor c = *cursor;
1411 
1412     *cursor = NULL;
1413     if (c) {
1414         if (c->cursor)
1415             krb5_cc_cache_end_seq_get(context, c->cursor);
1416         free(c);
1417     }
1418     return 0;
1419 }
1420 
1421 /**
1422  * Return the last time the credential cache was modified.
1423  *
1424  * @param context A Kerberos 5 context
1425  * @param id The credential cache to probe
1426  * @param mtime the last modification time, set to 0 on error.
1427 
1428  * @return Return 0 or and error. See krb5_get_error_message().
1429  *
1430  * @ingroup krb5_ccache
1431  */
1432 
1433 
1434 krb5_error_code KRB5_LIB_FUNCTION
1435 krb5_cc_last_change_time(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1436                          krb5_ccache id, 
1437                          krb5_timestamp *mtime)
1438 {
1439     *mtime = 0;
1440     return (*id->ops->lastchange)(context, id, mtime);
1441 }
1442 
1443 /**
1444  * Return the last modfication time for a cache collection. The query
1445  * can be limited to a specific cache type. If the function return 0
1446  * and mtime is 0, there was no credentials in the caches.
1447  *
1448  * @param context A Kerberos 5 context
1449  * @param id The credential cache to probe
1450  * @param mtime the last modification time, set to 0 on error.
1451 
1452  * @return Return 0 or and error. See krb5_get_error_message().
1453  *
1454  * @ingroup krb5_ccache
1455  */
1456 
1457 krb5_error_code KRB5_LIB_FUNCTION
1458 krb5_cccol_last_change_time(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
1459                             const char *type,
1460                             krb5_timestamp *mtime)
1461 {
1462     krb5_cccol_cursor cursor;
1463     krb5_error_code ret;
1464     krb5_ccache id;
1465     krb5_timestamp t = 0;
1466 
1467     *mtime = 0;
1468 
1469     ret = krb5_cccol_cursor_new (context, &cursor);
1470     if (ret)
1471         return ret;
1472 
1473     while ((ret = krb5_cccol_cursor_next (context, cursor, &id)) == 0) {
1474 
1475         if (type && strcmp(krb5_cc_get_type(context, id), type) != 0)
1476             continue;
1477 
1478         ret = krb5_cc_last_change_time(context, id, &t);
1479         krb5_cc_close(context, id);
1480         if (ret)
1481             continue;
1482         if (t > *mtime)
1483             *mtime = t;
1484     }
1485 
1486     krb5_cccol_cursor_free(context, &cursor);
1487 
1488     return 0;
1489 }

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