Expunge revision histories in files.
[become] / src / userdb.c
index bcefc85..cf63d9e 100644 (file)
@@ -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'
  *
  * 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 ------------------------------------------------------*/
 
 /* --- Unix headers --- */
 
+#include "config.h"
+
 #include <sys/types.h>
 
 #include <grp.h>
 #include <pwd.h>
 #include <unistd.h>
 
+/* --- mLib headers --- */
+
+#include <mLib/alloc.h>
+#include <mLib/sym.h>
+#include <mLib/trace.h>
+
 /* --- 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);
 }