3 * $Id: userdb.c,v 1.2 1997/08/04 10:24:26 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.2 1997/08/04 10:24:26 mdw
33 * Sources placed under CVS control.
35 * Revision 1.1 1997/07/21 13:47:43 mdw
40 /*----- Header files ------------------------------------------------------*/
42 /* --- ANSI headers --- */
50 /* --- Unix headers --- */
54 #include <sys/types.h>
57 # include <rpcsvc/ypclnt.h>
58 # include <rpcsvc/yp_prot.h>
65 /* --- Local headers --- */
71 /*----- Type definitions --------------------------------------------------*/
73 /* --- A map link --- */
75 typedef struct userdb__node {
76 struct userdb__node *next;
80 /* --- A reference to a real record --- */
82 typedef struct userdb__sym {
87 /* --- A name- and number-mapping --- */
89 typedef struct userdb__map {
95 /*----- Static variables --------------------------------------------------*/
97 static userdb__map userdb__users; /* Map of user info blocks */
98 static sym_iter userdb__useri; /* Iterator for users */
99 static userdb__map userdb__groups; /* Map of group info blocks */
100 static sym_iter userdb__groupi; /* Iterator for groups */
102 /*----- Map management functions ------------------------------------------*/
104 /* --- @userdb__createMap@ --- *
106 * Arguments: @userdb__map *m@ = pointer to a map block
110 * Use: Initialises a map table.
113 static void userdb__createMap(userdb__map *m)
115 sym_createTable(&m->nmap);
116 sym_createTable(&m->idmap);
120 /* --- @userdb__addToMap@ --- *
122 * Arguments: @userdb__map *m@ = pointer to the map block
123 * @const char *name@ = pointer to the item's name
124 * @int id@ = the item's id number
125 * @void *rec@ = pointer to the actual record
129 * Use: Adds an item to the given map.
132 static void userdb__addToMap(userdb__map *m,
140 s = sym_find(&m->nmap, name, -1, sizeof(*s), &f);
144 s = sym_find(&m->idmap, (char *)&id, sizeof(id), sizeof(*s), &f);
148 n = xmalloc(sizeof(*n));
154 /* --- @userdb__byName@ --- *
156 * Arguments: @userdb__map *m@ = pointer to a map block
157 * @const char *name@ = name to look up
159 * Returns: A pointer to the appropriate block, or zero if not found.
161 * Use: Looks up a name in a mapping and returns the result.
164 static void *userdb__byName(userdb__map *m, const char *name)
166 userdb__sym *s = sym_find(&m->nmap, name, -1, 0, 0);
167 return (s ? s->rec : 0);
170 /* --- @userdb__byId@ --- *
172 * Arguments: @userdb__map *m@ = pointer to a map block
173 * @int id@ = id number to find
175 * Returns: A pointer to the appropriate block, or zero if not found.
177 * Use: Looks up an ID in a mapping, and returns the result.
180 static void *userdb__byId(userdb__map *m, int id)
182 userdb__sym *s = sym_find(&m->idmap, (char *)&id, sizeof(id), 0, 0);
183 return (s ? s->rec : 0);
186 /* --- @userdb__clearMap@ --- *
188 * Arguments: @userdb__map *m@ = pointer to a map block
189 * @void (*freerec)(void *rec)@ = pointer to a free-record proc
193 * Use: Clears a map, emptying it and releasing the memory it
197 static void userdb__clearMap(userdb__map *m, void (*freerec)(void *rec))
201 sym_destroyTable(&m->nmap);
202 sym_destroyTable(&m->idmap);
204 for (n = m->list; n; n = t) {
211 /*----- User and group block management -----------------------------------*/
213 /* --- @userdb__dumpUser@ --- *
215 * Arguments: @const struct passwd *pw@ = pointer to a user block
216 * @FILE *fp@ = pointer to stream to write on
220 * Use: Writes a user's informationt to a stream.
225 static void userdb__dumpUser(const struct passwd *pw, FILE *fp)
235 pw->pw_name, pw->pw_passwd, (int)pw->pw_uid, (int)pw->pw_gid,
236 pw->pw_gecos, pw->pw_dir, pw->pw_shell);
241 #define userdb__dumpUser(pw, fp) ((void)0)
245 /* --- @userdb_copyUser@ --- *
247 * Arguments: @struct passwd *pw@ = pointer to block to copy
249 * Returns: Pointer to the copy.
251 * Use: Copies a user block. The copy is `deep' so all the strings
252 * are copied too. Free the copy with @userdb_freeUser@ when
253 * you don't want it any more.
256 struct passwd *userdb_copyUser(struct passwd *pw)
263 npw = xmalloc(sizeof(*npw));
265 npw->pw_name = xstrdup(pw->pw_name);
266 npw->pw_passwd = xstrdup(pw->pw_passwd);
267 npw->pw_uid = pw->pw_uid;
268 npw->pw_gid = pw->pw_gid;
269 npw->pw_gecos = xstrdup(pw->pw_gecos);
270 npw->pw_dir = xstrdup(pw->pw_dir);
271 npw->pw_shell = xstrdup(pw->pw_shell);
276 /* --- @userdb__buildUser@ --- *
278 * Arguments: @char *s@ = pointer to user string
280 * Returns: Pointer to a user block.
282 * Use: Converts a line from a user file into a password entry.
283 * Note that the string is corrupted by @strtok@ while it gets
287 static struct passwd *userdb__buildUser(char *s)
289 struct passwd *pw = xmalloc(sizeof(*pw));
291 s = strtok(s, ":"); if (!s) goto tidy_0; pw->pw_name = xstrdup(s);
292 s = strtok(0, ":"); if (!s) goto tidy_1; pw->pw_passwd = xstrdup(s);
293 s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_uid = atoi(s);
294 s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_gid = atoi(s);
295 s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_gecos = xstrdup(s);
296 s = strtok(0, ":"); if (!s) goto tidy_3; pw->pw_dir = xstrdup(s);
297 s = strtok(0, ":"); if (!s) goto tidy_4; pw->pw_shell = xstrdup(s);
300 /* --- Error handling --- */
316 /* --- @userdb_freeUser@ --- *
318 * Arguments: @void *rec@ = pointer to a user record
322 * Use: Frees a user record.
325 void userdb_freeUser(void *rec)
341 /* --- @userdb__dumpGroup@ --- *
343 * Arguments: @const struct group *gr@ = pointer to a group block
344 * @FILE *fp@ = pointer to stream to write on
348 * Use: Writes a group's information to a stream.
353 static void userdb__dumpGroup(const struct group *gr, FILE *fp)
362 gr->gr_name, gr->gr_passwd, (int)gr->gr_gid);
363 for (p = gr->gr_mem; *p; p++)
364 printf("*** %s\n", *p);
369 #define userdb__dumpUser(pw, fp) ((void)0)
373 /* --- @userdb_copyGroup@ --- *
375 * Arguments: @struct group *gr@ = pointer to group block
377 * Returns: Pointer to copied block
379 * Use: Copies a group block. The copy is `deep' so all the strings
380 * are copied too. Free the copy with @userdb_freeGroup@ when
381 * you don't want it any more.
384 struct group *userdb_copyGroup(struct group *gr)
392 ngr = xmalloc(sizeof(*ngr));
394 ngr->gr_name = xstrdup(gr->gr_name);
395 ngr->gr_passwd = xstrdup(gr->gr_passwd);
396 ngr->gr_gid = gr->gr_gid;
398 for (max = 0; gr->gr_mem[max]; max++)
400 ngr->gr_mem = xmalloc((max + 1) * sizeof(char *));
401 for (i = 0; i < max; i++)
402 ngr->gr_mem[i] = xstrdup(gr->gr_mem[i]);
403 ngr->gr_mem[max] = 0;
408 /* --- @userdb__buildGroup@ --- *
410 * Arguments: @char *s@ = pointer to group line string
412 * Returns: Pointer to a group block
414 * Use: Parses an entry in the groups file. The string is garbled
415 * by @strtok@ as we go.
418 static struct group *userdb__buildGroup(char *s)
420 struct group *gr = xmalloc(sizeof(*gr));
424 /* --- Do the easy bits --- */
426 s = strtok(s, ":"); if (!s) goto tidy_0; gr->gr_name = xstrdup(s);
427 s = strtok(0, ":"); if (!s) goto tidy_1; gr->gr_passwd = xstrdup(s);
428 s = strtok(0, ":"); if (!s) goto tidy_2; gr->gr_gid = atoi(s);
430 /* --- Find the start of the member list --- */
436 /* --- Count the number of members --- */
442 if ((p = strpbrk(p, ",")) == 0)
447 /* --- Allocate the block and fill it --- */
449 gr->gr_mem = xmalloc((i + 1) * sizeof(char *));
453 gr->gr_mem[i++] = xstrdup(s);
460 /* --- Various tidying-up things --- */
472 /* --- @userdb_freeGroup@ --- *
474 * Arguments: @void *rec@ = pointer to a group record
478 * Use: Frees a group record.
481 void userdb_freeGroup(void *rec)
492 for (p = gr->gr_mem; *p; p++)
498 /*----- Answering queries -------------------------------------------------*/
500 /* --- @userdb_userByName@, @userdb_userById@ --- *
502 * Arguments: @const char *name@ = pointer to user's name
503 * @uid_t id@ = user id to find
505 * Returns: Pointer to user block, or zero if not found.
507 * Use: Looks up a user by name or id.
510 struct passwd *userdb_userByName(const char *name)
511 { return (userdb__byName(&userdb__users, name)); }
513 struct passwd *userdb_userById(uid_t id)
514 { return (userdb__byId(&userdb__users, id)); }
516 /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- *
518 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
522 * Use: Initialises an iteration for the user database.
525 void userdb_iterateUsers(void)
526 { userdb_iterateUsers_r(&userdb__useri); }
528 void userdb_iterateUsers_r(userdb_iter *i)
529 { sym_createIter(i, &userdb__users.nmap); }
531 /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- *
533 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
535 * Returns: Pointer to the next user block, or null.
537 * Use: Returns another user block.
540 struct passwd *userdb_nextUser(void)
541 { return (userdb_nextUser_r(&userdb__useri)); }
543 struct passwd *userdb_nextUser_r(userdb_iter *i)
545 userdb__sym *s = sym_next(i);
546 return (s ? s->rec : 0);
549 /* --- @userdb_groupByName@, @userdb_groupById@ --- *
551 * Arguments: @const char *name@ = pointer to group's name
552 * @gid_t id@ = group id to find
554 * Returns: Pointer to group block, or zero if not found.
556 * Use: Looks up a group by name or id.
559 struct group *userdb_groupByName(const char *name)
560 { return (userdb__byName(&userdb__groups, name)); }
562 struct group *userdb_groupById(gid_t id)
563 { return (userdb__byId(&userdb__groups, id)); }
565 /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- *
567 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
571 * Use: Initialises an iteration for the group database.
574 void userdb_iterateGroups(void)
575 { userdb_iterateGroups_r(&userdb__groupi); }
577 void userdb_iterateGroups_r(userdb_iter *i)
578 { sym_createIter(i, &userdb__groups.nmap); }
580 /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- *
582 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
584 * Returns: Pointer to the next group block, or null.
586 * Use: Returns another group block.
589 struct group *userdb_nextGroup(void)
590 { return (userdb_nextGroup_r(&userdb__groupi)); }
592 struct group *userdb_nextGroup_r(userdb_iter *i)
594 userdb__sym *s = sym_next(i);
595 return (s ? s->rec : 0);
598 /*----- Yellow pages support ----------------------------------------------*/
602 /* --- @userdb__foreachUser@ --- *
604 * Arguments: @int st@ = YP protocol-level status code
605 * @char *k@ = address of the key for this record
606 * @int ksz@ = size of the key
607 * @char *v@ = address of the value for this record
608 * @int vsz@ = size of the value
609 * @char *data@ = pointer to some data passed to me
611 * Returns: Zero to be called again, nonzero to end the enumeration.
613 * Use: Handles an incoming user record.
616 static int userdb__foreachUser(int st, char *k, int ksz,
617 char *v, int vsz, char *data)
624 cv = xmalloc(vsz + 1);
627 pw = userdb__buildUser(cv);
628 if (pw && !userdb__byName(&userdb__users, pw->pw_name))
629 userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw);
634 /* --- @userdb__foreachGroup@ --- *
636 * Arguments: @int st@ = YP protocol-level status code
637 * @char *k@ = address of the key for this record
638 * @int ksz@ = size of the key
639 * @char *v@ = address of the value for this record
640 * @int vsz@ = size of the value
641 * @char *data@ = pointer to some data passed to me
643 * Returns: Zero to be called again, nonzero to end the enumeration.
645 * Use: Handles an incoming user record.
648 static int userdb__foreachGroup(int st, char *k, int ksz,
649 char *v, int vsz, char *data)
656 cv = xmalloc(vsz + 1);
659 gr = userdb__buildGroup(cv);
660 if (gr && !userdb__byName(&userdb__groups, gr->gr_name))
661 userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr);
666 /* --- @userdb_yp@ --- *
672 * Use: Fetches the YP database of users.
679 /* --- Bind to a server --- */
681 if (yp_get_default_domain(&ypdom) ||
685 /* --- Fetch the users map --- */
688 static struct ypall_callback ucb = { userdb__foreachUser, 0 };
689 yp_all(ypdom, "passwd.byuid", &ucb);
692 /* --- Fetch the groups map --- */
695 static struct ypall_callback gcb = { userdb__foreachGroup, 0 };
696 yp_all(ypdom, "group.bygid", &gcb);
705 void userdb_yp(void) { ; }
709 /*----- Building the databases --------------------------------------------*/
711 /* --- @userdb_local@ --- *
717 * Use: Reads the local list of users into the maps.
720 void userdb_local(void)
722 D( printf("adding local users...\n"); )
724 /* --- Fetch users first --- */
730 while ((pw = getpwent()) != 0) {
731 D( userdb__dumpUser(pw, stdout); )
732 if (!userdb__byName(&userdb__users, pw->pw_name))
733 userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid,
734 userdb_copyUser(pw));
739 /* --- Then fetch groups --- */
745 while ((gr = getgrent()) != 0) {
746 D( userdb__dumpGroup(gr, stdout); )
747 if (!userdb__byName(&userdb__groups, gr->gr_name))
748 userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid,
749 userdb_copyGroup(gr));
755 /* --- @userdb_init@ --- *
761 * Use: Initialises the user database.
764 void userdb_init(void)
766 userdb__createMap(&userdb__users);
767 userdb__createMap(&userdb__groups);
770 /* --- @userdb_reinit@ --- *
776 * Use: Reinitialises the user database.
779 void userdb_reinit(void)
781 userdb__clearMap(&userdb__users, userdb_freeUser);
782 userdb__clearMap(&userdb__groups, userdb_freeGroup);
786 /*----- Test rig ----------------------------------------------------------*/
790 void dumpit(const char *msg)
792 printf("\n\n$$$ %s\n", msg);
796 for (userdb_iterateUsers(); (pw = userdb_nextUser()) != 0; )
797 userdb__dumpUser(pw, stdout);
802 for (userdb_iterateGroups(); (gr = userdb_nextGroup()) != 0; )
803 userdb__dumpGroup(gr, stdout);
820 /*----- That's all, folks -------------------------------------------------*/