summaryrefslogtreecommitdiff
path: root/sysdep/linux/syspriv.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/linux/syspriv.h')
-rw-r--r--sysdep/linux/syspriv.h62
1 files changed, 62 insertions, 0 deletions
diff --git a/sysdep/linux/syspriv.h b/sysdep/linux/syspriv.h
new file mode 100644
index 00000000..bfe19ac3
--- /dev/null
+++ b/sysdep/linux/syspriv.h
@@ -0,0 +1,62 @@
+
+#include <sys/prctl.h>
+#include <linux/capability.h>
+
+#ifndef _LINUX_CAPABILITY_VERSION_3
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#define _LINUX_CAPABILITY_U32S_3 2
+#endif
+
+/* capset() prototype is missing ... */
+int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+
+static inline int
+set_capabilities(u32 caps)
+{
+ struct __user_cap_header_struct cap_hdr;
+ struct __user_cap_data_struct cap_dat[_LINUX_CAPABILITY_U32S_3];
+ int err;
+
+ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ cap_hdr.pid = 0;
+
+ memset(cap_dat, 0, sizeof(cap_dat));
+ cap_dat[0].effective = cap_dat[0].permitted = caps;
+
+ err = capset(&cap_hdr, cap_dat);
+ if (!err)
+ return 0;
+
+ /* Kernel may support do not support our version of capability interface.
+ The last call returned supported version so we just retry it. */
+ if (errno == EINVAL)
+ {
+ err = capset(&cap_hdr, cap_dat);
+ if (!err)
+ return 0;
+ }
+
+ return -1;
+}
+
+static void
+drop_uid(uid_t uid)
+{
+ u32 caps =
+ CAP_TO_MASK(CAP_NET_BIND_SERVICE) |
+ CAP_TO_MASK(CAP_NET_BROADCAST) |
+ CAP_TO_MASK(CAP_NET_ADMIN) |
+ CAP_TO_MASK(CAP_NET_RAW);
+
+ if (seteuid(uid) < 0)
+ die("seteuid: %m");
+
+ if (set_capabilities(caps) < 0)
+ die("capset: %m");
+
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0)
+ die("prctl: %m");
+
+ if (setresuid(uid, uid, uid) < 0)
+ die("setresuid: %m");
+}