]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Allow strongSwan to be spawned as non-root user
authorMicah Morton <mortonm@chromium.org>
Tue, 17 Apr 2018 20:29:03 +0000 (13:29 -0700)
committerTobias Brunner <tobias@strongswan.org>
Mon, 14 May 2018 13:50:01 +0000 (15:50 +0200)
This patch allows for giving strongSwan only the runtime capabilities it
needs, rather than full root privileges.

Adds preprocessor directives which allow strongSwan to be configured to
 1) start up as a non-root user
 2) avoid modprobe()'ing IPsec kernel modules into the kernel, which
    would normally require root or CAP_SYS_MODULE

Additionally, some small mods to charon/libstrongswan ensure that charon
fully supports starting as a non-root user.

Tested with strongSwan 5.5.3.

src/charon/charon.c
src/libstrongswan/networking/streams/stream_service_unix.c
src/libstrongswan/utils/capabilities.c
src/libstrongswan/utils/capabilities.h
src/starter/starter.c

index 1d1e623c11c8abe7bc40f4cc61e87202355ae28d..30f6ce2f6ecf1d5d29f946a495b5746305b8692e 100644 (file)
@@ -231,9 +231,15 @@ static bool check_pidfile()
                        DBG1(DBG_LIB, "setting FD_CLOEXEC for '"PID_FILE"' failed: %s",
                                 strerror(errno));
                }
-               ignore_result(fchown(fd,
-                                                        lib->caps->get_uid(lib->caps),
-                                                        lib->caps->get_gid(lib->caps)));
+               /* Only fchown() the pidfile if we have CAP_CHOWN. Otherwise,
+                * directory permissions should allow pidfile to be accessed
+                * by the UID/GID under which the charon deamon will run. */
+               if (lib->caps->check(lib->caps, CAP_CHOWN))
+               {
+                       ignore_result(fchown(fd,
+                                                                lib->caps->get_uid(lib->caps),
+                                                                lib->caps->get_gid(lib->caps)));
+               }
                fprintf(pidfile, "%d\n", getpid());
                fflush(pidfile);
                return FALSE;
index 1ed27c499db7ea10a8685b17f699df14deb0776e..92640fc9130f3f8f943f849f97e86208a57afb1d 100644 (file)
@@ -39,8 +39,9 @@ stream_service_t *stream_service_create_unix(char *uri, int backlog)
        }
        if (!lib->caps->check(lib->caps, CAP_CHOWN))
        {       /* required to chown(2) service socket */
-               DBG1(DBG_NET, "socket '%s' requires CAP_CHOWN capability", uri);
-               return NULL;
+               DBG1(DBG_NET, "cannot change ownership of socket '%s' without "
+                        "CAP_CHOWN capability. socket directory should be accessible to "
+                        "UID/GID under which the deamon will run", uri);
        }
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd == -1)
@@ -58,7 +59,9 @@ stream_service_t *stream_service_create_unix(char *uri, int backlog)
                return NULL;
        }
        umask(old);
-       if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),
+       /* only attempt to chown() socket if we have CAP_CHOWN */
+       if (lib->caps->check(lib->caps, CAP_CHOWN) &&
+               chown(addr.sun_path, lib->caps->get_uid(lib->caps),
                          lib->caps->get_gid(lib->caps)) != 0)
        {
                DBG1(DBG_NET, "changing socket permissions for '%s' failed: %s",
index ce5f550b50ca4d742c0453a7e7fb247da8ef3858..bd74e7ce79f8cf681cf1293f6f7988b069218434 100644 (file)
@@ -422,7 +422,10 @@ METHOD(capabilities_t, drop, bool,
 {
 #ifndef WIN32
 #ifdef HAVE_PRCTL
-       prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+       if (has_capability(this, CAP_SETPCAP, NULL))
+       {
+               prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+       }
 #endif
 
        if (this->uid && !init_supplementary_groups(this))
index 20c18554ba5b270d9f719b4d216403cbf89d7042..385a337e58b5d74a7ec4f67dc30ea85a061663f4 100644 (file)
@@ -47,6 +47,9 @@ typedef struct capabilities_t capabilities_t;
 #ifndef CAP_DAC_OVERRIDE
 # define CAP_DAC_OVERRIDE 1
 #endif
+#ifndef CAP_SETPCAP
+# define CAP_SETPCAP 8
+#endif
 
 /**
  * POSIX capability dropping abstraction layer.
index 6c07393404051d1355f5f3170ca9be6fc6e2dcc4..8ca1af29c2b037aa6114a7ce9eb346cdcb476e69 100644 (file)
@@ -477,6 +477,7 @@ int main (int argc, char **argv)
                }
        }
 
+#ifndef STARTER_ALLOW_NON_ROOT
        /* verify that we can start */
        if (getuid() != 0)
        {
@@ -484,6 +485,7 @@ int main (int argc, char **argv)
                cleanup();
                exit(LSB_RC_NOT_ALLOWED);
        }
+#endif
 
        if (check_pid(pid_file))
        {
@@ -520,6 +522,7 @@ int main (int argc, char **argv)
                exit(LSB_RC_INVALID_ARGUMENT);
        }
 
+#ifndef SKIP_KERNEL_IPSEC_MODPROBES
        /* determine if we have a native netkey IPsec stack */
        if (!starter_netkey_init())
        {
@@ -530,6 +533,7 @@ int main (int argc, char **argv)
                        DBG1(DBG_APP, "no known IPsec stack detected, ignoring!");
                }
        }
+#endif
 
        last_reload = time_monotonic(NULL);