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 (uidhash
));
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
)
135 size_t name_len
= strlen (src
->pw_name
) + 1;
136 size_t passwd_len
= strlen (src
->pw_gecos
) + 1;
137 size_t gecos_len
= strlen (src
->pw_dir
) + 1;
138 size_t dir_len
= strlen (src
->pw_dir
) + 1;
139 size_t shell_len
= strlen (src
->pw_shell
) + 1;
142 dest
= malloc (sizeof (struct passwd
)
143 + name_len
+ passwd_len
+ gecos_len
+ dir_len
+ shell_len
);
147 cp
= (char *) (dest
+ 1);
149 cp
= mempcpy (cp
, src
->pw_name
, name_len
) + 1;
150 dest
->pw_passwd
= cp
;
151 cp
= mempcpy (cp
, src
->pw_passwd
, passwd_len
) + 1;
152 dest
->pw_uid
= src
->pw_uid
;
153 dest
->pw_gid
= src
->pw_gid
;
155 cp
= mempcpy (cp
, src
->pw_gecos
, gecos_len
) + 1;
157 cp
= mempcpy (cp
, src
->pw_dir
, dir_len
) + 1;
159 mempcpy (cp
, src
->pw_shell
, shell_len
);
165 free_pwd (struct passwd
*src
)
171 add_cache (struct passwd
*pwd
)
175 unsigned long int hash
= __nis_hash (pwd
->pw_name
,
176 strlen (pwd
->pw_name
)) % modulo
;
179 dbg_log (_("pwd_add_cache (%s)"), pwd
->pw_name
);
181 work
= &pwdtbl
[hash
];
183 if (pwdtbl
[hash
].pwd
== NULL
)
184 pwdtbl
[hash
].pwd
= save_pwd (pwd
);
187 while (work
->next
!= NULL
)
190 work
->next
= calloc (1, sizeof (pwdhash
));
191 work
->next
->pwd
= save_pwd (pwd
);
194 /* Set a pointer from the pwuid hash table to the pwname hash table */
195 time (&work
->create
);
196 uidwork
= &uidtbl
[pwd
->pw_uid
% modulo
];
197 if (uidwork
->pwptr
== NULL
)
198 uidwork
->pwptr
= work
->pwd
;
201 while (uidwork
->next
!= NULL
)
202 uidwork
= uidwork
->next
;
204 uidwork
->next
= calloc (1, sizeof (uidhash
));
205 uidwork
->next
->pwptr
= work
->pwd
;
210 static struct passwd
*
211 cache_search_name (const char *name
)
214 unsigned long int hash
= __nis_hash (name
, strlen (name
)) % modulo
;
216 work
= &pwdtbl
[hash
];
218 while (work
->pwd
!= NULL
)
220 if (strcmp (work
->pwd
->pw_name
, name
) == 0)
222 if (work
->next
!= NULL
)
230 static struct passwd
*
231 cache_search_uid (uid_t uid
)
235 work
= &uidtbl
[uid
% modulo
];
237 while (work
->pwptr
!= NULL
)
239 if (work
->pwptr
->pw_uid
== uid
)
241 if (work
->next
!= NULL
)
250 add_negcache (char *key
)
253 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
256 dbg_log (_("pwd_add_netgache (%s|%ld)"), key
, hash
);
258 work
= &negtbl
[hash
];
260 if (negtbl
[hash
].key
== NULL
)
262 negtbl
[hash
].key
= strdup (key
);
263 negtbl
[hash
].next
= NULL
;
267 while (work
->next
!= NULL
)
270 work
->next
= calloc (1, sizeof (neghash
));
271 work
->next
->key
= strdup (key
);
275 time (&work
->create
);
281 cache_search_neg (const char *key
)
284 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
287 dbg_log (_("pwd_cache_search_neg (%s|%ld)"), key
, hash
);
289 work
= &negtbl
[hash
];
291 while (work
->key
!= NULL
)
293 if (strcmp (work
->key
, key
) == 0)
295 if (work
->next
!= NULL
)
304 cache_getpwnam (void *v_param
)
307 param_t
*param
= (param_t
*)v_param
;
309 pthread_rwlock_rdlock (&pwdlock
);
310 pwd
= cache_search_name (param
->key
);
312 /* I don't like it to hold the read only lock longer, but it is
313 necessary to avoid to much malloc/free/strcpy. */
318 dbg_log (_("Found \"%s\" in cache !"), param
->key
);
321 pw_send_answer (param
->conn
, pwd
);
322 close_socket (param
->conn
);
324 pthread_rwlock_unlock (&pwdlock
);
330 char *buffer
= calloc (1, buflen
);
331 struct passwd resultbuf
;
334 dbg_log (_("Doesn't found \"%s\" in cache !"), param
->key
);
336 pthread_rwlock_unlock (&pwdlock
);
338 pthread_rwlock_rdlock (&neglock
);
339 status
= cache_search_neg (param
->key
);
340 pthread_rwlock_unlock (&neglock
);
344 while (buffer
!= NULL
345 && (getpwnam_r (param
->key
, &resultbuf
, buffer
, buflen
, &pwd
)
351 buffer
= realloc (buffer
, buflen
);
354 if (buffer
!= NULL
&& pwd
!= NULL
)
359 pthread_rwlock_wrlock (&pwdlock
);
360 /* While we are waiting on the lock, somebody else could
362 tmp
= cache_search_name (param
->key
);
365 pthread_rwlock_unlock (&pwdlock
);
370 pthread_rwlock_wrlock (&neglock
);
371 add_negcache (param
->key
);
372 pthread_rwlock_unlock (&neglock
);
377 pw_send_answer (param
->conn
, pwd
);
378 close_socket (param
->conn
);
388 cache_pw_disabled (void *v_param
)
390 param_t
*param
= (param_t
*)v_param
;
393 dbg_log (_("\tpasswd cache is disabled\n"));
395 pw_send_disabled (param
->conn
);
400 cache_getpwuid (void *v_param
)
402 param_t
*param
= (param_t
*)v_param
;
403 struct passwd
*pwd
, resultbuf
;
404 uid_t uid
= strtol (param
->key
, NULL
, 10);
406 pthread_rwlock_rdlock (&pwdlock
);
407 pwd
= cache_search_uid (uid
);
409 /* I don't like it to hold the read only lock longer, but it is
410 necessary to avoid to much malloc/free/strcpy. */
415 dbg_log (_("Found \"%d\" in cache !"), uid
);
418 pw_send_answer (param
->conn
, pwd
);
419 close_socket (param
->conn
);
421 pthread_rwlock_unlock (&pwdlock
);
426 char *buffer
= malloc (buflen
);
430 dbg_log (_("Doesn't found \"%d\" in cache !"), uid
);
432 pthread_rwlock_unlock (&pwdlock
);
434 pthread_rwlock_rdlock (&neglock
);
435 status
= cache_search_neg (param
->key
);
436 pthread_rwlock_unlock (&neglock
);
440 while (buffer
!= NULL
441 && (getpwuid_r (uid
, &resultbuf
, buffer
, buflen
, &pwd
) != 0)
446 buffer
= realloc (buffer
, buflen
);
449 if (buffer
!= NULL
&& pwd
!= NULL
)
454 pthread_rwlock_wrlock (&pwdlock
);
455 /* While we are waiting on the lock, somebody else could
457 tmp
= cache_search_uid (uid
);
460 pthread_rwlock_unlock (&pwdlock
);
465 pthread_rwlock_wrlock (&neglock
);
466 add_negcache (param
->key
);
467 pthread_rwlock_unlock (&neglock
);
473 pw_send_answer (param
->conn
, pwd
);
474 close_socket (param
->conn
);
484 pwdtable_update (void *v
)
494 dbg_log (_("(pwdtable_update) Wait for write lock!"));
496 pthread_rwlock_wrlock (&pwdlock
);
499 dbg_log (_("(pwdtable_update) Have write lock"));
502 for (i
= 0; i
< modulo
; ++i
)
504 pwdhash
*work
= &pwdtbl
[i
];
506 while (work
&& work
->pwd
)
508 if ((now
- work
->create
) >= postimeout
)
510 uidhash
*uh
= &uidtbl
[work
->pwd
->pw_uid
% modulo
];
513 dbg_log (_("Give \"%s\" free"), work
->pwd
->pw_name
);
515 while (uh
!= NULL
&& uh
->pwptr
)
517 if (uh
->pwptr
->pw_uid
== work
->pwd
->pw_uid
)
520 dbg_log (_("Give uid for \"%s\" free"),
522 if (uh
->next
!= NULL
)
524 uidhash
*tmp
= uh
->next
;
525 uh
->pwptr
= tmp
->pwptr
;
526 uh
->next
= tmp
->next
;
535 free_pwd (work
->pwd
);
536 if (work
->next
!= NULL
)
538 pwdhash
*tmp
= work
->next
;
539 work
->create
= tmp
->create
;
540 work
->next
= tmp
->next
;
541 work
->pwd
= tmp
->pwd
;
551 dbg_log (_("(pwdtable_update) Release wait lock"));
552 pthread_rwlock_unlock (&pwdlock
);
559 negtable_update (void *v
)
569 dbg_log (_("(negpwdtable_update) Wait for write lock!"));
571 pthread_rwlock_wrlock (&neglock
);
574 dbg_log (_("(negpwdtable_update) Have write lock"));
577 for (i
= 0; i
< modulo
; ++i
)
579 neghash
*work
= &negtbl
[i
];
581 while (work
&& work
->key
)
583 if ((now
- work
->create
) >= negtimeout
)
586 dbg_log (_("Give \"%s\" free"), work
->key
);
590 if (work
->next
!= NULL
)
592 neghash
*tmp
= work
->next
;
593 work
->create
= tmp
->create
;
594 work
->next
= tmp
->next
;
595 work
->key
= tmp
->key
;
605 dbg_log (_("(negpwdtable_update) Release wait lock"));
607 pthread_rwlock_unlock (&neglock
);