X-Git-Url: https://git.distorted.org.uk/~mdw/become/blobdiff_plain/c4f2d992e4a0fc068281376d89ec38de56dc2f58..af4f4d6a77aceba8e2d6f58d15e894df320e7c24:/src/userdb.c diff --git a/src/userdb.c b/src/userdb.c index bcefc85..cf63d9e 100644 --- a/src/userdb.c +++ b/src/userdb.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: userdb.c,v 1.1 1997/07/21 13:47:43 mdw Exp $ + * $Id: userdb.c,v 1.11 2004/04/08 01:36:20 mdw Exp $ * * User database management * - * (c) 1997 EBI + * (c) 1998 EBI */ -/*----- Licencing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of `become' * @@ -22,16 +22,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with `become'; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*----- Revision history --------------------------------------------------* - * - * $Log: userdb.c,v $ - * Revision 1.1 1997/07/21 13:47:43 mdw - * Initial revision - * + * along with `become'; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*----- Header files ------------------------------------------------------*/ @@ -46,18 +38,25 @@ /* --- Unix headers --- */ +#include "config.h" + #include #include #include #include +/* --- mLib headers --- */ + +#include +#include +#include + /* --- Local headers --- */ -#include "config.h" -#include "sym.h" +#include "become.h" #include "userdb.h" -#include "utils.h" +#include "ypstuff.h" /*----- Type definitions --------------------------------------------------*/ @@ -103,8 +102,8 @@ static sym_iter userdb__groupi; /* Iterator for groups */ static void userdb__createMap(userdb__map *m) { - sym_createTable(&m->nmap); - sym_createTable(&m->idmap); + sym_create(&m->nmap); + sym_create(&m->idmap); m->list = 0; } @@ -112,7 +111,7 @@ static void userdb__createMap(userdb__map *m) * * Arguments: @userdb__map *m@ = pointer to the map block * @const char *name@ = pointer to the item's name - * @int id@ = the item's id number + * @uid_t id@ = the item's id number * @void *rec@ = pointer to the actual record * * Returns: --- @@ -122,7 +121,7 @@ static void userdb__createMap(userdb__map *m) static void userdb__addToMap(userdb__map *m, const char *name, - int id, void *rec) + uid_t id, void *rec) { unsigned f; userdb__sym *s; @@ -161,14 +160,14 @@ static void *userdb__byName(userdb__map *m, const char *name) /* --- @userdb__byId@ --- * * * Arguments: @userdb__map *m@ = pointer to a map block - * @int id@ = id number to find + * @uid_t id@ = id number to find * * Returns: A pointer to the appropriate block, or zero if not found. * * Use: Looks up an ID in a mapping, and returns the result. */ -static void *userdb__byId(userdb__map *m, int id) +static void *userdb__byId(userdb__map *m, uid_t id) { userdb__sym *s = sym_find(&m->idmap, (char *)&id, sizeof(id), 0, 0); return (s ? s->rec : 0); @@ -189,8 +188,8 @@ static void userdb__clearMap(userdb__map *m, void (*freerec)(void *rec)) { userdb__node *n, *t; - sym_destroyTable(&m->nmap); - sym_destroyTable(&m->idmap); + sym_destroy(&m->nmap); + sym_destroy(&m->idmap); for (n = m->list; n; n = t) { t = n->next; @@ -204,34 +203,58 @@ static void userdb__clearMap(userdb__map *m, void (*freerec)(void *rec)) /* --- @userdb__dumpUser@ --- * * * Arguments: @const struct passwd *pw@ = pointer to a user block - * @FILE *fp@ = pointer to stream to write on * * Returns: --- * * Use: Writes a user's informationt to a stream. */ -#ifndef NDEBUG +#ifndef NTRACE -static void userdb__dumpUser(const struct passwd *pw, FILE *fp) +static void userdb__dumpUser(const struct passwd *pw) { - printf("\n" - "*** name == %s\n" - "*** passwd == %s\n" - "*** uid == %i\n" - "*** gid == %i\n" - "*** gecos == %s\n" - "*** home == %s\n" - "*** shell == %s\n", - pw->pw_name, pw->pw_passwd, (int)pw->pw_uid, (int)pw->pw_gid, - pw->pw_gecos, pw->pw_dir, pw->pw_shell); + trace(TRACE_DEBUG, + "debug: name `%s' passwd `%s' uid %i gid %i", + pw->pw_name, pw->pw_passwd, (int)pw->pw_uid, (int)pw->pw_gid); + trace(TRACE_DEBUG, + "debug: ... gecos `%s' home `%s' shell `%s'", + pw->pw_gecos, pw->pw_dir, pw->pw_shell); } -#else +#endif -#define userdb__dumpUser(pw, fp) ((void)0) +/* --- @userdb__split@ --- * + * + * Arguments: @char *p@ = pointer to string + * @char **v@ = pointer to vector to fill in + * @int sz@ = maximum number of fields to split + * + * Returns: Number of fields extracted. + * + * Use: Splits a string into fields at colon characters. + */ -#endif +static int userdb__split(char *p, char **v, int sz) +{ + int count = 0; + + *v++ = p; sz--; count++; + if (!sz) + goto done; + while (*p) { + if (*p++ == ':') { + p[-1] = 0; + *v++ = p; sz--; count++; + if (!sz) + goto done; + } + } + while (sz--) + *v++ = 0; + +done: + return (count); +} /* --- @userdb_copyUser@ --- * * @@ -278,30 +301,21 @@ struct passwd *userdb_copyUser(struct passwd *pw) static struct passwd *userdb__buildUser(char *s) { struct passwd *pw = xmalloc(sizeof(*pw)); + char *v[7]; - s = strtok(s, ":"); if (!s) goto tidy_0; pw->pw_name = xstrdup(s); - s = strtok(0, ":"); if (!s) goto tidy_1; pw->pw_passwd = xstrdup(s); - s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_uid = atoi(s); - s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_gid = atoi(s); - s = strtok(0, ":"); if (!s) goto tidy_2; pw->pw_gecos = xstrdup(s); - s = strtok(0, ":"); if (!s) goto tidy_3; pw->pw_dir = xstrdup(s); - s = strtok(0, ":"); if (!s) goto tidy_4; pw->pw_shell = xstrdup(s); - return (pw); - - /* --- Error handling --- */ - -tidy_4: - free(pw->pw_dir); -tidy_3: - free(pw->pw_gecos); -tidy_2: - free(pw->pw_passwd); -tidy_1: - free(pw->pw_name); -tidy_0: - free(pw); + if (userdb__split(s, v, 7) < 7) { + free(pw); + return (0); + } - return (0); + pw->pw_name = xstrdup(v[0]); + pw->pw_passwd = xstrdup(v[1]); + pw->pw_uid = (uid_t)atol(v[2]); + pw->pw_gid = (gid_t)atol(v[3]); + pw->pw_gecos = xstrdup(v[4]); + pw->pw_dir = xstrdup(v[5]); + pw->pw_shell = xstrdup(v[6]); + return (pw); } /* --- @userdb_freeUser@ --- * @@ -339,26 +353,19 @@ void userdb_freeUser(void *rec) * Use: Writes a group's information to a stream. */ -#ifndef NDEBUG +#ifndef NTRACE -static void userdb__dumpGroup(const struct group *gr, FILE *fp) +static void userdb__dumpGroup(const struct group *gr) { char *const *p; - printf("\n" - "*** name == %s\n" - "*** passwd == %s\n" - "*** gid == %i\n" - "*** members...\n", + trace(TRACE_DEBUG, + "debug: name `%s' passwd `%s' gid %i", gr->gr_name, gr->gr_passwd, (int)gr->gr_gid); for (p = gr->gr_mem; *p; p++) - printf("*** %s\n", *p); + trace(TRACE_DEBUG,"debug: ... `%s'", *p); } -#else - -#define userdb__dumpUser(pw, fp) ((void)0) - #endif /* --- @userdb_copyGroup@ --- * @@ -409,55 +416,46 @@ struct group *userdb_copyGroup(struct group *gr) static struct group *userdb__buildGroup(char *s) { struct group *gr = xmalloc(sizeof(*gr)); - char *p; + char *v[4]; int i; /* --- Do the easy bits --- */ - s = strtok(s, ":"); if (!s) goto tidy_0; gr->gr_name = xstrdup(s); - s = strtok(0, ":"); if (!s) goto tidy_1; gr->gr_passwd = xstrdup(s); - s = strtok(0, ":"); if (!s) goto tidy_2; gr->gr_gid = atoi(s); - - /* --- Find the start of the member list --- */ - - s = strtok(0, ""); - if (!s) - goto tidy_2; + if (userdb__split(s, v, 4) < 3) { + free(gr); + return (0); + } + gr->gr_name = xstrdup(v[0]); + gr->gr_passwd = xstrdup(v[1]); + gr->gr_gid = (gid_t)atol(v[2]); /* --- Count the number of members --- */ - p = s; + s = v[3]; i = 0; - for (;;) { - i++; - if ((p = strpbrk(p, ",")) == 0) - break; - p++; + if (s && s[0]) { + for (;;) { + i++; + if ((s = strpbrk(s, ",")) == 0) + break; + s++; + } } /* --- Allocate the block and fill it --- */ gr->gr_mem = xmalloc((i + 1) * sizeof(char *)); i = 0; - s = strtok(s, ","); - do { - gr->gr_mem[i++] = xstrdup(s); - s = strtok(0, ","); - } while (s); + if (v[3]) { + s = strtok(v[3], ","); + while (s) { + gr->gr_mem[i++] = xstrdup(s); + s = strtok(0, ","); + } + } gr->gr_mem[i] = 0; return (gr); - - /* --- Various tidying-up things --- */ - -tidy_2: - free(gr->gr_passwd); -tidy_1: - free(gr->gr_name); -tidy_0: - free(gr); - - return (0); } /* --- @userdb_freeGroup@ --- * @@ -486,137 +484,7 @@ void userdb_freeGroup(void *rec) free(gr); } -/*----- Higher-level functions --------------------------------------------*/ - -/* --- @userdb_local@ --- * - * - * Arguments: --- - * - * Returns: --- - * - * Use: Reads the local list of users into the maps. - */ - -void userdb_local(void) -{ - D( printf("adding local users...\n"); ) - - /* --- Fetch users first --- */ - - { - struct passwd *pw; - - setpwent(); - while ((pw = getpwent()) != 0) { - D( userdb__dumpUser(pw, stdout); ) - if (!userdb__byName(&userdb__users, pw->pw_name)) - userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, - userdb_copyUser(pw)); - } - endpwent(); - } - - /* --- Then fetch groups --- */ - - { - struct group *gr; - - setgrent(); - while ((gr = getgrent()) != 0) { - D( userdb__dumpGroup(gr, stdout); ) - if (!userdb__byName(&userdb__groups, gr->gr_name)) - userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, - userdb_copyGroup(gr)); - } - endgrent(); - } -} - -/* --- @userdb__getLine@ --- * - * - * Arguments: @char *buff@ = pointer to buffer to read into - * @size_t sz@ = size of the buffer - * @FILE *fp@ = pointer to stream to read on - * - * Returns: Zero if something didn't work. - * - * Use: Reads a line into the buffer. If the line didn't fit, bits - * of it are thrown away. The newline character is not - * included. - */ - -static char *userdb__getLine(char *buff, size_t sz, FILE *fp) -{ - if ((buff = fgets(buff, sz, fp)) == 0) - return (0); - sz = strlen(buff) - 1; - if (buff[sz] == '\n') - buff[sz] = 0; - else for (;;) { - int ch = getc(fp); - if (ch == '\n' || ch == EOF) - break; - } - return (buff); -} - -/* --- @userdb_yp@ --- * - * - * Arguments: --- - * - * Returns: --- - * - * Use: Fetches the YP database of users. - */ - -void userdb_yp(void) -{ - -#ifdef HAVE_YP - - char line[1024]; - FILE *fp; - - D( printf("adding nis users\n"); ) - - /* --- First, users --- */ - - if ((fp = popen("ypcat passwd", "r")) != 0) { - while (userdb__getLine(line, sizeof(line), fp)) { - struct passwd *pw; - - if ((pw = userdb__buildUser(line)) != 0) { - D( userdb__dumpUser(pw, stdout); ) - if (userdb__byName(&userdb__users, pw->pw_name)) - userdb_freeUser(pw); - else - userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw); - } - } - pclose(fp); - } - - /* --- Next, groups --- */ - - - if ((fp = popen("ypcat group", "r")) != 0) { - while (userdb__getLine(line, sizeof(line), fp)) { - struct group *gr; - - if ((gr = userdb__buildGroup(line)) != 0) { - D( userdb__dumpGroup(gr, stdout); ) - if (userdb__byName(&userdb__groups, gr->gr_name)) - userdb_freeGroup(gr); - else - userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr); - } - } - pclose(fp); - } - -#endif - -} +/*----- Answering queries -------------------------------------------------*/ /* --- @userdb_userByName@, @userdb_userById@ --- * * @@ -647,7 +515,7 @@ void userdb_iterateUsers(void) { userdb_iterateUsers_r(&userdb__useri); } void userdb_iterateUsers_r(userdb_iter *i) -{ sym_createIter(i, &userdb__users.nmap); } +{ sym_mkiter(i, &userdb__users.nmap); } /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- * * @@ -696,7 +564,7 @@ void userdb_iterateGroups(void) { userdb_iterateGroups_r(&userdb__groupi); } void userdb_iterateGroups_r(userdb_iter *i) -{ sym_createIter(i, &userdb__groups.nmap); } +{ sym_mkiter(i, &userdb__groups.nmap); } /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- * * @@ -716,6 +584,168 @@ struct group *userdb_nextGroup_r(userdb_iter *i) return (s ? s->rec : 0); } +/*----- Yellow pages support ----------------------------------------------*/ + +#ifdef HAVE_YP + +/* --- @userdb__foreachUser@ --- * + * + * Arguments: @int st@ = YP protocol-level status code + * @char *k@ = address of the key for this record + * @int ksz@ = size of the key + * @char *v@ = address of the value for this record + * @int vsz@ = size of the value + * @char *data@ = pointer to some data passed to me + * + * Returns: Zero to be called again, nonzero to end the enumeration. + * + * Use: Handles an incoming user record. + */ + +static int userdb__foreachUser(int st, char *k, int ksz, + char *v, int vsz, char *data) +{ + char *cv; + struct passwd *pw; + + if (st != YP_TRUE) + return (-1); + cv = xmalloc(vsz + 1); + memcpy(cv, v, vsz); + cv[vsz] = 0; + T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); ) + pw = userdb__buildUser(cv); + if (pw && !userdb__byName(&userdb__users, pw->pw_name)) { + IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); ) + userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw); + } else + userdb_freeUser(pw); + free(cv); + return (0); +} + +/* --- @userdb__foreachGroup@ --- * + * + * Arguments: @int st@ = YP protocol-level status code + * @char *k@ = address of the key for this record + * @int ksz@ = size of the key + * @char *v@ = address of the value for this record + * @int vsz@ = size of the value + * @char *data@ = pointer to some data passed to me + * + * Returns: Zero to be called again, nonzero to end the enumeration. + * + * Use: Handles an incoming user record. + */ + +static int userdb__foreachGroup(int st, char *k, int ksz, + char *v, int vsz, char *data) +{ + char *cv; + struct group *gr; + + if (st != YP_TRUE) + return (-1); + cv = xmalloc(vsz + 1); + memcpy(cv, v, vsz); + cv[vsz] = 0; + T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); ) + gr = userdb__buildGroup(cv); + if (gr && !userdb__byName(&userdb__groups, gr->gr_name)) { + IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); ) + userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr); + } else + userdb_freeGroup(gr); + free(cv); + return (0); +} + +/* --- @userdb_yp@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Fetches the YP database of users. + */ + +void userdb_yp(void) +{ + /* --- Bind to a server --- */ + + ypstuff_bind(); + if (!yp_domain) + return; + + T( trace(TRACE_DEBUG, "debug: adding NIS users"); ) + + /* --- Fetch the users map --- */ + + { + static struct ypall_callback ucb = { userdb__foreachUser, 0 }; + yp_all(yp_domain, "passwd.byuid", &ucb); + } + + /* --- Fetch the groups map --- */ + + { + static struct ypall_callback gcb = { userdb__foreachGroup, 0 }; + yp_all(yp_domain, "group.bygid", &gcb); + } +} + +#else + +void userdb_yp(void) { ; } + +#endif + +/*----- Building the databases --------------------------------------------*/ + +/* --- @userdb_local@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Reads the local list of users into the maps. + */ + +void userdb_local(void) +{ + T( trace(TRACE_DEBUG, "debug: adding local users"); ) + + /* --- Fetch users first --- */ + + { + struct passwd *pw; + + setpwent(); + while ((pw = getpwent()) != 0) { + IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); ) + if (!userdb__byName(&userdb__users, pw->pw_name)) + userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, + userdb_copyUser(pw)); + } + endpwent(); + } + + /* --- Then fetch groups --- */ + + { + struct group *gr; + + setgrent(); + while ((gr = getgrent()) != 0) { + IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); ) + if (!userdb__byName(&userdb__groups, gr->gr_name)) + userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, + userdb_copyGroup(gr)); + } + endgrent(); + } +} + /* --- @userdb_init@ --- * * * Arguments: --- @@ -731,20 +761,19 @@ void userdb_init(void) userdb__createMap(&userdb__groups); } -/* --- @userdb_reinit@ --- * +/* --- @userdb_end@ --- * * * Arguments: --- * * Returns: --- * - * Use: Reinitialises the user database. + * Use: Closes down the user database. */ -void userdb_reinit(void) +void userdb_end(void) { userdb__clearMap(&userdb__users, userdb_freeUser); userdb__clearMap(&userdb__groups, userdb_freeGroup); - userdb_init(); } /*----- Test rig ----------------------------------------------------------*/ @@ -753,29 +782,41 @@ void userdb_reinit(void) void dumpit(const char *msg) { - printf("\n\n$$$ %s\n", msg); + trace(TRACE_DEBUG, "debug: %s", msg); { struct passwd *pw; for (userdb_iterateUsers(); (pw = userdb_nextUser()) != 0; ) - userdb__dumpUser(pw, stdout); + userdb__dumpUser(pw); } { struct group *gr; for (userdb_iterateGroups(); (gr = userdb_nextGroup()) != 0; ) - userdb__dumpGroup(gr, stdout); + userdb__dumpGroup(gr); } } int main(void) { + ego("userdb-test"); + trace_on(stdout, TRACE_ALL); userdb_init(); - dumpit("cleared"); userdb_local(); - dumpit("local"); userdb_yp(); - dumpit("yp"); + dumpit("spong"); +/* printf("loaded (%lu)\n", track_memused()); */ + getchar(); + for (;;) { + userdb_end(); +/* printf("cleared (%lu)\n", track_memused()); */ +/* track_memlist(); */ + userdb_init(); + userdb_local(); + userdb_yp(); +/* printf("reloaded (%lu)\n", track_memused()); */ + getchar(); + } return (0); }