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 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;
46 typedef struct pwdhash pwdhash
;
51 struct pwdhash
*pwptr
;
53 typedef struct uidhash uidhash
;
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 *);
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
;
86 set_pwd_modulo (unsigned long int mod
)
92 set_pos_pwd_ttl (unsigned long int ttl
)
98 set_neg_pwd_ttl (unsigned long int ttl
)
109 pwdtbl
= calloc (modulo
, sizeof (pwdhash
));
112 uidtbl
= calloc (modulo
, sizeof (pwdhash
));
115 negtbl
= calloc (modulo
, sizeof (neghash
));
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
);
130 static struct passwd
*
131 save_pwd (struct passwd
*src
)
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
);
148 free_pwd (struct passwd
*src
)
151 free (src
->pw_passwd
);
152 free (src
->pw_gecos
);
154 free (src
->pw_shell
);
159 add_cache (struct passwd
*pwd
)
162 unsigned long int hash
= __nis_hash (pwd
->pw_name
,
163 strlen (pwd
->pw_name
)) % modulo
;
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
);
174 while (work
->next
!= NULL
)
177 work
->next
= calloc (1, sizeof (pwdhash
));
178 work
->next
->pwd
= save_pwd (pwd
);
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
;
188 static struct passwd
*
189 cache_search_name (const char *name
)
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)
200 if (work
->next
!= NULL
)
208 static struct passwd
*
209 cache_search_uid (uid_t uid
)
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
)
228 add_negcache (char *key
)
231 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
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
;
245 while (work
->next
!= NULL
)
248 work
->next
= calloc (1, sizeof (neghash
));
249 work
->next
->key
= strdup (key
);
253 time (&work
->create
);
259 cache_search_neg (const char *key
)
262 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
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)
273 if (work
->next
!= NULL
)
282 cache_getpwnam (void *v_param
)
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. */
296 dbg_log (_("Found \"%s\" in cache !"), param
->key
);
299 pw_send_answer (param
->conn
, pwd
);
300 close_socket (param
->conn
);
302 pthread_rwlock_unlock (&pwdlock
);
308 char *buffer
= calloc (1, buflen
);
309 struct passwd resultbuf
;
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
);
322 while (buffer
!= NULL
323 && (getpwnam_r (param
->key
, &resultbuf
, buffer
, buflen
, &pwd
)
329 buffer
= realloc (buffer
, buflen
);
332 if (buffer
!= NULL
&& pwd
!= NULL
)
337 pthread_rwlock_wrlock (&pwdlock
);
338 /* While we are waiting on the lock, somebody else could
340 tmp
= cache_search_name (param
->key
);
343 pthread_rwlock_unlock (&pwdlock
);
348 pthread_rwlock_wrlock (&neglock
);
349 add_negcache (param
->key
);
350 pthread_rwlock_unlock (&neglock
);
355 pw_send_answer (param
->conn
, pwd
);
356 close_socket (param
->conn
);
366 cache_pw_disabled (void *v_param
)
368 param_t
*param
= (param_t
*)v_param
;
371 dbg_log (_("\tpasswd cache is disabled\n"));
373 pw_send_disabled (param
->conn
);
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. */
393 dbg_log (_("Found \"%d\" in cache !"), uid
);
396 pw_send_answer (param
->conn
, pwd
);
397 close_socket (param
->conn
);
399 pthread_rwlock_unlock (&pwdlock
);
404 char *buffer
= malloc (buflen
);
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
);
418 while (buffer
!= NULL
419 && (getpwuid_r (uid
, &resultbuf
, buffer
, buflen
, &pwd
) != 0)
424 buffer
= realloc (buffer
, buflen
);
427 if (buffer
!= NULL
&& pwd
!= NULL
)
432 pthread_rwlock_wrlock (&pwdlock
);
433 /* While we are waiting on the lock, somebody else could
435 tmp
= cache_search_uid (uid
);
438 pthread_rwlock_unlock (&pwdlock
);
443 pthread_rwlock_wrlock (&neglock
);
444 add_negcache (param
->key
);
445 pthread_rwlock_unlock (&neglock
);
451 pw_send_answer (param
->conn
, pwd
);
452 close_socket (param
->conn
);
462 pwdtable_update (void *v
)
472 dbg_log (_("(pwdtable_update) Wait for write lock!"));
474 pthread_rwlock_wrlock (&pwdlock
);
477 dbg_log (_("(pwdtable_update) Have write lock"));
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
];
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
)
498 dbg_log (_("Give uid for \"%s\" free"),
500 if (uh
->next
!= NULL
)
502 uidhash
*tmp
= uh
->next
;
503 uh
->pwptr
= tmp
->pwptr
;
504 uh
->next
= tmp
->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
;
529 dbg_log (_("(pwdtable_update) Release wait lock"));
530 pthread_rwlock_unlock (&pwdlock
);
537 negtable_update (void *v
)
547 dbg_log (_("(negtable_update) Wait for write lock!"));
549 pthread_rwlock_wrlock (&neglock
);
552 dbg_log (_("(negtable_update) Have write lock"));
555 for (i
= 0; i
< modulo
; ++i
)
557 neghash
*work
= &negtbl
[i
];
559 while (work
&& work
->key
)
561 if ((now
- work
->create
) >= negtimeout
)
564 dbg_log (_("Give \"%s\" 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
;
583 dbg_log (_("(negtable_update) Release wait lock"));
585 pthread_rwlock_unlock (&neglock
);