#############################################################################*/
#include <grp.h>
+#include <linux/capability.h>
#include <pwd.h>
#include <stddef.h>
+#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
#include "daemon.h"
#include "logging.h"
+static int cap_acquire_setpcap(void) {
+ cap_flag_value_t value;
+ int r;
+
+ // Fetch current capabilities
+ cap_t caps = cap_get_proc();
+
+ // Check if CAP_SETPCAP is already enabled
+ r = cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &value);
+ if (r) {
+ ERROR("The kernel does not seem to know CAP_SETPCAP: %m\n");
+ goto ERROR;
+ }
+
+ // It CAP_SETPCAP isn't set, we will try to set it
+ if (value != CAP_SET) {
+ const cap_value_t cap = CAP_SETPCAP;
+
+ r = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
+ if (r) {
+ ERROR("Could not set CAP_SETPCAP: %m\n");
+ goto ERROR;
+ }
+
+ // Store capabilities
+ r = cap_set_proc(caps);
+ if (r) {
+ ERROR("Could not acquire effective CAP_SETPCAP capability: %m\n");
+ goto ERROR;
+ }
+ }
+
+ERROR:
+ if (caps)
+ cap_free(caps);
+
+ return r;
+}
+
+static cap_flag_value_t keep_cap(const cap_value_t cap, const cap_value_t* keep_caps) {
+ for (const cap_value_t* c = keep_caps; *c; c++) {
+ if (cap == *c)
+ return CAP_SET;
+ }
+
+ return CAP_CLEAR;
+}
+
+static int drop_capabilities(void) {
+ int r;
+
+ const cap_value_t keep_caps[] = {
+ CAP_NET_ADMIN,
+ CAP_NET_BIND_SERVICE,
+ CAP_NET_BROADCAST,
+ CAP_NET_RAW,
+ 0,
+ };
+
+ // Acquire CAP_SETPCAP
+ r = cap_acquire_setpcap();
+ if (r)
+ return r;
+
+ // Fetch the current set of capabilities
+ cap_t caps = cap_get_proc();
+
+ // Drop all capabilities that we do not need
+ for (cap_value_t cap = 1; cap <= CAP_LAST_CAP; cap++) {
+ // Skip any capabilities we would like to skip
+ cap_flag_value_t flag = keep_cap(cap, keep_caps);
+
+ // Drop the capability from the bounding set
+ if (flag == CAP_CLEAR) {
+ r = prctl(PR_CAPBSET_DROP, cap);
+ if (r) {
+ ERROR("Could not drop capability from the bounding set: %m\n");
+ goto ERROR;
+ }
+ }
+
+ r = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
+ if (r) {
+ ERROR("Could not set capability %d: %m\n", (int)cap);
+ goto ERROR;
+ }
+
+ r = cap_set_flag(caps, CAP_PERMITTED, 1, &cap, flag);
+ if (r) {
+ ERROR("Could not set capability %d: %m\n", (int)cap);
+ goto ERROR;
+ }
+
+ r = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
+ if (r) {
+ ERROR("Could not set capability %d: %m\n", (int)cap);
+ goto ERROR;
+ }
+ }
+
+ // Restore capabilities
+ r = cap_set_proc(caps);
+ if (r) {
+ ERROR("Could not restore capabilities: %m\n");
+ goto ERROR;
+ }
+
+ERROR:
+ if (caps)
+ cap_free(caps);
+
+ return r;
+}
+
static int drop_privileges(const char* user) {
struct passwd* passwd = NULL;
int r;
return 1;
}
+ // Drop capabilities
+ r = drop_capabilities();
+ if (r)
+ return r;
+
return 0;
}