3 * $Id: userdb.c,v 1.1 1997/07/21 13:47:43 mdw Exp $
5 * User database management
10 /*----- Licencing 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
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.1 1997/07/21 13:47:43 mdw
37 /*----- Header files ------------------------------------------------------*/
39 /* --- ANSI headers --- */
47 /* --- Unix headers --- */
49 #include <sys/types.h>
55 /* --- Local headers --- */
62 /*----- Type definitions --------------------------------------------------*/
64 /* --- A map link --- */
66 typedef struct userdb__node
{
67 struct userdb__node
*next
;
71 /* --- A reference to a real record --- */
73 typedef struct userdb__sym
{
78 /* --- A name- and number-mapping --- */
80 typedef struct userdb__map
{
86 /*----- Static variables --------------------------------------------------*/
88 static userdb__map userdb__users
; /* Map of user info blocks */
89 static sym_iter userdb__useri
; /* Iterator for users */
90 static userdb__map userdb__groups
; /* Map of group info blocks */
91 static sym_iter userdb__groupi
; /* Iterator for groups */
93 /*----- Map management functions ------------------------------------------*/
95 /* --- @userdb__createMap@ --- *
97 * Arguments: @userdb__map *m@ = pointer to a map block
101 * Use: Initialises a map table.
104 static void userdb__createMap(userdb__map
*m
)
106 sym_createTable(&m
->nmap
);
107 sym_createTable(&m
->idmap
);
111 /* --- @userdb__addToMap@ --- *
113 * Arguments: @userdb__map *m@ = pointer to the map block
114 * @const char *name@ = pointer to the item's name
115 * @int id@ = the item's id number
116 * @void *rec@ = pointer to the actual record
120 * Use: Adds an item to the given map.
123 static void userdb__addToMap(userdb__map
*m
,
131 s
= sym_find(&m
->nmap
, name
, -1, sizeof(*s
), &f
);
135 s
= sym_find(&m
->idmap
, (char *)&id
, sizeof(id
), sizeof(*s
), &f
);
139 n
= xmalloc(sizeof(*n
));
145 /* --- @userdb__byName@ --- *
147 * Arguments: @userdb__map *m@ = pointer to a map block
148 * @const char *name@ = name to look up
150 * Returns: A pointer to the appropriate block, or zero if not found.
152 * Use: Looks up a name in a mapping and returns the result.
155 static void *userdb__byName(userdb__map
*m
, const char *name
)
157 userdb__sym
*s
= sym_find(&m
->nmap
, name
, -1, 0, 0);
158 return (s ? s
->rec
: 0);
161 /* --- @userdb__byId@ --- *
163 * Arguments: @userdb__map *m@ = pointer to a map block
164 * @int id@ = id number to find
166 * Returns: A pointer to the appropriate block, or zero if not found.
168 * Use: Looks up an ID in a mapping, and returns the result.
171 static void *userdb__byId(userdb__map
*m
, int id
)
173 userdb__sym
*s
= sym_find(&m
->idmap
, (char *)&id
, sizeof(id
), 0, 0);
174 return (s ? s
->rec
: 0);
177 /* --- @userdb__clearMap@ --- *
179 * Arguments: @userdb__map *m@ = pointer to a map block
180 * @void (*freerec)(void *rec)@ = pointer to a free-record proc
184 * Use: Clears a map, emptying it and releasing the memory it
188 static void userdb__clearMap(userdb__map
*m
, void (*freerec
)(void *rec
))
192 sym_destroyTable(&m
->nmap
);
193 sym_destroyTable(&m
->idmap
);
195 for (n
= m
->list
; n
; n
= t
) {
202 /*----- User and group block management -----------------------------------*/
204 /* --- @userdb__dumpUser@ --- *
206 * Arguments: @const struct passwd *pw@ = pointer to a user block
207 * @FILE *fp@ = pointer to stream to write on
211 * Use: Writes a user's informationt to a stream.
216 static void userdb__dumpUser(const struct passwd
*pw
, FILE *fp
)
226 pw
->pw_name
, pw
->pw_passwd
, (int)pw
->pw_uid
, (int)pw
->pw_gid
,
227 pw
->pw_gecos
, pw
->pw_dir
, pw
->pw_shell
);
232 #define userdb__dumpUser(pw, fp) ((void)0)
236 /* --- @userdb_copyUser@ --- *
238 * Arguments: @struct passwd *pw@ = pointer to block to copy
240 * Returns: Pointer to the copy.
242 * Use: Copies a user block. The copy is `deep' so all the strings
243 * are copied too. Free the copy with @userdb_freeUser@ when
244 * you don't want it any more.
247 struct passwd
*userdb_copyUser(struct passwd
*pw
)
254 npw
= xmalloc(sizeof(*npw
));
256 npw
->pw_name
= xstrdup(pw
->pw_name
);
257 npw
->pw_passwd
= xstrdup(pw
->pw_passwd
);
258 npw
->pw_uid
= pw
->pw_uid
;
259 npw
->pw_gid
= pw
->pw_gid
;
260 npw
->pw_gecos
= xstrdup(pw
->pw_gecos
);
261 npw
->pw_dir
= xstrdup(pw
->pw_dir
);
262 npw
->pw_shell
= xstrdup(pw
->pw_shell
);
267 /* --- @userdb__buildUser@ --- *
269 * Arguments: @char *s@ = pointer to user string
271 * Returns: Pointer to a user block.
273 * Use: Converts a line from a user file into a password entry.
274 * Note that the string is corrupted by @strtok@ while it gets
278 static struct passwd
*userdb__buildUser(char *s
)
280 struct passwd
*pw
= xmalloc(sizeof(*pw
));
282 s
= strtok(s
, ":"); if (!s
) goto tidy_0
; pw
->pw_name
= xstrdup(s
);
283 s
= strtok(0, ":"); if (!s
) goto tidy_1
; pw
->pw_passwd
= xstrdup(s
);
284 s
= strtok(0, ":"); if (!s
) goto tidy_2
; pw
->pw_uid
= atoi(s
);
285 s
= strtok(0, ":"); if (!s
) goto tidy_2
; pw
->pw_gid
= atoi(s
);
286 s
= strtok(0, ":"); if (!s
) goto tidy_2
; pw
->pw_gecos
= xstrdup(s
);
287 s
= strtok(0, ":"); if (!s
) goto tidy_3
; pw
->pw_dir
= xstrdup(s
);
288 s
= strtok(0, ":"); if (!s
) goto tidy_4
; pw
->pw_shell
= xstrdup(s
);
291 /* --- Error handling --- */
307 /* --- @userdb_freeUser@ --- *
309 * Arguments: @void *rec@ = pointer to a user record
313 * Use: Frees a user record.
316 void userdb_freeUser(void *rec
)
332 /* --- @userdb__dumpGroup@ --- *
334 * Arguments: @const struct group *gr@ = pointer to a group block
335 * @FILE *fp@ = pointer to stream to write on
339 * Use: Writes a group's information to a stream.
344 static void userdb__dumpGroup(const struct group
*gr
, FILE *fp
)
353 gr
->gr_name
, gr
->gr_passwd
, (int)gr
->gr_gid
);
354 for (p
= gr
->gr_mem
; *p
; p
++)
355 printf("*** %s\n", *p
);
360 #define userdb__dumpUser(pw, fp) ((void)0)
364 /* --- @userdb_copyGroup@ --- *
366 * Arguments: @struct group *gr@ = pointer to group block
368 * Returns: Pointer to copied block
370 * Use: Copies a group block. The copy is `deep' so all the strings
371 * are copied too. Free the copy with @userdb_freeGroup@ when
372 * you don't want it any more.
375 struct group
*userdb_copyGroup(struct group
*gr
)
383 ngr
= xmalloc(sizeof(*ngr
));
385 ngr
->gr_name
= xstrdup(gr
->gr_name
);
386 ngr
->gr_passwd
= xstrdup(gr
->gr_passwd
);
387 ngr
->gr_gid
= gr
->gr_gid
;
389 for (max
= 0; gr
->gr_mem
[max
]; max
++)
391 ngr
->gr_mem
= xmalloc((max
+ 1) * sizeof(char *));
392 for (i
= 0; i
< max
; i
++)
393 ngr
->gr_mem
[i
] = xstrdup(gr
->gr_mem
[i
]);
394 ngr
->gr_mem
[max
] = 0;
399 /* --- @userdb__buildGroup@ --- *
401 * Arguments: @char *s@ = pointer to group line string
403 * Returns: Pointer to a group block
405 * Use: Parses an entry in the groups file. The string is garbled
406 * by @strtok@ as we go.
409 static struct group
*userdb__buildGroup(char *s
)
411 struct group
*gr
= xmalloc(sizeof(*gr
));
415 /* --- Do the easy bits --- */
417 s
= strtok(s
, ":"); if (!s
) goto tidy_0
; gr
->gr_name
= xstrdup(s
);
418 s
= strtok(0, ":"); if (!s
) goto tidy_1
; gr
->gr_passwd
= xstrdup(s
);
419 s
= strtok(0, ":"); if (!s
) goto tidy_2
; gr
->gr_gid
= atoi(s
);
421 /* --- Find the start of the member list --- */
427 /* --- Count the number of members --- */
433 if ((p
= strpbrk(p
, ",")) == 0)
438 /* --- Allocate the block and fill it --- */
440 gr
->gr_mem
= xmalloc((i
+ 1) * sizeof(char *));
444 gr
->gr_mem
[i
++] = xstrdup(s
);
451 /* --- Various tidying-up things --- */
463 /* --- @userdb_freeGroup@ --- *
465 * Arguments: @void *rec@ = pointer to a group record
469 * Use: Frees a group record.
472 void userdb_freeGroup(void *rec
)
483 for (p
= gr
->gr_mem
; *p
; p
++)
489 /*----- Higher-level functions --------------------------------------------*/
491 /* --- @userdb_local@ --- *
497 * Use: Reads the local list of users into the maps.
500 void userdb_local(void)
502 D( printf("adding local users...\n"); )
504 /* --- Fetch users first --- */
510 while ((pw
= getpwent()) != 0) {
511 D( userdb__dumpUser(pw
, stdout
); )
512 if (!userdb__byName(&userdb__users
, pw
->pw_name
))
513 userdb__addToMap(&userdb__users
, pw
->pw_name
, pw
->pw_uid
,
514 userdb_copyUser(pw
));
519 /* --- Then fetch groups --- */
525 while ((gr
= getgrent()) != 0) {
526 D( userdb__dumpGroup(gr
, stdout
); )
527 if (!userdb__byName(&userdb__groups
, gr
->gr_name
))
528 userdb__addToMap(&userdb__groups
, gr
->gr_name
, gr
->gr_gid
,
529 userdb_copyGroup(gr
));
535 /* --- @userdb__getLine@ --- *
537 * Arguments: @char *buff@ = pointer to buffer to read into
538 * @size_t sz@ = size of the buffer
539 * @FILE *fp@ = pointer to stream to read on
541 * Returns: Zero if something didn't work.
543 * Use: Reads a line into the buffer. If the line didn't fit, bits
544 * of it are thrown away. The newline character is not
548 static char *userdb__getLine(char *buff
, size_t sz
, FILE *fp
)
550 if ((buff
= fgets(buff
, sz
, fp
)) == 0)
552 sz
= strlen(buff
) - 1;
553 if (buff
[sz
] == '\n')
557 if (ch
== '\n' || ch
== EOF
)
563 /* --- @userdb_yp@ --- *
569 * Use: Fetches the YP database of users.
580 D( printf("adding nis users\n"); )
582 /* --- First, users --- */
584 if ((fp
= popen("ypcat passwd", "r")) != 0) {
585 while (userdb__getLine(line
, sizeof(line
), fp
)) {
588 if ((pw
= userdb__buildUser(line
)) != 0) {
589 D( userdb__dumpUser(pw
, stdout
); )
590 if (userdb__byName(&userdb__users
, pw
->pw_name
))
593 userdb__addToMap(&userdb__users
, pw
->pw_name
, pw
->pw_uid
, pw
);
599 /* --- Next, groups --- */
602 if ((fp
= popen("ypcat group", "r")) != 0) {
603 while (userdb__getLine(line
, sizeof(line
), fp
)) {
606 if ((gr
= userdb__buildGroup(line
)) != 0) {
607 D( userdb__dumpGroup(gr
, stdout
); )
608 if (userdb__byName(&userdb__groups
, gr
->gr_name
))
609 userdb_freeGroup(gr
);
611 userdb__addToMap(&userdb__groups
, gr
->gr_name
, gr
->gr_gid
, gr
);
621 /* --- @userdb_userByName@, @userdb_userById@ --- *
623 * Arguments: @const char *name@ = pointer to user's name
624 * @uid_t id@ = user id to find
626 * Returns: Pointer to user block, or zero if not found.
628 * Use: Looks up a user by name or id.
631 struct passwd
*userdb_userByName(const char *name
)
632 { return (userdb__byName(&userdb__users
, name
)); }
634 struct passwd
*userdb_userById(uid_t id
)
635 { return (userdb__byId(&userdb__users
, id
)); }
637 /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- *
639 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
643 * Use: Initialises an iteration for the user database.
646 void userdb_iterateUsers(void)
647 { userdb_iterateUsers_r(&userdb__useri
); }
649 void userdb_iterateUsers_r(userdb_iter
*i
)
650 { sym_createIter(i
, &userdb__users
.nmap
); }
652 /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- *
654 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
656 * Returns: Pointer to the next user block, or null.
658 * Use: Returns another user block.
661 struct passwd
*userdb_nextUser(void)
662 { return (userdb_nextUser_r(&userdb__useri
)); }
664 struct passwd
*userdb_nextUser_r(userdb_iter
*i
)
666 userdb__sym
*s
= sym_next(i
);
667 return (s ? s
->rec
: 0);
670 /* --- @userdb_groupByName@, @userdb_groupById@ --- *
672 * Arguments: @const char *name@ = pointer to group's name
673 * @gid_t id@ = group id to find
675 * Returns: Pointer to group block, or zero if not found.
677 * Use: Looks up a group by name or id.
680 struct group
*userdb_groupByName(const char *name
)
681 { return (userdb__byName(&userdb__groups
, name
)); }
683 struct group
*userdb_groupById(gid_t id
)
684 { return (userdb__byId(&userdb__groups
, id
)); }
686 /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- *
688 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
692 * Use: Initialises an iteration for the group database.
695 void userdb_iterateGroups(void)
696 { userdb_iterateGroups_r(&userdb__groupi
); }
698 void userdb_iterateGroups_r(userdb_iter
*i
)
699 { sym_createIter(i
, &userdb__groups
.nmap
); }
701 /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- *
703 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
705 * Returns: Pointer to the next group block, or null.
707 * Use: Returns another group block.
710 struct group
*userdb_nextGroup(void)
711 { return (userdb_nextGroup_r(&userdb__groupi
)); }
713 struct group
*userdb_nextGroup_r(userdb_iter
*i
)
715 userdb__sym
*s
= sym_next(i
);
716 return (s ? s
->rec
: 0);
719 /* --- @userdb_init@ --- *
725 * Use: Initialises the user database.
728 void userdb_init(void)
730 userdb__createMap(&userdb__users
);
731 userdb__createMap(&userdb__groups
);
734 /* --- @userdb_reinit@ --- *
740 * Use: Reinitialises the user database.
743 void userdb_reinit(void)
745 userdb__clearMap(&userdb__users
, userdb_freeUser
);
746 userdb__clearMap(&userdb__groups
, userdb_freeGroup
);
750 /*----- Test rig ----------------------------------------------------------*/
754 void dumpit(const char *msg
)
756 printf("\n\n$$$ %s\n", msg
);
760 for (userdb_iterateUsers(); (pw
= userdb_nextUser()) != 0; )
761 userdb__dumpUser(pw
, stdout
);
766 for (userdb_iterateGroups(); (gr
= userdb_nextGroup()) != 0; )
767 userdb__dumpGroup(gr
, stdout
);
784 /*----- That's all, folks -------------------------------------------------*/