static int has_cap(sd_bus_creds *c, unsigned offset, int capability) { size_t sz; assert(c); assert(capability >= 0); assert(c->capability); if ((unsigned) capability > cap_last_cap()) return 0; sz = DIV_ROUND_UP(cap_last_cap(), 32U); return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability)); }
/* verify cap_last_cap() against /proc/sys/kernel/cap_last_cap */ static void test_last_cap_file(void) { _cleanup_free_ char *content = NULL; unsigned long val = 0; int r; r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content); assert_se(r >= 0); r = safe_atolu(content, &val); assert_se(r >= 0); assert_se(val != 0); assert_se(val == cap_last_cap()); }
/* verify cap_last_cap() against syscall probing */ static void test_last_cap_probe(void) { unsigned long p = (unsigned long)CAP_LAST_CAP; if (prctl(PR_CAPBSET_READ, p) < 0) { for (p--; p > 0; p --) if (prctl(PR_CAPBSET_READ, p) >= 0) break; } else { for (;; p++) if (prctl(PR_CAPBSET_READ, p+1) < 0) break; } assert_se(p != 0); assert_se(p == cap_last_cap()); }
static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) { size_t sz, max; unsigned i, j; assert(c); assert(p); max = DIV_ROUND_UP(cap_last_cap(), 32U); p += strspn(p, WHITESPACE); sz = strlen(p); if (sz % 8 != 0) return -EINVAL; sz /= 8; if (sz > max) return -EINVAL; if (!c->capability) { c->capability = new0(uint32_t, max * 4); if (!c->capability) return -ENOMEM; } for (i = 0; i < sz; i ++) { uint32_t v = 0; for (j = 0; j < 8; ++j) { int t; t = unhexchar(*p++); if (t < 0) return -EINVAL; v = (v << 4) | t; } c->capability[offset * max + (sz - i - 1)] = v; } return 0; }