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
);