>From 0bc3f5213743030206d0f40b342599d87a68b474 Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Sun, 22 Dec 2013 16:13:56 -0500
Subject: [PATCH] Add support for dropping privileges

If the 'proxy user' configuation option is set in the [gssproxy] section then
GSS Proxy will drop privileges to the specified after setting up all the
sockets.

Care must be taken to make sure all the resources the daemon need access to
(keytabs, ccache directories, etc..) are accessible as the proxy user.

Implements: https://fedorahosted.org/gss-proxy/ticket/102

Signed-off-by: Simo Sorce <simo@redhat.com>
---
 proxy/man/gssproxy.conf.5.xml |  9 +++++++++
 proxy/src/gp_config.c         | 11 +++++++++++
 proxy/src/gp_init.c           | 46 +++++++++++++++++++++++++++++++++++++++++++
 proxy/src/gp_proxy.h          |  3 +++
 proxy/src/gssproxy.c          |  5 +++++
 5 files changed, 74 insertions(+)

diff --git a/proxy/man/gssproxy.conf.5.xml b/proxy/man/gssproxy.conf.5.xml
index b4d5adde0b777ce062134104bb2ce7bf61d38e96..95fdb65431566e1266e8dee12b4777307f0677b9 100644
--- a/proxy/man/gssproxy.conf.5.xml
+++ b/proxy/man/gssproxy.conf.5.xml
@@ -254,6 +254,15 @@
                     </varlistentry>
 
                 <varlistentry>
+                    <term>run_as_user (string)</term>
+                    <listitem>
+                        <para>The name of the user gssproxy will drop privileges to.</para>
+                        <para>This option is only available in the global section.</para>
+                        <para>Default: run_as_user = </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>selinux_context (string)</term>
                     <listitem>
                         <para>This parameter instructs the proxy to allow map a
diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c
index ee96975c3544597fda1bbf4fdae533de9a922755..8afb6fe5e0d0af92ec7c0d7b734691aa47bb77a0 100644
--- a/proxy/src/gp_config.c
+++ b/proxy/src/gp_config.c
@@ -453,6 +453,17 @@ int load_config(struct gp_config *cfg)
         goto done;
     }
 
+    ret = gp_config_get_string(ctx, "gssproxy", "run_as_user", &tmpstr);
+    if (ret == 0) {
+        cfg->proxy_user = strdup(tmpstr);
+        if (!cfg->proxy_user) {
+            ret = ENOMEM;
+            goto done;
+        }
+    } else if (ret != ENOENT) {
+        goto done;
+    }
+
     ret = gp_config_get_int(ctx, "gssproxy", "worker threads",
                             &cfg->num_workers);
     if (ret != 0 && ret != ENOENT) {
diff --git a/proxy/src/gp_init.c b/proxy/src/gp_init.c
index 7e29c59de3f242b9ef4561f57220bf73e58098bb..830ae16a30d90ffa9f536a33d7e6c9519ebc5547 100644
--- a/proxy/src/gp_init.c
+++ b/proxy/src/gp_init.c
@@ -33,6 +33,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
 #include "gp_proxy.h"
 
 void init_server(bool daemonize)
@@ -207,3 +209,47 @@ void write_pid(void)
                 GP_PID_FILE, ret, gp_strerror(ret));
     }
 }
+
+int drop_privs(struct gp_config *cfg)
+{
+    char buf[2048];
+    struct passwd *pw, pws;
+    int ret;
+
+    if (cfg->proxy_user == NULL) {
+        /* not dropping privs */
+        return 0;
+    }
+
+    ret = getpwnam_r(cfg->proxy_user, &pws, buf, 2048, &pw);
+    if (ret) {
+        GPDEBUG("Failed to look up proxy user: '%s'! [%d:%s]\n",
+                cfg->proxy_user, ret, gp_strerror(ret));
+        return ret;
+    }
+
+    ret = initgroups(pw->pw_name, pw->pw_gid);
+    if (ret) {
+        GPDEBUG("Failed to set access credentials: [%d:%s]\n",
+                ret, gp_strerror(ret));
+        return ret;
+    }
+
+    ret = setgid(pw->pw_gid);
+    if (ret == -1) {
+        ret = errno;
+        GPDEBUG("Failed to set group id to %d: [%d:%s]\n",
+                pw->pw_gid, ret, gp_strerror(ret));
+        return ret;
+    }
+
+    ret = setuid(pw->pw_uid);
+    if (ret == -1) {
+        ret = errno;
+        GPDEBUG("Failed to set user id to %d: [%d:%s]\n",
+                pw->pw_uid, ret, gp_strerror(ret));
+        return ret;
+    }
+
+    return 0;
+}
diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h
index b6c64ae727d902fa73e87226ab5c1cf8506b1bf4..733fec515b59ba8df4e2ec3faf54fd6f9db69164 100644
--- a/proxy/src/gp_proxy.h
+++ b/proxy/src/gp_proxy.h
@@ -74,6 +74,8 @@ struct gp_config {
 
     struct gp_service **svcs;
     int num_svcs;
+
+    char *proxy_user;       /* user to drop privs to if not NULL */
 };
 
 struct gp_workers;
@@ -109,6 +111,7 @@ void fini_server(void);
 verto_ctx *init_event_loop(void);
 void init_proc_nfsd(struct gp_config *cfg);
 void write_pid(void);
+int drop_privs(struct gp_config *cfg);
 
 /* from gp_socket.c */
 struct gp_sock_ctx *init_unix_socket(struct gssproxy_ctx *gpctx,
diff --git a/proxy/src/gssproxy.c b/proxy/src/gssproxy.c
index 1fca9222377589cfac6d8e60acd7ca11f3e14720..1bf0a0bc84c7c06642bd8d8e83567d9b6216238f 100644
--- a/proxy/src/gssproxy.c
+++ b/proxy/src/gssproxy.c
@@ -142,6 +142,11 @@ int main(int argc, const char *argv[])
     /* special call to tell the Linux kernel gss-proxy is available */
     init_proc_nfsd(gpctx->config);
 
+    ret = drop_privs(gpctx->config);
+    if (ret) {
+        exit(EXIT_FAILURE);
+    }
+
     ret = gp_workers_init(gpctx);
     if (ret) {
         exit(EXIT_FAILURE);
-- 
1.8.4.2

