chiark / gitweb /
Use `uid_t' instead of `int' for uids and gids. Not quite sure why I
[become] / src / userdb.c
1 /* -*-c-*-
2  *
3  * $Id: userdb.c,v 1.5 1997/09/17 10:24:08 mdw Exp $
4  *
5  * User database management
6  *
7  * (c) 1997 EBI
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of `become'
13  *
14  * `Become' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * `Become' is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with `become'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------*
30  *
31  * $Log: userdb.c,v $
32  * Revision 1.5  1997/09/17 10:24:08  mdw
33  * Use `uid_t' instead of `int' for uids and gids.  Not quite sure why I
34  * didn't do this before.
35  *
36  * Revision 1.4  1997/08/20  16:24:58  mdw
37  * Patch memory leak.  Rename `userdb_reinit' to `userdb_end' for more
38  * sensible restart.
39  *
40  * Revision 1.3  1997/08/07 09:44:29  mdw
41  * Read NIS-based passwords from the YP server directly, rather than using
42  * `popen(ypcat)', which is probably both slower and less secure.
43  *
44  * Revision 1.2  1997/08/04 10:24:26  mdw
45  * Sources placed under CVS control.
46  *
47  * Revision 1.1  1997/07/21  13:47:43  mdw
48  * Initial revision
49  *
50  */
51
52 /*----- Header files ------------------------------------------------------*/
53
54 /* --- ANSI headers --- */
55
56 #include <ctype.h>
57 #include <errno.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61
62 /* --- Unix headers --- */
63
64 #include "config.h"
65
66 #include <sys/types.h>
67
68 #ifdef HAVE_YP
69 #  include <rpc/rpc.h>
70 #  include <rpcsvc/ypclnt.h>
71 #  include <rpcsvc/yp_prot.h>
72 #endif
73
74 #include <grp.h>
75 #include <pwd.h>
76 #include <unistd.h>
77
78 /* --- Local headers --- */
79
80 #include "become.h"
81 #include "sym.h"
82 #include "userdb.h"
83 #include "utils.h"
84
85 /*----- Type definitions --------------------------------------------------*/
86
87 /* --- A map link --- */
88
89 typedef struct userdb__node {
90   struct userdb__node *next;
91   void *rec;
92 } userdb__node;
93
94 /* --- A reference to a real record --- */
95
96 typedef struct userdb__sym {
97   sym_base _base;
98   void *rec;
99 } userdb__sym;
100
101 /* --- A name- and number-mapping --- */
102
103 typedef struct userdb__map {
104   sym_table nmap;
105   sym_table idmap;
106   userdb__node *list;
107 } userdb__map;
108
109 /*----- Static variables --------------------------------------------------*/
110
111 static userdb__map userdb__users;       /* Map of user info blocks */
112 static sym_iter userdb__useri;          /* Iterator for users */
113 static userdb__map userdb__groups;      /* Map of group info blocks */
114 static sym_iter userdb__groupi;         /* Iterator for groups */
115
116 /*----- Map management functions ------------------------------------------*/
117
118 /* --- @userdb__createMap@ --- *
119  *
120  * Arguments:   @userdb__map *m@ = pointer to a map block
121  *
122  * Returns:     ---
123  *
124  * Use:         Initialises a map table.
125  */
126
127 static void userdb__createMap(userdb__map *m)
128 {
129   sym_createTable(&m->nmap);
130   sym_createTable(&m->idmap);
131   m->list = 0;
132 }
133
134 /* --- @userdb__addToMap@ --- *
135  *
136  * Arguments:   @userdb__map *m@ = pointer to the map block
137  *              @const char *name@ = pointer to the item's name
138  *              @uid_t id@ = the item's id number
139  *              @void *rec@ = pointer to the actual record
140  *
141  * Returns:     ---
142  *
143  * Use:         Adds an item to the given map.
144  */
145
146 static void userdb__addToMap(userdb__map *m,
147                              const char *name,
148                              uid_t id, void *rec)
149 {
150   unsigned f;
151   userdb__sym *s;
152   userdb__node *n;
153
154   s = sym_find(&m->nmap, name, -1, sizeof(*s), &f);
155   if (!f)
156     s->rec = rec;
157
158   s = sym_find(&m->idmap, (char *)&id, sizeof(id), sizeof(*s), &f);
159   if (!f)
160     s->rec = rec;
161
162   n = xmalloc(sizeof(*n));
163   n->rec = rec;
164   n->next = m->list;
165   m->list = n;
166 }
167
168 /* --- @userdb__byName@ --- *
169  *
170  * Arguments:   @userdb__map *m@ = pointer to a map block
171  *              @const char *name@ = name to look up
172  *
173  * Returns:     A pointer to the appropriate block, or zero if not found.
174  *
175  * Use:         Looks up a name in a mapping and returns the result.
176  */
177
178 static void *userdb__byName(userdb__map *m, const char *name)
179 {
180   userdb__sym *s = sym_find(&m->nmap, name, -1, 0, 0);
181   return (s ? s->rec : 0);
182 }
183
184 /* --- @userdb__byId@ --- *
185  *
186  * Arguments:   @userdb__map *m@ = pointer to a map block
187  *              @uid_t id@ = id number to find
188  *
189  * Returns:     A pointer to the appropriate block, or zero if not found.
190  *
191  * Use:         Looks up an ID in a mapping, and returns the result.
192  */
193
194 static void *userdb__byId(userdb__map *m, uid_t id)
195 {
196   userdb__sym *s = sym_find(&m->idmap, (char *)&id, sizeof(id), 0, 0);
197   return (s ? s->rec : 0);
198 }
199
200 /* --- @userdb__clearMap@ --- *
201  *
202  * Arguments:   @userdb__map *m@ = pointer to a map block
203  *              @void (*freerec)(void *rec)@ = pointer to a free-record proc
204  *
205  * Returns:     ---
206  *
207  * Use:         Clears a map, emptying it and releasing the memory it
208  *              occupied.
209  */
210
211 static void userdb__clearMap(userdb__map *m, void (*freerec)(void *rec))
212 {
213   userdb__node *n, *t;
214
215   sym_destroyTable(&m->nmap);
216   sym_destroyTable(&m->idmap);
217
218   for (n = m->list; n; n = t) {
219     t = n->next;
220     freerec(n->rec);
221     free(n);
222   }
223 }
224
225 /*----- User and group block management -----------------------------------*/
226
227 /* --- @userdb__dumpUser@ --- *
228  *
229  * Arguments:   @const struct passwd *pw@ = pointer to a user block
230  *
231  * Returns:     ---
232  *
233  * Use:         Writes a user's informationt to a stream.
234  */
235
236 #ifdef TRACING
237
238 static void userdb__dumpUser(const struct passwd *pw)
239 {
240   trace(TRACE_DEBUG,
241         "debug: name `%s' passwd `%s' uid %i gid %i",
242         pw->pw_name, pw->pw_passwd, (int)pw->pw_uid, (int)pw->pw_gid);
243   trace(TRACE_DEBUG,
244         "debug: ... gecos `%s' home `%s' shell `%s'",
245         pw->pw_gecos, pw->pw_dir, pw->pw_shell);
246 }
247
248 #endif
249
250 /* --- @userdb_copyUser@ --- *
251  *
252  * Arguments:   @struct passwd *pw@ = pointer to block to copy
253  *
254  * Returns:     Pointer to the copy.
255  *
256  * Use:         Copies a user block.  The copy is `deep' so all the strings
257  *              are copied too.  Free the copy with @userdb_freeUser@ when
258  *              you don't want it any more.
259  */
260
261 struct passwd *userdb_copyUser(struct passwd *pw)
262 {
263   struct passwd *npw;
264
265   if (!pw)
266     return (0);
267
268   npw = xmalloc(sizeof(*npw));
269
270   npw->pw_name = xstrdup(pw->pw_name);
271   npw->pw_passwd = xstrdup(pw->pw_passwd);
272   npw->pw_uid = pw->pw_uid;
273   npw->pw_gid = pw->pw_gid;
274   npw->pw_gecos = xstrdup(pw->pw_gecos);
275   npw->pw_dir = xstrdup(pw->pw_dir);
276   npw->pw_shell = xstrdup(pw->pw_shell);
277
278   return (npw);
279 }
280
281 /* --- @userdb__buildUser@ --- *
282  *
283  * Arguments:   @char *s@ = pointer to user string
284  *
285  * Returns:     Pointer to a user block.
286  *
287  * Use:         Converts a line from a user file into a password entry.
288  *              Note that the string is corrupted by @strtok@ while it gets
289  *              parsed.
290  */
291
292 static struct passwd *userdb__buildUser(char *s)
293 {
294   struct passwd *pw = xmalloc(sizeof(*pw));
295
296   s = strtok(s, ":"); if (!s) goto tidy_0; pw->pw_name = xstrdup(s);
297   s = strtok(0, ":"); if (!s) goto tidy_1; pw->pw_passwd = xstrdup(s);
298   s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_uid = (uid_t)atol(s);
299   s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_gid = (gid_t)atol(s);
300   s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_gecos = xstrdup(s);
301   s = strtok(0, ":"); if (!s) goto tidy_3; pw->pw_dir = xstrdup(s);
302   s = strtok(0, ":"); if (!s) goto tidy_4; pw->pw_shell = xstrdup(s);
303   return (pw);
304
305   /* --- Error handling --- */
306
307 tidy_4:
308   free(pw->pw_dir);
309 tidy_3:
310   free(pw->pw_gecos);
311 tidy_2:
312   free(pw->pw_passwd);
313 tidy_1:
314   free(pw->pw_name);
315 tidy_0:
316   free(pw);
317
318   return (0);
319 }
320
321 /* --- @userdb_freeUser@ --- *
322  *
323  * Arguments:   @void *rec@ = pointer to a user record
324  *
325  * Returns:     ---
326  *
327  * Use:         Frees a user record.
328  */
329
330 void userdb_freeUser(void *rec)
331 {
332   struct passwd *pw;
333
334   if (!rec)
335     return;
336
337   pw = rec;
338   free(pw->pw_name);
339   free(pw->pw_passwd);
340   free(pw->pw_gecos);
341   free(pw->pw_dir);
342   free(pw->pw_shell);
343   free(pw);
344
345
346 /* --- @userdb__dumpGroup@ --- *
347  *
348  * Arguments:   @const struct group *gr@ = pointer to a group block
349  *              @FILE *fp@ = pointer to stream to write on
350  *
351  * Returns:     ---
352  *
353  * Use:         Writes a group's information to a stream.
354  */
355
356 #ifdef TRACING
357
358 static void userdb__dumpGroup(const struct group *gr)
359 {
360   char *const *p;
361
362   trace(TRACE_DEBUG,
363          "debug: name `%s' passwd `%s' gid %i",
364          gr->gr_name, gr->gr_passwd, (int)gr->gr_gid);
365   for (p = gr->gr_mem; *p; p++)
366     trace(TRACE_DEBUG,"debug: ... `%s'", *p);
367 }
368
369 #endif
370
371 /* --- @userdb_copyGroup@ --- *
372  *
373  * Arguments:   @struct group *gr@ = pointer to group block
374  *
375  * Returns:     Pointer to copied block
376  *
377  * Use:         Copies a group block.  The copy is `deep' so all the strings
378  *              are copied too.  Free the copy with @userdb_freeGroup@ when
379  *              you don't want it any more.
380  */
381
382 struct group *userdb_copyGroup(struct group *gr)
383 {
384   struct group *ngr;
385   int i, max;
386
387   if (!gr)
388     return (0);
389
390   ngr = xmalloc(sizeof(*ngr));
391
392   ngr->gr_name = xstrdup(gr->gr_name);
393   ngr->gr_passwd = xstrdup(gr->gr_passwd);
394   ngr->gr_gid = gr->gr_gid;
395
396   for (max = 0; gr->gr_mem[max]; max++)
397     ;
398   ngr->gr_mem = xmalloc((max + 1) * sizeof(char *));
399   for (i = 0; i < max; i++)
400     ngr->gr_mem[i] = xstrdup(gr->gr_mem[i]);
401   ngr->gr_mem[max] = 0;
402
403   return (ngr);
404 }
405
406 /* --- @userdb__buildGroup@ --- *
407  *
408  * Arguments:   @char *s@ = pointer to group line string
409  *
410  * Returns:     Pointer to a group block
411  *
412  * Use:         Parses an entry in the groups file.  The string is garbled
413  *              by @strtok@ as we go.
414  */
415
416 static struct group *userdb__buildGroup(char *s)
417 {
418   struct group *gr = xmalloc(sizeof(*gr));
419   char *p;
420   int i;
421
422   /* --- Do the easy bits --- */
423
424   s = strtok(s, ":"); if (!s) goto tidy_0; gr->gr_name = xstrdup(s);
425   s = strtok(0, ":"); if (!s) goto tidy_1; gr->gr_passwd = xstrdup(s);
426   s = strtok(0, ":"); if (!s) goto tidy_2; gr->gr_gid = (gid_t)atol(s);
427
428   /* --- Find the start of the member list --- */
429
430   s = strtok(0, "");
431   if (!s)
432     goto tidy_2;
433
434   /* --- Count the number of members --- */
435
436   p = s;
437   i = 0;
438   for (;;) {
439     i++;
440     if ((p = strpbrk(p, ",")) == 0)
441       break;
442     p++;
443   }
444
445   /* --- Allocate the block and fill it --- */
446
447   gr->gr_mem = xmalloc((i + 1) * sizeof(char *));
448   i = 0;
449   s = strtok(s, ",");
450   do {
451     gr->gr_mem[i++] = xstrdup(s);
452     s = strtok(0, ",");
453   } while (s);
454   gr->gr_mem[i] = 0;
455
456   return (gr);
457
458   /* --- Various tidying-up things --- */
459
460 tidy_2:
461   free(gr->gr_passwd);
462 tidy_1:
463   free(gr->gr_name);
464 tidy_0:
465   free(gr);
466
467   return (0);
468 }
469
470 /* --- @userdb_freeGroup@ --- *
471  *
472  * Arguments:   @void *rec@ = pointer to a group record
473  *
474  * Returns:     ---
475  *
476  * Use:         Frees a group record.
477  */
478
479 void userdb_freeGroup(void *rec)
480 {
481   struct group *gr;
482   char **p;
483
484   if (!rec)
485     return;
486
487   gr = rec;
488   free(gr->gr_name);
489   free(gr->gr_passwd);
490   for (p = gr->gr_mem; *p; p++)
491     free(*p);
492   free(gr->gr_mem);
493   free(gr);
494
495
496 /*----- Answering queries -------------------------------------------------*/
497
498 /* --- @userdb_userByName@, @userdb_userById@ --- *
499  *
500  * Arguments:   @const char *name@ = pointer to user's name
501  *              @uid_t id@ = user id to find
502  *
503  * Returns:     Pointer to user block, or zero if not found.
504  *
505  * Use:         Looks up a user by name or id.
506  */
507
508 struct passwd *userdb_userByName(const char *name)
509 { return (userdb__byName(&userdb__users, name)); }
510
511 struct passwd *userdb_userById(uid_t id)
512 { return (userdb__byId(&userdb__users, id)); }
513
514 /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- *
515  *
516  * Arguments:   @userdb_iter *i@ = pointer to a symbol table iterator object
517  *
518  * Returns:     ---
519  *
520  * Use:         Initialises an iteration for the user database.
521  */
522
523 void userdb_iterateUsers(void)
524 { userdb_iterateUsers_r(&userdb__useri); }
525
526 void userdb_iterateUsers_r(userdb_iter *i)
527 { sym_createIter(i, &userdb__users.nmap); }
528
529 /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- *
530  *
531  * Arguments:   @userdb_iter *i@ = pointer to a symbol table iterator oject
532  *
533  * Returns:     Pointer to the next user block, or null.
534  *
535  * Use:         Returns another user block.
536  */
537
538 struct passwd *userdb_nextUser(void)
539 { return (userdb_nextUser_r(&userdb__useri)); }
540
541 struct passwd *userdb_nextUser_r(userdb_iter *i)
542 {
543   userdb__sym *s = sym_next(i);
544   return (s ? s->rec : 0);
545 }
546
547 /* --- @userdb_groupByName@, @userdb_groupById@ --- *
548  *
549  * Arguments:   @const char *name@ = pointer to group's name
550  *              @gid_t id@ = group id to find
551  *
552  * Returns:     Pointer to group block, or zero if not found.
553  *
554  * Use:         Looks up a group by name or id.
555  */
556
557 struct group *userdb_groupByName(const char *name)
558 { return (userdb__byName(&userdb__groups, name)); }
559
560 struct group *userdb_groupById(gid_t id)
561 { return (userdb__byId(&userdb__groups, id)); }
562
563 /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- *
564  *
565  * Arguments:   @userdb_iter *i@ = pointer to a symbol table iterator object
566  *
567  * Returns:     ---
568  *
569  * Use:         Initialises an iteration for the group database.
570  */
571
572 void userdb_iterateGroups(void)
573 { userdb_iterateGroups_r(&userdb__groupi); }
574
575 void userdb_iterateGroups_r(userdb_iter *i)
576 { sym_createIter(i, &userdb__groups.nmap); }
577
578 /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- *
579  *
580  * Arguments:   @userdb_iter *i@ = pointer to a symbol table iterator oject
581  *
582  * Returns:     Pointer to the next group block, or null.
583  *
584  * Use:         Returns another group block.
585  */
586
587 struct group *userdb_nextGroup(void)
588 { return (userdb_nextGroup_r(&userdb__groupi)); }
589
590 struct group *userdb_nextGroup_r(userdb_iter *i)
591 {
592   userdb__sym *s = sym_next(i);
593   return (s ? s->rec : 0);
594 }
595
596 /*----- Yellow pages support ----------------------------------------------*/
597
598 #ifdef HAVE_YP
599
600 /* --- @userdb__foreachUser@ --- *
601  *
602  * Arguments:   @int st@ = YP protocol-level status code
603  *              @char *k@ = address of the key for this record
604  *              @int ksz@ = size of the key
605  *              @char *v@ = address of the value for this record
606  *              @int vsz@ = size of the value
607  *              @char *data@ = pointer to some data passed to me
608  *
609  * Returns:     Zero to be called again, nonzero to end the enumeration.
610  *
611  * Use:         Handles an incoming user record.
612  */
613
614 static int userdb__foreachUser(int st, char *k, int ksz,
615                                char *v, int vsz, char *data)
616 {
617   char *cv;
618   struct passwd *pw;
619
620   if (st != YP_TRUE)
621     return (-1);
622   cv = xmalloc(vsz + 1);
623   memcpy(cv, v, vsz);
624   cv[vsz] = 0;
625   T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); )
626   pw = userdb__buildUser(cv);
627   if (pw && !userdb__byName(&userdb__users, pw->pw_name)) {
628     IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); )
629     userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw);
630   } else
631     userdb_freeUser(pw);
632   free(cv);
633   return (0);
634 }
635
636 /* --- @userdb__foreachGroup@ --- *
637  *
638  * Arguments:   @int st@ = YP protocol-level status code
639  *              @char *k@ = address of the key for this record
640  *              @int ksz@ = size of the key
641  *              @char *v@ = address of the value for this record
642  *              @int vsz@ = size of the value
643  *              @char *data@ = pointer to some data passed to me
644  *
645  * Returns:     Zero to be called again, nonzero to end the enumeration.
646  *
647  * Use:         Handles an incoming user record.
648  */
649
650 static int userdb__foreachGroup(int st, char *k, int ksz,
651                                 char *v, int vsz, char *data)
652 {
653   char *cv;
654   struct group *gr;
655
656   if (st != YP_TRUE)
657     return (-1);
658   cv = xmalloc(vsz + 1);
659   memcpy(cv, v, vsz);
660   cv[vsz] = 0;
661   T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); )
662   gr = userdb__buildGroup(cv);
663   if (gr && !userdb__byName(&userdb__groups, gr->gr_name)) {
664     IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); )
665     userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr);
666   } else
667     userdb_freeGroup(gr);
668   free(cv);
669   return (0);
670 }
671
672 /* --- @userdb_yp@ --- *
673  *
674  * Arguments:   ---
675  *
676  * Returns:     ---
677  *
678  * Use:         Fetches the YP database of users.
679  */
680
681 void userdb_yp(void)
682 {
683   char *ypdom;
684
685   /* --- Bind to a server --- */
686
687   if (yp_get_default_domain(&ypdom) ||
688       yp_bind(ypdom))
689     return;
690
691   T( trace(TRACE_DEBUG, "debug: adding NIS users"); )
692
693   /* --- Fetch the users map --- */
694
695   {
696     static struct ypall_callback ucb = { userdb__foreachUser, 0 };
697     yp_all(ypdom, "passwd.byuid", &ucb);
698   }
699
700   /* --- Fetch the groups map --- */
701
702   {
703     static struct ypall_callback gcb = { userdb__foreachGroup, 0 };
704     yp_all(ypdom, "group.bygid", &gcb);
705   }
706
707   yp_unbind(ypdom);
708 }
709
710 #else
711
712 void userdb_yp(void) { ; }
713
714 #endif
715
716 /*----- Building the databases --------------------------------------------*/
717
718 /* --- @userdb_local@ --- *
719  *
720  * Arguments:   ---
721  *
722  * Returns:     ---
723  *
724  * Use:         Reads the local list of users into the maps.
725  */
726
727 void userdb_local(void)
728 {
729   T( trace(TRACE_DEBUG, "debug: adding local users"); )
730
731   /* --- Fetch users first --- */
732
733   {
734     struct passwd *pw;
735
736     setpwent();
737     while ((pw = getpwent()) != 0) {
738       IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); )
739       if (!userdb__byName(&userdb__users, pw->pw_name))
740         userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid,
741                          userdb_copyUser(pw));
742     }
743     endpwent();
744   }
745
746   /* --- Then fetch groups --- */
747
748   {
749     struct group *gr;
750
751     setgrent();
752     while ((gr = getgrent()) != 0) {
753       IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); )
754       if (!userdb__byName(&userdb__groups, gr->gr_name))
755         userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid,
756                          userdb_copyGroup(gr));
757     }
758     endgrent();
759   }
760 }
761
762 /* --- @userdb_init@ --- *
763  *
764  * Arguments:   ---
765  *
766  * Returns:     ---
767  *
768  * Use:         Initialises the user database.
769  */
770
771 void userdb_init(void)
772 {
773   userdb__createMap(&userdb__users);
774   userdb__createMap(&userdb__groups);
775 }
776
777 /* --- @userdb_end@ --- *
778  *
779  * Arguments:   ---
780  *
781  * Returns:     ---
782  *
783  * Use:         Closes down the user database.
784  */
785
786 void userdb_end(void)
787 {
788   userdb__clearMap(&userdb__users, userdb_freeUser);
789   userdb__clearMap(&userdb__groups, userdb_freeGroup);
790 }
791
792 /*----- Test rig ----------------------------------------------------------*/
793
794 #ifdef TEST_RIG
795
796 void dumpit(const char *msg)
797 {
798   trace(TRACE_DEBUG, "debug: %s", msg);
799
800   {
801     struct passwd *pw;
802     for (userdb_iterateUsers(); (pw = userdb_nextUser()) != 0; )
803       userdb__dumpUser(pw);
804   }
805
806   {
807     struct group *gr;
808     for (userdb_iterateGroups(); (gr = userdb_nextGroup()) != 0; )
809       userdb__dumpGroup(gr);
810   }
811 }
812
813 int main(void)
814 {
815   ego("userdb-test");
816 /*   traceon(stdout, TRACE_ALL); */
817   userdb_init();
818   userdb_local();
819   userdb_yp();
820   printf("loaded (%lu)\n", track_memused());
821   getchar();
822   for (;;) {
823     userdb_end();
824     printf("cleared (%lu)\n", track_memused());
825 /*    track_memlist(); */
826     userdb_init();
827     userdb_local();
828     userdb_yp();
829     printf("reloaded (%lu)\n", track_memused());
830     getchar();
831   }
832   return (0);
833 }
834
835 #endif
836
837 /*----- That's all, folks -------------------------------------------------*/