1 /* Copyright (c) 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
26 #include <rpcsvc/nis.h>
27 #include <sys/types.h>
32 static unsigned long modulo = 211;
33 static unsigned long postimeout = 3600;
34 static unsigned long negtimeout = 60;
36 static unsigned long poshit = 0;
37 static unsigned long posmiss = 0;
38 static unsigned long neghit = 0;
39 static unsigned long negmiss = 0;
47 typedef struct grphash grphash;
54 typedef struct gidhash gidhash;
62 typedef struct neghash neghash;
64 static grphash *grptbl;
65 static gidhash *gidtbl;
66 static neghash *negtbl;
68 static pthread_rwlock_t grplock = PTHREAD_RWLOCK_INITIALIZER;
69 static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER;
71 static void *grptable_update (void *);
72 static void *negtable_update (void *);
75 get_gr_stat (stat_response_header *stat)
77 stat->gr_poshit = poshit;
78 stat->gr_posmiss = posmiss;
79 stat->gr_neghit = neghit;
80 stat->gr_negmiss = negmiss;
81 stat->gr_size = modulo;
82 stat->gr_posttl = postimeout;
83 stat->gr_negttl = negtimeout;
87 set_grp_modulo (unsigned long mod)
93 set_pos_grp_ttl (unsigned long ttl)
99 set_neg_grp_ttl (unsigned long ttl)
110 grptbl = calloc (modulo, sizeof (grphash));
113 gidtbl = calloc (modulo, sizeof (grphash));
116 negtbl = calloc (modulo, sizeof (neghash));
120 pthread_attr_init (&attr);
121 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
123 pthread_create (&thread, NULL, grptable_update, &attr);
124 pthread_create (&thread, NULL, negtable_update, &attr);
126 pthread_attr_destroy (&attr);
131 static struct group *
132 save_grp (struct group *src)
137 dest = calloc (1, sizeof (struct group));
138 dest->gr_name = strdup (src->gr_name);
139 dest->gr_passwd = strdup (src->gr_passwd);
140 dest->gr_gid = src->gr_gid;
142 /* How many members does this group have? */
144 while (src->gr_mem[l])
147 dest->gr_mem = calloc (1, sizeof (char *) * (l+1));
149 while (src->gr_mem[l])
151 dest->gr_mem[l] = strdup (src->gr_mem[l]);
159 free_grp (struct group *src)
164 free (src->gr_passwd);
167 while (src->gr_mem[l])
169 free (src->gr_mem[l]);
177 add_cache (struct group *grp)
181 unsigned long int hash = __nis_hash (grp->gr_name,
182 strlen (grp->gr_name)) % modulo;
185 dbg_log (_("grp_add_cache (%s)"), grp->gr_name);
187 work = &grptbl[hash];
189 if (grptbl[hash].grp == NULL)
190 grptbl[hash].grp = save_grp (grp);
193 while (work->next != NULL)
196 work->next = calloc (1, sizeof (grphash));
197 work->next->grp = save_grp (grp);
201 time (&work->create);
202 gidwork = &gidtbl[grp->gr_gid % modulo];
203 if (gidwork->grptr == NULL)
204 gidwork->grptr = work->grp;
207 while (gidwork->next != NULL)
208 gidwork = gidwork->next;
210 gidwork->next = calloc (1, sizeof (gidhash));
211 gidwork->next->grptr = work->grp;
217 static struct group *
218 cache_search_name (const char *name)
221 unsigned long int hash = __nis_hash (name, strlen(name)) % modulo;
223 work = &grptbl[hash];
225 while (work->grp != NULL)
227 if (strcmp (work->grp->gr_name, name) == 0)
229 if (work->next != NULL)
237 static struct group *
238 cache_search_gid (gid_t gid)
242 work = &gidtbl[gid % modulo];
244 while (work->grptr != NULL)
246 if (work->grptr->gr_gid == gid)
248 if (work->next != NULL)
257 add_negcache (char *key)
260 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
263 dbg_log (_("grp_add_netgache (%s|%ld)"), key, hash);
265 work = &negtbl[hash];
267 if (negtbl[hash].key == NULL)
269 negtbl[hash].key = strdup (key);
270 negtbl[hash].next = NULL;
274 while (work->next != NULL)
277 work->next = calloc (1, sizeof (neghash));
278 work->next->key = strdup (key);
282 time (&work->create);
287 cache_search_neg (const char *key)
290 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
293 dbg_log (_("grp_cache_search_neg (%s|%ld)"), key, hash);
295 work = &negtbl[hash];
297 while (work->key != NULL)
299 if (strcmp (work->key, key) == 0)
301 if (work->next != NULL)
310 cache_getgrnam (void *v_param)
312 param_t *param = (param_t *)v_param;
315 pthread_rwlock_rdlock (&grplock);
316 grp = cache_search_name (param->key);
318 /* I don't like it to hold the read only lock longer, but it is
319 necessary to avoid to much malloc/free/strcpy. */
324 dbg_log (_("Found \"%s\" in cache !"), param->key);
327 gr_send_answer (param->conn, grp);
328 close_socket (param->conn);
330 pthread_rwlock_unlock (&grplock);
336 char *buffer = calloc (1, buflen);
337 struct group resultbuf;
340 dbg_log (_("Doesn't found \"%s\" in cache !"), param->key);
342 pthread_rwlock_unlock (&grplock);
344 pthread_rwlock_rdlock (&neglock);
345 status = cache_search_neg (param->key);
346 pthread_rwlock_unlock (&neglock);
350 while (buffer != NULL
351 && (getgrnam_r (param->key, &resultbuf, buffer, buflen, &grp)
357 buffer = realloc (buffer, buflen);
360 if (buffer != NULL && grp != NULL)
365 pthread_rwlock_wrlock (&grplock);
366 /* While we are waiting on the lock, somebody else could
368 tmp = cache_search_name (param->key);
371 pthread_rwlock_unlock (&grplock);
375 pthread_rwlock_wrlock (&neglock);
376 add_negcache (param->key);
378 pthread_rwlock_unlock (&neglock);
384 gr_send_answer (param->conn, grp);
385 close_socket (param->conn);
395 cache_gr_disabled (void *v_param)
397 param_t *param = (param_t *)v_param;
400 dbg_log (_("\tgroup cache is disabled\n"));
402 gr_send_disabled (param->conn);
407 cache_getgrgid (void *v_param)
409 param_t *param = (param_t *)v_param;
410 struct group *grp, resultbuf;
411 gid_t gid = strtol (param->key, NULL, 10);
413 pthread_rwlock_rdlock (&grplock);
414 grp = cache_search_gid (gid);
416 /* I don't like it to hold the read only lock longer, but it is
417 necessary to avoid to much malloc/free/strcpy. */
422 dbg_log (_("Found \"%d\" in cache !"), gid);
425 gr_send_answer (param->conn, grp);
426 close_socket (param->conn);
428 pthread_rwlock_unlock (&grplock);
433 char *buffer = malloc (buflen);
437 dbg_log (_("Doesn't found \"%d\" in cache !"), gid);
439 pthread_rwlock_unlock (&grplock);
441 pthread_rwlock_rdlock (&neglock);
442 status = cache_search_neg (param->key);
443 pthread_rwlock_unlock (&neglock);
447 while (buffer != NULL
448 && (getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0)
453 buffer = realloc (buffer, buflen);
456 if (buffer != NULL && grp != NULL)
461 pthread_rwlock_wrlock (&grplock);
462 /* While we are waiting on the lock, somebody else could
464 tmp = cache_search_gid (gid);
467 pthread_rwlock_unlock (&grplock);
472 pthread_rwlock_wrlock (&neglock);
473 add_negcache (param->key);
474 pthread_rwlock_unlock (&neglock);
480 gr_send_answer (param->conn, grp);
481 close_socket (param->conn);
491 grptable_update (void *v)
501 dbg_log (_("(grptable_update) Wait for write lock!"));
503 pthread_rwlock_wrlock (&grplock);
506 dbg_log (_("(grptable_update) Have write lock"));
509 for (i = 0; i < modulo; ++i)
511 grphash *work = &grptbl[i];
513 while (work && work->grp)
515 if ((now - work->create) >= postimeout)
517 gidhash *uh = &gidtbl[work->grp->gr_gid % modulo];
520 dbg_log (_("Give \"%s\" free"), work->grp->gr_name);
522 while (uh && uh->grptr)
524 if (uh->grptr->gr_gid == work->grp->gr_gid)
527 dbg_log (_("Give gid for \"%s\" free"),
529 if (uh->next != NULL)
531 gidhash *tmp = uh->next;
532 uh->grptr = tmp->grptr;
533 uh->next = tmp->next;
542 free_grp (work->grp);
543 if (work->next != NULL)
545 grphash *tmp = work->next;
546 work->create = tmp->create;
547 work->next = tmp->next;
548 work->grp = tmp->grp;
558 dbg_log (_("(grptable_update) Release wait lock"));
559 pthread_rwlock_unlock (&grplock);
566 negtable_update (void *v)
576 dbg_log (_("(neggrptable_update) Wait for write lock!"));
578 pthread_rwlock_wrlock (&neglock);
581 dbg_log (_("(neggrptable_update) Have write lock"));
584 for (i = 0; i < modulo; ++i)
586 neghash *work = &negtbl[i];
588 while (work && work->key)
590 if ((now - work->create) >= negtimeout)
593 dbg_log (_("Give \"%s\" free"), work->key);
597 if (work->next != NULL)
599 neghash *tmp = work->next;
600 work->create = tmp->create;
601 work->next = tmp->next;
602 work->key = tmp->key;
612 dbg_log (_("(neggrptable_update) Release wait lock"));
613 pthread_rwlock_unlock (&neglock);