aboutsummaryrefslogtreecommitdiff
path: root/progs/capsh.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/capsh.c')
-rw-r--r--progs/capsh.c385
1 files changed, 254 insertions, 131 deletions
diff --git a/progs/capsh.c b/progs/capsh.c
index 50c2c99..f753291 100644
--- a/progs/capsh.c
+++ b/progs/capsh.c
@@ -40,6 +40,35 @@
#define MAX_GROUPS 100 /* max number of supplementary groups for user */
+/* parse a non-negative integer with some error handling */
+static unsigned long nonneg_uint(const char *text, const char *prefix, int *ok)
+{
+ char *remains;
+ unsigned long value;
+ ssize_t len = strlen(text);
+
+ if (len == 0 || *text == '-') {
+ goto fail;
+ }
+ value = strtoul(text, &remains, 0);
+ if (*remains) {
+ goto fail;
+ }
+ if (ok != NULL) {
+ *ok = 1;
+ }
+ return value;
+
+fail:
+ if (ok == NULL) {
+ fprintf(stderr, "%s: want non-negative integer, got \"%s\"\n",
+ prefix, text);
+ exit(1);
+ }
+ *ok = 0;
+ return 0;
+}
+
static char *binary(unsigned long value)
{
static char string[8*sizeof(unsigned long) + 1];
@@ -89,6 +118,10 @@ static void display_current(void)
char *text;
all = cap_get_proc();
+ if (all == NULL) {
+ perror("failed to get process capabilities");
+ exit(1);
+ }
text = cap_to_text(all, NULL);
printf("Current: %s\n", text);
cap_free(text);
@@ -101,7 +134,16 @@ static void display_current_iab(void)
char *text;
iab = cap_iab_get_proc();
+ if (iab == NULL) {
+ perror("failed to get IAB for process");
+ exit(1);
+ }
text = cap_iab_to_text(iab);
+ if (text == NULL) {
+ perror("failed to obtain text for IAB");
+ cap_free(iab);
+ exit(1);
+ }
printf("Current IAB: %s\n", text);
cap_free(text);
cap_free(iab);
@@ -178,29 +220,42 @@ static void arg_print(void)
static const cap_value_t raise_setpcap[1] = { CAP_SETPCAP };
static const cap_value_t raise_chroot[1] = { CAP_SYS_CHROOT };
-static void push_pcap(cap_t *orig_p, cap_t *raised_for_setpcap_p)
+static cap_t will_need_setpcap(int strict)
{
- /*
- * We need to do this here because --inh=XXX may have reset
- * orig and it isn't until we are within the --drop code that
- * we know what the prevailing (orig) pI value is.
- */
- *orig_p = cap_get_proc();
- if (NULL == *orig_p) {
+ cap_flag_value_t enabled;
+ cap_t raised = NULL;
+
+ if (strict) {
+ return NULL;
+ }
+
+ raised = cap_get_proc();
+ if (raised == NULL) {
perror("Capabilities not available");
exit(1);
}
-
- *raised_for_setpcap_p = cap_dup(*orig_p);
- if (NULL == *raised_for_setpcap_p) {
- fprintf(stderr, "modification requires CAP_SETPCAP\n");
+ if (cap_get_flag(raised, CAP_SETPCAP, CAP_EFFECTIVE, &enabled) != 0) {
+ perror("Unable to check CAP_EFFECTIVE CAP_SETPCAP value");
exit(1);
}
- if (cap_set_flag(*raised_for_setpcap_p, CAP_EFFECTIVE, 1,
- raise_setpcap, CAP_SET) != 0) {
- perror("unable to select CAP_SETPCAP");
+ if (enabled != CAP_SET) {
+ cap_set_flag(raised, CAP_EFFECTIVE, 1, raise_setpcap, CAP_SET);
+ } else {
+ /* no need to raise - since already raised */
+ cap_free(raised);
+ raised = NULL;
+ }
+ return raised;
+}
+
+static void push_pcap(int strict, cap_t *orig_p, cap_t *raised_for_setpcap_p)
+{
+ *orig_p = cap_get_proc();
+ if (NULL == *orig_p) {
+ perror("Capabilities not available");
exit(1);
}
+ *raised_for_setpcap_p = will_need_setpcap(strict);
}
static void pop_pcap(cap_t orig, cap_t raised_for_setpcap)
@@ -209,23 +264,24 @@ static void pop_pcap(cap_t orig, cap_t raised_for_setpcap)
cap_free(orig);
}
-static void arg_drop(const char *arg_names)
+static void arg_drop(int strict, const char *arg_names)
{
char *ptr;
cap_t orig, raised_for_setpcap;
char *names;
- push_pcap(&orig, &raised_for_setpcap);
+ push_pcap(strict, &orig, &raised_for_setpcap);
if (strcmp("all", arg_names) == 0) {
unsigned j = 0;
while (CAP_IS_SUPPORTED(j)) {
int status;
- if (cap_set_proc(raised_for_setpcap) != 0) {
+ if (raised_for_setpcap != NULL &&
+ cap_set_proc(raised_for_setpcap) != 0) {
perror("unable to raise CAP_SETPCAP for BSET changes");
exit(1);
}
status = cap_drop_bound(j);
- if (cap_set_proc(orig) != 0) {
+ if (raised_for_setpcap != NULL && cap_set_proc(orig) != 0) {
perror("unable to lower CAP_SETPCAP post BSET change");
exit(1);
}
@@ -258,12 +314,13 @@ static void arg_drop(const char *arg_names)
fprintf(stderr, "capability [%s] is unknown to libcap\n", ptr);
exit(1);
}
- if (cap_set_proc(raised_for_setpcap) != 0) {
+ if (raised_for_setpcap != NULL &&
+ cap_set_proc(raised_for_setpcap) != 0) {
perror("unable to raise CAP_SETPCAP for BSET changes");
exit(1);
}
status = cap_drop_bound(cap);
- if (cap_set_proc(orig) != 0) {
+ if (raised_for_setpcap != NULL && cap_set_proc(orig) != 0) {
perror("unable to lower CAP_SETPCAP post BSET change");
exit(1);
}
@@ -279,23 +336,15 @@ static void arg_drop(const char *arg_names)
static void arg_change_amb(const char *arg_names, cap_flag_value_t set)
{
char *ptr;
- cap_t orig, raised_for_setpcap;
+ cap_t orig;
char *names;
- push_pcap(&orig, &raised_for_setpcap);
+ orig = cap_get_proc();
if (strcmp("all", arg_names) == 0) {
unsigned j = 0;
while (CAP_IS_SUPPORTED(j)) {
int status;
- if (cap_set_proc(raised_for_setpcap) != 0) {
- perror("unable to raise CAP_SETPCAP for AMBIENT changes");
- exit(1);
- }
status = cap_set_ambient(j, set);
- if (cap_set_proc(orig) != 0) {
- perror("unable to lower CAP_SETPCAP post AMBIENT change");
- exit(1);
- }
if (status != 0) {
char *name_ptr;
@@ -307,7 +356,7 @@ static void arg_change_amb(const char *arg_names, cap_flag_value_t set)
}
j++;
}
- pop_pcap(orig, raised_for_setpcap);
+ cap_free(orig);
return;
}
@@ -325,22 +374,14 @@ static void arg_change_amb(const char *arg_names, cap_flag_value_t set)
fprintf(stderr, "capability [%s] is unknown to libcap\n", ptr);
exit(1);
}
- if (cap_set_proc(raised_for_setpcap) != 0) {
- perror("unable to raise CAP_SETPCAP for AMBIENT changes");
- exit(1);
- }
status = cap_set_ambient(cap, set);
- if (cap_set_proc(orig) != 0) {
- perror("unable to lower CAP_SETPCAP post AMBIENT change");
- exit(1);
- }
if (status != 0) {
fprintf(stderr, "failed to %s ambient [%s=%u]\n",
set == CAP_CLEAR ? "clear":"raise", ptr, cap);
exit(1);
}
}
- pop_pcap(orig, raised_for_setpcap);
+ cap_free(orig);
free(names);
}
@@ -427,24 +468,70 @@ static void describe(cap_value_t cap) {
}
}
-int main(int argc, char *argv[], char *envp[])
+__attribute__ ((noreturn))
+static void do_launch(char *args[], char *envp[])
{
+ cap_launch_t lau;
pid_t child;
- unsigned i;
- const char *shell = SHELL;
+ int ret, result;
- child = 0;
-
- char *temp_name = cap_to_name(cap_max_bits() - 1);
- if (temp_name[0] != 'c') {
- printf("WARNING: libcap needs an update (cap=%d should have a name).\n",
- cap_max_bits() - 1);
+ lau = cap_new_launcher(args[0], (void *) args, (void *) envp);
+ if (lau == NULL) {
+ perror("failed to create launcher");
+ exit(1);
+ }
+ child = cap_launch(lau, NULL);
+ if (child <= 0) {
+ perror("child failed to start");
+ exit(1);
}
- cap_free(temp_name);
+ cap_free(lau);
+ ret = waitpid(child, &result, 0);
+ if (ret != child) {
+ fprintf(stderr, "failed to wait for PID=%d, result=%x: ",
+ child, result);
+ perror("");
+ exit(1);
+ }
+ if (WIFEXITED(result)) {
+ exit(WEXITSTATUS(result));
+ }
+ if (WIFSIGNALED(result)) {
+ fprintf(stderr, "child PID=%d terminated by signo=%d\n",
+ child, WTERMSIG(result));
+ exit(1);
+ }
+ fprintf(stderr, "child PID=%d generated result=%0x\n", child, result);
+ exit(1);
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+ pid_t child = 0;
+ unsigned i;
+ int strict = 0, quiet_start = 0, dont_set_env = 0;
+ const char *shell = SHELL;
for (i=1; i<argc; ++i) {
+ if (!strcmp("--quiet", argv[i])) {
+ quiet_start = 1;
+ continue;
+ }
+ if (i == 1) {
+ char *temp_name = cap_to_name(cap_max_bits() - 1);
+ if (temp_name == NULL) {
+ perror("obtaining highest capability name");
+ exit(1);
+ }
+ if (temp_name[0] != 'c') {
+ printf("WARNING: libcap needs an update"
+ " (cap=%d should have a name).\n",
+ cap_max_bits() - 1);
+ }
+ cap_free(temp_name);
+ }
if (!strncmp("--drop=", argv[i], 7)) {
- arg_drop(argv[i]+7);
+ arg_drop(strict, argv[i]+7);
} else if (!strncmp("--dropped=", argv[i], 10)) {
cap_value_t cap;
if (cap_from_name(argv[i]+10, &cap) < 0) {
@@ -459,7 +546,7 @@ int main(int argc, char *argv[], char *envp[])
}
} else if (!strcmp("--has-ambient", argv[i])) {
if (!CAP_AMBIENT_SUPPORTED()) {
- fprintf(stderr, "ambient set not supported\n");
+ perror("ambient set not supported");
exit(1);
}
} else if (!strncmp("--addamb=", argv[i], 9)) {
@@ -468,32 +555,21 @@ int main(int argc, char *argv[], char *envp[])
arg_change_amb(argv[i]+9, CAP_CLEAR);
} else if (!strncmp("--noamb", argv[i], 7)) {
if (cap_reset_ambient() != 0) {
- fprintf(stderr, "failed to reset ambient set\n");
+ perror("failed to reset ambient set");
exit(1);
}
+ } else if (!strcmp("--noenv", argv[i])) {
+ dont_set_env = 1;
} else if (!strncmp("--inh=", argv[i], 6)) {
cap_t all, raised_for_setpcap;
char *text;
char *ptr;
- all = cap_get_proc();
- if (all == NULL) {
- perror("Capabilities not available");
- exit(1);
- }
+ push_pcap(strict, &all, &raised_for_setpcap);
if (cap_clear_flag(all, CAP_INHERITABLE) != 0) {
perror("libcap:cap_clear_flag() internal error");
exit(1);
}
-
- raised_for_setpcap = cap_dup(all);
- if ((raised_for_setpcap != NULL)
- && (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
- raise_setpcap, CAP_SET) != 0)) {
- cap_free(raised_for_setpcap);
- raised_for_setpcap = NULL;
- }
-
text = cap_to_text(all, NULL);
cap_free(all);
if (text == NULL) {
@@ -510,13 +586,13 @@ int main(int argc, char *argv[], char *envp[])
} else {
strcpy(ptr, text);
}
+ cap_free(text);
all = cap_from_text(ptr);
if (all == NULL) {
perror("Fatal error internalizing capabilities");
exit(1);
}
- cap_free(text);
free(ptr);
if (raised_for_setpcap != NULL) {
@@ -534,45 +610,29 @@ int main(int argc, char *argv[], char *envp[])
perror("Unable to set inheritable capabilities");
exit(1);
}
- /*
- * Since status is based on orig, we don't want to restore
- * the previous value of 'all' again here!
- */
-
cap_free(all);
+ } else if (!strcmp("--strict", argv[i])) {
+ strict = !strict;
} else if (!strncmp("--caps=", argv[i], 7)) {
cap_t all, raised_for_setpcap;
- raised_for_setpcap = cap_get_proc();
- if (raised_for_setpcap == NULL) {
- perror("Capabilities not available");
- exit(1);
- }
-
- if ((raised_for_setpcap != NULL)
- && (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
- raise_setpcap, CAP_SET) != 0)) {
- cap_free(raised_for_setpcap);
- raised_for_setpcap = NULL;
- }
-
+ raised_for_setpcap = will_need_setpcap(strict);
all = cap_from_text(argv[i]+7);
if (all == NULL) {
fprintf(stderr, "unable to interpret [%s]\n", argv[i]);
exit(1);
}
-
if (raised_for_setpcap != NULL) {
/*
- * This is only for the case that pP does not contain
- * the requested change to pI.. Failing here is not
- * indicative of the cap_set_proc(all) failing (always).
+ * This is actually only for the case that pP does not
+ * contain the requested change to pI.. Failing here
+ * is not always indicative of the cap_set_proc(all)
+ * failing.
*/
(void) cap_set_proc(raised_for_setpcap);
cap_free(raised_for_setpcap);
raised_for_setpcap = NULL;
}
-
if (cap_set_proc(all) != 0) {
fprintf(stderr, "Unable to set capabilities [%s]\n", argv[i]);
exit(1);
@@ -581,7 +641,6 @@ int main(int argc, char *argv[], char *envp[])
* Since status is based on orig, we don't want to restore
* the previous value of 'all' again here!
*/
-
cap_free(all);
} else if (!strcmp("--modes", argv[i])) {
cap_mode_t c;
@@ -594,30 +653,38 @@ int main(int argc, char *argv[], char *envp[])
printf(" %s", m);
}
printf("\n");
- } else if (!strncmp("--mode=", argv[i], 7)) {
- const char *target = argv[i]+7;
- cap_mode_t c;
- int found = 0;
- for (c = 1; ; c++) {
- const char *m = cap_mode_name(c);
- if (!strcmp("UNKNOWN", m)) {
- found = 0;
- break;
+ } else if (!strncmp("--mode", argv[i], 6)) {
+ if (argv[i][6] == '=') {
+ const char *target = argv[i]+7;
+ cap_mode_t c;
+ int found = 0;
+ for (c = 1; ; c++) {
+ const char *m = cap_mode_name(c);
+ if (!strcmp("UNKNOWN", m)) {
+ found = 0;
+ break;
+ }
+ if (!strcmp(m, target)) {
+ found = 1;
+ break;
+ }
}
- if (!strcmp(m, target)) {
- found = 1;
- break;
+ if (!found) {
+ printf("unsupported mode: %s\n", target);
+ exit(1);
}
- }
- if (!found) {
- printf("unsupported mode: %s\n", target);
- exit(1);
- }
- int ret = cap_set_mode(c);
- if (ret != 0) {
- printf("failed to set mode [%s]: %s\n",
- target, strerror(errno));
- exit(1);
+ int ret = cap_set_mode(c);
+ if (ret != 0) {
+ printf("failed to set mode [%s]: %s\n",
+ target, strerror(errno));
+ exit(1);
+ }
+ } else if (argv[i][6]) {
+ printf("unrecognized command [%s]\n", argv[i]);
+ goto usage;
+ } else {
+ cap_mode_t m = cap_get_mode();
+ printf("Mode: %s\n", cap_mode_name(m));
}
} else if (!strncmp("--inmode=", argv[i], 9)) {
const char *target = argv[i]+9;
@@ -631,7 +698,7 @@ int main(int argc, char *argv[], char *envp[])
unsigned value;
int set;
- value = strtoul(argv[i]+7, NULL, 0);
+ value = nonneg_uint(argv[i]+7, "invalid --keep value", NULL);
set = prctl(PR_SET_KEEPCAPS, value);
if (set < 0) {
fprintf(stderr, "prctl(PR_SET_KEEPCAPS, %u) failed: %s\n",
@@ -688,7 +755,7 @@ int main(int argc, char *argv[], char *envp[])
} else if (!strncmp("--secbits=", argv[i], 10)) {
unsigned value;
int status;
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --secbits value", NULL);
status = cap_set_secbits(value);
if (status < 0) {
fprintf(stderr, "failed to set securebits to 0%o/0x%x\n",
@@ -701,8 +768,9 @@ int main(int argc, char *argv[], char *envp[])
fprintf(stderr, "already forked\n");
exit(1);
}
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --forkfor value", NULL);
if (value == 0) {
+ fprintf(stderr, "require non-zero --forkfor value\n");
goto usage;
}
child = fork();
@@ -717,7 +785,8 @@ int main(int argc, char *argv[], char *envp[])
pid_t result;
unsigned value;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --killit signo value",
+ NULL);
if (!child) {
fprintf(stderr, "no forked process to kill\n");
exit(1);
@@ -743,7 +812,7 @@ int main(int argc, char *argv[], char *envp[])
unsigned value;
int status;
- value = strtoul(argv[i]+6, NULL, 0);
+ value = nonneg_uint(argv[i]+6, "invalid --uid value", NULL);
status = setuid(value);
if (status < 0) {
fprintf(stderr, "Failed to set uid=%u: %s\n",
@@ -754,7 +823,7 @@ int main(int argc, char *argv[], char *envp[])
unsigned value;
int status;
- value = strtoul(argv[i]+10, NULL, 0);
+ value = nonneg_uint(argv[i]+10, "invalid --cap-uid value", NULL);
status = cap_setuid(value);
if (status < 0) {
fprintf(stderr, "Failed to cap_setuid(%u): %s\n",
@@ -765,7 +834,7 @@ int main(int argc, char *argv[], char *envp[])
unsigned value;
int status;
- value = strtoul(argv[i]+6, NULL, 0);
+ value = nonneg_uint(argv[i]+6, "invalid --gid value", NULL);
status = setgid(value);
if (status < 0) {
fprintf(stderr, "Failed to set gid=%u: %s\n",
@@ -845,6 +914,20 @@ int main(int argc, char *argv[], char *envp[])
pwd->pw_uid, user, strerror(errno));
exit(1);
}
+ if (!dont_set_env) {
+ /*
+ * not setting this confuses bash at start up, but use
+ * --noenv to preserve the HOME etc values instead.
+ */
+ if (setenv("HOME", pwd->pw_dir, 1) != 0) {
+ perror("unable to set HOME");
+ exit(1);
+ }
+ if (setenv("USER", user, 1) != 0) {
+ perror("unable to set USER");
+ exit(1);
+ }
+ }
} else if (!strncmp("--decode=", argv[i], 9)) {
unsigned long long value;
unsigned cap;
@@ -885,13 +968,22 @@ int main(int argc, char *argv[], char *envp[])
}
} else if (!strcmp("--print", argv[i])) {
arg_print();
- } else if ((!strcmp("--", argv[i])) || (!strcmp("==", argv[i]))) {
+ } else if ((!strcmp("--", argv[i])) || (!strcmp("==", argv[i]))
+ || (!strcmp("-+", argv[i])) || (!strcmp("=+", argv[i]))) {
+ int launch = argv[i][1] == '+';
if (argv[i][0] == '=') {
+ if (quiet_start) {
+ argv[i--] = strdup("--quiet");
+ }
argv[i] = find_self(argv[0]);
} else {
argv[i] = strdup(shell);
}
argv[argc] = NULL;
+ /* Two ways to chain load - use cap_launch() or execve() */
+ if (launch) {
+ do_launch(argv+i, envp);
+ }
execve(argv[i], argv+i, envp);
fprintf(stderr, "execve '%s' failed!\n", argv[i]);
free(argv[i]);
@@ -909,6 +1001,10 @@ int main(int argc, char *argv[], char *envp[])
exit(1);
}
orig = cap_get_proc();
+ if (orig == NULL) {
+ perror("failed to get process capabilities");
+ exit(1);
+ }
if (cap_get_flag(orig, cap, CAP_PERMITTED, &enabled) || !enabled) {
fprintf(stderr, "cap[%s] not permitted\n", argv[i]+8);
exit(1);
@@ -925,6 +1021,10 @@ int main(int argc, char *argv[], char *envp[])
exit(1);
}
orig = cap_get_proc();
+ if (orig == NULL) {
+ perror("failed to get process capabilities");
+ exit(1);
+ }
if (cap_get_flag(orig, cap, CAP_INHERITABLE, &enabled)
|| !enabled) {
fprintf(stderr, "cap[%s] not inheritable\n", argv[i]+8);
@@ -942,10 +1042,21 @@ int main(int argc, char *argv[], char *envp[])
fprintf(stderr, "cap[%s] not in ambient vector\n", argv[i]+8);
exit(1);
}
+ } else if (!strncmp("--has-b=", argv[i], 8)) {
+ cap_value_t cap;
+ if (cap_from_name(argv[i]+8, &cap) < 0) {
+ fprintf(stderr, "cap[%s] not recognized by library\n",
+ argv[i] + 8);
+ exit(1);
+ }
+ if (!cap_get_bound(cap)) {
+ fprintf(stderr, "cap[%s] not in bounding vector\n", argv[i]+8);
+ exit(1);
+ }
} else if (!strncmp("--is-uid=", argv[i], 9)) {
unsigned value;
uid_t uid;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --is-uid value", NULL);
uid = getuid();
if (uid != value) {
fprintf(stderr, "uid: got=%d, want=%d\n", uid, value);
@@ -954,7 +1065,7 @@ int main(int argc, char *argv[], char *envp[])
} else if (!strncmp("--is-gid=", argv[i], 9)) {
unsigned value;
gid_t gid;
- value = strtoul(argv[i]+9, NULL, 0);
+ value = nonneg_uint(argv[i]+9, "invalid --is-gid value", NULL);
gid = getgid();
if (gid != value) {
fprintf(stderr, "gid: got=%d, want=%d\n", gid, value);
@@ -967,7 +1078,7 @@ int main(int argc, char *argv[], char *envp[])
exit(1);
}
if (cap_iab_set_proc(iab)) {
- perror("unable to set IAP vectors");
+ perror("unable to set IAB tuple");
exit(1);
}
cap_free(iab);
@@ -983,7 +1094,7 @@ int main(int argc, char *argv[], char *envp[])
}
} else if (!strcmp("--license", argv[i])) {
printf(
- "%s see LICENSE file for details.\n"
+ "%s see License file for details.\n"
"Copyright (c) 2008-11,16,19-21 Andrew G. Morgan"
" <morgan@kernel.org>\n", argv[0]);
exit(0);
@@ -997,7 +1108,7 @@ int main(int argc, char *argv[], char *envp[])
fprintf(stderr, "negative capability (%d) invalid\n", cap);
exit(1);
}
- if (cap < CAPSH_DOC_LIMIT) {
+ if (cap < capsh_doc_limit) {
describe(cap);
continue;
}
@@ -1010,10 +1121,14 @@ int main(int argc, char *argv[], char *envp[])
} else if (!strncmp("--suggest=", argv[i], 10)) {
cap_value_t cap;
int hits = 0;
- for (cap=0; cap < CAPSH_DOC_LIMIT; cap++) {
+ for (cap=0; cap < capsh_doc_limit; cap++) {
const char **lines = explanations[cap];
int j;
char *name = cap_to_name(cap);
+ if (name == NULL) {
+ perror("invalid named cap");
+ exit(1);
+ }
char *match = strcasestr(name, argv[i]+10);
cap_free(name);
if (match != NULL) {
@@ -1046,11 +1161,13 @@ int main(int argc, char *argv[], char *envp[])
" --current show current caps and IAB vectors\n"
" --decode=xxx decode a hex string to a list of caps\n"
" --delamb=xxx remove xxx,... capabilities from ambient\n"
+ " --drop=xxx drop xxx,... caps from bounding set\n"
" --explain=xxx explain what capability xxx permits\n"
" --forkfor=<n> fork and make child sleep for <n> sec\n"
" --gid=<n> set gid to <n> (hint: id <username>)\n"
" --groups=g,... set the supplemental groups\n"
" --has-a=xxx exit 1 if capability xxx not ambient\n"
+ " --has-b=xxx exit 1 if capability xxx not dropped\n"
" --has-ambient exit 1 unless ambient vector supported\n"
" --has-i=xxx exit 1 if capability xxx not inheritable\n"
" --has-p=xxx exit 1 if capability xxx not permitted\n"
@@ -1064,19 +1181,25 @@ int main(int argc, char *argv[], char *envp[])
" --keep=<n> set keep-capability bit to <n>\n"
" --killit=<n> send signal(n) to child\n"
" --license display license info\n"
- " --modes list libcap named capability modes\n"
- " --mode=<xxx> set capability mode to <xxx>\n"
+ " --mode display current libcap mode\n"
+ " --mode=<xxx> set libcap mode to <xxx>\n"
+ " --modes list libcap named modes\n"
" --no-new-privs set sticky process privilege limiter\n"
" --noamb reset (drop) all ambient capabilities\n"
+ " --noenv no fixup of env vars (for --user)\n"
" --print display capability relevant state\n"
+ " --quiet if first argument skip max cap check\n"
" --secbits=<n> write a new value for securebits\n"
" --shell=/xx/yy use /xx/yy instead of " SHELL " for --\n"
+ " --strict toggle --caps, --drop and --inh fixups\n"
" --suggest=text search cap descriptions for text\n"
" --supports=xxx exit 1 if capability xxx unsupported\n"
" --uid=<n> set uid to <n> (hint: id <username>)\n"
" --user=<name> set uid,gid and groups to that of user\n"
" == re-exec(capsh) with args as for --\n"
+ " =+ cap_launch capsh with args as for -+\n"
" -- remaining arguments are for " SHELL "\n"
+ " -+ cap_launch " SHELL " with remaining args\n"
" (without -- [%s] will simply exit(0))\n",
argv[0], argv[0]);
if (strcmp("--help", argv[1]) && strcmp("-h", argv[1])) {