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