1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * mech_krb5/krb5/rcache/rc_mem.c 10 * 11 * This file of the Kerberos V5 software is derived from public-domain code 12 * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>. 13 */ 14 15 /* 16 * An implementation for the memory only (mem) replay cache type. 17 */ 18 #include "rc_common.h" 19 #include "rc_mem.h" 20 21 /* 22 * of course, list is backwards 23 * hash could be forwards since we have to search on match, but naaaah 24 */ 25 static int 26 rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep) 27 { 28 struct mem_data *t = (struct mem_data *)id->data; 29 int rephash; 30 struct authlist *ta, *pta = NULL, *head; 31 krb5_int32 time; 32 33 rephash = hash(rep, t->hsize); 34 35 /* Solaris: calling krb_timeofday() here, once for better perf. */ 36 krb5_timeofday(context, &time); 37 38 /* 39 * Solaris: calling alive() on rep since it doesn't make sense to store 40 * an expired replay. 41 */ 42 if (alive(context, rep, t->lifespan, time) == CMP_EXPIRED) 43 return (CMP_EXPIRED); 44 45 for (ta = t->h[rephash]; ta; ta = ta->nh) { 46 switch (cmp(&ta->rep, rep)) { 47 case CMP_REPLAY: 48 return (CMP_REPLAY); 49 case CMP_HOHUM: 50 if (alive(context, &ta->rep, t->lifespan, time) 51 == CMP_EXPIRED) { 52 free(ta->rep.client); 53 free(ta->rep.server); 54 if (pta) { 55 pta->nh = ta->nh; 56 free(ta); 57 ta = pta; 58 } else { 59 head = t->h[rephash]; 60 t->h[rephash] = ta->nh; 61 free(head); 62 } 63 continue; 64 } 65 } 66 pta = ta; 67 } 68 69 if (!(ta = (struct authlist *)malloc(sizeof (struct authlist)))) 70 return (CMP_MALLOC); 71 ta->rep = *rep; 72 if (!(ta->rep.client = strdup(rep->client))) { 73 free(ta); 74 return (CMP_MALLOC); 75 } 76 if (!(ta->rep.server = strdup(rep->server))) { 77 free(ta->rep.client); 78 free(ta); 79 return (CMP_MALLOC); 80 } 81 ta->nh = t->h[rephash]; 82 t->h[rephash] = ta; 83 84 return (CMP_HOHUM); 85 } 86 87 /*ARGSUSED*/ 88 char *KRB5_CALLCONV 89 krb5_rc_mem_get_name(krb5_context context, krb5_rcache id) 90 { 91 return (((struct mem_data *)(id->data))->name); 92 } 93 94 /*ARGSUSED*/ 95 krb5_error_code KRB5_CALLCONV 96 krb5_rc_mem_get_span( 97 krb5_context context, 98 krb5_rcache id, 99 krb5_deltat *lifespan) 100 { 101 krb5_error_code err; 102 struct mem_data *t; 103 104 err = k5_mutex_lock(&id->lock); 105 if (err) 106 return err; 107 t = (struct mem_data *) id->data; 108 *lifespan = t->lifespan; 109 k5_mutex_unlock(&id->lock); 110 return 0; 111 } 112 113 krb5_error_code KRB5_CALLCONV 114 krb5_rc_mem_init_locked(krb5_context context, krb5_rcache id, krb5_deltat lifespan) 115 { 116 struct mem_data *t = (struct mem_data *)id->data; 117 krb5_error_code retval; 118 119 t->lifespan = lifespan ? lifespan : context->clockskew; 120 /* default to clockskew from the context */ 121 return (0); 122 } 123 124 krb5_error_code KRB5_CALLCONV 125 krb5_rc_mem_init(krb5_context context, krb5_rcache id, krb5_deltat lifespan) 126 { 127 krb5_error_code retval; 128 129 retval = k5_mutex_lock(&id->lock); 130 if (retval) 131 return retval; 132 retval = krb5_rc_mem_init_locked(context, id, lifespan); 133 k5_mutex_unlock(&id->lock); 134 return retval; 135 } 136 137 138 krb5_error_code KRB5_CALLCONV 139 krb5_rc_mem_close_no_free(krb5_context context, krb5_rcache id) 140 { 141 struct mem_data *t = (struct mem_data *)id->data; 142 struct authlist *q, *qt; 143 int i; 144 145 if (t->name) 146 free(t->name); 147 for (i = 0; i < t->hsize; i++) 148 for (q = t->h[i]; q; q = qt) { 149 qt = q->nh; 150 free(q->rep.server); 151 free(q->rep.client); 152 free(q); 153 } 154 if (t->h) 155 free(t->h); 156 free(t); 157 id->data = NULL; 158 return (0); 159 } 160 161 krb5_error_code KRB5_CALLCONV 162 krb5_rc_mem_close(krb5_context context, krb5_rcache id) 163 { 164 krb5_error_code retval; 165 retval = k5_mutex_lock(&id->lock); 166 if (retval) 167 return retval; 168 krb5_rc_mem_close_no_free(context, id); 169 k5_mutex_unlock(&id->lock); 170 k5_mutex_destroy(&id->lock); 171 free(id); 172 return 0; 173 } 174 175 krb5_error_code KRB5_CALLCONV 176 krb5_rc_mem_destroy(krb5_context context, krb5_rcache id) 177 { 178 return (krb5_rc_mem_close(context, id)); 179 } 180 181 /*ARGSUSED*/ 182 krb5_error_code KRB5_CALLCONV 183 krb5_rc_mem_resolve(krb5_context context, krb5_rcache id, char *name) 184 { 185 struct mem_data *t = 0; 186 krb5_error_code retval; 187 188 /* allocate id? no */ 189 if (!(t = (struct mem_data *)malloc(sizeof (struct mem_data)))) 190 return (KRB5_RC_MALLOC); 191 id->data = (krb5_pointer)t; 192 memset(t, 0, sizeof (struct mem_data)); 193 if (name) { 194 t->name = malloc(strlen(name)+1); 195 if (!t->name) { 196 retval = KRB5_RC_MALLOC; 197 goto cleanup; 198 } 199 strcpy(t->name, name); 200 } else 201 t->name = 0; 202 t->hsize = HASHSIZE; /* no need to store---it's memory-only */ 203 t->h = (struct authlist **)malloc(t->hsize*sizeof (struct authlist *)); 204 if (!t->h) { 205 retval = KRB5_RC_MALLOC; 206 goto cleanup; 207 } 208 memset(t->h, 0, t->hsize*sizeof (struct authlist *)); 209 return (0); 210 211 cleanup: 212 if (t) { 213 if (t->name) 214 krb5_xfree(t->name); 215 if (t->h) 216 krb5_xfree(t->h); 217 krb5_xfree(t); 218 id->data = NULL; 219 } 220 return (retval); 221 } 222 223 krb5_error_code KRB5_CALLCONV 224 krb5_rc_mem_recover(krb5_context context, krb5_rcache id) 225 { 226 /* SUNW14resync - No need for locking here, just returning RC_NOIO */ 227 return (KRB5_RC_NOIO); 228 } 229 230 krb5_error_code KRB5_CALLCONV 231 krb5_rc_mem_recover_or_init(krb5_context context, krb5_rcache id, 232 krb5_deltat lifespan) 233 { 234 krb5_error_code retval; 235 236 retval = k5_mutex_lock(&id->lock); 237 if (retval) 238 return retval; 239 retval = krb5_rc_mem_recover(context, id); 240 if (retval) 241 retval = krb5_rc_mem_init_locked(context, id, lifespan); 242 k5_mutex_unlock(&id->lock); 243 return retval; 244 } 245 246 krb5_error_code KRB5_CALLCONV 247 krb5_rc_mem_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep) 248 { 249 krb5_error_code ret; 250 251 ret = k5_mutex_lock(&id->lock); 252 if (ret) 253 return (ret); 254 255 switch (rc_store(context, id, rep)) { 256 case CMP_MALLOC: 257 k5_mutex_unlock(&id->lock); 258 return (KRB5_RC_MALLOC); 259 case CMP_REPLAY: 260 k5_mutex_unlock(&id->lock); 261 return (KRB5KRB_AP_ERR_REPEAT); 262 case CMP_EXPIRED: 263 k5_mutex_unlock(&id->lock); 264 return (KRB5KRB_AP_ERR_SKEW); 265 case CMP_HOHUM: 266 break; 267 } 268 269 k5_mutex_unlock(&id->lock); 270 return (0); 271 } 272