Upgrade build system.
[checkpath] / checkpath.c
index 74eb243..a396d14 100644 (file)
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: checkpath.c,v 1.1 1999/04/06 20:12:07 mdw Exp $
+ * $Id: checkpath.c,v 1.6 2004/04/08 01:36:22 mdw Exp $
  *
  * Check a path for safety
  *
  * (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: checkpath.c,v $
- * Revision 1.1  1999/04/06 20:12:07  mdw
- * Initial revision
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
+#include "config.h"
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -52,7 +46,7 @@
 #include <mLib/alloc.h>
 #include <mLib/dstr.h>
 
-#include "path.h"
+#include "checkpath.h"
 
 /*----- Data structures ---------------------------------------------------*/
 
@@ -69,19 +63,15 @@ struct elt {
   char e_name[1];                      /* Name of the directory */
 };
 
-enum {
-  f_sticky = 1                         /* Directory has sticky bit set */
-};
+#define f_sticky 1u                    /* Directory has sticky bit set */
 
-enum {
-  f_last = 1                           /* This is the final item to check */
-};
+#define f_last 1u                      /* This is the final item to check */
 
 /*----- Static variables --------------------------------------------------*/
 
 static struct elt rootnode = { 0, 0, 0 }; /* Root of the list */
 static struct elt *sp;                 /* Stack pointer for list */
-static dstr d;                         /* Current path string */
+static dstr d = DSTR_INIT;             /* Current path string */
 
 /*----- Main code ---------------------------------------------------------*/
 
@@ -189,8 +179,8 @@ static void push(struct elt *e)
 
 /* --- @report@ --- *
  *
- * Arguments:  @struct chkpath *cp@ = pointer to context
- *             @int what@ = what sort of report is this?
+ * Arguments:  @const struct checkpath *cp@ = pointer to context
+ *             @unsigned what@ = what sort of report is this?
  *             @int verbose@ = how verbose is this?
  *             @const char *p@ = what path does it refer to?
  *             @const char *msg@ = the message to give to the user
@@ -200,7 +190,7 @@ static void push(struct elt *e)
  * Use:                Formats and presents messages to the client.
  */
 
-static void report(struct chkpath *cp, int what, int verbose,
+static void report(const struct checkpath *cp, unsigned what, int verbose,
                   const char *p, const char *msg, ...)
 {
   /* --- Decide whether to bin this message --- */
@@ -211,13 +201,12 @@ static void report(struct chkpath *cp, int what, int verbose,
   /* --- Format the message nicely --- */
 
   if (cp->cp_what & CP_REPORT) {
-    dstr d;
+    dstr d = DSTR_INIT;
     va_list ap;
     const char *q = msg;
     size_t n;
     int e = errno;
 
-    dstr_create(&d);
     va_start(ap, msg);
     if (verbose > 1)
       dstr_puts(&d, "[ ");
@@ -279,7 +268,7 @@ static void report(struct chkpath *cp, int what, int verbose,
  *
  * Arguments:  @const char *p@ = name of directory to check
  *             @struct stat *st@ = pointer to @stat@(2) block for it
- *             @struct chkpath *cp@ = pointer to caller parameters
+ *             @const struct checkpath *cp@ = pointer to caller parameters
  *             @unsigned f@ = various flags
  *
  * Returns:    Zero if everything's OK, else bitmask of problems.
@@ -287,16 +276,20 @@ static void report(struct chkpath *cp, int what, int verbose,
  * Use:                Performs the main load of sanity-checking on a directory.
  */
 
-static int sanity(const char *p, struct stat *st,
-                 struct chkpath *cp, unsigned f)
+static unsigned sanity(const char *p, struct stat *st,
+                      const struct checkpath *cp, unsigned f)
 {
-  int bad = 0;
-  int sticky = (cp->cp_what & CP_STICKYOK) || !(f & f_last) ? 01000 : 0;
+  unsigned bad = 0;
+  int stickyok = 0;
+
+  if (S_ISDIR(st->st_mode) &&
+      (!(f & f_last) || (cp->cp_what & CP_STICKYOK)))
+    stickyok = 01000;
 
   /* --- Check for world-writability --- */
 
   if ((cp->cp_what & CP_WRWORLD) &&
-      (st->st_mode & (0002 | sticky)) == 0002) {
+      (st->st_mode & (0002 | stickyok)) == 0002) {
     bad |= CP_WRWORLD;
     report(cp, CP_WRWORLD, 1, p, "** world writable **");
   }
@@ -304,19 +297,21 @@ static int sanity(const char *p, struct stat *st,
   /* --- Check for group-writability --- */
 
   if ((cp->cp_what & (CP_WRGRP | CP_WROTHGRP)) &&
-      (st->st_mode & (0020 | sticky)) == 0020) {
-    if (cp->cp_what & CP_WRGRP) {
-      bad |= CP_WRGRP;
-      report(cp, CP_WRGRP, 1, p, "writable by group %g", st->st_gid);
-    } else {
-      int i;
+      (st->st_mode & (0020 | stickyok)) == 0020) {
+    int i;
+    unsigned b = CP_WRGRP;
+
+    if (cp->cp_what & CP_WROTHGRP) {
+      b = CP_WROTHGRP;
       for (i = 0; i < cp->cp_gids; i++) {
        if (st->st_gid == cp->cp_gid[i])
-         goto good_gid;
+         b = cp->cp_what & CP_WRGRP;
       }
-      bad |= CP_WROTHGRP;
-      report(cp, CP_WROTHGRP, 1, p, "writable by group %g", st->st_gid);
-    good_gid:;
+    }
+    if (b) {
+      bad |= b;
+      report(cp, b, 1, p, "writable by %sgroup %g",
+            (b == CP_WROTHGRP) ? "other " : "", st->st_gid);
     }
   }
 
@@ -334,10 +329,10 @@ static int sanity(const char *p, struct stat *st,
   return (bad);
 }
 
-/* --- @path_check@ --- *
+/* --- @checkpath@ --- *
  *
  * Arguments:  @const char *p@ = directory name which needs checking
- *             @struct chkpath *cp@ = caller parameters for the check
+ *             @const struct checkpath *cp@ = parameters for the check
  *
  * Returns:    Zero if all is well, otherwise bitmask of problems.
  *
@@ -345,14 +340,14 @@ static int sanity(const char *p, struct stat *st,
  *             users could do to it.
  */
 
-int path_check(const char *p, struct chkpath *cp)
+unsigned checkpath(const char *p, const struct checkpath *cp)
 {
   char cwd[PATH_MAX];
   struct elt *e, *ee;
   struct stat st;
-  int bad = 0;
+  unsigned bad = 0;
 
-  /* --- Initialise stack pointer and path string --- */
+  /* --- Initialize stack pointer and path string --- */
 
   sp = &rootnode;
   dstr_destroy(&d);
@@ -418,18 +413,19 @@ int path_check(const char *p, struct chkpath *cp)
     /* --- Handle symbolic links specially --- */
 
     if (S_ISLNK(st.st_mode)) {
-      char buf[PATH_MAX];
+      dstr buf = DSTR_INIT;
       int i;
 
       /* --- Resolve the link --- */
 
-      if ((i = readlink(d.buf, buf, sizeof(buf))) < 0) {
+      dstr_ensure(&buf, st.st_size + 1);
+      if ((i = readlink(d.buf, buf.buf, buf.sz)) < 0) {
        report(cp, CP_ERROR, 0, d.buf, "can't readlink: %e");
        bad |= CP_ERROR;
        break;
       }
-      buf[i] = 0;
-      report(cp, CP_SYMLINK, 2, d.buf, "symlink -> `%s'", buf);
+      buf.buf[i] = 0;
+      report(cp, CP_SYMLINK, 2, d.buf, "symlink -> `%s'", buf.buf);
 
       /* --- Handle sticky parents --- *
        *
@@ -448,11 +444,12 @@ int path_check(const char *p, struct chkpath *cp)
 
       /* --- Sort out what to do from here --- */
 
-      if (buf[0] == '/')
+      if (buf.buf[0] == '/')
        popall();
       else
        pop();
-      ee = splitpath(buf, ee);
+      ee = splitpath(buf.buf, ee);
+      dstr_destroy(&buf);
       continue;
     }
 
@@ -488,23 +485,23 @@ int path_check(const char *p, struct chkpath *cp)
   return (bad);
 }
 
-/* --- @path_setids@ --- *
+/* --- @checkpath_setids@ --- *
  *
- * Arguments:  @struct chkpath *cp@ = pointer to block to fill in
+ * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
  *
- * Returns:    Zero if OK, else @-1@.
+ * Returns:    ---
  *
  * Use:                Fills in the user ids and things in the structure.
  */
 
-void path_setids(struct chkpath *cp)
+void checkpath_setids(struct checkpath *cp)
 {
   int n, i;
   gid_t g = getgid();
 
   cp->cp_uid = getuid();
   n = getgroups(sizeof(cp->cp_gid) / sizeof(cp->cp_gid[0]), cp->cp_gid);
-  
+
   for (i = 0; i < n; i++) {
     if (cp->cp_gid[i] == g)
       goto gid_ok;