cache.c revision 120945
1/* 2 * Copyright (c) 1997-2003 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "krb5_locl.h" 35 36RCSID("$Id: cache.c,v 1.52 2003/03/16 18:23:59 lha Exp $"); 37 38/* 39 * Add a new ccache type with operations `ops', overwriting any 40 * existing one if `override'. 41 * Return an error code or 0. 42 */ 43 44krb5_error_code 45krb5_cc_register(krb5_context context, 46 const krb5_cc_ops *ops, 47 krb5_boolean override) 48{ 49 int i; 50 51 for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 52 if(strcmp(context->cc_ops[i].prefix, ops->prefix) == 0) { 53 if(!override) { 54 krb5_set_error_string(context, 55 "ccache type %s already exists", 56 ops->prefix); 57 return KRB5_CC_TYPE_EXISTS; 58 } 59 break; 60 } 61 } 62 if(i == context->num_cc_ops) { 63 krb5_cc_ops *o = realloc(context->cc_ops, 64 (context->num_cc_ops + 1) * 65 sizeof(*context->cc_ops)); 66 if(o == NULL) { 67 krb5_set_error_string(context, "malloc: out of memory"); 68 return KRB5_CC_NOMEM; 69 } 70 context->num_cc_ops++; 71 context->cc_ops = o; 72 memset(context->cc_ops + i, 0, 73 (context->num_cc_ops - i) * sizeof(*context->cc_ops)); 74 } 75 memcpy(&context->cc_ops[i], ops, sizeof(context->cc_ops[i])); 76 return 0; 77} 78 79/* 80 * Allocate memory for a new ccache in `id' with operations `ops' 81 * and name `residual'. 82 * Return 0 or an error code. 83 */ 84 85static krb5_error_code 86allocate_ccache (krb5_context context, 87 const krb5_cc_ops *ops, 88 const char *residual, 89 krb5_ccache *id) 90{ 91 krb5_error_code ret; 92 krb5_ccache p; 93 94 p = malloc(sizeof(*p)); 95 if(p == NULL) { 96 krb5_set_error_string(context, "malloc: out of memory"); 97 return KRB5_CC_NOMEM; 98 } 99 p->ops = ops; 100 *id = p; 101 ret = p->ops->resolve(context, id, residual); 102 if(ret) 103 free(p); 104 return ret; 105} 106 107/* 108 * Find and allocate a ccache in `id' from the specification in `residual'. 109 * If the ccache name doesn't contain any colon, interpret it as a file name. 110 * Return 0 or an error code. 111 */ 112 113krb5_error_code 114krb5_cc_resolve(krb5_context context, 115 const char *name, 116 krb5_ccache *id) 117{ 118 int i; 119 120 for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { 121 size_t prefix_len = strlen(context->cc_ops[i].prefix); 122 123 if(strncmp(context->cc_ops[i].prefix, name, prefix_len) == 0 124 && name[prefix_len] == ':') { 125 return allocate_ccache (context, &context->cc_ops[i], 126 name + prefix_len + 1, 127 id); 128 } 129 } 130 if (strchr (name, ':') == NULL) 131 return allocate_ccache (context, &krb5_fcc_ops, name, id); 132 else { 133 krb5_set_error_string(context, "unknown ccache type %s", name); 134 return KRB5_CC_UNKNOWN_TYPE; 135 } 136} 137 138/* 139 * Generate a new ccache of type `ops' in `id'. 140 * Return 0 or an error code. 141 */ 142 143krb5_error_code 144krb5_cc_gen_new(krb5_context context, 145 const krb5_cc_ops *ops, 146 krb5_ccache *id) 147{ 148 krb5_ccache p; 149 150 p = malloc (sizeof(*p)); 151 if (p == NULL) { 152 krb5_set_error_string(context, "malloc: out of memory"); 153 return KRB5_CC_NOMEM; 154 } 155 p->ops = ops; 156 *id = p; 157 return p->ops->gen_new(context, id); 158} 159 160/* 161 * Return the name of the ccache `id' 162 */ 163 164const char* 165krb5_cc_get_name(krb5_context context, 166 krb5_ccache id) 167{ 168 return id->ops->get_name(context, id); 169} 170 171/* 172 * Return the type of the ccache `id'. 173 */ 174 175const char* 176krb5_cc_get_type(krb5_context context, 177 krb5_ccache id) 178{ 179 return id->ops->prefix; 180} 181 182/* 183 * Return krb5_cc_ops of a the ccache `id'. 184 */ 185 186const krb5_cc_ops * 187krb5_cc_get_ops(krb5_context context, krb5_ccache id) 188{ 189 return id->ops; 190} 191 192/* 193 * Set the default cc name for `context' to `name'. 194 */ 195 196krb5_error_code 197krb5_cc_set_default_name(krb5_context context, const char *name) 198{ 199 krb5_error_code ret = 0; 200 char *p; 201 202 if (name == NULL) { 203 char *e; 204 e = getenv("KRB5CCNAME"); 205 if (e) 206 p = strdup(e); 207 else 208 asprintf(&p,"FILE:/tmp/krb5cc_%u", (unsigned)getuid()); 209 } else 210 p = strdup(name); 211 212 if (p == NULL) 213 return ENOMEM; 214 215 if (context->default_cc_name) 216 free(context->default_cc_name); 217 218 context->default_cc_name = p; 219 220 return ret; 221} 222 223/* 224 * Return a pointer to a context static string containing the default ccache name. 225 */ 226 227const char* 228krb5_cc_default_name(krb5_context context) 229{ 230 if (context->default_cc_name == NULL) 231 krb5_cc_set_default_name(context, NULL); 232 233 return context->default_cc_name; 234} 235 236/* 237 * Open the default ccache in `id'. 238 * Return 0 or an error code. 239 */ 240 241krb5_error_code 242krb5_cc_default(krb5_context context, 243 krb5_ccache *id) 244{ 245 const char *p = krb5_cc_default_name(context); 246 247 if (p == NULL) 248 return ENOMEM; 249 return krb5_cc_resolve(context, p, id); 250} 251 252/* 253 * Create a new ccache in `id' for `primary_principal'. 254 * Return 0 or an error code. 255 */ 256 257krb5_error_code 258krb5_cc_initialize(krb5_context context, 259 krb5_ccache id, 260 krb5_principal primary_principal) 261{ 262 return id->ops->init(context, id, primary_principal); 263} 264 265 266/* 267 * Remove the ccache `id'. 268 * Return 0 or an error code. 269 */ 270 271krb5_error_code 272krb5_cc_destroy(krb5_context context, 273 krb5_ccache id) 274{ 275 krb5_error_code ret; 276 277 ret = id->ops->destroy(context, id); 278 krb5_cc_close (context, id); 279 return ret; 280} 281 282/* 283 * Stop using the ccache `id' and free the related resources. 284 * Return 0 or an error code. 285 */ 286 287krb5_error_code 288krb5_cc_close(krb5_context context, 289 krb5_ccache id) 290{ 291 krb5_error_code ret; 292 ret = id->ops->close(context, id); 293 free(id); 294 return ret; 295} 296 297/* 298 * Store `creds' in the ccache `id'. 299 * Return 0 or an error code. 300 */ 301 302krb5_error_code 303krb5_cc_store_cred(krb5_context context, 304 krb5_ccache id, 305 krb5_creds *creds) 306{ 307 return id->ops->store(context, id, creds); 308} 309 310/* 311 * Retrieve the credential identified by `mcreds' (and `whichfields') 312 * from `id' in `creds'. 313 * Return 0 or an error code. 314 */ 315 316krb5_error_code 317krb5_cc_retrieve_cred(krb5_context context, 318 krb5_ccache id, 319 krb5_flags whichfields, 320 const krb5_creds *mcreds, 321 krb5_creds *creds) 322{ 323 krb5_error_code ret; 324 krb5_cc_cursor cursor; 325 krb5_cc_start_seq_get(context, id, &cursor); 326 while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){ 327 if(krb5_compare_creds(context, whichfields, mcreds, creds)){ 328 ret = 0; 329 break; 330 } 331 krb5_free_creds_contents (context, creds); 332 } 333 krb5_cc_end_seq_get(context, id, &cursor); 334 return ret; 335} 336 337/* 338 * Return the principal of `id' in `principal'. 339 * Return 0 or an error code. 340 */ 341 342krb5_error_code 343krb5_cc_get_principal(krb5_context context, 344 krb5_ccache id, 345 krb5_principal *principal) 346{ 347 return id->ops->get_princ(context, id, principal); 348} 349 350/* 351 * Start iterating over `id', `cursor' is initialized to the 352 * beginning. 353 * Return 0 or an error code. 354 */ 355 356krb5_error_code 357krb5_cc_start_seq_get (krb5_context context, 358 const krb5_ccache id, 359 krb5_cc_cursor *cursor) 360{ 361 return id->ops->get_first(context, id, cursor); 362} 363 364/* 365 * Retrieve the next cred pointed to by (`id', `cursor') in `creds' 366 * and advance `cursor'. 367 * Return 0 or an error code. 368 */ 369 370krb5_error_code 371krb5_cc_next_cred (krb5_context context, 372 const krb5_ccache id, 373 krb5_cc_cursor *cursor, 374 krb5_creds *creds) 375{ 376 return id->ops->get_next(context, id, cursor, creds); 377} 378 379/* 380 * Destroy the cursor `cursor'. 381 */ 382 383krb5_error_code 384krb5_cc_end_seq_get (krb5_context context, 385 const krb5_ccache id, 386 krb5_cc_cursor *cursor) 387{ 388 return id->ops->end_get(context, id, cursor); 389} 390 391/* 392 * Remove the credential identified by `cred', `which' from `id'. 393 */ 394 395krb5_error_code 396krb5_cc_remove_cred(krb5_context context, 397 krb5_ccache id, 398 krb5_flags which, 399 krb5_creds *cred) 400{ 401 if(id->ops->remove_cred == NULL) { 402 krb5_set_error_string(context, 403 "ccache %s does not support remove_cred", 404 id->ops->prefix); 405 return EACCES; /* XXX */ 406 } 407 return (*id->ops->remove_cred)(context, id, which, cred); 408} 409 410/* 411 * Set the flags of `id' to `flags'. 412 */ 413 414krb5_error_code 415krb5_cc_set_flags(krb5_context context, 416 krb5_ccache id, 417 krb5_flags flags) 418{ 419 return id->ops->set_flags(context, id, flags); 420} 421 422/* 423 * Copy the contents of `from' to `to'. 424 */ 425 426krb5_error_code 427krb5_cc_copy_cache(krb5_context context, 428 const krb5_ccache from, 429 krb5_ccache to) 430{ 431 krb5_error_code ret; 432 krb5_cc_cursor cursor; 433 krb5_creds cred; 434 krb5_principal princ; 435 436 ret = krb5_cc_get_principal(context, from, &princ); 437 if(ret) 438 return ret; 439 ret = krb5_cc_initialize(context, to, princ); 440 if(ret){ 441 krb5_free_principal(context, princ); 442 return ret; 443 } 444 ret = krb5_cc_start_seq_get(context, from, &cursor); 445 if(ret){ 446 krb5_free_principal(context, princ); 447 return ret; 448 } 449 while(ret == 0 && krb5_cc_next_cred(context, from, &cursor, &cred) == 0){ 450 ret = krb5_cc_store_cred(context, to, &cred); 451 krb5_free_creds_contents (context, &cred); 452 } 453 krb5_cc_end_seq_get(context, from, &cursor); 454 krb5_free_principal(context, princ); 455 return ret; 456} 457 458/* 459 * Return the version of `id'. 460 */ 461 462krb5_error_code 463krb5_cc_get_version(krb5_context context, 464 const krb5_ccache id) 465{ 466 if(id->ops->get_version) 467 return id->ops->get_version(context, id); 468 else 469 return 0; 470} 471