3 * $Id: userdb.c,v 1.4 1997/08/20 16:24:58 mdw Exp $
5 * User database management
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of `become'
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.
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.
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.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.4 1997/08/20 16:24:58 mdw
33 * Patch memory leak. Rename `userdb_reinit' to `userdb_end' for more
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.
40 * Revision 1.2 1997/08/04 10:24:26 mdw
41 * Sources placed under CVS control.
43 * Revision 1.1 1997/07/21 13:47:43 mdw
48 /*----- Header files ------------------------------------------------------*/
50 /* --- ANSI headers --- */
58 /* --- Unix headers --- */
62 #include <sys/types.h>
66 # include <rpcsvc/ypclnt.h>
67 # include <rpcsvc/yp_prot.h>
74 /* --- Local headers --- */
81 /*----- Type definitions --------------------------------------------------*/
83 /* --- A map link --- */
85 typedef struct userdb__node
{
86 struct userdb__node
*next
;
90 /* --- A reference to a real record --- */
92 typedef struct userdb__sym
{
97 /* --- A name- and number-mapping --- */
99 typedef struct userdb__map
{
105 /*----- Static variables --------------------------------------------------*/
107 static userdb__map userdb__users
; /* Map of user info blocks */
108 static sym_iter userdb__useri
; /* Iterator for users */
109 static userdb__map userdb__groups
; /* Map of group info blocks */
110 static sym_iter userdb__groupi
; /* Iterator for groups */
112 /*----- Map management functions ------------------------------------------*/
114 /* --- @userdb__createMap@ --- *
116 * Arguments: @userdb__map *m@ = pointer to a map block
120 * Use: Initialises a map table.
123 static void userdb__createMap(userdb__map
*m
)
125 sym_createTable(&m
->nmap
);
126 sym_createTable(&m
->idmap
);
130 /* --- @userdb__addToMap@ --- *
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
139 * Use: Adds an item to the given map.
142 static void userdb__addToMap(userdb__map
*m
,
150 s
= sym_find(&m
->nmap
, name
, -1, sizeof(*s
), &f
);
154 s
= sym_find(&m
->idmap
, (char *)&id
, sizeof(id
), sizeof(*s
), &f
);
158 n
= xmalloc(sizeof(*n
));
164 /* --- @userdb__byName@ --- *
166 * Arguments: @userdb__map *m@ = pointer to a map block
167 * @const char *name@ = name to look up
169 * Returns: A pointer to the appropriate block, or zero if not found.
171 * Use: Looks up a name in a mapping and returns the result.
174 static void *userdb__byName(userdb__map
*m
, const char *name
)
176 userdb__sym
*s
= sym_find(&m
->nmap
, name
, -1, 0, 0);
177 return (s ? s
->rec
: 0);
180 /* --- @userdb__byId@ --- *
182 * Arguments: @userdb__map *m@ = pointer to a map block
183 * @int id@ = id number to find
185 * Returns: A pointer to the appropriate block, or zero if not found.
187 * Use: Looks up an ID in a mapping, and returns the result.
190 static void *userdb__byId(userdb__map
*m
, int id
)
192 userdb__sym
*s
= sym_find(&m
->idmap
, (char *)&id
, sizeof(id
), 0, 0);
193 return (s ? s
->rec
: 0);
196 /* --- @userdb__clearMap@ --- *
198 * Arguments: @userdb__map *m@ = pointer to a map block
199 * @void (*freerec)(void *rec)@ = pointer to a free-record proc
203 * Use: Clears a map, emptying it and releasing the memory it
207 static void userdb__clearMap(userdb__map
*m
, void (*freerec
)(void *rec
))
211 sym_destroyTable(&m
->nmap
);
212 sym_destroyTable(&m
->idmap
);
214 for (n
= m
->list
; n
; n
= t
) {
221 /*----- User and group block management -----------------------------------*/
223 /* --- @userdb__dumpUser@ --- *
225 * Arguments: @const struct passwd *pw@ = pointer to a user block
229 * Use: Writes a user's informationt to a stream.
234 static void userdb__dumpUser(const struct passwd
*pw
)
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
);
240 "debug: ... gecos `%s' home `%s' shell `%s'",
241 pw
->pw_gecos
, pw
->pw_dir
, pw
->pw_shell
);
246 /* --- @userdb_copyUser@ --- *
248 * Arguments: @struct passwd *pw@ = pointer to block to copy
250 * Returns: Pointer to the copy.
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.
257 struct passwd
*userdb_copyUser(struct passwd
*pw
)
264 npw
= xmalloc(sizeof(*npw
));
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
);
277 /* --- @userdb__buildUser@ --- *
279 * Arguments: @char *s@ = pointer to user string
281 * Returns: Pointer to a user block.
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
288 static struct passwd
*userdb__buildUser(char *s
)
290 struct passwd
*pw
= xmalloc(sizeof(*pw
));
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
);
301 /* --- Error handling --- */
317 /* --- @userdb_freeUser@ --- *
319 * Arguments: @void *rec@ = pointer to a user record
323 * Use: Frees a user record.
326 void userdb_freeUser(void *rec
)
342 /* --- @userdb__dumpGroup@ --- *
344 * Arguments: @const struct group *gr@ = pointer to a group block
345 * @FILE *fp@ = pointer to stream to write on
349 * Use: Writes a group's information to a stream.
354 static void userdb__dumpGroup(const struct group
*gr
)
359 "debug: name `%s' passwd `%s' gid %i",
360 gr
->gr_name
, gr
->gr_passwd
, (int)gr
->gr_gid
);
361 for (p
= gr
->gr_mem
; *p
; p
++)
362 trace(TRACE_DEBUG
,"debug: ... `%s'", *p
);
367 /* --- @userdb_copyGroup@ --- *
369 * Arguments: @struct group *gr@ = pointer to group block
371 * Returns: Pointer to copied block
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.
378 struct group
*userdb_copyGroup(struct group
*gr
)
386 ngr
= xmalloc(sizeof(*ngr
));
388 ngr
->gr_name
= xstrdup(gr
->gr_name
);
389 ngr
->gr_passwd
= xstrdup(gr
->gr_passwd
);
390 ngr
->gr_gid
= gr
->gr_gid
;
392 for (max
= 0; gr
->gr_mem
[max
]; max
++)
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;
402 /* --- @userdb__buildGroup@ --- *
404 * Arguments: @char *s@ = pointer to group line string
406 * Returns: Pointer to a group block
408 * Use: Parses an entry in the groups file. The string is garbled
409 * by @strtok@ as we go.
412 static struct group
*userdb__buildGroup(char *s
)
414 struct group
*gr
= xmalloc(sizeof(*gr
));
418 /* --- Do the easy bits --- */
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
);
424 /* --- Find the start of the member list --- */
430 /* --- Count the number of members --- */
436 if ((p
= strpbrk(p
, ",")) == 0)
441 /* --- Allocate the block and fill it --- */
443 gr
->gr_mem
= xmalloc((i
+ 1) * sizeof(char *));
447 gr
->gr_mem
[i
++] = xstrdup(s
);
454 /* --- Various tidying-up things --- */
466 /* --- @userdb_freeGroup@ --- *
468 * Arguments: @void *rec@ = pointer to a group record
472 * Use: Frees a group record.
475 void userdb_freeGroup(void *rec
)
486 for (p
= gr
->gr_mem
; *p
; p
++)
492 /*----- Answering queries -------------------------------------------------*/
494 /* --- @userdb_userByName@, @userdb_userById@ --- *
496 * Arguments: @const char *name@ = pointer to user's name
497 * @uid_t id@ = user id to find
499 * Returns: Pointer to user block, or zero if not found.
501 * Use: Looks up a user by name or id.
504 struct passwd
*userdb_userByName(const char *name
)
505 { return (userdb__byName(&userdb__users
, name
)); }
507 struct passwd
*userdb_userById(uid_t id
)
508 { return (userdb__byId(&userdb__users
, id
)); }
510 /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- *
512 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
516 * Use: Initialises an iteration for the user database.
519 void userdb_iterateUsers(void)
520 { userdb_iterateUsers_r(&userdb__useri
); }
522 void userdb_iterateUsers_r(userdb_iter
*i
)
523 { sym_createIter(i
, &userdb__users
.nmap
); }
525 /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- *
527 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
529 * Returns: Pointer to the next user block, or null.
531 * Use: Returns another user block.
534 struct passwd
*userdb_nextUser(void)
535 { return (userdb_nextUser_r(&userdb__useri
)); }
537 struct passwd
*userdb_nextUser_r(userdb_iter
*i
)
539 userdb__sym
*s
= sym_next(i
);
540 return (s ? s
->rec
: 0);
543 /* --- @userdb_groupByName@, @userdb_groupById@ --- *
545 * Arguments: @const char *name@ = pointer to group's name
546 * @gid_t id@ = group id to find
548 * Returns: Pointer to group block, or zero if not found.
550 * Use: Looks up a group by name or id.
553 struct group
*userdb_groupByName(const char *name
)
554 { return (userdb__byName(&userdb__groups
, name
)); }
556 struct group
*userdb_groupById(gid_t id
)
557 { return (userdb__byId(&userdb__groups
, id
)); }
559 /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- *
561 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
565 * Use: Initialises an iteration for the group database.
568 void userdb_iterateGroups(void)
569 { userdb_iterateGroups_r(&userdb__groupi
); }
571 void userdb_iterateGroups_r(userdb_iter
*i
)
572 { sym_createIter(i
, &userdb__groups
.nmap
); }
574 /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- *
576 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
578 * Returns: Pointer to the next group block, or null.
580 * Use: Returns another group block.
583 struct group
*userdb_nextGroup(void)
584 { return (userdb_nextGroup_r(&userdb__groupi
)); }
586 struct group
*userdb_nextGroup_r(userdb_iter
*i
)
588 userdb__sym
*s
= sym_next(i
);
589 return (s ? s
->rec
: 0);
592 /*----- Yellow pages support ----------------------------------------------*/
596 /* --- @userdb__foreachUser@ --- *
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
605 * Returns: Zero to be called again, nonzero to end the enumeration.
607 * Use: Handles an incoming user record.
610 static int userdb__foreachUser(int st
, char *k
, int ksz
,
611 char *v
, int vsz
, char *data
)
618 cv
= xmalloc(vsz
+ 1);
621 T( trace(TRACE_DEBUG
, "debug: nis string: `%s'", cv
); )
622 pw
= userdb__buildUser(cv
);
623 if (pw
&& !userdb__byName(&userdb__users
, pw
->pw_name
)) {
624 IF_TRACING(TRACE_DEBUG
, userdb__dumpUser(pw
); )
625 userdb__addToMap(&userdb__users
, pw
->pw_name
, pw
->pw_uid
, pw
);
632 /* --- @userdb__foreachGroup@ --- *
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
641 * Returns: Zero to be called again, nonzero to end the enumeration.
643 * Use: Handles an incoming user record.
646 static int userdb__foreachGroup(int st
, char *k
, int ksz
,
647 char *v
, int vsz
, char *data
)
654 cv
= xmalloc(vsz
+ 1);
657 T( trace(TRACE_DEBUG
, "debug: nis string: `%s'", cv
); )
658 gr
= userdb__buildGroup(cv
);
659 if (gr
&& !userdb__byName(&userdb__groups
, gr
->gr_name
)) {
660 IF_TRACING(TRACE_DEBUG
, userdb__dumpGroup(gr
); )
661 userdb__addToMap(&userdb__groups
, gr
->gr_name
, gr
->gr_gid
, gr
);
663 userdb_freeGroup(gr
);
668 /* --- @userdb_yp@ --- *
674 * Use: Fetches the YP database of users.
681 /* --- Bind to a server --- */
683 if (yp_get_default_domain(&ypdom
) ||
687 T( trace(TRACE_DEBUG
, "debug: adding NIS users"); )
689 /* --- Fetch the users map --- */
692 static struct ypall_callback ucb
= { userdb__foreachUser
, 0 };
693 yp_all(ypdom
, "passwd.byuid", &ucb
);
696 /* --- Fetch the groups map --- */
699 static struct ypall_callback gcb
= { userdb__foreachGroup
, 0 };
700 yp_all(ypdom
, "group.bygid", &gcb
);
708 void userdb_yp(void) { ; }
712 /*----- Building the databases --------------------------------------------*/
714 /* --- @userdb_local@ --- *
720 * Use: Reads the local list of users into the maps.
723 void userdb_local(void)
725 T( trace(TRACE_DEBUG
, "debug: adding local users"); )
727 /* --- Fetch users first --- */
733 while ((pw
= getpwent()) != 0) {
734 IF_TRACING(TRACE_DEBUG
, userdb__dumpUser(pw
); )
735 if (!userdb__byName(&userdb__users
, pw
->pw_name
))
736 userdb__addToMap(&userdb__users
, pw
->pw_name
, pw
->pw_uid
,
737 userdb_copyUser(pw
));
742 /* --- Then fetch groups --- */
748 while ((gr
= getgrent()) != 0) {
749 IF_TRACING(TRACE_DEBUG
, userdb__dumpGroup(gr
); )
750 if (!userdb__byName(&userdb__groups
, gr
->gr_name
))
751 userdb__addToMap(&userdb__groups
, gr
->gr_name
, gr
->gr_gid
,
752 userdb_copyGroup(gr
));
758 /* --- @userdb_init@ --- *
764 * Use: Initialises the user database.
767 void userdb_init(void)
769 userdb__createMap(&userdb__users
);
770 userdb__createMap(&userdb__groups
);
773 /* --- @userdb_end@ --- *
779 * Use: Closes down the user database.
782 void userdb_end(void)
784 userdb__clearMap(&userdb__users
, userdb_freeUser
);
785 userdb__clearMap(&userdb__groups
, userdb_freeGroup
);
788 /*----- Test rig ----------------------------------------------------------*/
792 void dumpit(const char *msg
)
794 trace(TRACE_DEBUG
, "debug: %s", msg
);
798 for (userdb_iterateUsers(); (pw
= userdb_nextUser()) != 0; )
799 userdb__dumpUser(pw
);
804 for (userdb_iterateGroups(); (gr
= userdb_nextGroup()) != 0; )
805 userdb__dumpGroup(gr
);
812 /* traceon(stdout, TRACE_ALL); */
816 printf("loaded (%lu)\n", track_memused());
820 printf("cleared (%lu)\n", track_memused());
821 /* track_memlist(); */
825 printf("reloaded (%lu)\n", track_memused());
833 /*----- That's all, folks -------------------------------------------------*/