Add testing features to capsh.

Capabilities in their various guises can be complicated. Add
some simple test flags to capsh so we can script more test
cases.

Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
diff --git a/doc/cap_get_proc.3 b/doc/cap_get_proc.3
index 712b3ff..80f7e21 100644
--- a/doc/cap_get_proc.3
+++ b/doc/cap_get_proc.3
@@ -117,6 +117,10 @@
 .I effective
 capability set must have a raised
 .BR CAP_SETPCAP .
+Further, to raise a specific ambient capability the
+.IR inheritable " and " permitted
+sets of the current process must contain the specified capability, and
+raised ambient bits will only be retained as long as this remains true.
 .PP
 .BR cap_reset_ambient ()
 resets all of the ambient capabilities for the current process to
diff --git a/doc/capsh.1 b/doc/capsh.1
index c3dc8fe..1e28b59 100644
--- a/doc/capsh.1
+++ b/doc/capsh.1
@@ -107,6 +107,10 @@
 process. Following this command the prevailing effective capabilities
 will be lowered.
 .TP
+.BI --is-uid= <id>
+Exit with status 1 unless the current
+.IR uid " equals " <id> .
+.TP
 .BI --gid= <id>
 Force all
 .B gid
@@ -116,6 +120,10 @@
 .BR setgid (2)
 system call.
 .TP
+.BI --is-gid= <id>
+Exit with status 1 unless the current
+.IR gid " equals " <id> .
+.TP
 .BI --groups= <gid-list>
 Set the supplementary groups to the numerical list provided. The
 groups are set with the
@@ -211,10 +219,24 @@
 kernel 2.6.27.  However, when run on kernel 2.6.38 it will silently
 succeed.
 .TP
+.BI --has-p= xxx
+Exit with status 1 unless the
+.I permitted
+vector has capability
+.B xxx
+raised.
+.TP
 .B --has-ambient
 Performs a check to see if the running kernel supports ambient
 capabilities. If not, the capsh command exits with status 1.
 .TP
+.BI --has-a= xxx
+Exit with status 1 unless the
+.I ambient
+vector has capability
+.B xxx
+raised.
+.TP
 .BI --addamb= xxx
 Adds the specificed ambient capability to the running process.
 .TP
diff --git a/progs/capsh.c b/progs/capsh.c
index ac3d108..2875096 100644
--- a/progs/capsh.c
+++ b/progs/capsh.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-11,16,19 Andrew G. Morgan <morgan@kernel.org>
+ * Copyright (c) 2008-11,16,19,2020 Andrew G. Morgan <morgan@kernel.org>
  *
  * This is a simple 'bash' wrapper program that can be used to
  * raise and lower both the bset and pI capabilities before invoking
@@ -761,6 +761,51 @@
 	    execve(argv[i], argv+i, envp);
 	    fprintf(stderr, "execve /bin/bash failed!\n");
 	    exit(1);
+	} else if (!strncmp("--has-p=", argv[i], 8)) {
+	    cap_value_t cap;
+	    cap_flag_value_t enabled;
+	    cap_t orig;
+
+	    if (cap_from_name(argv[i]+8, &cap) < 0) {
+		fprintf(stderr, "cap[%s] not recognized by libarary\n",
+			argv[i] + 8);
+		exit(1);
+	    }
+	    orig = cap_get_proc();
+	    if (cap_get_flag(orig, cap, CAP_PERMITTED, &enabled) || !enabled) {
+		fprintf(stderr, "cap[%s] not enabled\n", argv[i]+8);
+		exit(1);
+	    }
+	    cap_free(orig);
+	} else if (!strncmp("--has-a=", argv[i], 8)) {
+	    cap_value_t cap;
+	    if (cap_from_name(argv[i]+8, &cap) < 0) {
+		fprintf(stderr, "cap[%s] not recognized by libarary\n",
+			argv[i] + 8);
+		exit(1);
+	    }
+	    if (!cap_get_ambient(cap)) {
+		fprintf(stderr, "cap[%s] not in ambient 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);
+	    uid = getuid();
+	    if (uid != value) {
+		fprintf(stderr, "uid: got=%d, want=%d\n", uid, value);
+		exit(1);
+	    }
+	} else if (!strncmp("--is-gid=", argv[i], 9)) {
+	    unsigned value;
+	    gid_t gid;
+	    value = strtoul(argv[i]+9, NULL, 0);
+	    gid = getgid();
+	    if (gid != value) {
+		fprintf(stderr, "gid: got=%d, want=%d\n", gid, value);
+		exit(1);
+	    }
 	} else {
 	usage:
 	    printf("usage: %s [args ...]\n"
@@ -768,8 +813,10 @@
 		   "  --print        display capability relevant state\n"
 		   "  --decode=xxx   decode a hex string to a list of caps\n"
 		   "  --supports=xxx exit 1 if capability xxx unsupported\n"
+		   "  --has-p=xxx    exit 1 if capability xxx not permitted\n"
 		   "  --drop=xxx     remove xxx,.. capabilities from bset\n"
-		   "  --has-ambient  fail immediately unless ambient supported\n"
+		   "  --has-ambient  exit 1 unless ambient vector supported\n"
+		   "  --has-a=xxx    exit 1 if capability xxx not ambient\n"
 		   "  --addamb=xxx   add xxx,... capabilities to ambient set\n"
 		   "  --delamb=xxx   remove xxx,... capabilities from ambient\n"
 		   "  --noamb        reset (drop) all ambient capabilities\n"
@@ -779,7 +826,9 @@
 		   "  --keep=<n>     set keep-capabability bit to <n>\n"
 		   "  --uid=<n>      set uid to <n> (hint: id <username>)\n"
 		   "  --cap-uid=<n>  libcap cap_setuid() to change uid\n"
+		   "  --is-uid=<n>   exit 1 if uid != <n>\n"
 		   "  --gid=<n>      set gid to <n> (hint: id <username>)\n"
+		   "  --is-gid=<n>   exit 1 if gid != <n>\n"
 		   "  --groups=g,... set the supplemental groups\n"
                    "  --user=<name>  set uid,gid and groups to that of user\n"
 		   "  --chroot=path  chroot(2) to this path\n"