Release 1.2.4.
[checkpath] / tmpdir.c
index 453ebf3..0bf51d3 100644 (file)
--- a/tmpdir.c
+++ b/tmpdir.c
@@ -1,13 +1,11 @@
 /* -*-c-*-
  *
- * $Id: tmpdir.c,v 1.1 1999/04/06 20:12:07 mdw Exp $
- *
  * Choose and check temporary directories
  *
  * (c) 1999 Mark Wooding
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of chkpath.
  *
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * chkpath is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with chkpath; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: tmpdir.c,v $
- * Revision 1.1  1999/04/06 20:12:07  mdw
- * Initial revision
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
+#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>
 
-#include "path.h"
+#include "checkpath.h"
+#include "utils.h"
 
 /*----- Static variables --------------------------------------------------*/
 
 static uid_t me;
-static struct chkpath cp;
+static struct checkpath cp;
 static struct passwd *pw;
 
 /*----- Main code ---------------------------------------------------------*/
@@ -73,6 +69,17 @@ static struct passwd *pw;
  *             and @*f@ is set, then try to create the directory.
  */
 
+static void complain(const char *p, const char *msg, int err)
+{
+  dstr d = DSTR_INIT;
+
+  if (!cp.cp_verbose) return;
+  dstr_putf(&d, "Path: %s: %s", p, msg);
+  if (err) dstr_putf(&d, ": %s", strerror(err));
+  moan(d.buf);
+  dstr_destroy(&d);
+}
+
 static int ok(const char *p, int *f)
 {
   struct stat st;
@@ -83,9 +90,12 @@ static int ok(const char *p, int *f)
 
     /* --- Maybe create it if it doesn't exist --- */
 
-    if (errno != ENOENT || !f || !*f)
+    if (errno != ENOENT || !f || !*f) {
+      complain(p, "can't stat", errno);
       return (0);
+    }
     if (mkdir(p, 0700)) {
+      complain(p, "can't create", errno);
       *f = 0;
       return (0);
     }
@@ -96,8 +106,10 @@ static int ok(const char *p, int *f)
      * the @mkdir@.
      */
 
-    if (lstat(p, &st))
+    if (lstat(p, &st)) {
+      complain(p, "can't stat after creating", errno);
       return (0);
+    }
   }
 
   /* --- Make sure the directory is good --- *
@@ -106,7 +118,13 @@ static int ok(const char *p, int *f)
    * and writable only by its owner, and that owner must be me.
    */
 
-  if (S_ISDIR(st.st_mode) && (st.st_mode & 0777) == 0700 && st.st_uid == me)
+  if (!S_ISDIR(st.st_mode))
+    complain(p, "not a directory", 0);
+  else if (st.st_uid != me)
+    complain(p, "not owner", 0);
+  else if ((st.st_mode & 0777) != 0700)
+    complain(p, "non-owner access permitted", 0);
+  else
     return (1);
   return (0);
 }
@@ -128,7 +146,7 @@ static char *trytmp(const char *parent, const char *base)
                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ" };
   char *p, *q;
   char *qq;
-  dstr d;
+  dstr d = DSTR_INIT;
   int createflag = 1;
 
   /* --- Make sure the parent directory is sane --- *
@@ -139,12 +157,11 @@ static char *trytmp(const char *parent, const char *base)
    * safe.
    */
 
-  if (path_check(parent, &cp))
+  if (checkpath(parent, &cp))
     return (0);
 
   /* --- See whether the trivial version will work --- */
 
-  dstr_create(&d);
   dstr_putf(&d, "%s/%s", parent, base);
   if (ok(d.buf, &createflag))
     goto good;
@@ -189,9 +206,7 @@ good:
  */
 
 static int fullcheck(const char *p)
-{
-  return (path_check(p, &cp) == 0 && ok(p, 0));
-}
+  { return (checkpath(p, &cp) == 0 && ok(p, 0)); }
 
 /* --- @goodtmp@ --- *
  *
@@ -214,16 +229,12 @@ static char *goodtmp(void)
 
   /* --- Try making a directory in `/tmp' --- */
 
-  if (!(q = getenv("USER")) && !(q = getenv("LOGNAME")))
-    q = pw->pw_name;
-  if ((q = trytmp("/tmp", q)) != 0)
+  if ((q = trytmp("/tmp", pw->pw_name)) != 0)
     return (q);
 
   /* --- That failed: try a directory in the user's home --- */
 
-  if (!(q = getenv("HOME")))
-    q = pw->pw_dir;
-  if ((q = trytmp(q, "tmp")) != 0)
+  if ((q = trytmp(pw->pw_dir, "tmp")) != 0)
     return (q);
 
   /* --- Still no joy: give up --- *
@@ -235,19 +246,22 @@ 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)
-{
-  fprintf(fp, "Usage: %s [-bc] [-v PATH]\n", QUIS);
-}
+  { fprintf(fp, "Usage: %s [-bcv] [-g NAME] [-C PATH]\n", QUIS); }
 
 /* --- @version@ --- */
 
 static void version(FILE *fp)
-{
-  fprintf(fp, "%s version %s\n", QUIS, VERSION);
-}
+  { fprintf(fp, "%s version %s\n", QUIS, VERSION); }
 
 /* --- @help@ --- */
 
@@ -271,7 +285,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\
@@ -293,6 +309,7 @@ int main(int argc, char *argv[])
 {
   int shell = 0;
   int duff = 0;
+  char *p;
 
   enum {
     sh_unknown,
@@ -303,11 +320,12 @@ int main(int argc, char *argv[])
   /* --- Initialize variables --- */
 
   ego(argv[0]);
-  me = getuid();
-  cp.cp_what = CP_WRWORLD | CP_WRGRP | CP_WROTHUSR | CP_STICKYOK;
+  me = cp.cp_uid = geteuid();
+  cp.cp_what = (CP_WRWORLD | CP_WROTHGRP | CP_WROTHUSR |
+               CP_STICKYOK | CP_REPORT | CP_ERROR);
   cp.cp_verbose = 0;
-  cp.cp_report = 0;
-  path_setids(&cp);
+  cp.cp_report = report;
+  cp.cp_gids = 0;                      /* ignore group membership */
   pw = getpwuid(me);
   if (!pw)
     die(1, "you don't exist");
@@ -317,14 +335,18 @@ int main(int argc, char *argv[])
   for (;;) {
     static struct option opts[] = {
       { "help",                0,              0,      'h' },
-      { "version",     0,              0,      'V' },
+      { "version",     0,              0,      'V' },
       { "usage",       0,              0,      'u' },
       { "bourne",      0,              0,      'b' },
       { "cshell",      0,              0,      'c' },
-      { "verify",      gFlag_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;
@@ -344,9 +366,15 @@ int main(int argc, char *argv[])
       case 'c':
        shell = sh_csh;
        break;
-      case 'v':
+      case 'C':
        return (!fullcheck(optarg));
        break;
+      case 'g':
+       allowgroup(&cp, optarg);
+       break;
+      case 'v':
+       cp.cp_verbose++;
+       break;
       default:
        duff = 1;
        break;
@@ -361,7 +389,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"))
@@ -372,18 +399,15 @@ 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);