3 * $Id: userdb.c,v 1.9 2003/10/12 00:14:55 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.9 2003/10/12 00:14:55 mdw
33 * Major overhaul. Now uses DSA signatures rather than the bogus symmetric
34 * encrypt-and-hope thing. Integrated with mLib and Catacomb.
36 * Revision 1.8 1998/06/08 11:21:22 mdw
37 * Fixed bug in password and group file reading: strtok doesn't handle
38 * double colons nicely.
40 * Revision 1.7 1998/04/23 13:27:46 mdw
41 * Switch to using the ypstuff interface to YP server.
43 * Revision 1.6 1998/01/12 16:46:33 mdw
46 * Revision 1.5 1997/09/17 10:24:08 mdw
47 * Use `uid_t' instead of `int' for uids and gids. Not quite sure why I
48 * didn't do this before.
50 * Revision 1.4 1997/08/20 16:24:58 mdw
51 * Patch memory leak. Rename `userdb_reinit' to `userdb_end' for more
54 * Revision 1.3 1997/08/07 09:44:29 mdw
55 * Read NIS-based passwords from the YP server directly, rather than using
56 * `popen(ypcat)', which is probably both slower and less secure.
58 * Revision 1.2 1997/08/04 10:24:26 mdw
59 * Sources placed under CVS control.
61 * Revision 1.1 1997/07/21 13:47:43 mdw
66 /*----- Header files ------------------------------------------------------*/
68 /* --- ANSI headers --- */
76 /* --- Unix headers --- */
80 #include <sys/types.h>
86 /* --- mLib headers --- */
88 #include <mLib/alloc.h>
90 #include <mLib/trace.h>
92 /* --- Local headers --- */
98 /*----- Type definitions --------------------------------------------------*/
100 /* --- A map link --- */
102 typedef struct userdb__node
{
103 struct userdb__node
*next
;
107 /* --- A reference to a real record --- */
109 typedef struct userdb__sym
{
114 /* --- A name- and number-mapping --- */
116 typedef struct userdb__map
{
122 /*----- Static variables --------------------------------------------------*/
124 static userdb__map userdb__users
; /* Map of user info blocks */
125 static sym_iter userdb__useri
; /* Iterator for users */
126 static userdb__map userdb__groups
; /* Map of group info blocks */
127 static sym_iter userdb__groupi
; /* Iterator for groups */
129 /*----- Map management functions ------------------------------------------*/
131 /* --- @userdb__createMap@ --- *
133 * Arguments: @userdb__map *m@ = pointer to a map block
137 * Use: Initialises a map table.
140 static void userdb__createMap(userdb__map
*m
)
142 sym_create(&m
->nmap
);
143 sym_create(&m
->idmap
);
147 /* --- @userdb__addToMap@ --- *
149 * Arguments: @userdb__map *m@ = pointer to the map block
150 * @const char *name@ = pointer to the item's name
151 * @uid_t id@ = the item's id number
152 * @void *rec@ = pointer to the actual record
156 * Use: Adds an item to the given map.
159 static void userdb__addToMap(userdb__map
*m
,
167 s
= sym_find(&m
->nmap
, name
, -1, sizeof(*s
), &f
);
171 s
= sym_find(&m
->idmap
, (char *)&id
, sizeof(id
), sizeof(*s
), &f
);
175 n
= xmalloc(sizeof(*n
));
181 /* --- @userdb__byName@ --- *
183 * Arguments: @userdb__map *m@ = pointer to a map block
184 * @const char *name@ = name to look up
186 * Returns: A pointer to the appropriate block, or zero if not found.
188 * Use: Looks up a name in a mapping and returns the result.
191 static void *userdb__byName(userdb__map
*m
, const char *name
)
193 userdb__sym
*s
= sym_find(&m
->nmap
, name
, -1, 0, 0);
194 return (s ? s
->rec
: 0);
197 /* --- @userdb__byId@ --- *
199 * Arguments: @userdb__map *m@ = pointer to a map block
200 * @uid_t id@ = id number to find
202 * Returns: A pointer to the appropriate block, or zero if not found.
204 * Use: Looks up an ID in a mapping, and returns the result.
207 static void *userdb__byId(userdb__map
*m
, uid_t id
)
209 userdb__sym
*s
= sym_find(&m
->idmap
, (char *)&id
, sizeof(id
), 0, 0);
210 return (s ? s
->rec
: 0);
213 /* --- @userdb__clearMap@ --- *
215 * Arguments: @userdb__map *m@ = pointer to a map block
216 * @void (*freerec)(void *rec)@ = pointer to a free-record proc
220 * Use: Clears a map, emptying it and releasing the memory it
224 static void userdb__clearMap(userdb__map
*m
, void (*freerec
)(void *rec
))
228 sym_destroy(&m
->nmap
);
229 sym_destroy(&m
->idmap
);
231 for (n
= m
->list
; n
; n
= t
) {
238 /*----- User and group block management -----------------------------------*/
240 /* --- @userdb__dumpUser@ --- *
242 * Arguments: @const struct passwd *pw@ = pointer to a user block
246 * Use: Writes a user's informationt to a stream.
251 static void userdb__dumpUser(const struct passwd
*pw
)
254 "debug: name `%s' passwd `%s' uid %i gid %i",
255 pw
->pw_name
, pw
->pw_passwd
, (int)pw
->pw_uid
, (int)pw
->pw_gid
);
257 "debug: ... gecos `%s' home `%s' shell `%s'",
258 pw
->pw_gecos
, pw
->pw_dir
, pw
->pw_shell
);
263 /* --- @userdb__split@ --- *
265 * Arguments: @char *p@ = pointer to string
266 * @char **v@ = pointer to vector to fill in
267 * @int sz@ = maximum number of fields to split
269 * Returns: Number of fields extracted.
271 * Use: Splits a string into fields at colon characters.
274 static int userdb__split(char *p
, char **v
, int sz
)
278 *v
++ = p
; sz
--; count
++;
284 *v
++ = p
; sz
--; count
++;
296 /* --- @userdb_copyUser@ --- *
298 * Arguments: @struct passwd *pw@ = pointer to block to copy
300 * Returns: Pointer to the copy.
302 * Use: Copies a user block. The copy is `deep' so all the strings
303 * are copied too. Free the copy with @userdb_freeUser@ when
304 * you don't want it any more.
307 struct passwd
*userdb_copyUser(struct passwd
*pw
)
314 npw
= xmalloc(sizeof(*npw
));
316 npw
->pw_name
= xstrdup(pw
->pw_name
);
317 npw
->pw_passwd
= xstrdup(pw
->pw_passwd
);
318 npw
->pw_uid
= pw
->pw_uid
;
319 npw
->pw_gid
= pw
->pw_gid
;
320 npw
->pw_gecos
= xstrdup(pw
->pw_gecos
);
321 npw
->pw_dir
= xstrdup(pw
->pw_dir
);
322 npw
->pw_shell
= xstrdup(pw
->pw_shell
);
327 /* --- @userdb__buildUser@ --- *
329 * Arguments: @char *s@ = pointer to user string
331 * Returns: Pointer to a user block.
333 * Use: Converts a line from a user file into a password entry.
334 * Note that the string is corrupted by @strtok@ while it gets
338 static struct passwd
*userdb__buildUser(char *s
)
340 struct passwd
*pw
= xmalloc(sizeof(*pw
));
343 if (userdb__split(s
, v
, 7) < 7) {
348 pw
->pw_name
= xstrdup(v
[0]);
349 pw
->pw_passwd
= xstrdup(v
[1]);
350 pw
->pw_uid
= (uid_t
)atol(v
[2]);
351 pw
->pw_gid
= (gid_t
)atol(v
[3]);
352 pw
->pw_gecos
= xstrdup(v
[4]);
353 pw
->pw_dir
= xstrdup(v
[5]);
354 pw
->pw_shell
= xstrdup(v
[6]);
358 /* --- @userdb_freeUser@ --- *
360 * Arguments: @void *rec@ = pointer to a user record
364 * Use: Frees a user record.
367 void userdb_freeUser(void *rec
)
383 /* --- @userdb__dumpGroup@ --- *
385 * Arguments: @const struct group *gr@ = pointer to a group block
386 * @FILE *fp@ = pointer to stream to write on
390 * Use: Writes a group's information to a stream.
395 static void userdb__dumpGroup(const struct group
*gr
)
400 "debug: name `%s' passwd `%s' gid %i",
401 gr
->gr_name
, gr
->gr_passwd
, (int)gr
->gr_gid
);
402 for (p
= gr
->gr_mem
; *p
; p
++)
403 trace(TRACE_DEBUG
,"debug: ... `%s'", *p
);
408 /* --- @userdb_copyGroup@ --- *
410 * Arguments: @struct group *gr@ = pointer to group block
412 * Returns: Pointer to copied block
414 * Use: Copies a group block. The copy is `deep' so all the strings
415 * are copied too. Free the copy with @userdb_freeGroup@ when
416 * you don't want it any more.
419 struct group
*userdb_copyGroup(struct group
*gr
)
427 ngr
= xmalloc(sizeof(*ngr
));
429 ngr
->gr_name
= xstrdup(gr
->gr_name
);
430 ngr
->gr_passwd
= xstrdup(gr
->gr_passwd
);
431 ngr
->gr_gid
= gr
->gr_gid
;
433 for (max
= 0; gr
->gr_mem
[max
]; max
++)
435 ngr
->gr_mem
= xmalloc((max
+ 1) * sizeof(char *));
436 for (i
= 0; i
< max
; i
++)
437 ngr
->gr_mem
[i
] = xstrdup(gr
->gr_mem
[i
]);
438 ngr
->gr_mem
[max
] = 0;
443 /* --- @userdb__buildGroup@ --- *
445 * Arguments: @char *s@ = pointer to group line string
447 * Returns: Pointer to a group block
449 * Use: Parses an entry in the groups file. The string is garbled
450 * by @strtok@ as we go.
453 static struct group
*userdb__buildGroup(char *s
)
455 struct group
*gr
= xmalloc(sizeof(*gr
));
459 /* --- Do the easy bits --- */
461 if (userdb__split(s
, v
, 4) < 3) {
465 gr
->gr_name
= xstrdup(v
[0]);
466 gr
->gr_passwd
= xstrdup(v
[1]);
467 gr
->gr_gid
= (gid_t
)atol(v
[2]);
469 /* --- Count the number of members --- */
476 if ((s
= strpbrk(s
, ",")) == 0)
482 /* --- Allocate the block and fill it --- */
484 gr
->gr_mem
= xmalloc((i
+ 1) * sizeof(char *));
487 s
= strtok(v
[3], ",");
489 gr
->gr_mem
[i
++] = xstrdup(s
);
498 /* --- @userdb_freeGroup@ --- *
500 * Arguments: @void *rec@ = pointer to a group record
504 * Use: Frees a group record.
507 void userdb_freeGroup(void *rec
)
518 for (p
= gr
->gr_mem
; *p
; p
++)
524 /*----- Answering queries -------------------------------------------------*/
526 /* --- @userdb_userByName@, @userdb_userById@ --- *
528 * Arguments: @const char *name@ = pointer to user's name
529 * @uid_t id@ = user id to find
531 * Returns: Pointer to user block, or zero if not found.
533 * Use: Looks up a user by name or id.
536 struct passwd
*userdb_userByName(const char *name
)
537 { return (userdb__byName(&userdb__users
, name
)); }
539 struct passwd
*userdb_userById(uid_t id
)
540 { return (userdb__byId(&userdb__users
, id
)); }
542 /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- *
544 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
548 * Use: Initialises an iteration for the user database.
551 void userdb_iterateUsers(void)
552 { userdb_iterateUsers_r(&userdb__useri
); }
554 void userdb_iterateUsers_r(userdb_iter
*i
)
555 { sym_mkiter(i
, &userdb__users
.nmap
); }
557 /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- *
559 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
561 * Returns: Pointer to the next user block, or null.
563 * Use: Returns another user block.
566 struct passwd
*userdb_nextUser(void)
567 { return (userdb_nextUser_r(&userdb__useri
)); }
569 struct passwd
*userdb_nextUser_r(userdb_iter
*i
)
571 userdb__sym
*s
= sym_next(i
);
572 return (s ? s
->rec
: 0);
575 /* --- @userdb_groupByName@, @userdb_groupById@ --- *
577 * Arguments: @const char *name@ = pointer to group's name
578 * @gid_t id@ = group id to find
580 * Returns: Pointer to group block, or zero if not found.
582 * Use: Looks up a group by name or id.
585 struct group
*userdb_groupByName(const char *name
)
586 { return (userdb__byName(&userdb__groups
, name
)); }
588 struct group
*userdb_groupById(gid_t id
)
589 { return (userdb__byId(&userdb__groups
, id
)); }
591 /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- *
593 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object
597 * Use: Initialises an iteration for the group database.
600 void userdb_iterateGroups(void)
601 { userdb_iterateGroups_r(&userdb__groupi
); }
603 void userdb_iterateGroups_r(userdb_iter
*i
)
604 { sym_mkiter(i
, &userdb__groups
.nmap
); }
606 /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- *
608 * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject
610 * Returns: Pointer to the next group block, or null.
612 * Use: Returns another group block.
615 struct group
*userdb_nextGroup(void)
616 { return (userdb_nextGroup_r(&userdb__groupi
)); }
618 struct group
*userdb_nextGroup_r(userdb_iter
*i
)
620 userdb__sym
*s
= sym_next(i
);
621 return (s ? s
->rec
: 0);
624 /*----- Yellow pages support ----------------------------------------------*/
628 /* --- @userdb__foreachUser@ --- *
630 * Arguments: @int st@ = YP protocol-level status code
631 * @char *k@ = address of the key for this record
632 * @int ksz@ = size of the key
633 * @char *v@ = address of the value for this record
634 * @int vsz@ = size of the value
635 * @char *data@ = pointer to some data passed to me
637 * Returns: Zero to be called again, nonzero to end the enumeration.
639 * Use: Handles an incoming user record.
642 static int userdb__foreachUser(int st
, char *k
, int ksz
,
643 char *v
, int vsz
, char *data
)
650 cv
= xmalloc(vsz
+ 1);
653 T( trace(TRACE_DEBUG
, "debug: nis string: `%s'", cv
); )
654 pw
= userdb__buildUser(cv
);
655 if (pw
&& !userdb__byName(&userdb__users
, pw
->pw_name
)) {
656 IF_TRACING(TRACE_DEBUG
, userdb__dumpUser(pw
); )
657 userdb__addToMap(&userdb__users
, pw
->pw_name
, pw
->pw_uid
, pw
);
664 /* --- @userdb__foreachGroup@ --- *
666 * Arguments: @int st@ = YP protocol-level status code
667 * @char *k@ = address of the key for this record
668 * @int ksz@ = size of the key
669 * @char *v@ = address of the value for this record
670 * @int vsz@ = size of the value
671 * @char *data@ = pointer to some data passed to me
673 * Returns: Zero to be called again, nonzero to end the enumeration.
675 * Use: Handles an incoming user record.
678 static int userdb__foreachGroup(int st
, char *k
, int ksz
,
679 char *v
, int vsz
, char *data
)
686 cv
= xmalloc(vsz
+ 1);
689 T( trace(TRACE_DEBUG
, "debug: nis string: `%s'", cv
); )
690 gr
= userdb__buildGroup(cv
);
691 if (gr
&& !userdb__byName(&userdb__groups
, gr
->gr_name
)) {
692 IF_TRACING(TRACE_DEBUG
, userdb__dumpGroup(gr
); )
693 userdb__addToMap(&userdb__groups
, gr
->gr_name
, gr
->gr_gid
, gr
);
695 userdb_freeGroup(gr
);
700 /* --- @userdb_yp@ --- *
706 * Use: Fetches the YP database of users.
711 /* --- Bind to a server --- */
717 T( trace(TRACE_DEBUG
, "debug: adding NIS users"); )
719 /* --- Fetch the users map --- */
722 static struct ypall_callback ucb
= { userdb__foreachUser
, 0 };
723 yp_all(yp_domain
, "passwd.byuid", &ucb
);
726 /* --- Fetch the groups map --- */
729 static struct ypall_callback gcb
= { userdb__foreachGroup
, 0 };
730 yp_all(yp_domain
, "group.bygid", &gcb
);
736 void userdb_yp(void) { ; }
740 /*----- Building the databases --------------------------------------------*/
742 /* --- @userdb_local@ --- *
748 * Use: Reads the local list of users into the maps.
751 void userdb_local(void)
753 T( trace(TRACE_DEBUG
, "debug: adding local users"); )
755 /* --- Fetch users first --- */
761 while ((pw
= getpwent()) != 0) {
762 IF_TRACING(TRACE_DEBUG
, userdb__dumpUser(pw
); )
763 if (!userdb__byName(&userdb__users
, pw
->pw_name
))
764 userdb__addToMap(&userdb__users
, pw
->pw_name
, pw
->pw_uid
,
765 userdb_copyUser(pw
));
770 /* --- Then fetch groups --- */
776 while ((gr
= getgrent()) != 0) {
777 IF_TRACING(TRACE_DEBUG
, userdb__dumpGroup(gr
); )
778 if (!userdb__byName(&userdb__groups
, gr
->gr_name
))
779 userdb__addToMap(&userdb__groups
, gr
->gr_name
, gr
->gr_gid
,
780 userdb_copyGroup(gr
));
786 /* --- @userdb_init@ --- *
792 * Use: Initialises the user database.
795 void userdb_init(void)
797 userdb__createMap(&userdb__users
);
798 userdb__createMap(&userdb__groups
);
801 /* --- @userdb_end@ --- *
807 * Use: Closes down the user database.
810 void userdb_end(void)
812 userdb__clearMap(&userdb__users
, userdb_freeUser
);
813 userdb__clearMap(&userdb__groups
, userdb_freeGroup
);
816 /*----- Test rig ----------------------------------------------------------*/
820 void dumpit(const char *msg
)
822 trace(TRACE_DEBUG
, "debug: %s", msg
);
826 for (userdb_iterateUsers(); (pw
= userdb_nextUser()) != 0; )
827 userdb__dumpUser(pw
);
832 for (userdb_iterateGroups(); (gr
= userdb_nextGroup()) != 0; )
833 userdb__dumpGroup(gr
);
840 traceon(stdout
, TRACE_ALL
);
845 /* printf("loaded (%lu)\n", track_memused()); */
849 /* printf("cleared (%lu)\n", track_memused()); */
850 /* track_memlist(); */
854 /* printf("reloaded (%lu)\n", track_memused()); */
862 /*----- That's all, folks -------------------------------------------------*/