155682Smarkm/* 2178825Sdfr * Copyright (c) 1997 - 2007 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm 36178825SdfrRCSID("$Id: cache.c 22127 2007-12-04 00:54:37Z lha $"); 3755682Smarkm 38178825Sdfr/** 3955682Smarkm * Add a new ccache type with operations `ops', overwriting any 4055682Smarkm * existing one if `override'. 41178825Sdfr * 42178825Sdfr * @param context a Keberos context 43178825Sdfr * @param ops type of plugin symbol 44178825Sdfr * @param override flag to select if the registration is to overide 45178825Sdfr * an existing ops with the same name. 46178825Sdfr * 47178825Sdfr * @return Return an error code or 0. 48178825Sdfr * 49178825Sdfr * @ingroup krb5_ccache 5055682Smarkm */ 5155682Smarkm 52178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 5355682Smarkmkrb5_cc_register(krb5_context context, 5455682Smarkm const krb5_cc_ops *ops, 5555682Smarkm krb5_boolean override) 5655682Smarkm{ 5755682Smarkm int i; 5855682Smarkm 5955682Smarkm for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 6055682Smarkm if(strcmp(context->cc_ops[i].prefix, ops->prefix) == 0) { 61102644Snectar if(!override) { 6278527Sassar krb5_set_error_string(context, 6378527Sassar "ccache type %s already exists", 6478527Sassar ops->prefix); 6555682Smarkm return KRB5_CC_TYPE_EXISTS; 6678527Sassar } 67102644Snectar break; 6855682Smarkm } 6955682Smarkm } 7055682Smarkm if(i == context->num_cc_ops) { 7155682Smarkm krb5_cc_ops *o = realloc(context->cc_ops, 7255682Smarkm (context->num_cc_ops + 1) * 7355682Smarkm sizeof(*context->cc_ops)); 7478527Sassar if(o == NULL) { 7578527Sassar krb5_set_error_string(context, "malloc: out of memory"); 7655682Smarkm return KRB5_CC_NOMEM; 7778527Sassar } 7855682Smarkm context->num_cc_ops++; 7955682Smarkm context->cc_ops = o; 8055682Smarkm memset(context->cc_ops + i, 0, 8155682Smarkm (context->num_cc_ops - i) * sizeof(*context->cc_ops)); 8255682Smarkm } 8355682Smarkm memcpy(&context->cc_ops[i], ops, sizeof(context->cc_ops[i])); 8455682Smarkm return 0; 8555682Smarkm} 8655682Smarkm 8755682Smarkm/* 88178825Sdfr * Allocate the memory for a `id' and the that function table to 89178825Sdfr * `ops'. Returns 0 or and error code. 90178825Sdfr */ 91178825Sdfr 92178825Sdfrkrb5_error_code 93178825Sdfr_krb5_cc_allocate(krb5_context context, 94178825Sdfr const krb5_cc_ops *ops, 95178825Sdfr krb5_ccache *id) 96178825Sdfr{ 97178825Sdfr krb5_ccache p; 98178825Sdfr 99178825Sdfr p = malloc (sizeof(*p)); 100178825Sdfr if(p == NULL) { 101178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 102178825Sdfr return KRB5_CC_NOMEM; 103178825Sdfr } 104178825Sdfr p->ops = ops; 105178825Sdfr *id = p; 106178825Sdfr 107178825Sdfr return 0; 108178825Sdfr} 109178825Sdfr 110178825Sdfr/* 11155682Smarkm * Allocate memory for a new ccache in `id' with operations `ops' 112178825Sdfr * and name `residual'. Return 0 or an error code. 11355682Smarkm */ 11455682Smarkm 11555682Smarkmstatic krb5_error_code 11655682Smarkmallocate_ccache (krb5_context context, 11755682Smarkm const krb5_cc_ops *ops, 11855682Smarkm const char *residual, 11955682Smarkm krb5_ccache *id) 12055682Smarkm{ 12155682Smarkm krb5_error_code ret; 12255682Smarkm 123178825Sdfr ret = _krb5_cc_allocate(context, ops, id); 124178825Sdfr if (ret) 125178825Sdfr return ret; 126178825Sdfr ret = (*id)->ops->resolve(context, id, residual); 12755682Smarkm if(ret) 128178825Sdfr free(*id); 12955682Smarkm return ret; 13055682Smarkm} 13155682Smarkm 132178825Sdfr/** 13355682Smarkm * Find and allocate a ccache in `id' from the specification in `residual'. 13455682Smarkm * If the ccache name doesn't contain any colon, interpret it as a file name. 135178825Sdfr * 136178825Sdfr * @param context a Keberos context. 137178825Sdfr * @param name string name of a credential cache. 138178825Sdfr * @param id return pointer to a found credential cache. 139178825Sdfr * 140178825Sdfr * @return Return 0 or an error code. In case of an error, id is set 141178825Sdfr * to NULL. 142178825Sdfr * 143178825Sdfr * @ingroup krb5_ccache 14455682Smarkm */ 14555682Smarkm 146178825Sdfr 147178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 14855682Smarkmkrb5_cc_resolve(krb5_context context, 14955682Smarkm const char *name, 15055682Smarkm krb5_ccache *id) 15155682Smarkm{ 15255682Smarkm int i; 15355682Smarkm 154178825Sdfr *id = NULL; 155178825Sdfr 15655682Smarkm for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 15755682Smarkm size_t prefix_len = strlen(context->cc_ops[i].prefix); 15855682Smarkm 15955682Smarkm if(strncmp(context->cc_ops[i].prefix, name, prefix_len) == 0 16055682Smarkm && name[prefix_len] == ':') { 16155682Smarkm return allocate_ccache (context, &context->cc_ops[i], 16255682Smarkm name + prefix_len + 1, 16355682Smarkm id); 16455682Smarkm } 16555682Smarkm } 16655682Smarkm if (strchr (name, ':') == NULL) 16755682Smarkm return allocate_ccache (context, &krb5_fcc_ops, name, id); 16878527Sassar else { 16978527Sassar krb5_set_error_string(context, "unknown ccache type %s", name); 17055682Smarkm return KRB5_CC_UNKNOWN_TYPE; 17178527Sassar } 17255682Smarkm} 17355682Smarkm 174178825Sdfr/** 17555682Smarkm * Generate a new ccache of type `ops' in `id'. 176178825Sdfr * 177178825Sdfr * @return Return 0 or an error code. 178178825Sdfr * 179178825Sdfr * @ingroup krb5_ccache 18055682Smarkm */ 18155682Smarkm 182178825Sdfr 183178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 18455682Smarkmkrb5_cc_gen_new(krb5_context context, 18555682Smarkm const krb5_cc_ops *ops, 18655682Smarkm krb5_ccache *id) 18755682Smarkm{ 188178825Sdfr return krb5_cc_new_unique(context, ops->prefix, NULL, id); 189178825Sdfr} 19055682Smarkm 191178825Sdfr/** 192178825Sdfr * Generates a new unique ccache of `type` in `id'. If `type' is NULL, 193178825Sdfr * the library chooses the default credential cache type. The supplied 194178825Sdfr * `hint' (that can be NULL) is a string that the credential cache 195178825Sdfr * type can use to base the name of the credential on, this is to make 196178825Sdfr * it easier for the user to differentiate the credentials. 197178825Sdfr * 198178825Sdfr * @return Returns 0 or an error code. 199178825Sdfr * 200178825Sdfr * @ingroup krb5_ccache 201178825Sdfr */ 202178825Sdfr 203178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 204178825Sdfrkrb5_cc_new_unique(krb5_context context, const char *type, 205178825Sdfr const char *hint, krb5_ccache *id) 206178825Sdfr{ 207178825Sdfr const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; 208178825Sdfr krb5_error_code ret; 209178825Sdfr 210178825Sdfr if (type) { 211178825Sdfr ops = krb5_cc_get_prefix_ops(context, type); 212178825Sdfr if (ops == NULL) { 213178825Sdfr krb5_set_error_string(context, 214178825Sdfr "Credential cache type %s is unknown", type); 215178825Sdfr return KRB5_CC_UNKNOWN_TYPE; 216178825Sdfr } 21778527Sassar } 218178825Sdfr 219178825Sdfr ret = _krb5_cc_allocate(context, ops, id); 220178825Sdfr if (ret) 221178825Sdfr return ret; 222178825Sdfr return (*id)->ops->gen_new(context, id); 22355682Smarkm} 22455682Smarkm 225178825Sdfr/** 22655682Smarkm * Return the name of the ccache `id' 227178825Sdfr * 228178825Sdfr * @ingroup krb5_ccache 22955682Smarkm */ 23055682Smarkm 231178825Sdfr 232178825Sdfrconst char* KRB5_LIB_FUNCTION 23355682Smarkmkrb5_cc_get_name(krb5_context context, 23455682Smarkm krb5_ccache id) 23555682Smarkm{ 23655682Smarkm return id->ops->get_name(context, id); 23755682Smarkm} 23855682Smarkm 239178825Sdfr/** 24055682Smarkm * Return the type of the ccache `id'. 241178825Sdfr * 242178825Sdfr * @ingroup krb5_ccache 24355682Smarkm */ 24455682Smarkm 245178825Sdfr 246178825Sdfrconst char* KRB5_LIB_FUNCTION 24755682Smarkmkrb5_cc_get_type(krb5_context context, 24855682Smarkm krb5_ccache id) 24955682Smarkm{ 25055682Smarkm return id->ops->prefix; 25155682Smarkm} 25255682Smarkm 253178825Sdfr/** 254178825Sdfr * Return the complete resolvable name the ccache `id' in `str�. 255178825Sdfr * `str` should be freed with free(3). 256178825Sdfr * Returns 0 or an error (and then *str is set to NULL). 257178825Sdfr * 258178825Sdfr * @ingroup krb5_ccache 259178825Sdfr */ 260178825Sdfr 261178825Sdfr 262178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 263178825Sdfrkrb5_cc_get_full_name(krb5_context context, 264178825Sdfr krb5_ccache id, 265178825Sdfr char **str) 266178825Sdfr{ 267178825Sdfr const char *type, *name; 268178825Sdfr 269178825Sdfr *str = NULL; 270178825Sdfr 271178825Sdfr type = krb5_cc_get_type(context, id); 272178825Sdfr if (type == NULL) { 273178825Sdfr krb5_set_error_string(context, "cache have no name of type"); 274178825Sdfr return KRB5_CC_UNKNOWN_TYPE; 275178825Sdfr } 276178825Sdfr 277178825Sdfr name = krb5_cc_get_name(context, id); 278178825Sdfr if (name == NULL) { 279178825Sdfr krb5_set_error_string(context, "cache of type %s have no name", type); 280178825Sdfr return KRB5_CC_BADNAME; 281178825Sdfr } 282178825Sdfr 283178825Sdfr if (asprintf(str, "%s:%s", type, name) == -1) { 284178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 285178825Sdfr *str = NULL; 286178825Sdfr return ENOMEM; 287178825Sdfr } 288178825Sdfr return 0; 289178825Sdfr} 290178825Sdfr 291178825Sdfr/** 292120945Snectar * Return krb5_cc_ops of a the ccache `id'. 293178825Sdfr * 294178825Sdfr * @ingroup krb5_ccache 29555682Smarkm */ 29655682Smarkm 297178825Sdfr 298120945Snectarconst krb5_cc_ops * 299120945Snectarkrb5_cc_get_ops(krb5_context context, krb5_ccache id) 300120945Snectar{ 301120945Snectar return id->ops; 302120945Snectar} 303120945Snectar 304120945Snectar/* 305178825Sdfr * Expand variables in `str' into `res' 306178825Sdfr */ 307178825Sdfr 308178825Sdfrkrb5_error_code 309178825Sdfr_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res) 310178825Sdfr{ 311178825Sdfr size_t tlen, len = 0; 312178825Sdfr char *tmp, *tmp2, *append; 313178825Sdfr 314178825Sdfr *res = NULL; 315178825Sdfr 316178825Sdfr while (str && *str) { 317178825Sdfr tmp = strstr(str, "%{"); 318178825Sdfr if (tmp && tmp != str) { 319178825Sdfr append = malloc((tmp - str) + 1); 320178825Sdfr if (append) { 321178825Sdfr memcpy(append, str, tmp - str); 322178825Sdfr append[tmp - str] = '\0'; 323178825Sdfr } 324178825Sdfr str = tmp; 325178825Sdfr } else if (tmp) { 326178825Sdfr tmp2 = strchr(tmp, '}'); 327178825Sdfr if (tmp2 == NULL) { 328178825Sdfr free(*res); 329178825Sdfr *res = NULL; 330178825Sdfr krb5_set_error_string(context, "variable missing }"); 331178825Sdfr return KRB5_CONFIG_BADFORMAT; 332178825Sdfr } 333178825Sdfr if (strncasecmp(tmp, "%{uid}", 6) == 0) 334178825Sdfr asprintf(&append, "%u", (unsigned)getuid()); 335178825Sdfr else if (strncasecmp(tmp, "%{null}", 7) == 0) 336178825Sdfr append = strdup(""); 337178825Sdfr else { 338178825Sdfr free(*res); 339178825Sdfr *res = NULL; 340178825Sdfr krb5_set_error_string(context, 341178825Sdfr "expand default cache unknown " 342178825Sdfr "variable \"%.*s\"", 343178825Sdfr (int)(tmp2 - tmp) - 2, tmp + 2); 344178825Sdfr return KRB5_CONFIG_BADFORMAT; 345178825Sdfr } 346178825Sdfr str = tmp2 + 1; 347178825Sdfr } else { 348178825Sdfr append = strdup(str); 349178825Sdfr str = NULL; 350178825Sdfr } 351178825Sdfr if (append == NULL) { 352178825Sdfr free(*res); 353178825Sdfr *res = NULL; 354178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 355178825Sdfr return ENOMEM; 356178825Sdfr } 357178825Sdfr 358178825Sdfr tlen = strlen(append); 359178825Sdfr tmp = realloc(*res, len + tlen + 1); 360178825Sdfr if (tmp == NULL) { 361178825Sdfr free(append); 362178825Sdfr free(*res); 363178825Sdfr *res = NULL; 364178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 365178825Sdfr return ENOMEM; 366178825Sdfr } 367178825Sdfr *res = tmp; 368178825Sdfr memcpy(*res + len, append, tlen + 1); 369178825Sdfr len = len + tlen; 370178825Sdfr free(append); 371178825Sdfr } 372178825Sdfr return 0; 373178825Sdfr} 374178825Sdfr 375178825Sdfr/* 376178825Sdfr * Return non-zero if envirnoment that will determine default krb5cc 377178825Sdfr * name has changed. 378178825Sdfr */ 379178825Sdfr 380178825Sdfrstatic int 381178825Sdfrenvironment_changed(krb5_context context) 382178825Sdfr{ 383178825Sdfr const char *e; 384178825Sdfr 385178825Sdfr /* if the cc name was set, don't change it */ 386178825Sdfr if (context->default_cc_name_set) 387178825Sdfr return 0; 388178825Sdfr 389178825Sdfr if(issuid()) 390178825Sdfr return 0; 391178825Sdfr 392178825Sdfr e = getenv("KRB5CCNAME"); 393178825Sdfr if (e == NULL) { 394178825Sdfr if (context->default_cc_name_env) { 395178825Sdfr free(context->default_cc_name_env); 396178825Sdfr context->default_cc_name_env = NULL; 397178825Sdfr return 1; 398178825Sdfr } 399178825Sdfr } else { 400178825Sdfr if (context->default_cc_name_env == NULL) 401178825Sdfr return 1; 402178825Sdfr if (strcmp(e, context->default_cc_name_env) != 0) 403178825Sdfr return 1; 404178825Sdfr } 405178825Sdfr return 0; 406178825Sdfr} 407178825Sdfr 408178825Sdfr/** 409120945Snectar * Set the default cc name for `context' to `name'. 410178825Sdfr * 411178825Sdfr * @ingroup krb5_ccache 412120945Snectar */ 413120945Snectar 414178825Sdfr 415178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 416120945Snectarkrb5_cc_set_default_name(krb5_context context, const char *name) 417120945Snectar{ 418120945Snectar krb5_error_code ret = 0; 419120945Snectar char *p; 420120945Snectar 421120945Snectar if (name == NULL) { 422178825Sdfr const char *e = NULL; 423178825Sdfr 424178825Sdfr if(!issuid()) { 425178825Sdfr e = getenv("KRB5CCNAME"); 426178825Sdfr if (e) { 427178825Sdfr p = strdup(e); 428178825Sdfr if (context->default_cc_name_env) 429178825Sdfr free(context->default_cc_name_env); 430178825Sdfr context->default_cc_name_env = strdup(e); 431178825Sdfr } 432178825Sdfr } 433178825Sdfr if (e == NULL) { 434178825Sdfr e = krb5_config_get_string(context, NULL, "libdefaults", 435178825Sdfr "default_cc_name", NULL); 436178825Sdfr if (e) { 437178825Sdfr ret = _krb5_expand_default_cc_name(context, e, &p); 438178825Sdfr if (ret) 439178825Sdfr return ret; 440178825Sdfr } 441178825Sdfr if (e == NULL) { 442178825Sdfr const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE; 443178825Sdfr ret = (*ops->default_name)(context, &p); 444178825Sdfr if (ret) 445178825Sdfr return ret; 446178825Sdfr } 447178825Sdfr } 448178825Sdfr context->default_cc_name_set = 0; 449178825Sdfr } else { 450120945Snectar p = strdup(name); 451178825Sdfr context->default_cc_name_set = 1; 452178825Sdfr } 453120945Snectar 454178825Sdfr if (p == NULL) { 455178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 456120945Snectar return ENOMEM; 457178825Sdfr } 458120945Snectar 459120945Snectar if (context->default_cc_name) 460120945Snectar free(context->default_cc_name); 461120945Snectar 462120945Snectar context->default_cc_name = p; 463120945Snectar 464120945Snectar return ret; 465120945Snectar} 466120945Snectar 467178825Sdfr/** 468178825Sdfr * Return a pointer to a context static string containing the default 469178825Sdfr * ccache name. 470178825Sdfr * 471178825Sdfr * @return String to the default credential cache name. 472178825Sdfr * 473178825Sdfr * @ingroup krb5_ccache 474120945Snectar */ 475120945Snectar 476178825Sdfr 477178825Sdfrconst char* KRB5_LIB_FUNCTION 47855682Smarkmkrb5_cc_default_name(krb5_context context) 47955682Smarkm{ 480178825Sdfr if (context->default_cc_name == NULL || environment_changed(context)) 481120945Snectar krb5_cc_set_default_name(context, NULL); 48255682Smarkm 483120945Snectar return context->default_cc_name; 48455682Smarkm} 48555682Smarkm 486178825Sdfr/** 48755682Smarkm * Open the default ccache in `id'. 488178825Sdfr * 489178825Sdfr * @return Return 0 or an error code. 490178825Sdfr * 491178825Sdfr * @ingroup krb5_ccache 49255682Smarkm */ 49355682Smarkm 494178825Sdfr 495178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 49655682Smarkmkrb5_cc_default(krb5_context context, 49755682Smarkm krb5_ccache *id) 49855682Smarkm{ 499120945Snectar const char *p = krb5_cc_default_name(context); 500120945Snectar 501178825Sdfr if (p == NULL) { 502178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 503120945Snectar return ENOMEM; 504178825Sdfr } 505120945Snectar return krb5_cc_resolve(context, p, id); 50655682Smarkm} 50755682Smarkm 508178825Sdfr/** 50955682Smarkm * Create a new ccache in `id' for `primary_principal'. 510178825Sdfr * 511178825Sdfr * @return Return 0 or an error code. 512178825Sdfr * 513178825Sdfr * @ingroup krb5_ccache 51455682Smarkm */ 51555682Smarkm 516178825Sdfr 517178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 51855682Smarkmkrb5_cc_initialize(krb5_context context, 51955682Smarkm krb5_ccache id, 52055682Smarkm krb5_principal primary_principal) 52155682Smarkm{ 522178825Sdfr return (*id->ops->init)(context, id, primary_principal); 52355682Smarkm} 52455682Smarkm 52555682Smarkm 526178825Sdfr/** 52755682Smarkm * Remove the ccache `id'. 528178825Sdfr * 529178825Sdfr * @return Return 0 or an error code. 530178825Sdfr * 531178825Sdfr * @ingroup krb5_ccache 53255682Smarkm */ 53355682Smarkm 534178825Sdfr 535178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 53655682Smarkmkrb5_cc_destroy(krb5_context context, 53755682Smarkm krb5_ccache id) 53855682Smarkm{ 53955682Smarkm krb5_error_code ret; 54055682Smarkm 541178825Sdfr ret = (*id->ops->destroy)(context, id); 54255682Smarkm krb5_cc_close (context, id); 54355682Smarkm return ret; 54455682Smarkm} 54555682Smarkm 546178825Sdfr/** 54755682Smarkm * Stop using the ccache `id' and free the related resources. 548178825Sdfr * 549178825Sdfr * @return Return 0 or an error code. 550178825Sdfr * 551178825Sdfr * @ingroup krb5_ccache 55255682Smarkm */ 55355682Smarkm 554178825Sdfr 555178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 55655682Smarkmkrb5_cc_close(krb5_context context, 55755682Smarkm krb5_ccache id) 55855682Smarkm{ 55955682Smarkm krb5_error_code ret; 560178825Sdfr ret = (*id->ops->close)(context, id); 56155682Smarkm free(id); 56255682Smarkm return ret; 56355682Smarkm} 56455682Smarkm 565178825Sdfr/** 56655682Smarkm * Store `creds' in the ccache `id'. 567178825Sdfr * 568178825Sdfr * @return Return 0 or an error code. 569178825Sdfr * 570178825Sdfr * @ingroup krb5_ccache 57155682Smarkm */ 57255682Smarkm 573178825Sdfr 574178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 57555682Smarkmkrb5_cc_store_cred(krb5_context context, 57655682Smarkm krb5_ccache id, 57755682Smarkm krb5_creds *creds) 57855682Smarkm{ 579178825Sdfr return (*id->ops->store)(context, id, creds); 58055682Smarkm} 58155682Smarkm 582178825Sdfr/** 58355682Smarkm * Retrieve the credential identified by `mcreds' (and `whichfields') 584178825Sdfr * from `id' in `creds'. 'creds' must be free by the caller using 585178825Sdfr * krb5_free_cred_contents. 586178825Sdfr * 587178825Sdfr * @return Return 0 or an error code. 588178825Sdfr * 589178825Sdfr * @ingroup krb5_ccache 59055682Smarkm */ 59155682Smarkm 592178825Sdfr 593178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 59455682Smarkmkrb5_cc_retrieve_cred(krb5_context context, 59555682Smarkm krb5_ccache id, 59655682Smarkm krb5_flags whichfields, 59755682Smarkm const krb5_creds *mcreds, 59855682Smarkm krb5_creds *creds) 59955682Smarkm{ 60055682Smarkm krb5_error_code ret; 60155682Smarkm krb5_cc_cursor cursor; 602178825Sdfr 603178825Sdfr if (id->ops->retrieve != NULL) { 604178825Sdfr return (*id->ops->retrieve)(context, id, whichfields, 605178825Sdfr mcreds, creds); 606178825Sdfr } 607178825Sdfr 608178825Sdfr ret = krb5_cc_start_seq_get(context, id, &cursor); 609178825Sdfr if (ret) 610178825Sdfr return ret; 61178527Sassar while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){ 61255682Smarkm if(krb5_compare_creds(context, whichfields, mcreds, creds)){ 61355682Smarkm ret = 0; 61455682Smarkm break; 61555682Smarkm } 616178825Sdfr krb5_free_cred_contents (context, creds); 61755682Smarkm } 61855682Smarkm krb5_cc_end_seq_get(context, id, &cursor); 61955682Smarkm return ret; 62055682Smarkm} 62155682Smarkm 622178825Sdfr/** 62355682Smarkm * Return the principal of `id' in `principal'. 624178825Sdfr * 625178825Sdfr * @return Return 0 or an error code. 626178825Sdfr * 627178825Sdfr * @ingroup krb5_ccache 62855682Smarkm */ 62955682Smarkm 630178825Sdfr 631178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 63255682Smarkmkrb5_cc_get_principal(krb5_context context, 63355682Smarkm krb5_ccache id, 63455682Smarkm krb5_principal *principal) 63555682Smarkm{ 636178825Sdfr return (*id->ops->get_princ)(context, id, principal); 63755682Smarkm} 63855682Smarkm 639178825Sdfr/** 64055682Smarkm * Start iterating over `id', `cursor' is initialized to the 64155682Smarkm * beginning. 642178825Sdfr * 643178825Sdfr * @return Return 0 or an error code. 644178825Sdfr * 645178825Sdfr * @ingroup krb5_ccache 64655682Smarkm */ 64755682Smarkm 648178825Sdfr 649178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 65055682Smarkmkrb5_cc_start_seq_get (krb5_context context, 65155682Smarkm const krb5_ccache id, 65255682Smarkm krb5_cc_cursor *cursor) 65355682Smarkm{ 654178825Sdfr return (*id->ops->get_first)(context, id, cursor); 65555682Smarkm} 65655682Smarkm 657178825Sdfr/** 65855682Smarkm * Retrieve the next cred pointed to by (`id', `cursor') in `creds' 65955682Smarkm * and advance `cursor'. 660178825Sdfr * 661178825Sdfr * @return Return 0 or an error code. 662178825Sdfr * 663178825Sdfr * @ingroup krb5_ccache 66455682Smarkm */ 66555682Smarkm 666178825Sdfr 667178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 66855682Smarkmkrb5_cc_next_cred (krb5_context context, 66955682Smarkm const krb5_ccache id, 67078527Sassar krb5_cc_cursor *cursor, 67178527Sassar krb5_creds *creds) 67255682Smarkm{ 673178825Sdfr return (*id->ops->get_next)(context, id, cursor, creds); 67455682Smarkm} 67555682Smarkm 676178825Sdfr/** 677178825Sdfr * Like krb5_cc_next_cred, but allow for selective retrieval 678178825Sdfr * 679178825Sdfr * @ingroup krb5_ccache 680178825Sdfr */ 681178825Sdfr 682178825Sdfr 683178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 684178825Sdfrkrb5_cc_next_cred_match(krb5_context context, 685178825Sdfr const krb5_ccache id, 686178825Sdfr krb5_cc_cursor * cursor, 687178825Sdfr krb5_creds * creds, 688178825Sdfr krb5_flags whichfields, 689178825Sdfr const krb5_creds * mcreds) 690178825Sdfr{ 691178825Sdfr krb5_error_code ret; 692178825Sdfr while (1) { 693178825Sdfr ret = krb5_cc_next_cred(context, id, cursor, creds); 694178825Sdfr if (ret) 695178825Sdfr return ret; 696178825Sdfr if (mcreds == NULL || krb5_compare_creds(context, whichfields, mcreds, creds)) 697178825Sdfr return 0; 698178825Sdfr krb5_free_cred_contents(context, creds); 699178825Sdfr } 700178825Sdfr} 701178825Sdfr 702178825Sdfr/** 70355682Smarkm * Destroy the cursor `cursor'. 704178825Sdfr * 705178825Sdfr * @ingroup krb5_ccache 70655682Smarkm */ 70755682Smarkm 708178825Sdfr 709178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 71055682Smarkmkrb5_cc_end_seq_get (krb5_context context, 71155682Smarkm const krb5_ccache id, 71255682Smarkm krb5_cc_cursor *cursor) 71355682Smarkm{ 714178825Sdfr return (*id->ops->end_get)(context, id, cursor); 71555682Smarkm} 71655682Smarkm 717178825Sdfr/** 71855682Smarkm * Remove the credential identified by `cred', `which' from `id'. 719178825Sdfr * 720178825Sdfr * @ingroup krb5_ccache 72155682Smarkm */ 72255682Smarkm 723178825Sdfr 724178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 72555682Smarkmkrb5_cc_remove_cred(krb5_context context, 72655682Smarkm krb5_ccache id, 72755682Smarkm krb5_flags which, 72855682Smarkm krb5_creds *cred) 72955682Smarkm{ 73078527Sassar if(id->ops->remove_cred == NULL) { 73178527Sassar krb5_set_error_string(context, 73278527Sassar "ccache %s does not support remove_cred", 73378527Sassar id->ops->prefix); 73472445Sassar return EACCES; /* XXX */ 73578527Sassar } 73672445Sassar return (*id->ops->remove_cred)(context, id, which, cred); 73755682Smarkm} 73855682Smarkm 739178825Sdfr/** 74055682Smarkm * Set the flags of `id' to `flags'. 741178825Sdfr * 742178825Sdfr * @ingroup krb5_ccache 74355682Smarkm */ 74455682Smarkm 745178825Sdfr 746178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 74755682Smarkmkrb5_cc_set_flags(krb5_context context, 74855682Smarkm krb5_ccache id, 74955682Smarkm krb5_flags flags) 75055682Smarkm{ 751178825Sdfr return (*id->ops->set_flags)(context, id, flags); 75255682Smarkm} 75355682Smarkm 754178825Sdfr/** 75555682Smarkm * Copy the contents of `from' to `to'. 756178825Sdfr * 757178825Sdfr * @ingroup krb5_ccache 75855682Smarkm */ 75955682Smarkm 760178825Sdfr 761178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 762178825Sdfrkrb5_cc_copy_cache_match(krb5_context context, 763178825Sdfr const krb5_ccache from, 764178825Sdfr krb5_ccache to, 765178825Sdfr krb5_flags whichfields, 766178825Sdfr const krb5_creds * mcreds, 767178825Sdfr unsigned int *matched) 76855682Smarkm{ 76955682Smarkm krb5_error_code ret; 77055682Smarkm krb5_cc_cursor cursor; 77155682Smarkm krb5_creds cred; 77255682Smarkm krb5_principal princ; 77355682Smarkm 77455682Smarkm ret = krb5_cc_get_principal(context, from, &princ); 775178825Sdfr if (ret) 77655682Smarkm return ret; 77755682Smarkm ret = krb5_cc_initialize(context, to, princ); 778178825Sdfr if (ret) { 77955682Smarkm krb5_free_principal(context, princ); 78055682Smarkm return ret; 78155682Smarkm } 78255682Smarkm ret = krb5_cc_start_seq_get(context, from, &cursor); 783178825Sdfr if (ret) { 78455682Smarkm krb5_free_principal(context, princ); 78555682Smarkm return ret; 78655682Smarkm } 787178825Sdfr if (matched) 788178825Sdfr *matched = 0; 789178825Sdfr while (ret == 0 && 790178825Sdfr krb5_cc_next_cred_match(context, from, &cursor, &cred, 791178825Sdfr whichfields, mcreds) == 0) { 792178825Sdfr if (matched) 793178825Sdfr (*matched)++; 79455682Smarkm ret = krb5_cc_store_cred(context, to, &cred); 795178825Sdfr krb5_free_cred_contents(context, &cred); 79655682Smarkm } 79755682Smarkm krb5_cc_end_seq_get(context, from, &cursor); 79855682Smarkm krb5_free_principal(context, princ); 79955682Smarkm return ret; 80055682Smarkm} 80155682Smarkm 802178825Sdfr/** 803178825Sdfr * Just like krb5_cc_copy_cache_match, but copy everything. 804178825Sdfr * 805178825Sdfr * @ingroup krb5_ccache 806178825Sdfr */ 807178825Sdfr 808178825Sdfr 809178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 810178825Sdfrkrb5_cc_copy_cache(krb5_context context, 811178825Sdfr const krb5_ccache from, 812178825Sdfr krb5_ccache to) 813178825Sdfr{ 814178825Sdfr return krb5_cc_copy_cache_match(context, from, to, 0, NULL, NULL); 815178825Sdfr} 816178825Sdfr 817178825Sdfr/** 81855682Smarkm * Return the version of `id'. 819178825Sdfr * 820178825Sdfr * @ingroup krb5_ccache 82155682Smarkm */ 82255682Smarkm 823178825Sdfr 824178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 82555682Smarkmkrb5_cc_get_version(krb5_context context, 82655682Smarkm const krb5_ccache id) 82755682Smarkm{ 82855682Smarkm if(id->ops->get_version) 829178825Sdfr return (*id->ops->get_version)(context, id); 83055682Smarkm else 83155682Smarkm return 0; 83255682Smarkm} 833178825Sdfr 834178825Sdfr/** 835178825Sdfr * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred 836178825Sdfr * 837178825Sdfr * @ingroup krb5_ccache 838178825Sdfr */ 839178825Sdfr 840178825Sdfr 841178825Sdfrvoid KRB5_LIB_FUNCTION 842178825Sdfrkrb5_cc_clear_mcred(krb5_creds *mcred) 843178825Sdfr{ 844178825Sdfr memset(mcred, 0, sizeof(*mcred)); 845178825Sdfr} 846178825Sdfr 847178825Sdfr/** 848178825Sdfr * Get the cc ops that is registered in `context' to handle the 849178825Sdfr * `prefix'. `prefix' can be a complete credential cache name or a 850178825Sdfr * prefix, the function will only use part up to the first colon (:) 851178825Sdfr * if there is one. 852178825Sdfr * Returns NULL if ops not found. 853178825Sdfr * 854178825Sdfr * @ingroup krb5_ccache 855178825Sdfr */ 856178825Sdfr 857178825Sdfr 858178825Sdfrconst krb5_cc_ops * 859178825Sdfrkrb5_cc_get_prefix_ops(krb5_context context, const char *prefix) 860178825Sdfr{ 861178825Sdfr char *p, *p1; 862178825Sdfr int i; 863178825Sdfr 864178825Sdfr if (prefix[0] == '/') 865178825Sdfr return &krb5_fcc_ops; 866178825Sdfr 867178825Sdfr p = strdup(prefix); 868178825Sdfr if (p == NULL) { 869178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 870178825Sdfr return NULL; 871178825Sdfr } 872178825Sdfr p1 = strchr(p, ':'); 873178825Sdfr if (p1) 874178825Sdfr *p1 = '\0'; 875178825Sdfr 876178825Sdfr for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 877178825Sdfr if(strcmp(context->cc_ops[i].prefix, p) == 0) { 878178825Sdfr free(p); 879178825Sdfr return &context->cc_ops[i]; 880178825Sdfr } 881178825Sdfr } 882178825Sdfr free(p); 883178825Sdfr return NULL; 884178825Sdfr} 885178825Sdfr 886178825Sdfrstruct krb5_cc_cache_cursor_data { 887178825Sdfr const krb5_cc_ops *ops; 888178825Sdfr krb5_cc_cursor cursor; 889178825Sdfr}; 890178825Sdfr 891178825Sdfr/** 892178825Sdfr * Start iterating over all caches of `type'. If `type' is NULL, the 893178825Sdfr * default type is * used. `cursor' is initialized to the beginning. 894178825Sdfr * 895178825Sdfr * @return Return 0 or an error code. 896178825Sdfr * 897178825Sdfr * @ingroup krb5_ccache 898178825Sdfr */ 899178825Sdfr 900178825Sdfr 901178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 902178825Sdfrkrb5_cc_cache_get_first (krb5_context context, 903178825Sdfr const char *type, 904178825Sdfr krb5_cc_cache_cursor *cursor) 905178825Sdfr{ 906178825Sdfr const krb5_cc_ops *ops; 907178825Sdfr krb5_error_code ret; 908178825Sdfr 909178825Sdfr if (type == NULL) 910178825Sdfr type = krb5_cc_default_name(context); 911178825Sdfr 912178825Sdfr ops = krb5_cc_get_prefix_ops(context, type); 913178825Sdfr if (ops == NULL) { 914178825Sdfr krb5_set_error_string(context, "Unknown type \"%s\" when iterating " 915178825Sdfr "trying to iterate the credential caches", type); 916178825Sdfr return KRB5_CC_UNKNOWN_TYPE; 917178825Sdfr } 918178825Sdfr 919178825Sdfr if (ops->get_cache_first == NULL) { 920178825Sdfr krb5_set_error_string(context, "Credential cache type %s doesn't support " 921178825Sdfr "iterations over caches", ops->prefix); 922178825Sdfr return KRB5_CC_NOSUPP; 923178825Sdfr } 924178825Sdfr 925178825Sdfr *cursor = calloc(1, sizeof(**cursor)); 926178825Sdfr if (*cursor == NULL) { 927178825Sdfr krb5_set_error_string(context, "malloc - out of memory"); 928178825Sdfr return ENOMEM; 929178825Sdfr } 930178825Sdfr 931178825Sdfr (*cursor)->ops = ops; 932178825Sdfr 933178825Sdfr ret = ops->get_cache_first(context, &(*cursor)->cursor); 934178825Sdfr if (ret) { 935178825Sdfr free(*cursor); 936178825Sdfr *cursor = NULL; 937178825Sdfr } 938178825Sdfr return ret; 939178825Sdfr} 940178825Sdfr 941178825Sdfr/** 942178825Sdfr * Retrieve the next cache pointed to by (`cursor') in `id' 943178825Sdfr * and advance `cursor'. 944178825Sdfr * 945178825Sdfr * @return Return 0 or an error code. 946178825Sdfr * 947178825Sdfr * @ingroup krb5_ccache 948178825Sdfr */ 949178825Sdfr 950178825Sdfr 951178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 952178825Sdfrkrb5_cc_cache_next (krb5_context context, 953178825Sdfr krb5_cc_cache_cursor cursor, 954178825Sdfr krb5_ccache *id) 955178825Sdfr{ 956178825Sdfr return cursor->ops->get_cache_next(context, cursor->cursor, id); 957178825Sdfr} 958178825Sdfr 959178825Sdfr/** 960178825Sdfr * Destroy the cursor `cursor'. 961178825Sdfr * 962178825Sdfr * @return Return 0 or an error code. 963178825Sdfr * 964178825Sdfr * @ingroup krb5_ccache 965178825Sdfr */ 966178825Sdfr 967178825Sdfr 968178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 969178825Sdfrkrb5_cc_cache_end_seq_get (krb5_context context, 970178825Sdfr krb5_cc_cache_cursor cursor) 971178825Sdfr{ 972178825Sdfr krb5_error_code ret; 973178825Sdfr ret = cursor->ops->end_cache_get(context, cursor->cursor); 974178825Sdfr cursor->ops = NULL; 975178825Sdfr free(cursor); 976178825Sdfr return ret; 977178825Sdfr} 978178825Sdfr 979178825Sdfr/** 980178825Sdfr * Search for a matching credential cache of type `type' that have the 981178825Sdfr * `principal' as the default principal. If NULL is used for `type', 982178825Sdfr * the default type is used. On success, `id' needs to be freed with 983178825Sdfr * krb5_cc_close or krb5_cc_destroy. 984178825Sdfr * 985178825Sdfr * @return On failure, error code is returned and `id' is set to NULL. 986178825Sdfr * 987178825Sdfr * @ingroup krb5_ccache 988178825Sdfr */ 989178825Sdfr 990178825Sdfr 991178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 992178825Sdfrkrb5_cc_cache_match (krb5_context context, 993178825Sdfr krb5_principal client, 994178825Sdfr const char *type, 995178825Sdfr krb5_ccache *id) 996178825Sdfr{ 997178825Sdfr krb5_cc_cache_cursor cursor; 998178825Sdfr krb5_error_code ret; 999178825Sdfr krb5_ccache cache = NULL; 1000178825Sdfr 1001178825Sdfr *id = NULL; 1002178825Sdfr 1003178825Sdfr ret = krb5_cc_cache_get_first (context, type, &cursor); 1004178825Sdfr if (ret) 1005178825Sdfr return ret; 1006178825Sdfr 1007178825Sdfr while ((ret = krb5_cc_cache_next (context, cursor, &cache)) == 0) { 1008178825Sdfr krb5_principal principal; 1009178825Sdfr 1010178825Sdfr ret = krb5_cc_get_principal(context, cache, &principal); 1011178825Sdfr if (ret == 0) { 1012178825Sdfr krb5_boolean match; 1013178825Sdfr 1014178825Sdfr match = krb5_principal_compare(context, principal, client); 1015178825Sdfr krb5_free_principal(context, principal); 1016178825Sdfr if (match) 1017178825Sdfr break; 1018178825Sdfr } 1019178825Sdfr 1020178825Sdfr krb5_cc_close(context, cache); 1021178825Sdfr cache = NULL; 1022178825Sdfr } 1023178825Sdfr 1024178825Sdfr krb5_cc_cache_end_seq_get(context, cursor); 1025178825Sdfr 1026178825Sdfr if (cache == NULL) { 1027178825Sdfr char *str; 1028178825Sdfr 1029178825Sdfr krb5_unparse_name(context, client, &str); 1030178825Sdfr 1031178825Sdfr krb5_set_error_string(context, "Principal %s not found in a " 1032178825Sdfr "credential cache", str ? str : "<out of memory>"); 1033178825Sdfr if (str) 1034178825Sdfr free(str); 1035178825Sdfr return KRB5_CC_NOTFOUND; 1036178825Sdfr } 1037178825Sdfr *id = cache; 1038178825Sdfr 1039178825Sdfr return 0; 1040178825Sdfr} 1041178825Sdfr 1042178825Sdfr/** 1043178825Sdfr * Move the content from one credential cache to another. The 1044178825Sdfr * operation is an atomic switch. 1045178825Sdfr * 1046178825Sdfr * @param context a Keberos context 1047178825Sdfr * @param from the credential cache to move the content from 1048178825Sdfr * @param to the credential cache to move the content to 1049178825Sdfr 1050178825Sdfr * @return On sucess, from is freed. On failure, error code is 1051178825Sdfr * returned and from and to are both still allocated. 1052178825Sdfr * 1053178825Sdfr * @ingroup krb5_ccache 1054178825Sdfr */ 1055178825Sdfr 1056178825Sdfrkrb5_error_code 1057178825Sdfrkrb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 1058178825Sdfr{ 1059178825Sdfr krb5_error_code ret; 1060178825Sdfr 1061178825Sdfr if (strcmp(from->ops->prefix, to->ops->prefix) != 0) { 1062178825Sdfr krb5_set_error_string(context, "Moving credentials between diffrent " 1063178825Sdfr "types not yet supported"); 1064178825Sdfr return KRB5_CC_NOSUPP; 1065178825Sdfr } 1066178825Sdfr 1067178825Sdfr ret = (*to->ops->move)(context, from, to); 1068178825Sdfr if (ret == 0) { 1069178825Sdfr memset(from, 0, sizeof(*from)); 1070178825Sdfr free(from); 1071178825Sdfr } 1072178825Sdfr return ret; 1073178825Sdfr} 1074