Page MenuHomeFreeBSD

D4277.diff
No OneTemporary

D4277.diff

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: head/Makefile.inc1
===================================================================
--- head/Makefile.inc1
+++ head/Makefile.inc1
@@ -585,7 +585,7 @@
rm -f ${OBJTREE}${.CURDIR}/usr.bin/kdump/kdump_subr.c
.endif
.for _dir in \
- lib usr legacy/bin legacy/usr
+ lib lib/casper usr legacy/bin legacy/usr
mkdir -p ${WORLDTMP}/${_dir}
.endfor
mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \
@@ -1870,7 +1870,7 @@
lib/libfigpar \
${_lib_libgssapi} \
lib/libkiconv lib/libkvm lib/liblzma lib/libmd lib/libnv \
- ${_lib_libcapsicum} \
+ ${_lib_casper} \
lib/ncurses/ncurses lib/ncurses/ncursesw \
lib/libopie lib/libpam ${_lib_libthr} \
${_lib_libradius} lib/libsbuf lib/libtacplus \
@@ -1910,11 +1910,11 @@
.endif
.if ${MK_CASPER} != "no"
-_lib_libcapsicum=lib/libcapsicum
+_lib_casper= lib/libcasper
.endif
-lib/libcapsicum__L: lib/libnv__L
lib/libpjdlog__L: lib/libutil__L
+lib/libcasper__L: lib/libnv__L
lib/liblzma__L: lib/libthr__L
_generic_libs= ${_cddl_lib} gnu/lib ${_kerberos5_lib} lib ${_secure_lib} usr.bin/lex/lib ${_ofed_lib}
Index: head/ObsoleteFiles.inc
===================================================================
--- head/ObsoleteFiles.inc
+++ head/ObsoleteFiles.inc
@@ -38,6 +38,25 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20160225: Remove casperd and libcapsicum.
+OLD_FILES+=sbin/casperd
+OLD_FILES+=etc/rc.d/casperd
+OLD_FILES+=usr/share/man/man8/casperd.8.gz
+OLD_FILES+=usr/include/libcapsicum.h
+OLD_FILES+=usr/include/libcapsicum_service.h
+OLD_FILES+=usr/include/libcapsicum.h
+OLD_FILES+=usr/share/man/man3/libcapsicum.3.gz
+OLD_FILES+=usr/include/libcapsicum_dns.h
+OLD_FILES+=usr/include/libcapsicum_grp.h
+OLD_FILES+=usr/include/libcapsicum_impl.h
+OLD_FILES+=usr/include/libcapsicum_pwd.h
+OLD_FILES+=usr/include/libcapsicum_random.h
+OLD_FILES+=usr/include/libcapsicum_sysctl.h
+OLD_FILES+=libexec/casper/dns
+OLD_FILES+=libexec/casper/grp
+OLD_FILES+=libexec/casper/pwd
+OLD_FILES+=libexec/casper/random
+OLD_FILES+=libexec/casper/sysctl
# 20160223: functionality from mkulzma(1) merged into mkuzip(1)
OLD_FILES+=usr/bin/mkulzma
# 20160211: Remove obsolete unbound-control-setup
Index: head/contrib/mdocml/lib.in
===================================================================
--- head/contrib/mdocml/lib.in
+++ head/contrib/mdocml/lib.in
@@ -34,7 +34,7 @@
LINE("libc_r", "Reentrant C\\~Library (libc_r, \\-lc_r)")
LINE("libcalendar", "Calendar Arithmetic Library (libcalendar, \\-lcalendar)")
LINE("libcam", "Common Access Method User Library (libcam, \\-lcam)")
-LINE("libcapsicum", "Capsicum Library (libcapsicum, \\-lcapsicum)")
+LINE("libcasper", "Casper Library (libcasper, \\-lcapser)")
LINE("libcdk", "Curses Development Kit Library (libcdk, \\-lcdk)")
LINE("libcipher", "FreeSec Crypt Library (libcipher, \\-lcipher)")
LINE("libcompat", "Compatibility Library (libcompat, \\-lcompat)")
Index: head/contrib/tcpdump/addrtoname.c
===================================================================
--- head/contrib/tcpdump/addrtoname.c
+++ head/contrib/tcpdump/addrtoname.c
@@ -29,10 +29,10 @@
#include "config.h"
#endif
-#ifdef HAVE_CAPSICUM
-#include <libcapsicum.h>
-#include <libcapsicum_dns.h>
-#endif /* HAVE_CAPSICUM */
+#ifdef HAVE_CAPSPER
+#include <libcasper.h>
+#include <casper/cap_dns.h>
+#endif /* HAVE_CAPSPER */
#include <tcpdump-stdinc.h>
#ifdef USE_ETHER_NTOHOST
@@ -204,7 +204,7 @@
static uint32_t f_netmask;
static uint32_t f_localnet;
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
extern cap_channel_t *capdns;
#endif
@@ -252,7 +252,7 @@
*/
if (!ndo->ndo_nflag &&
(addr & f_netmask) == f_localnet) {
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
if (capdns != NULL) {
hp = cap_gethostbyaddr(capdns, (char *)&addr, 4,
AF_INET);
@@ -309,7 +309,7 @@
* Do not print names if -n was given.
*/
if (!ndo->ndo_nflag) {
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
if (capdns != NULL) {
hp = cap_gethostbyaddr(capdns, (char *)&addr,
sizeof(addr), AF_INET6);
Index: head/contrib/tcpdump/config.h.in
===================================================================
--- head/contrib/tcpdump/config.h.in
+++ head/contrib/tcpdump/config.h.in
@@ -10,7 +10,7 @@
#undef HAVE_BPF_DUMP
/* capsicum support available */
-#undef HAVE_CAPSICUM
+#undef HAVE_CAPSPER
/* Define to 1 if you have the `cap_enter' function. */
#undef HAVE_CAP_ENTER
Index: head/contrib/tcpdump/configure
===================================================================
--- head/contrib/tcpdump/configure
+++ head/contrib/tcpdump/configure
@@ -4566,7 +4566,7 @@
$as_echo_n "checking whether to sandbox using capsicum... " >&6; }
if test "x$ac_lbl_capsicum_function_seen" = "xyes" -a "x$ac_lbl_capsicum_function_not_seen" != "xyes"; then
-$as_echo "#define HAVE_CAPSICUM 1" >>confdefs.h
+$as_echo "#define HAVE_CAPSPER 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
Index: head/contrib/tcpdump/configure.in
===================================================================
--- head/contrib/tcpdump/configure.in
+++ head/contrib/tcpdump/configure.in
@@ -222,7 +222,7 @@
fi
AC_MSG_CHECKING([whether to sandbox using capsicum])
if test "x$ac_lbl_capsicum_function_seen" = "xyes" -a "x$ac_lbl_capsicum_function_not_seen" != "xyes"; then
- AC_DEFINE(HAVE_CAPSICUM, 1, [capsicum support available])
+ AC_DEFINE(HAVE_CASPER, 1, [casper support available])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
Index: head/contrib/tcpdump/tcpdump.c
===================================================================
--- head/contrib/tcpdump/tcpdump.c
+++ head/contrib/tcpdump/tcpdump.c
@@ -87,17 +87,16 @@
#include <sys/capsicum.h>
#include <sys/sysctl.h>
#endif /* __FreeBSD__ */
-#ifdef HAVE_CAPSICUM
-#include <libcapsicum.h>
-#include <libcapsicum_dns.h>
-#include <libcapsicum_service.h>
+#ifdef HAVE_CAPSPER
+#include <libcasper.h>
+#include <casper/cap_dns.h>
#include <sys/nv.h>
#include <sys/capability.h>
#include <sys/ioccom.h>
#include <net/bpf.h>
#include <fcntl.h>
#include <libgen.h>
-#endif /* HAVE_CAPSICUM */
+#endif /* HAVE_CAPSPER */
#include <pcap.h>
#include <signal.h>
#include <stdio.h>
@@ -161,7 +160,7 @@
char *program_name;
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
cap_channel_t *capdns;
#endif
@@ -485,7 +484,7 @@
char *CurrentFileName;
pcap_t *pd;
pcap_dumper_t *p;
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
int dirfd;
#endif
};
@@ -909,7 +908,7 @@
return ret;
}
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
static cap_channel_t *
capdns_setup(void)
{
@@ -918,10 +917,8 @@
int families[2];
capcas = cap_init();
- if (capcas == NULL) {
- warning("unable to contact casperd");
- return (NULL);
- }
+ if (capcas == NULL)
+ error("unable to create casper process");
capdnsloc = cap_service_open(capcas, "system.dns");
/* Casper capability no longer needed. */
cap_close(capcas);
@@ -938,7 +935,7 @@
return (capdnsloc);
}
-#endif /* HAVE_CAPSICUM */
+#endif /* HAVE_CAPSPER */
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
static int
@@ -970,7 +967,7 @@
}
#endif
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
/*
* Ensure that, on a dump file's descriptor, we have all the rights
* necessary to make the standard I/O library work with an fdopen()ed
@@ -1070,9 +1067,9 @@
#endif
int status;
FILE *VFile;
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
cap_rights_t rights;
-#endif /* HAVE_CAPSICUM */
+#endif /* HAVE_CAPSPER */
int cansandbox;
#ifdef WIN32
@@ -1613,7 +1610,7 @@
if (pd == NULL)
error("%s", ebuf);
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
cap_rights_init(&rights, CAP_READ);
if (cap_rights_limit(fileno(pcap_file(pd)), &rights) < 0 &&
errno != ENOSYS) {
@@ -1850,10 +1847,10 @@
exit(0);
}
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
if (!nflag)
capdns = capdns_setup();
-#endif /* HAVE_CAPSICUM */
+#endif /* HAVE_CAPSPER */
init_addrtoname(gndo, localnet, netmask);
init_checksum();
@@ -1921,7 +1918,7 @@
if (pcap_setfilter(pd, &fcode) < 0)
error("%s", pcap_geterr(pd));
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
if (RFileName == NULL && VFileName == NULL) {
static const unsigned long cmds[] = { BIOCGSTATS };
@@ -1971,11 +1968,11 @@
#endif /* HAVE_LIBCAP_NG */
if (p == NULL)
error("%s", pcap_geterr(pd));
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
set_dumper_capsicum_rights(p);
#endif
if (Cflag != 0 || Gflag != 0) {
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
dumpinfo.WFileName = strdup(basename(WFileName));
dumpinfo.dirfd = open(dirname(WFileName),
O_DIRECTORY | O_RDONLY);
@@ -1993,7 +1990,7 @@
errno != ENOSYS) {
error("unable to limit dump descriptor fcntls");
}
-#else /* !HAVE_CAPSICUM */
+#else /* !HAVE_CAPSPER */
dumpinfo.WFileName = WFileName;
#endif
callback = dump_packet_and_trunc;
@@ -2069,7 +2066,7 @@
#ifdef __FreeBSD__
cansandbox = (VFileName == NULL && zflag == NULL);
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
cansandbox = (cansandbox && (nflag || capdns != NULL));
#else
cansandbox = (cansandbox && nflag);
@@ -2125,7 +2122,7 @@
pd = pcap_open_offline(RFileName, ebuf);
if (pd == NULL)
error("%s", ebuf);
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
cap_rights_init(&rights, CAP_READ);
if (cap_rights_limit(fileno(pcap_file(pd)),
&rights) < 0 && errno != ENOSYS) {
@@ -2328,7 +2325,7 @@
/* If the time is greater than the specified window, rotate */
if (t - Gflag_time >= Gflag) {
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
FILE *fp;
int fd;
#endif
@@ -2386,7 +2383,7 @@
capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
capng_apply(CAPNG_SELECT_BOTH);
#endif /* HAVE_LIBCAP_NG */
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
fd = openat(dump_info->dirfd,
dump_info->CurrentFileName,
O_CREAT | O_WRONLY | O_TRUNC, 0644);
@@ -2400,7 +2397,7 @@
dump_info->CurrentFileName);
}
dump_info->p = pcap_dump_fopen(dump_info->pd, fp);
-#else /* !HAVE_CAPSICUM */
+#else /* !HAVE_CAPSPER */
dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
#endif
#ifdef HAVE_LIBCAP_NG
@@ -2409,7 +2406,7 @@
#endif /* HAVE_LIBCAP_NG */
if (dump_info->p == NULL)
error("%s", pcap_geterr(pd));
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
set_dumper_capsicum_rights(dump_info->p);
#endif
}
@@ -2426,7 +2423,7 @@
if (size == -1)
error("ftell fails on output file");
if (size > Cflag) {
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
FILE *fp;
int fd;
#endif
@@ -2458,7 +2455,7 @@
capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
capng_apply(CAPNG_SELECT_BOTH);
#endif /* HAVE_LIBCAP_NG */
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
fd = openat(dump_info->dirfd, dump_info->CurrentFileName,
O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0) {
@@ -2471,7 +2468,7 @@
dump_info->CurrentFileName);
}
dump_info->p = pcap_dump_fopen(dump_info->pd, fp);
-#else /* !HAVE_CAPSICUM */
+#else /* !HAVE_CAPSPER */
dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
#endif
#ifdef HAVE_LIBCAP_NG
@@ -2480,7 +2477,7 @@
#endif /* HAVE_LIBCAP_NG */
if (dump_info->p == NULL)
error("%s", pcap_geterr(pd));
-#ifdef HAVE_CAPSICUM
+#ifdef HAVE_CAPSPER
set_dumper_capsicum_rights(dump_info->p);
#endif
}
Index: head/etc/defaults/rc.conf
===================================================================
--- head/etc/defaults/rc.conf
+++ head/etc/defaults/rc.conf
@@ -681,7 +681,6 @@
newsyslog_flags="-CN" # Newsyslog flags to create marked files
mixer_enable="YES" # Run the sound mixer.
opensm_enable="NO" # Opensm(8) for infiniband devices defaults to off
-casperd_enable="YES" # casperd(8) daemon
# rctl(8) requires kernel options RACCT and RCTL
rctl_enable="YES" # Load rctl(8) rules on boot
Index: head/etc/mtree/BSD.debug.dist
===================================================================
--- head/etc/mtree/BSD.debug.dist
+++ head/etc/mtree/BSD.debug.dist
@@ -15,8 +15,6 @@
lib
geom
..
- ..
- libexec
casper
..
..
Index: head/etc/mtree/BSD.include.dist
===================================================================
--- head/etc/mtree/BSD.include.dist
+++ head/etc/mtree/BSD.include.dist
@@ -93,6 +93,8 @@
scsi
..
..
+ casper
+ ..
crypto
..
dev
Index: head/etc/mtree/BSD.root.dist
===================================================================
--- head/etc/mtree/BSD.root.dist
+++ head/etc/mtree/BSD.root.dist
@@ -80,12 +80,12 @@
..
..
lib
+ casper
+ ..
geom
..
..
libexec
- casper
- ..
resolvconf
..
..
Index: head/etc/rc.d/Makefile
===================================================================
--- head/etc/rc.d/Makefile
+++ head/etc/rc.d/Makefile
@@ -21,7 +21,6 @@
${_bluetooth} \
bridge \
${_bthidd} \
- ${_casperd} \
cleanvar \
cleartmp \
cron \
@@ -176,10 +175,6 @@
FILES+= bsnmpd
.endif
-.if ${MK_CASPER} != "no"
-_casperd= casperd
-.endif
-
.if ${MK_CCD} != "no"
FILES+= ccd
.endif
Index: head/etc/rc.d/casperd
===================================================================
--- head/etc/rc.d/casperd
+++ head/etc/rc.d/casperd
@@ -1,19 +0,0 @@
-#!/bin/sh
-#
-# $FreeBSD$
-#
-
-# PROVIDE: casperd
-# REQUIRE: NETWORKING syslogd
-# BEFORE: DAEMON
-# KEYWORD: shutdown
-
-. /etc/rc.subr
-
-name="casperd"
-rcvar="casperd_enable"
-pidfile="/var/run/${name}.pid"
-command="/sbin/${name}"
-
-load_rc_config $name
-run_rc_command "$1"
Index: head/gnu/usr.bin/groff/tmac/mdoc.local.in
===================================================================
--- head/gnu/usr.bin/groff/tmac/mdoc.local.in
+++ head/gnu/usr.bin/groff/tmac/mdoc.local.in
@@ -34,7 +34,7 @@
.\" FreeBSD .Lb values
.ds doc-str-Lb-libarchive Streaming Archive Library (libarchive, \-larchive)
.ds doc-str-Lb-libbluetooth Bluetooth User Library (libbluetooth, \-lbluetooth)
-.ds doc-str-Lb-libcapsicum Capsicum Library (libcapsicum, \-lcapsicum)
+.ds doc-str-Lb-libcseper Casper Library (libcapsicum, \-lcasper)
.ds doc-str-Lb-libcuse Userland Character Device Library (libcuse, \-lcuse)
.ds doc-str-Lb-libedit Line Editor and History Library (libedit, \-ledit)
.ds doc-str-Lb-libefi EFI Runtime Services Library (libefi, \-lefi)
Index: head/lib/Makefile
===================================================================
--- head/lib/Makefile
+++ head/lib/Makefile
@@ -36,7 +36,6 @@
libbz2 \
libcalendar \
libcam \
- ${_libcapsicum} \
${_libcasper} \
${_libcom_err} \
libcompat \
@@ -135,8 +134,7 @@
SUBDIR_DEPEND_libc++:= libcxxrt
SUBDIR_DEPEND_libc= libcompiler_rt
SUBDIR_DEPEND_libcam= libsbuf
-SUBDIR_DEPEND_libcapsicum= libnv
-SUBDIR_DEPEND_libcasper= libcapsicum libnv libpjdlog
+SUBDIR_DEPEND_libcasper= libnv
SUBDIR_DEPEND_libdevstat= libkvm
SUBDIR_DEPEND_libdpv= libfigpar ncurses libutil
SUBDIR_DEPEND_libedit= ncurses
@@ -171,7 +169,6 @@
.endif
.if ${MK_CASPER} != "no"
-_libcapsicum= libcapsicum
_libcasper= libcasper
.endif
Index: head/lib/libc/posix1e/posix1e.3
===================================================================
--- head/lib/libc/posix1e/posix1e.3
+++ head/lib/libc/posix1e/posix1e.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 15, 2014
+.Dd February 25, 2016
.Dt POSIX1E 3
.Os
.Sh NAME
@@ -94,7 +94,7 @@
.Xr acl 3 ,
.Xr extattr 3 ,
.Xr libbsm 3 ,
-.Xr libcapsicum 3 ,
+.Xr libcasper 3 ,
.Xr mac 3 ,
.Xr capsicum 4 ,
.Xr ffs 7 ,
Index: head/lib/libcapsicum/Makefile
===================================================================
--- head/lib/libcapsicum/Makefile
+++ head/lib/libcapsicum/Makefile
@@ -1,46 +0,0 @@
-# $FreeBSD$
-
-LIB= capsicum
-
-SHLIB_MAJOR= 0
-SHLIBDIR?= /lib
-
-SRCS= libcapsicum.c
-SRCS+= libcapsicum_dns.c
-SRCS+= libcapsicum_grp.c
-SRCS+= libcapsicum_pwd.c
-SRCS+= libcapsicum_random.c
-SRCS+= libcapsicum_service.c
-SRCS+= libcapsicum_sysctl.c
-
-INCS= libcapsicum.h
-INCS+= libcapsicum_dns.h
-INCS+= libcapsicum_grp.h
-INCS+= libcapsicum_pwd.h
-INCS+= libcapsicum_random.h
-INCS+= libcapsicum_service.h
-INCS+= libcapsicum_sysctl.h
-
-LIBADD= nv
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../libnv
-
-WARNS?= 6
-
-MAN+= libcapsicum.3
-
-MLINKS+=libcapsicum.3 cap_init.3
-MLINKS+=libcapsicum.3 cap_wrap.3
-MLINKS+=libcapsicum.3 cap_unwrap.3
-MLINKS+=libcapsicum.3 cap_sock.3
-MLINKS+=libcapsicum.3 cap_clone.3
-MLINKS+=libcapsicum.3 cap_close.3
-MLINKS+=libcapsicum.3 cap_limit_get.3
-MLINKS+=libcapsicum.3 cap_limit_set.3
-MLINKS+=libcapsicum.3 cap_send_nvlist.3
-MLINKS+=libcapsicum.3 cap_recv_nvlist.3
-MLINKS+=libcapsicum.3 cap_xfer_nvlist.3
-MLINKS+=libcapsicum.3 cap_service_open.3
-
-.include <bsd.lib.mk>
Index: head/lib/libcapsicum/Makefile.depend
===================================================================
--- head/lib/libcapsicum/Makefile.depend
+++ head/lib/libcapsicum/Makefile.depend
@@ -1,19 +0,0 @@
-# $FreeBSD$
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
- gnu/lib/csu \
- gnu/lib/libgcc \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
- lib/libcompiler_rt \
- lib/libnv \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
Index: head/lib/libcapsicum/libcapsicum.h
===================================================================
--- head/lib/libcapsicum/libcapsicum.h
+++ head/lib/libcapsicum/libcapsicum.h
@@ -1,115 +0,0 @@
-/*-
- * Copyright (c) 2012-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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_H_
-#define _LIBCAPSICUM_H_
-
-#ifndef _NVLIST_T_DECLARED
-#define _NVLIST_T_DECLARED
-struct nvlist;
-
-typedef struct nvlist nvlist_t;
-#endif
-
-#ifndef _CAP_CHANNEL_T_DECLARED
-#define _CAP_CHANNEL_T_DECLARED
-struct cap_channel;
-
-typedef struct cap_channel cap_channel_t;
-#endif
-
-/*
- * The function opens unrestricted communication channel to Casper.
- */
-cap_channel_t *cap_init(void);
-
-/*
- * The function creates cap_channel_t based on the given socket.
- */
-cap_channel_t *cap_wrap(int sock);
-
-/*
- * The function returns communication socket and frees cap_channel_t.
- */
-int cap_unwrap(cap_channel_t *chan);
-
-/*
- * The function clones the given capability.
- */
-cap_channel_t *cap_clone(const cap_channel_t *chan);
-
-/*
- * The function closes the given capability.
- */
-void cap_close(cap_channel_t *chan);
-
-/*
- * The function returns socket descriptor associated with the given
- * cap_channel_t for use with select(2)/kqueue(2)/etc.
- */
-int cap_sock(const cap_channel_t *chan);
-
-/*
- * The function limits the given capability.
- * It always destroys 'limits' on return.
- */
-int cap_limit_set(const cap_channel_t *chan, nvlist_t *limits);
-
-/*
- * The function returns current limits of the given capability.
- */
-int cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp);
-
-#ifdef TODO
-/*
- * The function registers a service within provided Casper's capability.
- * It will run with the same privileges the process has at the time of
- * calling this function.
- */
-int cap_service_register(cap_channel_t *chan, const char *name,
- cap_func_t *func);
-#endif
-
-/*
- * Function sends nvlist over the given capability.
- */
-int cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl);
-/*
- * Function receives nvlist over the given capability.
- */
-nvlist_t *cap_recv_nvlist(const cap_channel_t *chan, int flags);
-/*
- * Function sends the given nvlist, destroys it and receives new nvlist in
- * response over the given capability.
- */
-nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags);
-
-#endif /* !_LIBCAPSICUM_H_ */
Index: head/lib/libcapsicum/libcapsicum.3
===================================================================
--- head/lib/libcapsicum/libcapsicum.3
+++ head/lib/libcapsicum/libcapsicum.3
@@ -1,300 +0,0 @@
-.\" Copyright (c) 2013 The FreeBSD Foundation
-.\" All rights reserved.
-.\"
-.\" This documentation was written 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd May 2, 2015
-.Dt LIBCAPSICUM 3
-.Os
-.Sh NAME
-.Nm cap_init ,
-.Nm cap_wrap ,
-.Nm cap_unwrap ,
-.Nm cap_sock ,
-.Nm cap_clone ,
-.Nm cap_close ,
-.Nm cap_limit_get ,
-.Nm cap_limit_set ,
-.Nm cap_send_nvlist ,
-.Nm cap_recv_nvlist ,
-.Nm cap_xfer_nvlist ,
-.Nm cap_service_open
-.Nd "library for handling application capabilities"
-.Sh LIBRARY
-.Lb libcapsicum
-.Sh SYNOPSIS
-.In libcapsicum.h
-.In nv.h
-.Ft "cap_channel_t *"
-.Fn cap_init "void"
-.Ft "cap_channel_t *"
-.Fn cap_wrap "int sock"
-.Ft "int"
-.Fn cap_unwrap "cap_channel_t *chan"
-.Ft "int"
-.Fn cap_sock "const cap_channel_t *chan"
-.Ft "cap_channel_t *"
-.Fn cap_clone "const cap_channel_t *chan"
-.Ft "void"
-.Fn cap_close "cap_channel_t *chan"
-.Ft "int"
-.Fn cap_limit_get "const cap_channel_t *chan" "nvlist_t **limitsp"
-.Ft "int"
-.Fn cap_limit_set "const cap_channel_t *chan" "nvlist_t *limits"
-.Ft "int"
-.Fn cap_send_nvlist "const cap_channel_t *chan" "const nvlist_t *nvl"
-.Ft "nvlist_t *"
-.Fn cap_recv_nvlist "const cap_channel_t *chan" "int flags"
-.Ft "nvlist_t *"
-.Fn cap_xfer_nvlist "const cap_channel_t *chan" "nvlist_t *nvl" "int flags"
-.In libcapsicum_service.h
-.Ft "cap_channel_t *"
-.Fn cap_service_open "const cap_channel_t *chan" "const char *name"
-.Sh DESCRIPTION
-The
-.Nm libcapsicum
-library allows to manage application capabilities through the
-.Xr casperd 8
-daemon.
-.Pp
-The application capability (represented by the
-.Vt cap_channel_t
-type) is a communication channel between the caller and the
-.Xr casperd 8
-daemon or an instance of one of its services.
-A capability to the
-.Xr casperd 8
-daemon obtained with the
-.Fn cap_init
-function allows to create capabilities to casper's services via the
-.Fn cap_service_open
-function.
-.Pp
-The
-.Fn cap_init
-function opens capability to the
-.Xr casperd 8
-daemon.
-.Pp
-The
-.Fn cap_wrap
-function creates
-.Vt cap_channel_t
-based on the given socket.
-The function is used when capability is inherited through
-.Xr execve 2
-or send over
-.Xr unix 4
-domain socket as a regular file descriptor and has to be represented as
-.Vt cap_channel_t
-again.
-.Pp
-The
-.Fn cap_unwrap
-function is the opposite of the
-.Fn cap_wrap
-function.
-It frees the
-.Vt cap_channel_t
-structure and returns
-.Xr unix 4
-domain socket associated with it.
-.Pp
-The
-.Fn cap_clone
-function clones the given capability.
-.Pp
-The
-.Fn cap_close
-function closes the given capability.
-.Pp
-The
-.Fn cap_sock
-function returns
-.Xr unix 4
-domain socket descriptor associated with the given capability for use with
-system calls like
-.Xr kevent 2 ,
-.Xr poll 2
-and
-.Xr select 2 .
-.Pp
-The
-.Fn cap_limit_get
-function stores current limits of the given capability in the
-.Fa limitsp
-argument.
-If the function return
-.Va 0
-and
-.Dv NULL
-is stored in
-.Fa limitsp
-it means there are no limits set.
-.Pp
-The
-.Fn cap_limit_set
-function sets limits for the given capability.
-The limits are provided as nvlist.
-The exact format depends on the service the capability represents.
-.Pp
-The
-.Fn cap_send_nvlist
-function sends the given nvlist over the given capability.
-This is low level interface to communicate with casper services.
-Most services should provide higher level API.
-.Pp
-The
-.Fn cap_recv_nvlist
-function receives the given nvlist over the given capability.
-The
-.Fa flags
-argument defines what type the top nvlist is expected to be.
-If the nvlist flags do not match the flags passed to
-.Fn cap_recv_nvlist ,
-the nvlist will not be returned.
-.Pp
-The
-.Fn cap_xfer_nvlist
-function sends the given nvlist, destroys it and receives new nvlist in
-response over the given capability.
-The
-.Fa flags
-argument defines what type the top nvlist is expected to be.
-If the nvlist flags do not match the flags passed to
-.Fn cap_xfer_nvlist ,
-the nvlist will not be returned.
-It does not matter if the function succeeds or fails, the nvlist given
-for sending will always be destroyed once the function returns.
-.Pp
-The
-.Fn cap_service_open
-function opens casper service of the given name through casper capability
-obtained via the
-.Fn cap_init
-function.
-The function returns capability that provides access to opened service.
-.Sh RETURN VALUES
-The
-.Fn cap_clone ,
-.Fn cap_init ,
-.Fn cap_recv_nvlist ,
-.Fn cap_service_open ,
-.Fn cap_wrap
-and
-.Fn cap_xfer_nvlist
-functions return
-.Dv NULL
-and set the
-.Va errno
-variable on failure.
-.Pp
-The
-.Fn cap_limit_get ,
-.Fn cap_limit_set
-and
-.Fn cap_send_nvlist
-functions return
-.Dv -1
-and set the
-.Va errno
-variable on failure.
-.Pp
-The
-.Fn cap_close ,
-.Fn cap_sock
-and
-.Fn cap_unwrap
-functions always succeed.
-.Sh EXAMPLES
-The following example first opens capability to the
-.Xr casperd 8
-daemon, then using this capability creates new capability to the
-.Nm system.dns
-casper service and uses the latter capability to resolve IP address.
-.Bd -literal
-cap_channel_t *capcas, *capdns;
-nvlist_t *limits;
-const char *ipstr = "127.0.0.1";
-struct in_addr ip;
-struct hostent *hp;
-
-/* Open capability to the Casper daemon. */
-capcas = cap_init();
-if (capcas == NULL)
- err(1, "Unable to contact Casper daemon");
-
-/* Enter capability mode sandbox. */
-if (cap_enter() < 0 && errno != ENOSYS)
- err(1, "Unable to enter capability mode");
-
-/* Use Casper capability to create capability to the system.dns service. */
-capdns = cap_service_open(capcas, "system.dns");
-if (capdns == NULL)
- err(1, "Unable to open system.dns service");
-
-/* Close Casper capability, we don't need it anymore. */
-cap_close(capcas);
-
-/* Limit system.dns to reverse DNS lookups and IPv4 addresses. */
-limits = nvlist_create(0);
-nvlist_add_string(limits, "type", "ADDR");
-nvlist_add_number(limits, "family", (uint64_t)AF_INET);
-if (cap_limit_set(capdns, limits) < 0)
- err(1, "Unable to limit access to the system.dns service");
-
-/* Convert IP address in C-string to in_addr. */
-if (!inet_aton(ipstr, &ip))
- errx(1, "Unable to parse IP address %s.", ipstr);
-
-/* Find hostname for the given IP address. */
-hp = cap_gethostbyaddr(capdns, (const void *)&ip, sizeof(ip), AF_INET);
-if (hp == NULL)
- errx(1, "No name associated with %s.", ipstr);
-
-printf("Name associated with %s is %s.\\n", ipstr, hp->h_name);
-.Ed
-.Sh SEE ALSO
-.Xr cap_enter 2 ,
-.Xr execve 2 ,
-.Xr kevent 2 ,
-.Xr poll 2 ,
-.Xr select 2 ,
-.Xr cap_gethostbyaddr 3 ,
-.Xr err 3 ,
-.Xr gethostbyaddr 3 ,
-.Xr inet_aton 3 ,
-.Xr nv 3 ,
-.Xr capsicum 4 ,
-.Xr unix 4 ,
-.Xr casperd 8
-.Sh AUTHORS
-The
-.Nm libcapsicum
-library was implemented by
-.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
-under sponsorship from the FreeBSD Foundation.
Index: head/lib/libcapsicum/libcapsicum.c
===================================================================
--- head/lib/libcapsicum/libcapsicum.c
+++ head/lib/libcapsicum/libcapsicum.c
@@ -1,266 +0,0 @@
-/*-
- * Copyright (c) 2012-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/socket.h>
-#include <sys/un.h>
-#include <sys/nv.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "libcapsicum.h"
-#include "libcapsicum_impl.h"
-
-/*
- * Structure describing communication channel between two separated processes.
- */
-#define CAP_CHANNEL_MAGIC 0xcac8a31
-struct cap_channel {
- /*
- * Magic value helps to ensure that a pointer to the right structure is
- * passed to our functions.
- */
- int cch_magic;
- /* Socket descriptor for IPC. */
- int cch_sock;
-};
-
-bool
-fd_is_valid(int fd)
-{
-
- return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
-}
-
-cap_channel_t *
-cap_init(void)
-{
- cap_channel_t *chan;
- struct sockaddr_un sun;
- int serrno, sock;
-
- bzero(&sun, sizeof(sun));
- sun.sun_family = AF_UNIX;
- strlcpy(sun.sun_path, CASPER_SOCKPATH, sizeof(sun.sun_path));
- sun.sun_len = SUN_LEN(&sun);
-
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock == -1)
- return (NULL);
- if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
- serrno = errno;
- close(sock);
- errno = serrno;
- return (NULL);
- }
- chan = cap_wrap(sock);
- if (chan == NULL) {
- serrno = errno;
- close(sock);
- errno = serrno;
- return (NULL);
- }
- return (chan);
-}
-
-cap_channel_t *
-cap_wrap(int sock)
-{
- cap_channel_t *chan;
-
- if (!fd_is_valid(sock))
- return (NULL);
-
- chan = malloc(sizeof(*chan));
- if (chan != NULL) {
- chan->cch_sock = sock;
- chan->cch_magic = CAP_CHANNEL_MAGIC;
- }
-
- return (chan);
-}
-
-int
-cap_unwrap(cap_channel_t *chan)
-{
- int sock;
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- sock = chan->cch_sock;
- chan->cch_magic = 0;
- free(chan);
-
- return (sock);
-}
-
-cap_channel_t *
-cap_clone(const cap_channel_t *chan)
-{
- cap_channel_t *newchan;
- nvlist_t *nvl;
- int newsock;
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "clone");
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (NULL);
- if (nvlist_get_number(nvl, "error") != 0) {
- errno = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (NULL);
- }
- newsock = nvlist_take_descriptor(nvl, "sock");
- nvlist_destroy(nvl);
- newchan = cap_wrap(newsock);
- if (newchan == NULL) {
- int serrno;
-
- serrno = errno;
- close(newsock);
- errno = serrno;
- }
-
- return (newchan);
-}
-
-void
-cap_close(cap_channel_t *chan)
-{
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- chan->cch_magic = 0;
- close(chan->cch_sock);
- free(chan);
-}
-
-int
-cap_sock(const cap_channel_t *chan)
-{
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- return (chan->cch_sock);
-}
-
-int
-cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
-{
- nvlist_t *nvlmsg;
- int error;
-
- nvlmsg = nvlist_create(0);
- nvlist_add_string(nvlmsg, "cmd", "limit_set");
- nvlist_add_nvlist(nvlmsg, "limits", limits);
- nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
- if (nvlmsg == NULL) {
- nvlist_destroy(limits);
- return (-1);
- }
- error = (int)nvlist_get_number(nvlmsg, "error");
- nvlist_destroy(nvlmsg);
- nvlist_destroy(limits);
- if (error != 0) {
- errno = error;
- return (-1);
- }
- return (0);
-}
-
-int
-cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
-{
- nvlist_t *nvlmsg;
- int error;
-
- nvlmsg = nvlist_create(0);
- nvlist_add_string(nvlmsg, "cmd", "limit_get");
- nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
- if (nvlmsg == NULL)
- return (-1);
- error = (int)nvlist_get_number(nvlmsg, "error");
- if (error != 0) {
- nvlist_destroy(nvlmsg);
- errno = error;
- return (-1);
- }
- if (nvlist_exists_null(nvlmsg, "limits"))
- *limitsp = NULL;
- else
- *limitsp = nvlist_take_nvlist(nvlmsg, "limits");
- nvlist_destroy(nvlmsg);
- return (0);
-}
-
-int
-cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
-{
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- return (nvlist_send(chan->cch_sock, nvl));
-}
-
-nvlist_t *
-cap_recv_nvlist(const cap_channel_t *chan, int flags)
-{
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- return (nvlist_recv(chan->cch_sock, flags));
-}
-
-nvlist_t *
-cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
-{
-
- assert(chan != NULL);
- assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
-
- return (nvlist_xfer(chan->cch_sock, nvl, flags));
-}
Index: head/lib/libcapsicum/libcapsicum_dns.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_dns.h
+++ head/lib/libcapsicum/libcapsicum_dns.h
@@ -1,57 +0,0 @@
-/*-
- * Copyright (c) 2012 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_DNS_H_
-#define _LIBCAPSICUM_DNS_H_
-
-#include <sys/socket.h> /* socklen_t */
-
-struct addrinfo;
-struct hostent;
-
-struct hostent *cap_gethostbyname(cap_channel_t *chan, const char *name);
-struct hostent *cap_gethostbyname2(cap_channel_t *chan, const char *name,
- int type);
-struct hostent *cap_gethostbyaddr(cap_channel_t *chan, const void *addr,
- socklen_t len, int type);
-
-int cap_getaddrinfo(cap_channel_t *chan, const char *hostname,
- const char *servname, const struct addrinfo *hints, struct addrinfo **res);
-int cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa,
- socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen,
- int flags);
-
-int cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
- size_t ntypes);
-int cap_dns_family_limit(cap_channel_t *chan, const int *families,
- size_t nfamilies);
-
-#endif /* !_LIBCAPSICUM_DNS_H_ */
Index: head/lib/libcapsicum/libcapsicum_dns.c
===================================================================
--- head/lib/libcapsicum/libcapsicum_dns.c
+++ head/lib/libcapsicum/libcapsicum_dns.c
@@ -1,365 +0,0 @@
-/*-
- * Copyright (c) 2012-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/nv.h>
-
-#include <assert.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "libcapsicum.h"
-#include "libcapsicum_dns.h"
-
-static struct hostent hent;
-
-static void
-hostent_free(struct hostent *hp)
-{
- unsigned int ii;
-
- free(hp->h_name);
- hp->h_name = NULL;
- if (hp->h_aliases != NULL) {
- for (ii = 0; hp->h_aliases[ii] != NULL; ii++)
- free(hp->h_aliases[ii]);
- free(hp->h_aliases);
- hp->h_aliases = NULL;
- }
- if (hp->h_addr_list != NULL) {
- for (ii = 0; hp->h_addr_list[ii] != NULL; ii++)
- free(hp->h_addr_list[ii]);
- free(hp->h_addr_list);
- hp->h_addr_list = NULL;
- }
-}
-
-static struct hostent *
-hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
-{
- unsigned int ii, nitems;
- char nvlname[64];
- int n;
-
- hostent_free(hp);
-
- hp->h_name = strdup(nvlist_get_string(nvl, "name"));
- if (hp->h_name == NULL)
- goto fail;
- hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype");
- hp->h_length = (int)nvlist_get_number(nvl, "length");
-
- nitems = (unsigned int)nvlist_get_number(nvl, "naliases");
- hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1);
- if (hp->h_aliases == NULL)
- goto fail;
- for (ii = 0; ii < nitems; ii++) {
- n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- hp->h_aliases[ii] =
- strdup(nvlist_get_string(nvl, nvlname));
- if (hp->h_aliases[ii] == NULL)
- goto fail;
- }
- hp->h_aliases[ii] = NULL;
-
- nitems = (unsigned int)nvlist_get_number(nvl, "naddrs");
- hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1);
- if (hp->h_addr_list == NULL)
- goto fail;
- for (ii = 0; ii < nitems; ii++) {
- hp->h_addr_list[ii] = malloc(hp->h_length);
- if (hp->h_addr_list[ii] == NULL)
- goto fail;
- n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- bcopy(nvlist_get_binary(nvl, nvlname, NULL),
- hp->h_addr_list[ii], hp->h_length);
- }
- hp->h_addr_list[ii] = NULL;
-
- return (hp);
-fail:
- hostent_free(hp);
- h_errno = NO_RECOVERY;
- return (NULL);
-}
-
-struct hostent *
-cap_gethostbyname(cap_channel_t *chan, const char *name)
-{
-
- return (cap_gethostbyname2(chan, name, AF_INET));
-}
-
-struct hostent *
-cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
-{
- struct hostent *hp;
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "gethostbyname");
- nvlist_add_number(nvl, "family", (uint64_t)type);
- nvlist_add_string(nvl, "name", name);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL) {
- h_errno = NO_RECOVERY;
- return (NULL);
- }
- if (nvlist_get_number(nvl, "error") != 0) {
- h_errno = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (NULL);
- }
-
- hp = hostent_unpack(nvl, &hent);
- nvlist_destroy(nvl);
- return (hp);
-}
-
-struct hostent *
-cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
- int type)
-{
- struct hostent *hp;
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "gethostbyaddr");
- nvlist_add_binary(nvl, "addr", addr, (size_t)len);
- nvlist_add_number(nvl, "family", (uint64_t)type);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL) {
- h_errno = NO_RECOVERY;
- return (NULL);
- }
- if (nvlist_get_number(nvl, "error") != 0) {
- h_errno = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (NULL);
- }
- hp = hostent_unpack(nvl, &hent);
- nvlist_destroy(nvl);
- return (hp);
-}
-
-static struct addrinfo *
-addrinfo_unpack(const nvlist_t *nvl)
-{
- struct addrinfo *ai;
- const void *addr;
- size_t addrlen;
- const char *canonname;
-
- addr = nvlist_get_binary(nvl, "ai_addr", &addrlen);
- ai = malloc(sizeof(*ai) + addrlen);
- if (ai == NULL)
- return (NULL);
- ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags");
- ai->ai_family = (int)nvlist_get_number(nvl, "ai_family");
- ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype");
- ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol");
- ai->ai_addrlen = (socklen_t)addrlen;
- canonname = nvlist_get_string(nvl, "ai_canonname");
- if (canonname != NULL) {
- ai->ai_canonname = strdup(canonname);
- if (ai->ai_canonname == NULL) {
- free(ai);
- return (NULL);
- }
- } else {
- ai->ai_canonname = NULL;
- }
- ai->ai_addr = (void *)(ai + 1);
- bcopy(addr, ai->ai_addr, addrlen);
- ai->ai_next = NULL;
-
- return (ai);
-}
-
-int
-cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
- const struct addrinfo *hints, struct addrinfo **res)
-{
- struct addrinfo *firstai, *prevai, *curai;
- unsigned int ii;
- const nvlist_t *nvlai;
- char nvlname[64];
- nvlist_t *nvl;
- int error, n;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "getaddrinfo");
- nvlist_add_string(nvl, "hostname", hostname);
- nvlist_add_string(nvl, "servname", servname);
- if (hints != NULL) {
- nvlist_add_number(nvl, "hints.ai_flags",
- (uint64_t)hints->ai_flags);
- nvlist_add_number(nvl, "hints.ai_family",
- (uint64_t)hints->ai_family);
- nvlist_add_number(nvl, "hints.ai_socktype",
- (uint64_t)hints->ai_socktype);
- nvlist_add_number(nvl, "hints.ai_protocol",
- (uint64_t)hints->ai_protocol);
- }
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (EAI_MEMORY);
- if (nvlist_get_number(nvl, "error") != 0) {
- error = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (error);
- }
-
- nvlai = NULL;
- firstai = prevai = curai = NULL;
- for (ii = 0; ; ii++) {
- n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- if (!nvlist_exists_nvlist(nvl, nvlname))
- break;
- nvlai = nvlist_get_nvlist(nvl, nvlname);
- curai = addrinfo_unpack(nvlai);
- if (curai == NULL)
- break;
- if (prevai != NULL)
- prevai->ai_next = curai;
- else if (firstai == NULL)
- firstai = curai;
- prevai = curai;
- }
- nvlist_destroy(nvl);
- if (curai == NULL && nvlai != NULL) {
- if (firstai == NULL)
- freeaddrinfo(firstai);
- return (EAI_MEMORY);
- }
-
- *res = firstai;
- return (0);
-}
-
-int
-cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen, char *serv, size_t servlen, int flags)
-{
- nvlist_t *nvl;
- int error;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "getnameinfo");
- nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen);
- nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
- nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
- nvlist_add_number(nvl, "flags", (uint64_t)flags);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (EAI_MEMORY);
- if (nvlist_get_number(nvl, "error") != 0) {
- error = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (error);
- }
-
- if (host != NULL)
- strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1);
- if (serv != NULL)
- strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1);
- nvlist_destroy(nvl);
- return (0);
-}
-
-static void
-limit_remove(nvlist_t *limits, const char *prefix)
-{
- const char *name;
- size_t prefixlen;
- void *cookie;
-
- prefixlen = strlen(prefix);
-again:
- cookie = NULL;
- while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
- if (strncmp(name, prefix, prefixlen) == 0) {
- nvlist_free(limits, name);
- goto again;
- }
- }
-}
-
-int
-cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
- size_t ntypes)
-{
- nvlist_t *limits;
- unsigned int i;
- char nvlname[64];
- int n;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL)
- limits = nvlist_create(0);
- else
- limit_remove(limits, "type");
- for (i = 0; i < ntypes; i++) {
- n = snprintf(nvlname, sizeof(nvlname), "type%u", i);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_string(limits, nvlname, types[i]);
- }
- return (cap_limit_set(chan, limits));
-}
-
-int
-cap_dns_family_limit(cap_channel_t *chan, const int *families,
- size_t nfamilies)
-{
- nvlist_t *limits;
- unsigned int i;
- char nvlname[64];
- int n;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL)
- limits = nvlist_create(0);
- else
- limit_remove(limits, "family");
- for (i = 0; i < nfamilies; i++) {
- n = snprintf(nvlname, sizeof(nvlname), "family%u", i);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_number(limits, nvlname, (uint64_t)families[i]);
- }
- return (cap_limit_set(chan, limits));
-}
Index: head/lib/libcapsicum/libcapsicum_grp.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_grp.h
+++ head/lib/libcapsicum/libcapsicum_grp.h
@@ -1,57 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_GRP_H_
-#define _LIBCAPSICUM_GRP_H_
-
-struct group *cap_getgrent(cap_channel_t *chan);
-struct group *cap_getgrnam(cap_channel_t *chan, const char *name);
-struct group *cap_getgrgid(cap_channel_t *chan, gid_t gid);
-
-int cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer,
- size_t bufsize, struct group **result);
-int cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp,
- char *buffer, size_t bufsize, struct group **result);
-int cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp,
- char *buffer, size_t bufsize, struct group **result);
-
-int cap_setgroupent(cap_channel_t *chan, int stayopen);
-int cap_setgrent(cap_channel_t *chan);
-void cap_endgrent(cap_channel_t *chan);
-
-int cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds,
- size_t ncmds);
-int cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
- size_t nfields);
-int cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
- size_t nnames, gid_t *gids, size_t ngids);
-
-#endif /* !_LIBCAPSICUM_GRP_H_ */
Index: head/lib/libcapsicum/libcapsicum_grp.c
===================================================================
--- head/lib/libcapsicum/libcapsicum_grp.c
+++ head/lib/libcapsicum/libcapsicum_grp.c
@@ -1,438 +0,0 @@
-/*-
- * 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/dnv.h>
-#include <sys/nv.h>
-#include <sys/param.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <grp.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "libcapsicum.h"
-#include "libcapsicum_grp.h"
-
-static struct group ggrp;
-static char *gbuffer;
-static size_t gbufsize;
-
-static int
-group_resize(void)
-{
- char *buf;
-
- if (gbufsize == 0)
- gbufsize = 1024;
- else
- gbufsize *= 2;
-
- buf = gbuffer;
- gbuffer = realloc(buf, gbufsize);
- if (gbuffer == NULL) {
- free(buf);
- gbufsize = 0;
- return (ENOMEM);
- }
- memset(gbuffer, 0, gbufsize);
-
- return (0);
-}
-
-static int
-group_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
- char **bufferp, size_t *bufsizep)
-{
- const char *str;
- size_t len;
-
- str = nvlist_get_string(nvl, fieldname);
- len = strlcpy(*bufferp, str, *bufsizep);
- if (len >= *bufsizep)
- return (ERANGE);
- *fieldp = *bufferp;
- *bufferp += len + 1;
- *bufsizep -= len + 1;
-
- return (0);
-}
-
-static int
-group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
- size_t *bufsizep)
-{
- const char *mem;
- char **outstrs, *str, nvlname[64];
- size_t nmem, datasize, strsize;
- unsigned int ii;
- int n;
-
- if (!nvlist_exists_number(nvl, "gr_nmem")) {
- datasize = _ALIGNBYTES + sizeof(char *);
- if (datasize >= *bufsizep)
- return (ERANGE);
- outstrs = (char **)_ALIGN(*bufferp);
- outstrs[0] = NULL;
- *fieldp = outstrs;
- *bufferp += datasize;
- *bufsizep -= datasize;
- return (0);
- }
-
- nmem = (size_t)nvlist_get_number(nvl, "gr_nmem");
- datasize = _ALIGNBYTES + sizeof(char *) * (nmem + 1);
- for (ii = 0; ii < nmem; ii++) {
- n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- mem = dnvlist_get_string(nvl, nvlname, NULL);
- if (mem == NULL)
- return (EINVAL);
- datasize += strlen(mem) + 1;
- }
-
- if (datasize >= *bufsizep)
- return (ERANGE);
-
- outstrs = (char **)_ALIGN(*bufferp);
- str = (char *)outstrs + sizeof(char *) * (nmem + 1);
- for (ii = 0; ii < nmem; ii++) {
- n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- mem = nvlist_get_string(nvl, nvlname);
- strsize = strlen(mem) + 1;
- memcpy(str, mem, strsize);
- outstrs[ii] = str;
- str += strsize;
- }
- assert(ii == nmem);
- outstrs[ii] = NULL;
-
- *fieldp = outstrs;
- *bufferp += datasize;
- *bufsizep -= datasize;
-
- return (0);
-}
-
-static int
-group_unpack(const nvlist_t *nvl, struct group *grp, char *buffer,
- size_t bufsize)
-{
- int error;
-
- if (!nvlist_exists_string(nvl, "gr_name"))
- return (EINVAL);
-
- memset(grp, 0, sizeof(*grp));
-
- error = group_unpack_string(nvl, "gr_name", &grp->gr_name, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- error = group_unpack_string(nvl, "gr_passwd", &grp->gr_passwd, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- grp->gr_gid = (gid_t)nvlist_get_number(nvl, "gr_gid");
- error = group_unpack_members(nvl, &grp->gr_mem, &buffer, &bufsize);
- if (error != 0)
- return (error);
-
- return (0);
-}
-
-static int
-cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name,
- gid_t gid, struct group *grp, char *buffer, size_t bufsize,
- struct group **result)
-{
- nvlist_t *nvl;
- bool getgr_r;
- int error;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", cmd);
- if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0) {
- /* Add nothing. */
- } else if (strcmp(cmd, "getgrnam") == 0 ||
- strcmp(cmd, "getgrnam_r") == 0) {
- nvlist_add_string(nvl, "name", name);
- } else if (strcmp(cmd, "getgrgid") == 0 ||
- strcmp(cmd, "getgrgid_r") == 0) {
- nvlist_add_number(nvl, "gid", (uint64_t)gid);
- } else {
- abort();
- }
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL) {
- assert(errno != 0);
- *result = NULL;
- return (errno);
- }
- error = (int)nvlist_get_number(nvl, "error");
- if (error != 0) {
- nvlist_destroy(nvl);
- *result = NULL;
- return (error);
- }
-
- if (!nvlist_exists_string(nvl, "gr_name")) {
- /* Not found. */
- nvlist_destroy(nvl);
- *result = NULL;
- return (0);
- }
-
- getgr_r = (strcmp(cmd, "getgrent_r") == 0 ||
- strcmp(cmd, "getgrnam_r") == 0 || strcmp(cmd, "getgrgid_r") == 0);
-
- for (;;) {
- error = group_unpack(nvl, grp, buffer, bufsize);
- if (getgr_r || error != ERANGE)
- break;
- assert(buffer == gbuffer);
- assert(bufsize == gbufsize);
- error = group_resize();
- if (error != 0)
- break;
- /* Update pointers after resize. */
- buffer = gbuffer;
- bufsize = gbufsize;
- }
-
- nvlist_destroy(nvl);
-
- if (error == 0)
- *result = grp;
- else
- *result = NULL;
-
- return (error);
-}
-
-static struct group *
-cap_getgrcommon(cap_channel_t *chan, const char *cmd, const char *name,
- gid_t gid)
-{
- struct group *result;
- int error, serrno;
-
- serrno = errno;
-
- error = cap_getgrcommon_r(chan, cmd, name, gid, &ggrp, gbuffer,
- gbufsize, &result);
- if (error != 0) {
- errno = error;
- return (NULL);
- }
-
- errno = serrno;
-
- return (result);
-}
-
-struct group *
-cap_getgrent(cap_channel_t *chan)
-{
-
- return (cap_getgrcommon(chan, "getgrent", NULL, 0));
-}
-
-struct group *
-cap_getgrnam(cap_channel_t *chan, const char *name)
-{
-
- return (cap_getgrcommon(chan, "getgrnam", name, 0));
-}
-
-struct group *
-cap_getgrgid(cap_channel_t *chan, gid_t gid)
-{
-
- return (cap_getgrcommon(chan, "getgrgid", NULL, gid));
-}
-
-int
-cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer,
- size_t bufsize, struct group **result)
-{
-
- return (cap_getgrcommon_r(chan, "getgrent_r", NULL, 0, grp, buffer,
- bufsize, result));
-}
-
-int
-cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp,
- char *buffer, size_t bufsize, struct group **result)
-{
-
- return (cap_getgrcommon_r(chan, "getgrnam_r", name, 0, grp, buffer,
- bufsize, result));
-}
-
-int
-cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp, char *buffer,
- size_t bufsize, struct group **result)
-{
-
- return (cap_getgrcommon_r(chan, "getgrgid_r", NULL, gid, grp, buffer,
- bufsize, result));
-}
-
-int
-cap_setgroupent(cap_channel_t *chan, int stayopen)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "setgroupent");
- nvlist_add_bool(nvl, "stayopen", stayopen != 0);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (0);
- if (nvlist_get_number(nvl, "error") != 0) {
- errno = nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (0);
- }
- nvlist_destroy(nvl);
-
- return (1);
-}
-
-int
-cap_setgrent(cap_channel_t *chan)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "setgrent");
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (0);
- if (nvlist_get_number(nvl, "error") != 0) {
- errno = nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (0);
- }
- nvlist_destroy(nvl);
-
- return (1);
-}
-
-void
-cap_endgrent(cap_channel_t *chan)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "endgrent");
- /* Ignore any errors, we have no way to report them. */
- nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
-}
-
-int
-cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
-{
- nvlist_t *limits, *nvl;
- unsigned int i;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL) {
- limits = nvlist_create(0);
- } else {
- if (nvlist_exists_nvlist(limits, "cmds"))
- nvlist_free_nvlist(limits, "cmds");
- }
- nvl = nvlist_create(0);
- for (i = 0; i < ncmds; i++)
- nvlist_add_null(nvl, cmds[i]);
- nvlist_move_nvlist(limits, "cmds", nvl);
- return (cap_limit_set(chan, limits));
-}
-
-int
-cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
- size_t nfields)
-{
- nvlist_t *limits, *nvl;
- unsigned int i;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL) {
- limits = nvlist_create(0);
- } else {
- if (nvlist_exists_nvlist(limits, "fields"))
- nvlist_free_nvlist(limits, "fields");
- }
- nvl = nvlist_create(0);
- for (i = 0; i < nfields; i++)
- nvlist_add_null(nvl, fields[i]);
- nvlist_move_nvlist(limits, "fields", nvl);
- return (cap_limit_set(chan, limits));
-}
-
-int
-cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
- size_t nnames, gid_t *gids, size_t ngids)
-{
- nvlist_t *limits, *groups;
- unsigned int i;
- char nvlname[64];
- int n;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL) {
- limits = nvlist_create(0);
- } else {
- if (nvlist_exists_nvlist(limits, "groups"))
- nvlist_free_nvlist(limits, "groups");
- }
- groups = nvlist_create(0);
- for (i = 0; i < ngids; i++) {
- n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_number(groups, nvlname, (uint64_t)gids[i]);
- }
- for (i = 0; i < nnames; i++) {
- n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_string(groups, nvlname, names[i]);
- }
- nvlist_move_nvlist(limits, "groups", groups);
- return (cap_limit_set(chan, limits));
-}
Index: head/lib/libcapsicum/libcapsicum_impl.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_impl.h
+++ head/lib/libcapsicum/libcapsicum_impl.h
@@ -1,39 +0,0 @@
-/*-
- * Copyright (c) 2012-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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_IMPL_H_
-#define _LIBCAPSICUM_IMPL_H_
-
-#define CASPER_SOCKPATH "/var/run/casper"
-
-bool fd_is_valid(int fd);
-
-#endif /* !_LIBCAPSICUM_IMPL_H_ */
Index: head/lib/libcapsicum/libcapsicum_pwd.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_pwd.h
+++ head/lib/libcapsicum/libcapsicum_pwd.h
@@ -1,57 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_PWD_H_
-#define _LIBCAPSICUM_PWD_H_
-
-struct passwd *cap_getpwent(cap_channel_t *chan);
-struct passwd *cap_getpwnam(cap_channel_t *chan, const char *login);
-struct passwd *cap_getpwuid(cap_channel_t *chan, uid_t uid);
-
-int cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
- size_t bufsize, struct passwd **result);
-int cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
- char *buffer, size_t bufsize, struct passwd **result);
-int cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd,
- char *buffer, size_t bufsize, struct passwd **result);
-
-int cap_setpassent(cap_channel_t *chan, int stayopen);
-void cap_setpwent(cap_channel_t *chan);
-void cap_endpwent(cap_channel_t *chan);
-
-int cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds,
- size_t ncmds);
-int cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
- size_t nfields);
-int cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
- size_t nnames, uid_t *uids, size_t nuids);
-
-#endif /* !_LIBCAPSICUM_PWD_H_ */
Index: head/lib/libcapsicum/libcapsicum_pwd.c
===================================================================
--- head/lib/libcapsicum/libcapsicum_pwd.c
+++ head/lib/libcapsicum/libcapsicum_pwd.c
@@ -1,391 +0,0 @@
-/*-
- * 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/nv.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <pwd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "libcapsicum.h"
-#include "libcapsicum_pwd.h"
-
-static struct passwd gpwd;
-static char *gbuffer;
-static size_t gbufsize;
-
-static int
-passwd_resize(void)
-{
- char *buf;
-
- if (gbufsize == 0)
- gbufsize = 1024;
- else
- gbufsize *= 2;
-
- buf = gbuffer;
- gbuffer = realloc(buf, gbufsize);
- if (gbuffer == NULL) {
- free(buf);
- gbufsize = 0;
- return (ENOMEM);
- }
- memset(gbuffer, 0, gbufsize);
-
- return (0);
-}
-
-static int
-passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
- char **bufferp, size_t *bufsizep)
-{
- const char *str;
- size_t len;
-
- str = nvlist_get_string(nvl, fieldname);
- len = strlcpy(*bufferp, str, *bufsizep);
- if (len >= *bufsizep)
- return (ERANGE);
- *fieldp = *bufferp;
- *bufferp += len + 1;
- *bufsizep -= len + 1;
-
- return (0);
-}
-
-static int
-passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
- size_t bufsize)
-{
- int error;
-
- if (!nvlist_exists_string(nvl, "pw_name"))
- return (EINVAL);
-
- memset(pwd, 0, sizeof(*pwd));
-
- error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
- pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
- pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
- error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
- &bufsize);
- if (error != 0)
- return (error);
- pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
- pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
-
- return (0);
-}
-
-static int
-cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
- uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
- struct passwd **result)
-{
- nvlist_t *nvl;
- bool getpw_r;
- int error;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", cmd);
- if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
- /* Add nothing. */
- } else if (strcmp(cmd, "getpwnam") == 0 ||
- strcmp(cmd, "getpwnam_r") == 0) {
- nvlist_add_string(nvl, "name", login);
- } else if (strcmp(cmd, "getpwuid") == 0 ||
- strcmp(cmd, "getpwuid_r") == 0) {
- nvlist_add_number(nvl, "uid", (uint64_t)uid);
- } else {
- abort();
- }
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL) {
- assert(errno != 0);
- *result = NULL;
- return (errno);
- }
- error = (int)nvlist_get_number(nvl, "error");
- if (error != 0) {
- nvlist_destroy(nvl);
- *result = NULL;
- return (error);
- }
-
- if (!nvlist_exists_string(nvl, "pw_name")) {
- /* Not found. */
- nvlist_destroy(nvl);
- *result = NULL;
- return (0);
- }
-
- getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
- strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
-
- for (;;) {
- error = passwd_unpack(nvl, pwd, buffer, bufsize);
- if (getpw_r || error != ERANGE)
- break;
- assert(buffer == gbuffer);
- assert(bufsize == gbufsize);
- error = passwd_resize();
- if (error != 0)
- break;
- /* Update pointers after resize. */
- buffer = gbuffer;
- bufsize = gbufsize;
- }
-
- nvlist_destroy(nvl);
-
- if (error == 0)
- *result = pwd;
- else
- *result = NULL;
-
- return (error);
-}
-
-static struct passwd *
-cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
- uid_t uid)
-{
- struct passwd *result;
- int error, serrno;
-
- serrno = errno;
-
- error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
- gbufsize, &result);
- if (error != 0) {
- errno = error;
- return (NULL);
- }
-
- errno = serrno;
-
- return (result);
-}
-
-struct passwd *
-cap_getpwent(cap_channel_t *chan)
-{
-
- return (cap_getpwcommon(chan, "getpwent", NULL, 0));
-}
-
-struct passwd *
-cap_getpwnam(cap_channel_t *chan, const char *login)
-{
-
- return (cap_getpwcommon(chan, "getpwnam", login, 0));
-}
-
-struct passwd *
-cap_getpwuid(cap_channel_t *chan, uid_t uid)
-{
-
- return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
-}
-
-int
-cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
- size_t bufsize, struct passwd **result)
-{
-
- return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
- bufsize, result));
-}
-
-int
-cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
- char *buffer, size_t bufsize, struct passwd **result)
-{
-
- return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
- bufsize, result));
-}
-
-int
-cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
- size_t bufsize, struct passwd **result)
-{
-
- return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
- bufsize, result));
-}
-
-int
-cap_setpassent(cap_channel_t *chan, int stayopen)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "setpassent");
- nvlist_add_bool(nvl, "stayopen", stayopen != 0);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (0);
- if (nvlist_get_number(nvl, "error") != 0) {
- errno = nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (0);
- }
- nvlist_destroy(nvl);
-
- return (1);
-}
-
-static void
-cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", cmd);
- /* Ignore any errors, we have no way to report them. */
- nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
-}
-
-void
-cap_setpwent(cap_channel_t *chan)
-{
-
- cap_set_end_pwent(chan, "setpwent");
-}
-
-void
-cap_endpwent(cap_channel_t *chan)
-{
-
- cap_set_end_pwent(chan, "endpwent");
-}
-
-int
-cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
-{
- nvlist_t *limits, *nvl;
- unsigned int i;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL) {
- limits = nvlist_create(0);
- } else {
- if (nvlist_exists_nvlist(limits, "cmds"))
- nvlist_free_nvlist(limits, "cmds");
- }
- nvl = nvlist_create(0);
- for (i = 0; i < ncmds; i++)
- nvlist_add_null(nvl, cmds[i]);
- nvlist_move_nvlist(limits, "cmds", nvl);
- return (cap_limit_set(chan, limits));
-}
-
-int
-cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
- size_t nfields)
-{
- nvlist_t *limits, *nvl;
- unsigned int i;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL) {
- limits = nvlist_create(0);
- } else {
- if (nvlist_exists_nvlist(limits, "fields"))
- nvlist_free_nvlist(limits, "fields");
- }
- nvl = nvlist_create(0);
- for (i = 0; i < nfields; i++)
- nvlist_add_null(nvl, fields[i]);
- nvlist_move_nvlist(limits, "fields", nvl);
- return (cap_limit_set(chan, limits));
-}
-
-int
-cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
- size_t nnames, uid_t *uids, size_t nuids)
-{
- nvlist_t *limits, *users;
- char nvlname[64];
- unsigned int i;
- int n;
-
- if (cap_limit_get(chan, &limits) < 0)
- return (-1);
- if (limits == NULL) {
- limits = nvlist_create(0);
- } else {
- if (nvlist_exists_nvlist(limits, "users"))
- nvlist_free_nvlist(limits, "users");
- }
- users = nvlist_create(0);
- for (i = 0; i < nuids; i++) {
- n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
- }
- for (i = 0; i < nnames; i++) {
- n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_string(users, nvlname, names[i]);
- }
- nvlist_move_nvlist(limits, "users", users);
- return (cap_limit_set(chan, limits));
-}
Index: head/lib/libcapsicum/libcapsicum_random.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_random.h
+++ head/lib/libcapsicum/libcapsicum_random.h
@@ -1,37 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_RANDOM_H_
-#define _LIBCAPSICUM_RANDOM_H_
-
-int cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes);
-
-#endif /* !_LIBCAPSICUM_RANDOM_H_ */
Index: head/lib/libcapsicum/libcapsicum_random.c
===================================================================
--- head/lib/libcapsicum/libcapsicum_random.c
+++ head/lib/libcapsicum/libcapsicum_random.c
@@ -1,80 +0,0 @@
-/*-
- * 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/nv.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include "libcapsicum.h"
-#include "libcapsicum_random.h"
-
-#define MAXSIZE (1024 * 1024)
-
-int
-cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes)
-{
- nvlist_t *nvl;
- const void *randbuf;
- uint8_t *ptr;
- size_t left, randbufsize;
-
- left = nbytes;
- ptr = buf;
-
- while (left > 0) {
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "generate");
- nvlist_add_number(nvl, "size",
- (uint64_t)(left > MAXSIZE ? MAXSIZE : left));
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (-1);
- if (nvlist_get_number(nvl, "error") != 0) {
- errno = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (-1);
- }
-
- randbuf = nvlist_get_binary(nvl, "data", &randbufsize);
- memcpy(ptr, randbuf, randbufsize);
-
- nvlist_destroy(nvl);
-
- ptr += randbufsize;
- assert(left >= randbufsize);
- left -= randbufsize;
- }
-
- return (0);
-}
Index: head/lib/libcapsicum/libcapsicum_service.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_service.h
+++ head/lib/libcapsicum/libcapsicum_service.h
@@ -1,40 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_SERVICE_H_
-#define _LIBCAPSICUM_SERVICE_H_
-
-cap_channel_t *cap_service_open(const cap_channel_t *chan, const char *name);
-
-int cap_service_limit(const cap_channel_t *chan, const char * const *names,
- size_t nnames);
-
-#endif /* !_LIBCAPSICUM_SERVICE_H_ */
Index: head/lib/libcapsicum/libcapsicum_service.c
===================================================================
--- head/lib/libcapsicum/libcapsicum_service.c
+++ head/lib/libcapsicum/libcapsicum_service.c
@@ -1,97 +0,0 @@
-/*-
- * 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/nv.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "msgio.h"
-
-#include "libcapsicum.h"
-#include "libcapsicum_impl.h"
-#include "libcapsicum_service.h"
-
-cap_channel_t *
-cap_service_open(const cap_channel_t *chan, const char *name)
-{
- cap_channel_t *newchan;
- nvlist_t *nvl;
- int sock, error;
-
- sock = -1;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "open");
- nvlist_add_string(nvl, "service", name);
- if (fd_is_valid(STDERR_FILENO))
- nvlist_add_descriptor(nvl, "stderrfd", STDERR_FILENO);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (NULL);
- error = (int)nvlist_get_number(nvl, "error");
- if (error != 0) {
- nvlist_destroy(nvl);
- errno = error;
- return (NULL);
- }
- sock = nvlist_take_descriptor(nvl, "chanfd");
- assert(sock >= 0);
- nvlist_destroy(nvl);
- nvl = NULL;
- if (cred_send(sock) == -1)
- goto fail;
- newchan = cap_wrap(sock);
- if (newchan == NULL)
- goto fail;
- return (newchan);
-fail:
- error = errno;
- close(sock);
- errno = error;
- return (NULL);
-}
-
-int
-cap_service_limit(const cap_channel_t *chan, const char * const *names,
- size_t nnames)
-{
- nvlist_t *limits;
- unsigned int i;
-
- limits = nvlist_create(0);
- for (i = 0; i < nnames; i++)
- nvlist_add_null(limits, names[i]);
- return (cap_limit_set(chan, limits));
-}
Index: head/lib/libcapsicum/libcapsicum_sysctl.h
===================================================================
--- head/lib/libcapsicum/libcapsicum_sysctl.h
+++ head/lib/libcapsicum/libcapsicum_sysctl.h
@@ -1,43 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCAPSICUM_SYSCTL_H_
-#define _LIBCAPSICUM_SYSCTL_H_
-
-#define CAP_SYSCTL_READ 0x01
-#define CAP_SYSCTL_WRITE 0x02
-#define CAP_SYSCTL_RDWR (CAP_SYSCTL_READ | CAP_SYSCTL_WRITE)
-#define CAP_SYSCTL_RECURSIVE 0x04
-
-int cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
- size_t *oldlenp, const void *newp, size_t newlen);
-
-#endif /* !_LIBCAPSICUM_SYSCTL_H_ */
Index: head/lib/libcapsicum/libcapsicum_sysctl.c
===================================================================
--- head/lib/libcapsicum/libcapsicum_sysctl.c
+++ head/lib/libcapsicum/libcapsicum_sysctl.c
@@ -1,86 +0,0 @@
-/*-
- * 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/nv.h>
-
-#include <errno.h>
-#include <string.h>
-
-#include "libcapsicum.h"
-#include "libcapsicum_sysctl.h"
-
-int
-cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
- size_t *oldlenp, const void *newp, size_t newlen)
-{
- nvlist_t *nvl;
- const uint8_t *retoldp;
- uint8_t operation;
- size_t oldlen;
-
- operation = 0;
- if (oldp != NULL)
- operation |= CAP_SYSCTL_READ;
- if (newp != NULL)
- operation |= CAP_SYSCTL_WRITE;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "cmd", "sysctl");
- nvlist_add_string(nvl, "name", name);
- nvlist_add_number(nvl, "operation", (uint64_t)operation);
- if (oldp == NULL && oldlenp != NULL)
- nvlist_add_null(nvl, "justsize");
- else if (oldlenp != NULL)
- nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
- if (newp != NULL)
- nvlist_add_binary(nvl, "newp", newp, newlen);
- nvl = cap_xfer_nvlist(chan, nvl, 0);
- if (nvl == NULL)
- return (-1);
- if (nvlist_get_number(nvl, "error") != 0) {
- errno = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- return (-1);
- }
-
- if (oldp == NULL && oldlenp != NULL) {
- *oldlenp = (size_t)nvlist_get_number(nvl, "oldlen");
- } else if (oldp != NULL) {
- retoldp = nvlist_get_binary(nvl, "oldp", &oldlen);
- memcpy(oldp, retoldp, oldlen);
- if (oldlenp != NULL)
- *oldlenp = oldlen;
- }
- nvlist_destroy(nvl);
-
- return (0);
-}
Index: head/lib/libcasper/Makefile
===================================================================
--- head/lib/libcasper/Makefile
+++ head/lib/libcasper/Makefile
@@ -1,19 +1,6 @@
# $FreeBSD$
-LIB= casper
+SUBDIR= libcasper
+SUBDIR+= services
-SHLIB_MAJOR= 0
-SHLIBDIR?= /lib
-
-SRCS= libcasper.c
-INCS= libcasper.h
-
-LIBADD= capsicum nv pjdlog
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../libpjdlog
-CFLAGS+=-I${.CURDIR}/../../sbin/casper
-
-WARNS?= 6
-
-.include <bsd.lib.mk>
+.include <bsd.subdir.mk>
Index: head/lib/libcasper/libcasper.h
===================================================================
--- head/lib/libcasper/libcasper.h
+++ head/lib/libcasper/libcasper.h
@@ -1,70 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCASPER_H_
-#define _LIBCASPER_H_
-
-#ifndef _NVLIST_T_DECLARED
-#define _NVLIST_T_DECLARED
-struct nvlist;
-
-typedef struct nvlist nvlist_t;
-#endif
-
-#define PARENT_FILENO 3
-#define EXECUTABLE_FILENO 4
-#define PROC_FILENO 5
-
-struct service;
-struct service_connection;
-
-typedef int service_limit_func_t(const nvlist_t *, const nvlist_t *);
-typedef int service_command_func_t(const char *cmd, const nvlist_t *,
- nvlist_t *, nvlist_t *);
-
-struct service_connection *service_connection_add(struct service *service,
- int sock, const nvlist_t *limits);
-void service_connection_remove(struct service *service,
- struct service_connection *sconn);
-int service_connection_clone(struct service *service,
- struct service_connection *sconn);
-struct service_connection *service_connection_first(struct service *service);
-struct service_connection *service_connection_next(struct service_connection *sconn);
-cap_channel_t *service_connection_get_chan(const struct service_connection *sconn);
-int service_connection_get_sock(const struct service_connection *sconn);
-const nvlist_t *service_connection_get_limits(const struct service_connection *sconn);
-void service_connection_set_limits(struct service_connection *sconn,
- nvlist_t *limits);
-
-int service_start(const char *name, int sock, service_limit_func_t *limitfunc,
- service_command_func_t *commandfunc, int argc, char *argv[]);
-
-#endif /* !_LIBCASPER_H_ */
Index: head/lib/libcasper/libcasper.c
===================================================================
--- head/lib/libcasper/libcasper.c
+++ head/lib/libcasper/libcasper.c
@@ -1,441 +0,0 @@
-/*-
- * 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/capsicum.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <sys/nv.h>
-
-#include <assert.h>
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include <libcapsicum.h>
-#include <libcasper.h>
-#include <libcasper_impl.h>
-#include <pjdlog.h>
-
-/*
- * Currently there is only one service_connection per service.
- * In the future we may want multiple connections from multiple clients
- * per one service instance, but it has to be carefully designed.
- * The problem is that we may restrict/sandbox service instance according
- * to the limits provided. When new connection comes in with different
- * limits we won't be able to access requested resources.
- * Not to mention one process will serve to mutiple mutually untrusted
- * clients and compromise of this service instance by one of its clients
- * can lead to compromise of the other clients.
- */
-
-/*
- * Client connections to the given service.
- */
-#define SERVICE_CONNECTION_MAGIC 0x5e91c0ec
-struct service_connection {
- int sc_magic;
- cap_channel_t *sc_chan;
- nvlist_t *sc_limits;
- TAILQ_ENTRY(service_connection) sc_next;
-};
-
-#define SERVICE_MAGIC 0x5e91ce
-struct service {
- int s_magic;
- char *s_name;
- service_limit_func_t *s_limit;
- service_command_func_t *s_command;
- TAILQ_HEAD(, service_connection) s_connections;
-};
-
-struct service *
-service_alloc(const char *name, service_limit_func_t *limitfunc,
- service_command_func_t *commandfunc)
-{
- struct service *service;
-
- service = malloc(sizeof(*service));
- if (service == NULL)
- return (NULL);
- service->s_name = strdup(name);
- if (service->s_name == NULL) {
- free(service);
- return (NULL);
- }
- service->s_limit = limitfunc;
- service->s_command = commandfunc;
- TAILQ_INIT(&service->s_connections);
- service->s_magic = SERVICE_MAGIC;
-
- return (service);
-}
-
-void
-service_free(struct service *service)
-{
- struct service_connection *sconn;
-
- PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
-
- service->s_magic = 0;
- while ((sconn = service_connection_first(service)) != NULL)
- service_connection_remove(service, sconn);
- free(service->s_name);
- free(service);
-}
-
-struct service_connection *
-service_connection_add(struct service *service, int sock,
- const nvlist_t *limits)
-{
- struct service_connection *sconn;
- int serrno;
-
- PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
-
- sconn = malloc(sizeof(*sconn));
- if (sconn == NULL) {
- pjdlog_error("Unable to allocate memory for service connection.");
- return (NULL);
- }
- sconn->sc_chan = cap_wrap(sock);
- if (sconn->sc_chan == NULL) {
- serrno = errno;
- pjdlog_error("Unable to wrap communication channel.");
- free(sconn);
- errno = serrno;
- return (NULL);
- }
- if (limits == NULL) {
- sconn->sc_limits = NULL;
- } else {
- sconn->sc_limits = nvlist_clone(limits);
- if (sconn->sc_limits == NULL) {
- serrno = errno;
- pjdlog_error("Unable to clone limits.");
- (void)cap_unwrap(sconn->sc_chan);
- free(sconn);
- errno = serrno;
- return (NULL);
- }
- }
- sconn->sc_magic = SERVICE_CONNECTION_MAGIC;
- TAILQ_INSERT_TAIL(&service->s_connections, sconn, sc_next);
- return (sconn);
-}
-
-void
-service_connection_remove(struct service *service,
- struct service_connection *sconn)
-{
-
- PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
- PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
-
- TAILQ_REMOVE(&service->s_connections, sconn, sc_next);
- sconn->sc_magic = 0;
- nvlist_destroy(sconn->sc_limits);
- cap_close(sconn->sc_chan);
- free(sconn);
-}
-
-int
-service_connection_clone(struct service *service,
- struct service_connection *sconn)
-{
- struct service_connection *newsconn;
- int serrno, sock[2];
-
- if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sock) < 0)
- return (-1);
-
- newsconn = service_connection_add(service, sock[0],
- service_connection_get_limits(sconn));
- if (newsconn == NULL) {
- serrno = errno;
- close(sock[0]);
- close(sock[1]);
- errno = serrno;
- return (-1);
- }
-
- return (sock[1]);
-}
-
-struct service_connection *
-service_connection_first(struct service *service)
-{
- struct service_connection *sconn;
-
- PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
-
- sconn = TAILQ_FIRST(&service->s_connections);
- PJDLOG_ASSERT(sconn == NULL ||
- sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
- return (sconn);
-}
-
-struct service_connection *
-service_connection_next(struct service_connection *sconn)
-{
-
- PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
-
- sconn = TAILQ_NEXT(sconn, sc_next);
- PJDLOG_ASSERT(sconn == NULL ||
- sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
- return (sconn);
-}
-
-cap_channel_t *
-service_connection_get_chan(const struct service_connection *sconn)
-{
-
- PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
-
- return (sconn->sc_chan);
-}
-
-int
-service_connection_get_sock(const struct service_connection *sconn)
-{
-
- PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
-
- return (cap_sock(sconn->sc_chan));
-}
-
-const nvlist_t *
-service_connection_get_limits(const struct service_connection *sconn)
-{
-
- PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
-
- return (sconn->sc_limits);
-}
-
-void
-service_connection_set_limits(struct service_connection *sconn,
- nvlist_t *limits)
-{
-
- PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
-
- nvlist_destroy(sconn->sc_limits);
- sconn->sc_limits = limits;
-}
-
-#if 0
-static void
-casper_message_connection(struct service *service, const nvlist_t *nvl)
-{
-
- service_connection_add(&service->s_connections,
- nvlist_get_descriptor(nvl, "sock"));
-}
-
-static void
-casper_message(const cap_channel_t *capcas, struct service *service)
-{
- const char *cmd;
- nvlist_t *nvl;
-
- nvl = cap_recv_nvlist(capcas, 0);
- if (nvl == NULL)
- pjdlog_exit(1, "Unable to receive message from Casper");
- cmd = nvlist_get_string(nvl, "cmd");
- if (strcmp(cmd, "connection") == 0)
- casper_message_connection(service, nvl);
- else
- PJDLOG_ABORT("Unknown command from Casper: %s.", cmd);
-}
-#endif
-
-void
-service_message(struct service *service, struct service_connection *sconn)
-{
- nvlist_t *nvlin, *nvlout;
- const char *cmd;
- int error;
-
- nvlin = cap_recv_nvlist(service_connection_get_chan(sconn), 0);
- if (nvlin == NULL) {
- if (errno == ENOTCONN) {
- pjdlog_debug(1, "Connection closed by the client.");
- } else {
- pjdlog_errno(LOG_ERR,
- "Unable to receive message from client");
- }
- service_connection_remove(service, sconn);
- return;
- }
-
- error = EDOOFUS;
- nvlout = nvlist_create(0);
-
- cmd = nvlist_get_string(nvlin, "cmd");
- pjdlog_debug(1, "Command received from client: %s.", cmd);
- if (pjdlog_debug_get() >= 2)
- nvlist_fdump(nvlin, stderr);
- if (strcmp(cmd, "limit_set") == 0) {
- nvlist_t *nvllim;
-
- nvllim = nvlist_take_nvlist(nvlin, "limits");
- error = service->s_limit(service_connection_get_limits(sconn),
- nvllim);
- if (error == 0) {
- service_connection_set_limits(sconn, nvllim);
- /* Function consumes nvllim. */
- } else {
- nvlist_destroy(nvllim);
- }
- } else if (strcmp(cmd, "limit_get") == 0) {
- const nvlist_t *nvllim;
-
- nvllim = service_connection_get_limits(sconn);
- if (nvllim != NULL)
- nvlist_add_nvlist(nvlout, "limits", nvllim);
- else
- nvlist_add_null(nvlout, "limits");
- error = 0;
- } else if (strcmp(cmd, "clone") == 0) {
- int sock;
-
- sock = service_connection_clone(service, sconn);
- if (sock == -1) {
- error = errno;
- } else {
- nvlist_move_descriptor(nvlout, "sock", sock);
- error = 0;
- }
- } else {
- error = service->s_command(cmd,
- service_connection_get_limits(sconn), nvlin, nvlout);
- }
-
- nvlist_destroy(nvlin);
- nvlist_add_number(nvlout, "error", (uint64_t)error);
- pjdlog_debug(1, "Sending reply to client (error=%d).", error);
- if (pjdlog_debug_get() >= 2)
- nvlist_fdump(nvlout, stderr);
-
- if (cap_send_nvlist(service_connection_get_chan(sconn), nvlout) == -1) {
- pjdlog_errno(LOG_ERR, "Unable to send message to client");
- service_connection_remove(service, sconn);
- }
-
- nvlist_destroy(nvlout);
-}
-
-static int
-fd_add(fd_set *fdsp, int maxfd, int fd)
-{
-
- FD_SET(fd, fdsp);
- return (fd > maxfd ? fd : maxfd);
-}
-
-int
-service_start(const char *name, int sock, service_limit_func_t *limitfunc,
- service_command_func_t *commandfunc, int argc, char *argv[])
-{
- struct service *service;
- struct service_connection *sconn, *sconntmp;
- fd_set fds;
- int maxfd, nfds, serrno;
-
- assert(argc == 2);
-
- pjdlog_init(PJDLOG_MODE_STD);
- pjdlog_debug_set(atoi(argv[1]));
-
- service = service_alloc(name, limitfunc, commandfunc);
- if (service == NULL)
- return (errno);
- if (service_connection_add(service, sock, NULL) == NULL) {
- serrno = errno;
- service_free(service);
- return (serrno);
- }
-
- for (;;) {
- FD_ZERO(&fds);
- maxfd = -1;
- for (sconn = service_connection_first(service); sconn != NULL;
- sconn = service_connection_next(sconn)) {
- maxfd = fd_add(&fds, maxfd,
- service_connection_get_sock(sconn));
- }
-
- PJDLOG_ASSERT(maxfd >= 0);
- PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE);
- nfds = select(maxfd + 1, &fds, NULL, NULL, NULL);
- if (nfds < 0) {
- if (errno != EINTR)
- pjdlog_errno(LOG_ERR, "select() failed");
- continue;
- } else if (nfds == 0) {
- /* Timeout. */
- PJDLOG_ABORT("select() timeout");
- continue;
- }
-
- for (sconn = service_connection_first(service); sconn != NULL;
- sconn = sconntmp) {
- /*
- * Prepare for connection to be removed from the list
- * on failure.
- */
- sconntmp = service_connection_next(sconn);
- if (FD_ISSET(service_connection_get_sock(sconn), &fds))
- service_message(service, sconn);
- }
- if (service_connection_first(service) == NULL) {
- /*
- * No connections left, exiting.
- */
- break;
- }
- }
-
- return (0);
-}
Index: head/lib/libcasper/libcasper/Makefile
===================================================================
--- head/lib/libcasper/libcasper/Makefile
+++ head/lib/libcasper/libcasper/Makefile
@@ -0,0 +1,38 @@
+# $FreeBSD$
+
+LIB= casper
+
+SHLIB_MAJOR= 0
+SHLIBDIR?= /lib
+
+SRCS= libcasper.c
+SRCS+= libcasper_impl.c
+SRCS+= libcasper_service.c
+SRCS+= service.c
+SRCS+= zygote.c
+
+INCS= libcasper.h
+INCS+= libcasper_service.h
+
+LIBADD= nv
+
+CFLAGS+=-I${.CURDIR}
+
+WARNS?= 6
+
+MAN+= libcasper.3
+
+MLINKS+=libcasper.3 cap_init.3
+MLINKS+=libcasper.3 cap_wrap.3
+MLINKS+=libcasper.3 cap_unwrap.3
+MLINKS+=libcasper.3 cap_sock.3
+MLINKS+=libcasper.3 cap_clone.3
+MLINKS+=libcasper.3 cap_close.3
+MLINKS+=libcasper.3 cap_limit_get.3
+MLINKS+=libcasper.3 cap_limit_set.3
+MLINKS+=libcasper.3 cap_send_nvlist.3
+MLINKS+=libcasper.3 cap_recv_nvlist.3
+MLINKS+=libcasper.3 cap_xfer_nvlist.3
+MLINKS+=libcasper.3 cap_service_open.3
+
+.include <bsd.lib.mk>
Index: head/lib/libcasper/libcasper/libcasper.h
===================================================================
--- head/lib/libcasper/libcasper/libcasper.h
+++ head/lib/libcasper/libcasper/libcasper.h
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2012-2013 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBCASPER_H_
+#define _LIBCASPER_H_
+
+#include <sys/types.h>
+
+#ifndef _NVLIST_T_DECLARED
+#define _NVLIST_T_DECLARED
+struct nvlist;
+
+typedef struct nvlist nvlist_t;
+#endif
+
+#ifndef _CAP_CHANNEL_T_DECLARED
+#define _CAP_CHANNEL_T_DECLARED
+struct cap_channel;
+
+typedef struct cap_channel cap_channel_t;
+#endif
+
+/*
+ * The functions opens unrestricted communication channel to Casper.
+ */
+cap_channel_t *cap_init(void);
+
+/*
+ * The functions to communicate with service.
+ */
+cap_channel_t *cap_service_open(const cap_channel_t *chan, const char *name);
+int cap_service_limit(const cap_channel_t *chan,
+ const char * const *names, size_t nnames);
+
+/*
+ * The function creates cap_channel_t based on the given socket.
+ */
+cap_channel_t *cap_wrap(int sock);
+
+/*
+ * The function returns communication socket and frees cap_channel_t.
+ */
+int cap_unwrap(cap_channel_t *chan);
+
+/*
+ * The function clones the given capability.
+ */
+cap_channel_t *cap_clone(const cap_channel_t *chan);
+
+/*
+ * The function closes the given capability.
+ */
+void cap_close(cap_channel_t *chan);
+
+/*
+ * The function returns socket descriptor associated with the given
+ * cap_channel_t for use with select(2)/kqueue(2)/etc.
+ */
+int cap_sock(const cap_channel_t *chan);
+
+/*
+ * The function limits the given capability.
+ * It always destroys 'limits' on return.
+ */
+int cap_limit_set(const cap_channel_t *chan, nvlist_t *limits);
+
+/*
+ * The function returns current limits of the given capability.
+ */
+int cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp);
+
+/*
+ * Function sends nvlist over the given capability.
+ */
+int cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl);
+/*
+ * Function receives nvlist over the given capability.
+ */
+nvlist_t *cap_recv_nvlist(const cap_channel_t *chan, int flags);
+/*
+ * Function sends the given nvlist, destroys it and receives new nvlist in
+ * response over the given capability.
+ */
+nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags);
+
+#endif /* !_LIBCASPER_H_ */
Index: head/lib/libcasper/libcasper/libcasper.3
===================================================================
--- head/lib/libcasper/libcasper/libcasper.3
+++ head/lib/libcasper/libcasper/libcasper.3
@@ -0,0 +1,295 @@
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 25, 2016
+.Dt LIBCASPER 3
+.Os
+.Sh NAME
+.Nm cap_init ,
+.Nm cap_wrap ,
+.Nm cap_unwrap ,
+.Nm cap_sock ,
+.Nm cap_clone ,
+.Nm cap_close ,
+.Nm cap_limit_get ,
+.Nm cap_limit_set ,
+.Nm cap_send_nvlist ,
+.Nm cap_recv_nvlist ,
+.Nm cap_xfer_nvlist ,
+.Nm cap_service_open
+.Nd "library for handling application capabilities"
+.Sh LIBRARY
+.Lb libcasper
+.Sh SYNOPSIS
+.In libcasper.h
+.In nv.h
+.Ft "cap_channel_t *"
+.Fn cap_init "void"
+.Ft "cap_channel_t *"
+.Fn cap_wrap "int sock"
+.Ft "int"
+.Fn cap_unwrap "cap_channel_t *chan"
+.Ft "int"
+.Fn cap_sock "const cap_channel_t *chan"
+.Ft "cap_channel_t *"
+.Fn cap_clone "const cap_channel_t *chan"
+.Ft "void"
+.Fn cap_close "cap_channel_t *chan"
+.Ft "int"
+.Fn cap_limit_get "const cap_channel_t *chan" "nvlist_t **limitsp"
+.Ft "int"
+.Fn cap_limit_set "const cap_channel_t *chan" "nvlist_t *limits"
+.Ft "int"
+.Fn cap_send_nvlist "const cap_channel_t *chan" "const nvlist_t *nvl"
+.Ft "nvlist_t *"
+.Fn cap_recv_nvlist "const cap_channel_t *chan" "int flags"
+.Ft "nvlist_t *"
+.Fn cap_xfer_nvlist "const cap_channel_t *chan" "nvlist_t *nvl" "int flags"
+.Ft "cap_channel_t *"
+.Fn cap_service_open "const cap_channel_t *chan" "const char *name"
+.Sh DESCRIPTION
+The
+.Nm libcapsicum
+library allows to manage application capabilities through the casper process.
+.Pp
+The application capability (represented by the
+.Vt cap_channel_t
+type) is a communication channel between the caller and the casper process
+daemon or an instance of one of its services.
+A capability to the casper process obtained with the
+.Fn cap_init
+function allows to create capabilities to casper's services via the
+.Fn cap_service_open
+function.
+.Pp
+The
+.Fn cap_init
+function opens capability to the casper process.
+.Pp
+The
+.Fn cap_wrap
+function creates
+.Vt cap_channel_t
+based on the given socket.
+The function is used when capability is inherited through
+.Xr execve 2
+or send over
+.Xr unix 4
+domain socket as a regular file descriptor and has to be represented as
+.Vt cap_channel_t
+again.
+.Pp
+The
+.Fn cap_unwrap
+function is the opposite of the
+.Fn cap_wrap
+function.
+It frees the
+.Vt cap_channel_t
+structure and returns
+.Xr unix 4
+domain socket associated with it.
+.Pp
+The
+.Fn cap_clone
+function clones the given capability.
+.Pp
+The
+.Fn cap_close
+function closes the given capability.
+.Pp
+The
+.Fn cap_sock
+function returns
+.Xr unix 4
+domain socket descriptor associated with the given capability for use with
+system calls like
+.Xr kevent 2 ,
+.Xr poll 2
+and
+.Xr select 2 .
+.Pp
+The
+.Fn cap_limit_get
+function stores current limits of the given capability in the
+.Fa limitsp
+argument.
+If the function return
+.Va 0
+and
+.Dv NULL
+is stored in
+.Fa limitsp
+it means there are no limits set.
+.Pp
+The
+.Fn cap_limit_set
+function sets limits for the given capability.
+The limits are provided as nvlist.
+The exact format depends on the service the capability represents.
+.Pp
+The
+.Fn cap_send_nvlist
+function sends the given nvlist over the given capability.
+This is low level interface to communicate with casper services.
+Most services should provide higher level API.
+.Pp
+The
+.Fn cap_recv_nvlist
+function receives the given nvlist over the given capability.
+The
+.Fa flags
+argument defines what type the top nvlist is expected to be.
+If the nvlist flags do not match the flags passed to
+.Fn cap_recv_nvlist ,
+the nvlist will not be returned.
+.Pp
+The
+.Fn cap_xfer_nvlist
+function sends the given nvlist, destroys it and receives new nvlist in
+response over the given capability.
+The
+.Fa flags
+argument defines what type the top nvlist is expected to be.
+If the nvlist flags do not match the flags passed to
+.Fn cap_xfer_nvlist ,
+the nvlist will not be returned.
+It does not matter if the function succeeds or fails, the nvlist given
+for sending will always be destroyed once the function returns.
+.Pp
+The
+.Fn cap_service_open
+function opens casper service of the given name through casper capability
+obtained via the
+.Fn cap_init
+function.
+The function returns capability that provides access to opened service.
+.Sh RETURN VALUES
+The
+.Fn cap_clone ,
+.Fn cap_init ,
+.Fn cap_recv_nvlist ,
+.Fn cap_service_open ,
+.Fn cap_wrap
+and
+.Fn cap_xfer_nvlist
+functions return
+.Dv NULL
+and set the
+.Va errno
+variable on failure.
+.Pp
+The
+.Fn cap_limit_get ,
+.Fn cap_limit_set
+and
+.Fn cap_send_nvlist
+functions return
+.Dv -1
+and set the
+.Va errno
+variable on failure.
+.Pp
+The
+.Fn cap_close ,
+.Fn cap_sock
+and
+.Fn cap_unwrap
+functions always succeed.
+.Sh EXAMPLES
+The following example first opens capability to the casper then using this
+capability creates new capability to the
+.Nm system.dns
+casper service and uses the latter capability to resolve IP address.
+.Bd -literal
+cap_channel_t *capcas, *capdns;
+nvlist_t *limits;
+const char *ipstr = "127.0.0.1";
+struct in_addr ip;
+struct hostent *hp;
+
+/* Open capability to the Casper. */
+capcas = cap_init();
+if (capcas == NULL)
+ err(1, "Unable to contact Casper");
+
+/* Enter capability mode sandbox. */
+if (cap_enter() < 0 && errno != ENOSYS)
+ err(1, "Unable to enter capability mode");
+
+/* Use Casper capability to create capability to the system.dns service. */
+capdns = cap_service_open(capcas, "system.dns");
+if (capdns == NULL)
+ err(1, "Unable to open system.dns service");
+
+/* Close Casper capability, we don't need it anymore. */
+cap_close(capcas);
+
+/* Limit system.dns to reverse DNS lookups and IPv4 addresses. */
+limits = nvlist_create(0);
+nvlist_add_string(limits, "type", "ADDR");
+nvlist_add_number(limits, "family", (uint64_t)AF_INET);
+if (cap_limit_set(capdns, limits) < 0)
+ err(1, "Unable to limit access to the system.dns service");
+
+/* Convert IP address in C-string to in_addr. */
+if (!inet_aton(ipstr, &ip))
+ errx(1, "Unable to parse IP address %s.", ipstr);
+
+/* Find hostname for the given IP address. */
+hp = cap_gethostbyaddr(capdns, (const void *)&ip, sizeof(ip), AF_INET);
+if (hp == NULL)
+ errx(1, "No name associated with %s.", ipstr);
+
+printf("Name associated with %s is %s.\\n", ipstr, hp->h_name);
+.Ed
+.Sh SEE ALSO
+.Xr cap_enter 2 ,
+.Xr execve 2 ,
+.Xr kevent 2 ,
+.Xr poll 2 ,
+.Xr select 2 ,
+.Xr cap_gethostbyaddr 3 ,
+.Xr err 3 ,
+.Xr gethostbyaddr 3 ,
+.Xr inet_aton 3 ,
+.Xr nv 3 ,
+.Xr capsicum 4 ,
+.Xr unix 4
+.Sh AUTHORS
+The
+.Nm libcasper
+library was implemented by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
+The
+.Nm libcasper
+new architecture was implemented by
+.An Mariusz Zaborski Aq Mt oshogbo@FreeBSD.org
+.
Index: head/lib/libcasper/libcasper/libcasper.c
===================================================================
--- head/lib/libcasper/libcasper/libcasper.c
+++ head/lib/libcasper/libcasper/libcasper.c
@@ -0,0 +1,337 @@
+/*-
+ * Copyright (c) 2012-2013 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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/socket.h>
+#include <sys/nv.h>
+#include <sys/procdesc.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libcasper.h"
+#include "libcasper_impl.h"
+
+/*
+ * Structure describing communication channel between two separated processes.
+ */
+#define CAP_CHANNEL_MAGIC 0xcac8a31
+struct cap_channel {
+ /*
+ * Magic value helps to ensure that a pointer to the right structure is
+ * passed to our functions.
+ */
+ int cch_magic;
+ /* Socket descriptor for IPC. */
+ int cch_sock;
+ /* Process descriptor for casper. */
+ int cch_pd;
+};
+
+static bool
+cap_add_pd(cap_channel_t *chan, int pd)
+{
+
+ if (!fd_is_valid(pd))
+ return (false);
+ chan->cch_pd = pd;
+ return (true);
+}
+
+cap_channel_t *
+cap_init(void)
+{
+ pid_t pid;
+ int sock[2], serrno, pfd;
+ bool ret;
+ cap_channel_t *chan;
+
+ if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
+ sock) == -1) {
+ return (NULL);
+ }
+
+ pid = pdfork(&pfd, 0);
+ if (pid == 0) {
+ /* Parent. */
+ close(sock[0]);
+ casper_main_loop(sock[1]);
+ /* NOTREACHED. */
+ } else if (pid > 0) {
+ /* Child. */
+ close(sock[1]);
+ chan = cap_wrap(sock[0]);
+ if (chan == NULL) {
+ serrno = errno;
+ close(sock[0]);
+ close(pfd);
+ errno = serrno;
+ return (NULL);
+ }
+ ret = cap_add_pd(chan, pfd);
+ assert(ret);
+ return (chan);
+ }
+
+ /* Error. */
+ serrno = errno;
+ close(sock[0]);
+ close(sock[1]);
+ errno = serrno;
+ return (NULL);
+}
+
+cap_channel_t *
+cap_wrap(int sock)
+{
+ cap_channel_t *chan;
+
+ if (!fd_is_valid(sock))
+ return (NULL);
+
+ chan = malloc(sizeof(*chan));
+ if (chan != NULL) {
+ chan->cch_sock = sock;
+ chan->cch_pd = -1;
+ chan->cch_magic = CAP_CHANNEL_MAGIC;
+ }
+
+ return (chan);
+}
+
+int
+cap_unwrap(cap_channel_t *chan)
+{
+ int sock;
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ sock = chan->cch_sock;
+ if (chan->cch_pd != -1)
+ close(chan->cch_pd);
+ chan->cch_magic = 0;
+ free(chan);
+
+ return (sock);
+}
+
+cap_channel_t *
+cap_clone(const cap_channel_t *chan)
+{
+ cap_channel_t *newchan;
+ nvlist_t *nvl;
+ int newsock;
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "clone");
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (NULL);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ errno = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+ newsock = nvlist_take_descriptor(nvl, "sock");
+ nvlist_destroy(nvl);
+ newchan = cap_wrap(newsock);
+ if (newchan == NULL) {
+ int serrno;
+
+ serrno = errno;
+ close(newsock);
+ errno = serrno;
+ }
+
+ return (newchan);
+}
+
+void
+cap_close(cap_channel_t *chan)
+{
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ chan->cch_magic = 0;
+ if (chan->cch_pd != -1)
+ close(chan->cch_pd);
+ close(chan->cch_sock);
+ free(chan);
+}
+
+int
+cap_sock(const cap_channel_t *chan)
+{
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ return (chan->cch_sock);
+}
+
+int
+cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
+{
+ nvlist_t *nvlmsg;
+ int error;
+
+ nvlmsg = nvlist_create(0);
+ nvlist_add_string(nvlmsg, "cmd", "limit_set");
+ nvlist_add_nvlist(nvlmsg, "limits", limits);
+ nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
+ if (nvlmsg == NULL) {
+ nvlist_destroy(limits);
+ return (-1);
+ }
+ error = (int)nvlist_get_number(nvlmsg, "error");
+ nvlist_destroy(nvlmsg);
+ nvlist_destroy(limits);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
+{
+ nvlist_t *nvlmsg;
+ int error;
+
+ nvlmsg = nvlist_create(0);
+ nvlist_add_string(nvlmsg, "cmd", "limit_get");
+ nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
+ if (nvlmsg == NULL)
+ return (-1);
+ error = (int)nvlist_get_number(nvlmsg, "error");
+ if (error != 0) {
+ nvlist_destroy(nvlmsg);
+ errno = error;
+ return (-1);
+ }
+ if (nvlist_exists_null(nvlmsg, "limits"))
+ *limitsp = NULL;
+ else
+ *limitsp = nvlist_take_nvlist(nvlmsg, "limits");
+ nvlist_destroy(nvlmsg);
+ return (0);
+}
+
+int
+cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
+{
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ return (nvlist_send(chan->cch_sock, nvl));
+}
+
+nvlist_t *
+cap_recv_nvlist(const cap_channel_t *chan, int flags)
+{
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ return (nvlist_recv(chan->cch_sock, flags));
+}
+
+nvlist_t *
+cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
+{
+
+ assert(chan != NULL);
+ assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
+
+ return (nvlist_xfer(chan->cch_sock, nvl, flags));
+}
+
+cap_channel_t *
+cap_service_open(const cap_channel_t *chan, const char *name)
+{
+ cap_channel_t *newchan;
+ nvlist_t *nvl;
+ int sock, error;
+
+ sock = -1;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "open");
+ nvlist_add_string(nvl, "service", name);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (NULL);
+ error = (int)nvlist_get_number(nvl, "error");
+ if (error != 0) {
+ nvlist_destroy(nvl);
+ errno = error;
+ return (NULL);
+ }
+ sock = nvlist_take_descriptor(nvl, "chanfd");
+ assert(sock >= 0);
+ nvlist_destroy(nvl);
+ nvl = NULL;
+ newchan = cap_wrap(sock);
+ if (newchan == NULL)
+ goto fail;
+ return (newchan);
+fail:
+ error = errno;
+ close(sock);
+ errno = error;
+ return (NULL);
+}
+
+int
+cap_service_limit(const cap_channel_t *chan, const char * const *names,
+ size_t nnames)
+{
+ nvlist_t *limits;
+ unsigned int i;
+
+ limits = nvlist_create(0);
+ for (i = 0; i < nnames; i++)
+ nvlist_add_null(limits, names[i]);
+ return (cap_limit_set(chan, limits));
+}
Index: head/lib/libcasper/libcasper/libcasper_impl.h
===================================================================
--- head/lib/libcasper/libcasper/libcasper_impl.h
+++ head/lib/libcasper/libcasper/libcasper_impl.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBCASPER_IMPL_H_
+#define _LIBCASPER_IMPL_H_
+
+#include <stdbool.h>
+
+#include "libcasper.h"
+#include "libcasper_service.h"
+
+struct service;
+struct service_connection;
+
+bool fd_is_valid(int fd);
+
+/* Private service functions. */
+struct service *service_alloc(const char *name,
+ service_limit_func_t *limitfunc,
+ service_command_func_t *commandfunc);
+void service_free(struct service *service);
+void service_message(struct service *service,
+ struct service_connection *sconn);
+void service_start(struct service *service, int sock);
+const char *service_name(struct service *service);
+
+/* Private service connection functions. */
+struct service_connection *service_connection_add(struct service *service,
+ int sock, const nvlist_t *limits);
+void service_connection_remove(
+ struct service *service,
+ struct service_connection *sconn);
+int service_connection_clone(
+ struct service *service,
+ struct service_connection *sconn);
+struct service_connection *service_connection_first(
+ struct service *service);
+struct service_connection *service_connection_next(
+ struct service_connection *sconn);
+cap_channel_t *service_connection_get_chan(
+ const struct service_connection *sconn);
+int service_connection_get_sock(
+ const struct service_connection *sconn);
+const nvlist_t *service_connection_get_limits(
+ const struct service_connection *sconn);
+void service_connection_set_limits(
+ struct service_connection *sconn,
+ nvlist_t *limits);
+
+/* Private libcasper functions. */
+void casper_main_loop(int fd);
+
+#endif /* !_LIBCASPER_IMPL_H_ */
Index: head/lib/libcasper/libcasper/libcasper_impl.c
===================================================================
--- head/lib/libcasper/libcasper/libcasper_impl.c
+++ head/lib/libcasper/libcasper/libcasper_impl.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "libcasper_impl.h"
+
+bool
+fd_is_valid(int fd)
+{
+
+ return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
+}
Index: head/lib/libcasper/libcasper/libcasper_service.h
===================================================================
--- head/lib/libcasper/libcasper/libcasper_service.h
+++ head/lib/libcasper/libcasper/libcasper_service.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBCASPER_SERVICE_H_
+#define _LIBCASPER_SERVICE_H_
+
+#ifndef _NVLIST_T_DECLARED
+#define _NVLIST_T_DECLARED
+struct nvlist;
+
+typedef struct nvlist nvlist_t;
+#endif
+
+typedef int service_limit_func_t(const nvlist_t *, const nvlist_t *);
+typedef int service_command_func_t(const char *cmd, const nvlist_t *,
+ nvlist_t *, nvlist_t *);
+
+struct casper_service *service_register(const char *name,
+ service_limit_func_t *limitfunc, service_command_func_t *commandfunc);
+
+#define __constructor __attribute__((constructor))
+#define CREATE_SERVICE(name, limit_func, command_func) \
+ static __constructor void \
+ init_casper_service(void) \
+ { \
+ \
+ (void)service_register(name, limit_func, \
+ command_func); \
+ }
+
+#endif /* !_LIBCASPER_SERVICE_H_ */
Index: head/lib/libcasper/libcasper/libcasper_service.c
===================================================================
--- head/lib/libcasper/libcasper/libcasper_service.c
+++ head/lib/libcasper/libcasper/libcasper_service.c
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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/queue.h>
+#include <sys/socket.h>
+#include <sys/nv.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libcasper_impl.h"
+#include "zygote.h"
+
+struct casper_service {
+ struct service *cs_service;
+ TAILQ_ENTRY(casper_service) cs_next;
+};
+
+static TAILQ_HEAD(, casper_service) casper_services =
+ TAILQ_HEAD_INITIALIZER(casper_services);
+
+#define CORE_CASPER_NAME "core.casper"
+#define CSERVICE_IS_CORE(service) \
+ (strcmp(service_name(service->cs_service), CORE_CASPER_NAME) == 0)
+
+static struct casper_service *
+service_find(const char *name)
+{
+ struct casper_service *casserv;
+
+ TAILQ_FOREACH(casserv, &casper_services, cs_next) {
+ if (strcmp(service_name(casserv->cs_service), name) == 0)
+ break;
+ }
+ return (casserv);
+}
+
+struct casper_service *
+service_register(const char *name, service_limit_func_t *limitfunc,
+ service_command_func_t *commandfunc)
+{
+ struct casper_service *casserv;
+
+ if (commandfunc == NULL)
+ return (NULL);
+ if (name == NULL || name[0] == '\0')
+ return (NULL);
+ if (service_find(name) != NULL)
+ return (NULL);
+
+ casserv = malloc(sizeof(*casserv));
+ if (casserv == NULL)
+ return (NULL);
+
+ casserv->cs_service = service_alloc(name, limitfunc, commandfunc);
+ if (casserv->cs_service == NULL) {
+ free(casserv);
+ return (NULL);
+ }
+ TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next);
+
+ return (casserv);
+}
+
+static bool
+casper_allowed_service(const nvlist_t *limits, const char *service)
+{
+
+ if (limits == NULL)
+ return (true);
+
+ if (nvlist_exists_null(limits, service))
+ return (true);
+
+ return (false);
+}
+
+static int
+casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ int type;
+ void *cookie;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NULL)
+ return (EINVAL);
+ if (!casper_allowed_service(oldlimits, name))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static void
+service_execute(int chanfd)
+{
+ struct service *service;
+ nvlist_t *nvl;
+ int procfd;
+
+ nvl = nvlist_recv(chanfd, 0);
+ if (nvl == NULL)
+ exit(1);
+ service = (struct service *)(uintptr_t)nvlist_take_number(nvl,
+ "service");
+ //XXX: We should remove this?
+ procfd = nvlist_take_descriptor(nvl, "procfd");
+ nvlist_destroy(nvl);
+
+ service_start(service, chanfd);
+ /* Not reached. */
+ exit(1);
+}
+
+static int
+casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ struct casper_service *casserv;
+ const char *servname;
+ nvlist_t *nvl;
+ int chanfd, procfd, error;
+
+ if (strcmp(cmd, "open") != 0)
+ return (EINVAL);
+ if (!nvlist_exists_string(nvlin, "service"))
+ return (EINVAL);
+
+ servname = nvlist_get_string(nvlin, "service");
+ casserv = service_find(servname);
+ if (casserv == NULL)
+ return (ENOENT);
+
+ if (!casper_allowed_service(limits, servname))
+ return (ENOTCAPABLE);
+
+ if (zygote_clone(service_execute, &chanfd, &procfd) == -1)
+ return (errno);
+
+ nvl = nvlist_create(0);
+ nvlist_add_number(nvl, "service",
+ (uint64_t)(uintptr_t)casserv->cs_service);
+ nvlist_move_descriptor(nvl, "procfd", procfd);
+ if (nvlist_send(chanfd, nvl) == -1) {
+ error = errno;
+ nvlist_destroy(nvl);
+ close(chanfd);
+ return (error);
+ }
+ nvlist_destroy(nvl);
+
+ nvlist_move_descriptor(nvlout, "chanfd", chanfd);
+
+ return (0);
+}
+
+static void
+service_register_core(int fd)
+{
+ struct casper_service *casserv;
+ struct service_connection *sconn;
+
+ casserv = service_register(CORE_CASPER_NAME, casper_limit,
+ casper_command);
+ sconn = service_connection_add(casserv->cs_service, fd, NULL);
+ if (sconn == NULL) {
+ close(fd);
+ abort();
+ }
+}
+
+void
+casper_main_loop(int fd)
+{
+ fd_set fds;
+ struct casper_service *casserv;
+ struct service_connection *sconn, *sconntmp;
+ int sock, maxfd, ret;
+
+ if (zygote_init() < 0)
+ exit(1);
+
+ /*
+ * Register core services.
+ */
+ service_register_core(fd);
+
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ maxfd = -1;
+ TAILQ_FOREACH(casserv, &casper_services, cs_next) {
+ /* We handle only core services. */
+ if (!CSERVICE_IS_CORE(casserv))
+ continue;
+ for (sconn = service_connection_first(casserv->cs_service);
+ sconn != NULL;
+ sconn = service_connection_next(sconn)) {
+ sock = service_connection_get_sock(sconn);
+ FD_SET(sock, &fds);
+ maxfd = sock > maxfd ? sock : maxfd;
+ }
+ }
+ if (maxfd == -1) {
+ /* Nothing to do. */
+ exit(0);
+ }
+ maxfd++;
+
+
+ assert(maxfd <= (int)FD_SETSIZE);
+ ret = select(maxfd, &fds, NULL, NULL, NULL);
+ assert(ret == -1 || ret > 0); /* select() cannot timeout */
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ exit(1);
+ }
+
+ TAILQ_FOREACH(casserv, &casper_services, cs_next) {
+ /* We handle only core services. */
+ if (!CSERVICE_IS_CORE(casserv))
+ continue;
+ for (sconn = service_connection_first(casserv->cs_service);
+ sconn != NULL; sconn = sconntmp) {
+ /*
+ * Prepare for connection to be removed from
+ * the list on failure.
+ */
+ sconntmp = service_connection_next(sconn);
+ sock = service_connection_get_sock(sconn);
+ if (FD_ISSET(sock, &fds)) {
+ service_message(casserv->cs_service,
+ sconn);
+ }
+ }
+ }
+ }
+}
Index: head/lib/libcasper/libcasper/service.c
===================================================================
--- head/lib/libcasper/libcasper/service.c
+++ head/lib/libcasper/libcasper/service.c
@@ -0,0 +1,394 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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/queue.h>
+#include <sys/socket.h>
+#include <sys/nv.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "libcasper.h"
+#include "libcasper_impl.h"
+
+/*
+ * Currently there is only one service_connection per service.
+ * In the future we may want multiple connections from multiple clients
+ * per one service instance, but it has to be carefully designed.
+ * The problem is that we may restrict/sandbox service instance according
+ * to the limits provided. When new connection comes in with different
+ * limits we won't be able to access requested resources.
+ * Not to mention one process will serve to mutiple mutually untrusted
+ * clients and compromise of this service instance by one of its clients
+ * can lead to compromise of the other clients.
+ */
+
+/*
+ * Client connections to the given service.
+ */
+#define SERVICE_CONNECTION_MAGIC 0x5e91c0ec
+struct service_connection {
+ int sc_magic;
+ cap_channel_t *sc_chan;
+ nvlist_t *sc_limits;
+ TAILQ_ENTRY(service_connection) sc_next;
+};
+
+#define SERVICE_MAGIC 0x5e91ce
+struct service {
+ int s_magic;
+ char *s_name;
+ service_limit_func_t *s_limit;
+ service_command_func_t *s_command;
+ TAILQ_HEAD(, service_connection) s_connections;
+};
+
+struct service *
+service_alloc(const char *name, service_limit_func_t *limitfunc,
+ service_command_func_t *commandfunc)
+{
+ struct service *service;
+
+ service = malloc(sizeof(*service));
+ if (service == NULL)
+ return (NULL);
+ service->s_name = strdup(name);
+ if (service->s_name == NULL) {
+ free(service);
+ return (NULL);
+ }
+ service->s_limit = limitfunc;
+ service->s_command = commandfunc;
+ TAILQ_INIT(&service->s_connections);
+ service->s_magic = SERVICE_MAGIC;
+
+ return (service);
+}
+
+void
+service_free(struct service *service)
+{
+ struct service_connection *sconn;
+
+ assert(service->s_magic == SERVICE_MAGIC);
+
+ service->s_magic = 0;
+ while ((sconn = service_connection_first(service)) != NULL)
+ service_connection_remove(service, sconn);
+ free(service->s_name);
+ free(service);
+}
+
+struct service_connection *
+service_connection_add(struct service *service, int sock,
+ const nvlist_t *limits)
+{
+ struct service_connection *sconn;
+ int serrno;
+
+ assert(service->s_magic == SERVICE_MAGIC);
+
+ sconn = malloc(sizeof(*sconn));
+ if (sconn == NULL)
+ return (NULL);
+ sconn->sc_chan = cap_wrap(sock);
+ if (sconn->sc_chan == NULL) {
+ serrno = errno;
+ free(sconn);
+ errno = serrno;
+ return (NULL);
+ }
+ if (limits == NULL) {
+ sconn->sc_limits = NULL;
+ } else {
+ sconn->sc_limits = nvlist_clone(limits);
+ if (sconn->sc_limits == NULL) {
+ serrno = errno;
+ (void)cap_unwrap(sconn->sc_chan);
+ free(sconn);
+ errno = serrno;
+ return (NULL);
+ }
+ }
+ sconn->sc_magic = SERVICE_CONNECTION_MAGIC;
+ TAILQ_INSERT_TAIL(&service->s_connections, sconn, sc_next);
+ return (sconn);
+}
+
+void
+service_connection_remove(struct service *service,
+ struct service_connection *sconn)
+{
+
+ assert(service->s_magic == SERVICE_MAGIC);
+ assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+
+ TAILQ_REMOVE(&service->s_connections, sconn, sc_next);
+ sconn->sc_magic = 0;
+ nvlist_destroy(sconn->sc_limits);
+ cap_close(sconn->sc_chan);
+ free(sconn);
+}
+
+int
+service_connection_clone(struct service *service,
+ struct service_connection *sconn)
+{
+ struct service_connection *newsconn;
+ int serrno, sock[2];
+
+ if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sock) < 0)
+ return (-1);
+
+ newsconn = service_connection_add(service, sock[0],
+ service_connection_get_limits(sconn));
+ if (newsconn == NULL) {
+ serrno = errno;
+ close(sock[0]);
+ close(sock[1]);
+ errno = serrno;
+ return (-1);
+ }
+
+ return (sock[1]);
+}
+
+struct service_connection *
+service_connection_first(struct service *service)
+{
+ struct service_connection *sconn;
+
+ assert(service->s_magic == SERVICE_MAGIC);
+
+ sconn = TAILQ_FIRST(&service->s_connections);
+ assert(sconn == NULL ||
+ sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+ return (sconn);
+}
+
+struct service_connection *
+service_connection_next(struct service_connection *sconn)
+{
+
+ assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+
+ sconn = TAILQ_NEXT(sconn, sc_next);
+ assert(sconn == NULL ||
+ sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+ return (sconn);
+}
+
+cap_channel_t *
+service_connection_get_chan(const struct service_connection *sconn)
+{
+
+ assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+
+ return (sconn->sc_chan);
+}
+
+int
+service_connection_get_sock(const struct service_connection *sconn)
+{
+
+ assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+
+ return (cap_sock(sconn->sc_chan));
+}
+
+const nvlist_t *
+service_connection_get_limits(const struct service_connection *sconn)
+{
+
+ assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+
+ return (sconn->sc_limits);
+}
+
+void
+service_connection_set_limits(struct service_connection *sconn,
+ nvlist_t *limits)
+{
+
+ assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
+
+ nvlist_destroy(sconn->sc_limits);
+ sconn->sc_limits = limits;
+}
+
+void
+service_message(struct service *service, struct service_connection *sconn)
+{
+ nvlist_t *nvlin, *nvlout;
+ const char *cmd;
+ int error;
+
+ nvlin = cap_recv_nvlist(service_connection_get_chan(sconn), 0);
+ if (nvlin == NULL) {
+ service_connection_remove(service, sconn);
+ return;
+ }
+
+ error = EDOOFUS;
+ nvlout = nvlist_create(0);
+
+ cmd = nvlist_get_string(nvlin, "cmd");
+ if (strcmp(cmd, "limit_set") == 0) {
+ nvlist_t *nvllim;
+
+ nvllim = nvlist_take_nvlist(nvlin, "limits");
+ if (service->s_limit == NULL) {
+ error = EOPNOTSUPP;
+ } else {
+ error = service->s_limit(
+ service_connection_get_limits(sconn), nvllim);
+ }
+ if (error == 0) {
+ service_connection_set_limits(sconn, nvllim);
+ /* Function consumes nvllim. */
+ } else {
+ nvlist_destroy(nvllim);
+ }
+ } else if (strcmp(cmd, "limit_get") == 0) {
+ const nvlist_t *nvllim;
+
+ nvllim = service_connection_get_limits(sconn);
+ if (nvllim != NULL)
+ nvlist_add_nvlist(nvlout, "limits", nvllim);
+ else
+ nvlist_add_null(nvlout, "limits");
+ error = 0;
+ } else if (strcmp(cmd, "clone") == 0) {
+ int sock;
+
+ sock = service_connection_clone(service, sconn);
+ if (sock == -1) {
+ error = errno;
+ } else {
+ nvlist_move_descriptor(nvlout, "sock", sock);
+ error = 0;
+ }
+ } else {
+ error = service->s_command(cmd,
+ service_connection_get_limits(sconn), nvlin, nvlout);
+ }
+
+ nvlist_destroy(nvlin);
+ nvlist_add_number(nvlout, "error", (uint64_t)error);
+
+ if (cap_send_nvlist(service_connection_get_chan(sconn), nvlout) == -1)
+ service_connection_remove(service, sconn);
+
+ nvlist_destroy(nvlout);
+}
+
+static int
+fd_add(fd_set *fdsp, int maxfd, int fd)
+{
+
+ FD_SET(fd, fdsp);
+ return (fd > maxfd ? fd : maxfd);
+}
+
+const char *
+service_name(struct service *service)
+{
+
+ assert(service->s_magic == SERVICE_MAGIC);
+ return (service->s_name);
+}
+
+void
+service_start(struct service *service, int sock)
+{
+ struct service_connection *sconn, *sconntmp;
+ fd_set fds;
+ int maxfd, nfds;
+
+ assert(service != NULL);
+ assert(service->s_magic == SERVICE_MAGIC);
+ setproctitle("%s", service->s_name);
+ if (service_connection_add(service, sock, NULL) == NULL)
+ exit(1);
+
+ for (;;) {
+ FD_ZERO(&fds);
+ maxfd = -1;
+ for (sconn = service_connection_first(service); sconn != NULL;
+ sconn = service_connection_next(sconn)) {
+ maxfd = fd_add(&fds, maxfd,
+ service_connection_get_sock(sconn));
+ }
+
+ assert(maxfd >= 0);
+ assert(maxfd + 1 <= (int)FD_SETSIZE);
+ nfds = select(maxfd + 1, &fds, NULL, NULL, NULL);
+ if (nfds < 0) {
+ if (errno != EINTR)
+ exit(1);
+ continue;
+ } else if (nfds == 0) {
+ /* Timeout. */
+ abort();
+ }
+
+ for (sconn = service_connection_first(service); sconn != NULL;
+ sconn = sconntmp) {
+ /*
+ * Prepare for connection to be removed from the list
+ * on failure.
+ */
+ sconntmp = service_connection_next(sconn);
+ if (FD_ISSET(service_connection_get_sock(sconn), &fds))
+ service_message(service, sconn);
+ }
+ if (service_connection_first(service) == NULL) {
+ /*
+ * No connections left, exiting.
+ */
+ break;
+ }
+ }
+
+ exit(0);
+}
Index: head/lib/libcasper/libcasper/zygote.h
===================================================================
--- head/lib/libcasper/libcasper/zygote.h
+++ head/lib/libcasper/libcasper/zygote.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ZYGOTE_H_
+#define _ZYGOTE_H_
+
+typedef void zygote_func_t(int);
+
+int zygote_init(void);
+int zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp);
+
+#endif /* !_ZYGOTE_H_ */
Index: head/lib/libcasper/libcasper/zygote.c
===================================================================
--- head/lib/libcasper/libcasper/zygote.c
+++ head/lib/libcasper/libcasper/zygote.c
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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/capsicum.h>
+#include <sys/procdesc.h>
+#include <sys/socket.h>
+#include <sys/nv.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "zygote.h"
+
+/* Zygote info. */
+static int zygote_sock = -1;
+
+static void
+stdnull(void)
+{
+ int fd;
+
+ fd = open(_PATH_DEVNULL, O_RDWR);
+ if (fd == -1)
+ errx(1, "Unable to open %s", _PATH_DEVNULL);
+
+ if (setsid() == -1)
+ errx(1, "Unable to detach from session");
+
+ if (dup2(fd, STDIN_FILENO) == -1)
+ errx(1, "Unable to cover stdin");
+ if (dup2(fd, STDOUT_FILENO) == -1)
+ errx(1, "Unable to cover stdout");
+ if (dup2(fd, STDERR_FILENO) == -1)
+ errx(1, "Unable to cover stderr");
+
+ close(fd);
+}
+
+int
+zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp)
+{
+ nvlist_t *nvl;
+ int error;
+
+ if (zygote_sock == -1) {
+ /* Zygote didn't start. */
+ errno = ENXIO;
+ return (-1);
+ }
+
+ nvl = nvlist_create(0);
+ nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func);
+ nvl = nvlist_xfer(zygote_sock, nvl, 0);
+ if (nvl == NULL)
+ return (-1);
+ if (nvlist_exists_number(nvl, "error")) {
+ error = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ errno = error;
+ return (-1);
+ }
+
+ *chanfdp = nvlist_take_descriptor(nvl, "chanfd");
+ *procfdp = nvlist_take_descriptor(nvl, "procfd");
+
+ nvlist_destroy(nvl);
+ return (0);
+}
+
+/*
+ * This function creates sandboxes on-demand whoever has access to it via
+ * 'sock' socket. Function sends two descriptors to the caller: process
+ * descriptor of the sandbox and socket pair descriptor for communication
+ * between sandbox and its owner.
+ */
+static void
+zygote_main(int sock)
+{
+ int error, fd, procfd;
+ int chanfd[2];
+ nvlist_t *nvlin, *nvlout;
+ zygote_func_t *func;
+ pid_t pid;
+
+ assert(sock > STDERR_FILENO);
+
+ setproctitle("zygote");
+
+ stdnull();
+ for (fd = STDERR_FILENO + 1; fd < sock; fd++)
+ close(fd);
+ closefrom(sock + 1);
+
+ for (;;) {
+ nvlin = nvlist_recv(sock, 0);
+ if (nvlin == NULL) {
+ if (errno == ENOTCONN) {
+ /* Casper exited. */
+ exit(0);
+ }
+ continue;
+ }
+ func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin,
+ "func");
+ nvlist_destroy(nvlin);
+
+ /*
+ * Someone is requesting a new process, create one.
+ */
+ procfd = -1;
+ chanfd[0] = -1;
+ chanfd[1] = -1;
+ error = 0;
+ if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
+ chanfd) == -1) {
+ error = errno;
+ goto send;
+ }
+ pid = pdfork(&procfd, 0);
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ error = errno;
+ break;
+ case 0:
+ /* Child. */
+ close(sock);
+ close(chanfd[0]);
+ func(chanfd[1]);
+ /* NOTREACHED */
+ exit(1);
+ default:
+ /* Parent. */
+ close(chanfd[1]);
+ break;
+ }
+send:
+ nvlout = nvlist_create(0);
+ if (error != 0) {
+ nvlist_add_number(nvlout, "error", (uint64_t)error);
+ if (chanfd[0] >= 0)
+ close(chanfd[0]);
+ if (procfd >= 0)
+ close(procfd);
+ } else {
+ nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]);
+ nvlist_move_descriptor(nvlout, "procfd", procfd);
+ }
+ (void)nvlist_send(sock, nvlout);
+ nvlist_destroy(nvlout);
+ }
+ /* NOTREACHED */
+}
+
+int
+zygote_init(void)
+{
+ int serrno, sp[2];
+ pid_t pid;
+
+ if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp) == -1)
+ return (-1);
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ serrno = errno;
+ close(sp[0]);
+ close(sp[1]);
+ errno = serrno;
+ return (-1);
+ case 0:
+ /* Child. */
+ close(sp[0]);
+ zygote_main(sp[1]);
+ /* NOTREACHED */
+ abort();
+ default:
+ /* Parent. */
+ zygote_sock = sp[0];
+ close(sp[1]);
+ return (0);
+ }
+ /* NOTREACHED */
+}
Index: head/lib/libcasper/libcasper_impl.h
===================================================================
--- head/lib/libcasper/libcasper_impl.h
+++ head/lib/libcasper/libcasper_impl.h
@@ -1,46 +0,0 @@
-/*-
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _LIBCASPER_IMPL_H_
-#define _LIBCASPER_IMPL_H_
-
-#include "libcasper.h"
-
-struct service;
-struct service_connection;
-
-struct service * service_alloc(const char *name,
- service_limit_func_t *limitfunc, service_command_func_t *commandfunc);
-void service_free(struct service *service);
-
-void service_message(struct service *service, struct service_connection *sconn);
-
-#endif /* !_LIBCASPER_IMPL_H_ */
Index: head/lib/libcasper/services/Makefile
===================================================================
--- head/lib/libcasper/services/Makefile
+++ head/lib/libcasper/services/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+SUBDIR= cap_dns
+SUBDIR+= cap_grp
+SUBDIR+= cap_pwd
+SUBDIR+= cap_random
+SUBDIR+= cap_sysctl
+
+.include <bsd.subdir.mk>
Index: head/lib/libcasper/services/cap_dns/Makefile
===================================================================
--- head/lib/libcasper/services/cap_dns/Makefile
+++ head/lib/libcasper/services/cap_dns/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+LIB= cap_dns
+
+SHLIB_MAJOR= 0
+SHLIBDIR?= /lib/casper
+INCSDIR?= ${INCLUDEDIR}/casper
+
+SRCS= cap_dns.c
+
+INCS= cap_dns.h
+
+LIBADD= nv
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../libcasper
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
Index: head/lib/libcasper/services/cap_dns/cap_dns.h
===================================================================
--- head/lib/libcasper/services/cap_dns/cap_dns.h
+++ head/lib/libcasper/services/cap_dns/cap_dns.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2012 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CAP_DNS_H_
+#define _CAP_DNS_H_
+
+#include <sys/socket.h> /* socklen_t */
+
+struct addrinfo;
+struct hostent;
+
+struct hostent *cap_gethostbyname(cap_channel_t *chan, const char *name);
+struct hostent *cap_gethostbyname2(cap_channel_t *chan, const char *name,
+ int type);
+struct hostent *cap_gethostbyaddr(cap_channel_t *chan, const void *addr,
+ socklen_t len, int type);
+
+int cap_getaddrinfo(cap_channel_t *chan, const char *hostname,
+ const char *servname, const struct addrinfo *hints, struct addrinfo **res);
+int cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa,
+ socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen,
+ int flags);
+
+int cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
+ size_t ntypes);
+int cap_dns_family_limit(cap_channel_t *chan, const int *families,
+ size_t nfamilies);
+
+#endif /* !_CAP_DNS_H_ */
Index: head/lib/libcasper/services/cap_dns/cap_dns.c
===================================================================
--- head/lib/libcasper/services/cap_dns/cap_dns.c
+++ head/lib/libcasper/services/cap_dns/cap_dns.c
@@ -0,0 +1,761 @@
+/*-
+ * Copyright (c) 2012-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/dnv.h>
+#include <sys/nv.h>
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcasper.h>
+#include <libcasper_service.h>
+
+#include "cap_dns.h"
+
+static struct hostent hent;
+
+static void
+hostent_free(struct hostent *hp)
+{
+ unsigned int ii;
+
+ free(hp->h_name);
+ hp->h_name = NULL;
+ if (hp->h_aliases != NULL) {
+ for (ii = 0; hp->h_aliases[ii] != NULL; ii++)
+ free(hp->h_aliases[ii]);
+ free(hp->h_aliases);
+ hp->h_aliases = NULL;
+ }
+ if (hp->h_addr_list != NULL) {
+ for (ii = 0; hp->h_addr_list[ii] != NULL; ii++)
+ free(hp->h_addr_list[ii]);
+ free(hp->h_addr_list);
+ hp->h_addr_list = NULL;
+ }
+}
+
+static struct hostent *
+hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
+{
+ unsigned int ii, nitems;
+ char nvlname[64];
+ int n;
+
+ hostent_free(hp);
+
+ hp->h_name = strdup(nvlist_get_string(nvl, "name"));
+ if (hp->h_name == NULL)
+ goto fail;
+ hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype");
+ hp->h_length = (int)nvlist_get_number(nvl, "length");
+
+ nitems = (unsigned int)nvlist_get_number(nvl, "naliases");
+ hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1);
+ if (hp->h_aliases == NULL)
+ goto fail;
+ for (ii = 0; ii < nitems; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ hp->h_aliases[ii] =
+ strdup(nvlist_get_string(nvl, nvlname));
+ if (hp->h_aliases[ii] == NULL)
+ goto fail;
+ }
+ hp->h_aliases[ii] = NULL;
+
+ nitems = (unsigned int)nvlist_get_number(nvl, "naddrs");
+ hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1);
+ if (hp->h_addr_list == NULL)
+ goto fail;
+ for (ii = 0; ii < nitems; ii++) {
+ hp->h_addr_list[ii] = malloc(hp->h_length);
+ if (hp->h_addr_list[ii] == NULL)
+ goto fail;
+ n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ bcopy(nvlist_get_binary(nvl, nvlname, NULL),
+ hp->h_addr_list[ii], hp->h_length);
+ }
+ hp->h_addr_list[ii] = NULL;
+
+ return (hp);
+fail:
+ hostent_free(hp);
+ h_errno = NO_RECOVERY;
+ return (NULL);
+}
+
+struct hostent *
+cap_gethostbyname(cap_channel_t *chan, const char *name)
+{
+
+ return (cap_gethostbyname2(chan, name, AF_INET));
+}
+
+struct hostent *
+cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
+{
+ struct hostent *hp;
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "gethostbyname");
+ nvlist_add_number(nvl, "family", (uint64_t)type);
+ nvlist_add_string(nvl, "name", name);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL) {
+ h_errno = NO_RECOVERY;
+ return (NULL);
+ }
+ if (nvlist_get_number(nvl, "error") != 0) {
+ h_errno = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+
+ hp = hostent_unpack(nvl, &hent);
+ nvlist_destroy(nvl);
+ return (hp);
+}
+
+struct hostent *
+cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
+ int type)
+{
+ struct hostent *hp;
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "gethostbyaddr");
+ nvlist_add_binary(nvl, "addr", addr, (size_t)len);
+ nvlist_add_number(nvl, "family", (uint64_t)type);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL) {
+ h_errno = NO_RECOVERY;
+ return (NULL);
+ }
+ if (nvlist_get_number(nvl, "error") != 0) {
+ h_errno = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+ hp = hostent_unpack(nvl, &hent);
+ nvlist_destroy(nvl);
+ return (hp);
+}
+
+static struct addrinfo *
+addrinfo_unpack(const nvlist_t *nvl)
+{
+ struct addrinfo *ai;
+ const void *addr;
+ size_t addrlen;
+ const char *canonname;
+
+ addr = nvlist_get_binary(nvl, "ai_addr", &addrlen);
+ ai = malloc(sizeof(*ai) + addrlen);
+ if (ai == NULL)
+ return (NULL);
+ ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags");
+ ai->ai_family = (int)nvlist_get_number(nvl, "ai_family");
+ ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype");
+ ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol");
+ ai->ai_addrlen = (socklen_t)addrlen;
+ canonname = dnvlist_get_string(nvl, "ai_canonname", NULL);
+ if (canonname != NULL) {
+ ai->ai_canonname = strdup(canonname);
+ if (ai->ai_canonname == NULL) {
+ free(ai);
+ return (NULL);
+ }
+ } else {
+ ai->ai_canonname = NULL;
+ }
+ ai->ai_addr = (void *)(ai + 1);
+ bcopy(addr, ai->ai_addr, addrlen);
+ ai->ai_next = NULL;
+
+ return (ai);
+}
+
+int
+cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ struct addrinfo *firstai, *prevai, *curai;
+ unsigned int ii;
+ const nvlist_t *nvlai;
+ char nvlname[64];
+ nvlist_t *nvl;
+ int error, n;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "getaddrinfo");
+ if (hostname != NULL)
+ nvlist_add_string(nvl, "hostname", hostname);
+ if (servname != NULL)
+ nvlist_add_string(nvl, "servname", servname);
+ if (hints != NULL) {
+ nvlist_add_number(nvl, "hints.ai_flags",
+ (uint64_t)hints->ai_flags);
+ nvlist_add_number(nvl, "hints.ai_family",
+ (uint64_t)hints->ai_family);
+ nvlist_add_number(nvl, "hints.ai_socktype",
+ (uint64_t)hints->ai_socktype);
+ nvlist_add_number(nvl, "hints.ai_protocol",
+ (uint64_t)hints->ai_protocol);
+ }
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (EAI_MEMORY);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ error = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (error);
+ }
+
+ nvlai = NULL;
+ firstai = prevai = curai = NULL;
+ for (ii = 0; ; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ if (!nvlist_exists_nvlist(nvl, nvlname))
+ break;
+ nvlai = nvlist_get_nvlist(nvl, nvlname);
+ curai = addrinfo_unpack(nvlai);
+ if (curai == NULL)
+ break;
+ if (prevai != NULL)
+ prevai->ai_next = curai;
+ else if (firstai == NULL)
+ firstai = curai;
+ prevai = curai;
+ }
+ nvlist_destroy(nvl);
+ if (curai == NULL && nvlai != NULL) {
+ if (firstai == NULL)
+ freeaddrinfo(firstai);
+ return (EAI_MEMORY);
+ }
+
+ *res = firstai;
+ return (0);
+}
+
+int
+cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ nvlist_t *nvl;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "getnameinfo");
+ nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen);
+ nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
+ nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
+ nvlist_add_number(nvl, "flags", (uint64_t)flags);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (EAI_MEMORY);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ error = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (error);
+ }
+
+ if (host != NULL && nvlist_exists_string(nvl, "host"))
+ strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1);
+ if (serv != NULL && nvlist_exists_string(nvl, "serv"))
+ strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1);
+ nvlist_destroy(nvl);
+ return (0);
+}
+
+static void
+limit_remove(nvlist_t *limits, const char *prefix)
+{
+ const char *name;
+ size_t prefixlen;
+ void *cookie;
+
+ prefixlen = strlen(prefix);
+again:
+ cookie = NULL;
+ while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
+ if (strncmp(name, prefix, prefixlen) == 0) {
+ nvlist_free(limits, name);
+ goto again;
+ }
+ }
+}
+
+int
+cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
+ size_t ntypes)
+{
+ nvlist_t *limits;
+ unsigned int i;
+ char nvlname[64];
+ int n;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL)
+ limits = nvlist_create(0);
+ else
+ limit_remove(limits, "type");
+ for (i = 0; i < ntypes; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "type%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(limits, nvlname, types[i]);
+ }
+ return (cap_limit_set(chan, limits));
+}
+
+int
+cap_dns_family_limit(cap_channel_t *chan, const int *families,
+ size_t nfamilies)
+{
+ nvlist_t *limits;
+ unsigned int i;
+ char nvlname[64];
+ int n;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL)
+ limits = nvlist_create(0);
+ else
+ limit_remove(limits, "family");
+ for (i = 0; i < nfamilies; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "family%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_number(limits, nvlname, (uint64_t)families[i]);
+ }
+ return (cap_limit_set(chan, limits));
+}
+
+/*
+ * Service functions.
+ */
+static bool
+dns_allowed_type(const nvlist_t *limits, const char *type)
+{
+ const char *name;
+ bool notypes;
+ void *cookie;
+
+ if (limits == NULL)
+ return (true);
+
+ notypes = true;
+ cookie = NULL;
+ while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
+ if (strncmp(name, "type", sizeof("type") - 1) != 0)
+ continue;
+ notypes = false;
+ if (strcmp(nvlist_get_string(limits, name), type) == 0)
+ return (true);
+ }
+
+ /* If there are no types at all, allow any type. */
+ if (notypes)
+ return (true);
+
+ return (false);
+}
+
+static bool
+dns_allowed_family(const nvlist_t *limits, int family)
+{
+ const char *name;
+ bool nofamilies;
+ void *cookie;
+
+ if (limits == NULL)
+ return (true);
+
+ nofamilies = true;
+ cookie = NULL;
+ while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
+ if (strncmp(name, "family", sizeof("family") - 1) != 0)
+ continue;
+ nofamilies = false;
+ if (family == AF_UNSPEC)
+ continue;
+ if (nvlist_get_number(limits, name) == (uint64_t)family)
+ return (true);
+ }
+
+ /* If there are no families at all, allow any family. */
+ if (nofamilies)
+ return (true);
+
+ return (false);
+}
+
+static void
+hostent_pack(const struct hostent *hp, nvlist_t *nvl)
+{
+ unsigned int ii;
+ char nvlname[64];
+ int n;
+
+ nvlist_add_string(nvl, "name", hp->h_name);
+ nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype);
+ nvlist_add_number(nvl, "length", (uint64_t)hp->h_length);
+
+ if (hp->h_aliases == NULL) {
+ nvlist_add_number(nvl, "naliases", 0);
+ } else {
+ for (ii = 0; hp->h_aliases[ii] != NULL; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]);
+ }
+ nvlist_add_number(nvl, "naliases", (uint64_t)ii);
+ }
+
+ if (hp->h_addr_list == NULL) {
+ nvlist_add_number(nvl, "naddrs", 0);
+ } else {
+ for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii],
+ (size_t)hp->h_length);
+ }
+ nvlist_add_number(nvl, "naddrs", (uint64_t)ii);
+ }
+}
+
+static int
+dns_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ struct hostent *hp;
+ int family;
+
+ if (!dns_allowed_type(limits, "NAME"))
+ return (NO_RECOVERY);
+
+ family = (int)nvlist_get_number(nvlin, "family");
+
+ if (!dns_allowed_family(limits, family))
+ return (NO_RECOVERY);
+
+ hp = gethostbyname2(nvlist_get_string(nvlin, "name"), family);
+ if (hp == NULL)
+ return (h_errno);
+ hostent_pack(hp, nvlout);
+ return (0);
+}
+
+static int
+dns_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ struct hostent *hp;
+ const void *addr;
+ size_t addrsize;
+ int family;
+
+ if (!dns_allowed_type(limits, "ADDR"))
+ return (NO_RECOVERY);
+
+ family = (int)nvlist_get_number(nvlin, "family");
+
+ if (!dns_allowed_family(limits, family))
+ return (NO_RECOVERY);
+
+ addr = nvlist_get_binary(nvlin, "addr", &addrsize);
+ hp = gethostbyaddr(addr, (socklen_t)addrsize, family);
+ if (hp == NULL)
+ return (h_errno);
+ hostent_pack(hp, nvlout);
+ return (0);
+}
+
+static int
+dns_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ struct sockaddr_storage sast;
+ const void *sabin;
+ char *host, *serv;
+ size_t sabinsize, hostlen, servlen;
+ socklen_t salen;
+ int error, flags;
+
+ if (!dns_allowed_type(limits, "NAME"))
+ return (NO_RECOVERY);
+
+ error = 0;
+ host = serv = NULL;
+ memset(&sast, 0, sizeof(sast));
+
+ hostlen = (size_t)nvlist_get_number(nvlin, "hostlen");
+ servlen = (size_t)nvlist_get_number(nvlin, "servlen");
+
+ if (hostlen > 0) {
+ host = calloc(1, hostlen + 1);
+ if (host == NULL) {
+ error = EAI_MEMORY;
+ goto out;
+ }
+ }
+ if (servlen > 0) {
+ serv = calloc(1, servlen + 1);
+ if (serv == NULL) {
+ error = EAI_MEMORY;
+ goto out;
+ }
+ }
+
+ sabin = nvlist_get_binary(nvlin, "sa", &sabinsize);
+ if (sabinsize > sizeof(sast)) {
+ error = EAI_FAIL;
+ goto out;
+ }
+
+ memcpy(&sast, sabin, sabinsize);
+ salen = (socklen_t)sabinsize;
+
+ if ((sast.ss_family != AF_INET ||
+ salen != sizeof(struct sockaddr_in)) &&
+ (sast.ss_family != AF_INET6 ||
+ salen != sizeof(struct sockaddr_in6))) {
+ error = EAI_FAIL;
+ goto out;
+ }
+
+ if (!dns_allowed_family(limits, (int)sast.ss_family)) {
+ error = NO_RECOVERY;
+ goto out;
+ }
+
+ flags = (int)nvlist_get_number(nvlin, "flags");
+
+ error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen,
+ serv, servlen, flags);
+ if (error != 0)
+ goto out;
+
+ if (host != NULL)
+ nvlist_move_string(nvlout, "host", host);
+ if (serv != NULL)
+ nvlist_move_string(nvlout, "serv", serv);
+out:
+ if (error != 0) {
+ free(host);
+ free(serv);
+ }
+ return (error);
+}
+
+static nvlist_t *
+addrinfo_pack(const struct addrinfo *ai)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags);
+ nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family);
+ nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype);
+ nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol);
+ nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen);
+ if (ai->ai_canonname != NULL)
+ nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname);
+
+ return (nvl);
+}
+
+static int
+dns_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ struct addrinfo hints, *hintsp, *res, *cur;
+ const char *hostname, *servname;
+ char nvlname[64];
+ nvlist_t *elem;
+ unsigned int ii;
+ int error, family, n;
+
+ if (!dns_allowed_type(limits, "ADDR"))
+ return (NO_RECOVERY);
+
+ hostname = dnvlist_get_string(nvlin, "hostname", NULL);
+ servname = dnvlist_get_string(nvlin, "servname", NULL);
+ if (nvlist_exists_number(nvlin, "hints.ai_flags")) {
+ hints.ai_flags = (int)nvlist_get_number(nvlin,
+ "hints.ai_flags");
+ hints.ai_family = (int)nvlist_get_number(nvlin,
+ "hints.ai_family");
+ hints.ai_socktype = (int)nvlist_get_number(nvlin,
+ "hints.ai_socktype");
+ hints.ai_protocol = (int)nvlist_get_number(nvlin,
+ "hints.ai_protocol");
+ hints.ai_addrlen = 0;
+ hints.ai_addr = NULL;
+ hints.ai_canonname = NULL;
+ hintsp = &hints;
+ family = hints.ai_family;
+ } else {
+ hintsp = NULL;
+ family = AF_UNSPEC;
+ }
+
+ if (!dns_allowed_family(limits, family))
+ return (NO_RECOVERY);
+
+ error = getaddrinfo(hostname, servname, hintsp, &res);
+ if (error != 0)
+ goto out;
+
+ for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) {
+ elem = addrinfo_pack(cur);
+ n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_move_nvlist(nvlout, nvlname, elem);
+ }
+
+ freeaddrinfo(res);
+ error = 0;
+out:
+ return (error);
+}
+
+static bool
+limit_has_entry(const nvlist_t *limits, const char *prefix)
+{
+ const char *name;
+ size_t prefixlen;
+ void *cookie;
+
+ if (limits == NULL)
+ return (false);
+
+ prefixlen = strlen(prefix);
+
+ cookie = NULL;
+ while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
+ if (strncmp(name, prefix, prefixlen) == 0)
+ return (true);
+ }
+
+ return (false);
+}
+
+static int
+dns_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ void *cookie;
+ int nvtype;
+ bool hastype, hasfamily;
+
+ hastype = false;
+ hasfamily = false;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &nvtype, &cookie)) != NULL) {
+ if (nvtype == NV_TYPE_STRING) {
+ const char *type;
+
+ if (strncmp(name, "type", sizeof("type") - 1) != 0)
+ return (EINVAL);
+ type = nvlist_get_string(newlimits, name);
+ if (strcmp(type, "ADDR") != 0 &&
+ strcmp(type, "NAME") != 0) {
+ return (EINVAL);
+ }
+ if (!dns_allowed_type(oldlimits, type))
+ return (ENOTCAPABLE);
+ hastype = true;
+ } else if (nvtype == NV_TYPE_NUMBER) {
+ int family;
+
+ if (strncmp(name, "family", sizeof("family") - 1) != 0)
+ return (EINVAL);
+ family = (int)nvlist_get_number(newlimits, name);
+ if (!dns_allowed_family(oldlimits, family))
+ return (ENOTCAPABLE);
+ hasfamily = true;
+ } else {
+ return (EINVAL);
+ }
+ }
+
+ /*
+ * If the new limit doesn't mention type or family we have to
+ * check if the current limit does have those. Missing type or
+ * family in the limit means that all types or families are
+ * allowed.
+ */
+ if (!hastype) {
+ if (limit_has_entry(oldlimits, "type"))
+ return (ENOTCAPABLE);
+ }
+ if (!hasfamily) {
+ if (limit_has_entry(oldlimits, "family"))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static int
+dns_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ int error;
+
+ if (strcmp(cmd, "gethostbyname") == 0)
+ error = dns_gethostbyname(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "gethostbyaddr") == 0)
+ error = dns_gethostbyaddr(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "getnameinfo") == 0)
+ error = dns_getnameinfo(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "getaddrinfo") == 0)
+ error = dns_getaddrinfo(limits, nvlin, nvlout);
+ else
+ error = NO_RECOVERY;
+
+ return (error);
+}
+
+CREATE_SERVICE("system.dns", dns_limit, dns_command);
Index: head/lib/libcasper/services/cap_grp/Makefile
===================================================================
--- head/lib/libcasper/services/cap_grp/Makefile
+++ head/lib/libcasper/services/cap_grp/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+LIB= cap_grp
+
+SHLIB_MAJOR= 0
+SHLIBDIR?= /lib/casper
+INCSDIR?= ${INCLUDEDIR}/casper
+
+SRCS= cap_grp.c
+
+INCS= cap_grp.h
+
+LIBADD= nv
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../libcasper
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
Index: head/lib/libcasper/services/cap_grp/cap_grp.h
===================================================================
--- head/lib/libcasper/services/cap_grp/cap_grp.h
+++ head/lib/libcasper/services/cap_grp/cap_grp.h
@@ -0,0 +1,57 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CAP_GRP_H_
+#define _CAP_GRP_H_
+
+struct group *cap_getgrent(cap_channel_t *chan);
+struct group *cap_getgrnam(cap_channel_t *chan, const char *name);
+struct group *cap_getgrgid(cap_channel_t *chan, gid_t gid);
+
+int cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer,
+ size_t bufsize, struct group **result);
+int cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp,
+ char *buffer, size_t bufsize, struct group **result);
+int cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp,
+ char *buffer, size_t bufsize, struct group **result);
+
+int cap_setgroupent(cap_channel_t *chan, int stayopen);
+int cap_setgrent(cap_channel_t *chan);
+void cap_endgrent(cap_channel_t *chan);
+
+int cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds,
+ size_t ncmds);
+int cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
+ size_t nfields);
+int cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
+ size_t nnames, gid_t *gids, size_t ngids);
+
+#endif /* !_CAP_GRP_H_ */
Index: head/lib/libcasper/services/cap_grp/cap_grp.c
===================================================================
--- head/lib/libcasper/services/cap_grp/cap_grp.c
+++ head/lib/libcasper/services/cap_grp/cap_grp.c
@@ -0,0 +1,787 @@
+/*-
+ * 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/dnv.h>
+#include <sys/nv.h>
+#include <sys/param.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libcasper.h>
+#include <libcasper_service.h>
+
+#include "cap_grp.h"
+
+static struct group ggrp;
+static char *gbuffer;
+static size_t gbufsize;
+
+static int
+group_resize(void)
+{
+ char *buf;
+
+ if (gbufsize == 0)
+ gbufsize = 1024;
+ else
+ gbufsize *= 2;
+
+ buf = gbuffer;
+ gbuffer = realloc(buf, gbufsize);
+ if (gbuffer == NULL) {
+ free(buf);
+ gbufsize = 0;
+ return (ENOMEM);
+ }
+ memset(gbuffer, 0, gbufsize);
+
+ return (0);
+}
+
+static int
+group_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
+ char **bufferp, size_t *bufsizep)
+{
+ const char *str;
+ size_t len;
+
+ str = nvlist_get_string(nvl, fieldname);
+ len = strlcpy(*bufferp, str, *bufsizep);
+ if (len >= *bufsizep)
+ return (ERANGE);
+ *fieldp = *bufferp;
+ *bufferp += len + 1;
+ *bufsizep -= len + 1;
+
+ return (0);
+}
+
+static int
+group_unpack_members(const nvlist_t *nvl, char ***fieldp, char **bufferp,
+ size_t *bufsizep)
+{
+ const char *mem;
+ char **outstrs, *str, nvlname[64];
+ size_t nmem, datasize, strsize;
+ unsigned int ii;
+ int n;
+
+ if (!nvlist_exists_number(nvl, "gr_nmem")) {
+ datasize = _ALIGNBYTES + sizeof(char *);
+ if (datasize >= *bufsizep)
+ return (ERANGE);
+ outstrs = (char **)_ALIGN(*bufferp);
+ outstrs[0] = NULL;
+ *fieldp = outstrs;
+ *bufferp += datasize;
+ *bufsizep -= datasize;
+ return (0);
+ }
+
+ nmem = (size_t)nvlist_get_number(nvl, "gr_nmem");
+ datasize = _ALIGNBYTES + sizeof(char *) * (nmem + 1);
+ for (ii = 0; ii < nmem; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ mem = dnvlist_get_string(nvl, nvlname, NULL);
+ if (mem == NULL)
+ return (EINVAL);
+ datasize += strlen(mem) + 1;
+ }
+
+ if (datasize >= *bufsizep)
+ return (ERANGE);
+
+ outstrs = (char **)_ALIGN(*bufferp);
+ str = (char *)outstrs + sizeof(char *) * (nmem + 1);
+ for (ii = 0; ii < nmem; ii++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]", ii);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ mem = nvlist_get_string(nvl, nvlname);
+ strsize = strlen(mem) + 1;
+ memcpy(str, mem, strsize);
+ outstrs[ii] = str;
+ str += strsize;
+ }
+ assert(ii == nmem);
+ outstrs[ii] = NULL;
+
+ *fieldp = outstrs;
+ *bufferp += datasize;
+ *bufsizep -= datasize;
+
+ return (0);
+}
+
+static int
+group_unpack(const nvlist_t *nvl, struct group *grp, char *buffer,
+ size_t bufsize)
+{
+ int error;
+
+ if (!nvlist_exists_string(nvl, "gr_name"))
+ return (EINVAL);
+
+ memset(grp, 0, sizeof(*grp));
+
+ error = group_unpack_string(nvl, "gr_name", &grp->gr_name, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ error = group_unpack_string(nvl, "gr_passwd", &grp->gr_passwd, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ grp->gr_gid = (gid_t)nvlist_get_number(nvl, "gr_gid");
+ error = group_unpack_members(nvl, &grp->gr_mem, &buffer, &bufsize);
+ if (error != 0)
+ return (error);
+
+ return (0);
+}
+
+static int
+cap_getgrcommon_r(cap_channel_t *chan, const char *cmd, const char *name,
+ gid_t gid, struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
+{
+ nvlist_t *nvl;
+ bool getgr_r;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", cmd);
+ if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0) {
+ /* Add nothing. */
+ } else if (strcmp(cmd, "getgrnam") == 0 ||
+ strcmp(cmd, "getgrnam_r") == 0) {
+ nvlist_add_string(nvl, "name", name);
+ } else if (strcmp(cmd, "getgrgid") == 0 ||
+ strcmp(cmd, "getgrgid_r") == 0) {
+ nvlist_add_number(nvl, "gid", (uint64_t)gid);
+ } else {
+ abort();
+ }
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL) {
+ assert(errno != 0);
+ *result = NULL;
+ return (errno);
+ }
+ error = (int)nvlist_get_number(nvl, "error");
+ if (error != 0) {
+ nvlist_destroy(nvl);
+ *result = NULL;
+ return (error);
+ }
+
+ if (!nvlist_exists_string(nvl, "gr_name")) {
+ /* Not found. */
+ nvlist_destroy(nvl);
+ *result = NULL;
+ return (0);
+ }
+
+ getgr_r = (strcmp(cmd, "getgrent_r") == 0 ||
+ strcmp(cmd, "getgrnam_r") == 0 || strcmp(cmd, "getgrgid_r") == 0);
+
+ for (;;) {
+ error = group_unpack(nvl, grp, buffer, bufsize);
+ if (getgr_r || error != ERANGE)
+ break;
+ assert(buffer == gbuffer);
+ assert(bufsize == gbufsize);
+ error = group_resize();
+ if (error != 0)
+ break;
+ /* Update pointers after resize. */
+ buffer = gbuffer;
+ bufsize = gbufsize;
+ }
+
+ nvlist_destroy(nvl);
+
+ if (error == 0)
+ *result = grp;
+ else
+ *result = NULL;
+
+ return (error);
+}
+
+static struct group *
+cap_getgrcommon(cap_channel_t *chan, const char *cmd, const char *name,
+ gid_t gid)
+{
+ struct group *result;
+ int error, serrno;
+
+ serrno = errno;
+
+ error = cap_getgrcommon_r(chan, cmd, name, gid, &ggrp, gbuffer,
+ gbufsize, &result);
+ if (error != 0) {
+ errno = error;
+ return (NULL);
+ }
+
+ errno = serrno;
+
+ return (result);
+}
+
+struct group *
+cap_getgrent(cap_channel_t *chan)
+{
+
+ return (cap_getgrcommon(chan, "getgrent", NULL, 0));
+}
+
+struct group *
+cap_getgrnam(cap_channel_t *chan, const char *name)
+{
+
+ return (cap_getgrcommon(chan, "getgrnam", name, 0));
+}
+
+struct group *
+cap_getgrgid(cap_channel_t *chan, gid_t gid)
+{
+
+ return (cap_getgrcommon(chan, "getgrgid", NULL, gid));
+}
+
+int
+cap_getgrent_r(cap_channel_t *chan, struct group *grp, char *buffer,
+ size_t bufsize, struct group **result)
+{
+
+ return (cap_getgrcommon_r(chan, "getgrent_r", NULL, 0, grp, buffer,
+ bufsize, result));
+}
+
+int
+cap_getgrnam_r(cap_channel_t *chan, const char *name, struct group *grp,
+ char *buffer, size_t bufsize, struct group **result)
+{
+
+ return (cap_getgrcommon_r(chan, "getgrnam_r", name, 0, grp, buffer,
+ bufsize, result));
+}
+
+int
+cap_getgrgid_r(cap_channel_t *chan, gid_t gid, struct group *grp, char *buffer,
+ size_t bufsize, struct group **result)
+{
+
+ return (cap_getgrcommon_r(chan, "getgrgid_r", NULL, gid, grp, buffer,
+ bufsize, result));
+}
+
+int
+cap_setgroupent(cap_channel_t *chan, int stayopen)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "setgroupent");
+ nvlist_add_bool(nvl, "stayopen", stayopen != 0);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (0);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ errno = nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (0);
+ }
+ nvlist_destroy(nvl);
+
+ return (1);
+}
+
+int
+cap_setgrent(cap_channel_t *chan)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "setgrent");
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (0);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ errno = nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (0);
+ }
+ nvlist_destroy(nvl);
+
+ return (1);
+}
+
+void
+cap_endgrent(cap_channel_t *chan)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "endgrent");
+ /* Ignore any errors, we have no way to report them. */
+ nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
+}
+
+int
+cap_grp_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
+{
+ nvlist_t *limits, *nvl;
+ unsigned int i;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL) {
+ limits = nvlist_create(0);
+ } else {
+ if (nvlist_exists_nvlist(limits, "cmds"))
+ nvlist_free_nvlist(limits, "cmds");
+ }
+ nvl = nvlist_create(0);
+ for (i = 0; i < ncmds; i++)
+ nvlist_add_null(nvl, cmds[i]);
+ nvlist_move_nvlist(limits, "cmds", nvl);
+ return (cap_limit_set(chan, limits));
+}
+
+int
+cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
+ size_t nfields)
+{
+ nvlist_t *limits, *nvl;
+ unsigned int i;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL) {
+ limits = nvlist_create(0);
+ } else {
+ if (nvlist_exists_nvlist(limits, "fields"))
+ nvlist_free_nvlist(limits, "fields");
+ }
+ nvl = nvlist_create(0);
+ for (i = 0; i < nfields; i++)
+ nvlist_add_null(nvl, fields[i]);
+ nvlist_move_nvlist(limits, "fields", nvl);
+ return (cap_limit_set(chan, limits));
+}
+
+int
+cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
+ size_t nnames, gid_t *gids, size_t ngids)
+{
+ nvlist_t *limits, *groups;
+ unsigned int i;
+ char nvlname[64];
+ int n;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL) {
+ limits = nvlist_create(0);
+ } else {
+ if (nvlist_exists_nvlist(limits, "groups"))
+ nvlist_free_nvlist(limits, "groups");
+ }
+ groups = nvlist_create(0);
+ for (i = 0; i < ngids; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_number(groups, nvlname, (uint64_t)gids[i]);
+ }
+ for (i = 0; i < nnames; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gid%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(groups, nvlname, names[i]);
+ }
+ nvlist_move_nvlist(limits, "groups", groups);
+ return (cap_limit_set(chan, limits));
+}
+
+/*
+ * Service functions.
+ */
+static bool
+grp_allowed_cmd(const nvlist_t *limits, const char *cmd)
+{
+
+ if (limits == NULL)
+ return (true);
+
+ /*
+ * If no limit was set on allowed commands, then all commands
+ * are allowed.
+ */
+ if (!nvlist_exists_nvlist(limits, "cmds"))
+ return (true);
+
+ limits = nvlist_get_nvlist(limits, "cmds");
+ return (nvlist_exists_null(limits, cmd));
+}
+
+static int
+grp_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ void *cookie;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NULL)
+ return (EINVAL);
+ if (!grp_allowed_cmd(oldlimits, name))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static bool
+grp_allowed_group(const nvlist_t *limits, const char *gname, gid_t gid)
+{
+ const char *name;
+ void *cookie;
+ int type;
+
+ if (limits == NULL)
+ return (true);
+
+ /*
+ * If no limit was set on allowed groups, then all groups are allowed.
+ */
+ if (!nvlist_exists_nvlist(limits, "groups"))
+ return (true);
+
+ limits = nvlist_get_nvlist(limits, "groups");
+ cookie = NULL;
+ while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ if (gid != (gid_t)-1 &&
+ nvlist_get_number(limits, name) == (uint64_t)gid) {
+ return (true);
+ }
+ break;
+ case NV_TYPE_STRING:
+ if (gname != NULL &&
+ strcmp(nvlist_get_string(limits, name),
+ gname) == 0) {
+ return (true);
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+
+ return (false);
+}
+
+static int
+grp_allowed_groups(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name, *gname;
+ void *cookie;
+ gid_t gid;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ gid = (gid_t)nvlist_get_number(newlimits, name);
+ gname = NULL;
+ break;
+ case NV_TYPE_STRING:
+ gid = (gid_t)-1;
+ gname = nvlist_get_string(newlimits, name);
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (!grp_allowed_group(oldlimits, gname, gid))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static bool
+grp_allowed_field(const nvlist_t *limits, const char *field)
+{
+
+ if (limits == NULL)
+ return (true);
+
+ /*
+ * If no limit was set on allowed fields, then all fields are allowed.
+ */
+ if (!nvlist_exists_nvlist(limits, "fields"))
+ return (true);
+
+ limits = nvlist_get_nvlist(limits, "fields");
+ return (nvlist_exists_null(limits, field));
+}
+
+static int
+grp_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ void *cookie;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NULL)
+ return (EINVAL);
+ if (!grp_allowed_field(oldlimits, name))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static bool
+grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl)
+{
+ char nvlname[64];
+ int n;
+
+ if (grp == NULL)
+ return (true);
+
+ /*
+ * If either name or GID is allowed, we allow it.
+ */
+ if (!grp_allowed_group(limits, grp->gr_name, grp->gr_gid))
+ return (false);
+
+ if (grp_allowed_field(limits, "gr_name"))
+ nvlist_add_string(nvl, "gr_name", grp->gr_name);
+ else
+ nvlist_add_string(nvl, "gr_name", "");
+ if (grp_allowed_field(limits, "gr_passwd"))
+ nvlist_add_string(nvl, "gr_passwd", grp->gr_passwd);
+ else
+ nvlist_add_string(nvl, "gr_passwd", "");
+ if (grp_allowed_field(limits, "gr_gid"))
+ nvlist_add_number(nvl, "gr_gid", (uint64_t)grp->gr_gid);
+ else
+ nvlist_add_number(nvl, "gr_gid", (uint64_t)-1);
+ if (grp_allowed_field(limits, "gr_mem") && grp->gr_mem[0] != NULL) {
+ unsigned int ngroups;
+
+ for (ngroups = 0; grp->gr_mem[ngroups] != NULL; ngroups++) {
+ n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]",
+ ngroups);
+ assert(n > 0 && n < (ssize_t)sizeof(nvlname));
+ nvlist_add_string(nvl, nvlname, grp->gr_mem[ngroups]);
+ }
+ nvlist_add_number(nvl, "gr_nmem", (uint64_t)ngroups);
+ }
+
+ return (true);
+}
+
+static int
+grp_getgrent(const nvlist_t *limits, const nvlist_t *nvlin __unused,
+ nvlist_t *nvlout)
+{
+ struct group *grp;
+
+ for (;;) {
+ errno = 0;
+ grp = getgrent();
+ if (errno != 0)
+ return (errno);
+ if (grp_pack(limits, grp, nvlout))
+ return (0);
+ }
+
+ /* NOTREACHED */
+}
+
+static int
+grp_getgrnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ struct group *grp;
+ const char *name;
+
+ if (!nvlist_exists_string(nvlin, "name"))
+ return (EINVAL);
+ name = nvlist_get_string(nvlin, "name");
+ assert(name != NULL);
+
+ errno = 0;
+ grp = getgrnam(name);
+ if (errno != 0)
+ return (errno);
+
+ (void)grp_pack(limits, grp, nvlout);
+
+ return (0);
+}
+
+static int
+grp_getgrgid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ struct group *grp;
+ gid_t gid;
+
+ if (!nvlist_exists_number(nvlin, "gid"))
+ return (EINVAL);
+
+ gid = (gid_t)nvlist_get_number(nvlin, "gid");
+
+ errno = 0;
+ grp = getgrgid(gid);
+ if (errno != 0)
+ return (errno);
+
+ (void)grp_pack(limits, grp, nvlout);
+
+ return (0);
+}
+
+static int
+grp_setgroupent(const nvlist_t *limits __unused, const nvlist_t *nvlin,
+ nvlist_t *nvlout __unused)
+{
+ int stayopen;
+
+ if (!nvlist_exists_bool(nvlin, "stayopen"))
+ return (EINVAL);
+
+ stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
+
+ return (setgroupent(stayopen) == 0 ? EFAULT : 0);
+}
+
+static int
+grp_setgrent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
+ nvlist_t *nvlout __unused)
+{
+
+ return (setgrent() == 0 ? EFAULT : 0);
+}
+
+static int
+grp_endgrent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
+ nvlist_t *nvlout __unused)
+{
+
+ endgrent();
+
+ return (0);
+}
+
+static int
+grp_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const nvlist_t *limits;
+ const char *name;
+ void *cookie;
+ int error, type;
+
+ if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
+ !nvlist_exists_nvlist(newlimits, "cmds")) {
+ return (ENOTCAPABLE);
+ }
+ if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
+ !nvlist_exists_nvlist(newlimits, "fields")) {
+ return (ENOTCAPABLE);
+ }
+ if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "groups") &&
+ !nvlist_exists_nvlist(newlimits, "groups")) {
+ return (ENOTCAPABLE);
+ }
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NVLIST)
+ return (EINVAL);
+ limits = nvlist_get_nvlist(newlimits, name);
+ if (strcmp(name, "cmds") == 0)
+ error = grp_allowed_cmds(oldlimits, limits);
+ else if (strcmp(name, "fields") == 0)
+ error = grp_allowed_fields(oldlimits, limits);
+ else if (strcmp(name, "groups") == 0)
+ error = grp_allowed_groups(oldlimits, limits);
+ else
+ error = EINVAL;
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+grp_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ int error;
+
+ if (!grp_allowed_cmd(limits, cmd))
+ return (ENOTCAPABLE);
+
+ if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0)
+ error = grp_getgrent(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "getgrnam") == 0 || strcmp(cmd, "getgrnam_r") == 0)
+ error = grp_getgrnam(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "getgrgid") == 0 || strcmp(cmd, "getgrgid_r") == 0)
+ error = grp_getgrgid(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "setgroupent") == 0)
+ error = grp_setgroupent(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "setgrent") == 0)
+ error = grp_setgrent(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "endgrent") == 0)
+ error = grp_endgrent(limits, nvlin, nvlout);
+ else
+ error = EINVAL;
+
+ return (error);
+}
+
+CREATE_SERVICE("system.grp", grp_limit, grp_command);
Index: head/lib/libcasper/services/cap_pwd/Makefile
===================================================================
--- head/lib/libcasper/services/cap_pwd/Makefile
+++ head/lib/libcasper/services/cap_pwd/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+LIB= cap_pwd
+
+SHLIB_MAJOR= 0
+SHLIBDIR?= /lib/casper
+INCSDIR?= ${INCLUDEDIR}/casper
+
+SRCS= cap_pwd.c
+
+INCS= cap_pwd.h
+
+LIBADD= nv
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../libcasper
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
Index: head/lib/libcasper/services/cap_pwd/cap_pwd.h
===================================================================
--- head/lib/libcasper/services/cap_pwd/cap_pwd.h
+++ head/lib/libcasper/services/cap_pwd/cap_pwd.h
@@ -0,0 +1,57 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CAP_PWD_H_
+#define _CAP_PWD_H_
+
+struct passwd *cap_getpwent(cap_channel_t *chan);
+struct passwd *cap_getpwnam(cap_channel_t *chan, const char *login);
+struct passwd *cap_getpwuid(cap_channel_t *chan, uid_t uid);
+
+int cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **result);
+int cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
+ char *buffer, size_t bufsize, struct passwd **result);
+int cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd,
+ char *buffer, size_t bufsize, struct passwd **result);
+
+int cap_setpassent(cap_channel_t *chan, int stayopen);
+void cap_setpwent(cap_channel_t *chan);
+void cap_endpwent(cap_channel_t *chan);
+
+int cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds,
+ size_t ncmds);
+int cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
+ size_t nfields);
+int cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
+ size_t nnames, uid_t *uids, size_t nuids);
+
+#endif /* !_CAP_PWD_H_ */
Index: head/lib/libcasper/services/cap_pwd/cap_pwd.c
===================================================================
--- head/lib/libcasper/services/cap_pwd/cap_pwd.c
+++ head/lib/libcasper/services/cap_pwd/cap_pwd.c
@@ -0,0 +1,783 @@
+/*-
+ * 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/nv.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcasper.h>
+#include <libcasper_service.h>
+
+#include "cap_pwd.h"
+
+static struct passwd gpwd;
+static char *gbuffer;
+static size_t gbufsize;
+
+static int
+passwd_resize(void)
+{
+ char *buf;
+
+ if (gbufsize == 0)
+ gbufsize = 1024;
+ else
+ gbufsize *= 2;
+
+ buf = gbuffer;
+ gbuffer = realloc(buf, gbufsize);
+ if (gbuffer == NULL) {
+ free(buf);
+ gbufsize = 0;
+ return (ENOMEM);
+ }
+ memset(gbuffer, 0, gbufsize);
+
+ return (0);
+}
+
+static int
+passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
+ char **bufferp, size_t *bufsizep)
+{
+ const char *str;
+ size_t len;
+
+ str = nvlist_get_string(nvl, fieldname);
+ len = strlcpy(*bufferp, str, *bufsizep);
+ if (len >= *bufsizep)
+ return (ERANGE);
+ *fieldp = *bufferp;
+ *bufferp += len + 1;
+ *bufsizep -= len + 1;
+
+ return (0);
+}
+
+static int
+passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
+ size_t bufsize)
+{
+ int error;
+
+ if (!nvlist_exists_string(nvl, "pw_name"))
+ return (EINVAL);
+
+ memset(pwd, 0, sizeof(*pwd));
+
+ error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
+ pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
+ pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
+ error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
+ &bufsize);
+ if (error != 0)
+ return (error);
+ pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
+ pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
+
+ return (0);
+}
+
+static int
+cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
+ uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
+ struct passwd **result)
+{
+ nvlist_t *nvl;
+ bool getpw_r;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", cmd);
+ if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
+ /* Add nothing. */
+ } else if (strcmp(cmd, "getpwnam") == 0 ||
+ strcmp(cmd, "getpwnam_r") == 0) {
+ nvlist_add_string(nvl, "name", login);
+ } else if (strcmp(cmd, "getpwuid") == 0 ||
+ strcmp(cmd, "getpwuid_r") == 0) {
+ nvlist_add_number(nvl, "uid", (uint64_t)uid);
+ } else {
+ abort();
+ }
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL) {
+ assert(errno != 0);
+ *result = NULL;
+ return (errno);
+ }
+ error = (int)nvlist_get_number(nvl, "error");
+ if (error != 0) {
+ nvlist_destroy(nvl);
+ *result = NULL;
+ return (error);
+ }
+
+ if (!nvlist_exists_string(nvl, "pw_name")) {
+ /* Not found. */
+ nvlist_destroy(nvl);
+ *result = NULL;
+ return (0);
+ }
+
+ getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
+ strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
+
+ for (;;) {
+ error = passwd_unpack(nvl, pwd, buffer, bufsize);
+ if (getpw_r || error != ERANGE)
+ break;
+ assert(buffer == gbuffer);
+ assert(bufsize == gbufsize);
+ error = passwd_resize();
+ if (error != 0)
+ break;
+ /* Update pointers after resize. */
+ buffer = gbuffer;
+ bufsize = gbufsize;
+ }
+
+ nvlist_destroy(nvl);
+
+ if (error == 0)
+ *result = pwd;
+ else
+ *result = NULL;
+
+ return (error);
+}
+
+static struct passwd *
+cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
+ uid_t uid)
+{
+ struct passwd *result;
+ int error, serrno;
+
+ serrno = errno;
+
+ error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
+ gbufsize, &result);
+ if (error != 0) {
+ errno = error;
+ return (NULL);
+ }
+
+ errno = serrno;
+
+ return (result);
+}
+
+struct passwd *
+cap_getpwent(cap_channel_t *chan)
+{
+
+ return (cap_getpwcommon(chan, "getpwent", NULL, 0));
+}
+
+struct passwd *
+cap_getpwnam(cap_channel_t *chan, const char *login)
+{
+
+ return (cap_getpwcommon(chan, "getpwnam", login, 0));
+}
+
+struct passwd *
+cap_getpwuid(cap_channel_t *chan, uid_t uid)
+{
+
+ return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
+}
+
+int
+cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **result)
+{
+
+ return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
+ bufsize, result));
+}
+
+int
+cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
+ char *buffer, size_t bufsize, struct passwd **result)
+{
+
+ return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
+ bufsize, result));
+}
+
+int
+cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **result)
+{
+
+ return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
+ bufsize, result));
+}
+
+int
+cap_setpassent(cap_channel_t *chan, int stayopen)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "setpassent");
+ nvlist_add_bool(nvl, "stayopen", stayopen != 0);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (0);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ errno = nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (0);
+ }
+ nvlist_destroy(nvl);
+
+ return (1);
+}
+
+static void
+cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", cmd);
+ /* Ignore any errors, we have no way to report them. */
+ nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
+}
+
+void
+cap_setpwent(cap_channel_t *chan)
+{
+
+ cap_set_end_pwent(chan, "setpwent");
+}
+
+void
+cap_endpwent(cap_channel_t *chan)
+{
+
+ cap_set_end_pwent(chan, "endpwent");
+}
+
+int
+cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
+{
+ nvlist_t *limits, *nvl;
+ unsigned int i;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL) {
+ limits = nvlist_create(0);
+ } else {
+ if (nvlist_exists_nvlist(limits, "cmds"))
+ nvlist_free_nvlist(limits, "cmds");
+ }
+ nvl = nvlist_create(0);
+ for (i = 0; i < ncmds; i++)
+ nvlist_add_null(nvl, cmds[i]);
+ nvlist_move_nvlist(limits, "cmds", nvl);
+ return (cap_limit_set(chan, limits));
+}
+
+int
+cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
+ size_t nfields)
+{
+ nvlist_t *limits, *nvl;
+ unsigned int i;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL) {
+ limits = nvlist_create(0);
+ } else {
+ if (nvlist_exists_nvlist(limits, "fields"))
+ nvlist_free_nvlist(limits, "fields");
+ }
+ nvl = nvlist_create(0);
+ for (i = 0; i < nfields; i++)
+ nvlist_add_null(nvl, fields[i]);
+ nvlist_move_nvlist(limits, "fields", nvl);
+ return (cap_limit_set(chan, limits));
+}
+
+int
+cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
+ size_t nnames, uid_t *uids, size_t nuids)
+{
+ nvlist_t *limits, *users;
+ char nvlname[64];
+ unsigned int i;
+ int n;
+
+ if (cap_limit_get(chan, &limits) < 0)
+ return (-1);
+ if (limits == NULL) {
+ limits = nvlist_create(0);
+ } else {
+ if (nvlist_exists_nvlist(limits, "users"))
+ nvlist_free_nvlist(limits, "users");
+ }
+ users = nvlist_create(0);
+ for (i = 0; i < nuids; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
+ }
+ for (i = 0; i < nnames; i++) {
+ n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
+ assert(n > 0 && n < (int)sizeof(nvlname));
+ nvlist_add_string(users, nvlname, names[i]);
+ }
+ nvlist_move_nvlist(limits, "users", users);
+ return (cap_limit_set(chan, limits));
+}
+
+
+/*
+ * Service functions.
+ */
+static bool
+pwd_allowed_cmd(const nvlist_t *limits, const char *cmd)
+{
+
+ if (limits == NULL)
+ return (true);
+
+ /*
+ * If no limit was set on allowed commands, then all commands
+ * are allowed.
+ */
+ if (!nvlist_exists_nvlist(limits, "cmds"))
+ return (true);
+
+ limits = nvlist_get_nvlist(limits, "cmds");
+ return (nvlist_exists_null(limits, cmd));
+}
+
+static int
+pwd_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ void *cookie;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NULL)
+ return (EINVAL);
+ if (!pwd_allowed_cmd(oldlimits, name))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static bool
+pwd_allowed_user(const nvlist_t *limits, const char *uname, uid_t uid)
+{
+ const char *name;
+ void *cookie;
+ int type;
+
+ if (limits == NULL)
+ return (true);
+
+ /*
+ * If no limit was set on allowed users, then all users are allowed.
+ */
+ if (!nvlist_exists_nvlist(limits, "users"))
+ return (true);
+
+ limits = nvlist_get_nvlist(limits, "users");
+ cookie = NULL;
+ while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ if (uid != (uid_t)-1 &&
+ nvlist_get_number(limits, name) == (uint64_t)uid) {
+ return (true);
+ }
+ break;
+ case NV_TYPE_STRING:
+ if (uname != NULL &&
+ strcmp(nvlist_get_string(limits, name),
+ uname) == 0) {
+ return (true);
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+
+ return (false);
+}
+
+static int
+pwd_allowed_users(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name, *uname;
+ void *cookie;
+ uid_t uid;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ uid = (uid_t)nvlist_get_number(newlimits, name);
+ uname = NULL;
+ break;
+ case NV_TYPE_STRING:
+ uid = (uid_t)-1;
+ uname = nvlist_get_string(newlimits, name);
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (!pwd_allowed_user(oldlimits, uname, uid))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static bool
+pwd_allowed_field(const nvlist_t *limits, const char *field)
+{
+
+ if (limits == NULL)
+ return (true);
+
+ /*
+ * If no limit was set on allowed fields, then all fields are allowed.
+ */
+ if (!nvlist_exists_nvlist(limits, "fields"))
+ return (true);
+
+ limits = nvlist_get_nvlist(limits, "fields");
+ return (nvlist_exists_null(limits, field));
+}
+
+static int
+pwd_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ void *cookie;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NULL)
+ return (EINVAL);
+ if (!pwd_allowed_field(oldlimits, name))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static bool
+pwd_pack(const nvlist_t *limits, const struct passwd *pwd, nvlist_t *nvl)
+{
+ int fields;
+
+ if (pwd == NULL)
+ return (true);
+
+ /*
+ * If either name or UID is allowed, we allow it.
+ */
+ if (!pwd_allowed_user(limits, pwd->pw_name, pwd->pw_uid))
+ return (false);
+
+ fields = pwd->pw_fields;
+
+ if (pwd_allowed_field(limits, "pw_name")) {
+ nvlist_add_string(nvl, "pw_name", pwd->pw_name);
+ } else {
+ nvlist_add_string(nvl, "pw_name", "");
+ fields &= ~_PWF_NAME;
+ }
+ if (pwd_allowed_field(limits, "pw_uid")) {
+ nvlist_add_number(nvl, "pw_uid", (uint64_t)pwd->pw_uid);
+ } else {
+ nvlist_add_number(nvl, "pw_uid", (uint64_t)-1);
+ fields &= ~_PWF_UID;
+ }
+ if (pwd_allowed_field(limits, "pw_gid")) {
+ nvlist_add_number(nvl, "pw_gid", (uint64_t)pwd->pw_gid);
+ } else {
+ nvlist_add_number(nvl, "pw_gid", (uint64_t)-1);
+ fields &= ~_PWF_GID;
+ }
+ if (pwd_allowed_field(limits, "pw_change")) {
+ nvlist_add_number(nvl, "pw_change", (uint64_t)pwd->pw_change);
+ } else {
+ nvlist_add_number(nvl, "pw_change", (uint64_t)0);
+ fields &= ~_PWF_CHANGE;
+ }
+ if (pwd_allowed_field(limits, "pw_passwd")) {
+ nvlist_add_string(nvl, "pw_passwd", pwd->pw_passwd);
+ } else {
+ nvlist_add_string(nvl, "pw_passwd", "");
+ fields &= ~_PWF_PASSWD;
+ }
+ if (pwd_allowed_field(limits, "pw_class")) {
+ nvlist_add_string(nvl, "pw_class", pwd->pw_class);
+ } else {
+ nvlist_add_string(nvl, "pw_class", "");
+ fields &= ~_PWF_CLASS;
+ }
+ if (pwd_allowed_field(limits, "pw_gecos")) {
+ nvlist_add_string(nvl, "pw_gecos", pwd->pw_gecos);
+ } else {
+ nvlist_add_string(nvl, "pw_gecos", "");
+ fields &= ~_PWF_GECOS;
+ }
+ if (pwd_allowed_field(limits, "pw_dir")) {
+ nvlist_add_string(nvl, "pw_dir", pwd->pw_dir);
+ } else {
+ nvlist_add_string(nvl, "pw_dir", "");
+ fields &= ~_PWF_DIR;
+ }
+ if (pwd_allowed_field(limits, "pw_shell")) {
+ nvlist_add_string(nvl, "pw_shell", pwd->pw_shell);
+ } else {
+ nvlist_add_string(nvl, "pw_shell", "");
+ fields &= ~_PWF_SHELL;
+ }
+ if (pwd_allowed_field(limits, "pw_expire")) {
+ nvlist_add_number(nvl, "pw_expire", (uint64_t)pwd->pw_expire);
+ } else {
+ nvlist_add_number(nvl, "pw_expire", (uint64_t)0);
+ fields &= ~_PWF_EXPIRE;
+ }
+ nvlist_add_number(nvl, "pw_fields", (uint64_t)fields);
+
+ return (true);
+}
+
+static int
+pwd_getpwent(const nvlist_t *limits, const nvlist_t *nvlin __unused,
+ nvlist_t *nvlout)
+{
+ struct passwd *pwd;
+
+ for (;;) {
+ errno = 0;
+ pwd = getpwent();
+ if (errno != 0)
+ return (errno);
+ if (pwd_pack(limits, pwd, nvlout))
+ return (0);
+ }
+
+ /* NOTREACHED */
+}
+
+static int
+pwd_getpwnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ struct passwd *pwd;
+ const char *name;
+
+ if (!nvlist_exists_string(nvlin, "name"))
+ return (EINVAL);
+ name = nvlist_get_string(nvlin, "name");
+ assert(name != NULL);
+
+ errno = 0;
+ pwd = getpwnam(name);
+ if (errno != 0)
+ return (errno);
+
+ (void)pwd_pack(limits, pwd, nvlout);
+
+ return (0);
+}
+
+static int
+pwd_getpwuid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ struct passwd *pwd;
+ uid_t uid;
+
+ if (!nvlist_exists_number(nvlin, "uid"))
+ return (EINVAL);
+
+ uid = (uid_t)nvlist_get_number(nvlin, "uid");
+
+ errno = 0;
+ pwd = getpwuid(uid);
+ if (errno != 0)
+ return (errno);
+
+ (void)pwd_pack(limits, pwd, nvlout);
+
+ return (0);
+}
+
+static int
+pwd_setpassent(const nvlist_t *limits __unused, const nvlist_t *nvlin,
+ nvlist_t *nvlout __unused)
+{
+ int stayopen;
+
+ if (!nvlist_exists_bool(nvlin, "stayopen"))
+ return (EINVAL);
+
+ stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
+
+ return (setpassent(stayopen) == 0 ? EFAULT : 0);
+}
+
+static int
+pwd_setpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
+ nvlist_t *nvlout __unused)
+{
+
+ setpwent();
+
+ return (0);
+}
+
+static int
+pwd_endpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
+ nvlist_t *nvlout __unused)
+{
+
+ endpwent();
+
+ return (0);
+}
+
+static int
+pwd_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const nvlist_t *limits;
+ const char *name;
+ void *cookie;
+ int error, type;
+
+ if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
+ !nvlist_exists_nvlist(newlimits, "cmds")) {
+ return (ENOTCAPABLE);
+ }
+ if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
+ !nvlist_exists_nvlist(newlimits, "fields")) {
+ return (ENOTCAPABLE);
+ }
+ if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "users") &&
+ !nvlist_exists_nvlist(newlimits, "users")) {
+ return (ENOTCAPABLE);
+ }
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NVLIST)
+ return (EINVAL);
+ limits = nvlist_get_nvlist(newlimits, name);
+ if (strcmp(name, "cmds") == 0)
+ error = pwd_allowed_cmds(oldlimits, limits);
+ else if (strcmp(name, "fields") == 0)
+ error = pwd_allowed_fields(oldlimits, limits);
+ else if (strcmp(name, "users") == 0)
+ error = pwd_allowed_users(oldlimits, limits);
+ else
+ error = EINVAL;
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+pwd_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ int error;
+
+ if (!pwd_allowed_cmd(limits, cmd))
+ return (ENOTCAPABLE);
+
+ if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0)
+ error = pwd_getpwent(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "getpwnam") == 0 || strcmp(cmd, "getpwnam_r") == 0)
+ error = pwd_getpwnam(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "getpwuid") == 0 || strcmp(cmd, "getpwuid_r") == 0)
+ error = pwd_getpwuid(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "setpassent") == 0)
+ error = pwd_setpassent(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "setpwent") == 0)
+ error = pwd_setpwent(limits, nvlin, nvlout);
+ else if (strcmp(cmd, "endpwent") == 0)
+ error = pwd_endpwent(limits, nvlin, nvlout);
+ else
+ error = EINVAL;
+
+ return (error);
+}
+
+CREATE_SERVICE("system.pwd", pwd_limit, pwd_command);
Index: head/lib/libcasper/services/cap_random/Makefile
===================================================================
--- head/lib/libcasper/services/cap_random/Makefile
+++ head/lib/libcasper/services/cap_random/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+LIB= cap_random
+
+SHLIB_MAJOR= 0
+SHLIBDIR?= /lib/casper
+INCSDIR?= ${INCLUDEDIR}/casper
+
+SRCS= cap_random.c
+
+INCS= cap_random.h
+
+LIBADD= nv
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../libcasper
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
Index: head/lib/libcasper/services/cap_random/cap_random.h
===================================================================
--- head/lib/libcasper/services/cap_random/cap_random.h
+++ head/lib/libcasper/services/cap_random/cap_random.h
@@ -0,0 +1,37 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CAP_RANDOM_H_
+#define _CAP_RANDOM_H_
+
+int cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes);
+
+#endif /* !_CAP_RANDOM_H_ */
Index: head/lib/libcasper/services/cap_random/cap_random.c
===================================================================
--- head/lib/libcasper/services/cap_random/cap_random.c
+++ head/lib/libcasper/services/cap_random/cap_random.c
@@ -0,0 +1,117 @@
+/*-
+ * 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/nv.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libcasper.h>
+#include <libcasper_service.h>
+
+#include "cap_random.h"
+
+#define MAXSIZE (1024 * 1024)
+
+int
+cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes)
+{
+ nvlist_t *nvl;
+ const void *randbuf;
+ uint8_t *ptr;
+ size_t left, randbufsize;
+
+ left = nbytes;
+ ptr = buf;
+
+ while (left > 0) {
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "generate");
+ nvlist_add_number(nvl, "size",
+ (uint64_t)(left > MAXSIZE ? MAXSIZE : left));
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (-1);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ errno = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (-1);
+ }
+
+ randbuf = nvlist_get_binary(nvl, "data", &randbufsize);
+ memcpy(ptr, randbuf, randbufsize);
+
+ nvlist_destroy(nvl);
+
+ ptr += randbufsize;
+ assert(left >= randbufsize);
+ left -= randbufsize;
+ }
+
+ return (0);
+}
+
+/*
+ * Service functions.
+ */
+
+static int
+random_command(const char *cmd, const nvlist_t *limits __unused,
+ nvlist_t *nvlin, nvlist_t *nvlout)
+{
+ void *data;
+ size_t size;
+
+ if (strcmp(cmd, "generate") != 0)
+ return (EINVAL);
+ if (!nvlist_exists_number(nvlin, "size"))
+ return (EINVAL);
+
+ size = (size_t)nvlist_get_number(nvlin, "size");
+ if (size == 0 || size > MAXSIZE)
+ return (EINVAL);
+
+ data = malloc(size);
+ if (data == NULL)
+ return (ENOMEM);
+
+ arc4random_buf(data, size);
+
+ nvlist_move_binary(nvlout, "data", data, size);
+
+ return (0);
+}
+
+CREATE_SERVICE("system.random", NULL, random_command);
Index: head/lib/libcasper/services/cap_sysctl/Makefile
===================================================================
--- head/lib/libcasper/services/cap_sysctl/Makefile
+++ head/lib/libcasper/services/cap_sysctl/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+LIB= cap_sysctl
+
+SHLIB_MAJOR= 0
+SHLIBDIR?= /lib/casper
+INCSDIR?= ${INCLUDEDIR}/casper
+
+SRCS= cap_sysctl.c
+
+INCS= cap_sysctl.h
+
+LIBADD= nv
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../libcasper
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
Index: head/lib/libcasper/services/cap_sysctl/cap_sysctl.h
===================================================================
--- head/lib/libcasper/services/cap_sysctl/cap_sysctl.h
+++ head/lib/libcasper/services/cap_sysctl/cap_sysctl.h
@@ -0,0 +1,43 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CAP_SYSCTL_H_
+#define _CAP_SYSCTL_H_
+
+#define CAP_SYSCTL_READ 0x01
+#define CAP_SYSCTL_WRITE 0x02
+#define CAP_SYSCTL_RDWR (CAP_SYSCTL_READ | CAP_SYSCTL_WRITE)
+#define CAP_SYSCTL_RECURSIVE 0x04
+
+int cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
+ size_t *oldlenp, const void *newp, size_t newlen);
+
+#endif /* !_CAP_SYSCTL_H_ */
Index: head/lib/libcasper/services/cap_sysctl/cap_sysctl.c
===================================================================
--- head/lib/libcasper/services/cap_sysctl/cap_sysctl.c
+++ head/lib/libcasper/services/cap_sysctl/cap_sysctl.c
@@ -0,0 +1,293 @@
+/*-
+ * 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/sysctl.h>
+#include <sys/nv.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libcasper.h>
+#include <libcasper_service.h>
+
+#include "cap_sysctl.h"
+
+int
+cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
+ size_t *oldlenp, const void *newp, size_t newlen)
+{
+ nvlist_t *nvl;
+ const uint8_t *retoldp;
+ uint8_t operation;
+ size_t oldlen;
+
+ operation = 0;
+ if (oldp != NULL)
+ operation |= CAP_SYSCTL_READ;
+ if (newp != NULL)
+ operation |= CAP_SYSCTL_WRITE;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "sysctl");
+ nvlist_add_string(nvl, "name", name);
+ nvlist_add_number(nvl, "operation", (uint64_t)operation);
+ if (oldp == NULL && oldlenp != NULL)
+ nvlist_add_null(nvl, "justsize");
+ else if (oldlenp != NULL)
+ nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
+ if (newp != NULL)
+ nvlist_add_binary(nvl, "newp", newp, newlen);
+ nvl = cap_xfer_nvlist(chan, nvl, 0);
+ if (nvl == NULL)
+ return (-1);
+ if (nvlist_get_number(nvl, "error") != 0) {
+ errno = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ return (-1);
+ }
+
+ if (oldp == NULL && oldlenp != NULL) {
+ *oldlenp = (size_t)nvlist_get_number(nvl, "oldlen");
+ } else if (oldp != NULL) {
+ retoldp = nvlist_get_binary(nvl, "oldp", &oldlen);
+ memcpy(oldp, retoldp, oldlen);
+ if (oldlenp != NULL)
+ *oldlenp = oldlen;
+ }
+ nvlist_destroy(nvl);
+
+ return (0);
+}
+
+/*
+ * Service functions.
+ */
+static int
+sysctl_check_one(const nvlist_t *nvl, bool islimit)
+{
+ const char *name;
+ void *cookie;
+ int type;
+ unsigned int fields;
+
+ /* NULL nvl is of course invalid. */
+ if (nvl == NULL)
+ return (EINVAL);
+ if (nvlist_error(nvl) != 0)
+ return (nvlist_error(nvl));
+
+#define HAS_NAME 0x01
+#define HAS_OPERATION 0x02
+
+ fields = 0;
+ cookie = NULL;
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ /* We accept only one 'name' and one 'operation' in nvl. */
+ if (strcmp(name, "name") == 0) {
+ if (type != NV_TYPE_STRING)
+ return (EINVAL);
+ /* Only one 'name' can be present. */
+ if ((fields & HAS_NAME) != 0)
+ return (EINVAL);
+ fields |= HAS_NAME;
+ } else if (strcmp(name, "operation") == 0) {
+ uint64_t operation;
+
+ if (type != NV_TYPE_NUMBER)
+ return (EINVAL);
+ /*
+ * We accept only CAP_SYSCTL_READ and
+ * CAP_SYSCTL_WRITE flags.
+ */
+ operation = nvlist_get_number(nvl, name);
+ if ((operation & ~(CAP_SYSCTL_RDWR)) != 0)
+ return (EINVAL);
+ /* ...but there has to be at least one of them. */
+ if ((operation & (CAP_SYSCTL_RDWR)) == 0)
+ return (EINVAL);
+ /* Only one 'operation' can be present. */
+ if ((fields & HAS_OPERATION) != 0)
+ return (EINVAL);
+ fields |= HAS_OPERATION;
+ } else if (islimit) {
+ /* If this is limit, there can be no other fields. */
+ return (EINVAL);
+ }
+ }
+
+ /* Both fields has to be there. */
+ if (fields != (HAS_NAME | HAS_OPERATION))
+ return (EINVAL);
+
+#undef HAS_OPERATION
+#undef HAS_NAME
+
+ return (0);
+}
+
+static bool
+sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation)
+{
+ uint64_t operation;
+ const char *name;
+ void *cookie;
+ int type;
+
+ if (limits == NULL)
+ return (true);
+
+ cookie = NULL;
+ while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
+ assert(type == NV_TYPE_NUMBER);
+
+ operation = nvlist_get_number(limits, name);
+ if ((operation & choperation) != choperation)
+ continue;
+
+ if ((operation & CAP_SYSCTL_RECURSIVE) == 0) {
+ if (strcmp(name, chname) != 0)
+ continue;
+ } else {
+ size_t namelen;
+
+ namelen = strlen(name);
+ if (strncmp(name, chname, namelen) != 0)
+ continue;
+ if (chname[namelen] != '.' && chname[namelen] != '\0')
+ continue;
+ }
+
+ return (true);
+ }
+
+ return (false);
+}
+
+static int
+sysctl_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ void *cookie;
+ uint64_t operation;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NUMBER)
+ return (EINVAL);
+ operation = nvlist_get_number(newlimits, name);
+ if ((operation & ~(CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) != 0)
+ return (EINVAL);
+ if ((operation & (CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) == 0)
+ return (EINVAL);
+ if (!sysctl_allowed(oldlimits, name, operation))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static int
+sysctl_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ const char *name;
+ const void *newp;
+ void *oldp;
+ uint64_t operation;
+ size_t oldlen, newlen;
+ size_t *oldlenp;
+ int error;
+
+ if (strcmp(cmd, "sysctl") != 0)
+ return (EINVAL);
+ error = sysctl_check_one(nvlin, false);
+ if (error != 0)
+ return (error);
+
+ name = nvlist_get_string(nvlin, "name");
+ operation = nvlist_get_number(nvlin, "operation");
+ if (!sysctl_allowed(limits, name, operation))
+ return (ENOTCAPABLE);
+
+ if ((operation & CAP_SYSCTL_WRITE) != 0) {
+ if (!nvlist_exists_binary(nvlin, "newp"))
+ return (EINVAL);
+ newp = nvlist_get_binary(nvlin, "newp", &newlen);
+ assert(newp != NULL && newlen > 0);
+ } else {
+ newp = NULL;
+ newlen = 0;
+ }
+
+ if ((operation & CAP_SYSCTL_READ) != 0) {
+ if (nvlist_exists_null(nvlin, "justsize")) {
+ oldp = NULL;
+ oldlen = 0;
+ oldlenp = &oldlen;
+ } else {
+ if (!nvlist_exists_number(nvlin, "oldlen"))
+ return (EINVAL);
+ oldlen = (size_t)nvlist_get_number(nvlin, "oldlen");
+ if (oldlen == 0)
+ return (EINVAL);
+ oldp = calloc(1, oldlen);
+ if (oldp == NULL)
+ return (ENOMEM);
+ oldlenp = &oldlen;
+ }
+ } else {
+ oldp = NULL;
+ oldlen = 0;
+ oldlenp = NULL;
+ }
+
+ if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) {
+ error = errno;
+ free(oldp);
+ return (error);
+ }
+
+ if ((operation & CAP_SYSCTL_READ) != 0) {
+ if (nvlist_exists_null(nvlin, "justsize"))
+ nvlist_add_number(nvlout, "oldlen", (uint64_t)oldlen);
+ else
+ nvlist_move_binary(nvlout, "oldp", oldp, oldlen);
+ }
+
+ return (0);
+}
+
+CREATE_SERVICE("system.sysctl", sysctl_limit, sysctl_command);
Index: head/libexec/Makefile
===================================================================
--- head/libexec/Makefile
+++ head/libexec/Makefile
@@ -5,7 +5,6 @@
SUBDIR= ${_atf} \
${_atrun} \
- ${_casper} \
${_comsat} \
${_dma} \
getty \
@@ -38,10 +37,6 @@
SUBDIR+= bootpd
.endif
-.if ${MK_CASPER} != "no"
-_casper= casper
-.endif
-
.if ${MK_FINGER} != "no"
SUBDIR+= fingerd
.endif
Index: head/libexec/casper/Makefile
===================================================================
--- head/libexec/casper/Makefile
+++ head/libexec/casper/Makefile
@@ -1,11 +0,0 @@
-# $FreeBSD$
-
-.include <bsd.own.mk>
-
-SUBDIR= dns
-SUBDIR+=grp
-SUBDIR+=pwd
-SUBDIR+=random
-SUBDIR+=sysctl
-
-.include <bsd.subdir.mk>
Index: head/libexec/casper/dns/Makefile
===================================================================
--- head/libexec/casper/dns/Makefile
+++ head/libexec/casper/dns/Makefile
@@ -1,21 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
-
-PROG= dns
-
-SRCS= dns.c
-
-LIBADD= casper nv
-
-BINDIR= /libexec/casper
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
-CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
-CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
-CFLAGS+=-I${.CURDIR}/../../../sbin/casper
-
-MAN=
-
-.include <bsd.prog.mk>
Index: head/libexec/casper/dns/dns.c
===================================================================
--- head/libexec/casper/dns/dns.c
+++ head/libexec/casper/dns/dns.c
@@ -1,436 +0,0 @@
-/*-
- * Copyright (c) 2012-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/nv.h>
-#include <netinet/in.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libcapsicum.h>
-#include <libcapsicum_dns.h>
-#include <libcasper.h>
-#include <pjdlog.h>
-
-static bool
-dns_allowed_type(const nvlist_t *limits, const char *type)
-{
- const char *name;
- bool notypes;
- void *cookie;
-
- if (limits == NULL)
- return (true);
-
- notypes = true;
- cookie = NULL;
- while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
- if (strncmp(name, "type", sizeof("type") - 1) != 0)
- continue;
- notypes = false;
- if (strcmp(nvlist_get_string(limits, name), type) == 0)
- return (true);
- }
-
- /* If there are no types at all, allow any type. */
- if (notypes)
- return (true);
-
- return (false);
-}
-
-static bool
-dns_allowed_family(const nvlist_t *limits, int family)
-{
- const char *name;
- bool nofamilies;
- void *cookie;
-
- if (limits == NULL)
- return (true);
-
- nofamilies = true;
- cookie = NULL;
- while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
- if (strncmp(name, "family", sizeof("family") - 1) != 0)
- continue;
- nofamilies = false;
- if (family == AF_UNSPEC)
- continue;
- if (nvlist_get_number(limits, name) == (uint64_t)family)
- return (true);
- }
-
- /* If there are no families at all, allow any family. */
- if (nofamilies)
- return (true);
-
- return (false);
-}
-
-static void
-hostent_pack(const struct hostent *hp, nvlist_t *nvl)
-{
- unsigned int ii;
- char nvlname[64];
- int n;
-
- nvlist_add_string(nvl, "name", hp->h_name);
- nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype);
- nvlist_add_number(nvl, "length", (uint64_t)hp->h_length);
-
- if (hp->h_aliases == NULL) {
- nvlist_add_number(nvl, "naliases", 0);
- } else {
- for (ii = 0; hp->h_aliases[ii] != NULL; ii++) {
- n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]);
- }
- nvlist_add_number(nvl, "naliases", (uint64_t)ii);
- }
-
- if (hp->h_addr_list == NULL) {
- nvlist_add_number(nvl, "naddrs", 0);
- } else {
- for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) {
- n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii],
- (size_t)hp->h_length);
- }
- nvlist_add_number(nvl, "naddrs", (uint64_t)ii);
- }
-}
-
-static int
-dns_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- struct hostent *hp;
- int family;
-
- if (!dns_allowed_type(limits, "NAME"))
- return (NO_RECOVERY);
-
- family = (int)nvlist_get_number(nvlin, "family");
-
- if (!dns_allowed_family(limits, family))
- return (NO_RECOVERY);
-
- hp = gethostbyname2(nvlist_get_string(nvlin, "name"), family);
- if (hp == NULL)
- return (h_errno);
- hostent_pack(hp, nvlout);
- return (0);
-}
-
-static int
-dns_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- struct hostent *hp;
- const void *addr;
- size_t addrsize;
- int family;
-
- if (!dns_allowed_type(limits, "ADDR"))
- return (NO_RECOVERY);
-
- family = (int)nvlist_get_number(nvlin, "family");
-
- if (!dns_allowed_family(limits, family))
- return (NO_RECOVERY);
-
- addr = nvlist_get_binary(nvlin, "addr", &addrsize);
- hp = gethostbyaddr(addr, (socklen_t)addrsize, family);
- if (hp == NULL)
- return (h_errno);
- hostent_pack(hp, nvlout);
- return (0);
-}
-
-static int
-dns_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct sockaddr_storage sast;
- const void *sabin;
- char *host, *serv;
- size_t sabinsize, hostlen, servlen;
- socklen_t salen;
- int error, flags;
-
- if (!dns_allowed_type(limits, "NAME"))
- return (NO_RECOVERY);
-
- error = 0;
- host = serv = NULL;
- memset(&sast, 0, sizeof(sast));
-
- hostlen = (size_t)nvlist_get_number(nvlin, "hostlen");
- servlen = (size_t)nvlist_get_number(nvlin, "servlen");
-
- if (hostlen > 0) {
- host = calloc(1, hostlen + 1);
- if (host == NULL) {
- error = EAI_MEMORY;
- goto out;
- }
- }
- if (servlen > 0) {
- serv = calloc(1, servlen + 1);
- if (serv == NULL) {
- error = EAI_MEMORY;
- goto out;
- }
- }
-
- sabin = nvlist_get_binary(nvlin, "sa", &sabinsize);
- if (sabinsize > sizeof(sast)) {
- error = EAI_FAIL;
- goto out;
- }
-
- memcpy(&sast, sabin, sabinsize);
- salen = (socklen_t)sabinsize;
-
- if ((sast.ss_family != AF_INET ||
- salen != sizeof(struct sockaddr_in)) &&
- (sast.ss_family != AF_INET6 ||
- salen != sizeof(struct sockaddr_in6))) {
- error = EAI_FAIL;
- goto out;
- }
-
- if (!dns_allowed_family(limits, (int)sast.ss_family)) {
- error = NO_RECOVERY;
- goto out;
- }
-
- flags = (int)nvlist_get_number(nvlin, "flags");
-
- error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen,
- serv, servlen, flags);
- if (error != 0)
- goto out;
-
- nvlist_move_string(nvlout, "host", host);
- nvlist_move_string(nvlout, "serv", serv);
-out:
- if (error != 0) {
- free(host);
- free(serv);
- }
- return (error);
-}
-
-static nvlist_t *
-addrinfo_pack(const struct addrinfo *ai)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags);
- nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family);
- nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype);
- nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol);
- nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen);
- nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname);
-
- return (nvl);
-}
-
-static int
-dns_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct addrinfo hints, *hintsp, *res, *cur;
- const char *hostname, *servname;
- char nvlname[64];
- nvlist_t *elem;
- unsigned int ii;
- int error, family, n;
-
- if (!dns_allowed_type(limits, "ADDR"))
- return (NO_RECOVERY);
-
- hostname = nvlist_get_string(nvlin, "hostname");
- servname = nvlist_get_string(nvlin, "servname");
- if (nvlist_exists_number(nvlin, "hints.ai_flags")) {
- size_t addrlen;
-
- hints.ai_flags = (int)nvlist_get_number(nvlin,
- "hints.ai_flags");
- hints.ai_family = (int)nvlist_get_number(nvlin,
- "hints.ai_family");
- hints.ai_socktype = (int)nvlist_get_number(nvlin,
- "hints.ai_socktype");
- hints.ai_protocol = (int)nvlist_get_number(nvlin,
- "hints.ai_protocol");
- hints.ai_addrlen = 0;
- hints.ai_addr = NULL;
- hints.ai_canonname = NULL;
- hintsp = &hints;
- family = hints.ai_family;
- } else {
- hintsp = NULL;
- family = AF_UNSPEC;
- }
-
- if (!dns_allowed_family(limits, family))
- return (NO_RECOVERY);
-
- error = getaddrinfo(hostname, servname, hintsp, &res);
- if (error != 0)
- goto out;
-
- for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) {
- elem = addrinfo_pack(cur);
- n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
- assert(n > 0 && n < (int)sizeof(nvlname));
- nvlist_move_nvlist(nvlout, nvlname, elem);
- }
-
- freeaddrinfo(res);
- error = 0;
-out:
- return (error);
-}
-
-static bool
-limit_has_entry(const nvlist_t *limits, const char *prefix)
-{
- const char *name;
- size_t prefixlen;
- void *cookie;
-
- if (limits == NULL)
- return (false);
-
- prefixlen = strlen(prefix);
-
- cookie = NULL;
- while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
- if (strncmp(name, prefix, prefixlen) == 0)
- return (true);
- }
-
- return (false);
-}
-
-static int
-dns_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name;
- void *cookie;
- int nvtype;
- bool hastype, hasfamily;
-
- hastype = false;
- hasfamily = false;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &nvtype, &cookie)) != NULL) {
- if (nvtype == NV_TYPE_STRING) {
- const char *type;
-
- if (strncmp(name, "type", sizeof("type") - 1) != 0)
- return (EINVAL);
- type = nvlist_get_string(newlimits, name);
- if (strcmp(type, "ADDR") != 0 &&
- strcmp(type, "NAME") != 0) {
- return (EINVAL);
- }
- if (!dns_allowed_type(oldlimits, type))
- return (ENOTCAPABLE);
- hastype = true;
- } else if (nvtype == NV_TYPE_NUMBER) {
- int family;
-
- if (strncmp(name, "family", sizeof("family") - 1) != 0)
- return (EINVAL);
- family = (int)nvlist_get_number(newlimits, name);
- if (!dns_allowed_family(oldlimits, family))
- return (ENOTCAPABLE);
- hasfamily = true;
- } else {
- return (EINVAL);
- }
- }
-
- /*
- * If the new limit doesn't mention type or family we have to
- * check if the current limit does have those. Missing type or
- * family in the limit means that all types or families are
- * allowed.
- */
- if (!hastype) {
- if (limit_has_entry(oldlimits, "type"))
- return (ENOTCAPABLE);
- }
- if (!hasfamily) {
- if (limit_has_entry(oldlimits, "family"))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static int
-dns_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- int error;
-
- if (strcmp(cmd, "gethostbyname") == 0)
- error = dns_gethostbyname(limits, nvlin, nvlout);
- else if (strcmp(cmd, "gethostbyaddr") == 0)
- error = dns_gethostbyaddr(limits, nvlin, nvlout);
- else if (strcmp(cmd, "getnameinfo") == 0)
- error = dns_getnameinfo(limits, nvlin, nvlout);
- else if (strcmp(cmd, "getaddrinfo") == 0)
- error = dns_getaddrinfo(limits, nvlin, nvlout);
- else
- error = NO_RECOVERY;
-
- return (error);
-}
-
-int
-main(int argc, char *argv[])
-{
-
- return (service_start("system.dns", PARENT_FILENO, dns_limit,
- dns_command, argc, argv));
-}
Index: head/libexec/casper/grp/Makefile
===================================================================
--- head/libexec/casper/grp/Makefile
+++ head/libexec/casper/grp/Makefile
@@ -1,21 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
-
-PROG= grp
-
-SRCS= grp.c
-
-LIBADD= casper nv pjdlog
-
-BINDIR= /libexec/casper
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
-CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
-CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
-CFLAGS+=-I${.CURDIR}/../../../sbin/casper
-
-MAN=
-
-.include <bsd.prog.mk>
Index: head/libexec/casper/grp/grp.c
===================================================================
--- head/libexec/casper/grp/grp.c
+++ head/libexec/casper/grp/grp.c
@@ -1,390 +0,0 @@
-/*-
- * 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/nv.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <grp.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libcapsicum.h>
-#include <libcasper.h>
-#include <pjdlog.h>
-
-static bool
-grp_allowed_cmd(const nvlist_t *limits, const char *cmd)
-{
-
- if (limits == NULL)
- return (true);
-
- /*
- * If no limit was set on allowed commands, then all commands
- * are allowed.
- */
- if (!nvlist_exists_nvlist(limits, "cmds"))
- return (true);
-
- limits = nvlist_get_nvlist(limits, "cmds");
- return (nvlist_exists_null(limits, cmd));
-}
-
-static int
-grp_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name;
- void *cookie;
- int type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NULL)
- return (EINVAL);
- if (!grp_allowed_cmd(oldlimits, name))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static bool
-grp_allowed_group(const nvlist_t *limits, const char *gname, gid_t gid)
-{
- const char *name;
- void *cookie;
- int type;
-
- if (limits == NULL)
- return (true);
-
- /*
- * If no limit was set on allowed groups, then all groups are allowed.
- */
- if (!nvlist_exists_nvlist(limits, "groups"))
- return (true);
-
- limits = nvlist_get_nvlist(limits, "groups");
- cookie = NULL;
- while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
- switch (type) {
- case NV_TYPE_NUMBER:
- if (gid != (gid_t)-1 &&
- nvlist_get_number(limits, name) == (uint64_t)gid) {
- return (true);
- }
- break;
- case NV_TYPE_STRING:
- if (gname != NULL &&
- strcmp(nvlist_get_string(limits, name),
- gname) == 0) {
- return (true);
- }
- break;
- default:
- PJDLOG_ABORT("Unexpected type %d.", type);
- }
- }
-
- return (false);
-}
-
-static int
-grp_allowed_groups(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name, *gname;
- void *cookie;
- gid_t gid;
- int type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- switch (type) {
- case NV_TYPE_NUMBER:
- gid = (gid_t)nvlist_get_number(newlimits, name);
- gname = NULL;
- break;
- case NV_TYPE_STRING:
- gid = (gid_t)-1;
- gname = nvlist_get_string(newlimits, name);
- break;
- default:
- return (EINVAL);
- }
- if (!grp_allowed_group(oldlimits, gname, gid))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static bool
-grp_allowed_field(const nvlist_t *limits, const char *field)
-{
-
- if (limits == NULL)
- return (true);
-
- /*
- * If no limit was set on allowed fields, then all fields are allowed.
- */
- if (!nvlist_exists_nvlist(limits, "fields"))
- return (true);
-
- limits = nvlist_get_nvlist(limits, "fields");
- return (nvlist_exists_null(limits, field));
-}
-
-static int
-grp_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name;
- void *cookie;
- int type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NULL)
- return (EINVAL);
- if (!grp_allowed_field(oldlimits, name))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static bool
-grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl)
-{
- char nvlname[64];
- int n;
-
- if (grp == NULL)
- return (true);
-
- /*
- * If either name or GID is allowed, we allow it.
- */
- if (!grp_allowed_group(limits, grp->gr_name, grp->gr_gid))
- return (false);
-
- if (grp_allowed_field(limits, "gr_name"))
- nvlist_add_string(nvl, "gr_name", grp->gr_name);
- else
- nvlist_add_string(nvl, "gr_name", "");
- if (grp_allowed_field(limits, "gr_passwd"))
- nvlist_add_string(nvl, "gr_passwd", grp->gr_passwd);
- else
- nvlist_add_string(nvl, "gr_passwd", "");
- if (grp_allowed_field(limits, "gr_gid"))
- nvlist_add_number(nvl, "gr_gid", (uint64_t)grp->gr_gid);
- else
- nvlist_add_number(nvl, "gr_gid", (uint64_t)-1);
- if (grp_allowed_field(limits, "gr_mem") && grp->gr_mem[0] != NULL) {
- unsigned int ngroups;
-
- for (ngroups = 0; grp->gr_mem[ngroups] != NULL; ngroups++) {
- n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]",
- ngroups);
- assert(n > 0 && n < sizeof(nvlname));
- nvlist_add_string(nvl, nvlname, grp->gr_mem[ngroups]);
- }
- nvlist_add_number(nvl, "gr_nmem", (uint64_t)ngroups);
- }
-
- return (true);
-}
-
-static int
-grp_getgrent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct group *grp;
-
- for (;;) {
- errno = 0;
- grp = getgrent();
- if (errno != 0)
- return (errno);
- if (grp_pack(limits, grp, nvlout))
- return (0);
- }
-
- /* NOTREACHED */
-}
-
-static int
-grp_getgrnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct group *grp;
- const char *name;
-
- if (!nvlist_exists_string(nvlin, "name"))
- return (EINVAL);
- name = nvlist_get_string(nvlin, "name");
- PJDLOG_ASSERT(name != NULL);
-
- errno = 0;
- grp = getgrnam(name);
- if (errno != 0)
- return (errno);
-
- (void)grp_pack(limits, grp, nvlout);
-
- return (0);
-}
-
-static int
-grp_getgrgid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct group *grp;
- gid_t gid;
-
- if (!nvlist_exists_number(nvlin, "gid"))
- return (EINVAL);
-
- gid = (gid_t)nvlist_get_number(nvlin, "gid");
-
- errno = 0;
- grp = getgrgid(gid);
- if (errno != 0)
- return (errno);
-
- (void)grp_pack(limits, grp, nvlout);
-
- return (0);
-}
-
-static int
-grp_setgroupent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- int stayopen;
-
- if (!nvlist_exists_bool(nvlin, "stayopen"))
- return (EINVAL);
-
- stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
-
- return (setgroupent(stayopen) == 0 ? EFAULT : 0);
-}
-
-static int
-grp_setgrent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
-
- return (setgrent() == 0 ? EFAULT : 0);
-}
-
-static int
-grp_endgrent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
-
- endgrent();
-
- return (0);
-}
-
-static int
-grp_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const nvlist_t *limits;
- const char *name;
- void *cookie;
- int error, type;
-
- if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
- !nvlist_exists_nvlist(newlimits, "cmds")) {
- return (ENOTCAPABLE);
- }
- if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
- !nvlist_exists_nvlist(newlimits, "fields")) {
- return (ENOTCAPABLE);
- }
- if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "groups") &&
- !nvlist_exists_nvlist(newlimits, "groups")) {
- return (ENOTCAPABLE);
- }
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NVLIST)
- return (EINVAL);
- limits = nvlist_get_nvlist(newlimits, name);
- if (strcmp(name, "cmds") == 0)
- error = grp_allowed_cmds(oldlimits, limits);
- else if (strcmp(name, "fields") == 0)
- error = grp_allowed_fields(oldlimits, limits);
- else if (strcmp(name, "groups") == 0)
- error = grp_allowed_groups(oldlimits, limits);
- else
- error = EINVAL;
- if (error != 0)
- return (error);
- }
-
- return (0);
-}
-
-static int
-grp_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- int error;
-
- if (!grp_allowed_cmd(limits, cmd))
- return (ENOTCAPABLE);
-
- if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0)
- error = grp_getgrent(limits, nvlin, nvlout);
- else if (strcmp(cmd, "getgrnam") == 0 || strcmp(cmd, "getgrnam_r") == 0)
- error = grp_getgrnam(limits, nvlin, nvlout);
- else if (strcmp(cmd, "getgrgid") == 0 || strcmp(cmd, "getgrgid_r") == 0)
- error = grp_getgrgid(limits, nvlin, nvlout);
- else if (strcmp(cmd, "setgroupent") == 0)
- error = grp_setgroupent(limits, nvlin, nvlout);
- else if (strcmp(cmd, "setgrent") == 0)
- error = grp_setgrent(limits, nvlin, nvlout);
- else if (strcmp(cmd, "endgrent") == 0)
- error = grp_endgrent(limits, nvlin, nvlout);
- else
- error = EINVAL;
-
- return (error);
-}
-
-int
-main(int argc, char *argv[])
-{
-
- return (service_start("system.grp", PARENT_FILENO, grp_limit,
- grp_command, argc, argv));
-}
Index: head/libexec/casper/pwd/Makefile
===================================================================
--- head/libexec/casper/pwd/Makefile
+++ head/libexec/casper/pwd/Makefile
@@ -1,21 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
-
-PROG= pwd
-
-SRCS= pwd.c
-
-LIBADD= casper nv pjdlog
-
-BINDIR= /libexec/casper
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
-CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
-CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
-CFLAGS+=-I${.CURDIR}/../../../sbin/casper
-
-MAN=
-
-.include <bsd.prog.mk>
Index: head/libexec/casper/pwd/pwd.c
===================================================================
--- head/libexec/casper/pwd/pwd.c
+++ head/libexec/casper/pwd/pwd.c
@@ -1,430 +0,0 @@
-/*-
- * 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/nv.h>
-
-#include <errno.h>
-#include <pwd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libcapsicum.h>
-#include <libcasper.h>
-#include <pjdlog.h>
-
-static bool
-pwd_allowed_cmd(const nvlist_t *limits, const char *cmd)
-{
-
- if (limits == NULL)
- return (true);
-
- /*
- * If no limit was set on allowed commands, then all commands
- * are allowed.
- */
- if (!nvlist_exists_nvlist(limits, "cmds"))
- return (true);
-
- limits = nvlist_get_nvlist(limits, "cmds");
- return (nvlist_exists_null(limits, cmd));
-}
-
-static int
-pwd_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name;
- void *cookie;
- int type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NULL)
- return (EINVAL);
- if (!pwd_allowed_cmd(oldlimits, name))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static bool
-pwd_allowed_user(const nvlist_t *limits, const char *uname, uid_t uid)
-{
- const char *name;
- void *cookie;
- int type;
-
- if (limits == NULL)
- return (true);
-
- /*
- * If no limit was set on allowed users, then all users are allowed.
- */
- if (!nvlist_exists_nvlist(limits, "users"))
- return (true);
-
- limits = nvlist_get_nvlist(limits, "users");
- cookie = NULL;
- while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
- switch (type) {
- case NV_TYPE_NUMBER:
- if (uid != (uid_t)-1 &&
- nvlist_get_number(limits, name) == (uint64_t)uid) {
- return (true);
- }
- break;
- case NV_TYPE_STRING:
- if (uname != NULL &&
- strcmp(nvlist_get_string(limits, name),
- uname) == 0) {
- return (true);
- }
- break;
- default:
- PJDLOG_ABORT("Unexpected type %d.", type);
- }
- }
-
- return (false);
-}
-
-static int
-pwd_allowed_users(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name, *uname;
- void *cookie;
- uid_t uid;
- int type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- switch (type) {
- case NV_TYPE_NUMBER:
- uid = (uid_t)nvlist_get_number(newlimits, name);
- uname = NULL;
- break;
- case NV_TYPE_STRING:
- uid = (uid_t)-1;
- uname = nvlist_get_string(newlimits, name);
- break;
- default:
- return (EINVAL);
- }
- if (!pwd_allowed_user(oldlimits, uname, uid))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static bool
-pwd_allowed_field(const nvlist_t *limits, const char *field)
-{
-
- if (limits == NULL)
- return (true);
-
- /*
- * If no limit was set on allowed fields, then all fields are allowed.
- */
- if (!nvlist_exists_nvlist(limits, "fields"))
- return (true);
-
- limits = nvlist_get_nvlist(limits, "fields");
- return (nvlist_exists_null(limits, field));
-}
-
-static int
-pwd_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name;
- void *cookie;
- int type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NULL)
- return (EINVAL);
- if (!pwd_allowed_field(oldlimits, name))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static bool
-pwd_pack(const nvlist_t *limits, const struct passwd *pwd, nvlist_t *nvl)
-{
- int fields;
-
- if (pwd == NULL)
- return (true);
-
- /*
- * If either name or UID is allowed, we allow it.
- */
- if (!pwd_allowed_user(limits, pwd->pw_name, pwd->pw_uid))
- return (false);
-
- fields = pwd->pw_fields;
-
- if (pwd_allowed_field(limits, "pw_name")) {
- nvlist_add_string(nvl, "pw_name", pwd->pw_name);
- } else {
- nvlist_add_string(nvl, "pw_name", "");
- fields &= ~_PWF_NAME;
- }
- if (pwd_allowed_field(limits, "pw_uid")) {
- nvlist_add_number(nvl, "pw_uid", (uint64_t)pwd->pw_uid);
- } else {
- nvlist_add_number(nvl, "pw_uid", (uint64_t)-1);
- fields &= ~_PWF_UID;
- }
- if (pwd_allowed_field(limits, "pw_gid")) {
- nvlist_add_number(nvl, "pw_gid", (uint64_t)pwd->pw_gid);
- } else {
- nvlist_add_number(nvl, "pw_gid", (uint64_t)-1);
- fields &= ~_PWF_GID;
- }
- if (pwd_allowed_field(limits, "pw_change")) {
- nvlist_add_number(nvl, "pw_change", (uint64_t)pwd->pw_change);
- } else {
- nvlist_add_number(nvl, "pw_change", (uint64_t)0);
- fields &= ~_PWF_CHANGE;
- }
- if (pwd_allowed_field(limits, "pw_passwd")) {
- nvlist_add_string(nvl, "pw_passwd", pwd->pw_passwd);
- } else {
- nvlist_add_string(nvl, "pw_passwd", "");
- fields &= ~_PWF_PASSWD;
- }
- if (pwd_allowed_field(limits, "pw_class")) {
- nvlist_add_string(nvl, "pw_class", pwd->pw_class);
- } else {
- nvlist_add_string(nvl, "pw_class", "");
- fields &= ~_PWF_CLASS;
- }
- if (pwd_allowed_field(limits, "pw_gecos")) {
- nvlist_add_string(nvl, "pw_gecos", pwd->pw_gecos);
- } else {
- nvlist_add_string(nvl, "pw_gecos", "");
- fields &= ~_PWF_GECOS;
- }
- if (pwd_allowed_field(limits, "pw_dir")) {
- nvlist_add_string(nvl, "pw_dir", pwd->pw_dir);
- } else {
- nvlist_add_string(nvl, "pw_dir", "");
- fields &= ~_PWF_DIR;
- }
- if (pwd_allowed_field(limits, "pw_shell")) {
- nvlist_add_string(nvl, "pw_shell", pwd->pw_shell);
- } else {
- nvlist_add_string(nvl, "pw_shell", "");
- fields &= ~_PWF_SHELL;
- }
- if (pwd_allowed_field(limits, "pw_expire")) {
- nvlist_add_number(nvl, "pw_expire", (uint64_t)pwd->pw_expire);
- } else {
- nvlist_add_number(nvl, "pw_expire", (uint64_t)0);
- fields &= ~_PWF_EXPIRE;
- }
- nvlist_add_number(nvl, "pw_fields", (uint64_t)fields);
-
- return (true);
-}
-
-static int
-pwd_getpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct passwd *pwd;
-
- for (;;) {
- errno = 0;
- pwd = getpwent();
- if (errno != 0)
- return (errno);
- if (pwd_pack(limits, pwd, nvlout))
- return (0);
- }
-
- /* NOTREACHED */
-}
-
-static int
-pwd_getpwnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct passwd *pwd;
- const char *name;
-
- if (!nvlist_exists_string(nvlin, "name"))
- return (EINVAL);
- name = nvlist_get_string(nvlin, "name");
- PJDLOG_ASSERT(name != NULL);
-
- errno = 0;
- pwd = getpwnam(name);
- if (errno != 0)
- return (errno);
-
- (void)pwd_pack(limits, pwd, nvlout);
-
- return (0);
-}
-
-static int
-pwd_getpwuid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- struct passwd *pwd;
- uid_t uid;
-
- if (!nvlist_exists_number(nvlin, "uid"))
- return (EINVAL);
-
- uid = (uid_t)nvlist_get_number(nvlin, "uid");
-
- errno = 0;
- pwd = getpwuid(uid);
- if (errno != 0)
- return (errno);
-
- (void)pwd_pack(limits, pwd, nvlout);
-
- return (0);
-}
-
-static int
-pwd_setpassent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
- int stayopen;
-
- if (!nvlist_exists_bool(nvlin, "stayopen"))
- return (EINVAL);
-
- stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
-
- return (setpassent(stayopen) == 0 ? EFAULT : 0);
-}
-
-static int
-pwd_setpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
-
- setpwent();
-
- return (0);
-}
-
-static int
-pwd_endpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
-{
-
- endpwent();
-
- return (0);
-}
-
-static int
-pwd_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const nvlist_t *limits;
- const char *name;
- void *cookie;
- int error, type;
-
- if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
- !nvlist_exists_nvlist(newlimits, "cmds")) {
- return (ENOTCAPABLE);
- }
- if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
- !nvlist_exists_nvlist(newlimits, "fields")) {
- return (ENOTCAPABLE);
- }
- if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "users") &&
- !nvlist_exists_nvlist(newlimits, "users")) {
- return (ENOTCAPABLE);
- }
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NVLIST)
- return (EINVAL);
- limits = nvlist_get_nvlist(newlimits, name);
- if (strcmp(name, "cmds") == 0)
- error = pwd_allowed_cmds(oldlimits, limits);
- else if (strcmp(name, "fields") == 0)
- error = pwd_allowed_fields(oldlimits, limits);
- else if (strcmp(name, "users") == 0)
- error = pwd_allowed_users(oldlimits, limits);
- else
- error = EINVAL;
- if (error != 0)
- return (error);
- }
-
- return (0);
-}
-
-static int
-pwd_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- int error;
-
- if (!pwd_allowed_cmd(limits, cmd))
- return (ENOTCAPABLE);
-
- if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0)
- error = pwd_getpwent(limits, nvlin, nvlout);
- else if (strcmp(cmd, "getpwnam") == 0 || strcmp(cmd, "getpwnam_r") == 0)
- error = pwd_getpwnam(limits, nvlin, nvlout);
- else if (strcmp(cmd, "getpwuid") == 0 || strcmp(cmd, "getpwuid_r") == 0)
- error = pwd_getpwuid(limits, nvlin, nvlout);
- else if (strcmp(cmd, "setpassent") == 0)
- error = pwd_setpassent(limits, nvlin, nvlout);
- else if (strcmp(cmd, "setpwent") == 0)
- error = pwd_setpwent(limits, nvlin, nvlout);
- else if (strcmp(cmd, "endpwent") == 0)
- error = pwd_endpwent(limits, nvlin, nvlout);
- else
- error = EINVAL;
-
- return (error);
-}
-
-int
-main(int argc, char *argv[])
-{
-
- return (service_start("system.pwd", PARENT_FILENO, pwd_limit,
- pwd_command, argc, argv));
-}
Index: head/libexec/casper/random/Makefile
===================================================================
--- head/libexec/casper/random/Makefile
+++ head/libexec/casper/random/Makefile
@@ -1,21 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
-
-PROG= random
-
-SRCS= random.c
-
-LIBADD= casper nv
-
-BINDIR= /libexec/casper
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
-CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
-CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
-CFLAGS+=-I${.CURDIR}/../../../sbin/casper
-
-MAN=
-
-.include <bsd.prog.mk>
Index: head/libexec/casper/random/random.c
===================================================================
--- head/libexec/casper/random/random.c
+++ head/libexec/casper/random/random.c
@@ -1,82 +0,0 @@
-/*-
- * Copyright (c) 2012-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/nv.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libcapsicum.h>
-#include <libcasper.h>
-#include <pjdlog.h>
-
-#define MAXSIZE (1024 * 1024)
-
-static int
-random_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- void *data;
- size_t size;
-
- if (strcmp(cmd, "generate") != 0)
- return (EINVAL);
- if (!nvlist_exists_number(nvlin, "size"))
- return (EINVAL);
-
- size = (size_t)nvlist_get_number(nvlin, "size");
- if (size == 0 || size > MAXSIZE)
- return (EINVAL);
-
- data = malloc(size);
- if (data == NULL)
- return (ENOMEM);
-
- arc4random_buf(data, size);
-
- nvlist_move_binary(nvlout, "data", data, size);
-
- return (0);
-}
-
-int
-main(int argc, char *argv[])
-{
-
- /*
- * TODO: Sandbox this.
- */
-
- return (service_start("system.random", PARENT_FILENO, NULL,
- random_command, argc, argv));
-}
Index: head/libexec/casper/sysctl/Makefile
===================================================================
--- head/libexec/casper/sysctl/Makefile
+++ head/libexec/casper/sysctl/Makefile
@@ -1,21 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
-
-PROG= sysctl
-
-SRCS= sysctl.c
-
-LIBADD= casper nv pjdlog
-
-BINDIR= /libexec/casper
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
-CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
-CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
-CFLAGS+=-I${.CURDIR}/../../../sbin/casper
-
-MAN=
-
-.include <bsd.prog.mk>
Index: head/libexec/casper/sysctl/sysctl.c
===================================================================
--- head/libexec/casper/sysctl/sysctl.c
+++ head/libexec/casper/sysctl/sysctl.c
@@ -1,249 +0,0 @@
-/*-
- * 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/sysctl.h>
-#include <sys/nv.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libcapsicum.h>
-#include <libcapsicum_sysctl.h>
-#include <libcasper.h>
-#include <pjdlog.h>
-
-static int
-sysctl_check_one(const nvlist_t *nvl, bool islimit)
-{
- const char *name;
- void *cookie;
- int type;
- unsigned int fields;
-
- /* NULL nvl is of course invalid. */
- if (nvl == NULL)
- return (EINVAL);
- if (nvlist_error(nvl) != 0)
- return (nvlist_error(nvl));
-
-#define HAS_NAME 0x01
-#define HAS_OPERATION 0x02
-
- fields = 0;
- cookie = NULL;
- while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
- /* We accept only one 'name' and one 'operation' in nvl. */
- if (strcmp(name, "name") == 0) {
- if (type != NV_TYPE_STRING)
- return (EINVAL);
- /* Only one 'name' can be present. */
- if ((fields & HAS_NAME) != 0)
- return (EINVAL);
- fields |= HAS_NAME;
- } else if (strcmp(name, "operation") == 0) {
- uint64_t operation;
-
- if (type != NV_TYPE_NUMBER)
- return (EINVAL);
- /*
- * We accept only CAP_SYSCTL_READ and
- * CAP_SYSCTL_WRITE flags.
- */
- operation = nvlist_get_number(nvl, name);
- if ((operation & ~(CAP_SYSCTL_RDWR)) != 0)
- return (EINVAL);
- /* ...but there has to be at least one of them. */
- if ((operation & (CAP_SYSCTL_RDWR)) == 0)
- return (EINVAL);
- /* Only one 'operation' can be present. */
- if ((fields & HAS_OPERATION) != 0)
- return (EINVAL);
- fields |= HAS_OPERATION;
- } else if (islimit) {
- /* If this is limit, there can be no other fields. */
- return (EINVAL);
- }
- }
-
- /* Both fields has to be there. */
- if (fields != (HAS_NAME | HAS_OPERATION))
- return (EINVAL);
-
-#undef HAS_OPERATION
-#undef HAS_NAME
-
- return (0);
-}
-
-static bool
-sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation)
-{
- uint64_t operation;
- const char *name;
- void *cookie;
- int type;
-
- if (limits == NULL)
- return (true);
-
- cookie = NULL;
- while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
- PJDLOG_ASSERT(type == NV_TYPE_NUMBER);
-
- operation = nvlist_get_number(limits, name);
- if ((operation & choperation) != choperation)
- continue;
-
- if ((operation & CAP_SYSCTL_RECURSIVE) == 0) {
- if (strcmp(name, chname) != 0)
- continue;
- } else {
- size_t namelen;
-
- namelen = strlen(name);
- if (strncmp(name, chname, namelen) != 0)
- continue;
- if (chname[namelen] != '.' && chname[namelen] != '\0')
- continue;
- }
-
- return (true);
- }
-
- return (false);
-}
-
-static int
-sysctl_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const nvlist_t *nvl;
- const char *name;
- void *cookie;
- uint64_t operation;
- int error, type;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NUMBER)
- return (EINVAL);
- operation = nvlist_get_number(newlimits, name);
- if ((operation & ~(CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) != 0)
- return (EINVAL);
- if ((operation & (CAP_SYSCTL_RDWR | CAP_SYSCTL_RECURSIVE)) == 0)
- return (EINVAL);
- if (!sysctl_allowed(oldlimits, name, operation))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static int
-sysctl_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- const char *name;
- const void *newp;
- void *oldp;
- uint64_t operation;
- size_t oldlen, newlen;
- size_t *oldlenp;
- int error;
-
- if (strcmp(cmd, "sysctl") != 0)
- return (EINVAL);
- error = sysctl_check_one(nvlin, false);
- if (error != 0)
- return (error);
-
- name = nvlist_get_string(nvlin, "name");
- operation = nvlist_get_number(nvlin, "operation");
- if (!sysctl_allowed(limits, name, operation))
- return (ENOTCAPABLE);
-
- if ((operation & CAP_SYSCTL_WRITE) != 0) {
- if (!nvlist_exists_binary(nvlin, "newp"))
- return (EINVAL);
- newp = nvlist_get_binary(nvlin, "newp", &newlen);
- PJDLOG_ASSERT(newp != NULL && newlen > 0);
- } else {
- newp = NULL;
- newlen = 0;
- }
-
- if ((operation & CAP_SYSCTL_READ) != 0) {
- if (nvlist_exists_null(nvlin, "justsize")) {
- oldp = NULL;
- oldlen = 0;
- oldlenp = &oldlen;
- } else {
- if (!nvlist_exists_number(nvlin, "oldlen"))
- return (EINVAL);
- oldlen = (size_t)nvlist_get_number(nvlin, "oldlen");
- if (oldlen == 0)
- return (EINVAL);
- oldp = calloc(1, oldlen);
- if (oldp == NULL)
- return (ENOMEM);
- oldlenp = &oldlen;
- }
- } else {
- oldp = NULL;
- oldlen = 0;
- oldlenp = NULL;
- }
-
- if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) {
- error = errno;
- free(oldp);
- return (error);
- }
-
- if ((operation & CAP_SYSCTL_READ) != 0) {
- if (nvlist_exists_null(nvlin, "justsize"))
- nvlist_add_number(nvlout, "oldlen", (uint64_t)oldlen);
- else
- nvlist_move_binary(nvlout, "oldp", oldp, oldlen);
- }
-
- return (0);
-}
-
-int
-main(int argc, char *argv[])
-{
-
- return (service_start("system.sysctl", PARENT_FILENO, sysctl_limit,
- sysctl_command, argc, argv));
-}
Index: head/libexec/rtld-elf/paths.h
===================================================================
--- head/libexec/rtld-elf/paths.h
+++ head/libexec/rtld-elf/paths.h
@@ -52,7 +52,7 @@
#endif
#ifndef STANDARD_LIBRARY_PATH
-#define STANDARD_LIBRARY_PATH "/lib:/usr/lib"
+#define STANDARD_LIBRARY_PATH "/lib/casper:/lib:/usr/lib"
#endif
#ifndef LD_
Index: head/sbin/Makefile
===================================================================
--- head/sbin/Makefile
+++ head/sbin/Makefile
@@ -71,7 +71,6 @@
umount
SUBDIR.${MK_ATM}+= atm
-SUBDIR.${MK_CASPER}+= casperd
SUBDIR.${MK_CCD}+= ccdconfig
SUBDIR.${MK_CXX}+= devd
SUBDIR.${MK_HAST}+= hastctl
Index: head/sbin/casperd/Makefile
===================================================================
--- head/sbin/casperd/Makefile
+++ head/sbin/casperd/Makefile
@@ -1,17 +0,0 @@
-# $FreeBSD$
-
-PROG= casperd
-
-SRCS= casperd.c zygote.c
-
-LIBADD= casper nv pjdlog util
-
-MAN= casperd.8
-
-CFLAGS+=-I${.CURDIR}
-CFLAGS+=-I${.CURDIR}/../../lib/libcapsicum
-CFLAGS+=-I${.CURDIR}/../../lib/libcasper
-CFLAGS+=-I${.CURDIR}/../../lib/libnv
-CFLAGS+=-I${.CURDIR}/../../lib/libpjdlog
-
-.include <bsd.prog.mk>
Index: head/sbin/casperd/casperd.8
===================================================================
--- head/sbin/casperd/casperd.8
+++ head/sbin/casperd/casperd.8
@@ -1,132 +0,0 @@
-.\" Copyright (c) 2013 The FreeBSD Foundation
-.\" All rights reserved.
-.\"
-.\" This documentation was written 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd October 26, 2013
-.Dt CASPERD 8
-.Os
-.Sh NAME
-.Nm casperd
-.Nd "Capability Services friendly daemon"
-.Sh SYNOPSIS
-.Nm
-.Op Fl Fhv
-.Op Fl l Ar listenqueue
-.Op Fl D Ar servconfdir
-.Op Fl P Ar pidfile
-.Op Fl S Ar sockpath
-.Sh DESCRIPTION
-The
-.Nm
-daemon hosts various services that can be accessed through
-libcapsicum's capabilities by programs running in sandboxes.
-For example it is prohibited to send UDP packets to arbitrary destinations
-when operating in capability mode, which makes DNS resolution impossible.
-To make it possible the
-.Nm
-daemon provides the
-.Nm system.dns
-service that proxies DNS resolution requests through a dedicated,
-non-sandboxed process provided by
-.Nm .
-.Pp
-The
-.Nm
-daemon can be started with the following command line arguments:
-.Bl -tag -width ".Fl D Ar servconfdir"
-.It Fl D Ar servconfdir
-Specify alternative location of the service configuration directory.
-The default location is
-.Pa /etc/casper/ .
-.It Fl F
-Start the
-.Nm
-daemon in the foreground.
-By default
-.Nm
-starts in the background.
-.It Fl h
-Print the
-.Nm
-usage message.
-.It Fl l Ar listenqueue
-Specify depth of socket listen queue for the
-.Nm
-daemon.
-The default queue length is
-.Pa SOMAXCONN .
-.It Fl P Ar pidfile
-Specify alternative location of a file where main process PID will be
-stored.
-The default location is
-.Pa /var/run/casperd.pid .
-.It Fl S Ar sockpath
-Specify alternative location of the
-.Xr unix 4
-domain socket used to connect to the
-.Nm
-daemon.
-The default location is
-.Pa /var/run/casper .
-.It Fl v
-Print or log verbose/debugging information.
-This option can be specified multiple times to raise the verbosity
-level.
-.El
-.Sh FILES
-.Bl -tag -width ".Pa /var/run/casperd.pid" -compact
-.It Pa /etc/casper/
-The configuration directory for
-.Nm
-services.
-.It Pa /var/run/casper
-.Xr unix 4
-domain socket used to connect to the
-.Nm
-daemon.
-.It Pa /var/run/casperd.pid
-The default location of the
-.Nm
-PID file.
-.El
-.Sh EXIT STATUS
-The
-.Nm
-daemon exits 0 on success, and >0 if an error occurs.
-.Sh SEE ALSO
-.Xr cap_enter 2 ,
-.Xr libcapsicum 3 ,
-.Xr pidfile 3 ,
-.Xr capsicum 4 ,
-.Xr unix 4
-.Sh AUTHORS
-The
-.Nm
-was implemented by
-.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
-under sponsorship from the FreeBSD Foundation.
Index: head/sbin/casperd/casperd.c
===================================================================
--- head/sbin/casperd/casperd.c
+++ head/sbin/casperd/casperd.c
@@ -1,721 +0,0 @@
-/*-
- * Copyright (c) 2012 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/capsicum.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <sys/nv.h>
-
-#include <assert.h>
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <libutil.h>
-#include <paths.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include <libcapsicum.h>
-#include <libcapsicum_impl.h>
-#include <libcasper.h>
-#include <libcasper_impl.h>
-#include <msgio.h>
-#include <pjdlog.h>
-
-#include "msgio.h"
-
-#include "zygote.h"
-
-#define CASPERD_PIDFILE "/var/run/casperd.pid"
-#define CASPERD_SERVCONFDIR "/etc/casper"
-#define CASPERD_SOCKPATH "/var/run/casper"
-
-typedef void service_function_t(struct service_connection *, const nvlist_t *,
- nvlist_t *);
-
-struct casper_service {
- const char *cs_name;
- const char *cs_execpath;
- struct service *cs_service;
- nvlist_t *cs_attrs;
- TAILQ_ENTRY(casper_service) cs_next;
-};
-
-static TAILQ_HEAD(, casper_service) casper_services =
- TAILQ_HEAD_INITIALIZER(casper_services);
-
-#define SERVICE_IS_CORE(service) ((service)->cs_execpath == NULL)
-
-static void service_external_execute(int chanfd);
-
-#define KEEP_ERRNO(work) do { \
- int _serrno; \
- \
- _serrno = errno; \
- work; \
- errno = _serrno; \
-} while (0)
-
-static struct casper_service *
-service_find(const char *name)
-{
- struct casper_service *casserv;
-
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
- if (strcmp(casserv->cs_name, name) == 0)
- break;
- }
- return (casserv);
-}
-
-/*
- * Function always consumes the given attrs.
- */
-static void
-service_register(nvlist_t *attrs)
-{
- struct casper_service *casserv;
- const char *name;
-
- PJDLOG_ASSERT(nvlist_exists_string(attrs, "name"));
- PJDLOG_ASSERT(nvlist_exists_string(attrs, "execpath") ||
- (nvlist_exists_number(attrs, "commandfunc") &&
- nvlist_exists_number(attrs, "limitfunc")));
-
- name = nvlist_get_string(attrs, "name");
- PJDLOG_ASSERT(name != NULL);
- if (name[0] == '\0') {
- pjdlog_error("Unable to register service with an empty name.");
- nvlist_destroy(attrs);
- return;
- }
- if (service_find(name) != NULL) {
- pjdlog_error("Service \"%s\" is already registered.", name);
- nvlist_destroy(attrs);
- return;
- }
-
- casserv = malloc(sizeof(*casserv));
- if (casserv == NULL) {
- pjdlog_errno(LOG_ERR, "Unable to register service \"%s\"",
- name);
- nvlist_destroy(attrs);
- return;
- }
- casserv->cs_name = name;
- if (nvlist_exists_string(attrs, "execpath")) {
- struct stat sb;
-
- PJDLOG_ASSERT(!nvlist_exists_number(attrs, "commandfunc"));
- PJDLOG_ASSERT(!nvlist_exists_number(attrs, "limitfunc"));
-
- casserv->cs_service = NULL;
-
- casserv->cs_execpath = nvlist_get_string(attrs, "execpath");
- if (casserv->cs_execpath == NULL ||
- casserv->cs_execpath[0] == '\0') {
- pjdlog_error("Unable to register service with an empty execpath.");
- free(casserv);
- nvlist_destroy(attrs);
- return;
- }
- if (stat(casserv->cs_execpath, &sb) == -1) {
- pjdlog_errno(LOG_ERR,
- "Unable to register service \"%s\", problem with executable \"%s\"",
- name, casserv->cs_execpath);
- free(casserv);
- nvlist_destroy(attrs);
- return;
- }
- } else /* if (nvlist_exists_number(attrs, "commandfunc")) */ {
- PJDLOG_ASSERT(!nvlist_exists_string(attrs, "execpath"));
-
- casserv->cs_execpath = NULL;
-
- casserv->cs_service = service_alloc(name,
- (void *)(uintptr_t)nvlist_get_number(attrs, "limitfunc"),
- (void *)(uintptr_t)nvlist_get_number(attrs, "commandfunc"));
- if (casserv->cs_service == NULL) {
- pjdlog_errno(LOG_ERR,
- "Unable to register service \"%s\"", name);
- free(casserv);
- nvlist_destroy(attrs);
- return;
- }
- }
- casserv->cs_attrs = attrs;
- TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next);
- pjdlog_debug(1, "Service %s successfully registered.",
- casserv->cs_name);
-}
-
-static bool
-casper_allowed_service(const nvlist_t *limits, const char *service)
-{
-
- if (limits == NULL)
- return (true);
-
- if (nvlist_exists_null(limits, service))
- return (true);
-
- return (false);
-}
-
-static int
-casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
-{
- const char *name;
- int type;
- void *cookie;
-
- cookie = NULL;
- while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
- if (type != NV_TYPE_NULL)
- return (EINVAL);
- if (!casper_allowed_service(oldlimits, name))
- return (ENOTCAPABLE);
- }
-
- return (0);
-}
-
-static int
-casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
- nvlist_t *nvlout)
-{
- struct casper_service *casserv;
- const char *servname;
- nvlist_t *nvl;
- int chanfd, execfd, procfd, error;
-
- if (strcmp(cmd, "open") != 0)
- return (EINVAL);
- if (!nvlist_exists_string(nvlin, "service"))
- return (EINVAL);
-
- servname = nvlist_get_string(nvlin, "service");
-
- casserv = service_find(servname);
- if (casserv == NULL)
- return (ENOENT);
-
- if (!casper_allowed_service(limits, servname))
- return (ENOTCAPABLE);
-
-#ifdef O_EXEC_WORKING
- execfd = open(casserv->cs_execpath, O_EXEC);
-#else
- execfd = open(casserv->cs_execpath, O_RDONLY);
-#endif
- if (execfd < -1) {
- error = errno;
- pjdlog_errno(LOG_ERR,
- "Unable to open executable '%s' of service '%s'",
- casserv->cs_execpath, casserv->cs_name);
- return (error);
- }
-
- if (zygote_clone(service_external_execute, &chanfd, &procfd) == -1) {
- error = errno;
- close(execfd);
- return (error);
- }
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "service", casserv->cs_name);
- if (nvlist_exists_descriptor(nvlin, "stderrfd")) {
- nvlist_move_descriptor(nvl, "stderrfd",
- nvlist_take_descriptor(nvlin, "stderrfd"));
- }
- nvlist_move_descriptor(nvl, "execfd", execfd);
- nvlist_move_descriptor(nvl, "procfd", procfd);
- if (nvlist_send(chanfd, nvl) == -1) {
- error = errno;
- pjdlog_errno(LOG_ERR, "Unable to send nvlist");
- nvlist_destroy(nvl);
- close(chanfd);
- return (error);
- }
- nvlist_destroy(nvl);
-
- nvlist_move_descriptor(nvlout, "chanfd", chanfd);
-
- return (0);
-}
-
-static void
-fdswap(int *fd0, int *fd1)
-{
- int tmpfd;
-
- PJDLOG_VERIFY((tmpfd = dup(*fd0)) != -1);
- PJDLOG_VERIFY(dup2(*fd1, *fd0) != -1);
- PJDLOG_VERIFY(dup2(tmpfd, *fd1) != -1);
- close(tmpfd);
- tmpfd = *fd0;
- *fd0 = *fd1;
- *fd1 = tmpfd;
-}
-
-static void
-fdmove(int *oldfdp, int newfd)
-{
-
- if (*oldfdp != newfd) {
- PJDLOG_VERIFY(dup2(*oldfdp, newfd) != -1);
- close(*oldfdp);
- *oldfdp = newfd;
- }
-}
-
-static void
-fdcloexec(int fd)
-{
- int flags;
-
- flags = fcntl(fd, F_GETFD);
- PJDLOG_ASSERT(flags != -1);
- if ((flags & FD_CLOEXEC) != 0)
- PJDLOG_VERIFY(fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) != -1);
-}
-
-static void
-service_register_core(void)
-{
- nvlist_t *nvl;
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "name", "core.casper");
- nvlist_add_number(nvl, "limitfunc", (uint64_t)(uintptr_t)casper_limit);
- nvlist_add_number(nvl, "commandfunc",
- (uint64_t)(uintptr_t)casper_command);
- service_register(nvl);
-}
-
-static int
-setup_creds(int sock)
-{
- struct cmsgcred cred;
-
- if (cred_recv(sock, &cred) == -1)
- return (-1);
-
- if (setgroups((int)cred.cmcred_ngroups, cred.cmcred_groups) == -1)
- return (-1);
-
- if (setgid(cred.cmcred_groups[0]) == -1)
- return (-1);
-
- if (setuid(cred.cmcred_euid) == -1)
- return (-1);
-
- return (0);
-}
-
-static void
-service_external_execute(int chanfd)
-{
- char *service, *argv[3];
- int stderrfd, execfd, procfd;
- nvlist_t *nvl;
-
- nvl = nvlist_recv(chanfd, 0);
- if (nvl == NULL)
- pjdlog_exit(1, "Unable to receive nvlist");
- service = nvlist_take_string(nvl, "service");
- PJDLOG_ASSERT(service != NULL);
- if (nvlist_exists_descriptor(nvl, "stderrfd")) {
- stderrfd = nvlist_take_descriptor(nvl, "stderrfd");
- } else {
- stderrfd = open(_PATH_DEVNULL, O_RDWR);
- if (stderrfd < 0)
- pjdlog_exit(1, "Unable to open %s", _PATH_DEVNULL);
- }
- execfd = nvlist_take_descriptor(nvl, "execfd");
- procfd = nvlist_take_descriptor(nvl, "procfd");
- nvlist_destroy(nvl);
-
- /*
- * Move all descriptors into right slots.
- */
-
- if (stderrfd != STDERR_FILENO) {
- if (chanfd == STDERR_FILENO)
- fdswap(&stderrfd, &chanfd);
- else if (execfd == STDERR_FILENO)
- fdswap(&stderrfd, &execfd);
- else if (procfd == STDERR_FILENO)
- fdswap(&stderrfd, &procfd);
- fdmove(&stderrfd, STDERR_FILENO);
- }
- fdcloexec(stderrfd);
-
- if (chanfd != PARENT_FILENO) {
- if (execfd == PARENT_FILENO)
- fdswap(&chanfd, &execfd);
- else if (procfd == PARENT_FILENO)
- fdswap(&chanfd, &procfd);
- fdmove(&chanfd, PARENT_FILENO);
- }
- fdcloexec(chanfd);
-
- if (execfd != EXECUTABLE_FILENO) {
- if (procfd == EXECUTABLE_FILENO)
- fdswap(&execfd, &procfd);
- fdmove(&execfd, EXECUTABLE_FILENO);
- }
- fdcloexec(execfd);
-
- if (procfd != PROC_FILENO)
- fdmove(&procfd, PROC_FILENO);
- fdcloexec(procfd);
-
- /*
- * Use credentials of the caller process.
- */
- setup_creds(chanfd);
-
- argv[0] = service;
- asprintf(&argv[1], "%d", pjdlog_debug_get());
- argv[2] = NULL;
-
- fexecve(execfd, argv, NULL);
- pjdlog_exit(1, "Unable to execute service %s", service);
-}
-
-static void
-service_register_external_one(const char *dirpath, int dfd,
- const char *filename)
-{
- char execpath[FILENAME_MAX];
- nvlist_t *nvl;
- ssize_t done;
- int fd;
-
- fd = openat(dfd, filename, O_RDONLY);
- if (fd == -1) {
- pjdlog_errno(LOG_ERR, "Unable to open \"%s/%s\"", dirpath,
- filename);
- return;
- }
-
- done = read(fd, execpath, sizeof(execpath));
- if (done == -1) {
- pjdlog_errno(LOG_ERR, "Unable to read content of \"%s/%s\"",
- dirpath, filename);
- close(fd);
- return;
- }
- close(fd);
- if (done == sizeof(execpath)) {
- pjdlog_error("Executable path too long in \"%s/%s\".", dirpath,
- filename);
- return;
- }
- execpath[done] = '\0';
- while (done > 0) {
- if (execpath[--done] == '\n')
- execpath[done] = '\0';
- }
-
- nvl = nvlist_create(0);
- nvlist_add_string(nvl, "name", filename);
- nvlist_add_string(nvl, "execpath", execpath);
- if (nvlist_error(nvl) != 0) {
- pjdlog_common(LOG_ERR, 0, nvlist_error(nvl),
- "Unable to allocate attributes for service \"%s/%s\"",
- dirpath, filename);
- nvlist_destroy(nvl);
- return;
- }
-
- service_register(nvl);
- /* service_register() consumed nvl. */
-}
-
-static uint8_t
-file_type(int dfd, const char *filename)
-{
- struct stat sb;
-
- if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
- pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename);
- return (DT_UNKNOWN);
- }
- return (IFTODT(sb.st_mode));
-}
-
-static void
-service_register_external(const char *dirpath)
-{
- DIR *dirp;
- struct dirent *dp;
- int dfd;
-
- dirp = opendir(dirpath);
- if (dirp == NULL) {
- pjdlog_errno(LOG_WARNING, "Unable to open \"%s\"", dirpath);
- return;
- }
- dfd = dirfd(dirp);
- PJDLOG_ASSERT(dfd >= 0);
- while ((dp = readdir(dirp)) != NULL) {
- dp->d_type = file_type(dfd, dp->d_name);
- /* We are only interested in regular files, skip the rest. */
- if (dp->d_type != DT_REG) {
- pjdlog_debug(1,
- "File \"%s/%s\" is not a regular file, skipping.",
- dirpath, dp->d_name);
- continue;
- }
- service_register_external_one(dirpath, dfd, dp->d_name);
- }
- closedir(dirp);
-}
-
-static void
-casper_accept(int lsock)
-{
- struct casper_service *casserv;
- struct service_connection *sconn;
- int sock;
-
- sock = accept(lsock, NULL, NULL);
- if (sock == -1) {
- pjdlog_errno(LOG_ERR, "Unable to accept casper connection");
- return;
- }
- casserv = service_find("core.casper");
- PJDLOG_ASSERT(casserv != NULL);
-
- sconn = service_connection_add(casserv->cs_service, sock, NULL);
- if (sconn == NULL) {
- close(sock);
- return;
- }
-}
-
-static void
-main_loop(int lqlen, const char *sockpath, struct pidfh *pfh)
-{
- fd_set fds;
- struct sockaddr_un sun;
- struct casper_service *casserv;
- struct service_connection *sconn, *sconntmp;
- int lsock, sock, maxfd, ret;
- mode_t oldumask;
-
- lsock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (lsock == -1)
- pjdlog_exit(1, "Unable to create socket");
-
- (void)unlink(sockpath);
-
- bzero(&sun, sizeof(sun));
- sun.sun_family = AF_UNIX;
- PJDLOG_VERIFY(strlcpy(sun.sun_path, sockpath, sizeof(sun.sun_path)) <
- sizeof(sun.sun_path));
- sun.sun_len = SUN_LEN(&sun);
-
- oldumask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
- if (bind(lsock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
- pjdlog_exit(1, "Unable to bind to %s", sockpath);
- (void)umask(oldumask);
- if (listen(lsock, lqlen) == -1)
- pjdlog_exit(1, "Unable to listen on %s", sockpath);
-
- for (;;) {
- FD_ZERO(&fds);
- FD_SET(lsock, &fds);
- maxfd = lsock;
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
- /* We handle only core services. */
- if (!SERVICE_IS_CORE(casserv))
- continue;
- for (sconn = service_connection_first(casserv->cs_service);
- sconn != NULL;
- sconn = service_connection_next(sconn)) {
- sock = service_connection_get_sock(sconn);
- FD_SET(sock, &fds);
- maxfd = sock > maxfd ? sock : maxfd;
- }
- }
- maxfd++;
-
- PJDLOG_ASSERT(maxfd <= (int)FD_SETSIZE);
- ret = select(maxfd, &fds, NULL, NULL, NULL);
- PJDLOG_ASSERT(ret == -1 || ret > 0); /* select() cannot timeout */
- if (ret == -1) {
- if (errno == EINTR)
- continue;
- KEEP_ERRNO((void)pidfile_remove(pfh));
- pjdlog_exit(1, "select() failed");
- }
-
- if (FD_ISSET(lsock, &fds))
- casper_accept(lsock);
- TAILQ_FOREACH(casserv, &casper_services, cs_next) {
- /* We handle only core services. */
- if (!SERVICE_IS_CORE(casserv))
- continue;
- for (sconn = service_connection_first(casserv->cs_service);
- sconn != NULL; sconn = sconntmp) {
- /*
- * Prepare for connection to be removed from
- * the list on failure.
- */
- sconntmp = service_connection_next(sconn);
- sock = service_connection_get_sock(sconn);
- if (FD_ISSET(sock, &fds)) {
- service_message(casserv->cs_service,
- sconn);
- }
- }
- }
- }
-}
-
-static void
-usage(void)
-{
-
- pjdlog_exitx(1,
- "usage: casperd [-Fhv] [-D servconfdir] [-P pidfile] [-S sockpath]");
-}
-
-int
-main(int argc, char *argv[])
-{
- struct pidfh *pfh;
- const char *pidfile, *servconfdir, *sockpath;
- pid_t otherpid;
- int ch, debug, lqlen;
- bool foreground;
-
- pjdlog_init(PJDLOG_MODE_STD);
-
- debug = 0;
- foreground = false;
- lqlen = SOMAXCONN;
- pidfile = CASPERD_PIDFILE;
- servconfdir = CASPERD_SERVCONFDIR;
- sockpath = CASPERD_SOCKPATH;
-
- while ((ch = getopt(argc, argv, "D:Fhl:P:S:v")) != -1) {
- switch (ch) {
- case 'D':
- servconfdir = optarg;
- break;
- case 'F':
- foreground = true;
- break;
- case 'l':
- lqlen = strtol(optarg, NULL, 0);
- if (lqlen < 1)
- lqlen = SOMAXCONN;
- break;
- case 'P':
- pidfile = optarg;
- break;
- case 'S':
- sockpath = optarg;
- break;
- case 'v':
- debug++;
- break;
- case 'h':
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 0)
- usage();
-
- if (!foreground)
- pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
- pjdlog_prefix_set("(casperd) ");
- pjdlog_debug_set(debug);
-
- if (zygote_init() < 0)
- pjdlog_exit(1, "Unable to create zygote process");
-
- pfh = pidfile_open(pidfile, 0600, &otherpid);
- if (pfh == NULL) {
- if (errno == EEXIST) {
- pjdlog_exitx(1, "casperd already running, pid: %jd.",
- (intmax_t)otherpid);
- }
- pjdlog_errno(LOG_WARNING, "Cannot open or create pidfile %s",
- pidfile);
- }
-
- if (!foreground) {
- if (daemon(0, 0) == -1) {
- KEEP_ERRNO((void)pidfile_remove(pfh));
- pjdlog_exit(1, "Unable to go into background");
- }
- }
-
- /* Write PID to a file. */
- if (pidfile_write(pfh) == -1) {
- pjdlog_errno(LOG_WARNING, "Unable to write to pidfile %s",
- pidfile);
- } else {
- pjdlog_debug(1, "PID stored in %s.", pidfile);
- }
-
- /*
- * Register core services.
- */
- service_register_core();
- /*
- * Register external services.
- */
- service_register_external(servconfdir);
-
- /*
- * Wait for connections.
- */
- main_loop(lqlen, sockpath, pfh);
-}
Index: head/sbin/casperd/zygote.h
===================================================================
--- head/sbin/casperd/zygote.h
+++ head/sbin/casperd/zygote.h
@@ -1,40 +0,0 @@
-/*-
- * Copyright (c) 2012 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.
- *
- * $FreeBSD$
- */
-
-#ifndef _ZYGOTE_H_
-#define _ZYGOTE_H_
-
-typedef void zygote_func_t(int);
-
-int zygote_init(void);
-int zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp);
-
-#endif /* !_ZYGOTE_H_ */
Index: head/sbin/casperd/zygote.c
===================================================================
--- head/sbin/casperd/zygote.c
+++ head/sbin/casperd/zygote.c
@@ -1,227 +0,0 @@
-/*-
- * Copyright (c) 2012 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/capsicum.h>
-#include <sys/procdesc.h>
-#include <sys/socket.h>
-#include <sys/nv.h>
-
-#include <assert.h>
-#include <err.h>
-#include <errno.h>
-#include <paths.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include <libcapsicum.h>
-#include <libcapsicum_impl.h>
-#include <pjdlog.h>
-
-#include "zygote.h"
-
-/* Zygote info. */
-static int zygote_sock = -1;
-
-static void
-stdnull(void)
-{
- int fd;
-
- fd = open(_PATH_DEVNULL, O_RDWR);
- if (fd == -1)
- errx(1, "Unable to open %s", _PATH_DEVNULL);
-
- if (setsid() == -1)
- errx(1, "Unable to detach from session");
-
- if (dup2(fd, STDIN_FILENO) == -1)
- errx(1, "Unable to cover stdin");
- if (dup2(fd, STDOUT_FILENO) == -1)
- errx(1, "Unable to cover stdout");
- if (dup2(fd, STDERR_FILENO) == -1)
- errx(1, "Unable to cover stderr");
-
- close(fd);
-}
-
-int
-zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp)
-{
- nvlist_t *nvl;
- int error;
-
- if (zygote_sock == -1) {
- /* Zygote didn't start. */
- errno = ENXIO;
- return (-1);
- }
-
- nvl = nvlist_create(0);
- nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func);
- nvl = nvlist_xfer(zygote_sock, nvl, 0);
- if (nvl == NULL)
- return (-1);
- if (nvlist_exists_number(nvl, "error")) {
- error = (int)nvlist_get_number(nvl, "error");
- nvlist_destroy(nvl);
- errno = error;
- return (-1);
- }
-
- *chanfdp = nvlist_take_descriptor(nvl, "chanfd");
- *procfdp = nvlist_take_descriptor(nvl, "procfd");
-
- nvlist_destroy(nvl);
- return (0);
-}
-
-/*
- * This function creates sandboxes on-demand whoever has access to it via
- * 'sock' socket. Function sends two descriptors to the caller: process
- * descriptor of the sandbox and socket pair descriptor for communication
- * between sandbox and its owner.
- */
-static void
-zygote_main(int sock)
-{
- int error, fd, procfd;
- int chanfd[2];
- nvlist_t *nvlin, *nvlout;
- zygote_func_t *func;
- pid_t pid;
-
- assert(sock > STDERR_FILENO);
-
- setproctitle("zygote");
-
- if (pjdlog_mode_get() != PJDLOG_MODE_STD)
- stdnull();
- for (fd = STDERR_FILENO + 1; fd < sock; fd++)
- close(fd);
- closefrom(sock + 1);
-
- for (;;) {
- nvlin = nvlist_recv(sock, 0);
- if (nvlin == NULL) {
- if (errno == ENOTCONN) {
- /* Casperd exited. */
- exit(0);
- }
- continue;
- }
- func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin,
- "func");
- nvlist_destroy(nvlin);
-
- /*
- * Someone is requesting a new process, create one.
- */
- procfd = -1;
- chanfd[0] = -1;
- chanfd[1] = -1;
- error = 0;
- if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
- chanfd) == -1) {
- error = errno;
- goto send;
- }
- pid = pdfork(&procfd, 0);
- switch (pid) {
- case -1:
- /* Failure. */
- error = errno;
- break;
- case 0:
- /* Child. */
- close(sock);
- close(chanfd[0]);
- func(chanfd[1]);
- /* NOTREACHED */
- exit(1);
- default:
- /* Parent. */
- close(chanfd[1]);
- break;
- }
-send:
- nvlout = nvlist_create(0);
- if (error != 0) {
- nvlist_add_number(nvlout, "error", (uint64_t)error);
- if (chanfd[0] >= 0)
- close(chanfd[0]);
- if (procfd >= 0)
- close(procfd);
- } else {
- nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]);
- nvlist_move_descriptor(nvlout, "procfd", procfd);
- }
- (void)nvlist_send(sock, nvlout);
- nvlist_destroy(nvlout);
- }
- /* NOTREACHED */
-}
-
-int
-zygote_init(void)
-{
- int serrno, sp[2];
- pid_t pid;
-
- if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp) == -1)
- return (-1);
-
- pid = fork();
- switch (pid) {
- case -1:
- /* Failure. */
- serrno = errno;
- close(sp[0]);
- close(sp[1]);
- errno = serrno;
- return (-1);
- case 0:
- /* Child. */
- close(sp[0]);
- zygote_main(sp[1]);
- /* NOTREACHED */
- abort();
- default:
- /* Parent. */
- zygote_sock = sp[0];
- close(sp[1]);
- return (0);
- }
- /* NOTREACHED */
-}
Index: head/sbin/ping/Makefile
===================================================================
--- head/sbin/ping/Makefile
+++ head/sbin/ping/Makefile
@@ -11,8 +11,9 @@
LIBADD= m
.if ${MK_CASPER} != "no" && !defined(RESCUE)
-LIBADD+= capsicum
-CFLAGS+=-DHAVE_LIBCAPSICUM
+LIBADD+= casper
+LIBADD+= cap_dns
+CFLAGS+=-DHAVE_LIBCASPER
.endif
.if !defined(RELEASE_CRUNCH)
Index: head/sbin/ping/Makefile.depend
===================================================================
--- head/sbin/ping/Makefile.depend
+++ head/sbin/ping/Makefile.depend
@@ -9,7 +9,8 @@
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
- lib/libcapsicum \
+ lib/libcasper/libcasper \
+ lib/libcasper/services \
lib/libcompiler_rt \
lib/libipsec \
lib/libnv \
Index: head/sbin/ping/ping.c
===================================================================
--- head/sbin/ping/ping.c
+++ head/sbin/ping/ping.c
@@ -75,10 +75,10 @@
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <arpa/inet.h>
-#ifdef HAVE_LIBCAPSICUM
-#include <libcapsicum.h>
-#include <libcapsicum_dns.h>
-#include <libcapsicum_service.h>
+
+#ifdef HAVE_LIBCASPER
+#include <libcasper.h>
+#include <casper/cap_dns.h>
#endif
#ifdef IPSEC
@@ -204,13 +204,13 @@
static volatile sig_atomic_t finish_up;
static volatile sig_atomic_t siginfo_p;
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
static cap_channel_t *capdns;
#endif
static void fill(char *, char *);
static u_short in_cksum(u_short *, int);
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
static cap_channel_t *capdns_setup(void);
#endif
static void check_status(void);
@@ -553,7 +553,7 @@
if (options & F_PINGFILLED) {
fill((char *)datap, payload);
}
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
capdns = capdns_setup();
#endif
if (source) {
@@ -562,7 +562,7 @@
if (inet_aton(source, &sock_in.sin_addr) != 0) {
shostname = source;
} else {
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
if (capdns != NULL)
hp = cap_gethostbyname2(capdns, source,
AF_INET);
@@ -596,7 +596,7 @@
if (inet_aton(target, &to->sin_addr) != 0) {
hostname = target;
} else {
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
if (capdns != NULL)
hp = cap_gethostbyname2(capdns, target, AF_INET);
else
@@ -614,7 +614,7 @@
hostname = hnamebuf;
}
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
/* From now on we will use only reverse DNS lookups. */
if (capdns != NULL) {
const char *types[1];
@@ -722,7 +722,7 @@
if (options & F_NUMERIC)
cansandbox = true;
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
else if (capdns != NULL)
cansandbox = true;
#endif
@@ -1704,7 +1704,7 @@
if (options & F_NUMERIC)
return inet_ntoa(ina);
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
if (capdns != NULL)
hp = cap_gethostbyaddr(capdns, (char *)&ina, 4, AF_INET);
else
@@ -1788,7 +1788,7 @@
}
}
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
static cap_channel_t *
capdns_setup(void)
{
@@ -1797,10 +1797,8 @@
int families[1];
capcas = cap_init();
- if (capcas == NULL) {
- warn("unable to contact casperd");
- return (NULL);
- }
+ if (capcas == NULL)
+ err(1, "unable to create casper process");
capdnsloc = cap_service_open(capcas, "system.dns");
/* Casper capability no longer needed. */
cap_close(capcas);
@@ -1816,7 +1814,7 @@
return (capdnsloc);
}
-#endif /* HAVE_LIBCAPSICUM */
+#endif /* HAVE_LIBCASPER */
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define SECOPT " [-P policy]"
Index: head/share/man/man4/capsicum.4
===================================================================
--- head/share/man/man4/capsicum.4
+++ head/share/man/man4/capsicum.4
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 25, 2015
+.Dd February 25, 2016
.Dt CAPSICUM 4
.Os
.Sh NAME
@@ -104,9 +104,8 @@
.Xr shm_open 2 ,
.Xr write 2 ,
.Xr cap_rights_get 3 ,
-.Xr libcapsicum 3 ,
+.Xr casper 3 ,
.Xr procdesc 4 ,
-.Xr casperd 8
.Sh HISTORY
.Nm
first appeared in
Index: head/share/mk/bsd.libnames.mk
===================================================================
--- head/share/mk/bsd.libnames.mk
+++ head/share/mk/bsd.libnames.mk
@@ -30,7 +30,6 @@
LIBC?= ${DESTDIR}${LIBDIR}/libc.a
LIBCALENDAR?= ${DESTDIR}${LIBDIR}/libcalendar.a
LIBCAM?= ${DESTDIR}${LIBDIR}/libcam.a
-LIBCAPSICUM?= ${DESTDIR}${LIBDIR}/libcapsicum.a
LIBCASPER?= ${DESTDIR}${LIBDIR}/libcasper.a
LIBCOMPAT?= ${DESTDIR}${LIBDIR}/libcompat.a
LIBCOMPILER_RT?=${DESTDIR}${LIBDIR}/libcompiler_rt.a
Index: head/share/mk/src.libnames.mk
===================================================================
--- head/share/mk/src.libnames.mk
+++ head/share/mk/src.libnames.mk
@@ -68,8 +68,12 @@
c_pic \
calendar \
cam \
- capsicum \
casper \
+ cap_dns \
+ cap_grp \
+ cap_pwd \
+ cap_random \
+ cap_sysctl \
com_err \
compiler_rt \
crypt \
@@ -211,9 +215,13 @@
.endif
_DP_geom= bsdxml sbuf
_DP_cam= sbuf
-_DP_casper= capsicum nv pjdlog
-_DP_capsicum= nv
_DP_kvm= elf
+_DP_casper= nv
+_DP_cap_dns= nv
+_DP_cap_grp= nv
+_DP_cap_pwd= nv
+_DP_cap_random= nv
+_DP_cap_sysctl= nv
_DP_pjdlog= util
_DP_opie= md
_DP_usb= pthread
@@ -507,6 +515,25 @@
LIB${lib:tu}DIR?= ${OBJTOP}/lib/lib${lib}
.endfor
+# Casper exception.
+LIBCAP_CASPERDIR= ${OBJTOP}/lib/libcasper/libcasper
+LIBCAP_CASPER= ${DESTDIR}${LIBDIR}/libcasper.a
+
+LIBCAP_DNSDIR= ${OBJTOP}/lib/libcasper/services/cap_dns
+LIBCAP_DNS?= ${DESTDIR}${LIBDIR}/libcap_dns.a
+
+LIBCAP_GRPDIR= ${OBJTOP}/lib/libcasper/services/cap_grp
+LIBCAP_GRP?= ${DESTDIR}${LIBDIR}/libcap_grp.a
+
+LIBCAP_PWDDIR= ${OBJTOP}/lib/libcasper/services/cap_pwd
+LIBCAP_PWD?= ${DESTDIR}${LIBDIR}/libcap_pwd.a
+
+LIBCAP_RANDOMDIR= ${OBJTOP}/lib/libcasper/services/cap_random
+LIBCAP_RANDOM?= ${DESTDIR}${LIBDIR}/libcap_random.a
+
+LIBCAP_SYSCTLDIR= ${OBJTOP}/lib/libcasper/services/cap_sysctl
+LIBCAP_SYSCTL?= ${DESTDIR}${LIBDIR}/libcap_sysctl.a
+
# Validate that listed LIBADD are valid.
.for _l in ${LIBADD}
.if empty(_LIBRARIES:M${_l})
Index: head/targets/pseudo/userland/Makefile.depend
===================================================================
--- head/targets/pseudo/userland/Makefile.depend
+++ head/targets/pseudo/userland/Makefile.depend
@@ -894,10 +894,6 @@
DIRDEPS+= usr.bin/dtc
.endif
-.if ${MK_CASPER} == "yes"
-DIRDEPS+= sbin/casperd
-.endif
-
DIRDEPS+= ${DIRDEPS.${MACHINE}:U}
Index: head/targets/pseudo/userland/lib/Makefile.depend
===================================================================
--- head/targets/pseudo/userland/lib/Makefile.depend
+++ head/targets/pseudo/userland/lib/Makefile.depend
@@ -33,7 +33,6 @@
lib/libc++ \
lib/libcalendar \
lib/libcam \
- lib/libcasper \
lib/libcom_err/doc \
lib/libcompat \
lib/libcompiler_rt \
@@ -187,4 +186,15 @@
DIRDEPS+= lib/libnandfs
.endif
+.if ${MK_CASPER} != "no"
+DIRDEPS+= \
+ lib/libcasper \
+ lib/libcasper/services/cap_dns \
+ lib/libcasper/services/cap_grp \
+ lib/libcasper/services/cap_pwd \
+ lib/libcasper/services/cap_random \
+ lib/libcasper/services/cap_sysctl \
+
+.endif
+
.include <dirdeps.mk>
Index: head/targets/pseudo/userland/libexec/Makefile.depend
===================================================================
--- head/targets/pseudo/userland/libexec/Makefile.depend
+++ head/targets/pseudo/userland/libexec/Makefile.depend
@@ -10,11 +10,6 @@
libexec/bootpd/bootpgw \
libexec/bootpd/tools/bootpef \
libexec/bootpd/tools/bootptest \
- libexec/casper/dns \
- libexec/casper/grp \
- libexec/casper/pwd \
- libexec/casper/random \
- libexec/casper/sysctl \
libexec/comsat \
libexec/fingerd \
libexec/ftpd \
Index: head/tools/regression/capsicum/libcapsicum/Makefile
===================================================================
--- head/tools/regression/capsicum/libcapsicum/Makefile
+++ head/tools/regression/capsicum/libcapsicum/Makefile
@@ -1,33 +0,0 @@
-# $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
-
-SERVTEST= ${SERVICES:=.t}
-
-all: ${SERVTEST}
-
-.for SERVICE in ${SERVICES}
-
-${SERVICE}.t: ${SERVICE}.c
- ${CC} ${CFLAGS} ${@:.t=.c} -o $@ -lcapsicum -lnv
-
-.endfor
-
-test: all
- @prove -r ${.CURDIR}
-
-clean:
- rm -f ${SERVTEST}
Index: head/tools/regression/capsicum/libcapsicum/dns.c
===================================================================
--- head/tools/regression/capsicum/libcapsicum/dns.c
+++ head/tools/regression/capsicum/libcapsicum/dns.c
@@ -1,588 +0,0 @@
-/*-
- * 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/capsicum.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); \
- } \
- ntest++; \
-} 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..91\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);
-}
Index: head/tools/regression/capsicum/libcapsicum/grp.c
===================================================================
--- head/tools/regression/capsicum/libcapsicum/grp.c
+++ head/tools/regression/capsicum/libcapsicum/grp.c
@@ -1,1550 +0,0 @@
-/*-
- * 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/capsicum.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); \
- } \
- ntest++; \
-} 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..199\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);
-}
Index: head/tools/regression/capsicum/libcapsicum/pwd.c
===================================================================
--- head/tools/regression/capsicum/libcapsicum/pwd.c
+++ head/tools/regression/capsicum/libcapsicum/pwd.c
@@ -1,1536 +0,0 @@
-/*-
- * 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/capsicum.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); \
- } \
- ntest++; \
-} 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..188\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);
-}
Index: head/tools/regression/capsicum/libcapsicum/sysctl.c
===================================================================
--- head/tools/regression/capsicum/libcapsicum/sysctl.c
+++ head/tools/regression/capsicum/libcapsicum/sysctl.c
@@ -1,1510 +0,0 @@
-/*-
- * 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/capsicum.h>
-#include <sys/sysctl.h>
-#include <sys/nv.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>
-
-/*
- * 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); \
- } \
- ntest++; \
-} 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..256\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);
-}
Index: head/tools/regression/capsicum/libcasper/Makefile
===================================================================
--- head/tools/regression/capsicum/libcasper/Makefile
+++ head/tools/regression/capsicum/libcasper/Makefile
@@ -0,0 +1,32 @@
+# $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+= -ggdb
+
+SERVTEST= ${SERVICES:=.t}
+
+all: ${SERVTEST}
+
+.for SERVICE in ${SERVICES}
+
+${SERVICE}.t: ${SERVICE}.c
+ ${CC} ${CFLAGS} ${@:.t=.c} -o $@ -lnv -lcasper -lcap_${@:.t=}
+
+.endfor
+
+test: all
+ @prove -r ${.CURDIR}
+
+clean:
+ rm -f ${SERVTEST}
Index: head/tools/regression/capsicum/libcasper/dns.c
===================================================================
--- head/tools/regression/capsicum/libcasper/dns.c
+++ head/tools/regression/capsicum/libcasper/dns.c
@@ -0,0 +1,588 @@
+/*-
+ * 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/capsicum.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 <libcasper.h>
+
+#include <casper/cap_dns.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); \
+ } \
+ ntest++; \
+} 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..91\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);
+}
Index: head/tools/regression/capsicum/libcasper/grp.c
===================================================================
--- head/tools/regression/capsicum/libcasper/grp.c
+++ head/tools/regression/capsicum/libcasper/grp.c
@@ -0,0 +1,1550 @@
+/*-
+ * 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/capsicum.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 <libcasper.h>
+
+#include <casper/cap_grp.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); \
+ } \
+ ntest++; \
+} 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..199\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);
+}
Index: head/tools/regression/capsicum/libcasper/pwd.c
===================================================================
--- head/tools/regression/capsicum/libcasper/pwd.c
+++ head/tools/regression/capsicum/libcasper/pwd.c
@@ -0,0 +1,1536 @@
+/*-
+ * 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/capsicum.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 <libcasper.h>
+
+#include <casper/cap_pwd.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); \
+ } \
+ ntest++; \
+} 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..188\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);
+}
Index: head/tools/regression/capsicum/libcasper/sysctl.c
===================================================================
--- head/tools/regression/capsicum/libcasper/sysctl.c
+++ head/tools/regression/capsicum/libcasper/sysctl.c
@@ -0,0 +1,1510 @@
+/*-
+ * 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/capsicum.h>
+#include <sys/sysctl.h>
+#include <sys/nv.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 <libcasper.h>
+
+#include <casper/cap_sysctl.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); \
+ } \
+ ntest++; \
+} 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..256\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);
+}
Index: head/usr.bin/kdump/Makefile
===================================================================
--- head/usr.bin/kdump/Makefile
+++ head/usr.bin/kdump/Makefile
@@ -11,8 +11,10 @@
LIBADD= sysdecode
.if ${MK_CASPER} != "no"
-LIBADD+= capsicum
-CFLAGS+=-DHAVE_LIBCAPSICUM
+LIBADD+= casper
+LIBADD+= cap_grp
+LIBADD+= cap_pwd
+CFLAGS+=-DHAVE_LIBCASPER
.endif
NO_WERROR?= YES
Index: head/usr.bin/kdump/kdump.c
===================================================================
--- head/usr.bin/kdump/kdump.c
+++ head/usr.bin/kdump/kdump.c
@@ -61,7 +61,7 @@
#include <sys/un.h>
#include <sys/queue.h>
#include <sys/wait.h>
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
#include <sys/nv.h>
#endif
#include <arpa/inet.h>
@@ -70,12 +70,6 @@
#include <err.h>
#include <grp.h>
#include <inttypes.h>
-#ifdef HAVE_LIBCAPSICUM
-#include <libcapsicum.h>
-#include <libcapsicum_grp.h>
-#include <libcapsicum_pwd.h>
-#include <libcapsicum_service.h>
-#endif
#include <locale.h>
#include <netdb.h>
#include <nl_types.h>
@@ -91,6 +85,13 @@
#include "ktrace.h"
#include "kdump_subr.h"
+#ifdef HAVE_LIBCASPER
+#include <libcasper.h>
+
+#include <casper/cap_grp.h>
+#include <casper/cap_pwd.h>
+#endif
+
u_int abidump(struct ktr_header *);
int fetchprocinfo(struct ktr_header *, u_int *);
int fread_tail(void *, int, int);
@@ -151,7 +152,7 @@
static TAILQ_HEAD(trace_procs, proc_info) trace_procs;
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
static cap_channel_t *cappwd, *capgrp;
#endif
@@ -180,7 +181,7 @@
(void)localtime(&ltime);
}
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
static int
cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp)
{
@@ -189,8 +190,8 @@
capcas = cap_init();
if (capcas == NULL) {
- warn("unable to contact casperd");
- return (-1);
+ err(1, "unable to create casper process");
+ exit(1);
}
cappwdloc = cap_service_open(capcas, "system.pwd");
capgrploc = cap_service_open(capcas, "system.grp");
@@ -222,7 +223,7 @@
*capgrpp = capgrploc;
return (0);
}
-#endif /* HAVE_LIBCAPSICUM */
+#endif /* HAVE_LIBCASPER */
int
main(int argc, char *argv[])
@@ -302,7 +303,7 @@
strerror_init();
localtime_init();
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
if (resolv != 0) {
if (cappwdgrp_setup(&cappwd, &capgrp) < 0) {
cappwd = NULL;
@@ -1648,7 +1649,7 @@
if (resolv == 0) {
pwd = NULL;
} else {
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
if (cappwd != NULL)
pwd = cap_getpwuid(cappwd, statp->st_uid);
else
@@ -1662,7 +1663,7 @@
if (resolv == 0) {
grp = NULL;
} else {
-#ifdef HAVE_LIBCAPSICUM
+#ifdef HAVE_LIBCASPER
if (capgrp != NULL)
grp = cap_getgrgid(capgrp, statp->st_gid);
else
Index: head/usr.sbin/tcpdump/tcpdump/Makefile
===================================================================
--- head/usr.sbin/tcpdump/tcpdump/Makefile
+++ head/usr.sbin/tcpdump/tcpdump/Makefile
@@ -177,8 +177,9 @@
LIBADD= l pcap
.if ${MK_CASPER} != "no"
-LIBADD+= capsicum
-CFLAGS+=-DHAVE_CAPSICUM
+LIBADD+= casper
+LIBADD+= cap_dns
+CFLAGS+=-DHAVE_CASPER
.endif
.if ${MK_OPENSSL} != "no"
LIBADD+= crypto
Index: head/usr.sbin/tcpdump/tcpdump/config.h
===================================================================
--- head/usr.sbin/tcpdump/tcpdump/config.h
+++ head/usr.sbin/tcpdump/tcpdump/config.h
@@ -15,7 +15,7 @@
/* capsicum support available */
/* See Makefile */
-/* #undef HAVE_CAPSICUM */
+/* #undef HAVE_CAPSPER */
/* Define to 1 if you have the `cap_enter' function. */
#define HAVE_CAP_ENTER 1

File Metadata

Mime Type
text/plain
Expires
Fri, Dec 20, 2:02 PM (20 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15530747
Default Alt Text
D4277.diff (625 KB)

Event Timeline