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 modulo
= 211;
33 static unsigned long postimeout
= 3600;
34 static unsigned long negtimeout
= 60;
36 static unsigned long poshit
= 0;
37 static unsigned long posmiss
= 0;
38 static unsigned long neghit
= 0;
39 static unsigned long negmiss
= 0;
47 typedef struct grphash grphash
;
54 typedef struct gidhash gidhash
;
62 typedef struct neghash neghash
;
64 static grphash
*grptbl
;
65 static gidhash
*gidtbl
;
66 static neghash
*negtbl
;
68 static pthread_rwlock_t grplock
= PTHREAD_RWLOCK_INITIALIZER
;
69 static pthread_rwlock_t neglock
= PTHREAD_RWLOCK_INITIALIZER
;
71 static void *grptable_update (void *);
72 static void *negtable_update (void *);
75 get_gr_stat (stat_response_header
*stat
)
77 stat
->gr_poshit
= poshit
;
78 stat
->gr_posmiss
= posmiss
;
79 stat
->gr_neghit
= neghit
;
80 stat
->gr_negmiss
= negmiss
;
81 stat
->gr_size
= modulo
;
82 stat
->gr_posttl
= postimeout
;
83 stat
->gr_negttl
= negtimeout
;
87 set_grp_modulo (unsigned long mod
)
93 set_pos_grp_ttl (unsigned long ttl
)
99 set_neg_grp_ttl (unsigned long ttl
)
110 grptbl
= calloc (modulo
, sizeof (grphash
));
113 gidtbl
= calloc (modulo
, sizeof (grphash
));
116 negtbl
= calloc (modulo
, sizeof (neghash
));
120 pthread_attr_init (&attr
);
121 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
123 pthread_create (&thread
, NULL
, grptable_update
, &attr
);
124 pthread_create (&thread
, NULL
, negtable_update
, &attr
);
126 pthread_attr_destroy (&attr
);
131 static struct group
*
132 save_grp (struct group
*src
)
137 size_t name_len
= strlen (src
->gr_name
) + 1;
138 size_t passwd_len
= strlen (src
->gr_passwd
) + 1;
141 /* How many members does this group have? */
143 while (src
->gr_mem
[l
] != NULL
)
144 tlen
+= strlen (src
->gr_mem
[l
++]) + 1;
146 dest
= malloc (sizeof (struct group
) + (l
+ 1) * sizeof (char *)
147 + name_len
+ passwd_len
+ tlen
);
151 dest
->gr_mem
= (char **) (dest
+ 1);
152 cp
= (char *) (dest
->gr_mem
+ l
+ 1);
155 cp
= mempcpy (cp
, src
->gr_name
, name_len
);
156 dest
->gr_passwd
= cp
;
157 cp
= mempcpy (cp
, src
->gr_passwd
, passwd_len
);
158 dest
->gr_gid
= src
->gr_gid
;
161 while (src
->gr_mem
[l
] != NULL
)
163 dest
->gr_mem
[l
] = cp
;
164 cp
= stpcpy (cp
, src
->gr_mem
[l
]) + 1;
167 dest
->gr_mem
[l
] = NULL
;
173 free_grp (struct group
*src
)
179 add_cache (struct group
*grp
)
183 unsigned long int hash
= __nis_hash (grp
->gr_name
,
184 strlen (grp
->gr_name
)) % modulo
;
187 dbg_log (_("grp_add_cache (%s)"), grp
->gr_name
);
189 work
= &grptbl
[hash
];
191 if (grptbl
[hash
].grp
== NULL
)
192 grptbl
[hash
].grp
= save_grp (grp
);
195 while (work
->next
!= NULL
)
198 work
->next
= calloc (1, sizeof (grphash
));
199 work
->next
->grp
= save_grp (grp
);
203 time (&work
->create
);
204 gidwork
= &gidtbl
[grp
->gr_gid
% modulo
];
205 if (gidwork
->grptr
== NULL
)
206 gidwork
->grptr
= work
->grp
;
209 while (gidwork
->next
!= NULL
)
210 gidwork
= gidwork
->next
;
212 gidwork
->next
= calloc (1, sizeof (gidhash
));
213 gidwork
->next
->grptr
= work
->grp
;
219 static struct group
*
220 cache_search_name (const char *name
)
223 unsigned long int hash
= __nis_hash (name
, strlen(name
)) % modulo
;
225 work
= &grptbl
[hash
];
227 while (work
->grp
!= NULL
)
229 if (strcmp (work
->grp
->gr_name
, name
) == 0)
231 if (work
->next
!= NULL
)
239 static struct group
*
240 cache_search_gid (gid_t gid
)
244 work
= &gidtbl
[gid
% modulo
];
246 while (work
->grptr
!= NULL
)
248 if (work
->grptr
->gr_gid
== gid
)
250 if (work
->next
!= NULL
)
259 add_negcache (char *key
)
262 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
265 dbg_log (_("grp_add_netgache (%s|%ld)"), key
, hash
);
267 work
= &negtbl
[hash
];
269 if (negtbl
[hash
].key
== NULL
)
271 negtbl
[hash
].key
= strdup (key
);
272 negtbl
[hash
].next
= NULL
;
276 while (work
->next
!= NULL
)
279 work
->next
= calloc (1, sizeof (neghash
));
280 work
->next
->key
= strdup (key
);
284 time (&work
->create
);
289 cache_search_neg (const char *key
)
292 unsigned long int hash
= __nis_hash (key
, strlen (key
)) % modulo
;
295 dbg_log (_("grp_cache_search_neg (%s|%ld)"), key
, hash
);
297 work
= &negtbl
[hash
];
299 while (work
->key
!= NULL
)
301 if (strcmp (work
->key
, key
) == 0)
303 if (work
->next
!= NULL
)
312 cache_getgrnam (void *v_param
)
314 param_t
*param
= (param_t
*)v_param
;
317 pthread_rwlock_rdlock (&grplock
);
318 grp
= cache_search_name (param
->key
);
320 /* I don't like it to hold the read only lock longer, but it is
321 necessary to avoid to much malloc/free/strcpy. */
326 dbg_log (_("Found \"%s\" in cache !"), param
->key
);
329 gr_send_answer (param
->conn
, grp
);
330 close_socket (param
->conn
);
332 pthread_rwlock_unlock (&grplock
);
338 char *buffer
= calloc (1, buflen
);
339 struct group resultbuf
;
342 dbg_log (_("Doesn't found \"%s\" in cache !"), param
->key
);
344 pthread_rwlock_unlock (&grplock
);
346 pthread_rwlock_rdlock (&neglock
);
347 status
= cache_search_neg (param
->key
);
348 pthread_rwlock_unlock (&neglock
);
352 while (buffer
!= NULL
353 && (getgrnam_r (param
->key
, &resultbuf
, buffer
, buflen
, &grp
)
359 buffer
= realloc (buffer
, buflen
);
362 if (buffer
!= NULL
&& grp
!= NULL
)
367 pthread_rwlock_wrlock (&grplock
);
368 /* While we are waiting on the lock, somebody else could
370 tmp
= cache_search_name (param
->key
);
373 pthread_rwlock_unlock (&grplock
);
377 pthread_rwlock_wrlock (&neglock
);
378 add_negcache (param
->key
);
380 pthread_rwlock_unlock (&neglock
);
386 gr_send_answer (param
->conn
, grp
);
387 close_socket (param
->conn
);
397 cache_gr_disabled (void *v_param
)
399 param_t
*param
= (param_t
*)v_param
;
402 dbg_log (_("\tgroup cache is disabled\n"));
404 gr_send_disabled (param
->conn
);
409 cache_getgrgid (void *v_param
)
411 param_t
*param
= (param_t
*)v_param
;
412 struct group
*grp
, resultbuf
;
413 gid_t gid
= strtol (param
->key
, NULL
, 10);
415 pthread_rwlock_rdlock (&grplock
);
416 grp
= cache_search_gid (gid
);
418 /* I don't like it to hold the read only lock longer, but it is
419 necessary to avoid to much malloc/free/strcpy. */
424 dbg_log (_("Found \"%d\" in cache !"), gid
);
427 gr_send_answer (param
->conn
, grp
);
428 close_socket (param
->conn
);
430 pthread_rwlock_unlock (&grplock
);
435 char *buffer
= malloc (buflen
);
439 dbg_log (_("Doesn't found \"%d\" in cache !"), gid
);
441 pthread_rwlock_unlock (&grplock
);
443 pthread_rwlock_rdlock (&neglock
);
444 status
= cache_search_neg (param
->key
);
445 pthread_rwlock_unlock (&neglock
);
449 while (buffer
!= NULL
450 && (getgrgid_r (gid
, &resultbuf
, buffer
, buflen
, &grp
) != 0)
455 buffer
= realloc (buffer
, buflen
);
458 if (buffer
!= NULL
&& grp
!= NULL
)
463 pthread_rwlock_wrlock (&grplock
);
464 /* While we are waiting on the lock, somebody else could
466 tmp
= cache_search_gid (gid
);
469 pthread_rwlock_unlock (&grplock
);
474 pthread_rwlock_wrlock (&neglock
);
475 add_negcache (param
->key
);
476 pthread_rwlock_unlock (&neglock
);
482 gr_send_answer (param
->conn
, grp
);
483 close_socket (param
->conn
);
493 grptable_update (void *v
)
503 dbg_log (_("(grptable_update) Wait for write lock!"));
505 pthread_rwlock_wrlock (&grplock
);
508 dbg_log (_("(grptable_update) Have write lock"));
511 for (i
= 0; i
< modulo
; ++i
)
513 grphash
*work
= &grptbl
[i
];
515 while (work
&& work
->grp
)
517 if ((now
- work
->create
) >= postimeout
)
519 gidhash
*uh
= &gidtbl
[work
->grp
->gr_gid
% modulo
];
522 dbg_log (_("Give \"%s\" free"), work
->grp
->gr_name
);
524 while (uh
&& uh
->grptr
)
526 if (uh
->grptr
->gr_gid
== work
->grp
->gr_gid
)
529 dbg_log (_("Give gid for \"%s\" free"),
531 if (uh
->next
!= NULL
)
533 gidhash
*tmp
= uh
->next
;
534 uh
->grptr
= tmp
->grptr
;
535 uh
->next
= tmp
->next
;
544 free_grp (work
->grp
);
545 if (work
->next
!= NULL
)
547 grphash
*tmp
= work
->next
;
548 work
->create
= tmp
->create
;
549 work
->next
= tmp
->next
;
550 work
->grp
= tmp
->grp
;
560 dbg_log (_("(grptable_update) Release wait lock"));
561 pthread_rwlock_unlock (&grplock
);
568 negtable_update (void *v
)
578 dbg_log (_("(neggrptable_update) Wait for write lock!"));
580 pthread_rwlock_wrlock (&neglock
);
583 dbg_log (_("(neggrptable_update) Have write lock"));
586 for (i
= 0; i
< modulo
; ++i
)
588 neghash
*work
= &negtbl
[i
];
590 while (work
&& work
->key
)
592 if ((now
- work
->create
) >= negtimeout
)
595 dbg_log (_("Give \"%s\" free"), work
->key
);
599 if (work
->next
!= NULL
)
601 neghash
*tmp
= work
->next
;
602 work
->create
= tmp
->create
;
603 work
->next
= tmp
->next
;
604 work
->key
= tmp
->key
;
614 dbg_log (_("(neggrptable_update) Release wait lock"));
615 pthread_rwlock_unlock (&neglock
);