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