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 -#include -#endif /* HAVE_CAPSICUM */ +#ifdef HAVE_CAPSPER +#include +#include +#endif /* HAVE_CAPSPER */ #include #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 #include #endif /* __FreeBSD__ */ -#ifdef HAVE_CAPSICUM -#include -#include -#include +#ifdef HAVE_CAPSPER +#include +#include #include #include #include #include #include #include -#endif /* HAVE_CAPSICUM */ +#endif /* HAVE_CAPSPER */ #include #include #include @@ -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 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 - -.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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#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 /* 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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include -#include - -#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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#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 -__FBSDID("$FreeBSD$"); - -#include -#include - -#include -#include -#include -#include -#include -#include - -#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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include - -#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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include - -#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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include - -#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 +.include 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * 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 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 + * 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 + +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 + * 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 + +#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 + * 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 +#include +#include + +#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 + * 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 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 /* 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 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 +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 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 +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 - -SUBDIR= dns -SUBDIR+=grp -SUBDIR+=pwd -SUBDIR+=random -SUBDIR+=sysctl - -.include 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 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 -__FBSDID("$FreeBSD$"); - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -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 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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -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 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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include - -#include -#include -#include - -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 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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include - -#include -#include -#include - -#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 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -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 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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 #include #include -#ifdef HAVE_LIBCAPSICUM -#include -#include -#include + +#ifdef HAVE_LIBCASPER +#include +#include #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 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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * 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 +__FBSDID("$FreeBSD$"); + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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 +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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 +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + * 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 #include #include -#ifdef HAVE_LIBCAPSICUM +#ifdef HAVE_LIBCASPER #include #endif #include @@ -70,12 +70,6 @@ #include #include #include -#ifdef HAVE_LIBCAPSICUM -#include -#include -#include -#include -#endif #include #include #include @@ -91,6 +85,13 @@ #include "ktrace.h" #include "kdump_subr.h" +#ifdef HAVE_LIBCASPER +#include + +#include +#include +#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(<ime); } -#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