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