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