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 int modulo
= 211;
33 static unsigned long int postimeout
= 600;
34 static unsigned long int negtimeout
= 20;
36 static unsigned long int poshit
= 0;
37 static unsigned long int posmiss
= 0;
38 static unsigned long int neghit
= 0;
39 static unsigned long int negmiss
= 0;
47 typedef struct pwdhash pwdhash
;
54 typedef struct uidhash uidhash
;
62 typedef struct neghash neghash
;
64 static pwdhash
*pwdtbl
;
65 static uidhash
*uidtbl
;
66 static neghash
*negtbl
;
68 static pthread_rwlock_t pwdlock
= PTHREAD_RWLOCK_INITIALIZER
;
69 static pthread_rwlock_t neglock
= PTHREAD_RWLOCK_INITIALIZER
;
71 static void *pwdtable_update (void *);
72 static void *negtable_update (void *);
75 get_pw_stat (stat_response_header
*stat
)
77 stat
->pw_poshit
= poshit
;
78 stat
->pw_posmiss
= posmiss
;
79 stat
->pw_neghit
= neghit
;
80 stat
->pw_negmiss
= negmiss
;
81 stat
->pw_size
= modulo
;
82 stat
->pw_posttl
= postimeout
;
83 stat
->pw_negttl
= negtimeout
;
87 set_pwd_modulo (unsigned long int mod
)
93 set_pos_pwd_ttl (unsigned long int ttl
)
99 set_neg_pwd_ttl (unsigned long int ttl
)
110 pwdtbl
= calloc (modulo
, sizeof (pwdhash
));
113 uidtbl
= calloc (modulo
, sizeof (pwdhash
));
116 negtbl
= calloc (modulo
, sizeof (neghash
));
120 pthread_attr_init (&attr
);
121 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
123 pthread_create (&thread
, NULL
, pwdtable_update
, &attr
);
124 pthread_create (&thread
, NULL
, negtable_update
, &attr
);
126 pthread_attr_destroy (&attr
);
131 static struct passwd
*
132 save_pwd (struct passwd
*src
)
136 dest
= calloc (1, sizeof (struct passwd
));
137 dest
->pw_name
= strdup (src
->pw_name
);
138 dest
->pw_passwd
= strdup (src
->pw_passwd
);
139 dest
->pw_uid
= src
->pw_uid
;
140 dest
->pw_gid
= src
->pw_gid
;
141 dest
->pw_gecos
= strdup (src
->pw_gecos
);
142 dest
->pw_dir
= strdup (src
->pw_dir
);
143 dest
->pw_shell
= strdup (src
->pw_shell
);
149 free_pwd (struct passwd
*src
)
152 free (src
->pw_passwd
);
153 free (src
->pw_gecos
);
155 free (src
->pw_shell
);
160 add_cache (struct passwd
*pwd
)
164 unsigned long int hash
= __nis_hash (pwd
->pw_name
,
165 strlen (pwd
->pw_name
)) % modulo
;
168 dbg_log (_("pwd_add_cache (%s)"), pwd
->pw_name
);
170 work
= &pwdtbl
[hash
];
172 if (pwdtbl
[hash
].pwd
== NULL
)
173 pwdtbl
[hash
].pwd
= save_pwd (pwd
);
176 while (work
->next
!= NULL
)
179 work
->next
= calloc (1, sizeof (pwdhash
));
180 work
->next
->pwd
= save_pwd (pwd
);
183 /* Set a pointer from the pwuid hash table to the pwname hash table */
184 time (&work
->create
);
185 uidwork
= &uidtbl
[pwd
->pw_uid
% modulo
];
186 if (uidwork
->pwptr
== NULL
)
187 uidwork
->pwptr
= work
->pwd
;
190 while (uidwork
->next
!= NULL
)
191 uidwork
= uidwork
->next
;
193 uidwork
->next
= calloc (1, sizeof (uidhash
));
194 uidwork
->next
->pwptr
= work
->pwd
;
199 static struct passwd
*
200 cache_search_name (const char *name
)
203 unsigned long int hash
= __nis_hash (name
, strlen (name
)) % modulo
;
205 work
= &pwdtbl
[hash
];
207 while (work
->pwd
!= NULL
)
209 if (strcmp (work
->pwd
->pw_name
, name
) == 0)
211 if (work
->next
!= NULL
)
219 static struct passwd
*
220 cache_search_uid (uid_t uid
)
224 work
= &uidtbl
[uid
% modulo
];
226 while (work
->pwptr
!= NULL
)
228 if (work
->pwptr
->pw_uid
== uid
)
230 if (work
->next
!= NULL
)
239 add_negcache (char *key
)
242 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
245 dbg_log (_("pwd_add_netgache (%s|%ld)"), key
, hash
);
247 work
= &negtbl
[hash
];
249 if (negtbl
[hash
].key
== NULL
)
251 negtbl
[hash
].key
= strdup (key
);
252 negtbl
[hash
].next
= NULL
;
256 while (work
->next
!= NULL
)
259 work
->next
= calloc (1, sizeof (neghash
));
260 work
->next
->key
= strdup (key
);
264 time (&work
->create
);
270 cache_search_neg (const char *key
)
273 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
276 dbg_log (_("pwd_cache_search_neg (%s|%ld)"), key
, hash
);
278 work
= &negtbl
[hash
];
280 while (work
->key
!= NULL
)
282 if (strcmp (work
->key
, key
) == 0)
284 if (work
->next
!= NULL
)
293 cache_getpwnam (void *v_param
)
296 param_t
*param
= (param_t
*)v_param
;
298 pthread_rwlock_rdlock (&pwdlock
);
299 pwd
= cache_search_name (param
->key
);
301 /* I don't like it to hold the read only lock longer, but it is
302 necessary to avoid to much malloc/free/strcpy. */
307 dbg_log (_("Found \"%s\" in cache !"), param
->key
);
310 pw_send_answer (param
->conn
, pwd
);
311 close_socket (param
->conn
);
313 pthread_rwlock_unlock (&pwdlock
);
319 char *buffer
= calloc (1, buflen
);
320 struct passwd resultbuf
;
323 dbg_log (_("Doesn't found \"%s\" in cache !"), param
->key
);
325 pthread_rwlock_unlock (&pwdlock
);
327 pthread_rwlock_rdlock (&neglock
);
328 status
= cache_search_neg (param
->key
);
329 pthread_rwlock_unlock (&neglock
);
333 while (buffer
!= NULL
334 && (getpwnam_r (param
->key
, &resultbuf
, buffer
, buflen
, &pwd
)
340 buffer
= realloc (buffer
, buflen
);
343 if (buffer
!= NULL
&& pwd
!= NULL
)
348 pthread_rwlock_wrlock (&pwdlock
);
349 /* While we are waiting on the lock, somebody else could
351 tmp
= cache_search_name (param
->key
);
354 pthread_rwlock_unlock (&pwdlock
);
359 pthread_rwlock_wrlock (&neglock
);
360 add_negcache (param
->key
);
361 pthread_rwlock_unlock (&neglock
);
366 pw_send_answer (param
->conn
, pwd
);
367 close_socket (param
->conn
);
377 cache_pw_disabled (void *v_param
)
379 param_t
*param
= (param_t
*)v_param
;
382 dbg_log (_("\tpasswd cache is disabled\n"));
384 pw_send_disabled (param
->conn
);
389 cache_getpwuid (void *v_param
)
391 param_t
*param
= (param_t
*)v_param
;
392 struct passwd
*pwd
, resultbuf
;
393 uid_t uid
= strtol (param
->key
, NULL
, 10);
395 pthread_rwlock_rdlock (&pwdlock
);
396 pwd
= cache_search_uid (uid
);
398 /* I don't like it to hold the read only lock longer, but it is
399 necessary to avoid to much malloc/free/strcpy. */
404 dbg_log (_("Found \"%d\" in cache !"), uid
);
407 pw_send_answer (param
->conn
, pwd
);
408 close_socket (param
->conn
);
410 pthread_rwlock_unlock (&pwdlock
);
415 char *buffer
= malloc (buflen
);
419 dbg_log (_("Doesn't found \"%d\" in cache !"), uid
);
421 pthread_rwlock_unlock (&pwdlock
);
423 pthread_rwlock_rdlock (&neglock
);
424 status
= cache_search_neg (param
->key
);
425 pthread_rwlock_unlock (&neglock
);
429 while (buffer
!= NULL
430 && (getpwuid_r (uid
, &resultbuf
, buffer
, buflen
, &pwd
) != 0)
435 buffer
= realloc (buffer
, buflen
);
438 if (buffer
!= NULL
&& pwd
!= NULL
)
443 pthread_rwlock_wrlock (&pwdlock
);
444 /* While we are waiting on the lock, somebody else could
446 tmp
= cache_search_uid (uid
);
449 pthread_rwlock_unlock (&pwdlock
);
454 pthread_rwlock_wrlock (&neglock
);
455 add_negcache (param
->key
);
456 pthread_rwlock_unlock (&neglock
);
462 pw_send_answer (param
->conn
, pwd
);
463 close_socket (param
->conn
);
473 pwdtable_update (void *v
)
483 dbg_log (_("(pwdtable_update) Wait for write lock!"));
485 pthread_rwlock_wrlock (&pwdlock
);
488 dbg_log (_("(pwdtable_update) Have write lock"));
491 for (i
= 0; i
< modulo
; ++i
)
493 pwdhash
*work
= &pwdtbl
[i
];
495 while (work
&& work
->pwd
)
497 if ((now
- work
->create
) >= postimeout
)
499 uidhash
*uh
= &uidtbl
[work
->pwd
->pw_uid
% modulo
];
502 dbg_log (_("Give \"%s\" free"), work
->pwd
->pw_name
);
504 while (uh
!= NULL
&& uh
->pwptr
)
506 if (uh
->pwptr
->pw_uid
== work
->pwd
->pw_uid
)
509 dbg_log (_("Give uid for \"%s\" free"),
511 if (uh
->next
!= NULL
)
513 uidhash
*tmp
= uh
->next
;
514 uh
->pwptr
= tmp
->pwptr
;
515 uh
->next
= tmp
->next
;
524 free_pwd (work
->pwd
);
525 if (work
->next
!= NULL
)
527 pwdhash
*tmp
= work
->next
;
528 work
->create
= tmp
->create
;
529 work
->next
= tmp
->next
;
530 work
->pwd
= tmp
->pwd
;
540 dbg_log (_("(pwdtable_update) Release wait lock"));
541 pthread_rwlock_unlock (&pwdlock
);
548 negtable_update (void *v
)
558 dbg_log (_("(negpwdtable_update) Wait for write lock!"));
560 pthread_rwlock_wrlock (&neglock
);
563 dbg_log (_("(negpwdtable_update) Have write lock"));
566 for (i
= 0; i
< modulo
; ++i
)
568 neghash
*work
= &negtbl
[i
];
570 while (work
&& work
->key
)
572 if ((now
- work
->create
) >= negtimeout
)
575 dbg_log (_("Give \"%s\" free"), work
->key
);
579 if (work
->next
!= NULL
)
581 neghash
*tmp
= work
->next
;
582 work
->create
= tmp
->create
;
583 work
->next
= tmp
->next
;
584 work
->key
= tmp
->key
;
594 dbg_log (_("(negpwdtable_update) Release wait lock"));
596 pthread_rwlock_unlock (&neglock
);