diff options
author | ray <ray@FreeBSD.org> | 2013-12-05 00:57:53 +0000 |
---|---|---|
committer | ray <ray@FreeBSD.org> | 2013-12-05 00:57:53 +0000 |
commit | 1af064917e022f18acbf9fc2942cd40f1b26fbe5 (patch) | |
tree | ef10954b063bcd6939eabdcc7ecba95432634f70 /tools | |
parent | 40d47a9dd8116c90080a010ab3483d8917bd0524 (diff) | |
parent | 6e411c7e1916ef76b0aa51ded38fa235d3313371 (diff) | |
download | FreeBSD-src-1af064917e022f18acbf9fc2942cd40f1b26fbe5.zip FreeBSD-src-1af064917e022f18acbf9fc2942cd40f1b26fbe5.tar.gz |
MFC @r258947.
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'tools')
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 |