155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 755682Smarkm * 8233294Sstas * Redistribution and use in source and binary forms, with or without 9233294Sstas * modification, are permitted provided that the following conditions 10233294Sstas * are met: 1155682Smarkm * 12233294Sstas * 1. Redistributions of source code must retain the above copyright 13233294Sstas * notice, this list of conditions and the following disclaimer. 1455682Smarkm * 15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 16233294Sstas * notice, this list of conditions and the following disclaimer in the 17233294Sstas * documentation and/or other materials provided with the distribution. 1855682Smarkm * 19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 20233294Sstas * may be used to endorse or promote products derived from this software 21233294Sstas * without specific prior written permission. 22233294Sstas * 23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33233294Sstas * SUCH DAMAGE. 3455682Smarkm */ 3555682Smarkm 3655682Smarkm#include "krb5_locl.h" 3755682Smarkm 38233294Sstas/** 39233294Sstas * @page krb5_ccache_intro The credential cache functions 40233294Sstas * @section section_krb5_ccache Kerberos credential caches 41233294Sstas * 42233294Sstas * krb5_ccache structure holds a Kerberos credential cache. 43233294Sstas * 44233294Sstas * Heimdal support the follow types of credential caches: 45233294Sstas * 46233294Sstas * - SCC 47233294Sstas * Store the credential in a database 48233294Sstas * - FILE 49233294Sstas * Store the credential in memory 50233294Sstas * - MEMORY 51233294Sstas * Store the credential in memory 52233294Sstas * - API 53233294Sstas * A credential cache server based solution for Mac OS X 54233294Sstas * - KCM 55233294Sstas * A credential cache server based solution for all platforms 56233294Sstas * 57233294Sstas * @subsection Example 58233294Sstas * 59233294Sstas * This is a minimalistic version of klist: 60233294Sstas@code 61233294Sstas#include <krb5.h> 6255682Smarkm 63233294Sstasint 64233294Sstasmain (int argc, char **argv) 65233294Sstas{ 66233294Sstas krb5_context context; 67233294Sstas krb5_cc_cursor cursor; 68233294Sstas krb5_error_code ret; 69233294Sstas krb5_ccache id; 70233294Sstas krb5_creds creds; 71233294Sstas 72233294Sstas if (krb5_init_context (&context) != 0) 73233294Sstas errx(1, "krb5_context"); 74233294Sstas 75233294Sstas ret = krb5_cc_default (context, &id); 76233294Sstas if (ret) 77233294Sstas krb5_err(context, 1, ret, "krb5_cc_default"); 78233294Sstas 79233294Sstas ret = krb5_cc_start_seq_get(context, id, &cursor); 80233294Sstas if (ret) 81233294Sstas krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); 82233294Sstas 83233294Sstas while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){ 84233294Sstas char *principal; 85233294Sstas 86233294Sstas krb5_unparse_name(context, creds.server, &principal); 87233294Sstas printf("principal: %s\\n", principal); 88233294Sstas free(principal); 89233294Sstas krb5_free_cred_contents (context, &creds); 90233294Sstas } 91233294Sstas ret = krb5_cc_end_seq_get(context, id, &cursor); 92233294Sstas if (ret) 93233294Sstas krb5_err(context, 1, ret, "krb5_cc_end_seq_get"); 94233294Sstas 95233294Sstas krb5_cc_close(context, id); 96233294Sstas 97233294Sstas krb5_free_context(context); 98233294Sstas return 0; 99233294Sstas} 100233294Sstas* @endcode 101233294Sstas*/ 102233294Sstas 103178825Sdfr/** 10455682Smarkm * Add a new ccache type with operations `ops', overwriting any 10555682Smarkm * existing one if `override'. 106178825Sdfr * 107178825Sdfr * @param context a Keberos context 108178825Sdfr * @param ops type of plugin symbol 109178825Sdfr * @param override flag to select if the registration is to overide 110178825Sdfr * an existing ops with the same name. 111178825Sdfr * 112233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 113178825Sdfr * 114178825Sdfr * @ingroup krb5_ccache 11555682Smarkm */ 11655682Smarkm 117233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 118233294Sstaskrb5_cc_register(krb5_context context, 119233294Sstas const krb5_cc_ops *ops, 12055682Smarkm krb5_boolean override) 12155682Smarkm{ 12255682Smarkm int i; 12355682Smarkm 124233294Sstas for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { 125233294Sstas if(strcmp(context->cc_ops[i]->prefix, ops->prefix) == 0) { 126102644Snectar if(!override) { 127233294Sstas krb5_set_error_message(context, 128233294Sstas KRB5_CC_TYPE_EXISTS, 129233294Sstas N_("cache type %s already exists", "type"), 130233294Sstas ops->prefix); 13155682Smarkm return KRB5_CC_TYPE_EXISTS; 13278527Sassar } 133102644Snectar break; 13455682Smarkm } 13555682Smarkm } 13655682Smarkm if(i == context->num_cc_ops) { 137233294Sstas const krb5_cc_ops **o = realloc(rk_UNCONST(context->cc_ops), 138233294Sstas (context->num_cc_ops + 1) * 139233294Sstas sizeof(context->cc_ops[0])); 14078527Sassar if(o == NULL) { 141233294Sstas krb5_set_error_message(context, KRB5_CC_NOMEM, 142233294Sstas N_("malloc: out of memory", "")); 14355682Smarkm return KRB5_CC_NOMEM; 14478527Sassar } 145233294Sstas context->cc_ops = o; 146233294Sstas context->cc_ops[context->num_cc_ops] = NULL; 14755682Smarkm context->num_cc_ops++; 14855682Smarkm } 149233294Sstas context->cc_ops[i] = ops; 15055682Smarkm return 0; 15155682Smarkm} 15255682Smarkm 15355682Smarkm/* 154178825Sdfr * Allocate the memory for a `id' and the that function table to 155178825Sdfr * `ops'. Returns 0 or and error code. 156178825Sdfr */ 157178825Sdfr 158178825Sdfrkrb5_error_code 159233294Sstas_krb5_cc_allocate(krb5_context context, 160178825Sdfr const krb5_cc_ops *ops, 161178825Sdfr krb5_ccache *id) 162178825Sdfr{ 163178825Sdfr krb5_ccache p; 164178825Sdfr 165178825Sdfr p = malloc (sizeof(*p)); 166178825Sdfr if(p == NULL) { 167233294Sstas krb5_set_error_message(context, KRB5_CC_NOMEM, 168233294Sstas N_("malloc: out of memory", "")); 169178825Sdfr return KRB5_CC_NOMEM; 170178825Sdfr } 171178825Sdfr p->ops = ops; 172178825Sdfr *id = p; 173178825Sdfr 174178825Sdfr return 0; 175178825Sdfr} 176178825Sdfr 177178825Sdfr/* 17855682Smarkm * Allocate memory for a new ccache in `id' with operations `ops' 179178825Sdfr * and name `residual'. Return 0 or an error code. 18055682Smarkm */ 18155682Smarkm 18255682Smarkmstatic krb5_error_code 18355682Smarkmallocate_ccache (krb5_context context, 18455682Smarkm const krb5_cc_ops *ops, 18555682Smarkm const char *residual, 18655682Smarkm krb5_ccache *id) 18755682Smarkm{ 18855682Smarkm krb5_error_code ret; 189233294Sstas#ifdef KRB5_USE_PATH_TOKENS 190233294Sstas char * exp_residual = NULL; 19155682Smarkm 192233294Sstas ret = _krb5_expand_path_tokens(context, residual, &exp_residual); 193178825Sdfr if (ret) 194178825Sdfr return ret; 195233294Sstas 196233294Sstas residual = exp_residual; 197233294Sstas#endif 198233294Sstas 199233294Sstas ret = _krb5_cc_allocate(context, ops, id); 200233294Sstas if (ret) { 201233294Sstas#ifdef KRB5_USE_PATH_TOKENS 202233294Sstas if (exp_residual) 203233294Sstas free(exp_residual); 204233294Sstas#endif 205233294Sstas return ret; 206233294Sstas } 207233294Sstas 208178825Sdfr ret = (*id)->ops->resolve(context, id, residual); 209233294Sstas if(ret) { 210178825Sdfr free(*id); 211233294Sstas *id = NULL; 212233294Sstas } 213233294Sstas 214233294Sstas#ifdef KRB5_USE_PATH_TOKENS 215233294Sstas if (exp_residual) 216233294Sstas free(exp_residual); 217233294Sstas#endif 218233294Sstas 21955682Smarkm return ret; 22055682Smarkm} 22155682Smarkm 222233294Sstasstatic int 223233294Sstasis_possible_path_name(const char * name) 224233294Sstas{ 225233294Sstas const char * colon; 226233294Sstas 227233294Sstas if ((colon = strchr(name, ':')) == NULL) 228233294Sstas return TRUE; 229233294Sstas 230233294Sstas#ifdef _WIN32 231233294Sstas /* <drive letter>:\path\to\cache ? */ 232233294Sstas 233233294Sstas if (colon == name + 1 && 234233294Sstas strchr(colon + 1, ':') == NULL) 235233294Sstas return TRUE; 236233294Sstas#endif 237233294Sstas 238233294Sstas return FALSE; 239233294Sstas} 240233294Sstas 241178825Sdfr/** 24255682Smarkm * Find and allocate a ccache in `id' from the specification in `residual'. 24355682Smarkm * If the ccache name doesn't contain any colon, interpret it as a file name. 244178825Sdfr * 245178825Sdfr * @param context a Keberos context. 246178825Sdfr * @param name string name of a credential cache. 247178825Sdfr * @param id return pointer to a found credential cache. 248178825Sdfr * 249178825Sdfr * @return Return 0 or an error code. In case of an error, id is set 250233294Sstas * to NULL, see krb5_get_error_message(). 251178825Sdfr * 252178825Sdfr * @ingroup krb5_ccache 25355682Smarkm */ 25455682Smarkm 255178825Sdfr 256233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 25755682Smarkmkrb5_cc_resolve(krb5_context context, 25855682Smarkm const char *name, 25955682Smarkm krb5_ccache *id) 26055682Smarkm{ 26155682Smarkm int i; 26255682Smarkm 263178825Sdfr *id = NULL; 264178825Sdfr 265233294Sstas for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { 266233294Sstas size_t prefix_len = strlen(context->cc_ops[i]->prefix); 26755682Smarkm 268233294Sstas if(strncmp(context->cc_ops[i]->prefix, name, prefix_len) == 0 26955682Smarkm && name[prefix_len] == ':') { 270233294Sstas return allocate_ccache (context, context->cc_ops[i], 27155682Smarkm name + prefix_len + 1, 27255682Smarkm id); 27355682Smarkm } 27455682Smarkm } 275233294Sstas if (is_possible_path_name(name)) 27655682Smarkm return allocate_ccache (context, &krb5_fcc_ops, name, id); 27778527Sassar else { 278233294Sstas krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 279233294Sstas N_("unknown ccache type %s", "name"), name); 28055682Smarkm return KRB5_CC_UNKNOWN_TYPE; 28178527Sassar } 28255682Smarkm} 28355682Smarkm 284178825Sdfr/** 285178825Sdfr * Generates a new unique ccache of `type` in `id'. If `type' is NULL, 286178825Sdfr * the library chooses the default credential cache type. The supplied 287178825Sdfr * `hint' (that can be NULL) is a string that the credential cache 288178825Sdfr * type can use to base the name of the credential on, this is to make 289178825Sdfr * it easier for the user to differentiate the credentials. 290178825Sdfr * 291233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 292178825Sdfr * 293178825Sdfr * @ingroup krb5_ccache 294178825Sdfr */ 295178825Sdfr 296233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 297233294Sstaskrb5_cc_new_unique(krb5_context context, const char *type, 298178825Sdfr const char *hint, krb5_ccache *id) 299178825Sdfr{ 300233294Sstas const krb5_cc_ops *ops; 301178825Sdfr krb5_error_code ret; 302178825Sdfr 303233294Sstas ops = krb5_cc_get_prefix_ops(context, type); 304233294Sstas if (ops == NULL) { 305233294Sstas krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 306233294Sstas "Credential cache type %s is unknown", type); 307233294Sstas return KRB5_CC_UNKNOWN_TYPE; 30878527Sassar } 309178825Sdfr 310178825Sdfr ret = _krb5_cc_allocate(context, ops, id); 311178825Sdfr if (ret) 312178825Sdfr return ret; 313233294Sstas ret = (*id)->ops->gen_new(context, id); 314233294Sstas if (ret) { 315233294Sstas free(*id); 316233294Sstas *id = NULL; 317233294Sstas } 318233294Sstas return ret; 31955682Smarkm} 32055682Smarkm 321178825Sdfr/** 32255682Smarkm * Return the name of the ccache `id' 323178825Sdfr * 324178825Sdfr * @ingroup krb5_ccache 32555682Smarkm */ 32655682Smarkm 327178825Sdfr 328233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 32955682Smarkmkrb5_cc_get_name(krb5_context context, 33055682Smarkm krb5_ccache id) 33155682Smarkm{ 33255682Smarkm return id->ops->get_name(context, id); 33355682Smarkm} 33455682Smarkm 335178825Sdfr/** 33655682Smarkm * Return the type of the ccache `id'. 337178825Sdfr * 338178825Sdfr * @ingroup krb5_ccache 33955682Smarkm */ 34055682Smarkm 341178825Sdfr 342233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 34355682Smarkmkrb5_cc_get_type(krb5_context context, 34455682Smarkm krb5_ccache id) 34555682Smarkm{ 34655682Smarkm return id->ops->prefix; 34755682Smarkm} 34855682Smarkm 349178825Sdfr/** 350233294Sstas * Return the complete resolvable name the cache 351233294Sstas 352233294Sstas * @param context a Keberos context 353233294Sstas * @param id return pointer to a found credential cache 354233294Sstas * @param str the returned name of a credential cache, free with krb5_xfree() 355178825Sdfr * 356233294Sstas * @return Returns 0 or an error (and then *str is set to NULL). 357233294Sstas * 358178825Sdfr * @ingroup krb5_ccache 359178825Sdfr */ 360178825Sdfr 361178825Sdfr 362233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 363178825Sdfrkrb5_cc_get_full_name(krb5_context context, 364178825Sdfr krb5_ccache id, 365178825Sdfr char **str) 366178825Sdfr{ 367178825Sdfr const char *type, *name; 368178825Sdfr 369178825Sdfr *str = NULL; 370178825Sdfr 371178825Sdfr type = krb5_cc_get_type(context, id); 372178825Sdfr if (type == NULL) { 373233294Sstas krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 374233294Sstas "cache have no name of type"); 375178825Sdfr return KRB5_CC_UNKNOWN_TYPE; 376178825Sdfr } 377178825Sdfr 378178825Sdfr name = krb5_cc_get_name(context, id); 379178825Sdfr if (name == NULL) { 380233294Sstas krb5_set_error_message(context, KRB5_CC_BADNAME, 381233294Sstas "cache of type %s have no name", type); 382178825Sdfr return KRB5_CC_BADNAME; 383178825Sdfr } 384233294Sstas 385178825Sdfr if (asprintf(str, "%s:%s", type, name) == -1) { 386233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 387178825Sdfr *str = NULL; 388178825Sdfr return ENOMEM; 389178825Sdfr } 390178825Sdfr return 0; 391178825Sdfr} 392178825Sdfr 393178825Sdfr/** 394120945Snectar * Return krb5_cc_ops of a the ccache `id'. 395178825Sdfr * 396178825Sdfr * @ingroup krb5_ccache 39755682Smarkm */ 39855682Smarkm 399178825Sdfr 400233294SstasKRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL 401120945Snectarkrb5_cc_get_ops(krb5_context context, krb5_ccache id) 402120945Snectar{ 403120945Snectar return id->ops; 404120945Snectar} 405120945Snectar 406120945Snectar/* 407178825Sdfr * Expand variables in `str' into `res' 408178825Sdfr */ 409178825Sdfr 410178825Sdfrkrb5_error_code 411178825Sdfr_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res) 412178825Sdfr{ 413233294Sstas return _krb5_expand_path_tokens(context, str, res); 414178825Sdfr} 415178825Sdfr 416178825Sdfr/* 417178825Sdfr * Return non-zero if envirnoment that will determine default krb5cc 418178825Sdfr * name has changed. 419178825Sdfr */ 420178825Sdfr 421178825Sdfrstatic int 422178825Sdfrenvironment_changed(krb5_context context) 423178825Sdfr{ 424178825Sdfr const char *e; 425178825Sdfr 426178825Sdfr /* if the cc name was set, don't change it */ 427178825Sdfr if (context->default_cc_name_set) 428178825Sdfr return 0; 429178825Sdfr 430233294Sstas /* XXX performance: always ask KCM/API if default name has changed */ 431233294Sstas if (context->default_cc_name && 432233294Sstas (strncmp(context->default_cc_name, "KCM:", 4) == 0 || 433233294Sstas strncmp(context->default_cc_name, "API:", 4) == 0)) 434233294Sstas return 1; 435233294Sstas 436178825Sdfr if(issuid()) 437178825Sdfr return 0; 438178825Sdfr 439178825Sdfr e = getenv("KRB5CCNAME"); 440178825Sdfr if (e == NULL) { 441178825Sdfr if (context->default_cc_name_env) { 442178825Sdfr free(context->default_cc_name_env); 443178825Sdfr context->default_cc_name_env = NULL; 444178825Sdfr return 1; 445178825Sdfr } 446178825Sdfr } else { 447178825Sdfr if (context->default_cc_name_env == NULL) 448178825Sdfr return 1; 449178825Sdfr if (strcmp(e, context->default_cc_name_env) != 0) 450178825Sdfr return 1; 451178825Sdfr } 452178825Sdfr return 0; 453178825Sdfr} 454178825Sdfr 455178825Sdfr/** 456233294Sstas * Switch the default default credential cache for a specific 457233294Sstas * credcache type (and name for some implementations). 458233294Sstas * 459233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 460233294Sstas * 461233294Sstas * @ingroup krb5_ccache 462233294Sstas */ 463233294Sstas 464233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 465233294Sstaskrb5_cc_switch(krb5_context context, krb5_ccache id) 466233294Sstas{ 467233294Sstas#ifdef _WIN32 468233294Sstas _krb5_set_default_cc_name_to_registry(context, id); 469233294Sstas#endif 470233294Sstas 471233294Sstas if (id->ops->set_default == NULL) 472233294Sstas return 0; 473233294Sstas 474233294Sstas return (*id->ops->set_default)(context, id); 475233294Sstas} 476233294Sstas 477233294Sstas/** 478233294Sstas * Return true if the default credential cache support switch 479233294Sstas * 480233294Sstas * @ingroup krb5_ccache 481233294Sstas */ 482233294Sstas 483233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 484233294Sstaskrb5_cc_support_switch(krb5_context context, const char *type) 485233294Sstas{ 486233294Sstas const krb5_cc_ops *ops; 487233294Sstas 488233294Sstas ops = krb5_cc_get_prefix_ops(context, type); 489233294Sstas if (ops && ops->set_default) 490233294Sstas return 1; 491233294Sstas return FALSE; 492233294Sstas} 493233294Sstas 494233294Sstas/** 495120945Snectar * Set the default cc name for `context' to `name'. 496178825Sdfr * 497178825Sdfr * @ingroup krb5_ccache 498120945Snectar */ 499120945Snectar 500233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 501120945Snectarkrb5_cc_set_default_name(krb5_context context, const char *name) 502120945Snectar{ 503120945Snectar krb5_error_code ret = 0; 504233294Sstas char *p = NULL, *exp_p = NULL; 505120945Snectar 506120945Snectar if (name == NULL) { 507178825Sdfr const char *e = NULL; 508178825Sdfr 509178825Sdfr if(!issuid()) { 510178825Sdfr e = getenv("KRB5CCNAME"); 511178825Sdfr if (e) { 512178825Sdfr p = strdup(e); 513178825Sdfr if (context->default_cc_name_env) 514178825Sdfr free(context->default_cc_name_env); 515178825Sdfr context->default_cc_name_env = strdup(e); 516178825Sdfr } 517178825Sdfr } 518233294Sstas 519233294Sstas#ifdef _WIN32 520233294Sstas if (e == NULL) { 521233294Sstas e = p = _krb5_get_default_cc_name_from_registry(context); 522233294Sstas } 523233294Sstas#endif 524178825Sdfr if (e == NULL) { 525178825Sdfr e = krb5_config_get_string(context, NULL, "libdefaults", 526178825Sdfr "default_cc_name", NULL); 527178825Sdfr if (e) { 528178825Sdfr ret = _krb5_expand_default_cc_name(context, e, &p); 529178825Sdfr if (ret) 530178825Sdfr return ret; 531178825Sdfr } 532178825Sdfr if (e == NULL) { 533178825Sdfr const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; 534233294Sstas e = krb5_config_get_string(context, NULL, "libdefaults", 535233294Sstas "default_cc_type", NULL); 536233294Sstas if (e) { 537233294Sstas ops = krb5_cc_get_prefix_ops(context, e); 538233294Sstas if (ops == NULL) { 539233294Sstas krb5_set_error_message(context, 540233294Sstas KRB5_CC_UNKNOWN_TYPE, 541233294Sstas "Credential cache type %s " 542233294Sstas "is unknown", e); 543233294Sstas return KRB5_CC_UNKNOWN_TYPE; 544233294Sstas } 545233294Sstas } 546233294Sstas ret = (*ops->get_default_name)(context, &p); 547178825Sdfr if (ret) 548178825Sdfr return ret; 549178825Sdfr } 550178825Sdfr } 551178825Sdfr context->default_cc_name_set = 0; 552178825Sdfr } else { 553120945Snectar p = strdup(name); 554178825Sdfr context->default_cc_name_set = 1; 555178825Sdfr } 556120945Snectar 557178825Sdfr if (p == NULL) { 558233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 559120945Snectar return ENOMEM; 560178825Sdfr } 561120945Snectar 562233294Sstas ret = _krb5_expand_path_tokens(context, p, &exp_p); 563233294Sstas free(p); 564233294Sstas if (ret) 565233294Sstas return ret; 566233294Sstas 567120945Snectar if (context->default_cc_name) 568120945Snectar free(context->default_cc_name); 569120945Snectar 570233294Sstas context->default_cc_name = exp_p; 571120945Snectar 572233294Sstas return 0; 573120945Snectar} 574120945Snectar 575178825Sdfr/** 576178825Sdfr * Return a pointer to a context static string containing the default 577178825Sdfr * ccache name. 578178825Sdfr * 579178825Sdfr * @return String to the default credential cache name. 580178825Sdfr * 581178825Sdfr * @ingroup krb5_ccache 582120945Snectar */ 583120945Snectar 584178825Sdfr 585233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 58655682Smarkmkrb5_cc_default_name(krb5_context context) 58755682Smarkm{ 588178825Sdfr if (context->default_cc_name == NULL || environment_changed(context)) 589120945Snectar krb5_cc_set_default_name(context, NULL); 59055682Smarkm 591120945Snectar return context->default_cc_name; 59255682Smarkm} 59355682Smarkm 594178825Sdfr/** 59555682Smarkm * Open the default ccache in `id'. 596178825Sdfr * 597233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 598178825Sdfr * 599178825Sdfr * @ingroup krb5_ccache 60055682Smarkm */ 60155682Smarkm 602178825Sdfr 603233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 60455682Smarkmkrb5_cc_default(krb5_context context, 60555682Smarkm krb5_ccache *id) 60655682Smarkm{ 607120945Snectar const char *p = krb5_cc_default_name(context); 608120945Snectar 609178825Sdfr if (p == NULL) { 610233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 611120945Snectar return ENOMEM; 612178825Sdfr } 613120945Snectar return krb5_cc_resolve(context, p, id); 61455682Smarkm} 61555682Smarkm 616178825Sdfr/** 61755682Smarkm * Create a new ccache in `id' for `primary_principal'. 618178825Sdfr * 619233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 620178825Sdfr * 621178825Sdfr * @ingroup krb5_ccache 62255682Smarkm */ 62355682Smarkm 624178825Sdfr 625233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 62655682Smarkmkrb5_cc_initialize(krb5_context context, 62755682Smarkm krb5_ccache id, 62855682Smarkm krb5_principal primary_principal) 62955682Smarkm{ 630178825Sdfr return (*id->ops->init)(context, id, primary_principal); 63155682Smarkm} 63255682Smarkm 63355682Smarkm 634178825Sdfr/** 63555682Smarkm * Remove the ccache `id'. 636178825Sdfr * 637233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 638178825Sdfr * 639178825Sdfr * @ingroup krb5_ccache 64055682Smarkm */ 64155682Smarkm 642178825Sdfr 643233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 64455682Smarkmkrb5_cc_destroy(krb5_context context, 64555682Smarkm krb5_ccache id) 64655682Smarkm{ 64755682Smarkm krb5_error_code ret; 64855682Smarkm 649178825Sdfr ret = (*id->ops->destroy)(context, id); 65055682Smarkm krb5_cc_close (context, id); 65155682Smarkm return ret; 65255682Smarkm} 65355682Smarkm 654178825Sdfr/** 65555682Smarkm * Stop using the ccache `id' and free the related resources. 656178825Sdfr * 657233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 658178825Sdfr * 659178825Sdfr * @ingroup krb5_ccache 66055682Smarkm */ 66155682Smarkm 662178825Sdfr 663233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 66455682Smarkmkrb5_cc_close(krb5_context context, 66555682Smarkm krb5_ccache id) 66655682Smarkm{ 66755682Smarkm krb5_error_code ret; 668178825Sdfr ret = (*id->ops->close)(context, id); 66955682Smarkm free(id); 67055682Smarkm return ret; 67155682Smarkm} 67255682Smarkm 673178825Sdfr/** 67455682Smarkm * Store `creds' in the ccache `id'. 675178825Sdfr * 676233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 677178825Sdfr * 678178825Sdfr * @ingroup krb5_ccache 67955682Smarkm */ 68055682Smarkm 681178825Sdfr 682233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 68355682Smarkmkrb5_cc_store_cred(krb5_context context, 68455682Smarkm krb5_ccache id, 68555682Smarkm krb5_creds *creds) 68655682Smarkm{ 687178825Sdfr return (*id->ops->store)(context, id, creds); 68855682Smarkm} 68955682Smarkm 690178825Sdfr/** 69155682Smarkm * Retrieve the credential identified by `mcreds' (and `whichfields') 692178825Sdfr * from `id' in `creds'. 'creds' must be free by the caller using 693178825Sdfr * krb5_free_cred_contents. 694178825Sdfr * 695233294Sstas * @param context A Kerberos 5 context 696233294Sstas * @param id a Kerberos 5 credential cache 697233294Sstas * @param whichfields what fields to use for matching credentials, same 698233294Sstas * flags as whichfields in krb5_compare_creds() 699233294Sstas * @param mcreds template credential to use for comparing 700233294Sstas * @param creds returned credential, free with krb5_free_cred_contents() 701178825Sdfr * 702233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 703233294Sstas * 704178825Sdfr * @ingroup krb5_ccache 70555682Smarkm */ 70655682Smarkm 707178825Sdfr 708233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 70955682Smarkmkrb5_cc_retrieve_cred(krb5_context context, 71055682Smarkm krb5_ccache id, 71155682Smarkm krb5_flags whichfields, 71255682Smarkm const krb5_creds *mcreds, 71355682Smarkm krb5_creds *creds) 71455682Smarkm{ 71555682Smarkm krb5_error_code ret; 71655682Smarkm krb5_cc_cursor cursor; 717178825Sdfr 718178825Sdfr if (id->ops->retrieve != NULL) { 719178825Sdfr return (*id->ops->retrieve)(context, id, whichfields, 720178825Sdfr mcreds, creds); 721178825Sdfr } 722178825Sdfr 723178825Sdfr ret = krb5_cc_start_seq_get(context, id, &cursor); 724178825Sdfr if (ret) 725178825Sdfr return ret; 72678527Sassar while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){ 72755682Smarkm if(krb5_compare_creds(context, whichfields, mcreds, creds)){ 72855682Smarkm ret = 0; 72955682Smarkm break; 73055682Smarkm } 731178825Sdfr krb5_free_cred_contents (context, creds); 73255682Smarkm } 73355682Smarkm krb5_cc_end_seq_get(context, id, &cursor); 73455682Smarkm return ret; 73555682Smarkm} 73655682Smarkm 737178825Sdfr/** 73855682Smarkm * Return the principal of `id' in `principal'. 739178825Sdfr * 740233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 741178825Sdfr * 742178825Sdfr * @ingroup krb5_ccache 74355682Smarkm */ 74455682Smarkm 745178825Sdfr 746233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 74755682Smarkmkrb5_cc_get_principal(krb5_context context, 74855682Smarkm krb5_ccache id, 74955682Smarkm krb5_principal *principal) 75055682Smarkm{ 751178825Sdfr return (*id->ops->get_princ)(context, id, principal); 75255682Smarkm} 75355682Smarkm 754178825Sdfr/** 75555682Smarkm * Start iterating over `id', `cursor' is initialized to the 756233294Sstas * beginning. Caller must free the cursor with krb5_cc_end_seq_get(). 757178825Sdfr * 758233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 759178825Sdfr * 760178825Sdfr * @ingroup krb5_ccache 76155682Smarkm */ 76255682Smarkm 763178825Sdfr 764233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 76555682Smarkmkrb5_cc_start_seq_get (krb5_context context, 76655682Smarkm const krb5_ccache id, 76755682Smarkm krb5_cc_cursor *cursor) 76855682Smarkm{ 769178825Sdfr return (*id->ops->get_first)(context, id, cursor); 77055682Smarkm} 77155682Smarkm 772178825Sdfr/** 77355682Smarkm * Retrieve the next cred pointed to by (`id', `cursor') in `creds' 77455682Smarkm * and advance `cursor'. 775178825Sdfr * 776233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 777178825Sdfr * 778178825Sdfr * @ingroup krb5_ccache 77955682Smarkm */ 78055682Smarkm 781178825Sdfr 782233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 78355682Smarkmkrb5_cc_next_cred (krb5_context context, 78455682Smarkm const krb5_ccache id, 78578527Sassar krb5_cc_cursor *cursor, 78678527Sassar krb5_creds *creds) 78755682Smarkm{ 788178825Sdfr return (*id->ops->get_next)(context, id, cursor, creds); 78955682Smarkm} 79055682Smarkm 791178825Sdfr/** 79255682Smarkm * Destroy the cursor `cursor'. 793178825Sdfr * 794178825Sdfr * @ingroup krb5_ccache 79555682Smarkm */ 79655682Smarkm 797178825Sdfr 798233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 79955682Smarkmkrb5_cc_end_seq_get (krb5_context context, 80055682Smarkm const krb5_ccache id, 80155682Smarkm krb5_cc_cursor *cursor) 80255682Smarkm{ 803178825Sdfr return (*id->ops->end_get)(context, id, cursor); 80455682Smarkm} 80555682Smarkm 806178825Sdfr/** 80755682Smarkm * Remove the credential identified by `cred', `which' from `id'. 808178825Sdfr * 809178825Sdfr * @ingroup krb5_ccache 81055682Smarkm */ 81155682Smarkm 812178825Sdfr 813233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 81455682Smarkmkrb5_cc_remove_cred(krb5_context context, 81555682Smarkm krb5_ccache id, 81655682Smarkm krb5_flags which, 81755682Smarkm krb5_creds *cred) 81855682Smarkm{ 81978527Sassar if(id->ops->remove_cred == NULL) { 820233294Sstas krb5_set_error_message(context, 821233294Sstas EACCES, 822233294Sstas "ccache %s does not support remove_cred", 823233294Sstas id->ops->prefix); 82472445Sassar return EACCES; /* XXX */ 82578527Sassar } 82672445Sassar return (*id->ops->remove_cred)(context, id, which, cred); 82755682Smarkm} 82855682Smarkm 829178825Sdfr/** 83055682Smarkm * Set the flags of `id' to `flags'. 831178825Sdfr * 832178825Sdfr * @ingroup krb5_ccache 83355682Smarkm */ 83455682Smarkm 835178825Sdfr 836233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 83755682Smarkmkrb5_cc_set_flags(krb5_context context, 83855682Smarkm krb5_ccache id, 83955682Smarkm krb5_flags flags) 84055682Smarkm{ 841178825Sdfr return (*id->ops->set_flags)(context, id, flags); 84255682Smarkm} 843233294Sstas 844178825Sdfr/** 845233294Sstas * Get the flags of `id', store them in `flags'. 846178825Sdfr * 847178825Sdfr * @ingroup krb5_ccache 84855682Smarkm */ 84955682Smarkm 850233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 851233294Sstaskrb5_cc_get_flags(krb5_context context, 852233294Sstas krb5_ccache id, 853233294Sstas krb5_flags *flags) 854233294Sstas{ 855233294Sstas *flags = 0; 856233294Sstas return 0; 857233294Sstas} 858178825Sdfr 859233294Sstas/** 860233294Sstas * Copy the contents of `from' to `to' if the given match function 861233294Sstas * return true. 862233294Sstas * 863233294Sstas * @param context A Kerberos 5 context. 864233294Sstas * @param from the cache to copy data from. 865233294Sstas * @param to the cache to copy data to. 866233294Sstas * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied. 867233294Sstas * @param matchctx context passed to match function. 868233294Sstas * @param matched set to true if there was a credential that matched, may be NULL. 869233294Sstas * 870233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 871233294Sstas * 872233294Sstas * @ingroup krb5_ccache 873233294Sstas */ 874233294Sstas 875233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 876233294Sstaskrb5_cc_copy_match_f(krb5_context context, 877233294Sstas const krb5_ccache from, 878233294Sstas krb5_ccache to, 879233294Sstas krb5_boolean (*match)(krb5_context, void *, const krb5_creds *), 880233294Sstas void *matchctx, 881233294Sstas unsigned int *matched) 88255682Smarkm{ 88355682Smarkm krb5_error_code ret; 88455682Smarkm krb5_cc_cursor cursor; 88555682Smarkm krb5_creds cred; 88655682Smarkm krb5_principal princ; 88755682Smarkm 888233294Sstas if (matched) 889233294Sstas *matched = 0; 890233294Sstas 89155682Smarkm ret = krb5_cc_get_principal(context, from, &princ); 892178825Sdfr if (ret) 89355682Smarkm return ret; 89455682Smarkm ret = krb5_cc_initialize(context, to, princ); 895178825Sdfr if (ret) { 89655682Smarkm krb5_free_principal(context, princ); 89755682Smarkm return ret; 89855682Smarkm } 89955682Smarkm ret = krb5_cc_start_seq_get(context, from, &cursor); 900178825Sdfr if (ret) { 90155682Smarkm krb5_free_principal(context, princ); 90255682Smarkm return ret; 90355682Smarkm } 904233294Sstas 905233294Sstas while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) { 906233294Sstas if (match == NULL || (*match)(context, matchctx, &cred) == 0) { 907233294Sstas if (matched) 908233294Sstas (*matched)++; 909233294Sstas ret = krb5_cc_store_cred(context, to, &cred); 910233294Sstas if (ret) 911233294Sstas break; 912233294Sstas } 913233294Sstas krb5_free_cred_contents(context, &cred); 91455682Smarkm } 91555682Smarkm krb5_cc_end_seq_get(context, from, &cursor); 91655682Smarkm krb5_free_principal(context, princ); 917233294Sstas if (ret == KRB5_CC_END) 918233294Sstas ret = 0; 91955682Smarkm return ret; 92055682Smarkm} 92155682Smarkm 922178825Sdfr/** 923233294Sstas * Just like krb5_cc_copy_match_f(), but copy everything. 924178825Sdfr * 925233294Sstas * @ingroup @krb5_ccache 926178825Sdfr */ 927178825Sdfr 928233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 929178825Sdfrkrb5_cc_copy_cache(krb5_context context, 930178825Sdfr const krb5_ccache from, 931178825Sdfr krb5_ccache to) 932178825Sdfr{ 933233294Sstas return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL); 934178825Sdfr} 935178825Sdfr 936178825Sdfr/** 93755682Smarkm * Return the version of `id'. 938178825Sdfr * 939178825Sdfr * @ingroup krb5_ccache 94055682Smarkm */ 94155682Smarkm 942178825Sdfr 943233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 94455682Smarkmkrb5_cc_get_version(krb5_context context, 94555682Smarkm const krb5_ccache id) 94655682Smarkm{ 94755682Smarkm if(id->ops->get_version) 948178825Sdfr return (*id->ops->get_version)(context, id); 94955682Smarkm else 95055682Smarkm return 0; 95155682Smarkm} 952178825Sdfr 953178825Sdfr/** 954178825Sdfr * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred 955178825Sdfr * 956178825Sdfr * @ingroup krb5_ccache 957178825Sdfr */ 958178825Sdfr 959178825Sdfr 960233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 961178825Sdfrkrb5_cc_clear_mcred(krb5_creds *mcred) 962178825Sdfr{ 963178825Sdfr memset(mcred, 0, sizeof(*mcred)); 964178825Sdfr} 965178825Sdfr 966178825Sdfr/** 967178825Sdfr * Get the cc ops that is registered in `context' to handle the 968233294Sstas * prefix. prefix can be a complete credential cache name or a 969178825Sdfr * prefix, the function will only use part up to the first colon (:) 970233294Sstas * if there is one. If prefix the argument is NULL, the default ccache 971233294Sstas * implemtation is returned. 972178825Sdfr * 973233294Sstas * @return Returns NULL if ops not found. 974233294Sstas * 975178825Sdfr * @ingroup krb5_ccache 976178825Sdfr */ 977178825Sdfr 978178825Sdfr 979233294SstasKRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL 980178825Sdfrkrb5_cc_get_prefix_ops(krb5_context context, const char *prefix) 981178825Sdfr{ 982178825Sdfr char *p, *p1; 983178825Sdfr int i; 984233294Sstas 985233294Sstas if (prefix == NULL) 986233294Sstas return KRB5_DEFAULT_CCTYPE; 987178825Sdfr if (prefix[0] == '/') 988178825Sdfr return &krb5_fcc_ops; 989178825Sdfr 990178825Sdfr p = strdup(prefix); 991178825Sdfr if (p == NULL) { 992233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 993178825Sdfr return NULL; 994178825Sdfr } 995178825Sdfr p1 = strchr(p, ':'); 996178825Sdfr if (p1) 997178825Sdfr *p1 = '\0'; 998178825Sdfr 999233294Sstas for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) { 1000233294Sstas if(strcmp(context->cc_ops[i]->prefix, p) == 0) { 1001178825Sdfr free(p); 1002233294Sstas return context->cc_ops[i]; 1003178825Sdfr } 1004178825Sdfr } 1005178825Sdfr free(p); 1006178825Sdfr return NULL; 1007178825Sdfr} 1008178825Sdfr 1009178825Sdfrstruct krb5_cc_cache_cursor_data { 1010178825Sdfr const krb5_cc_ops *ops; 1011178825Sdfr krb5_cc_cursor cursor; 1012178825Sdfr}; 1013178825Sdfr 1014178825Sdfr/** 1015233294Sstas * Start iterating over all caches of specified type. See also 1016233294Sstas * krb5_cccol_cursor_new(). 1017233294Sstas 1018233294Sstas * @param context A Kerberos 5 context 1019233294Sstas * @param type optional type to iterate over, if NULL, the default cache is used. 1020233294Sstas * @param cursor cursor should be freed with krb5_cc_cache_end_seq_get(). 1021178825Sdfr * 1022233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1023178825Sdfr * 1024178825Sdfr * @ingroup krb5_ccache 1025178825Sdfr */ 1026178825Sdfr 1027178825Sdfr 1028233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1029178825Sdfrkrb5_cc_cache_get_first (krb5_context context, 1030178825Sdfr const char *type, 1031178825Sdfr krb5_cc_cache_cursor *cursor) 1032178825Sdfr{ 1033178825Sdfr const krb5_cc_ops *ops; 1034178825Sdfr krb5_error_code ret; 1035178825Sdfr 1036178825Sdfr if (type == NULL) 1037178825Sdfr type = krb5_cc_default_name(context); 1038178825Sdfr 1039178825Sdfr ops = krb5_cc_get_prefix_ops(context, type); 1040178825Sdfr if (ops == NULL) { 1041233294Sstas krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE, 1042233294Sstas "Unknown type \"%s\" when iterating " 1043233294Sstas "trying to iterate the credential caches", type); 1044178825Sdfr return KRB5_CC_UNKNOWN_TYPE; 1045178825Sdfr } 1046178825Sdfr 1047178825Sdfr if (ops->get_cache_first == NULL) { 1048233294Sstas krb5_set_error_message(context, KRB5_CC_NOSUPP, 1049233294Sstas N_("Credential cache type %s doesn't support " 1050233294Sstas "iterations over caches", "type"), 1051233294Sstas ops->prefix); 1052178825Sdfr return KRB5_CC_NOSUPP; 1053178825Sdfr } 1054178825Sdfr 1055178825Sdfr *cursor = calloc(1, sizeof(**cursor)); 1056178825Sdfr if (*cursor == NULL) { 1057233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1058178825Sdfr return ENOMEM; 1059178825Sdfr } 1060178825Sdfr 1061178825Sdfr (*cursor)->ops = ops; 1062178825Sdfr 1063178825Sdfr ret = ops->get_cache_first(context, &(*cursor)->cursor); 1064178825Sdfr if (ret) { 1065178825Sdfr free(*cursor); 1066178825Sdfr *cursor = NULL; 1067178825Sdfr } 1068178825Sdfr return ret; 1069178825Sdfr} 1070178825Sdfr 1071178825Sdfr/** 1072178825Sdfr * Retrieve the next cache pointed to by (`cursor') in `id' 1073178825Sdfr * and advance `cursor'. 1074178825Sdfr * 1075233294Sstas * @param context A Kerberos 5 context 1076233294Sstas * @param cursor the iterator cursor, returned by krb5_cc_cache_get_first() 1077233294Sstas * @param id next ccache 1078178825Sdfr * 1079233294Sstas * @return Return 0 or an error code. Returns KRB5_CC_END when the end 1080233294Sstas * of caches is reached, see krb5_get_error_message(). 1081233294Sstas * 1082178825Sdfr * @ingroup krb5_ccache 1083178825Sdfr */ 1084178825Sdfr 1085178825Sdfr 1086233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1087178825Sdfrkrb5_cc_cache_next (krb5_context context, 1088178825Sdfr krb5_cc_cache_cursor cursor, 1089178825Sdfr krb5_ccache *id) 1090178825Sdfr{ 1091178825Sdfr return cursor->ops->get_cache_next(context, cursor->cursor, id); 1092178825Sdfr} 1093178825Sdfr 1094178825Sdfr/** 1095178825Sdfr * Destroy the cursor `cursor'. 1096178825Sdfr * 1097233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1098178825Sdfr * 1099178825Sdfr * @ingroup krb5_ccache 1100178825Sdfr */ 1101178825Sdfr 1102178825Sdfr 1103233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1104178825Sdfrkrb5_cc_cache_end_seq_get (krb5_context context, 1105178825Sdfr krb5_cc_cache_cursor cursor) 1106178825Sdfr{ 1107178825Sdfr krb5_error_code ret; 1108178825Sdfr ret = cursor->ops->end_cache_get(context, cursor->cursor); 1109178825Sdfr cursor->ops = NULL; 1110178825Sdfr free(cursor); 1111178825Sdfr return ret; 1112178825Sdfr} 1113178825Sdfr 1114178825Sdfr/** 1115233294Sstas * Search for a matching credential cache that have the 1116233294Sstas * `principal' as the default principal. On success, `id' needs to be 1117233294Sstas * freed with krb5_cc_close() or krb5_cc_destroy(). 1118178825Sdfr * 1119233294Sstas * @param context A Kerberos 5 context 1120233294Sstas * @param client The principal to search for 1121233294Sstas * @param id the returned credential cache 1122233294Sstas * 1123178825Sdfr * @return On failure, error code is returned and `id' is set to NULL. 1124178825Sdfr * 1125178825Sdfr * @ingroup krb5_ccache 1126178825Sdfr */ 1127178825Sdfr 1128178825Sdfr 1129233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1130178825Sdfrkrb5_cc_cache_match (krb5_context context, 1131178825Sdfr krb5_principal client, 1132178825Sdfr krb5_ccache *id) 1133178825Sdfr{ 1134233294Sstas krb5_cccol_cursor cursor; 1135178825Sdfr krb5_error_code ret; 1136178825Sdfr krb5_ccache cache = NULL; 1137178825Sdfr 1138178825Sdfr *id = NULL; 1139178825Sdfr 1140233294Sstas ret = krb5_cccol_cursor_new (context, &cursor); 1141178825Sdfr if (ret) 1142178825Sdfr return ret; 1143178825Sdfr 1144233294Sstas while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) { 1145178825Sdfr krb5_principal principal; 1146178825Sdfr 1147178825Sdfr ret = krb5_cc_get_principal(context, cache, &principal); 1148178825Sdfr if (ret == 0) { 1149178825Sdfr krb5_boolean match; 1150233294Sstas 1151178825Sdfr match = krb5_principal_compare(context, principal, client); 1152178825Sdfr krb5_free_principal(context, principal); 1153178825Sdfr if (match) 1154178825Sdfr break; 1155178825Sdfr } 1156178825Sdfr 1157178825Sdfr krb5_cc_close(context, cache); 1158178825Sdfr cache = NULL; 1159178825Sdfr } 1160178825Sdfr 1161233294Sstas krb5_cccol_cursor_free(context, &cursor); 1162178825Sdfr 1163178825Sdfr if (cache == NULL) { 1164178825Sdfr char *str; 1165178825Sdfr 1166178825Sdfr krb5_unparse_name(context, client, &str); 1167178825Sdfr 1168233294Sstas krb5_set_error_message(context, KRB5_CC_NOTFOUND, 1169233294Sstas N_("Principal %s not found in any " 1170233294Sstas "credential cache", ""), 1171233294Sstas str ? str : "<out of memory>"); 1172178825Sdfr if (str) 1173178825Sdfr free(str); 1174178825Sdfr return KRB5_CC_NOTFOUND; 1175178825Sdfr } 1176178825Sdfr *id = cache; 1177178825Sdfr 1178178825Sdfr return 0; 1179178825Sdfr} 1180178825Sdfr 1181178825Sdfr/** 1182178825Sdfr * Move the content from one credential cache to another. The 1183233294Sstas * operation is an atomic switch. 1184178825Sdfr * 1185178825Sdfr * @param context a Keberos context 1186178825Sdfr * @param from the credential cache to move the content from 1187178825Sdfr * @param to the credential cache to move the content to 1188178825Sdfr 1189178825Sdfr * @return On sucess, from is freed. On failure, error code is 1190233294Sstas * returned and from and to are both still allocated, see krb5_get_error_message(). 1191178825Sdfr * 1192178825Sdfr * @ingroup krb5_ccache 1193178825Sdfr */ 1194178825Sdfr 1195233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1196178825Sdfrkrb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 1197178825Sdfr{ 1198178825Sdfr krb5_error_code ret; 1199178825Sdfr 1200178825Sdfr if (strcmp(from->ops->prefix, to->ops->prefix) != 0) { 1201233294Sstas krb5_set_error_message(context, KRB5_CC_NOSUPP, 1202233294Sstas N_("Moving credentials between diffrent " 1203233294Sstas "types not yet supported", "")); 1204178825Sdfr return KRB5_CC_NOSUPP; 1205178825Sdfr } 1206178825Sdfr 1207178825Sdfr ret = (*to->ops->move)(context, from, to); 1208178825Sdfr if (ret == 0) { 1209178825Sdfr memset(from, 0, sizeof(*from)); 1210178825Sdfr free(from); 1211178825Sdfr } 1212178825Sdfr return ret; 1213178825Sdfr} 1214233294Sstas 1215233294Sstas#define KRB5_CONF_NAME "krb5_ccache_conf_data" 1216233294Sstas#define KRB5_REALM_NAME "X-CACHECONF:" 1217233294Sstas 1218233294Sstasstatic krb5_error_code 1219233294Sstasbuild_conf_principals(krb5_context context, krb5_ccache id, 1220233294Sstas krb5_const_principal principal, 1221233294Sstas const char *name, krb5_creds *cred) 1222233294Sstas{ 1223233294Sstas krb5_principal client; 1224233294Sstas krb5_error_code ret; 1225233294Sstas char *pname = NULL; 1226233294Sstas 1227233294Sstas memset(cred, 0, sizeof(*cred)); 1228233294Sstas 1229233294Sstas ret = krb5_cc_get_principal(context, id, &client); 1230233294Sstas if (ret) 1231233294Sstas return ret; 1232233294Sstas 1233233294Sstas if (principal) { 1234233294Sstas ret = krb5_unparse_name(context, principal, &pname); 1235233294Sstas if (ret) 1236233294Sstas return ret; 1237233294Sstas } 1238233294Sstas 1239233294Sstas ret = krb5_make_principal(context, &cred->server, 1240233294Sstas KRB5_REALM_NAME, 1241233294Sstas KRB5_CONF_NAME, name, pname, NULL); 1242233294Sstas free(pname); 1243233294Sstas if (ret) { 1244233294Sstas krb5_free_principal(context, client); 1245233294Sstas return ret; 1246233294Sstas } 1247233294Sstas ret = krb5_copy_principal(context, client, &cred->client); 1248233294Sstas krb5_free_principal(context, client); 1249233294Sstas return ret; 1250233294Sstas} 1251233294Sstas 1252233294Sstas/** 1253233294Sstas * Return TRUE (non zero) if the principal is a configuration 1254233294Sstas * principal (generated part of krb5_cc_set_config()). Returns FALSE 1255233294Sstas * (zero) if not a configuration principal. 1256233294Sstas * 1257233294Sstas * @param context a Keberos context 1258233294Sstas * @param principal principal to check if it a configuration principal 1259233294Sstas * 1260233294Sstas * @ingroup krb5_ccache 1261233294Sstas */ 1262233294Sstas 1263233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1264233294Sstaskrb5_is_config_principal(krb5_context context, 1265233294Sstas krb5_const_principal principal) 1266233294Sstas{ 1267233294Sstas if (strcmp(principal->realm, KRB5_REALM_NAME) != 0) 1268233294Sstas return FALSE; 1269233294Sstas 1270233294Sstas if (principal->name.name_string.len == 0 || 1271233294Sstas strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0) 1272233294Sstas return FALSE; 1273233294Sstas 1274233294Sstas return TRUE; 1275233294Sstas} 1276233294Sstas 1277233294Sstas/** 1278233294Sstas * Store some configuration for the credential cache in the cache. 1279233294Sstas * Existing configuration under the same name is over-written. 1280233294Sstas * 1281233294Sstas * @param context a Keberos context 1282233294Sstas * @param id the credential cache to store the data for 1283233294Sstas * @param principal configuration for a specific principal, if 1284233294Sstas * NULL, global for the whole cache. 1285233294Sstas * @param name name under which the configuraion is stored. 1286233294Sstas * @param data data to store, if NULL, configure is removed. 1287233294Sstas * 1288233294Sstas * @ingroup krb5_ccache 1289233294Sstas */ 1290233294Sstas 1291233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1292233294Sstaskrb5_cc_set_config(krb5_context context, krb5_ccache id, 1293233294Sstas krb5_const_principal principal, 1294233294Sstas const char *name, krb5_data *data) 1295233294Sstas{ 1296233294Sstas krb5_error_code ret; 1297233294Sstas krb5_creds cred; 1298233294Sstas 1299233294Sstas ret = build_conf_principals(context, id, principal, name, &cred); 1300233294Sstas if (ret) 1301233294Sstas goto out; 1302233294Sstas 1303233294Sstas /* Remove old configuration */ 1304233294Sstas ret = krb5_cc_remove_cred(context, id, 0, &cred); 1305233294Sstas if (ret && ret != KRB5_CC_NOTFOUND) 1306233294Sstas goto out; 1307233294Sstas 1308233294Sstas if (data) { 1309233294Sstas /* not that anyone care when this expire */ 1310233294Sstas cred.times.authtime = time(NULL); 1311233294Sstas cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; 1312233294Sstas 1313233294Sstas ret = krb5_data_copy(&cred.ticket, data->data, data->length); 1314233294Sstas if (ret) 1315233294Sstas goto out; 1316233294Sstas 1317233294Sstas ret = krb5_cc_store_cred(context, id, &cred); 1318233294Sstas } 1319233294Sstas 1320233294Sstasout: 1321233294Sstas krb5_free_cred_contents (context, &cred); 1322233294Sstas return ret; 1323233294Sstas} 1324233294Sstas 1325233294Sstas/** 1326233294Sstas * Get some configuration for the credential cache in the cache. 1327233294Sstas * 1328233294Sstas * @param context a Keberos context 1329233294Sstas * @param id the credential cache to store the data for 1330233294Sstas * @param principal configuration for a specific principal, if 1331233294Sstas * NULL, global for the whole cache. 1332233294Sstas * @param name name under which the configuraion is stored. 1333233294Sstas * @param data data to fetched, free with krb5_data_free() 1334233294Sstas * 1335233294Sstas * @ingroup krb5_ccache 1336233294Sstas */ 1337233294Sstas 1338233294Sstas 1339233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1340233294Sstaskrb5_cc_get_config(krb5_context context, krb5_ccache id, 1341233294Sstas krb5_const_principal principal, 1342233294Sstas const char *name, krb5_data *data) 1343233294Sstas{ 1344233294Sstas krb5_creds mcred, cred; 1345233294Sstas krb5_error_code ret; 1346233294Sstas 1347233294Sstas memset(&cred, 0, sizeof(cred)); 1348233294Sstas krb5_data_zero(data); 1349233294Sstas 1350233294Sstas ret = build_conf_principals(context, id, principal, name, &mcred); 1351233294Sstas if (ret) 1352233294Sstas goto out; 1353233294Sstas 1354233294Sstas ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred); 1355233294Sstas if (ret) 1356233294Sstas goto out; 1357233294Sstas 1358233294Sstas ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length); 1359233294Sstas 1360233294Sstasout: 1361233294Sstas krb5_free_cred_contents (context, &cred); 1362233294Sstas krb5_free_cred_contents (context, &mcred); 1363233294Sstas return ret; 1364233294Sstas} 1365233294Sstas 1366233294Sstas/* 1367233294Sstas * 1368233294Sstas */ 1369233294Sstas 1370233294Sstasstruct krb5_cccol_cursor_data { 1371233294Sstas int idx; 1372233294Sstas krb5_cc_cache_cursor cursor; 1373233294Sstas}; 1374233294Sstas 1375233294Sstas/** 1376233294Sstas * Get a new cache interation cursor that will interate over all 1377233294Sstas * credentials caches independent of type. 1378233294Sstas * 1379233294Sstas * @param context a Keberos context 1380233294Sstas * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free(). 1381233294Sstas * 1382233294Sstas * @return Returns 0 or and error code, see krb5_get_error_message(). 1383233294Sstas * 1384233294Sstas * @ingroup krb5_ccache 1385233294Sstas */ 1386233294Sstas 1387233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1388233294Sstaskrb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor) 1389233294Sstas{ 1390233294Sstas *cursor = calloc(1, sizeof(**cursor)); 1391233294Sstas if (*cursor == NULL) { 1392233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1393233294Sstas return ENOMEM; 1394233294Sstas } 1395233294Sstas (*cursor)->idx = 0; 1396233294Sstas (*cursor)->cursor = NULL; 1397233294Sstas 1398233294Sstas return 0; 1399233294Sstas} 1400233294Sstas 1401233294Sstas/** 1402233294Sstas * Get next credential cache from the iteration. 1403233294Sstas * 1404233294Sstas * @param context A Kerberos 5 context 1405233294Sstas * @param cursor the iteration cursor 1406233294Sstas * @param cache the returned cursor, pointer is set to NULL on failure 1407233294Sstas * and a cache on success. The returned cache needs to be freed 1408233294Sstas * with krb5_cc_close() or destroyed with krb5_cc_destroy(). 1409233294Sstas * MIT Kerberos behavies slightly diffrent and sets cache to NULL 1410233294Sstas * when all caches are iterated over and return 0. 1411233294Sstas * 1412233294Sstas * @return Return 0 or and error, KRB5_CC_END is returned at the end 1413233294Sstas * of iteration. See krb5_get_error_message(). 1414233294Sstas * 1415233294Sstas * @ingroup krb5_ccache 1416233294Sstas */ 1417233294Sstas 1418233294Sstas 1419233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1420233294Sstaskrb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor, 1421233294Sstas krb5_ccache *cache) 1422233294Sstas{ 1423233294Sstas krb5_error_code ret; 1424233294Sstas 1425233294Sstas *cache = NULL; 1426233294Sstas 1427233294Sstas while (cursor->idx < context->num_cc_ops) { 1428233294Sstas 1429233294Sstas if (cursor->cursor == NULL) { 1430233294Sstas ret = krb5_cc_cache_get_first (context, 1431233294Sstas context->cc_ops[cursor->idx]->prefix, 1432233294Sstas &cursor->cursor); 1433233294Sstas if (ret) { 1434233294Sstas cursor->idx++; 1435233294Sstas continue; 1436233294Sstas } 1437233294Sstas } 1438233294Sstas ret = krb5_cc_cache_next(context, cursor->cursor, cache); 1439233294Sstas if (ret == 0) 1440233294Sstas break; 1441233294Sstas 1442233294Sstas krb5_cc_cache_end_seq_get(context, cursor->cursor); 1443233294Sstas cursor->cursor = NULL; 1444233294Sstas if (ret != KRB5_CC_END) 1445233294Sstas break; 1446233294Sstas 1447233294Sstas cursor->idx++; 1448233294Sstas } 1449233294Sstas if (cursor->idx >= context->num_cc_ops) { 1450233294Sstas krb5_set_error_message(context, KRB5_CC_END, 1451233294Sstas N_("Reached end of credential caches", "")); 1452233294Sstas return KRB5_CC_END; 1453233294Sstas } 1454233294Sstas 1455233294Sstas return 0; 1456233294Sstas} 1457233294Sstas 1458233294Sstas/** 1459233294Sstas * End an iteration and free all resources, can be done before end is reached. 1460233294Sstas * 1461233294Sstas * @param context A Kerberos 5 context 1462233294Sstas * @param cursor the iteration cursor to be freed. 1463233294Sstas * 1464233294Sstas * @return Return 0 or and error, KRB5_CC_END is returned at the end 1465233294Sstas * of iteration. See krb5_get_error_message(). 1466233294Sstas * 1467233294Sstas * @ingroup krb5_ccache 1468233294Sstas */ 1469233294Sstas 1470233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1471233294Sstaskrb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor) 1472233294Sstas{ 1473233294Sstas krb5_cccol_cursor c = *cursor; 1474233294Sstas 1475233294Sstas *cursor = NULL; 1476233294Sstas if (c) { 1477233294Sstas if (c->cursor) 1478233294Sstas krb5_cc_cache_end_seq_get(context, c->cursor); 1479233294Sstas free(c); 1480233294Sstas } 1481233294Sstas return 0; 1482233294Sstas} 1483233294Sstas 1484233294Sstas/** 1485233294Sstas * Return the last time the credential cache was modified. 1486233294Sstas * 1487233294Sstas * @param context A Kerberos 5 context 1488233294Sstas * @param id The credential cache to probe 1489233294Sstas * @param mtime the last modification time, set to 0 on error. 1490233294Sstas 1491233294Sstas * @return Return 0 or and error. See krb5_get_error_message(). 1492233294Sstas * 1493233294Sstas * @ingroup krb5_ccache 1494233294Sstas */ 1495233294Sstas 1496233294Sstas 1497233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1498233294Sstaskrb5_cc_last_change_time(krb5_context context, 1499233294Sstas krb5_ccache id, 1500233294Sstas krb5_timestamp *mtime) 1501233294Sstas{ 1502233294Sstas *mtime = 0; 1503233294Sstas return (*id->ops->lastchange)(context, id, mtime); 1504233294Sstas} 1505233294Sstas 1506233294Sstas/** 1507233294Sstas * Return the last modfication time for a cache collection. The query 1508233294Sstas * can be limited to a specific cache type. If the function return 0 1509233294Sstas * and mtime is 0, there was no credentials in the caches. 1510233294Sstas * 1511233294Sstas * @param context A Kerberos 5 context 1512233294Sstas * @param type The credential cache to probe, if NULL, all type are traversed. 1513233294Sstas * @param mtime the last modification time, set to 0 on error. 1514233294Sstas 1515233294Sstas * @return Return 0 or and error. See krb5_get_error_message(). 1516233294Sstas * 1517233294Sstas * @ingroup krb5_ccache 1518233294Sstas */ 1519233294Sstas 1520233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1521233294Sstaskrb5_cccol_last_change_time(krb5_context context, 1522233294Sstas const char *type, 1523233294Sstas krb5_timestamp *mtime) 1524233294Sstas{ 1525233294Sstas krb5_cccol_cursor cursor; 1526233294Sstas krb5_error_code ret; 1527233294Sstas krb5_ccache id; 1528233294Sstas krb5_timestamp t = 0; 1529233294Sstas 1530233294Sstas *mtime = 0; 1531233294Sstas 1532233294Sstas ret = krb5_cccol_cursor_new (context, &cursor); 1533233294Sstas if (ret) 1534233294Sstas return ret; 1535233294Sstas 1536233294Sstas while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) { 1537233294Sstas 1538233294Sstas if (type && strcmp(krb5_cc_get_type(context, id), type) != 0) 1539233294Sstas continue; 1540233294Sstas 1541233294Sstas ret = krb5_cc_last_change_time(context, id, &t); 1542233294Sstas krb5_cc_close(context, id); 1543233294Sstas if (ret) 1544233294Sstas continue; 1545233294Sstas if (t > *mtime) 1546233294Sstas *mtime = t; 1547233294Sstas } 1548233294Sstas 1549233294Sstas krb5_cccol_cursor_free(context, &cursor); 1550233294Sstas 1551233294Sstas return 0; 1552233294Sstas} 1553233294Sstas/** 1554233294Sstas * Return a friendly name on credential cache. Free the result with krb5_xfree(). 1555233294Sstas * 1556233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1557233294Sstas * 1558233294Sstas * @ingroup krb5_ccache 1559233294Sstas */ 1560233294Sstas 1561233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1562233294Sstaskrb5_cc_get_friendly_name(krb5_context context, 1563233294Sstas krb5_ccache id, 1564233294Sstas char **name) 1565233294Sstas{ 1566233294Sstas krb5_error_code ret; 1567233294Sstas krb5_data data; 1568233294Sstas 1569233294Sstas ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data); 1570233294Sstas if (ret) { 1571233294Sstas krb5_principal principal; 1572233294Sstas ret = krb5_cc_get_principal(context, id, &principal); 1573233294Sstas if (ret) 1574233294Sstas return ret; 1575233294Sstas ret = krb5_unparse_name(context, principal, name); 1576233294Sstas krb5_free_principal(context, principal); 1577233294Sstas } else { 1578233294Sstas ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data); 1579233294Sstas krb5_data_free(&data); 1580233294Sstas if (ret <= 0) { 1581233294Sstas ret = ENOMEM; 1582233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1583233294Sstas } else 1584233294Sstas ret = 0; 1585233294Sstas } 1586233294Sstas 1587233294Sstas return ret; 1588233294Sstas} 1589233294Sstas 1590233294Sstas/** 1591233294Sstas * Set the friendly name on credential cache. 1592233294Sstas * 1593233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1594233294Sstas * 1595233294Sstas * @ingroup krb5_ccache 1596233294Sstas */ 1597233294Sstas 1598233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1599233294Sstaskrb5_cc_set_friendly_name(krb5_context context, 1600233294Sstas krb5_ccache id, 1601233294Sstas const char *name) 1602233294Sstas{ 1603233294Sstas krb5_data data; 1604233294Sstas 1605233294Sstas data.data = rk_UNCONST(name); 1606233294Sstas data.length = strlen(name); 1607233294Sstas 1608233294Sstas return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data); 1609233294Sstas} 1610233294Sstas 1611233294Sstas/** 1612233294Sstas * Get the lifetime of the initial ticket in the cache 1613233294Sstas * 1614233294Sstas * Get the lifetime of the initial ticket in the cache, if the initial 1615233294Sstas * ticket was not found, the error code KRB5_CC_END is returned. 1616233294Sstas * 1617233294Sstas * @param context A Kerberos 5 context. 1618233294Sstas * @param id a credential cache 1619233294Sstas * @param t the relative lifetime of the initial ticket 1620233294Sstas * 1621233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1622233294Sstas * 1623233294Sstas * @ingroup krb5_ccache 1624233294Sstas */ 1625233294Sstas 1626233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1627233294Sstaskrb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t) 1628233294Sstas{ 1629233294Sstas krb5_cc_cursor cursor; 1630233294Sstas krb5_error_code ret; 1631233294Sstas krb5_creds cred; 1632233294Sstas time_t now; 1633233294Sstas 1634233294Sstas *t = 0; 1635233294Sstas now = time(NULL); 1636233294Sstas 1637233294Sstas ret = krb5_cc_start_seq_get(context, id, &cursor); 1638233294Sstas if (ret) 1639233294Sstas return ret; 1640233294Sstas 1641233294Sstas while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) { 1642233294Sstas if (cred.flags.b.initial) { 1643233294Sstas if (now < cred.times.endtime) 1644233294Sstas *t = cred.times.endtime - now; 1645233294Sstas krb5_free_cred_contents(context, &cred); 1646233294Sstas break; 1647233294Sstas } 1648233294Sstas krb5_free_cred_contents(context, &cred); 1649233294Sstas } 1650233294Sstas 1651233294Sstas krb5_cc_end_seq_get(context, id, &cursor); 1652233294Sstas 1653233294Sstas return ret; 1654233294Sstas} 1655233294Sstas 1656233294Sstas/** 1657233294Sstas * Set the time offset betwen the client and the KDC 1658233294Sstas * 1659233294Sstas * If the backend doesn't support KDC offset, use the context global setting. 1660233294Sstas * 1661233294Sstas * @param context A Kerberos 5 context. 1662233294Sstas * @param id a credential cache 1663233294Sstas * @param offset the offset in seconds 1664233294Sstas * 1665233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1666233294Sstas * 1667233294Sstas * @ingroup krb5_ccache 1668233294Sstas */ 1669233294Sstas 1670233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1671233294Sstaskrb5_cc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset) 1672233294Sstas{ 1673233294Sstas if (id->ops->set_kdc_offset == NULL) { 1674233294Sstas context->kdc_sec_offset = offset; 1675233294Sstas context->kdc_usec_offset = 0; 1676233294Sstas return 0; 1677233294Sstas } 1678233294Sstas return (*id->ops->set_kdc_offset)(context, id, offset); 1679233294Sstas} 1680233294Sstas 1681233294Sstas/** 1682233294Sstas * Get the time offset betwen the client and the KDC 1683233294Sstas * 1684233294Sstas * If the backend doesn't support KDC offset, use the context global setting. 1685233294Sstas * 1686233294Sstas * @param context A Kerberos 5 context. 1687233294Sstas * @param id a credential cache 1688233294Sstas * @param offset the offset in seconds 1689233294Sstas * 1690233294Sstas * @return Return an error code or 0, see krb5_get_error_message(). 1691233294Sstas * 1692233294Sstas * @ingroup krb5_ccache 1693233294Sstas */ 1694233294Sstas 1695233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1696233294Sstaskrb5_cc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *offset) 1697233294Sstas{ 1698233294Sstas if (id->ops->get_kdc_offset == NULL) { 1699233294Sstas *offset = context->kdc_sec_offset; 1700233294Sstas return 0; 1701233294Sstas } 1702233294Sstas return (*id->ops->get_kdc_offset)(context, id, offset); 1703233294Sstas} 1704233294Sstas 1705233294Sstas 1706233294Sstas#ifdef _WIN32 1707233294Sstas 1708233294Sstas#define REGPATH_MIT_KRB5 "SOFTWARE\\MIT\\Kerberos5" 1709233294Sstaschar * 1710233294Sstas_krb5_get_default_cc_name_from_registry(krb5_context context) 1711233294Sstas{ 1712233294Sstas HKEY hk_k5 = 0; 1713233294Sstas LONG code; 1714233294Sstas char * ccname = NULL; 1715233294Sstas 1716233294Sstas code = RegOpenKeyEx(HKEY_CURRENT_USER, 1717233294Sstas REGPATH_MIT_KRB5, 1718233294Sstas 0, KEY_READ, &hk_k5); 1719233294Sstas 1720233294Sstas if (code != ERROR_SUCCESS) 1721233294Sstas return NULL; 1722233294Sstas 1723233294Sstas ccname = _krb5_parse_reg_value_as_string(context, hk_k5, "ccname", 1724233294Sstas REG_NONE, 0); 1725233294Sstas 1726233294Sstas RegCloseKey(hk_k5); 1727233294Sstas 1728233294Sstas return ccname; 1729233294Sstas} 1730233294Sstas 1731233294Sstasint 1732233294Sstas_krb5_set_default_cc_name_to_registry(krb5_context context, krb5_ccache id) 1733233294Sstas{ 1734233294Sstas HKEY hk_k5 = 0; 1735233294Sstas LONG code; 1736233294Sstas int ret = -1; 1737233294Sstas char * ccname = NULL; 1738233294Sstas 1739233294Sstas code = RegOpenKeyEx(HKEY_CURRENT_USER, 1740233294Sstas REGPATH_MIT_KRB5, 1741233294Sstas 0, KEY_READ|KEY_WRITE, &hk_k5); 1742233294Sstas 1743233294Sstas if (code != ERROR_SUCCESS) 1744233294Sstas return -1; 1745233294Sstas 1746233294Sstas ret = asprintf(&ccname, "%s:%s", krb5_cc_get_type(context, id), krb5_cc_get_name(context, id)); 1747233294Sstas if (ret < 0) 1748233294Sstas goto cleanup; 1749233294Sstas 1750233294Sstas ret = _krb5_store_string_to_reg_value(context, hk_k5, "ccname", 1751233294Sstas REG_SZ, ccname, -1, 0); 1752233294Sstas 1753233294Sstas cleanup: 1754233294Sstas 1755233294Sstas if (ccname) 1756233294Sstas free(ccname); 1757233294Sstas 1758233294Sstas RegCloseKey(hk_k5); 1759233294Sstas 1760233294Sstas return ret; 1761233294Sstas} 1762233294Sstas 1763233294Sstas#endif 1764