Merge branch 'master' of chiark:src/checkpath
authorMark Wooding <mdw@distorted.org.uk>
Sun, 13 Apr 2008 17:23:33 +0000 (18:23 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 13 Apr 2008 17:23:33 +0000 (18:23 +0100)
* 'master' of chiark:src/checkpath:
  tmpdir: Allow trusting of particular groups.
  tmpdir: Introduce option for verbose reporting, for diagnosing problems.
  Improve formatting before we get too stuck in.

Conflicts:

tmpdir.c

checkpath.c
checkpath.h
chkpath.c
tmpdir.1
tmpdir.c

index a396d14..2047800 100644 (file)
@@ -1,7 +1,5 @@
 /* -*-c-*-
  *
- * $Id: checkpath.c,v 1.6 2004/04/08 01:36:22 mdw Exp $
- *
  * Check a path for safety
  *
  * (c) 1999 Mark Wooding
@@ -154,10 +152,7 @@ static void pop(void)
  */
 
 static void popall(void)
-{
-  while (sp->e_link)
-    pop();
-}
+  { while (sp->e_link) pop(); }
 
 /* --- @push@ --- *
  *
@@ -193,75 +188,82 @@ static void push(struct elt *e)
 static void report(const struct checkpath *cp, unsigned what, int verbose,
                   const char *p, const char *msg, ...)
 {
+  dstr d = DSTR_INIT;
+  va_list ap;
+  const char *q = msg;
+  const char *s;
+  size_t n;
+  int e = errno;
+  uid_t u;
+  struct passwd *pw;
+  gid_t g;
+  struct group *gr;
+
   /* --- Decide whether to bin this message --- */
 
   if (!cp->cp_report || verbose > cp->cp_verbose || !(cp->cp_what & what))
     return;
 
+  /* --- If no reporting, do the easy thing --- */
+
+  if (!(cp->cp_what & CP_REPORT)) {
+    cp->cp_report(what, verbose, p, 0, cp->cp_arg);
+    return;
+  }
+
   /* --- Format the message nicely --- */
 
-  if (cp->cp_what & CP_REPORT) {
-    dstr d = DSTR_INIT;
-    va_list ap;
-    const char *q = msg;
-    size_t n;
-    int e = errno;
-
-    va_start(ap, msg);
-    if (verbose > 1)
-      dstr_puts(&d, "[ ");
-    if (p)
-      dstr_putf(&d, "Path: %s: ", p);
-    while (*q) {
-      if (*q == '%') {
-       q++;
-       switch (*q) {
-         case 'e':
-           dstr_puts(&d, strerror(e));
-           break;
-         case 'u': {
-           uid_t u = (uid_t)va_arg(ap, int);
-           struct passwd *pw = getpwuid(u);
-           if (pw)
-             dstr_putf(&d, "`%s'", pw->pw_name);
-           else
-             dstr_putf(&d, "%i", (int)u);
-         } break;
-         case 'g': {
-           gid_t g = (gid_t)va_arg(ap, int);
-           struct group *gr = getgrgid(g);
-           if (gr)
-             dstr_putf(&d, "`%s'", gr->gr_name);
-           else
-             dstr_putf(&d, "%i", (int)g);
-         } break;
-         case 's': {
-           const char *s = va_arg(ap, const char *);
-           dstr_puts(&d, s);
-         } break;
-         case '%':
-           dstr_putc(&d, '%');
-           break;
-         default:
-           dstr_putc(&d, '%');
-           dstr_putc(&d, *q);
-           break;
-       }
-       q++;
-      } else {
-       n = strcspn(q, "%");
-       DPUTM(&d, q, n);
-       q += n;
+  va_start(ap, msg);
+  if (verbose > 1)
+    dstr_puts(&d, "[ ");
+  if (p)
+    dstr_putf(&d, "Path: %s: ", p);
+  while (*q) {
+    if (*q == '%') {
+      q++;
+      switch (*q) {
+       case 'e':
+         dstr_puts(&d, strerror(e));
+         break;
+       case 'u':
+         u = (uid_t)va_arg(ap, int);
+         if ((pw = getpwuid(u)) != 0)
+           dstr_putf(&d, "`%s'", pw->pw_name);
+         else
+           dstr_putf(&d, "%i", (int)u);
+         break;
+       case 'g':
+         g = (gid_t)va_arg(ap, int);
+         if ((gr = getgrgid(g)) != 0)
+           dstr_putf(&d, "`%s'", gr->gr_name);
+         else
+           dstr_putf(&d, "%i", (int)g);
+         break;
+       case 's':
+         s = va_arg(ap, const char *);
+         dstr_puts(&d, s);
+         break;
+       case '%':
+         dstr_putc(&d, '%');
+         break;
+       default:
+         dstr_putc(&d, '%');
+         dstr_putc(&d, *q);
+         break;
       }
+      q++;
+    } else {
+      n = strcspn(q, "%");
+      DPUTM(&d, q, n);
+      q += n;
     }
-    if (verbose > 1)
-      dstr_puts(&d, " ]");
-    DPUTZ(&d);
-    cp->cp_report(what, verbose, p, d.buf, cp->cp_arg);
-    dstr_destroy(&d);
-    va_end(ap);
-  } else
-    cp->cp_report(what, verbose, p, 0, cp->cp_arg);
+  }
+  if (verbose > 1)
+    dstr_puts(&d, " ]");
+  DPUTZ(&d);
+  cp->cp_report(what, verbose, p, d.buf, cp->cp_arg);
+  dstr_destroy(&d);
+  va_end(ap);
 }
 
 /* --- @sanity@ --- *
@@ -281,6 +283,8 @@ static unsigned sanity(const char *p, struct stat *st,
 {
   unsigned bad = 0;
   int stickyok = 0;
+  int i;
+  unsigned b;
 
   if (S_ISDIR(st->st_mode) &&
       (!(f & f_last) || (cp->cp_what & CP_STICKYOK)))
@@ -298,8 +302,7 @@ static unsigned sanity(const char *p, struct stat *st,
 
   if ((cp->cp_what & (CP_WRGRP | CP_WROTHGRP)) &&
       (st->st_mode & (0020 | stickyok)) == 0020) {
-    int i;
-    unsigned b = CP_WRGRP;
+    b = CP_WRGRP;
 
     if (cp->cp_what & CP_WROTHGRP) {
       b = CP_WROTHGRP;
index d52eac9..bd9d256 100644 (file)
@@ -1,7 +1,5 @@
 /* -*-c-*-
  *
- * $Id: checkpath.h,v 1.4 2004/04/08 01:36:22 mdw Exp $
- *
  * Check a path for safety
  *
  * (c) 1999 Mark Wooding
index 0751449..65d9390 100644 (file)
--- a/chkpath.c
+++ b/chkpath.c
@@ -1,7 +1,5 @@
 /* -*-c-*-
  *
- * $Id: chkpath.c,v 1.4 2004/04/08 01:36:22 mdw Exp $
- *
  * Check a user's file search path
  *
  * (c) 1999 Mark Wooding
@@ -45,6 +43,8 @@
 
 /*----- Main code ---------------------------------------------------------*/
 
+/* --- @report@ --- */
+
 static void report(unsigned what, int verbose,
                   const char *p, const char *msg,
                   void *arg)
index 589c945..05030ba 100644 (file)
--- a/tmpdir.1
+++ b/tmpdir.1
@@ -4,8 +4,10 @@
 tmpdir \- choose, or check a choice of, temporary directory
 .SH SYNOPSIS
 .B tmpdir
-.RB [ \-bc ]
-.RB [ \-v
+.RB [ \-bcv ]
+.RB [ \-g
+.IR group ]
+.RB [ \-C
 .IR dir ]
 .SH USAGE
 The
@@ -71,7 +73,15 @@ examine the user's shell and decide which syntax to use based on that.
 .B "\-c, \-\-cshell"
 Output an assignment using C shell syntax.
 .TP
-.BI "\-v, --verify " dir
+.BI "\-g, \-\-group " group
+Trust (the members of)
+.IR group :
+consider directories they can write to be safe.
+.TP
+.B "-v, \-\-verbose"
+Report problems to standard error.  Repeat for more verbosity.
+.TP
+.BI "\-C, --check " dir
 Don't try to find a temporary directory; just see whether
 .I dir
 is secure, and exit successfully if it is (and unsuccessfully if it
index f7e611b..f0fcb5f 100644 (file)
--- a/tmpdir.c
+++ b/tmpdir.c
@@ -1,7 +1,5 @@
 /* -*-c-*-
  *
- * $Id: tmpdir.c,v 1.5 2004/04/08 01:36:22 mdw Exp $
- *
  * Choose and check temporary directories
  *
  * (c) 1999 Mark Wooding
@@ -31,6 +29,7 @@
 #include "config.h"
 
 #include <errno.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <pwd.h>
+#include <grp.h>
 
 #include <mLib/alloc.h>
 #include <mLib/dstr.h>
+#include <mLib/macros.h>
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
 #include <mLib/report.h>
@@ -222,6 +223,13 @@ static char *goodtmp(void)
   return (0);
 }
 
+/* --- @report@ --- */
+
+static void report(unsigned what, int verbose,
+                  const char *p, const char *msg,
+                  void *arg)
+  { moan("%s", msg); }
+
 /* --- @usage@ --- */
 
 static void usage(FILE *fp)
@@ -254,7 +262,9 @@ Options supported:\n\
 \n\
 -b, --bourne           Output a `TMPDIR' setting for Bourne shell users.\n\
 -c, --cshell           Output a `TMPDIR' setting for C shell users.\n\
--v, --verify PATH      Check whether PATH is good, setting exit status.\n\
+-v, --verbose          Report problems to standard error.\n\
+-g, --group NAME       Trust group NAME to be honest and true.\n\
+-C, --check PATH       Check whether PATH is good, setting exit status.\n\
 \n\
 The default action is to examine the caller's shell and output a suitable\n\
 setting for that shell type.\n\
@@ -262,6 +272,46 @@ setting for that shell type.\n\
        fp);
 }
 
+/* --- @allowgroup@ --- *
+ *
+ * Arguments:  @const char *gname@ = trust group @gname@
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds the gid corresponding to @gname@ (which may be a number)
+ *             to the list of things we trust.
+ */
+
+static void allowgroup(const char *gname)
+{
+  struct group *gr;
+  const char *p;
+  gid_t g;
+
+  /* --- Check for numeric group spec --- */
+
+  for (p = gname; *p; p++) {
+    if (!isdigit((unsigned char)*p))
+      goto lookup;
+  }
+  g = atoi(gname);
+  goto insert;
+
+  /* --- Look up a group by name --- */
+
+lookup:
+  if ((gr = getgrnam(gname)) == 0)
+    die(1, "group %s not found", gname);
+  g = gr->gr_gid;
+
+  /* --- Insert the group into the table --- */
+
+insert:
+  if (cp.cp_gids >= N(cp.cp_gid))
+    die(1, "too many groups");
+  cp.cp_gid[cp.cp_gids++] = g;
+}
+
 /* --- @main@ --- *
  *
  * Arguments:  @int argc@ = number of command line arguments
@@ -276,6 +326,7 @@ int main(int argc, char *argv[])
 {
   int shell = 0;
   int duff = 0;
+  char *p;
 
   enum {
     sh_unknown,
@@ -287,10 +338,12 @@ int main(int argc, char *argv[])
 
   ego(argv[0]);
   me = geteuid();
-  cp.cp_what = CP_WRWORLD | CP_WRGRP | CP_WROTHUSR | CP_STICKYOK;
+  cp.cp_what = (CP_WRWORLD | CP_WROTHGRP | CP_WROTHUSR |
+               CP_STICKYOK | CP_REPORT);
   cp.cp_verbose = 0;
-  cp.cp_report = 0;
+  cp.cp_report = report;
   checkpath_setids(&cp);
+  cp.cp_gids = 0;                      /* ignore group membership */
   pw = getpwuid(me);
   if (!pw)
     die(1, "you don't exist");
@@ -304,10 +357,14 @@ int main(int argc, char *argv[])
       { "usage",       0,              0,      'u' },
       { "bourne",      0,              0,      'b' },
       { "cshell",      0,              0,      'c' },
-      { "verify",      OPTF_ARGREQ,    0,      'v' },
+      { "check",       OPTF_ARGREQ,    0,      'C' },
+      { "verify",      OPTF_ARGREQ,    0,      'C' },
+      { "verbose",     0,              0,      'v' },
+      { "trust-groups",        0,              0,      't' },
+      { "group",       OPTF_ARGREQ,    0,      'g' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "hVu" "bcv:", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "hVu" "bcvtg:c:", opts, 0, 0, 0);
 
     if (i < 0)
       break;
@@ -327,9 +384,15 @@ int main(int argc, char *argv[])
       case 'c':
        shell = sh_csh;
        break;
-      case 'v':
+      case 'C':
        return (!fullcheck(optarg));
        break;
+      case 'g':
+       allowgroup(optarg);
+       break;
+      case 'v':
+       cp.cp_verbose++;
+       break;
       default:
        duff = 1;
        break;
@@ -344,7 +407,6 @@ int main(int argc, char *argv[])
   /* --- Choose a shell --- */
 
   if (!shell) {
-    char *p;
     if (!(p = getenv("SHELL")))
       p = pw->pw_shell;
     if (strstr(p, "csh"))
@@ -355,19 +417,16 @@ int main(int argc, char *argv[])
 
   /* --- Start the checking --- */
 
-  {
-    char *p = goodtmp();
-    if (!p)
-      die(1, "no good tmp directory");
-    switch (shell) {
-      case sh_bourne:
-       printf("TMPDIR=\"%s\"; export TMPDIR\n", p);
-       break;
-      case sh_csh:
-       printf("setenv TMPDIR \"%s\"\n", p);
+  if ((p = goodtmp()) == 0)
+    die(1, "no good tmp directory");
+  switch (shell) {
+    case sh_bourne:
+      printf("TMPDIR=\"%s\"; export TMPDIR\n", p);
+      break;
+    case sh_csh:
+      printf("setenv TMPDIR \"%s\"\n", p);
        break;
-    }
-  }
+  }    
 
   return (0);
 }