*** empty log message ***
[arla.git] / arlad / cred.c
blobf396528e4ac629e61431c789b4aea3f33ca5afcc
1 /*
2 * Copyright (c) 1995 - 2002, 2005 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.
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.
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.
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.
35 * Cache of credentials
37 * Each 'cred,type' pair is collected on a list where the head is in
38 * the cell CRED_ROOT_CELL. This is to enable fast iterations over
39 * all creds for a user (indexed on cred,type).
42 #include "arla_local.h"
43 RCSID("$Id$");
45 #define CRED_ROOT_CELL (-1)
47 #define CREDCACHESIZE 101
49 #define CREDFREEINC 10
51 /* a hashtable of all credentials */
52 static Hashtab *credhtab;
54 /* list of all free entries */
55 static List *freelist;
57 /* # of credentials */
58 static unsigned ncredentials;
60 /* # of active credentials */
61 static unsigned nactive_credentials;
63 static void root_free(CredCacheEntry *);
66 * Functions for handling entries into the credentials cache.
69 static int
70 credcmp (void *a, void *b)
72 CredCacheEntry *c1 = (CredCacheEntry*)a;
73 CredCacheEntry *c2 = (CredCacheEntry*)b;
75 return c1->cred != c2->cred
76 || c1->type != c2->type
77 || c1->cell != c2->cell;
80 static unsigned
81 credhash (void *a)
83 CredCacheEntry *c = (CredCacheEntry*)a;
85 return c->cred + c->type + c->cell;
90 * Create `n' credentials and add them to `freelist'
93 static void
94 create_new_credentials (unsigned n)
96 unsigned i;
97 CredCacheEntry *entries;
99 entries = (CredCacheEntry*)calloc (n, sizeof (CredCacheEntry));
100 if (entries == NULL)
101 arla_errx (1, ADEBERROR, "credcache: calloc failed");
102 for (i = 0; i < n; ++i) {
103 entries[i].cred_data = NULL;
104 listaddhead (freelist, &entries[i]);
106 ncredentials += n;
110 * Initialize the cred cache.
113 void
114 cred_init (unsigned nentries)
116 credhtab = hashtabnew (CREDCACHESIZE, credcmp, credhash);
117 if (credhtab == NULL)
118 arla_errx (1, ADEBERROR, "cred_init: hashtabnew failed");
119 freelist = listnew ();
120 if (freelist == NULL)
121 arla_errx (1, ADEBERROR, "cred_init: listnew failed");
122 ncredentials = 0;
123 create_new_credentials (nentries);
126 static CredCacheEntry *
127 internal_get (long cell, nnpfs_pag_t cred, int type)
129 CredCacheEntry *e;
130 CredCacheEntry key;
132 if (cell == CRED_ROOT_CELL)
133 return NULL;
135 key.cell = cell;
136 key.type = type;
137 key.cred = cred;
139 e = (CredCacheEntry *)hashtabsearch (credhtab, (void *)&key);
141 if (e == NULL && type == CRED_NONE) {
142 e = cred_add (cred, type, 0, cell, 0, NULL, 0, 0);
145 if (e != NULL) {
146 ++e->refcount;
147 assert(e->cell != CRED_ROOT_CELL);
150 return e;
153 struct list_pag {
154 int (*func)(CredCacheEntry *, void *);
155 void *arg;
158 static Bool
159 list_pag_func(List *l, Listitem *li, void *arg)
161 CredCacheEntry *e = listdata(li);
162 struct list_pag *d = arg;
164 return (d->func)(e, d->arg);
168 cred_list_pag(nnpfs_pag_t cred, int type,
169 int (*func)(CredCacheEntry *, void *),
170 void *ptr)
172 CredCacheEntry key, *root_e;
173 struct list_pag d;
175 key.cell = CRED_ROOT_CELL;
176 key.type = type;
177 key.cred = cred;
179 root_e = (CredCacheEntry *)hashtabsearch (credhtab, (void *)&key);
180 if (root_e == NULL)
181 return 0;
183 d.func = func;
184 d.arg = ptr;
186 listiter(root_e->pag.list, list_pag_func, &d);
188 return 0;
191 CredCacheEntry *
192 cred_get (long cell, nnpfs_pag_t cred, int type)
194 if (type == CRED_ANY) {
195 CredCacheEntry *e;
196 int i;
198 for (i = CRED_MAX; i > CRED_NONE; --i) {
199 e = internal_get (cell, cred, i);
200 if (e != NULL)
201 return e;
204 return internal_get (cell, cred, CRED_NONE);
205 } else
206 return internal_get (cell, cred, type);
209 static void
210 recycle_entry (CredCacheEntry *ce)
212 assert(ce->refcount == 0);
214 if (ce->cell != CRED_ROOT_CELL)
215 root_free(ce);
216 if (!ce->flags.killme)
217 hashtabdel (credhtab, ce);
218 if (ce->cred_data != NULL)
219 free (ce->cred_data);
220 memset (ce, 0, sizeof(*ce));
221 listaddhead (freelist, ce);
222 --nactive_credentials;
225 void
226 cred_free (CredCacheEntry *ce)
228 if(ce == NULL)
229 return;
230 assert (ce->cell != CRED_ROOT_CELL);
232 --ce->refcount;
233 if (ce->flags.killme && ce->refcount == 0)
234 recycle_entry (ce);
237 static CredCacheEntry *
238 get_free_cred (void)
240 CredCacheEntry *e;
242 e = (CredCacheEntry *)listdelhead (freelist);
243 if (e != NULL)
244 return e;
246 create_new_credentials (CREDFREEINC);
248 e = (CredCacheEntry *)listdelhead (freelist);
249 if (e != NULL)
250 return e;
252 arla_errx (1, ADEBERROR,
253 "credcache: there was no way of getting a cred");
256 static void
257 root_free(CredCacheEntry *e)
259 CredCacheEntry key, *root_e;
261 assert(e->cell != CRED_ROOT_CELL);
263 if (e->pag.li == NULL)
264 return;
266 key.cell = CRED_ROOT_CELL;
267 key.type = e->type;
268 key.cred = e->cred;
270 root_e = (CredCacheEntry *)hashtabsearch (credhtab, (void *)&key);
271 assert(root_e);
273 listdel(root_e->pag.list, e->pag.li);
274 e->pag.li = NULL;
276 if (listemptyp(root_e->pag.list)) {
277 listfree(root_e->pag.list);
278 root_e->pag.list = NULL;
279 recycle_entry(root_e);
283 static void
284 add_to_root_entry(CredCacheEntry *e)
286 CredCacheEntry key, *root_e;
288 assert(e->cell != CRED_ROOT_CELL);
290 key.cell = CRED_ROOT_CELL;
291 key.type = e->type;
292 key.cred = e->cred;
294 root_e = (CredCacheEntry *)hashtabsearch (credhtab, (void *)&key);
295 if (root_e == NULL) {
296 root_e = get_free_cred ();
298 root_e->cell = CRED_ROOT_CELL;
299 root_e->type = e->type;
300 root_e->cred = e->cred;
301 root_e->securityindex = -1;
302 root_e->expire = 0;
303 root_e->cred_data = NULL;
304 root_e->uid = e->uid;
305 root_e->pag.list = listnew();
306 if (root_e->pag.list == NULL)
307 arla_errx (1, ADEBERROR, "add_to_root_entry: out of memory");
309 hashtabadd(credhtab, root_e);
311 ++nactive_credentials;
313 e->pag.li = listaddhead (root_e->pag.list, e);
316 CredCacheEntry *
317 cred_add (nnpfs_pag_t cred, int type, int securityindex, long cell,
318 time_t expire, void *cred_data, size_t cred_data_sz,
319 uid_t uid)
321 void *data;
322 CredCacheEntry *e;
323 CredCacheEntry *old;
325 if (cred_data != NULL) {
326 data = malloc (cred_data_sz);
327 if (data == NULL)
328 return NULL;
329 memcpy (data, cred_data, cred_data_sz);
330 } else
331 data = NULL;
333 e = get_free_cred ();
335 e->cred = cred;
336 e->type = type;
337 e->securityindex = securityindex;
338 e->cell = cell;
339 e->expire = expire;
340 e->cred_data = data;
341 e->uid = uid;
342 e->pag.li = NULL;
344 add_to_root_entry(e);
346 old = (CredCacheEntry *)hashtabsearch (credhtab, (void *)e);
347 if (old != NULL)
348 cred_delete (old);
350 hashtabadd (credhtab, e);
352 ++nactive_credentials;
354 return e;
361 void
362 cred_delete (CredCacheEntry *ce)
364 assert(ce->cell != CRED_ROOT_CELL);
366 if (ce->refcount > 0) {
367 ce->flags.killme = 1;
368 hashtabdel (credhtab, ce);
369 root_free(ce);
370 } else
371 recycle_entry (ce);
378 void
379 cred_expire (CredCacheEntry *ce)
381 const char *cell_name = cell_num2name (ce->cell);
383 if (cell_name != NULL)
384 arla_warnx (ADEBWARN,
385 "Credentials for UID %u in cell %s have expired",
386 (unsigned)ce->uid, cell_name);
387 else
388 arla_warnx (ADEBWARN,
389 "Credentials for UID %u in cell unknown %ld have expired",
390 (unsigned)ce->uid, ce->cell);
392 cred_delete (ce);
395 static Bool
396 remove_entry (void *ptr, void *arg)
398 CredCacheEntry *ce = (CredCacheEntry *)ptr;
399 nnpfs_pag_t *cred = (nnpfs_pag_t *)arg;
401 if (ce->cell == CRED_ROOT_CELL)
402 return FALSE;
404 if (ce->cred == *cred)
405 cred_delete (ce);
406 return FALSE;
409 void
410 cred_remove (nnpfs_pag_t cred)
412 hashtabforeach (credhtab, remove_entry, &cred);
415 static Bool
416 print_cred (void *ptr, void *arg)
418 CredCacheEntry *e = (CredCacheEntry *)ptr;
420 arla_log(ADEBVLOG, "cred = %u, type = %d, securityindex = %d, "
421 "cell = %ld, refcount = %u, killme = %d, uid = %lu",
422 e->cred, e->type, e->securityindex, e->cell, e->refcount,
423 e->flags.killme, (unsigned long)e->uid);
424 return FALSE;
427 void
428 cred_status (void)
430 arla_log(ADEBVLOG, "%u(%u) credentials",
431 nactive_credentials, ncredentials);
432 hashtabforeach (credhtab, print_cred, NULL);