chiark / gitweb /
server: Set admin socket permissions to match user.
[tripe] / server / admin.c
index 382baca97b7ea6e85c2705a477b72fbd127845ad..00288f3017264e9bdf477ac8dee2d8726341324c 100644 (file)
@@ -1062,7 +1062,7 @@ static void a_resolve(admin *a, admin_resop *r, const char *tag,
   r->sa.sin.sin_family = AF_INET;
   r->sasz = sizeof(r->sa.sin);
   r->addr = xstrdup(av[i]);
-  if (!av[i + i])
+  if (!av[i + 1])
     pt = TRIPE_PORT;
   else {
     pt = strtoul(av[i + 1], &p, 0);
@@ -1913,61 +1913,66 @@ static void acmd_help(admin *a, unsigned ac, char *av[])
 
 static void a_destroypending(void)
 {
-  admin *a, *aa;
+  admin *a, *aa, *head;
   admin_bgop *bg, *bbg;
   admin_service *svc, *ssvc;
 
-  /* --- Destroy connections marked as pending --- */
+  /* --- Destroy connections marked as pending --- *
+   *
+   * Slightly messy.  Killing clients may cause others to finally die.  Make
+   * sure that they can be put on the list without clobbering anything or
+   * getting lost.
+   */
 
-  for (a = a_dead; a; a = aa) {
-    aa = a->next;
-    assert(a->f & AF_DEAD);
+  while (a_dead) {
+    head = a_dead;
+    a_dead = 0;
+    for (a = head; a; a = aa) {
+      aa = a->next;
+      assert(a->f & AF_DEAD);
 
-    /* --- Report what we're doing --- */
+      /* --- Report what we're doing --- */
 
-    T( trace(T_ADMIN, "admin: completing destruction of connection %u",
-            a->seq); )
+      T( trace(T_ADMIN, "admin: completing destruction of connection %u",
+              a->seq); )
 
-    /* --- If this is the foreground client then shut down --- */
+      /* --- If this is the foreground client then shut down --- */
 
-    if (a->f & AF_FOREGROUND) {
-      T( trace(T_ADMIN, "admin: foreground client quit: shutting down"); )
-      a_warn("SERVER", "quit", "foreground-eof", A_END);
-      a_quit();
-    }
+      if (a->f & AF_FOREGROUND) {
+       T( trace(T_ADMIN, "admin: foreground client quit: shutting down"); )
+       a_warn("SERVER", "quit", "foreground-eof", A_END);
+       a_quit();
+      }
 
-    /* --- Abort any background jobs in progress --- */
+      /* --- Abort any background jobs in progress --- */
 
-    for (bg = a->bg; bg; bg = bbg) {
-      bbg = bg->next;
-      bg->cancel(bg);
-      if (bg->tag) xfree(bg->tag);
-      xfree(bg);
-    }
+      for (bg = a->bg; bg; bg = bbg) {
+       bbg = bg->next;
+       bg->cancel(bg);
+       if (bg->tag) xfree(bg->tag);
+       xfree(bg);
+      }
 
-    /* --- Release services I hold, and abort pending jobs --- */
+      /* --- Release services I hold, and abort pending jobs --- */
 
-    for (svc = a->svcs; svc; svc = ssvc) {
-      ssvc = svc->next;
-      a_svcrelease(svc);
-    }
-    a_jobtablefinal(&a->j);
+      for (svc = a->svcs; svc; svc = ssvc) {
+       ssvc = svc->next;
+       a_svcrelease(svc);
+      }
+      a_jobtablefinal(&a->j);
 
-    /* --- Close file descriptors and selectory --- */
+      /* --- Close file descriptors and selectory --- */
 
-    selbuf_destroy(&a->b);
-    if (a->b.reader.fd != a->w.fd) close(a->b.reader.fd);
-    close(a->w.fd);
-    if (a_stdin == a) a_stdin = 0;
+      selbuf_destroy(&a->b);
+      if (a->b.reader.fd != a->w.fd) close(a->b.reader.fd);
+      close(a->w.fd);
+      if (a_stdin == a) a_stdin = 0;
 
-    /* --- Done --- */
+      /* --- Done --- */
 
-    DESTROY(a);
+      DESTROY(a);
+    }
   }
-
-  /* --- All pending destruction completed --- */
-
-  a_dead = 0;
 }
 
 /* --- @a_destroy@ --- *
@@ -2025,7 +2030,7 @@ static void a_line(char *p, size_t len, void *vp)
 {
   admin *a = vp;
   const acmd *c;
-  char *av[16];
+  char *av[16 + 1];
   size_t ac;
 
   TIMER;
@@ -2040,9 +2045,10 @@ static void a_line(char *p, size_t len, void *vp)
     }
     return;
   }
-  ac = str_qsplit(p, av, 16, 0, STRF_QUOTE);
+  ac = str_qsplit(p, av, N(av) - 1, 0, STRF_QUOTE);
   if (!ac)
     return;
+  av[ac] = 0;
   for (c = acmdtab; c->name; c++) {
     if (mystrieq(av[0], c->name)) {
       ac--;
@@ -2147,13 +2153,15 @@ void a_daemon(void) { flags |= F_DAEMON; }
 /* --- @a_init@ --- *
  *
  * Arguments:  @const char *name@ = socket name to create
+ *             @uid_t u@ = user to own the socket
+ *             @gid_t g@ = group to own the socket
  *
  * Returns:    ---
  *
  * Use:                Creates the admin listening socket.
  */
 
-void a_init(const char *name)
+void a_init(const char *name, uid_t u, gid_t g)
 {
   int fd;
   int n = 5;
@@ -2209,6 +2217,11 @@ again:
     goto again;
   }
   chmod(sun.sun_path, 0600);
+  if (chown(sun.sun_path, u, g)) {
+    T( trace(T_ADMIN,
+            "admin: failed to give away socket: %s",
+            strerror(errno)); )
+  }
   fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
   if (listen(fd, 5))
     die(EXIT_FAILURE, "couldn't listen on socket: %s", strerror(errno));