diff options
-rw-r--r-- | util-linux/setpriv.c | 151 |
1 files changed, 147 insertions, 4 deletions
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c index 8d3f25875..a509204a2 100644 --- a/util-linux/setpriv.c +++ b/util-linux/setpriv.c @@ -23,6 +23,26 @@ //config: help //config: Enables the "--dump" switch to print out the current privilege //config: state. This is helpful for diagnosing problems. +//config: +//config:config FEATURE_SETPRIV_CAPABILITIES +//config: bool "Support capabilities" +//config: default y +//config: depends on SETPRIV +//config: help +//config: Capabilities can be used to grant processes additional rights +//config: without the necessity to always execute as the root user. +//config: Enabling this option enables "--dump" to show information on +//config: capabilities. +//config: +//config:config FEATURE_SETPRIV_CAPABILITY_NAMES +//config: bool "Support capability names" +//config: default y +//config: depends on SETPRIV && FEATURE_SETPRIV_CAPABILITIES +//config: help +//config: Capabilities can be either referenced via a human-readble name, +//config: e.g. "net_admin", or using their index, e.g. "cap_12". Enabling +//config: this option allows using the human-readable names in addition to +//config: the index-based names. //applet:IF_SETPRIV(APPLET(setpriv, BB_DIR_BIN, BB_SUID_DROP)) @@ -55,6 +75,10 @@ // --selinux-label <label> set SELinux label // --apparmor-profile <pr> set AppArmor profile +#if ENABLE_FEATURE_SETPRIV_CAPABILITIES +#include <linux/capability.h> +#include <sys/capability.h> +#endif #include <sys/prctl.h> #include "libbb.h" @@ -74,13 +98,106 @@ enum { OPT_NNP = (1 << OPTBIT_NNP), }; +#if ENABLE_FEATURE_SETPRIV_CAPABILITIES +struct caps { + struct __user_cap_header_struct header; + cap_user_data_t data; + int u32s; +}; + +#if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES +static const char *const capabilities[] = { + "chown", + "dac_override", + "dac_read_search", + "fowner", + "fsetid", + "kill", + "setgid", + "setuid", + "setpcap", + "linux_immutable", + "net_bind_service", + "net_broadcast", + "net_admin", + "net_raw", + "ipc_lock", + "ipc_owner", + "sys_module", + "sys_rawio", + "sys_chroot", + "sys_ptrace", + "sys_pacct", + "sys_admin", + "sys_boot", + "sys_nice", + "sys_resource", + "sys_time", + "sys_tty_config", + "mknod", + "lease", + "audit_write", + "audit_control", + "setfcap", + "mac_override", + "mac_admin", + "syslog", + "wake_alarm", + "block_suspend", + "audit_read", +}; +#endif /* FEATURE_SETPRIV_CAPABILITY_NAMES */ + +#endif /* FEATURE_SETPRIV_CAPABILITIES */ + #if ENABLE_FEATURE_SETPRIV_DUMP +# if ENABLE_FEATURE_SETPRIV_CAPABILITIES +static void getcaps(struct caps *caps) +{ + int versions[] = { + _LINUX_CAPABILITY_U32S_3, + _LINUX_CAPABILITY_U32S_2, + _LINUX_CAPABILITY_U32S_1, + }; + int i; + + caps->header.pid = 0; + for (i = 0; i < ARRAY_SIZE(versions); i++) { + caps->header.version = versions[i]; + if (capget(&caps->header, NULL) == 0) + goto got_it; + } + bb_simple_perror_msg_and_die("capget"); + got_it: + + switch (caps->header.version) { + case _LINUX_CAPABILITY_VERSION_1: + caps->u32s = _LINUX_CAPABILITY_U32S_1; + break; + case _LINUX_CAPABILITY_VERSION_2: + caps->u32s = _LINUX_CAPABILITY_U32S_2; + break; + case _LINUX_CAPABILITY_VERSION_3: + caps->u32s = _LINUX_CAPABILITY_U32S_3; + break; + default: + bb_error_msg_and_die("unsupported capability version"); + } + + caps->data = xmalloc(sizeof(caps->data[0]) * caps->u32s); + if (capget(&caps->header, caps->data) < 0) + bb_simple_perror_msg_and_die("capget"); +} +# endif /* FEATURE_SETPRIV_CAPABILITIES */ + static int dump(void) { + IF_FEATURE_SETPRIV_CAPABILITIES(struct caps caps;) + const char *fmt; uid_t ruid, euid, suid; gid_t rgid, egid, sgid; gid_t *gids; - int ngids, nnp; + int i, ngids, nnp; getresuid(&ruid, &euid, &suid); /* never fails in Linux */ getresgid(&rgid, &egid, &sgid); /* never fails in Linux */ @@ -100,8 +217,7 @@ static int dump(void) if (ngids == 0) { printf("[none]"); } else { - const char *fmt = ",%u" + 1; - int i; + fmt = ",%u" + 1; for (i = 0; i < ngids; i++) { printf(fmt, (unsigned)gids[i]); fmt = ",%u"; @@ -109,8 +225,35 @@ static int dump(void) } printf("\nno_new_privs: %d\n", nnp); - if (ENABLE_FEATURE_CLEAN_UP) +# if ENABLE_FEATURE_SETPRIV_CAPABILITIES + getcaps(&caps); + printf("Inheritable capabilities: "); + fmt = ""; + for (i = 0; cap_valid(i); i++) { + unsigned idx = CAP_TO_INDEX(i); + if (idx >= caps.u32s) { + printf("\nindex: %u u32s: %u capability: %u\n", idx, caps.u32s, i); + bb_error_msg_and_die("unsupported capability"); + } + if (caps.data[idx].inheritable & CAP_TO_MASK(i)) { +# if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES + if (i < ARRAY_SIZE(capabilities)) + printf("%s%s", fmt, capabilities[i]); + else +# endif + printf("%scap_%u", fmt, i); + fmt = ","; + } + } + if (!fmt[0]) + printf("[none]"); + bb_putchar('\n'); +# endif + + if (ENABLE_FEATURE_CLEAN_UP) { + IF_FEATURE_SETPRIV_CAPABILITIES(free(caps.data);) free(gids); + } return EXIT_SUCCESS; } #endif /* FEATURE_SETPRIV_DUMP */ |