1 /* 2 * Copyright (c) 1997-2004 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: mcache.c,v 1.15.6.1 2004/03/06 16:57:16 lha Exp $"); 37 38 typedef struct krb5_mcache { 39 char *name; 40 unsigned int refcnt; 41 int dead; 42 krb5_principal primary_principal; 43 struct link { 44 krb5_creds cred; 45 struct link *next; 46 } *creds; 47 struct krb5_mcache *next; 48 } krb5_mcache; 49 50 static struct krb5_mcache *mcc_head; 51 52 #define MCACHE(X) ((krb5_mcache *)(X)->data.data) 53 54 #define MISDEAD(X) ((X)->dead) 55 56 #define MCC_CURSOR(C) ((struct link*)(C)) 57 58 static const char* 59 mcc_get_name(krb5_context context, 60 krb5_ccache id) 61 { 62 return MCACHE(id)->name; 63 } 64 65 static krb5_mcache * 66 mcc_alloc(const char *name) 67 { 68 krb5_mcache *m; 69 70 ALLOC(m, 1); 71 if(m == NULL) 72 return NULL; 73 if(name == NULL) 74 asprintf(&m->name, "%p", m); 75 else 76 m->name = strdup(name); 77 if(m->name == NULL) { 78 free(m); 79 return NULL; 80 } 81 m->dead = 0; 82 m->refcnt = 1; 83 m->primary_principal = NULL; 84 m->creds = NULL; 85 m->next = mcc_head; 86 mcc_head = m; 87 return m; 88 } 89 90 static krb5_error_code 91 mcc_resolve(krb5_context context, krb5_ccache *id, const char *res) 92 { 93 krb5_mcache *m; 94 95 for (m = mcc_head; m != NULL; m = m->next) 96 if (strcmp(m->name, res) == 0) 97 break; 98 99 if (m != NULL) { 100 m->refcnt++; 101 (*id)->data.data = m; 102 (*id)->data.length = sizeof(*m); 103 return 0; 104 } 105 106 m = mcc_alloc(res); 107 if (m == NULL) { 108 krb5_set_error_string (context, "malloc: out of memory"); 109 return KRB5_CC_NOMEM; 110 } 111 112 (*id)->data.data = m; 113 (*id)->data.length = sizeof(*m); 114 115 return 0; 116 } 117 118 119 static krb5_error_code 120 mcc_gen_new(krb5_context context, krb5_ccache *id) 121 { 122 krb5_mcache *m; 123 124 m = mcc_alloc(NULL); 125 126 if (m == NULL) { 127 krb5_set_error_string (context, "malloc: out of memory"); 128 return KRB5_CC_NOMEM; 129 } 130 131 (*id)->data.data = m; 132 (*id)->data.length = sizeof(*m); 133 134 return 0; 135 } 136 137 static krb5_error_code 138 mcc_initialize(krb5_context context, 139 krb5_ccache id, 140 krb5_principal primary_principal) 141 { 142 krb5_mcache *m = MCACHE(id); 143 m->dead = 0; 144 return krb5_copy_principal (context, 145 primary_principal, 146 &m->primary_principal); 147 } 148 149 static krb5_error_code 150 mcc_close(krb5_context context, 151 krb5_ccache id) 152 { 153 krb5_mcache *m = MCACHE(id); 154 155 if (--m->refcnt != 0) 156 return 0; 157 158 if (MISDEAD(m)) { 159 free (m->name); 160 krb5_data_free(&id->data); 161 } 162 163 return 0; 164 } 165 166 static krb5_error_code 167 mcc_destroy(krb5_context context, 168 krb5_ccache id) 169 { 170 krb5_mcache **n, *m = MCACHE(id); 171 struct link *l; 172 173 if (m->refcnt == 0) 174 krb5_abortx(context, "mcc_destroy: refcnt already 0"); 175 176 if (!MISDEAD(m)) { 177 /* if this is an active mcache, remove it from the linked 178 list, and free all data */ 179 for(n = &mcc_head; n && *n; n = &(*n)->next) { 180 if(m == *n) { 181 *n = m->next; 182 break; 183 } 184 } 185 if (m->primary_principal != NULL) { 186 krb5_free_principal (context, m->primary_principal); 187 m->primary_principal = NULL; 188 } 189 m->dead = 1; 190 191 l = m->creds; 192 while (l != NULL) { 193 struct link *old; 194 195 krb5_free_creds_contents (context, &l->cred); 196 old = l; 197 l = l->next; 198 free (old); 199 } 200 m->creds = NULL; 201 } 202 return 0; 203 } 204 205 static krb5_error_code 206 mcc_store_cred(krb5_context context, 207 krb5_ccache id, 208 krb5_creds *creds) 209 { 210 krb5_mcache *m = MCACHE(id); 211 krb5_error_code ret; 212 struct link *l; 213 214 if (MISDEAD(m)) 215 return ENOENT; 216 217 l = malloc (sizeof(*l)); 218 if (l == NULL) { 219 krb5_set_error_string (context, "malloc: out of memory"); 220 return KRB5_CC_NOMEM; 221 } 222 l->next = m->creds; 223 m->creds = l; 224 memset (&l->cred, 0, sizeof(l->cred)); 225 ret = krb5_copy_creds_contents (context, creds, &l->cred); 226 if (ret) { 227 m->creds = l->next; 228 free (l); 229 return ret; 230 } 231 return 0; 232 } 233 234 static krb5_error_code 235 mcc_get_principal(krb5_context context, 236 krb5_ccache id, 237 krb5_principal *principal) 238 { 239 krb5_mcache *m = MCACHE(id); 240 241 if (MISDEAD(m) || m->primary_principal == NULL) 242 return ENOENT; 243 return krb5_copy_principal (context, 244 m->primary_principal, 245 principal); 246 } 247 248 static krb5_error_code 249 mcc_get_first (krb5_context context, 250 krb5_ccache id, 251 krb5_cc_cursor *cursor) 252 { 253 krb5_mcache *m = MCACHE(id); 254 255 if (MISDEAD(m)) 256 return ENOENT; 257 258 *cursor = m->creds; 259 return 0; 260 } 261 262 static krb5_error_code 263 mcc_get_next (krb5_context context, 264 krb5_ccache id, 265 krb5_cc_cursor *cursor, 266 krb5_creds *creds) 267 { 268 krb5_mcache *m = MCACHE(id); 269 struct link *l; 270 271 if (MISDEAD(m)) 272 return ENOENT; 273 274 l = *cursor; 275 if (l != NULL) { 276 *cursor = l->next; 277 return krb5_copy_creds_contents (context, 278 &l->cred, 279 creds); 280 } else 281 return KRB5_CC_END; 282 } 283 284 static krb5_error_code 285 mcc_end_get (krb5_context context, 286 krb5_ccache id, 287 krb5_cc_cursor *cursor) 288 { 289 return 0; 290 } 291 292 static krb5_error_code 293 mcc_remove_cred(krb5_context context, 294 krb5_ccache id, 295 krb5_flags which, 296 krb5_creds *mcreds) 297 { 298 krb5_mcache *m = MCACHE(id); 299 struct link **q, *p; 300 for(q = &m->creds, p = *q; p; p = *q) { 301 if(krb5_compare_creds(context, which, mcreds, &p->cred)) { 302 *q = p->next; 303 krb5_free_creds_contents(context, &p->cred); 304 free(p); 305 } else 306 q = &p->next; 307 } 308 return 0; 309 } 310 311 static krb5_error_code 312 mcc_set_flags(krb5_context context, 313 krb5_ccache id, 314 krb5_flags flags) 315 { 316 return 0; /* XXX */ 317 } 318 319 const krb5_cc_ops krb5_mcc_ops = { 320 "MEMORY", 321 mcc_get_name, 322 mcc_resolve, 323 mcc_gen_new, 324 mcc_initialize, 325 mcc_destroy, 326 mcc_close, 327 mcc_store_cred, 328 NULL, /* mcc_retrieve */ 329 mcc_get_principal, 330 mcc_get_first, 331 mcc_get_next, 332 mcc_end_get, 333 mcc_remove_cred, 334 mcc_set_flags 335 }; 336