mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 09:58:01 +00:00
lib/daemon: support --user option for all OVS daemon
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 <azhou@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
parent
1bbebfb7af
commit
e91b927d89
1
NEWS
1
NEWS
@ -23,6 +23,7 @@ Post-v2.4.0
|
|||||||
- Dropped support for GRE64 tunnel.
|
- Dropped support for GRE64 tunnel.
|
||||||
- Mark --syslog-target argument as deprecated. It will be removed in
|
- Mark --syslog-target argument as deprecated. It will be removed in
|
||||||
the next OVS release.
|
the next OVS release.
|
||||||
|
- Added --user option to all daemons
|
||||||
|
|
||||||
|
|
||||||
v2.4.0 - 20 Aug 2015
|
v2.4.0 - 20 Aug 2015
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include "daemon-private.h"
|
#include "daemon-private.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -26,6 +28,9 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#if HAVE_LIBCAPNG
|
||||||
|
#include <cap-ng.h>
|
||||||
|
#endif
|
||||||
#include "command-line.h"
|
#include "command-line.h"
|
||||||
#include "fatal-signal.h"
|
#include "fatal-signal.h"
|
||||||
#include "dirs.h"
|
#include "dirs.h"
|
||||||
@ -39,6 +44,18 @@
|
|||||||
|
|
||||||
VLOG_DEFINE_THIS_MODULE(daemon_unix);
|
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? */
|
/* --detach: Should we run in the background? */
|
||||||
bool detach; /* Was --detach specified? */
|
bool detach; /* Was --detach specified? */
|
||||||
static bool detached; /* Have we already detached? */
|
static bool detached; /* Have we already detached? */
|
||||||
@ -64,6 +81,15 @@ static int daemonize_fd = -1;
|
|||||||
* it dies due to an error signal? */
|
* it dies due to an error signal? */
|
||||||
static bool monitor;
|
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 void check_already_running(void);
|
||||||
static int lock_pidfile(FILE *, int command);
|
static int lock_pidfile(FILE *, int command);
|
||||||
static pid_t fork_and_clean_up(void);
|
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
|
* daemon_complete()) or that it failed to start up (by exiting with a nonzero
|
||||||
* exit code). */
|
* exit code). */
|
||||||
void
|
void
|
||||||
daemonize_start(void)
|
daemonize_start(bool access_datapath)
|
||||||
{
|
{
|
||||||
assert_single_threaded();
|
assert_single_threaded();
|
||||||
daemonize_fd = -1;
|
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) {
|
if (detach) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
@ -684,3 +720,326 @@ should_service_stop(void)
|
|||||||
{
|
{
|
||||||
return false;
|
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) {
|
||||||
|
const capng_type_t cap_sets = CAPNG_EFFECTIVE|CAPNG_PERMITTED;
|
||||||
|
|
||||||
|
capng_clear(CAPNG_SELECT_BOTH);
|
||||||
|
|
||||||
|
ret = capng_update(CAPNG_ADD, cap_sets, CAP_IPC_LOCK)
|
||||||
|
|| capng_update(CAPNG_ADD, cap_sets, CAP_NET_BIND_SERVICE);
|
||||||
|
|
||||||
|
if (access_datapath && !ret) {
|
||||||
|
ret = capng_update(CAPNG_ADD, cap_sets, CAP_NET_ADMIN)
|
||||||
|
|| capng_update(CAPNG_ADD, cap_sets, CAP_NET_RAW);
|
||||||
|
}
|
||||||
|
} 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 {
|
||||||
|
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 wrapps 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;
|
||||||
|
}
|
||||||
|
@ -447,7 +447,8 @@ make_pidfile(void)
|
|||||||
/* Don't close the pidfile till the process exits. */
|
/* Don't close the pidfile till the process exits. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void daemonize_start(void)
|
void
|
||||||
|
daemonize_start(bool access_datapath OVS_UNUSED)
|
||||||
{
|
{
|
||||||
if (pidfile) {
|
if (pidfile) {
|
||||||
make_pidfile();
|
make_pidfile();
|
||||||
@ -474,6 +475,11 @@ daemonize_complete(void)
|
|||||||
service_complete();
|
service_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
daemon_become_new_user(bool access_datapath OVS_UNUSED)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns the file name that would be used for a pidfile if 'name' were
|
/* 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. */
|
* provided to set_pidfile(). The caller must free the returned string. */
|
||||||
char *
|
char *
|
||||||
@ -485,3 +491,9 @@ make_pidfile_name(const char *name)
|
|||||||
return xasprintf("%s/%s.pid", ovs_rundir(), program_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.");
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@ get_detach(void)
|
|||||||
void
|
void
|
||||||
daemonize(void)
|
daemonize(void)
|
||||||
{
|
{
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
daemonize_complete();
|
daemonize_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
lib/daemon.h
33
lib/daemon.h
@ -42,14 +42,16 @@
|
|||||||
OPT_NO_CHDIR, \
|
OPT_NO_CHDIR, \
|
||||||
OPT_OVERWRITE_PIDFILE, \
|
OPT_OVERWRITE_PIDFILE, \
|
||||||
OPT_PIDFILE, \
|
OPT_PIDFILE, \
|
||||||
OPT_MONITOR
|
OPT_MONITOR, \
|
||||||
|
OPT_USER_GROUP
|
||||||
|
|
||||||
#define DAEMON_LONG_OPTIONS \
|
#define DAEMON_LONG_OPTIONS \
|
||||||
{"detach", no_argument, NULL, OPT_DETACH}, \
|
{"detach", no_argument, NULL, OPT_DETACH}, \
|
||||||
{"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \
|
{"no-chdir", no_argument, NULL, OPT_NO_CHDIR}, \
|
||||||
{"pidfile", optional_argument, NULL, OPT_PIDFILE}, \
|
{"pidfile", optional_argument, NULL, OPT_PIDFILE}, \
|
||||||
{"overwrite-pidfile", no_argument, NULL, OPT_OVERWRITE_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 \
|
#define DAEMON_OPTION_HANDLERS \
|
||||||
case OPT_DETACH: \
|
case OPT_DETACH: \
|
||||||
@ -70,6 +72,10 @@
|
|||||||
\
|
\
|
||||||
case OPT_MONITOR: \
|
case OPT_MONITOR: \
|
||||||
daemon_set_monitor(); \
|
daemon_set_monitor(); \
|
||||||
|
break; \
|
||||||
|
\
|
||||||
|
case OPT_USER_GROUP: \
|
||||||
|
daemon_set_new_user(optarg); \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
void set_detach(void);
|
void set_detach(void);
|
||||||
@ -84,7 +90,8 @@ pid_t read_pidfile(const char *name);
|
|||||||
OPT_PIDFILE, \
|
OPT_PIDFILE, \
|
||||||
OPT_PIPE_HANDLE, \
|
OPT_PIPE_HANDLE, \
|
||||||
OPT_SERVICE, \
|
OPT_SERVICE, \
|
||||||
OPT_SERVICE_MONITOR
|
OPT_SERVICE_MONITOR \
|
||||||
|
OPT_USER_GROUP \
|
||||||
|
|
||||||
#define DAEMON_LONG_OPTIONS \
|
#define DAEMON_LONG_OPTIONS \
|
||||||
{"detach", no_argument, NULL, OPT_DETACH}, \
|
{"detach", no_argument, NULL, OPT_DETACH}, \
|
||||||
@ -92,7 +99,8 @@ pid_t read_pidfile(const char *name);
|
|||||||
{"pidfile", optional_argument, NULL, OPT_PIDFILE}, \
|
{"pidfile", optional_argument, NULL, OPT_PIDFILE}, \
|
||||||
{"pipe-handle", required_argument, NULL, OPT_PIPE_HANDLE}, \
|
{"pipe-handle", required_argument, NULL, OPT_PIPE_HANDLE}, \
|
||||||
{"service", no_argument, NULL, OPT_SERVICE}, \
|
{"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 \
|
#define DAEMON_OPTION_HANDLERS \
|
||||||
case OPT_DETACH: \
|
case OPT_DETACH: \
|
||||||
@ -113,7 +121,10 @@ pid_t read_pidfile(const char *name);
|
|||||||
break; \
|
break; \
|
||||||
\
|
\
|
||||||
case OPT_SERVICE_MONITOR: \
|
case OPT_SERVICE_MONITOR: \
|
||||||
break;
|
break; \
|
||||||
|
\
|
||||||
|
case OPT_USER_GROUP: \
|
||||||
|
daemon_set_new_user(optarg); \
|
||||||
|
|
||||||
void control_handler(DWORD request);
|
void control_handler(DWORD request);
|
||||||
void set_pipe_handle(const char *pipe_handle);
|
void set_pipe_handle(const char *pipe_handle);
|
||||||
@ -122,8 +133,10 @@ void set_pipe_handle(const char *pipe_handle);
|
|||||||
bool get_detach(void);
|
bool get_detach(void);
|
||||||
void daemon_save_fd(int fd);
|
void daemon_save_fd(int fd);
|
||||||
void daemonize(void);
|
void daemonize(void);
|
||||||
void daemonize_start(void);
|
void daemonize_start(bool access_datapath);
|
||||||
void daemonize_complete(void);
|
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 daemon_usage(void);
|
||||||
void service_start(int *argcp, char **argvp[]);
|
void service_start(int *argcp, char **argvp[]);
|
||||||
void service_stop(void);
|
void service_stop(void);
|
||||||
|
@ -50,3 +50,18 @@ core dumps into the current working directory and the root directory
|
|||||||
is not a good directory to use.
|
is not a good directory to use.
|
||||||
.IP
|
.IP
|
||||||
This option has no effect when \fB\-\-detach\fR is not specified.
|
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.
|
||||||
|
@ -64,7 +64,7 @@ main(int argc, char *argv[])
|
|||||||
parse_options(argc, argv);
|
parse_options(argc, argv);
|
||||||
fatal_ignore_sigpipe();
|
fatal_ignore_sigpipe();
|
||||||
|
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
retval = unixctl_server_create(NULL, &unixctl);
|
retval = unixctl_server_create(NULL, &unixctl);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -386,7 +386,7 @@ main(int argc, char *argv[])
|
|||||||
parse_options(argc, argv);
|
parse_options(argc, argv);
|
||||||
fatal_ignore_sigpipe();
|
fatal_ignore_sigpipe();
|
||||||
|
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
retval = unixctl_server_create(NULL, &unixctl);
|
retval = unixctl_server_create(NULL, &unixctl);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -1167,7 +1167,7 @@ main(int argc, char *argv[])
|
|||||||
vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
|
vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
|
||||||
parse_options(argc, argv);
|
parse_options(argc, argv);
|
||||||
|
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
retval = unixctl_server_create(NULL, &unixctl);
|
retval = unixctl_server_create(NULL, &unixctl);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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);
|
parse_options(argc, argv);
|
||||||
fatal_ignore_sigpipe();
|
fatal_ignore_sigpipe();
|
||||||
|
|
||||||
|
daemon_become_new_user(false);
|
||||||
if (optind >= argc) {
|
if (optind >= argc) {
|
||||||
ovs_fatal(0, "missing command name; use --help for help");
|
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;
|
size_t n_mts, allocated_mts;
|
||||||
|
|
||||||
daemon_save_fd(STDOUT_FILENO);
|
daemon_save_fd(STDOUT_FILENO);
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
if (get_detach()) {
|
if (get_detach()) {
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -221,6 +221,7 @@ main(int argc, char *argv[])
|
|||||||
process_init();
|
process_init();
|
||||||
|
|
||||||
parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
|
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
|
/* Create and initialize 'config_tmpfile' as a temporary file to hold
|
||||||
* ovsdb-server's most basic configuration, and then save our initial
|
* 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);
|
save_config__(config_tmpfile, &remotes, &db_filenames);
|
||||||
|
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
/* Load the saved config. */
|
/* Load the saved config. */
|
||||||
load_config(config_tmpfile, &remotes, &db_filenames);
|
load_config(config_tmpfile, &remotes, &db_filenames);
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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);
|
daemon_save_fd(STDOUT_FILENO);
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
error = unixctl_server_create(NULL, &server);
|
error = unixctl_server_create(NULL, &server);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -683,7 +683,7 @@ test_sflow_main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
daemon_save_fd(STDOUT_FILENO);
|
daemon_save_fd(STDOUT_FILENO);
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
error = unixctl_server_create(NULL, &server);
|
error = unixctl_server_create(NULL, &server);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -130,6 +130,8 @@ main(int argc, char *argv[])
|
|||||||
fatal_ignore_sigpipe();
|
fatal_ignore_sigpipe();
|
||||||
ctx.argc = argc - optind;
|
ctx.argc = argc - optind;
|
||||||
ctx.argv = argv + optind;
|
ctx.argv = argv + optind;
|
||||||
|
|
||||||
|
daemon_become_new_user(false);
|
||||||
ovs_cmdl_run_command(&ctx, get_all_commands());
|
ovs_cmdl_run_command(&ctx, get_all_commands());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1611,7 +1613,7 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
daemon_save_fd(STDERR_FILENO);
|
daemon_save_fd(STDERR_FILENO);
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
error = unixctl_server_create(unixctl_path, &server);
|
error = unixctl_server_create(unixctl_path, &server);
|
||||||
if (error) {
|
if (error) {
|
||||||
ovs_fatal(error, "failed to create unixctl server");
|
ovs_fatal(error, "failed to create unixctl server");
|
||||||
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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);
|
parse_options(argc, argv);
|
||||||
fatal_ignore_sigpipe();
|
fatal_ignore_sigpipe();
|
||||||
|
|
||||||
|
daemon_become_new_user(false);
|
||||||
|
|
||||||
if (argc - optind < 1) {
|
if (argc - optind < 1) {
|
||||||
ovs_fatal(0, "at least one vconn argument required; "
|
ovs_fatal(0, "at least one vconn argument required; "
|
||||||
"use --help for usage");
|
"use --help for usage");
|
||||||
@ -145,7 +147,7 @@ main(int argc, char *argv[])
|
|||||||
ovs_fatal(0, "no active or passive switch connections");
|
ovs_fatal(0, "no active or passive switch connections");
|
||||||
}
|
}
|
||||||
|
|
||||||
daemonize_start();
|
daemonize_start(false);
|
||||||
|
|
||||||
retval = unixctl_server_create(unixctl_path, &unixctl);
|
retval = unixctl_server_create(unixctl_path, &unixctl);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
@ -85,7 +85,7 @@ main(int argc, char *argv[])
|
|||||||
fatal_ignore_sigpipe();
|
fatal_ignore_sigpipe();
|
||||||
ovsrec_init();
|
ovsrec_init();
|
||||||
|
|
||||||
daemonize_start();
|
daemonize_start(true);
|
||||||
|
|
||||||
if (want_mlockall) {
|
if (want_mlockall) {
|
||||||
#ifdef HAVE_MLOCKALL
|
#ifdef HAVE_MLOCKALL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user