* sysdeps/unix/sysv/linux/m68k/dl-librecon.h: New file.
[glibc.git] / nscd / pwdcache.c
blob721e77b7c9367d60a372cf0a5231bbc4cc9c54b8
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. */
20 #include <errno.h>
21 #include <malloc.h>
22 #include <pthread.h>
23 #include <pwd.h>
24 #include <string.h>
25 #include <rpcsvc/nis.h>
26 #include <sys/types.h>
28 #include "dbg_log.h"
29 #include "nscd.h"
31 static unsigned long int modulo = 211;
32 static unsigned long int postimeout = 600;
33 static unsigned long int negtimeout = 20;
35 static unsigned long int poshit = 0;
36 static unsigned long int posmiss = 0;
37 static unsigned long int neghit = 0;
38 static unsigned long int negmiss = 0;
40 struct pwdhash
42 time_t create;
43 struct pwdhash *next;
44 struct passwd *pwd;
46 typedef struct pwdhash pwdhash;
48 struct uidhash
50 struct uidhash *next;
51 struct pwdhash *pwptr;
53 typedef struct uidhash uidhash;
55 struct neghash
57 time_t create;
58 struct neghash *next;
59 char *key;
61 typedef struct neghash neghash;
63 static pwdhash *pwdtbl;
64 static uidhash *uidtbl;
65 static neghash *negtbl;
67 static pthread_rwlock_t pwdlock = PTHREAD_RWLOCK_INITIALIZER;
68 static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER;
70 static void *pwdtable_update (void *);
71 static void *negtable_update (void *);
73 void
74 get_pw_stat (stat_response_header *stat)
76 stat->pw_poshit = poshit;
77 stat->pw_posmiss = posmiss;
78 stat->pw_neghit = neghit;
79 stat->pw_negmiss = negmiss;
80 stat->pw_size = modulo;
81 stat->pw_posttl = postimeout;
82 stat->pw_negttl = negtimeout;
85 void
86 set_pwd_modulo (unsigned long int mod)
88 modulo = mod;
91 void
92 set_pos_pwd_ttl (unsigned long int ttl)
94 postimeout = ttl;
97 void
98 set_neg_pwd_ttl (unsigned long int ttl)
100 negtimeout = ttl;
104 cache_pwdinit ()
106 pthread_attr_t attr;
107 pthread_t thread;
109 pwdtbl = calloc (modulo, sizeof (pwdhash));
110 if (pwdtbl == NULL)
111 return -1;
112 uidtbl = calloc (modulo, sizeof (pwdhash));
113 if (uidtbl == NULL)
114 return -1;
115 negtbl = calloc (modulo, sizeof (neghash));
116 if (negtbl == NULL)
117 return -1;
119 pthread_attr_init (&attr);
120 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
122 pthread_create (&thread, NULL, pwdtable_update, &attr);
123 pthread_create (&thread, NULL, negtable_update, &attr);
125 pthread_attr_destroy (&attr);
127 return 0;
130 static struct passwd *
131 save_pwd (struct passwd *src)
133 struct passwd *dest;
135 dest = calloc (1, sizeof (struct passwd));
136 dest->pw_name = strdup (src->pw_name);
137 dest->pw_passwd = strdup (src->pw_passwd);
138 dest->pw_uid = src->pw_uid;
139 dest->pw_gid = src->pw_gid;
140 dest->pw_gecos = strdup (src->pw_gecos);
141 dest->pw_dir = strdup (src->pw_dir);
142 dest->pw_shell = strdup (src->pw_shell);
144 return dest;
147 static void
148 free_pwd (struct passwd *src)
150 free (src->pw_name);
151 free (src->pw_passwd);
152 free (src->pw_gecos);
153 free (src->pw_dir);
154 free (src->pw_shell);
155 free (src);
158 static int
159 add_cache (struct passwd *pwd)
161 pwdhash *work;
162 unsigned long int hash = __nis_hash (pwd->pw_name,
163 strlen (pwd->pw_name)) % modulo;
165 if (debug_flag)
166 dbg_log (_("pwd_add_cache (%s)"), pwd->pw_name);
168 work = &pwdtbl[hash];
170 if (pwdtbl[hash].pwd == NULL)
171 pwdtbl[hash].pwd = save_pwd (pwd);
172 else
174 while (work->next != NULL)
175 work = work->next;
177 work->next = calloc (1, sizeof (pwdhash));
178 work->next->pwd = save_pwd (pwd);
179 work = work->next;
181 /* Set a pointer from the pwuid hash table to the pwname hash table */
182 time (&work->create);
183 uidtbl[pwd->pw_uid % modulo].pwptr = work;
185 return 0;
188 static struct passwd *
189 cache_search_name (const char *name)
191 pwdhash *work;
192 unsigned long int hash = __nis_hash (name, strlen (name)) % modulo;
194 work = &pwdtbl[hash];
196 while (work->pwd != NULL)
198 if (strcmp (work->pwd->pw_name, name) == 0)
199 return work->pwd;
200 if (work->next != NULL)
201 work = work->next;
202 else
203 return NULL;
205 return NULL;
208 static struct passwd *
209 cache_search_uid (uid_t uid)
211 uidhash *work;
213 work = &uidtbl[uid % modulo];
215 while (work->pwptr != NULL)
217 if (work->pwptr->pwd->pw_uid == uid)
218 return work->pwptr->pwd;
219 if (work->next != NULL)
220 work = work->next;
221 else
222 return NULL;
224 return NULL;
227 static int
228 add_negcache (char *key)
230 neghash *work;
231 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
233 if (debug_flag)
234 dbg_log (_("pwd_add_netgache (%s|%ld)"), key, hash);
236 work = &negtbl[hash];
238 if (negtbl[hash].key == NULL)
240 negtbl[hash].key = strdup (key);
241 negtbl[hash].next = NULL;
243 else
245 while (work->next != NULL)
246 work = work->next;
248 work->next = calloc (1, sizeof (neghash));
249 work->next->key = strdup (key);
250 work = work->next;
253 time (&work->create);
255 return 0;
258 static int
259 cache_search_neg (const char *key)
261 neghash *work;
262 unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
264 if (debug_flag)
265 dbg_log (_("pwd_cache_search_neg (%s|%ld)"), key, hash);
267 work = &negtbl[hash];
269 while (work->key != NULL)
271 if (strcmp (work->key, key) == 0)
272 return 1;
273 if (work->next != NULL)
274 work = work->next;
275 else
276 return 0;
278 return 0;
281 void *
282 cache_getpwnam (void *v_param)
284 struct passwd *pwd;
285 param_t *param = (param_t *)v_param;
287 pthread_rwlock_rdlock (&pwdlock);
288 pwd = cache_search_name (param->key);
290 /* I don't like it to hold the read only lock longer, but it is
291 necessary to avoid to much malloc/free/strcpy. */
293 if (pwd != NULL)
295 if (debug_flag)
296 dbg_log (_("Found \"%s\" in cache !"), param->key);
298 ++poshit;
299 pw_send_answer (param->conn, pwd);
300 close_socket (param->conn);
302 pthread_rwlock_unlock (&pwdlock);
304 else
306 int status;
307 int buflen = 1024;
308 char *buffer = calloc (1, buflen);
309 struct passwd resultbuf;
311 if (debug_flag)
312 dbg_log (_("Doesn't found \"%s\" in cache !"), param->key);
314 pthread_rwlock_unlock (&pwdlock);
316 pthread_rwlock_rdlock (&neglock);
317 status = cache_search_neg (param->key);
318 pthread_rwlock_unlock (&neglock);
320 if (status == 0)
322 while (buffer != NULL
323 && (getpwnam_r (param->key, &resultbuf, buffer, buflen, &pwd)
324 != 0)
325 && errno == ERANGE)
327 errno = 0;
328 buflen += 1024;
329 buffer = realloc (buffer, buflen);
332 if (buffer != NULL && pwd != NULL)
334 struct passwd *tmp;
336 ++posmiss;
337 pthread_rwlock_wrlock (&pwdlock);
338 /* While we are waiting on the lock, somebody else could
339 add this entry. */
340 tmp = cache_search_name (param->key);
341 if (tmp == NULL)
342 add_cache (pwd);
343 pthread_rwlock_unlock (&pwdlock);
345 else
347 ++negmiss;
348 pthread_rwlock_wrlock (&neglock);
349 add_negcache (param->key);
350 pthread_rwlock_unlock (&neglock);
353 else
354 ++neghit;
355 pw_send_answer (param->conn, pwd);
356 close_socket (param->conn);
357 if (buffer != NULL)
358 free (buffer);
360 free (param->key);
361 free (param);
362 return NULL;
365 void *
366 cache_pw_disabled (void *v_param)
368 param_t *param = (param_t *)v_param;
370 if (debug_flag)
371 dbg_log (_("\tpasswd cache is disabled\n"));
373 pw_send_disabled (param->conn);
374 return NULL;
377 void *
378 cache_getpwuid (void *v_param)
380 param_t *param = (param_t *)v_param;
381 struct passwd *pwd, resultbuf;
382 uid_t uid = strtol (param->key, NULL, 10);
384 pthread_rwlock_rdlock (&pwdlock);
385 pwd = cache_search_uid (uid);
387 /* I don't like it to hold the read only lock longer, but it is
388 necessary to avoid to much malloc/free/strcpy. */
390 if (pwd != NULL)
392 if (debug_flag)
393 dbg_log (_("Found \"%d\" in cache !"), uid);
395 ++poshit;
396 pw_send_answer (param->conn, pwd);
397 close_socket (param->conn);
399 pthread_rwlock_unlock (&pwdlock);
401 else
403 int buflen = 1024;
404 char *buffer = malloc (buflen);
405 int status;
407 if (debug_flag)
408 dbg_log (_("Doesn't found \"%d\" in cache !"), uid);
410 pthread_rwlock_unlock (&pwdlock);
412 pthread_rwlock_rdlock (&neglock);
413 status = cache_search_neg (param->key);
414 pthread_rwlock_unlock (&neglock);
416 if (status == 0)
418 while (buffer != NULL
419 && (getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0)
420 && errno == ERANGE)
422 errno = 0;
423 buflen += 1024;
424 buffer = realloc (buffer, buflen);
427 if (buffer != NULL && pwd != NULL)
429 struct passwd *tmp;
431 ++posmiss;
432 pthread_rwlock_wrlock (&pwdlock);
433 /* While we are waiting on the lock, somebody else could
434 add this entry. */
435 tmp = cache_search_uid (uid);
436 if (tmp == NULL)
437 add_cache (pwd);
438 pthread_rwlock_unlock (&pwdlock);
440 else
442 ++negmiss;
443 pthread_rwlock_wrlock (&neglock);
444 add_negcache (param->key);
445 pthread_rwlock_unlock (&neglock);
448 else
449 ++neghit;
451 pw_send_answer (param->conn, pwd);
452 close_socket (param->conn);
453 if (buffer != NULL)
454 free (buffer);
456 free (param->key);
457 free (param);
458 return NULL;
461 void *
462 pwdtable_update (void *v)
464 time_t now;
465 int i;
467 sleep (20);
469 while (!do_shutdown)
471 if (debug_flag > 2)
472 dbg_log (_("(pwdtable_update) Wait for write lock!"));
474 pthread_rwlock_wrlock (&pwdlock);
476 if (debug_flag > 2)
477 dbg_log (_("(pwdtable_update) Have write lock"));
479 time (&now);
480 for (i = 0; i < modulo; ++i)
482 pwdhash *work = &pwdtbl[i];
484 while (work && work->pwd)
486 if ((now - work->create) >= postimeout)
488 uidhash *uh = &uidtbl[work->pwd->pw_uid % modulo];
490 if (debug_flag)
491 dbg_log (_("Give \"%s\" free"), work->pwd->pw_name);
493 while (uh != NULL && uh->pwptr)
495 if (uh->pwptr->pwd->pw_uid == work->pwd->pw_uid)
497 if (debug_flag)
498 dbg_log (_("Give uid for \"%s\" free"),
499 work->pwd->pw_name);
500 if (uh->next != NULL)
502 uidhash *tmp = uh->next;
503 uh->pwptr = tmp->pwptr;
504 uh->next = tmp->next;
505 free (tmp);
507 else
508 uh->pwptr = NULL;
510 uh = uh->next;
513 free_pwd (work->pwd);
514 if (work->next != NULL)
516 pwdhash *tmp = work->next;
517 work->create = tmp->create;
518 work->next = tmp->next;
519 work->pwd = tmp->pwd;
520 free (tmp);
522 else
523 work->pwd = NULL;
525 work = work->next;
528 if (debug_flag > 2)
529 dbg_log (_("(pwdtable_update) Release wait lock"));
530 pthread_rwlock_unlock (&pwdlock);
531 sleep (20);
533 return NULL;
536 void *
537 negtable_update (void *v)
539 time_t now;
540 int i;
542 sleep (30);
544 while (!do_shutdown)
546 if (debug_flag > 2)
547 dbg_log (_("(negtable_update) Wait for write lock!"));
549 pthread_rwlock_wrlock (&neglock);
551 if (debug_flag)
552 dbg_log (_("(negtable_update) Have write lock"));
554 time (&now);
555 for (i = 0; i < modulo; ++i)
557 neghash *work = &negtbl[i];
559 while (work && work->key)
561 if ((now - work->create) >= negtimeout)
563 if (debug_flag)
564 dbg_log (_("Give \"%s\" free"), work->key);
566 free (work->key);
568 if (work->next != NULL)
570 neghash *tmp = work->next;
571 work->create = tmp->create;
572 work->next = tmp->next;
573 work->key = tmp->key;
574 free (tmp);
576 else
577 work->key = NULL;
579 work = work->next;
582 if (debug_flag)
583 dbg_log (_("(negtable_update) Release wait lock"));
585 pthread_rwlock_unlock (&neglock);
586 sleep (10);
588 return NULL;