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