summaryrefslogtreecommitdiff
path: root/tools/regression/capsicum
diff options
context:
space:
mode:
authorPawel Jakub Dawidek <pjd@FreeBSD.org>2013-12-02 17:01:01 +0000
committerPawel Jakub Dawidek <pjd@FreeBSD.org>2013-12-02 17:01:01 +0000
commitca9aa9026b7a5f1b9baee68021ad651a389da2f9 (patch)
treec1febe13b240966764643c0ff1d3d741beb9c9bf /tools/regression/capsicum
parent4e11928ded709681347a62e5322a6b16fd39a78e (diff)
downloadsrc-test2-ca9aa9026b7a5f1b9baee68021ad651a389da2f9.tar.gz
src-test2-ca9aa9026b7a5f1b9baee68021ad651a389da2f9.zip
Notes
Diffstat (limited to 'tools/regression/capsicum')
-rw-r--r--tools/regression/capsicum/libcapsicum/Makefile31
-rw-r--r--tools/regression/capsicum/libcapsicum/dns.c587
-rw-r--r--tools/regression/capsicum/libcapsicum/grp.c1549
-rw-r--r--tools/regression/capsicum/libcapsicum/pwd.c1535
-rw-r--r--tools/regression/capsicum/libcapsicum/sysctl.c1509
5 files changed, 5211 insertions, 0 deletions
diff --git a/tools/regression/capsicum/libcapsicum/Makefile b/tools/regression/capsicum/libcapsicum/Makefile
new file mode 100644
index 000000000000..6fc98ba7d946
--- /dev/null
+++ b/tools/regression/capsicum/libcapsicum/Makefile
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+SERVICES= dns
+SERVICES+= grp
+SERVICES+= pwd
+SERVICES+= sysctl
+
+CFLAGS= -O2 -pipe -std=gnu99 -fstack-protector
+CFLAGS+= -Wsystem-headers -Werror -Wall -Wno-format-y2k -W -Wno-unused-parameter
+CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type
+CFLAGS+= -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wunused-parameter
+CFLAGS+= -Wcast-align -Wchar-subscripts -Winline -Wnested-externs -Wredundant-decls
+CFLAGS+= -Wold-style-definition -Wno-pointer-sign
+
+CFLAGS+= -I${.CURDIR}/../../../../lib/libcapsicum
+CFLAGS+= -ggdb
+
+all: ${SERVICES}
+
+.for SERVICE in ${SERVICES}
+
+${SERVICE}: ${SERVICE}.c
+ ${CC} ${CFLAGS} ${@}.c -o $@ -lcapsicum -lnv
+
+.endfor
+
+test: all
+ @prove -r ${.CURDIR}
+
+clean:
+ rm -f ${SERVICES}
diff --git a/tools/regression/capsicum/libcapsicum/dns.c b/tools/regression/capsicum/libcapsicum/dns.c
new file mode 100644
index 000000000000..bb7f613dd3ff
--- /dev/null
+++ b/tools/regression/capsicum/libcapsicum/dns.c
@@ -0,0 +1,587 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/capability.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcapsicum.h>
+#include <libcapsicum_dns.h>
+#include <libcapsicum_service.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ ntest++; \
+} while (0)
+#define CHECKX(expr) do { \
+ if ((expr)) { \
+ printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ } else { \
+ printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ exit(1); \
+ } \
+} while (0)
+
+#define GETHOSTBYNAME 0x01
+#define GETHOSTBYNAME2_AF_INET 0x02
+#define GETHOSTBYNAME2_AF_INET6 0x04
+#define GETHOSTBYADDR_AF_INET 0x08
+#define GETHOSTBYADDR_AF_INET6 0x10
+
+static bool
+hostent_aliases_compare(char **aliases0, char **aliases1)
+{
+ int i0, i1;
+
+ if (aliases0 == NULL && aliases1 == NULL)
+ return (true);
+ if (aliases0 == NULL || aliases1 == NULL)
+ return (false);
+
+ for (i0 = 0; aliases0[i0] != NULL; i0++) {
+ for (i1 = 0; aliases1[i1] != NULL; i1++) {
+ if (strcmp(aliases0[i0], aliases1[i1]) == 0)
+ break;
+ }
+ if (aliases1[i1] == NULL)
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+hostent_addr_list_compare(char **addr_list0, char **addr_list1, int length)
+{
+ int i0, i1;
+
+ if (addr_list0 == NULL && addr_list1 == NULL)
+ return (true);
+ if (addr_list0 == NULL || addr_list1 == NULL)
+ return (false);
+
+ for (i0 = 0; addr_list0[i0] != NULL; i0++) {
+ for (i1 = 0; addr_list1[i1] != NULL; i1++) {
+ if (memcmp(addr_list0[i0], addr_list1[i1], length) == 0)
+ break;
+ }
+ if (addr_list1[i1] == NULL)
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+hostent_compare(const struct hostent *hp0, const struct hostent *hp1)
+{
+
+ if (hp0 == NULL && hp1 != NULL)
+ return (true);
+
+ if (hp0 == NULL || hp1 == NULL)
+ return (false);
+
+ if (hp0->h_name != NULL || hp1->h_name != NULL) {
+ if (hp0->h_name == NULL || hp1->h_name == NULL)
+ return (false);
+ if (strcmp(hp0->h_name, hp1->h_name) != 0)
+ return (false);
+ }
+
+ if (!hostent_aliases_compare(hp0->h_aliases, hp1->h_aliases))
+ return (false);
+ if (!hostent_aliases_compare(hp1->h_aliases, hp0->h_aliases))
+ return (false);
+
+ if (hp0->h_addrtype != hp1->h_addrtype)
+ return (false);
+
+ if (hp0->h_length != hp1->h_length)
+ return (false);
+
+ if (!hostent_addr_list_compare(hp0->h_addr_list, hp1->h_addr_list,
+ hp0->h_length)) {
+ return (false);
+ }
+ if (!hostent_addr_list_compare(hp1->h_addr_list, hp0->h_addr_list,
+ hp0->h_length)) {
+ return (false);
+ }
+
+ return (true);
+}
+
+static unsigned int
+runtest(cap_channel_t *capdns)
+{
+ unsigned int result;
+ struct hostent *hps, *hpc;
+ struct in_addr ip4;
+ struct in6_addr ip6;
+
+ result = 0;
+
+ hps = gethostbyname("example.com");
+ if (hps == NULL)
+ fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
+ hpc = cap_gethostbyname(capdns, "example.com");
+ if (hostent_compare(hps, hpc))
+ result |= GETHOSTBYNAME;
+
+ hps = gethostbyname2("example.com", AF_INET);
+ if (hps == NULL)
+ fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
+ hpc = cap_gethostbyname2(capdns, "example.com", AF_INET);
+ if (hostent_compare(hps, hpc))
+ result |= GETHOSTBYNAME2_AF_INET;
+
+ hps = gethostbyname2("example.com", AF_INET6);
+ if (hps == NULL)
+ fprintf(stderr, "Unable to resolve %s IPv6.\n", "example.com");
+ hpc = cap_gethostbyname2(capdns, "example.com", AF_INET6);
+ if (hostent_compare(hps, hpc))
+ result |= GETHOSTBYNAME2_AF_INET6;
+
+ /*
+ * 8.8.178.135 is IPv4 address of freefall.freebsd.org
+ * as of 27 October 2013.
+ */
+ inet_pton(AF_INET, "8.8.178.135", &ip4);
+ hps = gethostbyaddr(&ip4, sizeof(ip4), AF_INET);
+ if (hps == NULL)
+ fprintf(stderr, "Unable to resolve %s.\n", "8.8.178.135");
+ hpc = cap_gethostbyaddr(capdns, &ip4, sizeof(ip4), AF_INET);
+ if (hostent_compare(hps, hpc))
+ result |= GETHOSTBYADDR_AF_INET;
+
+ /*
+ * 2001:1900:2254:206c::16:87 is IPv6 address of freefall.freebsd.org
+ * as of 27 October 2013.
+ */
+ inet_pton(AF_INET6, "2001:1900:2254:206c::16:87", &ip6);
+ hps = gethostbyaddr(&ip6, sizeof(ip6), AF_INET6);
+ if (hps == NULL) {
+ fprintf(stderr, "Unable to resolve %s.\n",
+ "2001:1900:2254:206c::16:87");
+ }
+ hpc = cap_gethostbyaddr(capdns, &ip6, sizeof(ip6), AF_INET6);
+ if (hostent_compare(hps, hpc))
+ result |= GETHOSTBYADDR_AF_INET6;
+
+ return (result);
+}
+
+int
+main(void)
+{
+ cap_channel_t *capcas, *capdns, *origcapdns;
+ const char *types[2];
+ int families[2];
+
+ printf("1..89\n");
+
+ capcas = cap_init();
+ CHECKX(capcas != NULL);
+
+ origcapdns = capdns = cap_service_open(capcas, "system.dns");
+ CHECKX(capdns != NULL);
+
+ cap_close(capcas);
+
+ /* No limits set. */
+
+ CHECK(runtest(capdns) ==
+ (GETHOSTBYNAME | GETHOSTBYNAME2_AF_INET | GETHOSTBYNAME2_AF_INET6 |
+ GETHOSTBYADDR_AF_INET | GETHOSTBYADDR_AF_INET6));
+
+ /*
+ * Allow:
+ * type: NAME, ADDR
+ * family: AF_INET, AF_INET6
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+
+ CHECK(runtest(capdns) ==
+ (GETHOSTBYNAME | GETHOSTBYNAME2_AF_INET | GETHOSTBYNAME2_AF_INET6 |
+ GETHOSTBYADDR_AF_INET | GETHOSTBYADDR_AF_INET6));
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: NAME
+ * family: AF_INET, AF_INET6
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+
+ CHECK(runtest(capdns) ==
+ (GETHOSTBYNAME | GETHOSTBYNAME2_AF_INET | GETHOSTBYNAME2_AF_INET6));
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: ADDR
+ * family: AF_INET, AF_INET6
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ types[1] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+
+ CHECK(runtest(capdns) ==
+ (GETHOSTBYADDR_AF_INET | GETHOSTBYADDR_AF_INET6));
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: NAME, ADDR
+ * family: AF_INET
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest(capdns) ==
+ (GETHOSTBYNAME | GETHOSTBYNAME2_AF_INET | GETHOSTBYADDR_AF_INET));
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: NAME, ADDR
+ * family: AF_INET6
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+ families[1] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest(capdns) ==
+ (GETHOSTBYNAME2_AF_INET6 | GETHOSTBYADDR_AF_INET6));
+
+ cap_close(capdns);
+
+ /* Below we also test further limiting capability. */
+
+ /*
+ * Allow:
+ * type: NAME
+ * family: AF_INET
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest(capdns) == (GETHOSTBYNAME | GETHOSTBYNAME2_AF_INET));
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: NAME
+ * family: AF_INET6
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+ families[1] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest(capdns) == GETHOSTBYNAME2_AF_INET6);
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: ADDR
+ * family: AF_INET
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ types[1] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest(capdns) == GETHOSTBYADDR_AF_INET);
+
+ cap_close(capdns);
+
+ /*
+ * Allow:
+ * type: ADDR
+ * family: AF_INET6
+ */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == 0);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == 0);
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ types[1] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+ families[1] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest(capdns) == GETHOSTBYADDR_AF_INET6);
+
+ cap_close(capdns);
+
+ /* Trying to rise the limits. */
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(cap_dns_type_limit(capdns, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ CHECK(cap_dns_family_limit(capdns, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+
+ /* Do the limits still hold? */
+ CHECK(runtest(capdns) == (GETHOSTBYNAME | GETHOSTBYNAME2_AF_INET));
+
+ cap_close(capdns);
+
+ capdns = cap_clone(origcapdns);
+ CHECK(capdns != NULL);
+
+ types[0] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == 0);
+ families[0] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == 0);
+
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ CHECK(cap_dns_type_limit(capdns, types, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ families[1] = AF_INET6;
+ CHECK(cap_dns_family_limit(capdns, families, 2) == -1 &&
+ errno == ENOTCAPABLE);
+
+ types[0] = "NAME";
+ CHECK(cap_dns_type_limit(capdns, types, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ families[0] = AF_INET;
+ CHECK(cap_dns_family_limit(capdns, families, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(cap_dns_type_limit(capdns, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ CHECK(cap_dns_family_limit(capdns, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+
+ /* Do the limits still hold? */
+ CHECK(runtest(capdns) == GETHOSTBYADDR_AF_INET6);
+
+ cap_close(capdns);
+
+ cap_close(origcapdns);
+
+ exit(0);
+}
diff --git a/tools/regression/capsicum/libcapsicum/grp.c b/tools/regression/capsicum/libcapsicum/grp.c
new file mode 100644
index 000000000000..1d3adfb845aa
--- /dev/null
+++ b/tools/regression/capsicum/libcapsicum/grp.c
@@ -0,0 +1,1549 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/capability.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcapsicum.h>
+#include <libcapsicum_grp.h>
+#include <libcapsicum_service.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ ntest++; \
+} while (0)
+#define CHECKX(expr) do { \
+ if ((expr)) { \
+ printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ } else { \
+ printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ exit(1); \
+ } \
+} while (0)
+
+#define GID_WHEEL 0
+#define GID_OPERATOR 5
+
+#define GETGRENT0 0x0001
+#define GETGRENT1 0x0002
+#define GETGRENT2 0x0004
+#define GETGRENT (GETGRENT0 | GETGRENT1 | GETGRENT2)
+#define GETGRENT_R0 0x0008
+#define GETGRENT_R1 0x0010
+#define GETGRENT_R2 0x0020
+#define GETGRENT_R (GETGRENT_R0 | GETGRENT_R1 | GETGRENT_R2)
+#define GETGRNAM 0x0040
+#define GETGRNAM_R 0x0080
+#define GETGRGID 0x0100
+#define GETGRGID_R 0x0200
+#define SETGRENT 0x0400
+
+static bool
+group_mem_compare(char **mem0, char **mem1)
+{
+ int i0, i1;
+
+ if (mem0 == NULL && mem1 == NULL)
+ return (true);
+ if (mem0 == NULL || mem1 == NULL)
+ return (false);
+
+ for (i0 = 0; mem0[i0] != NULL; i0++) {
+ for (i1 = 0; mem1[i1] != NULL; i1++) {
+ if (strcmp(mem0[i0], mem1[i1]) == 0)
+ break;
+ }
+ if (mem1[i1] == NULL)
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+group_compare(const struct group *grp0, const struct group *grp1)
+{
+
+ if (grp0 == NULL && grp1 == NULL)
+ return (true);
+ if (grp0 == NULL || grp1 == NULL)
+ return (false);
+
+ if (strcmp(grp0->gr_name, grp1->gr_name) != 0)
+ return (false);
+
+ if (grp0->gr_passwd != NULL || grp1->gr_passwd != NULL) {
+ if (grp0->gr_passwd == NULL || grp1->gr_passwd == NULL)
+ return (false);
+ if (strcmp(grp0->gr_passwd, grp1->gr_passwd) != 0)
+ return (false);
+ }
+
+ if (grp0->gr_gid != grp1->gr_gid)
+ return (false);
+
+ if (!group_mem_compare(grp0->gr_mem, grp1->gr_mem))
+ return (false);
+
+ return (true);
+}
+
+static unsigned int
+runtest_cmds(cap_channel_t *capgrp)
+{
+ char bufs[1024], bufc[1024];
+ unsigned int result;
+ struct group *grps, *grpc;
+ struct group sts, stc;
+
+ result = 0;
+
+ (void)setgrent();
+ if (cap_setgrent(capgrp) == 1)
+ result |= SETGRENT;
+
+ grps = getgrent();
+ grpc = cap_getgrent(capgrp);
+ if (group_compare(grps, grpc)) {
+ result |= GETGRENT0;
+ grps = getgrent();
+ grpc = cap_getgrent(capgrp);
+ if (group_compare(grps, grpc))
+ result |= GETGRENT1;
+ }
+
+ getgrent_r(&sts, bufs, sizeof(bufs), &grps);
+ cap_getgrent_r(capgrp, &stc, bufc, sizeof(bufc), &grpc);
+ if (group_compare(grps, grpc)) {
+ result |= GETGRENT_R0;
+ getgrent_r(&sts, bufs, sizeof(bufs), &grps);
+ cap_getgrent_r(capgrp, &stc, bufc, sizeof(bufc), &grpc);
+ if (group_compare(grps, grpc))
+ result |= GETGRENT_R1;
+ }
+
+ (void)setgrent();
+ if (cap_setgrent(capgrp) == 1)
+ result |= SETGRENT;
+
+ getgrent_r(&sts, bufs, sizeof(bufs), &grps);
+ cap_getgrent_r(capgrp, &stc, bufc, sizeof(bufc), &grpc);
+ if (group_compare(grps, grpc))
+ result |= GETGRENT_R2;
+
+ grps = getgrent();
+ grpc = cap_getgrent(capgrp);
+ if (group_compare(grps, grpc))
+ result |= GETGRENT2;
+
+ grps = getgrnam("wheel");
+ grpc = cap_getgrnam(capgrp, "wheel");
+ if (group_compare(grps, grpc)) {
+ grps = getgrnam("operator");
+ grpc = cap_getgrnam(capgrp, "operator");
+ if (group_compare(grps, grpc))
+ result |= GETGRNAM;
+ }
+
+ getgrnam_r("wheel", &sts, bufs, sizeof(bufs), &grps);
+ cap_getgrnam_r(capgrp, "wheel", &stc, bufc, sizeof(bufc), &grpc);
+ if (group_compare(grps, grpc)) {
+ getgrnam_r("operator", &sts, bufs, sizeof(bufs), &grps);
+ cap_getgrnam_r(capgrp, "operator", &stc, bufc, sizeof(bufc),
+ &grpc);
+ if (group_compare(grps, grpc))
+ result |= GETGRNAM_R;
+ }
+
+ grps = getgrgid(GID_WHEEL);
+ grpc = cap_getgrgid(capgrp, GID_WHEEL);
+ if (group_compare(grps, grpc)) {
+ grps = getgrgid(GID_OPERATOR);
+ grpc = cap_getgrgid(capgrp, GID_OPERATOR);
+ if (group_compare(grps, grpc))
+ result |= GETGRGID;
+ }
+
+ getgrgid_r(GID_WHEEL, &sts, bufs, sizeof(bufs), &grps);
+ cap_getgrgid_r(capgrp, GID_WHEEL, &stc, bufc, sizeof(bufc), &grpc);
+ if (group_compare(grps, grpc)) {
+ getgrgid_r(GID_OPERATOR, &sts, bufs, sizeof(bufs), &grps);
+ cap_getgrgid_r(capgrp, GID_OPERATOR, &stc, bufc, sizeof(bufc),
+ &grpc);
+ if (group_compare(grps, grpc))
+ result |= GETGRGID_R;
+ }
+
+ return (result);
+}
+
+static void
+test_cmds(cap_channel_t *origcapgrp)
+{
+ cap_channel_t *capgrp;
+ const char *cmds[7], *fields[4], *names[5];
+ gid_t gids[5];
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+
+ names[0] = "wheel";
+ names[1] = "daemon";
+ names[2] = "kmem";
+ names[3] = "sys";
+ names[4] = "operator";
+
+ gids[0] = 0;
+ gids[1] = 1;
+ gids[2] = 2;
+ gids[3] = 3;
+ gids[4] = 5;
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == 0);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == 0);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: setgrent
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "getgrent";
+ cmds[1] = "getgrent_r";
+ cmds[2] = "getgrnam";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "setgrent";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (GETGRENT0 | GETGRENT1 | GETGRENT_R0 |
+ GETGRENT_R1 | GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: setgrent
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "getgrent";
+ cmds[1] = "getgrent_r";
+ cmds[2] = "getgrnam";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "setgrent";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (GETGRENT0 | GETGRENT1 | GETGRENT_R0 |
+ GETGRENT_R1 | GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: getgrent
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent_r";
+ cmds[2] = "getgrnam";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrent";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT_R2 |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getgrent
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent_r";
+ cmds[2] = "getgrnam";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrent";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT_R2 |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: getgrent_r
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrnam";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrent_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT0 | GETGRENT1 |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrnam, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getgrent_r
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrnam";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrent_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT0 | GETGRENT1 |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: getgrnam
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrnam";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam_r,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getgrnam
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam_r";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrnam";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: getgrnam_r
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrnam_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam,
+ * getgrgid, getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getgrnam_r
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrgid";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrnam_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRGID | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: getgrgid
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrgid";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid_r
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getgrgid
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrgid";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID_R));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names: wheel, daemon, kmem, sys, operator
+ * gids:
+ * Disallow:
+ * cmds: getgrgid_r
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * cmds: setgrent, getgrent, getgrent_r, getgrnam, getgrnam_r,
+ * getgrgid
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ * groups:
+ * names:
+ * gids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getgrgid_r
+ * fields:
+ * groups:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 6) == 0);
+ cmds[0] = "setgrent";
+ cmds[1] = "getgrent";
+ cmds[2] = "getgrent_r";
+ cmds[3] = "getgrnam";
+ cmds[4] = "getgrnam_r";
+ cmds[5] = "getgrgid";
+ cmds[6] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getgrgid_r";
+ CHECK(cap_grp_limit_cmds(capgrp, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 5) == 0);
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID));
+
+ cap_close(capgrp);
+}
+
+#define GR_NAME 0x01
+#define GR_PASSWD 0x02
+#define GR_GID 0x04
+#define GR_MEM 0x08
+
+static unsigned int
+group_fields(const struct group *grp)
+{
+ unsigned int result;
+
+ result = 0;
+
+ if (grp->gr_name != NULL && grp->gr_name[0] != '\0')
+ result |= GR_NAME;
+
+ if (grp->gr_passwd != NULL && grp->gr_passwd[0] != '\0')
+ result |= GR_PASSWD;
+
+ if (grp->gr_gid != (gid_t)-1)
+ result |= GR_GID;
+
+ if (grp->gr_mem != NULL && grp->gr_mem[0] != NULL)
+ result |= GR_MEM;
+
+ return (result);
+}
+
+static bool
+runtest_fields(cap_channel_t *capgrp, unsigned int expected)
+{
+ char buf[1024];
+ struct group *grp;
+ struct group st;
+
+ (void)cap_setgrent(capgrp);
+ grp = cap_getgrent(capgrp);
+ if (group_fields(grp) != expected)
+ return (false);
+
+ (void)cap_setgrent(capgrp);
+ cap_getgrent_r(capgrp, &st, buf, sizeof(buf), &grp);
+ if (group_fields(grp) != expected)
+ return (false);
+
+ grp = cap_getgrnam(capgrp, "wheel");
+ if (group_fields(grp) != expected)
+ return (false);
+
+ cap_getgrnam_r(capgrp, "wheel", &st, buf, sizeof(buf), &grp);
+ if (group_fields(grp) != expected)
+ return (false);
+
+ grp = cap_getgrgid(capgrp, GID_WHEEL);
+ if (group_fields(grp) != expected)
+ return (false);
+
+ cap_getgrgid_r(capgrp, GID_WHEEL, &st, buf, sizeof(buf), &grp);
+ if (group_fields(grp) != expected)
+ return (false);
+
+ return (true);
+}
+
+static void
+test_fields(cap_channel_t *origcapgrp)
+{
+ cap_channel_t *capgrp;
+ const char *fields[4];
+
+ /* No limits. */
+
+ CHECK(runtest_fields(origcapgrp, GR_NAME | GR_PASSWD | GR_GID | GR_MEM));
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_passwd, gr_gid, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == 0);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD | GR_GID | GR_MEM));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_passwd, gr_gid, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_passwd";
+ fields[1] = "gr_gid";
+ fields[2] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_PASSWD | GR_GID | GR_MEM));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_gid, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_gid";
+ fields[2] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_passwd";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_GID | GR_MEM));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_passwd, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_gid";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD | GR_MEM));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_passwd, gr_gid
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 3) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD | GR_GID));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_passwd
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_gid";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_PASSWD));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_gid
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_gid";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_GID));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_name, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_name";
+ fields[1] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_passwd";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_NAME | GR_MEM));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_passwd, gr_gid
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_passwd";
+ fields[1] = "gr_gid";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_PASSWD | GR_GID));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_passwd, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_passwd";
+ fields[1] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_gid";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_PASSWD | GR_MEM));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * fields: gr_gid, gr_mem
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ fields[0] = "gr_gid";
+ fields[1] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 2) == 0);
+ fields[0] = "gr_name";
+ fields[1] = "gr_passwd";
+ fields[2] = "gr_gid";
+ fields[3] = "gr_mem";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "gr_passwd";
+ CHECK(cap_grp_limit_fields(capgrp, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(capgrp, GR_GID | GR_MEM));
+
+ cap_close(capgrp);
+}
+
+static bool
+runtest_groups(cap_channel_t *capgrp, const char **names, const gid_t *gids,
+ size_t ngroups)
+{
+ char buf[1024];
+ struct group *grp;
+ struct group st;
+ unsigned int i, got;
+
+ (void)cap_setgrent(capgrp);
+ got = 0;
+ for (;;) {
+ grp = cap_getgrent(capgrp);
+ if (grp == NULL)
+ break;
+ got++;
+ for (i = 0; i < ngroups; i++) {
+ if (strcmp(names[i], grp->gr_name) == 0 &&
+ gids[i] == grp->gr_gid) {
+ break;
+ }
+ }
+ if (i == ngroups)
+ return (false);
+ }
+ if (got != ngroups)
+ return (false);
+
+ (void)cap_setgrent(capgrp);
+ got = 0;
+ for (;;) {
+ cap_getgrent_r(capgrp, &st, buf, sizeof(buf), &grp);
+ if (grp == NULL)
+ break;
+ got++;
+ for (i = 0; i < ngroups; i++) {
+ if (strcmp(names[i], grp->gr_name) == 0 &&
+ gids[i] == grp->gr_gid) {
+ break;
+ }
+ }
+ if (i == ngroups)
+ return (false);
+ }
+ if (got != ngroups)
+ return (false);
+
+ for (i = 0; i < ngroups; i++) {
+ grp = cap_getgrnam(capgrp, names[i]);
+ if (grp == NULL)
+ return (false);
+ }
+
+ for (i = 0; i < ngroups; i++) {
+ cap_getgrnam_r(capgrp, names[i], &st, buf, sizeof(buf), &grp);
+ if (grp == NULL)
+ return (false);
+ }
+
+ for (i = 0; i < ngroups; i++) {
+ grp = cap_getgrgid(capgrp, gids[i]);
+ if (grp == NULL)
+ return (false);
+ }
+
+ for (i = 0; i < ngroups; i++) {
+ cap_getgrgid_r(capgrp, gids[i], &st, buf, sizeof(buf), &grp);
+ if (grp == NULL)
+ return (false);
+ }
+
+ return (true);
+}
+
+static void
+test_groups(cap_channel_t *origcapgrp)
+{
+ cap_channel_t *capgrp;
+ const char *names[5];
+ gid_t gids[5];
+
+ /*
+ * Allow:
+ * groups:
+ * names: wheel, daemon, kmem, sys, tty
+ * gids:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "wheel";
+ names[1] = "daemon";
+ names[2] = "kmem";
+ names[3] = "sys";
+ names[4] = "tty";
+ CHECK(cap_grp_limit_groups(capgrp, names, 5, NULL, 0) == 0);
+ gids[0] = 0;
+ gids[1] = 1;
+ gids[2] = 2;
+ gids[3] = 3;
+ gids[4] = 4;
+
+ CHECK(runtest_groups(capgrp, names, gids, 5));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names: kmem, sys, tty
+ * gids:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "kmem";
+ names[1] = "sys";
+ names[2] = "tty";
+ CHECK(cap_grp_limit_groups(capgrp, names, 3, NULL, 0) == 0);
+ names[3] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 4, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "kmem";
+ gids[0] = 2;
+ gids[1] = 3;
+ gids[2] = 4;
+
+ CHECK(runtest_groups(capgrp, names, gids, 3));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names: wheel, kmem, tty
+ * gids:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "wheel";
+ names[1] = "kmem";
+ names[2] = "tty";
+ CHECK(cap_grp_limit_groups(capgrp, names, 3, NULL, 0) == 0);
+ names[3] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 4, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "wheel";
+ gids[0] = 0;
+ gids[1] = 2;
+ gids[2] = 4;
+
+ CHECK(runtest_groups(capgrp, names, gids, 3));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names:
+ * gids: 2, 3, 4
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "kmem";
+ names[1] = "sys";
+ names[2] = "tty";
+ gids[0] = 2;
+ gids[1] = 3;
+ gids[2] = 4;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 3) == 0);
+ gids[3] = 0;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 0;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 2;
+
+ CHECK(runtest_groups(capgrp, names, gids, 3));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names:
+ * gids: 0, 2, 4
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "wheel";
+ names[1] = "kmem";
+ names[2] = "tty";
+ gids[0] = 0;
+ gids[1] = 2;
+ gids[2] = 4;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 3) == 0);
+ gids[3] = 1;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 1;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 0;
+
+ CHECK(runtest_groups(capgrp, names, gids, 3));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names: kmem
+ * gids:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "kmem";
+ CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == 0);
+ names[1] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 2, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "kmem";
+ gids[0] = 2;
+
+ CHECK(runtest_groups(capgrp, names, gids, 1));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names: wheel, tty
+ * gids:
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "wheel";
+ names[1] = "tty";
+ CHECK(cap_grp_limit_groups(capgrp, names, 2, NULL, 0) == 0);
+ names[2] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 3, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ CHECK(cap_grp_limit_groups(capgrp, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "wheel";
+ gids[0] = 0;
+ gids[1] = 4;
+
+ CHECK(runtest_groups(capgrp, names, gids, 2));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names:
+ * gids: 2
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "kmem";
+ gids[0] = 2;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == 0);
+ gids[1] = 1;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 1;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 2;
+
+ CHECK(runtest_groups(capgrp, names, gids, 1));
+
+ cap_close(capgrp);
+
+ /*
+ * Allow:
+ * groups:
+ * names:
+ * gids: 0, 4
+ */
+ capgrp = cap_clone(origcapgrp);
+ CHECK(capgrp != NULL);
+
+ names[0] = "wheel";
+ names[1] = "tty";
+ gids[0] = 0;
+ gids[1] = 4;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 2) == 0);
+ gids[2] = 1;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 3) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 1;
+ CHECK(cap_grp_limit_groups(capgrp, NULL, 0, gids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ gids[0] = 0;
+
+ CHECK(runtest_groups(capgrp, names, gids, 2));
+
+ cap_close(capgrp);
+}
+
+int
+main(void)
+{
+ cap_channel_t *capcas, *capgrp;
+
+ printf("1..197\n");
+
+ capcas = cap_init();
+ CHECKX(capcas != NULL);
+
+ capgrp = cap_service_open(capcas, "system.grp");
+ CHECKX(capgrp != NULL);
+
+ cap_close(capcas);
+
+ /* No limits. */
+
+ CHECK(runtest_cmds(capgrp) == (SETGRENT | GETGRENT | GETGRENT_R |
+ GETGRNAM | GETGRNAM_R | GETGRGID | GETGRGID_R));
+
+ test_cmds(capgrp);
+
+ test_fields(capgrp);
+
+ test_groups(capgrp);
+
+ cap_close(capgrp);
+
+ exit(0);
+}
diff --git a/tools/regression/capsicum/libcapsicum/pwd.c b/tools/regression/capsicum/libcapsicum/pwd.c
new file mode 100644
index 000000000000..161885dd4214
--- /dev/null
+++ b/tools/regression/capsicum/libcapsicum/pwd.c
@@ -0,0 +1,1535 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/capability.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcapsicum.h>
+#include <libcapsicum_pwd.h>
+#include <libcapsicum_service.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+#define CHECKX(expr) do { \
+ if ((expr)) { \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ } else { \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ exit(1); \
+ } \
+} while (0)
+
+#define UID_ROOT 0
+#define UID_OPERATOR 2
+
+#define GETPWENT0 0x0001
+#define GETPWENT1 0x0002
+#define GETPWENT2 0x0004
+#define GETPWENT (GETPWENT0 | GETPWENT1 | GETPWENT2)
+#define GETPWENT_R0 0x0008
+#define GETPWENT_R1 0x0010
+#define GETPWENT_R2 0x0020
+#define GETPWENT_R (GETPWENT_R0 | GETPWENT_R1 | GETPWENT_R2)
+#define GETPWNAM 0x0040
+#define GETPWNAM_R 0x0080
+#define GETPWUID 0x0100
+#define GETPWUID_R 0x0200
+
+static bool
+passwd_compare(const struct passwd *pwd0, const struct passwd *pwd1)
+{
+
+ if (pwd0 == NULL && pwd1 == NULL)
+ return (true);
+ if (pwd0 == NULL || pwd1 == NULL)
+ return (false);
+
+ if (strcmp(pwd0->pw_name, pwd1->pw_name) != 0)
+ return (false);
+
+ if (pwd0->pw_passwd != NULL || pwd1->pw_passwd != NULL) {
+ if (pwd0->pw_passwd == NULL || pwd1->pw_passwd == NULL)
+ return (false);
+ if (strcmp(pwd0->pw_passwd, pwd1->pw_passwd) != 0)
+ return (false);
+ }
+
+ if (pwd0->pw_uid != pwd1->pw_uid)
+ return (false);
+
+ if (pwd0->pw_gid != pwd1->pw_gid)
+ return (false);
+
+ if (pwd0->pw_change != pwd1->pw_change)
+ return (false);
+
+ if (pwd0->pw_class != NULL || pwd1->pw_class != NULL) {
+ if (pwd0->pw_class == NULL || pwd1->pw_class == NULL)
+ return (false);
+ if (strcmp(pwd0->pw_class, pwd1->pw_class) != 0)
+ return (false);
+ }
+
+ if (pwd0->pw_gecos != NULL || pwd1->pw_gecos != NULL) {
+ if (pwd0->pw_gecos == NULL || pwd1->pw_gecos == NULL)
+ return (false);
+ if (strcmp(pwd0->pw_gecos, pwd1->pw_gecos) != 0)
+ return (false);
+ }
+
+ if (pwd0->pw_dir != NULL || pwd1->pw_dir != NULL) {
+ if (pwd0->pw_dir == NULL || pwd1->pw_dir == NULL)
+ return (false);
+ if (strcmp(pwd0->pw_dir, pwd1->pw_dir) != 0)
+ return (false);
+ }
+
+ if (pwd0->pw_shell != NULL || pwd1->pw_shell != NULL) {
+ if (pwd0->pw_shell == NULL || pwd1->pw_shell == NULL)
+ return (false);
+ if (strcmp(pwd0->pw_shell, pwd1->pw_shell) != 0)
+ return (false);
+ }
+
+ if (pwd0->pw_expire != pwd1->pw_expire)
+ return (false);
+
+ if (pwd0->pw_fields != pwd1->pw_fields)
+ return (false);
+
+ return (true);
+}
+
+static unsigned int
+runtest_cmds(cap_channel_t *cappwd)
+{
+ char bufs[1024], bufc[1024];
+ unsigned int result;
+ struct passwd *pwds, *pwdc;
+ struct passwd sts, stc;
+
+ result = 0;
+
+ setpwent();
+ cap_setpwent(cappwd);
+
+ pwds = getpwent();
+ pwdc = cap_getpwent(cappwd);
+ if (passwd_compare(pwds, pwdc)) {
+ result |= GETPWENT0;
+ pwds = getpwent();
+ pwdc = cap_getpwent(cappwd);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWENT1;
+ }
+
+ getpwent_r(&sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwent_r(cappwd, &stc, bufc, sizeof(bufc), &pwdc);
+ if (passwd_compare(pwds, pwdc)) {
+ result |= GETPWENT_R0;
+ getpwent_r(&sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwent_r(cappwd, &stc, bufc, sizeof(bufc), &pwdc);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWENT_R1;
+ }
+
+ setpwent();
+ cap_setpwent(cappwd);
+
+ getpwent_r(&sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwent_r(cappwd, &stc, bufc, sizeof(bufc), &pwdc);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWENT_R2;
+
+ pwds = getpwent();
+ pwdc = cap_getpwent(cappwd);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWENT2;
+
+ pwds = getpwnam("root");
+ pwdc = cap_getpwnam(cappwd, "root");
+ if (passwd_compare(pwds, pwdc)) {
+ pwds = getpwnam("operator");
+ pwdc = cap_getpwnam(cappwd, "operator");
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWNAM;
+ }
+
+ getpwnam_r("root", &sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwnam_r(cappwd, "root", &stc, bufc, sizeof(bufc), &pwdc);
+ if (passwd_compare(pwds, pwdc)) {
+ getpwnam_r("operator", &sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwnam_r(cappwd, "operator", &stc, bufc, sizeof(bufc),
+ &pwdc);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWNAM_R;
+ }
+
+ pwds = getpwuid(UID_ROOT);
+ pwdc = cap_getpwuid(cappwd, UID_ROOT);
+ if (passwd_compare(pwds, pwdc)) {
+ pwds = getpwuid(UID_OPERATOR);
+ pwdc = cap_getpwuid(cappwd, UID_OPERATOR);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWUID;
+ }
+
+ getpwuid_r(UID_ROOT, &sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwuid_r(cappwd, UID_ROOT, &stc, bufc, sizeof(bufc), &pwdc);
+ if (passwd_compare(pwds, pwdc)) {
+ getpwuid_r(UID_OPERATOR, &sts, bufs, sizeof(bufs), &pwds);
+ cap_getpwuid_r(cappwd, UID_OPERATOR, &stc, bufc, sizeof(bufc),
+ &pwdc);
+ if (passwd_compare(pwds, pwdc))
+ result |= GETPWUID_R;
+ }
+
+ return (result);
+}
+
+static void
+test_cmds(cap_channel_t *origcappwd)
+{
+ cap_channel_t *cappwd;
+ const char *cmds[7], *fields[10], *names[6];
+ uid_t uids[5];
+
+ fields[0] = "pw_name";
+ fields[1] = "pw_passwd";
+ fields[2] = "pw_uid";
+ fields[3] = "pw_gid";
+ fields[4] = "pw_change";
+ fields[5] = "pw_class";
+ fields[6] = "pw_gecos";
+ fields[7] = "pw_dir";
+ fields[8] = "pw_shell";
+ fields[9] = "pw_expire";
+
+ names[0] = "root";
+ names[1] = "toor";
+ names[2] = "daemon";
+ names[3] = "operator";
+ names[4] = "bin";
+ names[5] = "kmem";
+
+ uids[0] = 0;
+ uids[1] = 1;
+ uids[2] = 2;
+ uids[3] = 3;
+ uids[4] = 5;
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == 0);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == 0);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: setpwent
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cap_setpwent(cappwd);
+
+ cmds[0] = "getpwent";
+ cmds[1] = "getpwent_r";
+ cmds[2] = "getpwnam";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "setpwent";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 | GETPWENT_R0 |
+ GETPWENT_R1 | GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: setpwent
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cap_setpwent(cappwd);
+
+ cmds[0] = "getpwent";
+ cmds[1] = "getpwent_r";
+ cmds[2] = "getpwnam";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "setpwent";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 | GETPWENT_R0 |
+ GETPWENT_R1 | GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: getpwent
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent_r";
+ cmds[2] = "getpwnam";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwent";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT_R2 |
+ GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getpwent
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent_r";
+ cmds[2] = "getpwnam";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwent";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT_R2 |
+ GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: getpwent_r
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwnam";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwent_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 |
+ GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwnam, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getpwent_r
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwnam";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwent_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 |
+ GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: getpwnam
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwnam";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam_r,
+ * getpwuid, getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getpwnam
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam_r";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwnam";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam,
+ * getpwuid, getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: getpwnam_r
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwnam_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam,
+ * getpwuid, getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getpwnam_r
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwuid";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwnam_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWUID | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid_r
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: getpwuid
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwuid";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWNAM_R | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid_r
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getpwuid
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwuid";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWNAM_R | GETPWUID_R));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid
+ * users:
+ * names: root, toor, daemon, operator, bin, kmem
+ * uids:
+ * Disallow:
+ * cmds: getpwuid_r
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWNAM_R | GETPWUID));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * cmds: setpwent, getpwent, getpwent_r, getpwnam, getpwnam_r,
+ * getpwuid
+ * users:
+ * names:
+ * uids: 0, 1, 2, 3, 5
+ * Disallow:
+ * cmds: getpwuid_r
+ * users:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
+ cmds[0] = "setpwent";
+ cmds[1] = "getpwent";
+ cmds[2] = "getpwent_r";
+ cmds[3] = "getpwnam";
+ cmds[4] = "getpwnam_r";
+ cmds[5] = "getpwuid";
+ cmds[6] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
+ cmds[0] = "getpwuid_r";
+ CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
+ GETPWNAM | GETPWNAM_R | GETPWUID));
+
+ cap_close(cappwd);
+}
+
+#define PW_NAME _PWF_NAME
+#define PW_PASSWD _PWF_PASSWD
+#define PW_UID _PWF_UID
+#define PW_GID _PWF_GID
+#define PW_CHANGE _PWF_CHANGE
+#define PW_CLASS _PWF_CLASS
+#define PW_GECOS _PWF_GECOS
+#define PW_DIR _PWF_DIR
+#define PW_SHELL _PWF_SHELL
+#define PW_EXPIRE _PWF_EXPIRE
+
+static unsigned int
+passwd_fields(const struct passwd *pwd)
+{
+ unsigned int result;
+
+ result = 0;
+
+ if (pwd->pw_name != NULL && pwd->pw_name[0] != '\0')
+ result |= PW_NAME;
+// else
+// printf("No pw_name\n");
+
+ if (pwd->pw_passwd != NULL && pwd->pw_passwd[0] != '\0')
+ result |= PW_PASSWD;
+ else if ((pwd->pw_fields & _PWF_PASSWD) != 0)
+ result |= PW_PASSWD;
+// else
+// printf("No pw_passwd\n");
+
+ if (pwd->pw_uid != (uid_t)-1)
+ result |= PW_UID;
+// else
+// printf("No pw_uid\n");
+
+ if (pwd->pw_gid != (gid_t)-1)
+ result |= PW_GID;
+// else
+// printf("No pw_gid\n");
+
+ if (pwd->pw_change != 0 || (pwd->pw_fields & _PWF_CHANGE) != 0)
+ result |= PW_CHANGE;
+// else
+// printf("No pw_change\n");
+
+ if (pwd->pw_class != NULL && pwd->pw_class[0] != '\0')
+ result |= PW_CLASS;
+ else if ((pwd->pw_fields & _PWF_CLASS) != 0)
+ result |= PW_CLASS;
+// else
+// printf("No pw_class\n");
+
+ if (pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0')
+ result |= PW_GECOS;
+ else if ((pwd->pw_fields & _PWF_GECOS) != 0)
+ result |= PW_GECOS;
+// else
+// printf("No pw_gecos\n");
+
+ if (pwd->pw_dir != NULL && pwd->pw_dir[0] != '\0')
+ result |= PW_DIR;
+ else if ((pwd->pw_fields & _PWF_DIR) != 0)
+ result |= PW_DIR;
+// else
+// printf("No pw_dir\n");
+
+ if (pwd->pw_shell != NULL && pwd->pw_shell[0] != '\0')
+ result |= PW_SHELL;
+ else if ((pwd->pw_fields & _PWF_SHELL) != 0)
+ result |= PW_SHELL;
+// else
+// printf("No pw_shell\n");
+
+ if (pwd->pw_expire != 0 || (pwd->pw_fields & _PWF_EXPIRE) != 0)
+ result |= PW_EXPIRE;
+// else
+// printf("No pw_expire\n");
+
+if (false && pwd->pw_fields != (int)result) {
+printf("fields=0x%x != result=0x%x\n", (const unsigned int)pwd->pw_fields, result);
+printf(" fields result\n");
+printf("PW_NAME %d %d\n", (pwd->pw_fields & PW_NAME) != 0, (result & PW_NAME) != 0);
+printf("PW_PASSWD %d %d\n", (pwd->pw_fields & PW_PASSWD) != 0, (result & PW_PASSWD) != 0);
+printf("PW_UID %d %d\n", (pwd->pw_fields & PW_UID) != 0, (result & PW_UID) != 0);
+printf("PW_GID %d %d\n", (pwd->pw_fields & PW_GID) != 0, (result & PW_GID) != 0);
+printf("PW_CHANGE %d %d\n", (pwd->pw_fields & PW_CHANGE) != 0, (result & PW_CHANGE) != 0);
+printf("PW_CLASS %d %d\n", (pwd->pw_fields & PW_CLASS) != 0, (result & PW_CLASS) != 0);
+printf("PW_GECOS %d %d\n", (pwd->pw_fields & PW_GECOS) != 0, (result & PW_GECOS) != 0);
+printf("PW_DIR %d %d\n", (pwd->pw_fields & PW_DIR) != 0, (result & PW_DIR) != 0);
+printf("PW_SHELL %d %d\n", (pwd->pw_fields & PW_SHELL) != 0, (result & PW_SHELL) != 0);
+printf("PW_EXPIRE %d %d\n", (pwd->pw_fields & PW_EXPIRE) != 0, (result & PW_EXPIRE) != 0);
+}
+
+//printf("result=0x%x\n", result);
+ return (result);
+}
+
+static bool
+runtest_fields(cap_channel_t *cappwd, unsigned int expected)
+{
+ char buf[1024];
+ struct passwd *pwd;
+ struct passwd st;
+
+//printf("expected=0x%x\n", expected);
+ cap_setpwent(cappwd);
+ pwd = cap_getpwent(cappwd);
+ if ((passwd_fields(pwd) & ~expected) != 0)
+ return (false);
+
+ cap_setpwent(cappwd);
+ cap_getpwent_r(cappwd, &st, buf, sizeof(buf), &pwd);
+ if ((passwd_fields(pwd) & ~expected) != 0)
+ return (false);
+
+ pwd = cap_getpwnam(cappwd, "root");
+ if ((passwd_fields(pwd) & ~expected) != 0)
+ return (false);
+
+ cap_getpwnam_r(cappwd, "root", &st, buf, sizeof(buf), &pwd);
+ if ((passwd_fields(pwd) & ~expected) != 0)
+ return (false);
+
+ pwd = cap_getpwuid(cappwd, UID_ROOT);
+ if ((passwd_fields(pwd) & ~expected) != 0)
+ return (false);
+
+ cap_getpwuid_r(cappwd, UID_ROOT, &st, buf, sizeof(buf), &pwd);
+ if ((passwd_fields(pwd) & ~expected) != 0)
+ return (false);
+
+ return (true);
+}
+
+static void
+test_fields(cap_channel_t *origcappwd)
+{
+ cap_channel_t *cappwd;
+ const char *fields[10];
+
+ /* No limits. */
+
+ CHECK(runtest_fields(origcappwd, PW_NAME | PW_PASSWD | PW_UID |
+ PW_GID | PW_CHANGE | PW_CLASS | PW_GECOS | PW_DIR | PW_SHELL |
+ PW_EXPIRE));
+
+ /*
+ * Allow:
+ * fields: pw_name, pw_passwd, pw_uid, pw_gid, pw_change, pw_class,
+ * pw_gecos, pw_dir, pw_shell, pw_expire
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_name";
+ fields[1] = "pw_passwd";
+ fields[2] = "pw_uid";
+ fields[3] = "pw_gid";
+ fields[4] = "pw_change";
+ fields[5] = "pw_class";
+ fields[6] = "pw_gecos";
+ fields[7] = "pw_dir";
+ fields[8] = "pw_shell";
+ fields[9] = "pw_expire";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
+
+ CHECK(runtest_fields(origcappwd, PW_NAME | PW_PASSWD | PW_UID |
+ PW_GID | PW_CHANGE | PW_CLASS | PW_GECOS | PW_DIR | PW_SHELL |
+ PW_EXPIRE));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * fields: pw_name, pw_passwd, pw_uid, pw_gid, pw_change
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_name";
+ fields[1] = "pw_passwd";
+ fields[2] = "pw_uid";
+ fields[3] = "pw_gid";
+ fields[4] = "pw_change";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
+ fields[5] = "pw_class";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "pw_class";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(cappwd, PW_NAME | PW_PASSWD | PW_UID |
+ PW_GID | PW_CHANGE));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * fields: pw_class, pw_gecos, pw_dir, pw_shell, pw_expire
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_class";
+ fields[1] = "pw_gecos";
+ fields[2] = "pw_dir";
+ fields[3] = "pw_shell";
+ fields[4] = "pw_expire";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
+ fields[5] = "pw_uid";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "pw_uid";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(cappwd, PW_CLASS | PW_GECOS | PW_DIR |
+ PW_SHELL | PW_EXPIRE));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * fields: pw_name, pw_uid, pw_change, pw_gecos, pw_shell
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_name";
+ fields[1] = "pw_uid";
+ fields[2] = "pw_change";
+ fields[3] = "pw_gecos";
+ fields[4] = "pw_shell";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
+ fields[5] = "pw_class";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "pw_class";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(cappwd, PW_NAME | PW_UID | PW_CHANGE |
+ PW_GECOS | PW_SHELL));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * fields: pw_passwd, pw_gid, pw_class, pw_dir, pw_expire
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_passwd";
+ fields[1] = "pw_gid";
+ fields[2] = "pw_class";
+ fields[3] = "pw_dir";
+ fields[4] = "pw_expire";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
+ fields[5] = "pw_uid";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "pw_uid";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(cappwd, PW_PASSWD | PW_GID | PW_CLASS |
+ PW_DIR | PW_EXPIRE));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * fields: pw_uid, pw_class, pw_shell
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_uid";
+ fields[1] = "pw_class";
+ fields[2] = "pw_shell";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 3) == 0);
+ fields[3] = "pw_change";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "pw_change";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(cappwd, PW_UID | PW_CLASS | PW_SHELL));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * fields: pw_change
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ fields[0] = "pw_change";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == 0);
+ fields[1] = "pw_uid";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ fields[0] = "pw_uid";
+ CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
+ errno == ENOTCAPABLE);
+
+ CHECK(runtest_fields(cappwd, PW_CHANGE));
+
+ cap_close(cappwd);
+}
+
+static bool
+runtest_users(cap_channel_t *cappwd, const char **names, const uid_t *uids,
+ size_t nusers)
+{
+ char buf[1024];
+ struct passwd *pwd;
+ struct passwd st;
+ unsigned int i, got;
+
+ cap_setpwent(cappwd);
+ got = 0;
+ for (;;) {
+ pwd = cap_getpwent(cappwd);
+ if (pwd == NULL)
+ break;
+ got++;
+ for (i = 0; i < nusers; i++) {
+ if (strcmp(names[i], pwd->pw_name) == 0 &&
+ uids[i] == pwd->pw_uid) {
+ break;
+ }
+ }
+ if (i == nusers)
+ return (false);
+ }
+ if (got != nusers)
+ return (false);
+
+ cap_setpwent(cappwd);
+ got = 0;
+ for (;;) {
+ cap_getpwent_r(cappwd, &st, buf, sizeof(buf), &pwd);
+ if (pwd == NULL)
+ break;
+ got++;
+ for (i = 0; i < nusers; i++) {
+ if (strcmp(names[i], pwd->pw_name) == 0 &&
+ uids[i] == pwd->pw_uid) {
+ break;
+ }
+ }
+ if (i == nusers)
+ return (false);
+ }
+ if (got != nusers)
+ return (false);
+
+ for (i = 0; i < nusers; i++) {
+ pwd = cap_getpwnam(cappwd, names[i]);
+ if (pwd == NULL)
+ return (false);
+ }
+
+ for (i = 0; i < nusers; i++) {
+ cap_getpwnam_r(cappwd, names[i], &st, buf, sizeof(buf), &pwd);
+ if (pwd == NULL)
+ return (false);
+ }
+
+ for (i = 0; i < nusers; i++) {
+ pwd = cap_getpwuid(cappwd, uids[i]);
+ if (pwd == NULL)
+ return (false);
+ }
+
+ for (i = 0; i < nusers; i++) {
+ cap_getpwuid_r(cappwd, uids[i], &st, buf, sizeof(buf), &pwd);
+ if (pwd == NULL)
+ return (false);
+ }
+
+ return (true);
+}
+
+static void
+test_users(cap_channel_t *origcappwd)
+{
+ cap_channel_t *cappwd;
+ const char *names[6];
+ uid_t uids[6];
+
+ /*
+ * Allow:
+ * users:
+ * names: root, toor, daemon, operator, bin, tty
+ * uids:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "root";
+ names[1] = "toor";
+ names[2] = "daemon";
+ names[3] = "operator";
+ names[4] = "bin";
+ names[5] = "tty";
+ CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
+ uids[0] = 0;
+ uids[1] = 0;
+ uids[2] = 1;
+ uids[3] = 2;
+ uids[4] = 3;
+ uids[5] = 4;
+
+ CHECK(runtest_users(cappwd, names, uids, 6));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names: daemon, operator, bin
+ * uids:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "daemon";
+ names[1] = "operator";
+ names[2] = "bin";
+ CHECK(cap_pwd_limit_users(cappwd, names, 3, NULL, 0) == 0);
+ names[3] = "tty";
+ CHECK(cap_pwd_limit_users(cappwd, names, 4, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "tty";
+ CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ uids[0] = 1;
+ uids[1] = 2;
+ uids[2] = 3;
+
+ CHECK(runtest_users(cappwd, names, uids, 3));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names: daemon, bin, tty
+ * uids:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "daemon";
+ names[1] = "bin";
+ names[2] = "tty";
+ CHECK(cap_pwd_limit_users(cappwd, names, 3, NULL, 0) == 0);
+ names[3] = "operator";
+ CHECK(cap_pwd_limit_users(cappwd, names, 4, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "operator";
+ CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ uids[0] = 1;
+ uids[1] = 3;
+ uids[2] = 4;
+
+ CHECK(runtest_users(cappwd, names, uids, 3));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names:
+ * uids: 1, 2, 3
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "daemon";
+ names[1] = "operator";
+ names[2] = "bin";
+ uids[0] = 1;
+ uids[1] = 2;
+ uids[2] = 3;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 3) == 0);
+ uids[3] = 4;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 4;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 1;
+
+ CHECK(runtest_users(cappwd, names, uids, 3));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names:
+ * uids: 1, 3, 4
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "daemon";
+ names[1] = "bin";
+ names[2] = "tty";
+ uids[0] = 1;
+ uids[1] = 3;
+ uids[2] = 4;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 3) == 0);
+ uids[3] = 5;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 4) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 5;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 1;
+
+ CHECK(runtest_users(cappwd, names, uids, 3));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names: bin
+ * uids:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "bin";
+ CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == 0);
+ names[1] = "operator";
+ CHECK(cap_pwd_limit_users(cappwd, names, 2, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "operator";
+ CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "bin";
+ uids[0] = 3;
+
+ CHECK(runtest_users(cappwd, names, uids, 1));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names: daemon, tty
+ * uids:
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "daemon";
+ names[1] = "tty";
+ CHECK(cap_pwd_limit_users(cappwd, names, 2, NULL, 0) == 0);
+ names[2] = "operator";
+ CHECK(cap_pwd_limit_users(cappwd, names, 3, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "operator";
+ CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
+ errno == ENOTCAPABLE);
+ names[0] = "daemon";
+ uids[0] = 1;
+ uids[1] = 4;
+
+ CHECK(runtest_users(cappwd, names, uids, 2));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names:
+ * uids: 3
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "bin";
+ uids[0] = 3;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == 0);
+ uids[1] = 4;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 2) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 4;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 3;
+
+ CHECK(runtest_users(cappwd, names, uids, 1));
+
+ cap_close(cappwd);
+
+ /*
+ * Allow:
+ * users:
+ * names:
+ * uids: 1, 4
+ */
+ cappwd = cap_clone(origcappwd);
+ CHECK(cappwd != NULL);
+
+ names[0] = "daemon";
+ names[1] = "tty";
+ uids[0] = 1;
+ uids[1] = 4;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 2) == 0);
+ uids[2] = 3;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 3) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 3;
+ CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
+ errno == ENOTCAPABLE);
+ uids[0] = 1;
+
+ CHECK(runtest_users(cappwd, names, uids, 2));
+
+ cap_close(cappwd);
+}
+
+int
+main(void)
+{
+ cap_channel_t *capcas, *cappwd;
+
+ printf("1..186\n");
+
+ capcas = cap_init();
+ CHECKX(capcas != NULL);
+
+ cappwd = cap_service_open(capcas, "system.pwd");
+ CHECKX(cappwd != NULL);
+
+ cap_close(capcas);
+
+ /* No limits. */
+
+ CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R | GETPWNAM |
+ GETPWNAM_R | GETPWUID | GETPWUID_R));
+
+ test_cmds(cappwd);
+
+ test_fields(cappwd);
+
+ test_users(cappwd);
+
+ cap_close(cappwd);
+
+ exit(0);
+}
diff --git a/tools/regression/capsicum/libcapsicum/sysctl.c b/tools/regression/capsicum/libcapsicum/sysctl.c
new file mode 100644
index 000000000000..14c735f0e767
--- /dev/null
+++ b/tools/regression/capsicum/libcapsicum/sysctl.c
@@ -0,0 +1,1509 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcapsicum.h>
+#include <libcapsicum_service.h>
+#include <libcapsicum_sysctl.h>
+#include <nv.h>
+
+/*
+ * We need some sysctls to perform the tests on.
+ * We remember their values and restore them afer the test is done.
+ */
+#define SYSCTL0_PARENT "kern"
+#define SYSCTL0_NAME "kern.sync_on_panic"
+#define SYSCTL1_PARENT "debug"
+#define SYSCTL1_NAME "debug.minidump"
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ ntest++; \
+} while (0)
+#define CHECKX(expr) do { \
+ if ((expr)) { \
+ printf("ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ } else { \
+ printf("not ok %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ exit(1); \
+ } \
+} while (0)
+
+#define SYSCTL0_READ0 0x0001
+#define SYSCTL0_READ1 0x0002
+#define SYSCTL0_READ2 0x0004
+#define SYSCTL0_WRITE 0x0008
+#define SYSCTL0_READ_WRITE 0x0010
+#define SYSCTL1_READ0 0x0020
+#define SYSCTL1_READ1 0x0040
+#define SYSCTL1_READ2 0x0080
+#define SYSCTL1_WRITE 0x0100
+#define SYSCTL1_READ_WRITE 0x0200
+
+static unsigned int
+runtest(cap_channel_t *capsysctl)
+{
+ unsigned int result;
+ int oldvalue, newvalue;
+ size_t oldsize;
+
+ result = 0;
+
+ oldsize = sizeof(oldvalue);
+ if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, &oldvalue, &oldsize,
+ NULL, 0) == 0) {
+ if (oldsize == sizeof(oldvalue))
+ result |= SYSCTL0_READ0;
+ }
+
+ newvalue = 123;
+ if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, NULL, NULL, &newvalue,
+ sizeof(newvalue)) == 0) {
+ result |= SYSCTL0_WRITE;
+ }
+
+ if ((result & SYSCTL0_WRITE) != 0) {
+ oldsize = sizeof(oldvalue);
+ if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, &oldvalue,
+ &oldsize, NULL, 0) == 0) {
+ if (oldsize == sizeof(oldvalue) && oldvalue == 123)
+ result |= SYSCTL0_READ1;
+ }
+ }
+
+ oldsize = sizeof(oldvalue);
+ newvalue = 4567;
+ if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, &oldvalue, &oldsize,
+ &newvalue, sizeof(newvalue)) == 0) {
+ if (oldsize == sizeof(oldvalue) && oldvalue == 123)
+ result |= SYSCTL0_READ_WRITE;
+ }
+
+ if ((result & SYSCTL0_READ_WRITE) != 0) {
+ oldsize = sizeof(oldvalue);
+ if (cap_sysctlbyname(capsysctl, SYSCTL0_NAME, &oldvalue,
+ &oldsize, NULL, 0) == 0) {
+ if (oldsize == sizeof(oldvalue) && oldvalue == 4567)
+ result |= SYSCTL0_READ2;
+ }
+ }
+
+ oldsize = sizeof(oldvalue);
+ if (cap_sysctlbyname(capsysctl, SYSCTL1_NAME, &oldvalue, &oldsize,
+ NULL, 0) == 0) {
+ if (oldsize == sizeof(oldvalue))
+ result |= SYSCTL1_READ0;
+ }
+
+ newvalue = 506;
+ if (cap_sysctlbyname(capsysctl, SYSCTL1_NAME, NULL, NULL, &newvalue,
+ sizeof(newvalue)) == 0) {
+ result |= SYSCTL1_WRITE;
+ }
+
+ if ((result & SYSCTL1_WRITE) != 0) {
+ oldsize = sizeof(oldvalue);
+ if (cap_sysctlbyname(capsysctl, SYSCTL1_NAME, &oldvalue,
+ &oldsize, NULL, 0) == 0) {
+ if (oldsize == sizeof(oldvalue) && oldvalue == 506)
+ result |= SYSCTL1_READ1;
+ }
+ }
+
+ oldsize = sizeof(oldvalue);
+ newvalue = 7008;
+ if (cap_sysctlbyname(capsysctl, SYSCTL1_NAME, &oldvalue, &oldsize,
+ &newvalue, sizeof(newvalue)) == 0) {
+ if (oldsize == sizeof(oldvalue) && oldvalue == 506)
+ result |= SYSCTL1_READ_WRITE;
+ }
+
+ if ((result & SYSCTL1_READ_WRITE) != 0) {
+ oldsize = sizeof(oldvalue);
+ if (cap_sysctlbyname(capsysctl, SYSCTL1_NAME, &oldvalue,
+ &oldsize, NULL, 0) == 0) {
+ if (oldsize == sizeof(oldvalue) && oldvalue == 7008)
+ result |= SYSCTL1_READ2;
+ }
+ }
+
+ return (result);
+}
+
+static void
+test_operation(cap_channel_t *origcapsysctl)
+{
+ cap_channel_t *capsysctl;
+ nvlist_t *limits;
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/RDWR/RECURSIVE
+ * SYSCTL1_PARENT/RDWR/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, "foo.bar",
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, "foo.bar",
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE |
+ SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE |
+ SYSCTL1_READ_WRITE));
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE |
+ SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE |
+ SYSCTL1_READ_WRITE));
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE));
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE));
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == SYSCTL0_READ0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/RDWR/RECURSIVE
+ * SYSCTL1_NAME/RDWR/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE |
+ SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE |
+ SYSCTL1_READ_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/RDWR
+ * SYSCTL1_PARENT/RDWR
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/RDWR
+ * SYSCTL1_NAME/RDWR
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE |
+ SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE |
+ SYSCTL1_READ_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/RDWR
+ * SYSCTL1_PARENT/RDWR/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL1_READ0 | SYSCTL1_READ1 |
+ SYSCTL1_READ2 | SYSCTL1_WRITE | SYSCTL1_READ_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/RDWR
+ * SYSCTL1_NAME/RDWR/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE |
+ SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE |
+ SYSCTL1_READ_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ/RECURSIVE
+ * SYSCTL1_PARENT/READ/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_READ0));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/READ/RECURSIVE
+ * SYSCTL1_NAME/READ/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_READ0));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ
+ * SYSCTL1_PARENT/READ
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/READ
+ * SYSCTL1_NAME/READ
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_READ0));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ
+ * SYSCTL1_PARENT/READ/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_READ0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/READ
+ * SYSCTL1_NAME/READ/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_READ0));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/WRITE/RECURSIVE
+ * SYSCTL1_PARENT/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_WRITE | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/WRITE/RECURSIVE
+ * SYSCTL1_NAME/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_WRITE | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/WRITE
+ * SYSCTL1_PARENT/WRITE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/WRITE
+ * SYSCTL1_NAME/WRITE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_WRITE | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/WRITE
+ * SYSCTL1_PARENT/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_WRITE);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/WRITE
+ * SYSCTL1_NAME/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_WRITE | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ/RECURSIVE
+ * SYSCTL1_PARENT/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/READ/RECURSIVE
+ * SYSCTL1_NAME/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ
+ * SYSCTL1_PARENT/WRITE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/READ
+ * SYSCTL1_NAME/WRITE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ
+ * SYSCTL1_PARENT/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_WRITE);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_NAME/READ
+ * SYSCTL1_NAME/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL1_WRITE));
+
+ cap_close(capsysctl);
+}
+
+static void
+test_names(cap_channel_t *origcapsysctl)
+{
+ cap_channel_t *capsysctl;
+ nvlist_t *limits;
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL0_READ0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL1_NAME/READ/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_READ | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_READ0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL0_WRITE);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL1_NAME/WRITE/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_WRITE | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_WRITE);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/RDWR/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL1_NAME/RDWR/RECURSIVE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ nvlist_add_number(limits, SYSCTL1_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME,
+ CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL1_READ0 | SYSCTL1_READ1 |
+ SYSCTL1_READ2 | SYSCTL1_WRITE | SYSCTL1_READ_WRITE));
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/READ
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL1_NAME/READ
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_READ);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_READ0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/WRITE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL1_NAME/WRITE
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_WRITE);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == SYSCTL1_WRITE);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL0_PARENT/RDWR
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_PARENT, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_PARENT, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == 0);
+
+ cap_close(capsysctl);
+
+ /*
+ * Allow:
+ * SYSCTL1_NAME/RDWR
+ */
+
+ capsysctl = cap_clone(origcapsysctl);
+ CHECK(capsysctl != NULL);
+
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == 0);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ nvlist_add_number(limits, SYSCTL1_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+ limits = nvlist_create(0);
+ nvlist_add_number(limits, SYSCTL0_NAME, CAP_SYSCTL_RDWR);
+ CHECK(cap_limit_set(capsysctl, limits) == -1 && errno == ENOTCAPABLE);
+
+ CHECK(runtest(capsysctl) == (SYSCTL1_READ0 | SYSCTL1_READ1 |
+ SYSCTL1_READ2 | SYSCTL1_WRITE | SYSCTL1_READ_WRITE));
+
+ cap_close(capsysctl);
+}
+
+int
+main(void)
+{
+ cap_channel_t *capcas, *capsysctl;
+ int scvalue0, scvalue1;
+ size_t scsize;
+
+ printf("1..250\n");
+
+ scsize = sizeof(scvalue0);
+ CHECKX(sysctlbyname(SYSCTL0_NAME, &scvalue0, &scsize, NULL, 0) == 0);
+ CHECKX(scsize == sizeof(scvalue0));
+ scsize = sizeof(scvalue1);
+ CHECKX(sysctlbyname(SYSCTL1_NAME, &scvalue1, &scsize, NULL, 0) == 0);
+ CHECKX(scsize == sizeof(scvalue1));
+
+ capcas = cap_init();
+ CHECKX(capcas != NULL);
+
+ capsysctl = cap_service_open(capcas, "system.sysctl");
+ CHECKX(capsysctl != NULL);
+
+ cap_close(capcas);
+
+ /* No limits set. */
+
+ CHECK(runtest(capsysctl) == (SYSCTL0_READ0 | SYSCTL0_READ1 |
+ SYSCTL0_READ2 | SYSCTL0_WRITE | SYSCTL0_READ_WRITE |
+ SYSCTL1_READ0 | SYSCTL1_READ1 | SYSCTL1_READ2 | SYSCTL1_WRITE |
+ SYSCTL1_READ_WRITE));
+
+ test_operation(capsysctl);
+
+ test_names(capsysctl);
+
+ cap_close(capsysctl);
+
+ CHECK(sysctlbyname(SYSCTL0_NAME, NULL, NULL, &scvalue0,
+ sizeof(scvalue0)) == 0);
+ CHECK(sysctlbyname(SYSCTL1_NAME, NULL, NULL, &scvalue1,
+ sizeof(scvalue1)) == 0);
+
+ exit(0);
+}