From f2f11e477a489ac25a4c4be064eddc26fc9d677c Mon Sep 17 00:00:00 2001
From: lns <matzeton@googlemail.com>
Date: Wed, 11 Apr 2018 14:28:18 +0200
Subject: POTD skeleton.

Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
---
 src/capabilities.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 344 insertions(+)
 create mode 100644 src/capabilities.c

(limited to 'src/capabilities.c')

diff --git a/src/capabilities.c b/src/capabilities.c
new file mode 100644
index 0000000..57658cc
--- /dev/null
+++ b/src/capabilities.c
@@ -0,0 +1,344 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <errno.h>
+#include <linux/capability.h>
+#include <sys/prctl.h>
+
+#include "capabilities.h"
+#include "utils.h"
+#include "log.h"
+
+typedef struct {
+    const char *name;
+    int nr;
+} CapsEntry;
+
+static CapsEntry capslist[] = {
+#ifdef CAP_CHOWN
+    {"chown", CAP_CHOWN },
+#endif
+#ifdef CAP_DAC_OVERRIDE
+    {"dac_override", CAP_DAC_OVERRIDE },
+#endif
+#ifdef CAP_DAC_READ_SEARCH
+    {"dac_read_search", CAP_DAC_READ_SEARCH },
+#endif
+#ifdef CAP_FOWNER
+    {"fowner", CAP_FOWNER },
+#endif
+#ifdef CAP_FSETID
+    {"fsetid", CAP_FSETID },
+#endif
+#ifdef CAP_KILL
+    {"kill", CAP_KILL },
+#endif
+#ifdef CAP_SETGID
+    {"setgid", CAP_SETGID },
+#endif
+#ifdef CAP_SETUID
+    {"setuid", CAP_SETUID },
+#endif
+#ifdef CAP_SETPCAP
+    {"setpcap", CAP_SETPCAP },
+#endif
+#ifdef CAP_LINUX_IMMUTABLE
+    {"linux_immutable", CAP_LINUX_IMMUTABLE },
+#endif
+#ifdef CAP_NET_BIND_SERVICE
+    {"net_bind_service", CAP_NET_BIND_SERVICE },
+#endif
+#ifdef CAP_NET_BROADCAST
+    {"net_broadcast", CAP_NET_BROADCAST },
+#endif
+#ifdef CAP_NET_ADMIN
+    {"net_admin", CAP_NET_ADMIN },
+#endif
+#ifdef CAP_NET_RAW
+    {"net_raw", CAP_NET_RAW },
+#endif
+#ifdef CAP_IPC_LOCK
+    {"ipc_lock", CAP_IPC_LOCK },
+#endif
+#ifdef CAP_IPC_OWNER
+    {"ipc_owner", CAP_IPC_OWNER },
+#endif
+#ifdef CAP_SYS_MODULE
+    {"sys_module", CAP_SYS_MODULE },
+#endif
+#ifdef CAP_SYS_RAWIO
+    {"sys_rawio", CAP_SYS_RAWIO },
+#endif
+#ifdef CAP_SYS_CHROOT
+    {"sys_chroot", CAP_SYS_CHROOT },
+#endif
+#ifdef CAP_SYS_PTRACE
+    {"sys_ptrace", CAP_SYS_PTRACE },
+#endif
+#ifdef CAP_SYS_PACCT
+    {"sys_pacct", CAP_SYS_PACCT },
+#endif
+#ifdef CAP_SYS_ADMIN
+    {"sys_admin", CAP_SYS_ADMIN },
+#endif
+#ifdef CAP_SYS_BOOT
+    {"sys_boot", CAP_SYS_BOOT },
+#endif
+#ifdef CAP_SYS_NICE
+    {"sys_nice", CAP_SYS_NICE },
+#endif
+#ifdef CAP_SYS_RESOURCE
+    {"sys_resource", CAP_SYS_RESOURCE },
+#endif
+#ifdef CAP_SYS_TIME
+    {"sys_time", CAP_SYS_TIME },
+#endif
+#ifdef CAP_SYS_TTY_CONFIG
+    {"sys_tty_config", CAP_SYS_TTY_CONFIG },
+#endif
+#ifdef CAP_MKNOD
+    {"mknod", CAP_MKNOD },
+#endif
+#ifdef CAP_LEASE
+    {"lease", CAP_LEASE },
+#endif
+#ifdef CAP_AUDIT_WRITE
+    {"audit_write", CAP_AUDIT_WRITE },
+#endif
+#ifdef CAP_AUDIT_CONTROL
+    {"audit_control", CAP_AUDIT_CONTROL },
+#endif
+#ifdef CAP_SETFCAP
+    {"setfcap", CAP_SETFCAP },
+#endif
+#ifdef CAP_MAC_OVERRIDE
+    {"mac_override", CAP_MAC_OVERRIDE },
+#endif
+#ifdef CAP_MAC_ADMIN
+    {"mac_admin", CAP_MAC_ADMIN },
+#endif
+#ifdef CAP_SYSLOG
+    {"syslog", CAP_SYSLOG },
+#endif
+#ifdef CAP_WAKE_ALARM
+    {"wake_alarm", CAP_WAKE_ALARM },
+#endif
+#ifdef CAP_BLOCK_SUSPEND
+    {"block_suspend", CAP_BLOCK_SUSPEND },
+#else
+    {"block_suspend", 36 },
+#endif
+#ifdef CAP_AUDIT_READ
+    {"audit_read", CAP_AUDIT_READ },
+#else
+    {"audit_read", 37 },
+#endif
+}; // end of capslist
+
+
+static int caps_find_name(const char *name)
+{
+    int i;
+    int elems = SIZEOF(capslist);
+
+    for (i = 0; i < elems; i++) {
+        if (strcmp(name, capslist[i].name) == 0)
+            return capslist[i].nr;
+    }
+
+    W2("Capability \"%s\" not found or not available on your system", name);
+    return -1;
+}
+
+void caps_check_list(const char *clist, void (*callback)(int))
+{
+    char *str = NULL;
+    char *ptr = NULL;
+    char *start = NULL;
+    int nr;
+
+    assert(clist && *clist != '\0');
+    str = strdup(clist);
+    assert(str);
+
+    ptr = str;
+    start = str;
+    while (*ptr != '\0') {
+        if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') {
+        } else if (*ptr == ',') {
+            *ptr = '\0';
+            nr = caps_find_name(start);
+            if (nr == -1)
+                goto errexit;
+            else if (callback != NULL)
+                callback(nr);
+
+            start = ptr + 1;
+        }
+        ptr++;
+    }
+    if (*start != '\0') {
+        nr = caps_find_name(start);
+        if (nr == -1)
+            goto errexit;
+        else if (callback != NULL)
+            callback(nr);
+    }
+
+    free(str);
+    return;
+
+errexit:
+	E2("Error: capability \"%s\" not found", start);
+	exit(EXIT_FAILURE);
+}
+
+void caps_print(void)
+{
+    int i;
+    int elems = SIZEOF(capslist);
+    int cnt = 0;
+    unsigned long cap;
+    int code;
+
+    for (cap=0; cap <= 63; cap++) {
+        code = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0);
+        if (code == 0)
+            cnt++;
+    }
+    D("Your kernel supports %d capabilities.", cnt);
+
+    for (i = 0; i < elems; i++) {
+        D("%d\t- %s", capslist[i].nr, capslist[i].name);
+    }
+}
+
+void caps_drop_dac_override(int noprofile)
+{
+    if (getuid() == 0 && !noprofile) {
+        if (prctl(PR_CAPBSET_DROP, CAP_DAC_OVERRIDE, 0, 0, 0)) {
+        } else {
+            D("%s", "Drop CAP_DAC_OVERRIDE");
+        }
+
+        if (prctl(PR_CAPBSET_DROP, CAP_DAC_READ_SEARCH, 0, 0, 0)) {
+        } else {
+            D("%s", "Drop CAP_DAC_READ_SEARCH");
+        }
+    }
+}
+
+int caps_default_filter(void)
+{
+    size_t i;
+    int code;
+    const char *const capstrs[] = {
+        "sys_module", "sys_rawio", "sys_boot",
+        "sys_nice", "sys_tty_config",
+        "mknod", "sys_admin", "sys_resource",
+        "sys_time"
+    };
+
+    for (i = 0; i < SIZEOF(capstrs); ++i ) {
+        code = caps_find_name(capstrs[i]);
+        if (code < 0)
+            goto errexit;
+        if (prctl(PR_CAPBSET_DROP, code, 0, 0, 0) < 0)
+            goto errexit;
+    }
+
+    return 0;
+errexit:
+    E("%s", "Can not drop capabilities");
+    exit(EXIT_FAILURE);
+}
+
+int caps_jail_filter(void)
+{
+    size_t i;
+    int code;
+    const char *const capstrs[] = {
+#ifdef CAP_SYSLOG
+        "syslog",
+#endif
+        "audit_control", "audit_read", "audit_write",
+        "sys_ptrace", "sys_pacct", "sys_chroot", "sys_nice",
+        "sys_tty_config"
+    };
+
+    for (i = 0; i < SIZEOF(capstrs); ++i) {
+        code = caps_find_name(capstrs[i]);
+        if (code < 0)
+            goto errexit;
+        if (prctl(PR_CAPBSET_DROP, code, 0, 0, 0) < 0)
+            goto errexit;
+    }
+
+    return 0;
+errexit:
+    E("%s", "Can not drop capabilities");
+    exit(EXIT_FAILURE);
+}
+
+void caps_drop_all(void)
+{
+    unsigned long cap;
+    int code;
+
+    D("%s", "Dropping all capabilities");
+    for (cap = 0; cap <= 63; cap++) {
+        code = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0);
+        if (code == -1 && errno != EINVAL) {
+            FATAL("%s", "PR_CAPBSET_DROP");
+        }
+    }
+}
+
+
+void caps_set(uint64_t caps)
+{
+    unsigned long i;
+    uint64_t mask = 1LLU;
+    int code;
+
+    D("Set caps filter %llx\n", (unsigned long long) caps);
+    for (i = 0; i < 64; i++, mask <<= 1) {
+        if ((mask & caps) == 0) {
+            code = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+            if (code == -1 && errno != EINVAL)
+                FATAL("%s", "PR_CAPBSET_DROP");
+        }
+    }
+}
+
+static uint64_t filter;
+
+static void caps_set_bit(int nr)
+{
+	uint64_t mask = 1LLU << nr;
+	filter |= mask;
+}
+
+static void caps_reset_bit(int nr)
+{
+	uint64_t mask = 1LLU << nr;
+	filter &= ~mask;
+}
+
+void caps_drop_list(const char *clist)
+{
+	filter = 0;
+	filter--;
+	caps_check_list(clist, caps_reset_bit);
+	caps_set(filter);
+}
+
+void caps_keep_list(const char *clist)
+{
+	filter = 0;
+	caps_check_list(clist, caps_set_bit);
+	caps_set(filter);
+}
-- 
cgit v1.2.3