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. */
25 #include <rpcsvc/nis.h>
26 #include <sys/types.h>
31 static unsigned long modulo = 211;
32 static unsigned long postimeout = 3600;
33 static unsigned long negtimeout = 60;
35 static unsigned long poshit = 0;
36 static unsigned long posmiss = 0;
37 static unsigned long neghit = 0;
38 static unsigned long negmiss = 0;
46 typedef struct grphash grphash;
51 struct grphash *grptr;
53 typedef struct gidhash gidhash;
61 typedef struct neghash neghash;
63 static grphash *grptbl;
64 static gidhash *gidtbl;
65 static neghash *negtbl;
67 static pthread_rwlock_t grplock = PTHREAD_RWLOCK_INITIALIZER;
68 static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER;
70 static void *grptable_update (void *);
71 static void *negtable_update (void *);
74 get_gr_stat (stat_response_header *stat)
76 stat->gr_poshit = poshit;
77 stat->gr_posmiss = posmiss;
78 stat->gr_neghit = neghit;
79 stat->gr_negmiss = negmiss;
80 stat->gr_size = modulo;
81 stat->gr_posttl = postimeout;
82 stat->gr_negttl = negtimeout;
86 set_grp_modulo (unsigned long mod)
92 set_pos_grp_ttl (unsigned long ttl)
98 set_neg_grp_ttl (unsigned long ttl)
109 grptbl = calloc (modulo, sizeof (grphash));
112 calloc (modulo, sizeof (grphash));
115 negtbl = calloc (modulo, sizeof (neghash));
119 pthread_attr_init (&attr);
120 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
122 pthread_create (&thread, NULL, grptable_update, &attr);
123 pthread_create (&thread, NULL, negtable_update, &attr);
125 pthread_attr_destroy (&attr);
130 static struct group *
131 save_grp (struct group *src)
136 dest = calloc (1, sizeof (struct group));
137 dest->gr_name = strdup (src->gr_name);
138 dest->gr_passwd = strdup (src->gr_passwd);
139 dest->gr_gid = src->gr_gid;
141 /* How many members does this group have? */
143 while (src->gr_mem[l])
146 dest->gr_mem = calloc (1, sizeof (char *) * (l+1));
148 while (src->gr_mem[l])
150 dest->gr_mem[l] = strdup (src->gr_mem[l]);
158 free_grp (struct group *src)
163 free (src->gr_passwd);
166 while (src->gr_mem[l])
168 free (src->gr_mem[l]);
176 add_cache (struct group *grp)
179 unsigned long int hash = __nis_hash (grp->gr_name,
180 strlen (grp->gr_name)) % modulo;
182 work = &grptbl[hash];
184 if (grptbl[hash].grp == NULL)
185 grptbl[hash].grp = save_grp (grp);
188 while (work->next != NULL)
191 work->next = calloc (1, sizeof (grphash));
192 work->next->grp = save_grp (grp);
196 time (&work->create);
197 gidtbl[grp->gr_gid % modulo].grptr = work;
202 static struct group *
203 cache_search_name (const char *name)
206 unsigned long int hash = __nis_hash (name, strlen(name)) % modulo;
208 work = &grptbl[hash];
210 while (work->grp != NULL)
212 if (strcmp (work->grp->gr_name, name) == 0)
214 if (work->next != NULL)
222 static struct group *
223 cache_search_gid (gid_t gid)
227 work = &gidtbl[gid % modulo];
229 while (work->grptr != NULL)
231 if (work->grptr->grp->gr_gid == gid)
232 return work->grptr->grp;
233 if (work->next != NULL)
242 add_negcache (char *key)
245 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
247 work = &negtbl[hash];
249 if (negtbl[hash].key == NULL)
250 negtbl[hash].key = strdup (key);
253 while (work->next != NULL)
256 work->next = calloc (1, sizeof (neghash));
257 work->next->key = strdup (key);
261 time (&work->create);
266 cache_search_neg (const char *key)
269 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
271 work = &negtbl[hash];
273 while (work->key != NULL)
275 if (strcmp (work->key, key) == 0)
277 if (work->next != NULL)
286 cache_getgrnam (void *v_param)
288 param_t *param = (param_t *)v_param;
289 struct group *grp, resultbuf;
291 pthread_rwlock_rdlock (&grplock);
292 grp = cache_search_name (param->key);
294 /* I don't like it to hold the read only lock longer, but it is
295 necessary to avoid to much malloc/free/strcpy. */
300 dbg_log (_("Found \"%s\" in cache !"), param->key);
303 gr_send_answer (param->conn, grp);
304 close_socket (param->conn);
306 pthread_rwlock_unlock (&grplock);
311 char *buffer = calloc (1, buflen);
315 dbg_log (_("Doesn't found \"%s\" in cache !"), param->key);
317 pthread_rwlock_unlock (&grplock);
319 pthread_rwlock_rdlock (&neglock);
320 status = cache_search_neg (param->key);
321 pthread_rwlock_unlock (&neglock);
325 while (buffer != NULL
326 && (getgrnam_r (param->key, &resultbuf, buffer, buflen, &grp)
332 buffer = realloc (buffer, buflen);
335 if (buffer != NULL && grp != NULL)
340 pthread_rwlock_wrlock (&grplock);
341 /* While we are waiting on the lock, somebody else could
343 tmp = cache_search_name (param->key);
346 pthread_rwlock_unlock (&grplock);
350 pthread_rwlock_wrlock (&neglock);
351 add_negcache (param->key);
353 pthread_rwlock_unlock (&neglock);
359 gr_send_answer (param->conn, grp);
360 close_socket (param->conn);
370 cache_gr_disabled (void *v_param)
372 param_t *param = (param_t *)v_param;
374 gr_send_disabled (param->conn);
379 cache_getgrgid (void *v_param)
381 param_t *param = (param_t *)v_param;
382 struct group *grp, resultbuf;
383 gid_t gid = strtol (param->key, NULL, 10);
385 pthread_rwlock_rdlock (&grplock);
386 grp = cache_search_gid (gid);
388 /* I don't like it to hold the read only lock longer, but it is
389 necessary to avoid to much malloc/free/strcpy. */
394 dbg_log (_("Found \"%d\" in cache !\n"), gid);
397 gr_send_answer (param->conn, grp);
398 close_socket (param->conn);
400 pthread_rwlock_unlock (&grplock);
405 char *buffer = malloc (buflen);
409 dbg_log (_("Doesn't found \"%d\" in cache !\n"), gid);
411 pthread_rwlock_unlock (&grplock);
413 pthread_rwlock_rdlock (&neglock);
414 status = cache_search_neg (param->key);
415 pthread_rwlock_unlock (&neglock);
419 while (buffer != NULL
420 && (getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0)
425 buffer = realloc (buffer, buflen);
428 if (buffer != NULL && grp != NULL)
433 pthread_rwlock_wrlock (&grplock);
434 /* While we are waiting on the lock, somebody else could
436 tmp = cache_search_gid (gid);
439 pthread_rwlock_unlock (&grplock);
444 pthread_rwlock_wrlock (&neglock);
445 add_negcache (param->key);
446 pthread_rwlock_unlock (&neglock);
452 gr_send_answer (param->conn, grp);
453 close_socket (param->conn);
463 grptable_update (void *v)
473 dbg_log (_("(grptable_update) Wait for write lock!"));
475 pthread_rwlock_wrlock (&grplock);
478 dbg_log (_("(grptable_update) Have write lock"));
481 for (i = 0; i < modulo; ++i)
483 grphash *work = &grptbl[i];
485 while (work && work->grp)
487 if ((now - work->create) >= postimeout)
489 gidhash *uh = &gidtbl[work->grp->gr_gid % modulo];
492 dbg_log (_("Give \"%s\" free"), work->grp->gr_name);
494 while (uh && uh->grptr)
496 if (uh->grptr->grp->gr_gid == work->grp->gr_gid)
499 dbg_log (_("Give gid for \"%s\" free"),
501 if (uh->next != NULL)
503 gidhash *tmp = uh->next;
504 uh->grptr = tmp->grptr;
505 uh->next = tmp->next;
514 free_grp (work->grp);
515 if (work->next != NULL)
517 grphash *tmp = work->next;
518 work->create = tmp->create;
519 work->next = tmp->next;
520 work->grp = tmp->grp;
530 dbg_log (_("(pwdtable_update) Release wait lock\n"));
531 pthread_rwlock_unlock (&grplock);
538 negtable_update (void *v)
548 dbg_log (_("(negtable_update) Wait for write lock!"));
550 pthread_rwlock_wrlock (&neglock);
553 dbg_log (_("(negtable_update) Have write lock"));
556 for (i = 0; i < modulo; ++i)
558 neghash *work = &negtbl[i];
560 while (work && work->key)
562 if ((now - work->create) >= negtimeout)
565 dbg_log (_("Give \"%s\" free"), work->key);
569 if (work->next != NULL)
571 neghash *tmp = work->next;
572 work->create = tmp->create;
573 work->next = tmp->next;
574 work->key = tmp->key;
584 dbg_log (_("(negtable_update) Release wait lock"));
585 pthread_rwlock_unlock (&neglock);