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