bbd41d2
From 3e0812fe9d3f4712638a1c4c49bf2b2a7dc4311b Mon Sep 17 00:00:00 2001
bbd41d2
From: Ben Gamari <ben@smart-cactus.org>
bbd41d2
Date: Mon, 1 Jul 2019 11:03:33 -0400
bbd41d2
Subject: [PATCH] Call initgroups before setuid
bbd41d2
bbd41d2
Previously we would fail to call initgroups before setuid'ing. This
bbd41d2
meant that our groups we not be reset to reflect those our new user
bbd41d2
belongs to. Fix this.
bbd41d2
---
bbd41d2
 cbits/runProcess.c   | 32 +++++++++++++++++++++++++++++---
bbd41d2
 include/runProcess.h |  4 ++++
bbd41d2
 2 files changed, 33 insertions(+), 3 deletions(-)
bbd41d2
bbd41d2
diff --git a/cbits/runProcess.c b/cbits/runProcess.c
bbd41d2
index 10794bc..84d5fd4 100644
bbd41d2
--- a/cbits/runProcess.c
bbd41d2
+++ b/cbits/runProcess.c
bbd41d2
@@ -33,6 +33,10 @@ static long max_fd = 0;
bbd41d2
 extern void blockUserSignals(void);
bbd41d2
 extern void unblockUserSignals(void);
bbd41d2
 
bbd41d2
+// These are arbitrarily chosen -- JP
bbd41d2
+#define forkSetgidFailed 124
bbd41d2
+#define forkSetuidFailed 125
bbd41d2
+
bbd41d2
 // See #1593.  The convention for the exit code when
bbd41d2
 // exec() fails seems to be 127 (gleened from C's
bbd41d2
 // system()), but there's no equivalent convention for
bbd41d2
@@ -40,9 +44,8 @@ extern void unblockUserSignals(void);
bbd41d2
 #define forkChdirFailed 126
bbd41d2
 #define forkExecFailed  127
bbd41d2
 
bbd41d2
-// These are arbitrarily chosen -- JP
bbd41d2
-#define forkSetgidFailed 124
bbd41d2
-#define forkSetuidFailed 125
bbd41d2
+#define forkGetpwuidFailed 128
bbd41d2
+#define forkInitgroupsFailed 129
bbd41d2
 
bbd41d2
 __attribute__((__noreturn__))
bbd41d2
 static void childFailed(int pipe, int failCode) {
bbd41d2
@@ -182,6 +185,23 @@ runInteractiveProcess (char *const args[],
bbd41d2
         }
bbd41d2
 
bbd41d2
         if ( childUser) {
bbd41d2
+            // Using setuid properly first requires that we initgroups.
bbd41d2
+            // However, to do this we must know the username of the user we are
bbd41d2
+            // switching to.
bbd41d2
+            struct passwd pw;
bbd41d2
+            struct passwd *res = NULL;
bbd41d2
+            int buf_len = sysconf(_SC_GETPW_R_SIZE_MAX);
bbd41d2
+            char *buf = malloc(buf_len);
bbd41d2
+            gid_t suppl_gid = childGroup ? *childGroup : getgid();
bbd41d2
+            if ( getpwuid_r(*childUser, &pw, buf, buf_len, &res) != 0) {
bbd41d2
+                childFailed(forkCommunicationFds[1], forkGetpwuidFailed);
bbd41d2
+            }
bbd41d2
+            if ( res == NULL ) {
bbd41d2
+                childFailed(forkCommunicationFds[1], forkGetpwuidFailed);
bbd41d2
+            }
bbd41d2
+            if ( initgroups(res->pw_name, suppl_gid) != 0) {
bbd41d2
+                childFailed(forkCommunicationFds[1], forkInitgroupsFailed);
bbd41d2
+            }
bbd41d2
             if ( setuid( *childUser) != 0) {
bbd41d2
                 // ERROR
bbd41d2
                 childFailed(forkCommunicationFds[1], forkSetuidFailed);
bbd41d2
@@ -330,6 +350,12 @@ runInteractiveProcess (char *const args[],
bbd41d2
         case forkSetuidFailed:
bbd41d2
             *failed_doing = "runInteractiveProcess: setuid";
bbd41d2
             break;
bbd41d2
+        case forkGetpwuidFailed:
bbd41d2
+            *failed_doing = "runInteractiveProcess: getpwuid";
bbd41d2
+            break;
bbd41d2
+        case forkInitgroupsFailed:
bbd41d2
+            *failed_doing = "runInteractiveProcess: initgroups";
bbd41d2
+            break;
bbd41d2
         default:
bbd41d2
             *failed_doing = "runInteractiveProcess: unknown";
bbd41d2
             break;
bbd41d2
diff --git a/include/runProcess.h b/include/runProcess.h
bbd41d2
index 3807389..dff3905 100644
bbd41d2
--- a/include/runProcess.h
bbd41d2
+++ b/include/runProcess.h
bbd41d2
@@ -21,6 +21,10 @@
bbd41d2
 
bbd41d2
 #include <unistd.h>
bbd41d2
 #include <sys/types.h>
bbd41d2
+#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32))
bbd41d2
+#include <pwd.h>
bbd41d2
+#include <grp.h>
bbd41d2
+#endif
bbd41d2
 
bbd41d2
 #ifdef HAVE_FCNTL_H
bbd41d2
 #include <fcntl.h>