From c65acebe95211c1abcd00e324408c2825cdb7d09 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 5 Jul 2014 20:33:49 +0200 Subject: [PATCH] Be able to preserve caps across daemon start Be able to preserve some linux capabilities across setuid in daemon_run, so we can switch to normal user but still be able to eg. bind low ports. Still needs detection if capabilities are available on the system. --- ucw/Makefile | 2 +- ucw/daemon.c | 19 +++++++++++++++++++ ucw/daemon.h | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ucw/Makefile b/ucw/Makefile index e45a339c..160abd5c 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -92,7 +92,7 @@ include $(s)/ucw/doc/Makefile LIBUCW_MOD_PATHS=$(addprefix $(o)/ucw/,$(LIBUCW_MODS)) -export LIBUCW_LIBS=-lm +export LIBUCW_LIBS=-lm -lcap ifdef CONFIG_UCW_THREADS LIBUCW_LIBS+=-lpthread endif diff --git a/ucw/daemon.c b/ucw/daemon.c index 9b136d8a..eb4a4d79 100644 --- a/ucw/daemon.c +++ b/ucw/daemon.c @@ -21,6 +21,7 @@ #include #include #include +#include void daemon_resolve_ugid(struct daemon_params *dp) @@ -81,12 +82,30 @@ daemon_resolve_ugid(struct daemon_params *dp) void daemon_switch_ugid(struct daemon_params *dp) { + // If we want to preserve some caps across UID switch, keep all first, to avoid having to set them twice. + if (dp->keep_caps && prctl(PR_SET_KEEPCAPS, 1L) < 0) + die("Can not keep caps: %m"); if (dp->want_setgid && setresgid(dp->run_as_gid, dp->run_as_gid, dp->run_as_gid) < 0) die("Cannot set GID to %d: %m", (int) dp->run_as_gid); if (dp->want_setgid > 1 && initgroups(dp->run_as_user, dp->run_as_gid) < 0) die("Cannot initialize groups: %m"); if (dp->want_setuid && setresuid(dp->run_as_uid, dp->run_as_uid, dp->run_as_uid) < 0) die("Cannot set UID to %d: %m", (int) dp->run_as_uid); + if (dp->keep_caps) + { + cap_t caps = cap_init(); + if (cap_clear(caps) < 0) + die("Couldn't clear capability set: %m"); + if (cap_set_flag(caps, CAP_EFFECTIVE, dp->keep_cap_count, dp->keep_caps, 1) < 0 || + cap_set_flag(caps, CAP_PERMITTED, dp->keep_cap_count, dp->keep_caps, 1) < 0 || + cap_set_flag(caps, CAP_INHERITABLE, dp->keep_cap_count, dp->keep_caps, 1) < 0) + die("Couldn't set capability flags: %m"); + if (cap_set_proc(caps) < 0) + die("Couldn't set capabilities: %m"); + if (prctl(PR_SET_KEEPCAPS, 0L) < 0) + die("Couldn't give up keeping caps: %m"); + cap_free(caps); + } } void diff --git a/ucw/daemon.h b/ucw/daemon.h index 25a34f80..ab9f5245 100644 --- a/ucw/daemon.h +++ b/ucw/daemon.h @@ -11,6 +11,7 @@ #define _UCW_DAEMON_H #include +#include #ifdef CONFIG_UCW_CLEAN_ABI #define daemon_control ucw_daemon_control @@ -27,6 +28,8 @@ struct daemon_params { const char *pid_file; // A path to PID file (optional) const char *run_as_user; // User name or "#uid" (optional) const char *run_as_group; // Group name or "#gid" (optional) + const cap_value_t *keep_caps; // Keep these capabilities across UID switch (optional) + int keep_cap_count; // Internal uid_t run_as_uid; -- 2.39.5