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 gidtbl = 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;
183 dbg_log (_("grp_add_cache (%s)"), grp->gr_name);
185 work = &grptbl[hash];
187 if (grptbl[hash].grp == NULL)
188 grptbl[hash].grp = save_grp (grp);
191 while (work->next != NULL)
194 work->next = calloc (1, sizeof (grphash));
195 work->next->grp = save_grp (grp);
199 time (&work->create);
200 gidtbl[grp->gr_gid % modulo].grptr = work;
205 static struct group *
206 cache_search_name (const char *name)
209 unsigned long int hash = __nis_hash (name, strlen(name)) % modulo;
211 work = &grptbl[hash];
213 while (work->grp != NULL)
215 if (strcmp (work->grp->gr_name, name) == 0)
217 if (work->next != NULL)
225 static struct group *
226 cache_search_gid (gid_t gid)
230 work = &gidtbl[gid % modulo];
232 while (work->grptr != NULL)
234 if (work->grptr->grp->gr_gid == gid)
235 return work->grptr->grp;
236 if (work->next != NULL)
245 add_negcache (char *key)
248 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
251 dbg_log (_("grp_add_netgache (%s|%ld)"), key, hash);
253 work = &negtbl[hash];
255 if (negtbl[hash].key == NULL)
257 negtbl[hash].key = strdup (key);
258 negtbl[hash].next = NULL;
262 while (work->next != NULL)
265 work->next = calloc (1, sizeof (neghash));
266 work->next->key = strdup (key);
270 time (&work->create);
275 cache_search_neg (const char *key)
278 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
281 dbg_log (_("grp_cache_search_neg (%s|%ld)"), key, hash);
283 work = &negtbl[hash];
285 while (work->key != NULL)
287 if (strcmp (work->key, key) == 0)
289 if (work->next != NULL)
298 cache_getgrnam (void *v_param)
300 param_t *param = (param_t *)v_param;
303 pthread_rwlock_rdlock (&grplock);
304 grp = cache_search_name (param->key);
306 /* I don't like it to hold the read only lock longer, but it is
307 necessary to avoid to much malloc/free/strcpy. */
312 dbg_log (_("Found \"%s\" in cache !"), param->key);
315 gr_send_answer (param->conn, grp);
316 close_socket (param->conn);
318 pthread_rwlock_unlock (&grplock);
324 char *buffer = calloc (1, buflen);
325 struct group resultbuf;
328 dbg_log (_("Doesn't found \"%s\" in cache !"), param->key);
330 pthread_rwlock_unlock (&grplock);
332 pthread_rwlock_rdlock (&neglock);
333 status = cache_search_neg (param->key);
334 pthread_rwlock_unlock (&neglock);
338 while (buffer != NULL
339 && (getgrnam_r (param->key, &resultbuf, buffer, buflen, &grp)
345 buffer = realloc (buffer, buflen);
348 if (buffer != NULL && grp != NULL)
353 pthread_rwlock_wrlock (&grplock);
354 /* While we are waiting on the lock, somebody else could
356 tmp = cache_search_name (param->key);
359 pthread_rwlock_unlock (&grplock);
363 pthread_rwlock_wrlock (&neglock);
364 add_negcache (param->key);
366 pthread_rwlock_unlock (&neglock);
372 gr_send_answer (param->conn, grp);
373 close_socket (param->conn);
383 cache_gr_disabled (void *v_param)
385 param_t *param = (param_t *)v_param;
388 dbg_log (_("\tgroup cache is disabled\n"));
390 gr_send_disabled (param->conn);
395 cache_getgrgid (void *v_param)
397 param_t *param = (param_t *)v_param;
398 struct group *grp, resultbuf;
399 gid_t gid = strtol (param->key, NULL, 10);
401 pthread_rwlock_rdlock (&grplock);
402 grp = cache_search_gid (gid);
404 /* I don't like it to hold the read only lock longer, but it is
405 necessary to avoid to much malloc/free/strcpy. */
410 dbg_log (_("Found \"%d\" in cache !"), gid);
413 gr_send_answer (param->conn, grp);
414 close_socket (param->conn);
416 pthread_rwlock_unlock (&grplock);
421 char *buffer = malloc (buflen);
425 dbg_log (_("Doesn't found \"%d\" in cache !"), gid);
427 pthread_rwlock_unlock (&grplock);
429 pthread_rwlock_rdlock (&neglock);
430 status = cache_search_neg (param->key);
431 pthread_rwlock_unlock (&neglock);
435 while (buffer != NULL
436 && (getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0)
441 buffer = realloc (buffer, buflen);
444 if (buffer != NULL && grp != NULL)
449 pthread_rwlock_wrlock (&grplock);
450 /* While we are waiting on the lock, somebody else could
452 tmp = cache_search_gid (gid);
455 pthread_rwlock_unlock (&grplock);
460 pthread_rwlock_wrlock (&neglock);
461 add_negcache (param->key);
462 pthread_rwlock_unlock (&neglock);
468 gr_send_answer (param->conn, grp);
469 close_socket (param->conn);
479 grptable_update (void *v)
489 dbg_log (_("(grptable_update) Wait for write lock!"));
491 pthread_rwlock_wrlock (&grplock);
494 dbg_log (_("(grptable_update) Have write lock"));
497 for (i = 0; i < modulo; ++i)
499 grphash *work = &grptbl[i];
501 while (work && work->grp)
503 if ((now - work->create) >= postimeout)
505 gidhash *uh = &gidtbl[work->grp->gr_gid % modulo];
508 dbg_log (_("Give \"%s\" free"), work->grp->gr_name);
510 while (uh && uh->grptr)
512 if (uh->grptr->grp->gr_gid == work->grp->gr_gid)
515 dbg_log (_("Give gid for \"%s\" free"),
517 if (uh->next != NULL)
519 gidhash *tmp = uh->next;
520 uh->grptr = tmp->grptr;
521 uh->next = tmp->next;
530 free_grp (work->grp);
531 if (work->next != NULL)
533 grphash *tmp = work->next;
534 work->create = tmp->create;
535 work->next = tmp->next;
536 work->grp = tmp->grp;
546 dbg_log (_("(pwdtable_update) Release wait lock\n"));
547 pthread_rwlock_unlock (&grplock);
554 negtable_update (void *v)
564 dbg_log (_("(negtable_update) Wait for write lock!"));
566 pthread_rwlock_wrlock (&neglock);
569 dbg_log (_("(negtable_update) Have write lock"));
572 for (i = 0; i < modulo; ++i)
574 neghash *work = &negtbl[i];
576 while (work && work->key)
578 if ((now - work->create) >= negtimeout)
581 dbg_log (_("Give \"%s\" free"), work->key);
585 if (work->next != NULL)
587 neghash *tmp = work->next;
588 work->create = tmp->create;
589 work->next = tmp->next;
590 work->key = tmp->key;
600 dbg_log (_("(negtable_update) Release wait lock"));
601 pthread_rwlock_unlock (&neglock);