]> mj.ucw.cz Git - libucw.git/commitdiff
Be able to preserve caps across daemon start
authorMichal 'vorner' Vaner <vorner@vorner.cz>
Sat, 5 Jul 2014 18:33:49 +0000 (20:33 +0200)
committerMichal 'vorner' Vaner <vorner@vorner.cz>
Sat, 5 Jul 2014 18:33:49 +0000 (20:33 +0200)
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
ucw/daemon.c
ucw/daemon.h

index e45a339c752f28f69eb600208302ca17578ba851..160abd5cf3273067bfff1d7c804f10ebd49364d5 100644 (file)
@@ -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
index 9b136d8ac2c171434d6d2d893dc4d824b73068f7..eb4a4d79493c9c7fe5d22812ada202081dae9c6e 100644 (file)
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/file.h>
+#include <sys/prctl.h>
 
 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
index 25a34f8033f3b43690b036892da17a82a4415a30..ab9f5245371a1b00f1dd36b23f27e42697239e78 100644 (file)
@@ -11,6 +11,7 @@
 #define _UCW_DAEMON_H
 
 #include <sys/types.h>
+#include <sys/capability.h>
 
 #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;