bunpen: implement capability struct with parse method

This commit is contained in:
2024-08-30 17:02:44 +00:00
parent 25b3ccaa48
commit 475d1615fa

View File

@@ -0,0 +1,172 @@
// vim: set shiftwidth=2 :
use ascii;
use strings;
export type capability = enum {
AUDIT_CONTROL,
AUDIT_READ,
AUDIT_WRITE,
BLOCK_SUSPEND,
BPF,
CHECKPOINT_RESTORE,
CHOWN,
DAC_OVERRIDE,
DAC_READ_SEARCH,
FOWNER,
FSETID,
IPC_LOCK,
IPC_OWNER,
KILL,
LEASE,
LINUX_IMMUTABLE,
MAC_ADMIN,
MAC_OVERRIDE,
MKNOD,
NET_ADMIN,
NET_BIND_SERVICE,
NET_BROADCAST,
NET_RAW,
PERFMON,
SETFCAP,
SETGID,
SETPCAP,
SETUID,
SYS_ADMIN,
SYS_BOOT,
SYS_CHROOT,
SYS_MODULE,
SYS_NICE,
SYS_PACCT,
SYS_PTRACE,
SYS_RAWIO,
SYS_RESOURCE,
SYS_TIME,
SYS_TTY_CONFIG,
SYSLOG,
WAKE_ALARM,
};
fn capability_fromstr(v: str) (capability | error) = {
// strip leading CAP_ and allow either form.
if (len(v) > 4 && ascii::strcasecmp(strings::sub(v, 0, 4), "CAP_") == 0)
v = strings::sub(v, 4);
if (ascii::strcasecmp(v, "AUDIT_CONTROL") == 0)
return capability::AUDIT_CONTROL;
if (ascii::strcasecmp(v, "AUDIT_READ") == 0)
return capability::AUDIT_READ;
if (ascii::strcasecmp(v, "AUDIT_WRITE") == 0)
return capability::AUDIT_WRITE;
if (ascii::strcasecmp(v, "BLOCK_SUSPEND") == 0)
return capability::BLOCK_SUSPEND;
if (ascii::strcasecmp(v, "BPF") == 0)
return capability::BPF;
if (ascii::strcasecmp(v, "CHECKPOINT_RESTORE") == 0)
return capability::CHECKPOINT_RESTORE;
if (ascii::strcasecmp(v, "CHOWN") == 0)
return capability::CHOWN;
if (ascii::strcasecmp(v, "DAC_OVERRIDE") == 0)
return capability::DAC_OVERRIDE;
if (ascii::strcasecmp(v, "DAC_READ_SEARCH") == 0)
return capability::DAC_READ_SEARCH;
if (ascii::strcasecmp(v, "FOWNER") == 0)
return capability::FOWNER;
if (ascii::strcasecmp(v, "FSETID") == 0)
return capability::FSETID;
if (ascii::strcasecmp(v, "IPC_LOCK") == 0)
return capability::IPC_LOCK;
if (ascii::strcasecmp(v, "IPC_OWNER") == 0)
return capability::IPC_OWNER;
if (ascii::strcasecmp(v, "KILL") == 0)
return capability::KILL;
if (ascii::strcasecmp(v, "LEASE") == 0)
return capability::LEASE;
if (ascii::strcasecmp(v, "LINUX_IMMUTABLE") == 0)
return capability::LINUX_IMMUTABLE;
if (ascii::strcasecmp(v, "MAC_ADMIN") == 0)
return capability::MAC_ADMIN;
if (ascii::strcasecmp(v, "MAC_OVERRIDE") == 0)
return capability::MAC_OVERRIDE;
if (ascii::strcasecmp(v, "MKNOD") == 0)
return capability::MKNOD;
if (ascii::strcasecmp(v, "NET_ADMIN") == 0)
return capability::NET_ADMIN;
if (ascii::strcasecmp(v, "NET_BIND_SERVICE") == 0)
return capability::NET_BIND_SERVICE;
if (ascii::strcasecmp(v, "NET_BROADCAST") == 0)
return capability::NET_BROADCAST;
if (ascii::strcasecmp(v, "NET_RAW") == 0)
return capability::NET_RAW;
if (ascii::strcasecmp(v, "PERFMON") == 0)
return capability::PERFMON;
if (ascii::strcasecmp(v, "SETFCAP") == 0)
return capability::SETFCAP;
if (ascii::strcasecmp(v, "SETGID") == 0)
return capability::SETGID;
if (ascii::strcasecmp(v, "SETPCAP") == 0)
return capability::SETPCAP;
if (ascii::strcasecmp(v, "SETUID") == 0)
return capability::SETUID;
if (ascii::strcasecmp(v, "SYS_ADMIN") == 0)
return capability::SYS_ADMIN;
if (ascii::strcasecmp(v, "SYS_BOOT") == 0)
return capability::SYS_BOOT;
if (ascii::strcasecmp(v, "SYS_CHROOT") == 0)
return capability::SYS_CHROOT;
if (ascii::strcasecmp(v, "SYS_MODULE") == 0)
return capability::SYS_MODULE;
if (ascii::strcasecmp(v, "SYS_NICE") == 0)
return capability::SYS_NICE;
if (ascii::strcasecmp(v, "SYS_PACCT") == 0)
return capability::SYS_PACCT;
if (ascii::strcasecmp(v, "SYS_PTRACE") == 0)
return capability::SYS_PTRACE;
if (ascii::strcasecmp(v, "SYS_RAWIO") == 0)
return capability::SYS_RAWIO;
if (ascii::strcasecmp(v, "SYS_RESOURCE") == 0)
return capability::SYS_RESOURCE;
if (ascii::strcasecmp(v, "SYS_TIME") == 0)
return capability::SYS_TIME;
if (ascii::strcasecmp(v, "SYS_TTY_CONFIG") == 0)
return capability::SYS_TTY_CONFIG;
if (ascii::strcasecmp(v, "SYSLOG") == 0)
return capability::SYSLOG;
if (ascii::strcasecmp(v, "WAKE_ALARM") == 0)
return capability::WAKE_ALARM;
return error;
};
// return true if `s` parses to `expect`
fn _parse_eq(s: str, expect: (capability | error)) bool = {
let got = capability_fromstr(s);
return match (expect) {
case let c: capability => yield match (got) {
case let c2: capability => yield c2 == c;
case => yield false;
};
case error => yield match (got) {
case error => yield true; // both errors
case => yield false;
};
};
};
@test fn cap_from_str_good() void = {
assert(_parse_eq("SYS_ADMIN", capability::SYS_ADMIN));
assert(_parse_eq("CAP_SYS_ADMIN", capability::SYS_ADMIN));
assert(_parse_eq("sys_admin", capability::SYS_ADMIN));
assert(_parse_eq("cap_sys_admin", capability::SYS_ADMIN));
assert(_parse_eq("CAP_sys_admin", capability::SYS_ADMIN));
assert(_parse_eq("cap_SYS_ADMIN", capability::SYS_ADMIN));
};
@test fn cap_from_str_bad() void = {
assert(_parse_eq("CAP_SYS_ADMIN_AND_MORE", error));
assert(_parse_eq("SYS_ADMIN_CAP", error));
assert(_parse_eq("SYS", error));
assert(_parse_eq("", error));
};