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