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