Break checkpath_setids into separate functions which work properly even
authorMark Wooding <mdw@distorted.org.uk>
Sun, 13 Apr 2008 20:53:16 +0000 (21:53 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 13 Apr 2008 20:53:16 +0000 (21:53 +0100)
on a populated table.

checkpath.3
checkpath.c
checkpath.h

index 8c2b5ac..921dec7 100644 (file)
@@ -8,6 +8,10 @@ checkpath \- library for examining path security
 
 .BI "int checkpath(const char *" path ,
 .BI "              const struct checkpath *" cp ");"
 
 .BI "int checkpath(const char *" path ,
 .BI "              const struct checkpath *" cp ");"
+.BI "int checkpath_addgid(struct checkpath *" cp ", gid_t " g ");"
+.BI "void checkpath_setuid(struct checkpath *" cp ");"
+.BI "int checkpath_setgid(struct checkpath *" cp ");"
+.BI "int checkpath_setgroups(struct checkpath *" cp ");"
 .BI "void checkpath_setids(struct checkpath *" cp ");"
 .fi
 .SH DESCRIPTION
 .BI "void checkpath_setids(struct checkpath *" cp ");"
 .fi
 .SH DESCRIPTION
@@ -73,7 +77,38 @@ and
 can be set up to reflect the current user and group memberships by
 calling
 .B checkpath_setids
 can be set up to reflect the current user and group memberships by
 calling
 .B checkpath_setids
-passing the address of the structure to fill in.
+passing the address of the structure to fill in; this overwrites the
+previous contents of the
+.BR cp_uid ,
+.BR cp_gid ,
+and
+.BR cp_gids
+members.  Alternatively, the functions
+.BR checkpath_setuid ,
+.BR checkpath_setgid ,
+and
+.B checkpath_setgroups
+can be called to do the job in stages.  The
+.B checkpath_setuid
+function simply stores the process's real uid in
+.BR cp_uid .
+The
+.B checkpath_setgid
+and
+.B checkpath_setgroups
+functions store respectively the process's real gid and supplementary
+gids in the
+.B cp_gid
+array; they avoid inserting duplicate entries; they return 0 on success
+or \-1 if the table would overflow; they assume that the table is
+properly set up (minimally, just set
+.BR "cp_gids = 0" ).
+They use a utility function
+.B checkpath_addgid
+to do their work; it takes a pointer to a
+.B struct checkpath
+and a gid, and again returns 0 on success or \-1 if overflow would
+occur.
 .SS "The cp_what flags"
 The
 .B cp_what
 .SS "The cp_what flags"
 The
 .B cp_what
index 2047800..e594201 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <mLib/alloc.h>
 #include <mLib/dstr.h>
 
 #include <mLib/alloc.h>
 #include <mLib/dstr.h>
+#include <mLib/macros.h>
 
 #include "checkpath.h"
 
 
 #include "checkpath.h"
 
@@ -488,30 +489,95 @@ unsigned checkpath(const char *p, const struct checkpath *cp)
   return (bad);
 }
 
   return (bad);
 }
 
-/* --- @checkpath_setids@ --- *
+/* --- @checkpath_addgid@ --- *
  *
  * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
  *
  * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
+ *             @gid_t g@ = group id to add
  *
  *
- * Returns:    ---
+ * Returns:    Zero if successful, nonzero if the array is full.
  *
  *
- * Use:                Fills in the user ids and things in the structure.
+ * Use:                Adds the group @g@ to the structure.
  */
 
  */
 
-void checkpath_setids(struct checkpath *cp)
+int checkpath_addgid(struct checkpath *cp, gid_t g)
 {
 {
-  int n, i;
-  gid_t g = getgid();
+  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 @cp_uid@ slot of the structure with the real uid
+ *             of the current process.
+ */
+
+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.
+ */
 
 
-  cp->cp_uid = getuid();
-  n = getgroups(sizeof(cp->cp_gid) / sizeof(cp->cp_gid[0]), cp->cp_gid);
+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 i, n;
+  gid_t gg[NGROUPS_MAX];
+
+  n = getgroups(N(gg), gg);
   for (i = 0; i < n; i++) {
   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 -------------------------------------------------*/
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index bd9d256..5b2e938 100644 (file)
@@ -86,13 +86,63 @@ struct checkpath {
 
 extern unsigned checkpath(const char */*p*/, const struct checkpath */*cp*/);
 
 
 extern unsigned checkpath(const char */*p*/, const struct checkpath */*cp*/);
 
+/* --- @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.
+ */
+
+extern int checkpath_addgid(struct checkpath */*cp*/, gid_t /*g*/);
+
+/* --- @checkpath_setuid@ --- *
+ *
+ * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
+ *
+ * Returns:    ---
+ *
+ * Use:                Fills in the @cp_uid@ slot of the structure with the real uid
+ *             of the current process.
+ */
+
+extern void checkpath_setuid(struct checkpath */*cp*/);
+
+/* --- @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.
+ */
+
+extern int checkpath_setgid(/*cp*/);
+
+/* --- @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.
+ */
+
+extern int checkpath_setgroups(struct checkpath */*cp*/);
+
 /* --- @checkpath_setids@ --- *
  *
  * Arguments:  @struct checkpath *cp@ = pointer to block to fill in
  *
  * Returns:    ---
  *
 /* --- @checkpath_setids@ --- *
  *
  * 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 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.
  */
 
 extern void checkpath_setids(struct checkpath */*cp*/);
  */
 
 extern void checkpath_setids(struct checkpath */*cp*/);