Long overdue whitespace cleanup.
[checkpath] / checkpath.c
index b6ee94e..e594201 100644 (file)
@@ -1,13 +1,11 @@
 /* -*-c-*-
  *
- * $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.
@@ -28,6 +26,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#include "config.h"
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -43,6 +43,7 @@
 
 #include <mLib/alloc.h>
 #include <mLib/dstr.h>
+#include <mLib/macros.h>
 
 #include "checkpath.h"
 
@@ -152,10 +153,7 @@ static void pop(void)
  */
 
 static void popall(void)
-{
-  while (sp->e_link)
-    pop();
-}
+  { while (sp->e_link) pop(); }
 
 /* --- @push@ --- *
  *
@@ -191,75 +189,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@ --- *
@@ -279,6 +284,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)))
@@ -296,8 +303,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;
@@ -483,30 +489,95 @@ unsigned checkpath(const char *p, const struct checkpath *cp)
   return (bad);
 }
 
-/* --- @checkpath_setids@ --- *
+/* --- @checkpath_addgid@ --- *
+ *
+ * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
+ *             @gid_t g@ = group id to add
+ *
+ * Returns:    Zero if successful, nonzero if the array is full.
+ *
+ * Use:                Adds the group @g@ to the structure.
+ */
+
+int checkpath_addgid(struct checkpath *cp, gid_t g)
+{
+  int i;
+
+  for (i = 0; i < cp->cp_gids; i++) {
+    if (cp->cp_gid[i] == g)
+      return (0);
+  }
+  if (cp->cp_gids >= N(cp->cp_gid))
+    return (-1);
+  cp->cp_gid[cp->cp_gids++] = g;
+  return (0);
+}
+
+/* --- @checkpath_setuid@ --- *
  *
  * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
  *
  * Returns:    ---
  *
- * Use:                Fills in the user ids and things in the structure.
+ * Use:                Fills in the @cp_uid@ slot of the structure with the real uid
+ *             of the current process.
  */
 
-void checkpath_setids(struct checkpath *cp)
+void checkpath_setuid(struct checkpath *cp) { cp->cp_uid = getuid(); }
+
+/* --- @checkpath_setgid@ --- *
+ *
+ * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
+ *
+ * Returns:    Zero if successful, nonzero if the array is full.
+ *
+ * Use:                Adds the real gid of the current process to the @cp_gid@
+ *             array.
+ */
+
+int checkpath_setgid(struct checkpath *cp)
+  { return (checkpath_addgid(cp, getgid())); }
+
+/* --- @checkpath_setgroups@ --- *
+ *
+ * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
+ *
+ * Returns:    Zero if successful, nonzero if the array is full.
+ *
+ * Use:                Adds the current process's supplementary groups to the
+ *             @cp_gid@ table.
+ */
+
+int checkpath_setgroups(struct checkpath *cp)
 {
-  int n, i;
-  gid_t g = getgid();
+  int i, n;
+  gid_t gg[NGROUPS_MAX];
 
-  cp->cp_uid = getuid();
-  n = getgroups(sizeof(cp->cp_gid) / sizeof(cp->cp_gid[0]), cp->cp_gid);
-  
+  n = getgroups(N(gg), gg);
   for (i = 0; i < n; i++) {
-    if (cp->cp_gid[i] == g)
-      goto gid_ok;
+    if (checkpath_addgid(cp, gg[i]))
+      return (-1);
   }
-  cp->cp_gid[n++] = g;
-gid_ok:
-  cp->cp_gids = n;
+  return (0);
+}
+
+/* --- @checkpath_setids@ --- *
+ *
+ * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
+ *
+ * Returns:    ---
+ *
+ * Use:                Fills in the user ids and things in the structure.  This is
+ *             equivalent to setting @cp_gids = 0@ and then calling
+ *             @_setuid@, @_setgid@ and @_setgroups@.  It can't fail.
+ */
+
+void checkpath_setids(struct checkpath *cp)
+{
+  cp->cp_gids = 0;
+  checkpath_setuid(cp);
+  checkpath_setgid(cp);
+  checkpath_setgroups(cp);
 }
 
 /*----- That's all, folks -------------------------------------------------*/