1 /* 2 * lib/krb5/ccache/ccbase.c 3 * 4 * Copyright 1990,2004 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 * 26 * 27 * Registration functions for ccache. 28 */ 29 30 /* 31 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 32 * Use is subject to license terms. 33 */ 34 35 36 #include "k5-int.h" 37 #include "k5-thread.h" 38 39 #include "fcc.h" 40 #include "cc-int.h" 41 42 struct krb5_cc_typelist { 43 const krb5_cc_ops *ops; 44 struct krb5_cc_typelist *next; 45 }; 46 47 struct krb5_cc_typecursor { 48 struct krb5_cc_typelist *tptr; 49 }; 50 /* typedef krb5_cc_typecursor in k5-int.h */ 51 52 extern const krb5_cc_ops krb5_mcc_ops; 53 #ifdef USE_KEYRING_CCACHE 54 extern const krb5_cc_ops krb5_krcc_ops; 55 #endif 56 57 #ifdef _WIN32 58 extern const krb5_cc_ops krb5_lcc_ops; 59 static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL }; 60 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry }; 61 #else 62 63 #ifdef USE_CCAPI_V3 64 extern const krb5_cc_ops krb5_cc_stdcc_ops; 65 static struct krb5_cc_typelist cc_stdcc_entry = { &krb5_cc_stdcc_ops, NULL }; 66 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_stdcc_entry }; 67 #else 68 69 static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL }; 70 #endif /* USE_CCAPI_V3 */ 71 72 #ifdef USE_KEYRING_CCACHE 73 static struct krb5_cc_typelist cc_file_entry = { &krb5_cc_file_ops, 74 &cc_mcc_entry }; 75 static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops, 76 &cc_file_entry }; 77 #endif /* USE_KEYRING_CCACHE */ 78 #endif 79 80 static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops, 81 &cc_mcc_entry }; 82 #ifdef USE_KEYRING_CCACHE 83 #define INITIAL_TYPEHEAD (&cc_krcc_entry) 84 #else 85 #define INITIAL_TYPEHEAD (&cc_fcc_entry) 86 #endif 87 static struct krb5_cc_typelist *cc_typehead = INITIAL_TYPEHEAD; 88 static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER; 89 90 static krb5_error_code 91 krb5int_cc_getops(krb5_context, const char *, const krb5_cc_ops **); 92 93 int 94 krb5int_cc_initialize(void) 95 { 96 int err; 97 98 err = k5_mutex_finish_init(&krb5int_mcc_mutex); 99 if (err) 100 return err; 101 err = k5_mutex_finish_init(&cc_typelist_lock); 102 if (err) 103 return err; 104 err = k5_mutex_finish_init(&krb5int_cc_file_mutex); 105 if (err) 106 return err; 107 #ifdef USE_KEYRING_CCACHE 108 err = k5_mutex_finish_init(&krb5int_krcc_mutex); 109 if (err) 110 return err; 111 #endif 112 return 0; 113 } 114 115 void 116 krb5int_cc_finalize(void) 117 { 118 struct krb5_cc_typelist *t, *t_next; 119 k5_mutex_destroy(&cc_typelist_lock); 120 k5_mutex_destroy(&krb5int_cc_file_mutex); 121 k5_mutex_destroy(&krb5int_mcc_mutex); 122 #ifdef USE_KEYRING_CCACHE 123 k5_mutex_destroy(&krb5int_krcc_mutex); 124 #endif 125 for (t = cc_typehead; t != INITIAL_TYPEHEAD; t = t_next) { 126 t_next = t->next; 127 free(t); 128 } 129 } 130 131 132 /* 133 * Register a new credentials cache type 134 * If override is set, replace any existing ccache with that type tag 135 */ 136 137 krb5_error_code KRB5_CALLCONV 138 krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override) 139 { 140 struct krb5_cc_typelist *t; 141 krb5_error_code err; 142 143 err = k5_mutex_lock(&cc_typelist_lock); 144 if (err) 145 return err; 146 for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next) 147 ; 148 if (t) { 149 if (override) { 150 t->ops = ops; 151 k5_mutex_unlock(&cc_typelist_lock); 152 return 0; 153 } else { 154 k5_mutex_unlock(&cc_typelist_lock); 155 return KRB5_CC_TYPE_EXISTS; 156 } 157 } 158 if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) { 159 k5_mutex_unlock(&cc_typelist_lock); 160 return ENOMEM; 161 } 162 t->next = cc_typehead; 163 t->ops = ops; 164 cc_typehead = t; 165 k5_mutex_unlock(&cc_typelist_lock); 166 return 0; 167 } 168 169 /* 170 * Resolve a credential cache name into a cred. cache object. 171 * 172 * The name is currently constrained to be of the form "type:residual"; 173 * 174 * The "type" portion corresponds to one of the predefined credential 175 * cache types, while the "residual" portion is specific to the 176 * particular cache type. 177 */ 178 179 #include <ctype.h> 180 krb5_error_code KRB5_CALLCONV 181 krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache) 182 { 183 char *pfx, *cp; 184 const char *resid; 185 unsigned int pfxlen; 186 krb5_error_code err; 187 const krb5_cc_ops *ops; 188 189 /* Solaris Kerberos */ 190 if (!name) 191 return KRB5_CC_BADNAME; 192 193 pfx = NULL; 194 cp = strchr (name, ':'); 195 if (!cp) { 196 if (krb5_cc_dfl_ops) 197 return (*krb5_cc_dfl_ops->resolve)(context, cache, name); 198 else 199 return KRB5_CC_BADNAME; 200 } 201 202 pfxlen = cp - name; 203 204 if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) { 205 /* We found a drive letter not a prefix - use FILE */ 206 pfx = strdup("FILE"); 207 if (!pfx) 208 return ENOMEM; 209 210 resid = name; 211 } else { 212 resid = name + pfxlen + 1; 213 214 pfx = malloc (pfxlen+1); 215 if (!pfx) 216 return ENOMEM; 217 218 memcpy (pfx, name, pfxlen); 219 pfx[pfxlen] = '\0'; 220 } 221 222 *cache = (krb5_ccache) 0; 223 224 err = krb5int_cc_getops(context, pfx, &ops); 225 if (pfx != NULL) 226 free(pfx); 227 if (err) 228 return err; 229 230 return ops->resolve(context, cache, resid); 231 } 232 233 /* 234 * cc_getops 235 * 236 * Internal function to return the ops vector for a given ccache 237 * prefix string. 238 */ 239 static krb5_error_code 240 krb5int_cc_getops( 241 krb5_context context, 242 const char *pfx, 243 const krb5_cc_ops **ops) 244 { 245 krb5_error_code err; 246 struct krb5_cc_typelist *tlist; 247 248 err = k5_mutex_lock(&cc_typelist_lock); 249 if (err) 250 return err; 251 252 for (tlist = cc_typehead; tlist; tlist = tlist->next) { 253 if (strcmp (tlist->ops->prefix, pfx) == 0) { 254 *ops = tlist->ops; 255 k5_mutex_unlock(&cc_typelist_lock); 256 return 0; 257 } 258 } 259 k5_mutex_unlock(&cc_typelist_lock); 260 if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) { 261 *ops = krb5_cc_dfl_ops; 262 return 0; 263 } 264 return KRB5_CC_UNKNOWN_TYPE; 265 } 266 267 /* 268 * cc_new_unique 269 * 270 * Generate a new unique ccache, given a ccache type and a hint 271 * string. Ignores the hint string for now. 272 */ 273 krb5_error_code KRB5_CALLCONV 274 krb5_cc_new_unique( 275 krb5_context context, 276 const char *type, 277 const char *hint, 278 krb5_ccache *id) 279 { 280 const krb5_cc_ops *ops; 281 krb5_error_code err; 282 283 *id = NULL; 284 285 err = krb5int_cc_getops(context, type, &ops); 286 if (err) 287 return err; 288 289 return ops->gen_new(context, id); 290 } 291 292 /* 293 * cc_typecursor 294 * 295 * Note: to avoid copying the typelist at cursor creation time, among 296 * other things, we assume that the only additions ever occur to the 297 * typelist. 298 */ 299 krb5_error_code 300 krb5int_cc_typecursor_new(krb5_context context, krb5_cc_typecursor *t) 301 { 302 krb5_error_code err = 0; 303 krb5_cc_typecursor n = NULL; 304 305 *t = NULL; 306 n = malloc(sizeof(*n)); 307 if (n == NULL) 308 return ENOMEM; 309 310 err = k5_mutex_lock(&cc_typelist_lock); 311 if (err) 312 goto errout; 313 n->tptr = cc_typehead; 314 err = k5_mutex_unlock(&cc_typelist_lock); 315 if (err) 316 goto errout; 317 318 *t = n; 319 errout: 320 if (err) 321 free(n); 322 return err; 323 } 324 325 krb5_error_code 326 krb5int_cc_typecursor_next( 327 krb5_context context, 328 krb5_cc_typecursor t, 329 const krb5_cc_ops **ops) 330 { 331 krb5_error_code err = 0; 332 333 *ops = NULL; 334 if (t->tptr == NULL) 335 return 0; 336 337 err = k5_mutex_lock(&cc_typelist_lock); 338 if (err) 339 goto errout; 340 *ops = t->tptr->ops; 341 t->tptr = t->tptr->next; 342 err = k5_mutex_unlock(&cc_typelist_lock); 343 if (err) 344 goto errout; 345 346 errout: 347 return err; 348 } 349 350 krb5_error_code 351 krb5int_cc_typecursor_free(krb5_context context, krb5_cc_typecursor *t) 352 { 353 free(*t); 354 *t = NULL; 355 return 0; 356 } 357