OVS daemons can now support --user option to run as a non-root user with less privileges.
See the manpage patch for more descriptions. Signed-off-by: Andy Zhou <az...@nicira.com> ---- v3->v4: calling daemon_become_new_user() from daemonize_start(), so the API works will for most daemons. In case a daemon processe needs to switch user prior to calling daemonize_start(), it daemon_become_new_user() can be called directly. Added check in daemonize_start() to make sure --user option has been executed if specified. On linux, libcap-ng is used exclusively for executing the --user option. On Windows, --user option will cause the process to die with an error message. All daemons now accepts --user option. --- NEWS | 1 + lib/daemon-unix.c | 361 +++++++++++++++++++++++++++++- lib/daemon-windows.c | 14 +- lib/daemon.c | 2 +- lib/daemon.h | 33 ++- lib/daemon.man | 15 ++ ovn/controller-vtep/ovn-controller-vtep.c | 2 +- ovn/controller/ovn-controller.c | 2 +- ovn/northd/ovn-northd.c | 2 +- ovsdb/ovsdb-client.c | 5 +- ovsdb/ovsdb-server.c | 3 +- tests/test-jsonrpc.c | 2 +- tests/test-netflow.c | 4 +- tests/test-sflow.c | 2 +- utilities/ovs-ofctl.c | 4 +- utilities/ovs-testcontroller.c | 6 +- vswitchd/ovs-vswitchd.c | 8 +- 17 files changed, 438 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index ca22c8e..ee4dc2a 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ Post-v2.4.0 targets to run a new system testsuite. These tests can be run inside a Vagrant box. See INSTALL.md for details - Dropped support for GRE64 tunnel. + - Added --user option to all daemons v2.4.0 - 20 Aug 2015 diff --git a/lib/daemon-unix.c b/lib/daemon-unix.c index eb95521..9efe43a 100644 --- a/lib/daemon-unix.c +++ b/lib/daemon-unix.c @@ -19,6 +19,8 @@ #include "daemon-private.h" #include <errno.h> #include <fcntl.h> +#include <grp.h> +#include <pwd.h> #include <signal.h> #include <stdlib.h> #include <string.h> @@ -26,6 +28,9 @@ #include <sys/wait.h> #include <sys/stat.h> #include <unistd.h> +#if HAVE_LIBCAPNG +#include <cap-ng.h> +#endif #include "command-line.h" #include "fatal-signal.h" #include "dirs.h" @@ -39,6 +44,18 @@ VLOG_DEFINE_THIS_MODULE(daemon_unix); +#ifdef __linux__ +#define LINUX 1 +#else +#define LINUX 0 +#endif + +#if HAVE_LIBCAPNG +#define LIBCAPNG 1 +#else +#define LIBCAPNG 0 +#endif + /* --detach: Should we run in the background? */ bool detach; /* Was --detach specified? */ static bool detached; /* Have we already detached? */ @@ -64,6 +81,15 @@ static int daemonize_fd = -1; * it dies due to an error signal? */ static bool monitor; +/* --user: Only root can use this option. Switch to new uid:gid after + * initially running as root. */ +static bool switch_user = false; +static bool non_root_user = false; +static uid_t uid; +static gid_t gid; +static char *user = NULL; +static void daemon_become_new_user__(bool access_datapath); + static void check_already_running(void); static int lock_pidfile(FILE *, int command); static pid_t fork_and_clean_up(void); @@ -409,11 +435,21 @@ monitor_daemon(pid_t daemon_pid) * daemon_complete()) or that it failed to start up (by exiting with a nonzero * exit code). */ void -daemonize_start(void) +daemonize_start(bool access_datapath) { assert_single_threaded(); daemonize_fd = -1; + if (switch_user) { + daemon_become_new_user__(access_datapath); + switch_user = false; + } + + /* If --user is specified, make sure user switch has completed by now. */ + if (non_root_user) { + ovs_assert(geteuid() && getuid()); + } + if (detach) { pid_t pid; @@ -645,7 +681,7 @@ error: } /* Opens and reads a PID from 'pidfile'. Returns the positive PID if - * successful, otherwise a negative errno value. */ + *successful, otherwise a negative errno value. */ pid_t read_pidfile(const char *pidfile) { @@ -684,3 +720,324 @@ should_service_stop(void) { return false; } + + +static bool +gid_matches(gid_t expected, gid_t value) +{ + return expected == -1 || expected == value; +} + +static bool +gid_verify(gid_t real, gid_t effective, gid_t saved) +{ + gid_t r, e, s; + + return (getresgid(&r, &e, &s) == 0 && + gid_matches(real, r) && + gid_matches(effective, e) && + gid_matches(saved, s)); +} + +static void +daemon_switch_group(gid_t real, gid_t effective, + gid_t saved) +{ + if ((setresgid(real, effective, saved) == -1) || + !gid_verify(real, effective, saved)) { + VLOG_FATAL("%s: fail to switch group to gid as %d, aborting", + pidfile, gid); + } +} + +static bool +uid_matches(uid_t expected, uid_t value) +{ + return expected == -1 || expected == value; +} + +static bool +uid_verify(const uid_t real, const uid_t effective, const uid_t saved) +{ + uid_t r, e, s; + + return (getresuid(&r, &e, &s) == 0 && + uid_matches(real, r) && + uid_matches(effective, e) && + uid_matches(saved, s)); +} + +static void +daemon_switch_user(const uid_t real, const uid_t effective, const uid_t saved, + const char *user) +{ + if ((setresuid(real, effective, saved) == -1) || + !uid_verify(real, effective, saved)) { + VLOG_FATAL("%s: fail to switch user to %s, aborting", + pidfile, user); + } +} + +/* Use portable Unix APIs to switch uid:gid, when datapath + * access is not required. On Linux systems, all capabilities + * will be dropped. */ +static void +daemon_become_new_user_unix(void) +{ + /* "Setuid Demystified" by Hao Chen, etc outlines some caveats of + * around unix system call setuid() and friends. This implementation + * mostly follow the advice given by the paper. The paper is + * published in 2002, so things could have changed. */ + + /* Change both real and effective uid and gid will permanently + * drop the process' privilege. "Setuid Demystified" suggested + * that calling getuid() after each setuid() call to verify they + * are actually set, because checking return code alone is not + * sufficient. */ + daemon_switch_group(gid, gid, gid); + if (user && initgroups(user, gid) == -1) { + VLOG_FATAL("%s: fail to add supplementary group gid %d, " + "aborting", pidfile, gid); + } + daemon_switch_user(uid, uid, uid, user); +} + +/* Linux specific implementation of daemon_become_new_user() + * using libcap-ng. */ +#if defined __linux__ && HAVE_LIBCAPNG +static void +daemon_become_new_user_linux(bool access_datapath) +{ + int ret; + + ret = capng_get_caps_process(); + + if (!ret) { + if (capng_have_capabilities(CAPNG_SELECT_CAPS) > CAPNG_NONE) { + unsigned int cap = CAP_IPC_LOCK | CAP_NET_BIND_SERVICE; + + capng_clear(CAPNG_SELECT_BOTH); + if (access_datapath) { + cap |= CAP_NET_ADMIN | CAP_NET_RAW; + } + ret = capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, + cap); + } else { + ret = -1; + } + } + + if (!ret) { + /* CAPNG_INIT_SUPP_GRP will be a better choice than + * CAPNG_DROP_SUPP_GRP. However this enum value is only defined + * with libcap-ng higher than version 0.7.4, which is not wildly + * available on many Linux distributions yet. Taking a more + * conservative approach to make sure OVS behaves consistently. + * + * XXX We may change this for future OVS releases. + */ + ret = capng_change_id(uid, gid, CAPNG_DROP_SUPP_GRP + | CAPNG_CLEAR_BOUNDING); + } + + if (ret) { + VLOG_FATAL("%s: libcap-ng fail to switch to user and group " + "%d:%d, aborting", pidfile, uid, gid); + } +} +#endif + +static void +daemon_become_new_user__(bool access_datapath) +{ + if (LINUX) { + if (LIBCAPNG) { + daemon_become_new_user_linux(access_datapath); + } else { + VLOG_FATAL("%s: fail to downgrade user using libcap-ng. " + "(libcap-ng is not configured at compile time), " + "aborting.", pidfile); + } + } else { + ovs_assert(!access_datapath); + daemon_become_new_user_unix(); + } +} + +/* Noramlly, user switch is embedded within daemonize_start(). + * However, there in case the user switch needs to be done + * before daemonize_start(), the following API can be used. */ +void +daemon_become_new_user(bool access_datapath) +{ + assert_single_threaded(); + if (switch_user) { + daemon_become_new_user__(access_datapath); + + /* Make sure daemonize_start() will not switch + * user again. */ + switch_user = false; + } +} + +/* Return the maximun suggested buffer size for both getpwname_r() + * and getgrnam_r(). + * + * This size may still not be big enough. In case getpwname_r() + * and friends return ERANGE, a larger buffer should be supplied to + * retry. (The man page did not specify the max size to stop at, we + * will keep trying with doubling the buffer size for each round until + * the size wraps around size_t. */ +static size_t +get_sysconf_buffer_size(void) +{ + size_t bufsize, pwd_bs = 0, grp_bs = 0; + const size_t default_bufsize = 1024; + + errno = 0; + if ((pwd_bs = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) { + if (errno) { + VLOG_FATAL("%s: Read initial passwordd struct size " + "failed (%s), aborting. ", pidfile, + ovs_strerror(errno)); + } + } + + if ((grp_bs = sysconf(_SC_GETGR_R_SIZE_MAX)) == -1) { + if (errno) { + VLOG_FATAL("%s: Read initial group struct size " + "failed (%s), aborting. ", pidfile, + ovs_strerror(errno)); + } + } + + bufsize = MAX(pwd_bs, grp_bs); + return bufsize ? bufsize : default_bufsize; +} + +/* Try to double the size of '*buf', return true + * if successful, and '*sizep' will be updated with + * the new size. Otherwise, return false. */ +static bool +enlarge_buffer(char **buf, size_t *sizep) +{ + size_t newsize = *sizep * 2; + + if (newsize > *sizep) { + *buf = xrealloc(*buf, newsize); + *sizep = newsize; + return true; + } + + return false; +} + +/* Parse and sanity check user_spec. + * + * If successful, set global variables 'uid' and 'gid' + * with the parsed results. Global variable 'user' + * will be pointing to a string that stores the name + * of the user to be switched into. + * + * Also set 'switch_to_new_user' to true, The actual + * user switching is done as soon as daemonize_start() + * is called. I/O access before calling daemonize_start() + * will still be with root's credential. */ +void +daemon_set_new_user(const char *user_spec) +{ + char *pos = strchr(user_spec, ':'); + size_t init_bufsize, bufsize; + + init_bufsize = get_sysconf_buffer_size(); + uid = getuid(); + gid = getgid(); + + if (geteuid() || uid) { + VLOG_FATAL("%s: only root can use --user option", pidfile); + } + + user_spec += strspn(user_spec, " \t\r\n"); + size_t len = pos ? pos - user_spec : strlen(user_spec); + char *buf; + struct passwd pwd, *res; + int e; + + bufsize = init_bufsize; + buf = xmalloc(bufsize); + if (len) { + user = xmemdup0(user_spec, len); + + while ((e = getpwnam_r(user, &pwd, buf, bufsize, &res)) == ERANGE) { + if (!enlarge_buffer(&buf, &bufsize)) { + break; + } + } + + if (e != 0) { + VLOG_FATAL("%s: Failed to retrive user %s's uid (%s), aborting.", + pidfile, user, ovs_strerror(e)); + } + } else { + /* User name is not specified, use current user. */ + while ((e = getpwuid_r(uid, &pwd, buf, bufsize, &res)) == ERANGE) { + if (!enlarge_buffer(&buf, &bufsize)) { + break; + } + } + + if (e != 0) { + VLOG_FATAL("%s: Failed to retrive current user's name " + "(%s), aborting.", pidfile, ovs_strerror(e)); + } + user = xstrdup(pwd.pw_name); + } + + uid = pwd.pw_uid; + gid = pwd.pw_gid; + free(buf); + + if (pos) { + char *grpstr = pos + 1; + grpstr += strspn(grpstr, " \t\r\n"); + + if (*grpstr) { + struct group grp, *res; + + bufsize = init_bufsize; + buf = xmalloc(bufsize); + while ((e = getgrnam_r(grpstr, &grp, buf, bufsize, &res)) + == ERANGE) { + if (!enlarge_buffer(&buf, &bufsize)) { + break; + } + } + + if (e) { + VLOG_FATAL("%s: Failed to get group entry for %s, " + "(%s), aborting.", pidfile, grpstr, + ovs_strerror(e)); + } + + if (gid != grp.gr_gid) { + char **mem; + + for (mem = grp.gr_mem; *mem; ++mem) { + if (!strcmp(*mem, user)) { + break; + } + } + + if (!*mem) { + VLOG_FATAL("%s: Invalid --user option %s (user %s is " + "not in group %s), aborting.", pidfile, + user_spec, user, grpstr); + } + gid = grp.gr_gid; + } + free(buf); + } + } + + switch_user = non_root_user = true; +} diff --git a/lib/daemon-windows.c b/lib/daemon-windows.c index 04e1f1a..fa6b230 100644 --- a/lib/daemon-windows.c +++ b/lib/daemon-windows.c @@ -446,7 +446,8 @@ make_pidfile(void) /* Don't close the pidfile till the process exits. */ } -void daemonize_start(void) +void +daemonize_start(bool access_datapath OVS_UNUSED) { if (pidfile) { make_pidfile(); @@ -473,6 +474,11 @@ daemonize_complete(void) service_complete(); } +void +dameon_become_new_user(bool access_datapath OVS_UNUSED) +{ +} + /* Returns the file name that would be used for a pidfile if 'name' were * provided to set_pidfile(). The caller must free the returned string. */ char * @@ -484,3 +490,9 @@ make_pidfile_name(const char *name) return xasprintf("%s/%s.pid", ovs_rundir(), program_name); } } + +void +daemon_set_new_user(const char *user_spec OVS_UNUSED) +{ + VLOG_FATAL("--user options is not currently supported."); +} diff --git a/lib/daemon.c b/lib/daemon.c index 4ac32b8..b8313d4 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -41,7 +41,7 @@ get_detach(void) void daemonize(void) { - daemonize_start(); + daemonize_start(false); daemonize_complete(); } diff --git a/lib/daemon.h b/lib/daemon.h index 959341d..cb663ca 100644 --- a/lib/daemon.h +++ b/lib/daemon.h @@ -42,14 +42,16 @@ OPT_NO_CHDIR, \ OPT_OVERWRITE_PIDFILE, \ OPT_PIDFILE, \ - OPT_MONITOR + OPT_MONITOR, \ + OPT_USER_GROUP -#define DAEMON_LONG_OPTIONS \ - {"detach", no_argument, NULL, OPT_DETACH}, \ - {"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \ - {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ +#define DAEMON_LONG_OPTIONS \ + {"detach", no_argument, NULL, OPT_DETACH}, \ + {"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \ + {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ {"overwrite-pidfile", no_argument, NULL, OPT_OVERWRITE_PIDFILE}, \ - {"monitor", no_argument, NULL, OPT_MONITOR} + {"monitor", no_argument, NULL, OPT_MONITOR}, \ + {"user", required_argument, NULL, OPT_USER_GROUP} #define DAEMON_OPTION_HANDLERS \ case OPT_DETACH: \ @@ -70,6 +72,10 @@ \ case OPT_MONITOR: \ daemon_set_monitor(); \ + break; \ + \ + case OPT_USER_GROUP: \ + daemon_set_new_user(optarg); \ break; void set_detach(void); @@ -84,7 +90,8 @@ pid_t read_pidfile(const char *name); OPT_PIDFILE, \ OPT_PIPE_HANDLE, \ OPT_SERVICE, \ - OPT_SERVICE_MONITOR + OPT_SERVICE_MONITOR \ + OPT_USER_GROUP \ #define DAEMON_LONG_OPTIONS \ {"detach", no_argument, NULL, OPT_DETACH}, \ @@ -92,7 +99,8 @@ pid_t read_pidfile(const char *name); {"pidfile", optional_argument, NULL, OPT_PIDFILE}, \ {"pipe-handle", required_argument, NULL, OPT_PIPE_HANDLE}, \ {"service", no_argument, NULL, OPT_SERVICE}, \ - {"service-monitor", no_argument, NULL, OPT_SERVICE_MONITOR} + {"service-monitor", no_argument, NULL, OPT_SERVICE_MONITOR} \ + {"user", required_argument, NULL, OPT_USER_GROUP} #define DAEMON_OPTION_HANDLERS \ case OPT_DETACH: \ @@ -113,7 +121,10 @@ pid_t read_pidfile(const char *name); break; \ \ case OPT_SERVICE_MONITOR: \ - break; + break; \ + \ + case OPT_USER_GROUP: \ + daemon_set_new_user(optarg); \ void control_handler(DWORD request); void set_pipe_handle(const char *pipe_handle); @@ -122,8 +133,10 @@ void set_pipe_handle(const char *pipe_handle); bool get_detach(void); void daemon_save_fd(int fd); void daemonize(void); -void daemonize_start(void); +void daemonize_start(bool access_datapath); void daemonize_complete(void); +void daemon_set_new_user(const char * user_spec); +void daemon_become_new_user(bool access_datapath); void daemon_usage(void); void service_start(int *argcp, char **argvp[]); void service_stop(void); diff --git a/lib/daemon.man b/lib/daemon.man index 4ab9823..fedc8a0 100644 --- a/lib/daemon.man +++ b/lib/daemon.man @@ -50,3 +50,18 @@ core dumps into the current working directory and the root directory is not a good directory to use. .IP This option has no effect when \fB\-\-detach\fR is not specified. +. +.TP +\fB\-\-user\fR +Causes \fB\*(PN\fR to run as a non root user specified in "user:group", thus +dropping all root privileges. Short forms "user" and ":group" are also +allowed, with current user or group are assumed respectively. Only daemons +started by the root user accepts this argument. +.IP +On Linux, daemons will be granted CAP_IPC_LOCK and CAP_NET_BIND_SERVICES +before dropping root privileges. Daemons interact with datapath, +such as ovs-vswitchd, will be granted two additional capabilities, namely +CAP_NET_ADMIN and CAP_NET_RAW. +.IP +On Windows, this option is not currently supported. For security reasons, +Specifying this option will cause the daemon process not to start. diff --git a/ovn/controller-vtep/ovn-controller-vtep.c b/ovn/controller-vtep/ovn-controller-vtep.c index b54b29d..da6eeee 100644 --- a/ovn/controller-vtep/ovn-controller-vtep.c +++ b/ovn/controller-vtep/ovn-controller-vtep.c @@ -63,7 +63,7 @@ main(int argc, char *argv[]) parse_options(argc, argv); fatal_ignore_sigpipe(); - daemonize_start(); + daemonize_start(false); retval = unixctl_server_create(NULL, &unixctl); if (retval) { diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 8c858bb..f1bc524 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -386,7 +386,7 @@ main(int argc, char *argv[]) parse_options(argc, argv); fatal_ignore_sigpipe(); - daemonize_start(); + daemonize_start(false); retval = unixctl_server_create(NULL, &unixctl); if (retval) { diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 0f57e58..e698907 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -1167,7 +1167,7 @@ main(int argc, char *argv[]) vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); parse_options(argc, argv); - daemonize_start(); + daemonize_start(false); retval = unixctl_server_create(NULL, &unixctl); if (retval) { diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index 575cf91..b59388f 100644 --- a/ovsdb/ovsdb-client.c +++ b/ovsdb/ovsdb-client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,7 @@ main(int argc, char *argv[]) parse_options(argc, argv); fatal_ignore_sigpipe(); + daemon_become_new_user(false); if (optind >= argc) { ovs_fatal(0, "missing command name; use --help for help"); } @@ -791,7 +792,7 @@ do_monitor(struct jsonrpc *rpc, const char *database, size_t n_mts, allocated_mts; daemon_save_fd(STDOUT_FILENO); - daemonize_start(); + daemonize_start(false); if (get_detach()) { int error; diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 4088d85..0c34820 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -221,6 +221,7 @@ main(int argc, char *argv[]) process_init(); parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command); + daemon_become_new_user(false); /* Create and initialize 'config_tmpfile' as a temporary file to hold * ovsdb-server's most basic configuration, and then save our initial @@ -248,7 +249,7 @@ main(int argc, char *argv[]) save_config__(config_tmpfile, &remotes, &db_filenames); - daemonize_start(); + daemonize_start(false); /* Load the saved config. */ load_config(config_tmpfile, &remotes, &db_filenames); diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c index f66dc65..feac0b0 100644 --- a/tests/test-jsonrpc.c +++ b/tests/test-jsonrpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/tests/test-netflow.c b/tests/test-netflow.c index 631d7a2..2abc57f 100644 --- a/tests/test-netflow.c +++ b/tests/test-netflow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -195,7 +195,7 @@ test_netflow_main(int argc, char *argv[]) } daemon_save_fd(STDOUT_FILENO); - daemonize_start(); + daemonize_start(false); error = unixctl_server_create(NULL, &server); if (error) { diff --git a/tests/test-sflow.c b/tests/test-sflow.c index 6f90ebf..08591bf 100644 --- a/tests/test-sflow.c +++ b/tests/test-sflow.c @@ -683,7 +683,7 @@ test_sflow_main(int argc, char *argv[]) } daemon_save_fd(STDOUT_FILENO); - daemonize_start(); + daemonize_start(false); error = unixctl_server_create(NULL, &server); if (error) { diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 75e84e2..0c315c1 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -130,6 +130,8 @@ main(int argc, char *argv[]) fatal_ignore_sigpipe(); ctx.argc = argc - optind; ctx.argv = argv + optind; + + daemon_become_new_user(false); ovs_cmdl_run_command(&ctx, get_all_commands()); return 0; } @@ -1611,7 +1613,7 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) int error; daemon_save_fd(STDERR_FILENO); - daemonize_start(); + daemonize_start(false); error = unixctl_server_create(unixctl_path, &server); if (error) { ovs_fatal(error, "failed to create unixctl server"); diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c index 3d59adb..60cc32f 100644 --- a/utilities/ovs-testcontroller.c +++ b/utilities/ovs-testcontroller.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -108,6 +108,8 @@ main(int argc, char *argv[]) parse_options(argc, argv); fatal_ignore_sigpipe(); + daemon_become_new_user(false); + if (argc - optind < 1) { ovs_fatal(0, "at least one vconn argument required; " "use --help for usage"); @@ -145,7 +147,7 @@ main(int argc, char *argv[]) ovs_fatal(0, "no active or passive switch connections"); } - daemonize_start(); + daemonize_start(false); retval = unixctl_server_create(unixctl_path, &unixctl); if (retval) { diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c index 4fe479e..0ccf632 100644 --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@ -69,6 +69,7 @@ main(int argc, char *argv[]) char *remote; bool exiting; int retval; + bool access_datapath; set_program_name(argv[0]); retval = dpdk_init(argc,argv); @@ -85,7 +86,12 @@ main(int argc, char *argv[]) fatal_ignore_sigpipe(); ovsrec_init(); - daemonize_start(); +#ifdef __linux__ + access_datapath = true; +#else + access_datapath = false; +#endif + daemonize_start(access_datapath); if (want_mlockall) { #ifdef HAVE_MLOCKALL -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev