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