3 * $Id: userdb.c,v 1.11 2004/04/08 01:36:20 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 /*----- Header files ------------------------------------------------------*/
31 /* --- ANSI headers --- */
39 /* --- Unix headers --- */
43 #include <sys/types.h>
49 /* --- mLib headers --- */
51 #include <mLib/alloc.h>
53 #include <mLib/trace.h>
55 /* --- Local headers --- */
61 /*----- Type definitions --------------------------------------------------*/
63 /* --- A map link --- */
65 typedef struct userdb__node {
66 struct userdb__node *next;
70 /* --- A reference to a real record --- */
72 typedef struct userdb__sym {
77 /* --- A name- and number-mapping --- */
79 typedef struct userdb__map {
85 /*----- Static variables --------------------------------------------------*/
87 static userdb__map userdb__users; /* Map of user info blocks */
88 static sym_iter userdb__useri; /* Iterator for users */
89 static userdb__map userdb__groups; /* Map of group info blocks */
90 static sym_iter userdb__groupi; /* Iterator for groups */
92 /*----- Map management functions ------------------------------------------*/
94 /* --- @userdb__createMap@ --- *
96 * Arguments: @userdb__map *m@ = pointer to a map block
100 * Use: Initialises a map table.
103 static void userdb__createMap(userdb__map *m)
105 sym_create(&m->nmap);
106 sym_create(&m->idmap);
110 /* --- @userdb__addToMap@ --- *
112 * Arguments: @userdb__map *m@ = pointer to the map block
113 * @const char *name@ = pointer to the item's name
114 * @uid_t id@ = the item's id number
115 * @void *rec@ = pointer to the actual record
119 * Use: Adds an item to the given map.
122 static void userdb__addToMap(userdb__map *m,
130 s = sym_find(&m->nmap, name, -1, sizeof(*s), &f);
134 s = sym_find(&m->idmap, (char *)&id, sizeof(id), sizeof(*s), &f);
138 n = xmalloc(sizeof(*n));
144 /* --- @userdb__byName@ --- *
146 * Arguments: @userdb__map *m@ = pointer to a map block
147 * @const char *name@ = name to look up
149 * Returns: A pointer to the appropriate block, or zero if not found.
151 * Use: Looks up a name in a mapping and returns the result.
154 static void *userdb__byName(userdb__map *m, const char *name)
156 userdb__sym *s = sym_find(&m->nmap, name, -1, 0, 0);
157 return (s ? s->rec : 0);
160 /* --- @userdb__byId@ --- *
162 * Arguments: @userdb__map *m@ = pointer to a map block
163 * @uid_t id@ = id number to find
165 * Returns: A pointer to the appropriate block, or zero if not found.
167 * Use: Looks up an ID in a mapping, and returns the result.
170 static void *userdb__byId(userdb__map *m, uid_t id)
172 userdb__sym *s = sym_find(&m->idmap, (char *)&id, sizeof(id), 0, 0);
173 return (s ? s->rec : 0);
176 /* --- @userdb__clearMap@ --- *
178 * Arguments: @userdb__map *m@ = pointer to a map block
179 * @void (*freerec)(void *rec)@ = pointer to a free-record proc
183 * Use: Clears a map, emptying it and releasing the memory it
187 static void userdb__clearMap(userdb__map *m, void (*freerec)(void *rec))
191 sym_destroy(&m->nmap);
192 sym_destroy(&m->idmap);
194 for (n = m->list; n; n = t) {
201 /*----- User and group block management -----------------------------------*/
203 /* --- @userdb__dumpUser@ --- *
205 * Arguments: @const struct passwd *pw@ = pointer to a user block
209 * Use: Writes a user's informationt to a stream.
214 static void userdb__dumpUser(const struct passwd *pw)
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);
220 "debug: ... gecos `%s' home `%s' shell `%s'",
221 pw->pw_gecos, pw->pw_dir, pw->pw_shell);
226 /* --- @userdb__split@ --- *
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
232 * Returns: Number of fields extracted.
234 * Use: Splits a string into fields at colon characters.
237 static int userdb__split(char *p, char **v, int sz)
241 *v++ = p; sz--; count++;
247 *v++ = p; sz--; count++;
259 /* --- @userdb_copyUser@ --- *
261 * Arguments: @struct passwd *pw@ = pointer to block to copy
263 * Returns: Pointer to the copy.
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.
270 struct passwd *userdb_copyUser(struct passwd *pw)
277 npw = xmalloc(sizeof(*npw));
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);
290 /* --- @userdb__buildUser@ --- *
292 * Arguments: @char *s@ = pointer to user string
294 * Returns: Pointer to a user block.
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
301 static struct passwd *userdb__buildUser(char *s)
303 struct passwd *pw = xmalloc(sizeof(*pw));
306 if (userdb__split(s, v, 7) < 7) {
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]);
321 /* --- @userdb_freeUser@ --- *
323 * Arguments: @void *rec@ = pointer to a user record
327 * Use: Frees a user record.
330 void userdb_freeUser(void *rec)
346 /* --- @userdb__dumpGroup@ --- *
348 * Arguments: @const struct group *gr@ = pointer to a group block
349 * @FILE *fp@ = pointer to stream to write on
353 * Use: Writes a group's information to a stream.
358 static void userdb__dumpGroup(const struct group *gr)
363 "debug: name `%s' passwd `%s' gid %i",
364 gr->gr_name, gr->gr_passwd, (int)gr->gr_gid);
365 for (p = gr->gr_mem; *p; p++)
366 trace(TRACE_DEBUG,"debug: ... `%s'", *p);
371 /* --- @userdb_copyGroup@ --- *
373 * Arguments: @struct group *gr@ = pointer to group block
375 * Returns: Pointer to copied block
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.
382 struct group *userdb_copyGroup(struct group *gr)
390 ngr = xmalloc(sizeof(*ngr));
392 ngr->gr_name = xstrdup(gr->gr_name);
393 ngr->gr_passwd = xstrdup(gr->gr_passwd);
394 ngr->gr_gid = gr->gr_gid;
396 for (max = 0; gr->gr_mem[max]; max++)
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;
406 /* --- @userdb__buildGroup@ --- *
408 * Arguments: @char *s@ = pointer to group line string
410 * Returns: Pointer to a group block
412 * Use: Parses an entry in the groups file. The string is garbled
413 * by @strtok@ as we go.
416 static struct group *userdb__buildGroup(char *s)
418 struct group *gr = xmalloc(sizeof(*gr));
422 /* --- Do the easy bits --- */
424 if (userdb__split(s, v, 4) < 3) {
428 gr->gr_name = xstrdup(v[0]);
429 gr->gr_passwd = xstrdup(v[1]);
430 gr->gr_gid = (gid_t)atol(v[2]);
432 /* --- Count the number of members --- */
439 if ((s = strpbrk(s, ",")) == 0)
445 /* --- Allocate the block and fill it --- */
447 gr->gr_mem = xmalloc((i + 1) * sizeof(char *));
450 s = strtok(v[3], ",");
452 gr->gr_mem[i++] = xstrdup(s);
461 /* --- @userdb_freeGroup@ --- *
463 * Arguments: @void *rec@ = pointer to a group record
467 * Use: Frees a group record.
470 void userdb_freeGroup(void *rec)
481 for (p = gr->gr_mem; *p; p++)
487 /*----- Answering queries -------------------------------------------------*/
489 /* --- @userdb_userByName@, @userdb_userById@ --- *
491 * Arguments: @const char *name@ = pointer to user's name
492 * @uid_t id@ = user id to find
494 * Returns: Pointer to user block, or zero if not found.
496 * Use: Looks up a user by name or id.
499 struct passwd *userdb_userByName(const char *name)
500 { return (userdb__byName(&userdb__users, name)); }
502 struct passwd *userdb_userById(uid_t id)
503 { return (userdb__byId(&userdb__users, id)); }
505 /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- *
507 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
511 * Use: Initialises an iteration for the user database.
514 void userdb_iterateUsers(void)
515 { userdb_iterateUsers_r(&userdb__useri); }
517 void userdb_iterateUsers_r(userdb_iter *i)
518 { sym_mkiter(i, &userdb__users.nmap); }
520 /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- *
522 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
524 * Returns: Pointer to the next user block, or null.
526 * Use: Returns another user block.
529 struct passwd *userdb_nextUser(void)
530 { return (userdb_nextUser_r(&userdb__useri)); }
532 struct passwd *userdb_nextUser_r(userdb_iter *i)
534 userdb__sym *s = sym_next(i);
535 return (s ? s->rec : 0);
538 /* --- @userdb_groupByName@, @userdb_groupById@ --- *
540 * Arguments: @const char *name@ = pointer to group's name
541 * @gid_t id@ = group id to find
543 * Returns: Pointer to group block, or zero if not found.
545 * Use: Looks up a group by name or id.
548 struct group *userdb_groupByName(const char *name)
549 { return (userdb__byName(&userdb__groups, name)); }
551 struct group *userdb_groupById(gid_t id)
552 { return (userdb__byId(&userdb__groups, id)); }
554 /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- *
556 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
560 * Use: Initialises an iteration for the group database.
563 void userdb_iterateGroups(void)
564 { userdb_iterateGroups_r(&userdb__groupi); }
566 void userdb_iterateGroups_r(userdb_iter *i)
567 { sym_mkiter(i, &userdb__groups.nmap); }
569 /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- *
571 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
573 * Returns: Pointer to the next group block, or null.
575 * Use: Returns another group block.
578 struct group *userdb_nextGroup(void)
579 { return (userdb_nextGroup_r(&userdb__groupi)); }
581 struct group *userdb_nextGroup_r(userdb_iter *i)
583 userdb__sym *s = sym_next(i);
584 return (s ? s->rec : 0);
587 /*----- Yellow pages support ----------------------------------------------*/
591 /* --- @userdb__foreachUser@ --- *
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
600 * Returns: Zero to be called again, nonzero to end the enumeration.
602 * Use: Handles an incoming user record.
605 static int userdb__foreachUser(int st, char *k, int ksz,
606 char *v, int vsz, char *data)
613 cv = xmalloc(vsz + 1);
616 T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); )
617 pw = userdb__buildUser(cv);
618 if (pw && !userdb__byName(&userdb__users, pw->pw_name)) {
619 IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); )
620 userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw);
627 /* --- @userdb__foreachGroup@ --- *
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
636 * Returns: Zero to be called again, nonzero to end the enumeration.
638 * Use: Handles an incoming user record.
641 static int userdb__foreachGroup(int st, char *k, int ksz,
642 char *v, int vsz, char *data)
649 cv = xmalloc(vsz + 1);
652 T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); )
653 gr = userdb__buildGroup(cv);
654 if (gr && !userdb__byName(&userdb__groups, gr->gr_name)) {
655 IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); )
656 userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr);
658 userdb_freeGroup(gr);
663 /* --- @userdb_yp@ --- *
669 * Use: Fetches the YP database of users.
674 /* --- Bind to a server --- */
680 T( trace(TRACE_DEBUG, "debug: adding NIS users"); )
682 /* --- Fetch the users map --- */
685 static struct ypall_callback ucb = { userdb__foreachUser, 0 };
686 yp_all(yp_domain, "passwd.byuid", &ucb);
689 /* --- Fetch the groups map --- */
692 static struct ypall_callback gcb = { userdb__foreachGroup, 0 };
693 yp_all(yp_domain, "group.bygid", &gcb);
699 void userdb_yp(void) { ; }
703 /*----- Building the databases --------------------------------------------*/
705 /* --- @userdb_local@ --- *
711 * Use: Reads the local list of users into the maps.
714 void userdb_local(void)
716 T( trace(TRACE_DEBUG, "debug: adding local users"); )
718 /* --- Fetch users first --- */
724 while ((pw = getpwent()) != 0) {
725 IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); )
726 if (!userdb__byName(&userdb__users, pw->pw_name))
727 userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid,
728 userdb_copyUser(pw));
733 /* --- Then fetch groups --- */
739 while ((gr = getgrent()) != 0) {
740 IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); )
741 if (!userdb__byName(&userdb__groups, gr->gr_name))
742 userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid,
743 userdb_copyGroup(gr));
749 /* --- @userdb_init@ --- *
755 * Use: Initialises the user database.
758 void userdb_init(void)
760 userdb__createMap(&userdb__users);
761 userdb__createMap(&userdb__groups);
764 /* --- @userdb_end@ --- *
770 * Use: Closes down the user database.
773 void userdb_end(void)
775 userdb__clearMap(&userdb__users, userdb_freeUser);
776 userdb__clearMap(&userdb__groups, userdb_freeGroup);
779 /*----- Test rig ----------------------------------------------------------*/
783 void dumpit(const char *msg)
785 trace(TRACE_DEBUG, "debug: %s", msg);
789 for (userdb_iterateUsers(); (pw = userdb_nextUser()) != 0; )
790 userdb__dumpUser(pw);
795 for (userdb_iterateGroups(); (gr = userdb_nextGroup()) != 0; )
796 userdb__dumpGroup(gr);
803 trace_on(stdout, TRACE_ALL);
808 /* printf("loaded (%lu)\n", track_memused()); */
812 /* printf("cleared (%lu)\n", track_memused()); */
813 /* track_memlist(); */
817 /* printf("reloaded (%lu)\n", track_memused()); */
825 /*----- That's all, folks -------------------------------------------------*/