summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorray <ray@FreeBSD.org>2013-12-05 00:57:53 +0000
committerray <ray@FreeBSD.org>2013-12-05 00:57:53 +0000
commit1af064917e022f18acbf9fc2942cd40f1b26fbe5 (patch)
treeef10954b063bcd6939eabdcc7ecba95432634f70 /tools
parent40d47a9dd8116c90080a010ab3483d8917bd0524 (diff)
parent6e411c7e1916ef76b0aa51ded38fa235d3313371 (diff)
downloadFreeBSD-src-1af064917e022f18acbf9fc2942cd40f1b26fbe5.zip
FreeBSD-src-1af064917e022f18acbf9fc2942cd40f1b26fbe5.tar.gz
MFC @r258947.
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'tools')
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc5
-rw-r--r--tools/build/options/WITHOUT_CASPER2
-rw-r--r--tools/build/options/WITHOUT_PKGBOOTSTRAP2
-rw-r--r--tools/regression/bin/sh/execution/bg10.04
-rw-r--r--tools/regression/bin/sh/execution/bg10.0.stdout1
-rw-r--r--tools/regression/bin/sh/execution/bg5.04
-rw-r--r--tools/regression/bin/sh/execution/bg6.04
-rw-r--r--tools/regression/bin/sh/execution/bg6.0.stdout1
-rw-r--r--tools/regression/bin/sh/execution/bg7.05
-rw-r--r--tools/regression/bin/sh/execution/bg8.05
-rw-r--r--tools/regression/bin/sh/execution/bg9.05
-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
-rw-r--r--tools/regression/fsx/fsx.c107
-rwxr-xr-xtools/regression/usr.sbin/etcupdate/fbsdid.sh48
-rw-r--r--tools/test/dtrace/Makefile5
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.sh2
-rw-r--r--tools/tools/cxgbetool/Makefile2
-rw-r--r--tools/tools/cxgbetool/cxgbetool.c133
-rw-r--r--tools/tools/nanobsd/nanobsd.sh82
-rw-r--r--tools/tools/umastat/umastat.c26
-rw-r--r--tools/tools/zfsboottest/Makefile2
25 files changed, 5615 insertions, 41 deletions
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 8cee751..3bb942b 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -4056,7 +4056,10 @@ OLD_FILES+=usr/share/man/man1/telnet.1.gz
OLD_FILES+=usr/share/man/man8/telnetd.8.gz
.endif
-.if ${MK_TESTS} == no
+.if ${MK_TESTS} == yes
+OLD_FILES+=usr/tests/lib/atf/libatf-c/test_helpers_test
+OLD_FILES+=usr/tests/lib/atf/test-programs/fork_test
+.else
# ATF libraries.
OLD_FILES+=usr/bin/atf-sh
OLD_DIRS+=usr/include/atf-c
diff --git a/tools/build/options/WITHOUT_CASPER b/tools/build/options/WITHOUT_CASPER
new file mode 100644
index 0000000..d364305
--- /dev/null
+++ b/tools/build/options/WITHOUT_CASPER
@@ -0,0 +1,2 @@
+.\" $FreeBSD$
+Set to not build Casper program and related libraries.
diff --git a/tools/build/options/WITHOUT_PKGBOOTSTRAP b/tools/build/options/WITHOUT_PKGBOOTSTRAP
index b3d857f..121209b 100644
--- a/tools/build/options/WITHOUT_PKGBOOTSTRAP
+++ b/tools/build/options/WITHOUT_PKGBOOTSTRAP
@@ -1,4 +1,4 @@
.\" $FreeBSD$
Set to not build
.Xr pkg 7
-bootstrap tool
+bootstrap tool.
diff --git a/tools/regression/bin/sh/execution/bg10.0 b/tools/regression/bin/sh/execution/bg10.0
new file mode 100644
index 0000000..44a25dc
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg10.0
@@ -0,0 +1,4 @@
+# $FreeBSD$
+# The redirection overrides the </dev/null implicit in a background command.
+
+echo yes | ${SH} -c '{ cat & wait; } <&0'
diff --git a/tools/regression/bin/sh/execution/bg10.0.stdout b/tools/regression/bin/sh/execution/bg10.0.stdout
new file mode 100644
index 0000000..7cfab5b
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg10.0.stdout
@@ -0,0 +1 @@
+yes
diff --git a/tools/regression/bin/sh/execution/bg5.0 b/tools/regression/bin/sh/execution/bg5.0
new file mode 100644
index 0000000..cc9ceaa
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg5.0
@@ -0,0 +1,4 @@
+# $FreeBSD$
+# A background command has an implicit </dev/null redirection.
+
+echo bad | ${SH} -c '{ cat & wait; }'
diff --git a/tools/regression/bin/sh/execution/bg6.0 b/tools/regression/bin/sh/execution/bg6.0
new file mode 100644
index 0000000..b0faf9e
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg6.0
@@ -0,0 +1,4 @@
+# $FreeBSD$
+# The redirection overrides the </dev/null implicit in a background command.
+
+echo yes | ${SH} -c '{ cat & wait; } </dev/stdin'
diff --git a/tools/regression/bin/sh/execution/bg6.0.stdout b/tools/regression/bin/sh/execution/bg6.0.stdout
new file mode 100644
index 0000000..7cfab5b
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg6.0.stdout
@@ -0,0 +1 @@
+yes
diff --git a/tools/regression/bin/sh/execution/bg7.0 b/tools/regression/bin/sh/execution/bg7.0
new file mode 100644
index 0000000..f771edc
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg7.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c '</dev/null; { cat & wait; }'
diff --git a/tools/regression/bin/sh/execution/bg8.0 b/tools/regression/bin/sh/execution/bg8.0
new file mode 100644
index 0000000..33667cb
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg8.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c 'command eval \) </dev/null 2>/dev/null; { cat & wait; }'
diff --git a/tools/regression/bin/sh/execution/bg9.0 b/tools/regression/bin/sh/execution/bg9.0
new file mode 100644
index 0000000..64fde3e
--- /dev/null
+++ b/tools/regression/bin/sh/execution/bg9.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c 'command eval eval \\\) \</dev/null 2>/dev/null; { cat & wait; }'
diff --git a/tools/regression/capsicum/libcapsicum/Makefile b/tools/regression/capsicum/libcapsicum/Makefile
new file mode 100644
index 0000000..6fc98ba
--- /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 0000000..bb7f613
--- /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 0000000..1d3adfb
--- /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 0000000..161885d
--- /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 0000000..14c735f
--- /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);
+}
diff --git a/tools/regression/fsx/fsx.c b/tools/regression/fsx/fsx.c
index cee7d90..5e9b451 100644
--- a/tools/regression/fsx/fsx.c
+++ b/tools/regression/fsx/fsx.c
@@ -90,6 +90,7 @@ int logcount = 0; /* total ops */
#define OP_MAPREAD 5
#define OP_MAPWRITE 6
#define OP_SKIPPED 7
+#define OP_INVALIDATE 8
int page_size;
int page_mask;
@@ -107,6 +108,7 @@ unsigned long testcalls = 0; /* calls to function "test" */
unsigned long simulatedopcount = 0; /* -b flag */
int closeprob = 0; /* -c flag */
+int invlprob = 0; /* -i flag */
int debug = 0; /* -d flag */
unsigned long debugstart = 0; /* -D flag */
unsigned long maxfilelen = 256 * 1024; /* -l flag */
@@ -126,10 +128,12 @@ int randomoplen = 1; /* -O flag disables it */
int seed = 1; /* -S flag */
int mapped_writes = 1; /* -W flag disables */
int mapped_reads = 1; /* -R flag disables it */
+int mapped_msync = 1; /* -U flag disables */
int fsxgoodfd = 0;
FILE * fsxlogf = NULL;
int badoff = -1;
int closeopen = 0;
+int invl = 0;
void
@@ -181,14 +185,12 @@ prterr(char *prefix)
void
-log4(int operation, int arg0, int arg1, int arg2)
+do_log4(int operation, int arg0, int arg1, int arg2)
{
struct log_entry *le;
le = &oplog[logptr];
le->operation = operation;
- if (closeopen)
- le->operation = ~ le->operation;
le->args[0] = arg0;
le->args[1] = arg1;
le->args[2] = arg2;
@@ -200,10 +202,21 @@ log4(int operation, int arg0, int arg1, int arg2)
void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+ do_log4(operation, arg0, arg1, arg2);
+ if (closeopen)
+ do_log4(OP_CLOSEOPEN, 0, 0, 0);
+ if (invl)
+ do_log4(OP_INVALIDATE, 0, 0, 0);
+}
+
+
+void
logdump(void)
{
- int i, count, down;
struct log_entry *lp;
+ int i, count, down, opnum;
prt("LOG DUMP (%d total operations):\n", logcount);
if (logcount < LOGSIZE) {
@@ -213,15 +226,28 @@ logdump(void)
i = logptr;
count = LOGSIZE;
}
+
+ opnum = i + 1 + (logcount/LOGSIZE)*LOGSIZE;
for ( ; count > 0; count--) {
- int opnum;
+ lp = &oplog[i];
+
+ if (lp->operation == OP_CLOSEOPEN ||
+ lp->operation == OP_INVALIDATE) {
+ switch (lp->operation) {
+ case OP_CLOSEOPEN:
+ prt("\t\tCLOSE/OPEN\n");
+ break;
+ case OP_INVALIDATE:
+ prt("\t\tMS_INVALIDATE\n");
+ break;
+ }
+ i++;
+ if (i == LOGSIZE)
+ i = 0;
+ continue;
+ }
- opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
prt("%d(%d mod 256): ", opnum, opnum%256);
- lp = &oplog[i];
- if ((closeopen = lp->operation < 0))
- lp->operation = ~ lp->operation;
-
switch (lp->operation) {
case OP_MAPREAD:
prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
@@ -274,9 +300,8 @@ logdump(void)
prt("BOGUS LOG ENTRY (operation code = %d)!",
lp->operation);
}
- if (closeopen)
- prt("\n\t\tCLOSE/OPEN");
prt("\n");
+ opnum++;
i++;
if (i == LOGSIZE)
i = 0;
@@ -679,12 +704,12 @@ domapwrite(unsigned offset, unsigned size)
if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd,
- (off_t)(offset - pg_offset))) == (char *)-1) {
+ (off_t)(offset - pg_offset))) == MAP_FAILED) {
prterr("domapwrite: mmap");
report_failure(202);
}
memcpy(p + pg_offset, good_buf + offset, size);
- if (msync(p, map_size, 0) != 0) {
+ if (mapped_msync && msync(p, map_size, MS_SYNC) != 0) {
prterr("domapwrite: msync");
report_failure(203);
}
@@ -778,6 +803,36 @@ docloseopen(void)
void
+doinvl(void)
+{
+ char *p;
+
+ if (file_size == 0)
+ return;
+ if (testcalls <= simulatedopcount)
+ return;
+ if (debug)
+ prt("%lu msync(MS_INVALIDATE)\n", testcalls);
+
+ if ((p = (char *)mmap(0, file_size, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ prterr("doinvl: mmap");
+ report_failure(205);
+ }
+
+ if (msync(p, 0, MS_SYNC | MS_INVALIDATE) != 0) {
+ prterr("doinvl: msync");
+ report_failure(206);
+ }
+
+ if (munmap(p, file_size) != 0) {
+ prterr("doinvl: munmap");
+ report_failure(207);
+ }
+}
+
+
+void
test(void)
{
unsigned long offset;
@@ -797,6 +852,8 @@ test(void)
if (closeprob)
closeopen = (rv >> 3) < (1 << 28) / closeprob;
+ if (invlprob)
+ invl = (rv >> 3) < (1 << 28) / invlprob;
if (debugstart > 0 && testcalls >= debugstart)
debug = 1;
@@ -844,6 +901,8 @@ test(void)
}
if (sizechecks && testcalls > simulatedopcount)
check_size();
+ if (invl)
+ doinvl();
if (closeopen)
docloseopen();
}
@@ -868,6 +927,7 @@ usage(void)
-b opnum: beginning operation number (default 1)\n\
-c P: 1 in P chance of file close+open at each op (default infinity)\n\
-d: debug output for all operations\n\
+ -i P: 1 in P chance of calling msync(MS_INVALIDATE) (default infinity)\n\
-l flen: the upper bound on file size (default 262144)\n\
-m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
-n: no verifications of file size\n\
@@ -886,6 +946,7 @@ usage(void)
-S seed: for random # generator (default 1) 0 gets timestamp\n\
-W: mapped write operations DISabled\n\
-R: mapped read operations DISabled)\n\
+ -U: msync after mapped write operations DISabled\n\
fname: this filename is REQUIRED (no default)\n");
exit(90);
}
@@ -941,8 +1002,8 @@ main(int argc, char **argv)
setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
- while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W"))
- != -1)
+ while ((ch = getopt(argc, argv,
+ "b:c:di:l:m:no:p:qr:s:t:w:D:LN:OP:RS:UW")) != -1)
switch (ch) {
case 'b':
simulatedopcount = getnum(optarg, &endp);
@@ -965,6 +1026,15 @@ main(int argc, char **argv)
case 'd':
debug = 1;
break;
+ case 'i':
+ invlprob = getnum(optarg, &endp);
+ if (!quiet)
+ fprintf(stdout,
+ "Chance of MS_INVALIDATE is 1 in %d\n",
+ invlprob);
+ if (invlprob <= 0)
+ usage();
+ break;
case 'l':
maxfilelen = getnum(optarg, &endp);
if (maxfilelen <= 0)
@@ -1057,6 +1127,11 @@ main(int argc, char **argv)
if (!quiet)
fprintf(stdout, "mapped writes DISABLED\n");
break;
+ case 'U':
+ mapped_msync = 0;
+ if (!quiet)
+ fprintf(stdout, "mapped msync DISABLED\n");
+ break;
default:
usage();
diff --git a/tools/regression/usr.sbin/etcupdate/fbsdid.sh b/tools/regression/usr.sbin/etcupdate/fbsdid.sh
index 07df248..e713c35 100755
--- a/tools/regression/usr.sbin/etcupdate/fbsdid.sh
+++ b/tools/regression/usr.sbin/etcupdate/fbsdid.sh
@@ -195,6 +195,17 @@ EOF
these are some local mods to the file
EOF
+
+ # local-remove: A file removed locally changed it's FreeBSD ID
+ # but nothing else
+ store_id $OLD/local-remove ": head/local-remove 12000 jhb "
+ store_id $NEW/local-remove ": head/local-remove 12345 jhb "
+ for i in $OLD $NEW; do
+ cat >> $i/local-remove <<EOF
+
+this is a file
+EOF
+ done
}
# $1 - relative path to file that should be missing from TEST
@@ -282,6 +293,7 @@ cat > $WORKDIR/correct.out <<EOF
C /add
Warnings:
Modified regular file remains: /remove
+ Removed file changed: /local-remove
EOF
echo "Differences for regular:"
@@ -299,6 +311,7 @@ conflict /conflict 868452f666fea1c60ffb918ad9ad9607
file /local "" aa33e614b5e749449f230e2a2b0072eb
conflict /local 3df93e64043c8e348fc625b93ea220f4
file /local-already "" 0298b958a603049f45ae6a109c4f7fea
+missing /local-remove
# Now test with -F.
@@ -329,3 +342,38 @@ file /conflict "" dc27978df125b0daeb7d9b93265f03fd
conflict /conflict 868452f666fea1c60ffb918ad9ad9607
file /local "" 3ed5a35e380c8a93fb5f599d4c052713
file /local-already "" 0298b958a603049f45ae6a109c4f7fea
+missing /local-remove
+
+# Now test with -F and -A forcing all installs. (-A should have
+# precedence over -F)
+
+build_trees
+
+$COMMAND -A '/*' -rF -d $WORKDIR -D $TEST > $WORKDIR/testAF.out
+
+cat > $WORKDIR/correctAF.out <<EOF
+ D /remove
+ U /already
+ U /conflict
+ U /local
+ U /local-already
+ A /local-remove
+ U /old
+ U /add
+EOF
+
+echo "Differences for -A '/*' -F:"
+diff -u -L "correct" $WORKDIR/correctAF.out -L "test" $WORKDIR/testAF.out
+
+missing /remove
+file /old "" 6a9f34f109d94406a4de3bc5d72de259
+noconflict /old
+file /already "" 21f4eca3aacc702c49878c8da7afd3d0
+noconflict /already
+file /add "" 0208bd647111fedf6318511712ab9e97
+noconflict /add
+file /conflict "" 75ee141c4136beaf14e39de92efa84e4
+noconflict /conflict
+file /local "" 6a8fc5c2755b7a49015089f5e1dbe092
+file /local-already "" 49045f8b51542dd634655301cd296f66
+file /local-remove "" 5c38322efed4014797d7127f5c652d9d
diff --git a/tools/test/dtrace/Makefile b/tools/test/dtrace/Makefile
index c9e9a20..fc8af34 100644
--- a/tools/test/dtrace/Makefile
+++ b/tools/test/dtrace/Makefile
@@ -59,7 +59,6 @@ IGNORE= \
${TESTSRCDIR}/tst/common/proc/tst.discard.ksh \
${TESTSRCDIR}/tst/common/proc/tst.signal.ksh \
${TESTSRCDIR}/tst/common/proc/tst.startexit.ksh \
- ${TESTSRCDIR}/tst/common/profile-n/tst.ufuncsort.c \
${TESTSRCDIR}/tst/common/scalars/tst.misc.d \
${TESTSRCDIR}/tst/common/scalars/tst.selfarray2.d \
${TESTSRCDIR}/tst/common/sysevent/tst.post.c \
@@ -115,10 +114,6 @@ NOTWORK+= \
${TESTSRCDIR}/tst/common/profile-n/tst.func.ksh \
${TESTSRCDIR}/tst/common/profile-n/tst.mod.ksh \
${TESTSRCDIR}/tst/common/profile-n/tst.sym.ksh \
- ${TESTSRCDIR}/tst/common/profile-n/tst.ufunc.ksh \
- ${TESTSRCDIR}/tst/common/profile-n/tst.ufuncsort.ksh \
- ${TESTSRCDIR}/tst/common/profile-n/tst.umod.ksh \
- ${TESTSRCDIR}/tst/common/profile-n/tst.usym.ksh \
${TESTSRCDIR}/tst/common/safety/tst.basename.d \
${TESTSRCDIR}/tst/common/safety/tst.caller.d \
${TESTSRCDIR}/tst/common/safety/tst.cleanpath.d \
diff --git a/tools/tools/bus_autoconf/bus_autoconf.sh b/tools/tools/bus_autoconf/bus_autoconf.sh
index c99df91..68d15f8 100644
--- a/tools/tools/bus_autoconf/bus_autoconf.sh
+++ b/tools/tools/bus_autoconf/bus_autoconf.sh
@@ -34,7 +34,7 @@ cat <<EOF
#
# ${DOLLAR}${OS}${DOLLAR}
#
-# This file was automatically generated by "tools/bus_autoconf.sh".
+# This file was automatically generated by "tools/tools/bus_autoconf/bus_autoconf.sh".
# Please do not edit!
#
diff --git a/tools/tools/cxgbetool/Makefile b/tools/tools/cxgbetool/Makefile
index dc2beda..21f1283 100644
--- a/tools/tools/cxgbetool/Makefile
+++ b/tools/tools/cxgbetool/Makefile
@@ -3,7 +3,7 @@
PROG= cxgbetool
SRCS= cxgbetool.c
NO_MAN=
-CFLAGS+= -I${.CURDIR}/../../../sys/dev/cxgbe -I.
+CFLAGS+= -I${.CURDIR}/../../../sys/dev/cxgbe -I${.CURDIR}/../../../sys -I.
BINDIR?= /usr/sbin
.include <bsd.prog.mk>
diff --git a/tools/tools/cxgbetool/cxgbetool.c b/tools/tools/cxgbetool/cxgbetool.c
index e5704e7..071942c 100644
--- a/tools/tools/cxgbetool/cxgbetool.c
+++ b/tools/tools/cxgbetool/cxgbetool.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <net/ethernet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <net/sff8472.h>
#include "t4_ioctl.h"
@@ -94,6 +95,7 @@ usage(FILE *fp)
"\ti2c <port> <devaddr> <addr> [<len>] read from i2c device\n"
"\tloadfw <fw-image.bin> install firmware\n"
"\tmemdump <addr> <len> dump a memory range\n"
+ "\tmodinfo <port> optics/cable information\n"
"\treg <address>[=<val>] read/write register\n"
"\treg64 <address>[=<val>] read/write 64 bit register\n"
"\tregdump [<module>] ... dump registers\n"
@@ -1828,6 +1830,135 @@ set_tracer(uint8_t idx, int argc, const char *argv[])
}
static int
+modinfo(int argc, const char *argv[])
+{
+ long port;
+ char string[16], *p;
+ struct t4_i2c_data i2cd;
+ int rc, i;
+ uint16_t temp, vcc, tx_bias, tx_power, rx_power;
+
+ if (argc != 1) {
+ warnx("must supply a port");
+ return (EINVAL);
+ }
+
+ p = str_to_number(argv[0], &port, NULL);
+ if (*p || port > UCHAR_MAX) {
+ warnx("invalid port id \"%s\"", argv[0]);
+ return (EINVAL);
+ }
+
+ bzero(&i2cd, sizeof(i2cd));
+ i2cd.len = 1;
+ i2cd.port_id = port;
+ i2cd.dev_addr = SFF_8472_BASE;
+
+ i2cd.offset = SFF_8472_ID;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+
+ if (i2cd.data[0] > SFF_8472_ID_LAST)
+ printf("Unknown ID\n");
+ else
+ printf("ID: %s\n", sff_8472_id[i2cd.data[0]]);
+
+ bzero(&string, sizeof(string));
+ for (i = SFF_8472_VENDOR_START; i < SFF_8472_VENDOR_END; i++) {
+ i2cd.offset = i;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ string[i - SFF_8472_VENDOR_START] = i2cd.data[0];
+ }
+ printf("Vendor %s\n", string);
+
+ bzero(&string, sizeof(string));
+ for (i = SFF_8472_SN_START; i < SFF_8472_SN_END; i++) {
+ i2cd.offset = i;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ string[i - SFF_8472_SN_START] = i2cd.data[0];
+ }
+ printf("SN %s\n", string);
+
+ bzero(&string, sizeof(string));
+ for (i = SFF_8472_PN_START; i < SFF_8472_PN_END; i++) {
+ i2cd.offset = i;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ string[i - SFF_8472_PN_START] = i2cd.data[0];
+ }
+ printf("PN %s\n", string);
+
+ bzero(&string, sizeof(string));
+ for (i = SFF_8472_REV_START; i < SFF_8472_REV_END; i++) {
+ i2cd.offset = i;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ string[i - SFF_8472_REV_START] = i2cd.data[0];
+ }
+ printf("Rev %s\n", string);
+
+ i2cd.offset = SFF_8472_DIAG_TYPE;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+
+ if ((char )i2cd.data[0] & (SFF_8472_DIAG_IMPL |
+ SFF_8472_DIAG_INTERNAL)) {
+
+ /* Switch to reading from the Diagnostic address. */
+ i2cd.dev_addr = SFF_8472_DIAG;
+ i2cd.len = 1;
+
+ i2cd.offset = SFF_8472_TEMP;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ temp = i2cd.data[0] << 8;
+ printf("Temp: ");
+ if ((temp & SFF_8472_TEMP_SIGN) == SFF_8472_TEMP_SIGN)
+ printf("-");
+ else
+ printf("+");
+ printf("%dC\n", (temp & SFF_8472_TEMP_MSK) >>
+ SFF_8472_TEMP_SHIFT);
+
+ i2cd.offset = SFF_8472_VCC;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ vcc = i2cd.data[0] << 8;
+ printf("Vcc %fV\n", vcc / SFF_8472_VCC_FACTOR);
+
+ i2cd.offset = SFF_8472_TX_BIAS;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ tx_bias = i2cd.data[0] << 8;
+ printf("TX Bias %fuA\n", tx_bias / SFF_8472_BIAS_FACTOR);
+
+ i2cd.offset = SFF_8472_TX_POWER;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ tx_power = i2cd.data[0] << 8;
+ printf("TX Power %fmW\n", tx_power / SFF_8472_POWER_FACTOR);
+
+ i2cd.offset = SFF_8472_RX_POWER;
+ if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+ goto fail;
+ rx_power = i2cd.data[0] << 8;
+ printf("RX Power %fmW\n", rx_power / SFF_8472_POWER_FACTOR);
+
+ } else
+ printf("Diagnostics not supported.\n");
+
+ return(0);
+
+fail:
+ if (rc == EPERM)
+ warnx("No module/cable in port %ld", port);
+ return (rc);
+
+}
+
+static int
tracer_cmd(int argc, const char *argv[])
{
long long val;
@@ -1900,6 +2031,8 @@ run_cmd(int argc, const char *argv[])
rc = clearstats(argc, argv);
else if (!strcmp(cmd, "tracer"))
rc = tracer_cmd(argc, argv);
+ else if (!strcmp(cmd, "modinfo"))
+ rc = modinfo(argc, argv);
else {
rc = EINVAL;
warnx("invalid command \"%s\"", cmd);
diff --git a/tools/tools/nanobsd/nanobsd.sh b/tools/tools/nanobsd/nanobsd.sh
index 216c900..f8bd2cd 100644
--- a/tools/tools/nanobsd/nanobsd.sh
+++ b/tools/tools/nanobsd/nanobsd.sh
@@ -57,7 +57,8 @@ NANO_PACKAGE_LIST="*"
# default is ${NANO_OBJ}
#NANO_DISKIMGDIR=""
-# Parallel Make
+# Make & parallel Make
+NANO_MAKE="make"
NANO_PMAKE="make -j 3"
# The default name for any image we create.
@@ -254,7 +255,7 @@ install_world ( ) (
cd ${NANO_SRC}
env TARGET_ARCH=${NANO_ARCH} \
- ${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} installworld \
+ ${NANO_MAKE} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} installworld \
DESTDIR=${NANO_WORLDDIR} \
> ${NANO_OBJ}/_.iw 2>&1
chflags -R noschg ${NANO_WORLDDIR}
@@ -267,7 +268,7 @@ install_etc ( ) (
cd ${NANO_SRC}
env TARGET_ARCH=${NANO_ARCH} \
- ${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} distribution \
+ ${NANO_MAKE} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} distribution \
DESTDIR=${NANO_WORLDDIR} \
> ${NANO_OBJ}/_.etc 2>&1
# make.conf doesn't get created by default, but some ports need it
@@ -288,7 +289,7 @@ install_kernel ( ) (
fi
cd ${NANO_SRC}
- env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \
+ env TARGET_ARCH=${NANO_ARCH} ${NANO_MAKE} installkernel \
DESTDIR=${NANO_WORLDDIR} \
__MAKE_CONF=${NANO_MAKE_CONF_INSTALL} \
${kernconfdir:+"KERNCONFDIR="}${kernconfdir} \
@@ -733,6 +734,77 @@ cust_pkg () (
rm -rf ${NANO_WORLDDIR}/Pkg
)
+cust_pkgng () (
+
+ # If the package directory doesn't exist, we're done.
+ if [ ! -d ${NANO_PACKAGE_DIR} ]; then
+ echo "DONE 0 packages"
+ return 0
+ fi
+
+ # Find a pkg-* package
+ for x in `find -s ${NANO_PACKAGE_DIR} -iname 'pkg-*'`; do
+ _NANO_PKG_PACKAGE=`basename "$x"`
+ done
+ if [ -z "${_NANO_PKG_PACKAGE}" -o ! -f "${NANO_PACKAGE_DIR}/${_NANO_PKG_PACKAGE}" ]; then
+ echo "FAILED: need a pkg/ package for bootstrapping"
+ exit 2
+ fi
+
+ # Copy packages into chroot
+ mkdir -p ${NANO_WORLDDIR}/Pkg
+ (
+ cd ${NANO_PACKAGE_DIR}
+ find ${NANO_PACKAGE_LIST} -print |
+ cpio -Ldumpv ${NANO_WORLDDIR}/Pkg
+ )
+
+ #Bootstrap pkg
+ chroot ${NANO_WORLDDIR} sh -c \
+ "env ASSUME_ALWAYS_YES=YES SIGNATURE_TYPE=none /usr/sbin/pkg add /Pkg/${_NANO_PKG_PACKAGE}"
+ chroot ${NANO_WORLDDIR} sh -c "pkg -N >/dev/null 2>&1;"
+ if [ "$?" -ne "0" ]; then
+ echo "FAILED: pkg bootstrapping faied"
+ exit 2
+ fi
+ rm -f ${NANO_WORLDDIR}/Pkg/pkg-*
+
+ # Count & report how many we have to install
+ todo=`ls ${NANO_WORLDDIR}/Pkg | /usr/bin/wc -l`
+ todo=$(expr $todo + 1) # add one for pkg since it is installed already
+ echo "=== TODO: $todo"
+ ls ${NANO_WORLDDIR}/Pkg
+ echo "==="
+ while true
+ do
+ # Record how many we have now
+ have=`chroot ${NANO_WORLDDIR} sh -c \
+ 'env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg info | /usr/bin/wc -l'`
+
+ # Attempt to install more packages
+ # ...but no more than 200 at a time due to (XXX still the case?) pkg_add's internal
+ # limitations.
+ chroot ${NANO_WORLDDIR} sh -c \
+ 'ls Pkg/*txz | xargs -n 200 env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg add ' || true
+
+ # See what that got us
+ now=`chroot ${NANO_WORLDDIR} sh -c \
+ 'env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg info | /usr/bin/wc -l'`
+ echo "=== NOW $now"
+ chroot ${NANO_WORLDDIR} sh -c \
+ 'env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg info'
+ echo "==="
+ if [ $now -eq $todo ] ; then
+ echo "DONE $now packages"
+ break
+ elif [ $now -eq $have ] ; then
+ echo "FAILED: Nothing happened on this pass"
+ exit 2
+ fi
+ done
+ rm -rf ${NANO_WORLDDIR}/Pkg
+)
+
#######################################################################
# Convenience function:
# Register all args as customize function.
@@ -878,6 +950,7 @@ fi
if $do_clean ; then
true
else
+ NANO_MAKE="${NANO_MAKE} -DNO_CLEAN"
NANO_PMAKE="${NANO_PMAKE} -DNO_CLEAN"
fi
@@ -897,6 +970,7 @@ export NANO_DRIVE
export NANO_HEADS
export NANO_IMAGES
export NANO_IMGNAME
+export NANO_MAKE
export NANO_MAKE_CONF_BUILD
export NANO_MAKE_CONF_INSTALL
export NANO_MEDIASIZE
diff --git a/tools/tools/umastat/umastat.c b/tools/tools/umastat/umastat.c
index 758195e..77bc590 100644
--- a/tools/tools/umastat/umastat.c
+++ b/tools/tools/umastat/umastat.c
@@ -117,7 +117,9 @@ static const struct flaginfo {
u_int32_t fi_flag;
const char *fi_name;
} flaginfo[] = {
- { UMA_ZFLAG_PRIVALLOC, "privalloc" },
+ { UMA_ZFLAG_MULTI, "multi" },
+ { UMA_ZFLAG_DRAINING, "draining" },
+ { UMA_ZFLAG_BUCKET, "bucket" },
{ UMA_ZFLAG_INTERNAL, "internal" },
{ UMA_ZFLAG_FULL, "full" },
{ UMA_ZFLAG_CACHEONLY, "cacheonly" },
@@ -133,6 +135,10 @@ static const struct flaginfo {
{ UMA_ZONE_SECONDARY, "secondary" },
{ UMA_ZONE_REFCNT, "refcnt" },
{ UMA_ZONE_MAXBUCKET, "maxbucket" },
+ { UMA_ZONE_CACHESPREAD, "cachespread" },
+ { UMA_ZONE_VTOSLAB, "vtoslab" },
+ { UMA_ZONE_NODUMP, "nodump" },
+ { UMA_ZONE_PCPU, "pcpu" },
};
static const int flaginfo_count = sizeof(flaginfo) / sizeof(struct flaginfo);
@@ -364,14 +370,15 @@ main(int argc, char *argv[])
}
printf("Keg {\n");
- printf(" uk_recurse = %d\n", kz.uk_recurse);
uma_print_keg_align(&kz, " ");
printf(" uk_pages = %d\n", kz.uk_pages);
printf(" uk_free = %d\n", kz.uk_free);
+ printf(" uk_reserve = %d\n", kz.uk_reserve);
printf(" uk_size = %d\n", kz.uk_size);
printf(" uk_rsize = %d\n", kz.uk_rsize);
printf(" uk_maxpages = %d\n", kz.uk_maxpages);
+ printf(" uk_slabsize = %d\n", kz.uk_slabsize);
printf(" uk_pgoff = %d\n", kz.uk_pgoff);
printf(" uk_ppera = %d\n", kz.uk_ppera);
printf(" uk_ipers = %d\n", kz.uk_ipers);
@@ -414,21 +421,18 @@ main(int argc, char *argv[])
}
printf(" Zone {\n");
printf(" uz_name = \"%s\";\n", name);
- printf(" uz_allocs = %ju;\n",
+ printf(" uz_allocs = %lu;\n",
uzp_userspace->uz_allocs);
- printf(" uz_frees = %ju;\n",
+ printf(" uz_frees = %lu;\n",
uzp_userspace->uz_frees);
- printf(" uz_fails = %ju;\n",
+ printf(" uz_fails = %lu;\n",
uzp_userspace->uz_fails);
- printf(" uz_fills = %u;\n",
- uzp_userspace->uz_fills);
+ printf(" uz_sleeps = %ju;\n",
+ uzp_userspace->uz_sleeps);
printf(" uz_count = %u;\n",
uzp_userspace->uz_count);
uma_print_bucketlist(kvm, (void *)
- &uzp_userspace->uz_full_bucket, "uz_full_bucket",
- " ");
- uma_print_bucketlist(kvm, (void *)
- &uzp_userspace->uz_free_bucket, "uz_free_bucket",
+ &uzp_userspace->uz_buckets, "uz_buckets",
" ");
if (!(kz.uk_flags & UMA_ZFLAG_INTERNAL)) {
diff --git a/tools/tools/zfsboottest/Makefile b/tools/tools/zfsboottest/Makefile
index a04c78f..a194a83 100644
--- a/tools/tools/zfsboottest/Makefile
+++ b/tools/tools/zfsboottest/Makefile
@@ -16,7 +16,7 @@ CFLAGS= -O1 \
-I. \
-fdiagnostics-show-option \
-W -Wextra -Wno-sign-compare -Wno-unused-parameter
-LDFLAGS+=-lmd
+LDADD+= -lmd
.if ${MACHINE_CPUARCH} == "amd64"
beforedepend zfsboottest.o: machine
OpenPOWER on IntegriCloud