Convert casperd(8) daemon to the libcasper.

After calling the cap_init(3) function Casper will fork from it's original
process, using pdfork(2). Forking from a process has a lot of advantages:
1. We have the same cwd as the original process.
2. The same uid, gid and groups.
3. The same MAC labels.
4. The same descriptor table.
5. The same routing table.
6. The same umask.
7. The same cpuset(1).
From now services are also in form of libraries.
We also removed libcapsicum at all and converts existing program using Casper
to new architecture.

Discussed with:		pjd, jonathan, ed, drysdale@google.com, emaste
Partially reviewed by:	drysdale@google.com, bdrewery
Approved by:		pjd (mentor)
Differential Revision:	https://reviews.freebsd.org/D4277
This commit is contained in:
Mariusz Zaborski 2016-02-25 18:23:40 +00:00
parent 6fb8946b7f
commit c501d73c7e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296047
85 changed files with 2072 additions and 2997 deletions

View File

@ -585,7 +585,7 @@ _worldtmp: .PHONY
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 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \
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 @@ _ofed_lib= contrib/ofed/usr.lib/
.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}

View File

@ -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

View File

@ -34,7 +34,7 @@ LINE("libc", "Standard C\\~Library (libc, \\-lc)")
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)")

View File

@ -29,10 +29,10 @@
#include "config.h"
#endif
#ifdef HAVE_CAPSICUM
#include <libcapsicum.h>
#include <libcapsicum_dns.h>
#endif /* HAVE_CAPSICUM */
#ifdef HAVE_CAPSPER
#include <libcasper.h>
#include <casper/cap_dns.h>
#endif /* HAVE_CAPSPER */
#include <tcpdump-stdinc.h>
#ifdef USE_ETHER_NTOHOST
@ -204,7 +204,7 @@ intoa(uint32_t addr)
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 @@ getname(netdissect_options *ndo, const u_char *ap)
*/
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 @@ getname6(netdissect_options *ndo, const u_char *ap)
* 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);

View File

@ -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

View File

@ -4566,7 +4566,7 @@ fi
$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; }

View File

@ -222,7 +222,7 @@ if test ! -z "$with_sandbox-capsicum" && test "$with_sandbox-capsicum" != "no" ;
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)

View File

@ -87,17 +87,16 @@ extern int SIZE_BUF;
#include <sys/capsicum.h>
#include <sys/sysctl.h>
#endif /* __FreeBSD__ */
#ifdef HAVE_CAPSICUM
#include <libcapsicum.h>
#include <libcapsicum_dns.h>
#include <libcapsicum_service.h>
#ifdef HAVE_CAPSPER
#include <libcasper.h>
#include <casper/cap_dns.h>
#include <sys/nv.h>
#include <sys/capability.h>
#include <sys/ioccom.h>
#include <net/bpf.h>
#include <fcntl.h>
#include <libgen.h>
#endif /* HAVE_CAPSICUM */
#endif /* HAVE_CAPSPER */
#include <pcap.h>
#include <signal.h>
#include <stdio.h>
@ -161,7 +160,7 @@ static int infoprint;
char *program_name;
#ifdef HAVE_CAPSICUM
#ifdef HAVE_CAPSPER
cap_channel_t *capdns;
#endif
@ -485,7 +484,7 @@ struct dump_info {
char *CurrentFileName;
pcap_t *pd;
pcap_dumper_t *p;
#ifdef HAVE_CAPSICUM
#ifdef HAVE_CAPSPER
int dirfd;
#endif
};
@ -909,7 +908,7 @@ get_next_file(FILE *VFile, char *ptr)
return ret;
}
#ifdef HAVE_CAPSICUM
#ifdef HAVE_CAPSPER
static cap_channel_t *
capdns_setup(void)
{
@ -918,10 +917,8 @@ capdns_setup(void)
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 @@ capdns_setup(void)
return (capdnsloc);
}
#endif /* HAVE_CAPSICUM */
#endif /* HAVE_CAPSPER */
#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
static int
@ -970,7 +967,7 @@ tstamp_precision_to_string(int precision)
}
#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 @@ main(int argc, char **argv)
#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 @@ main(int argc, char **argv)
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 @@ main(int argc, char **argv)
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 @@ main(int argc, char **argv)
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 @@ main(int argc, char **argv)
#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 @@ main(int argc, char **argv)
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 @@ main(int argc, char **argv)
#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 @@ main(int argc, char **argv)
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 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
/* 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 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
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_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
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 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
#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 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
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 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
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_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
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 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
#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
}

View File

@ -681,7 +681,6 @@ newsyslog_enable="YES" # Run newsyslog at startup.
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

View File

@ -15,8 +15,6 @@
lib
geom
..
..
libexec
casper
..
..

View File

@ -93,6 +93,8 @@
scsi
..
..
casper
..
crypto
..
dev

View File

@ -80,12 +80,12 @@
..
..
lib
casper
..
geom
..
..
libexec
casper
..
resolvconf
..
..

View File

@ -21,7 +21,6 @@ FILES= DAEMON \
${_bluetooth} \
bridge \
${_bthidd} \
${_casperd} \
cleanvar \
cleartmp \
cron \
@ -176,10 +175,6 @@ FILES+= bootparams
FILES+= bsnmpd
.endif
.if ${MK_CASPER} != "no"
_casperd= casperd
.endif
.if ${MK_CCD} != "no"
FILES+= ccd
.endif

View File

@ -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"

View File

@ -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)

View File

@ -36,7 +36,6 @@ SUBDIR= ${SUBDIR_ORDERED} \
libbz2 \
libcalendar \
libcam \
${_libcapsicum} \
${_libcasper} \
${_libcom_err} \
libcompat \
@ -135,8 +134,7 @@ SUBDIR_DEPEND_libbsnmp= ${_libnetgraph}
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 @@ _libbsnmp= libbsnmp
.endif
.if ${MK_CASPER} != "no"
_libcapsicum= libcapsicum
_libcasper= libcasper
.endif

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 15, 2014
.Dd February 25, 2016
.Dt POSIX1E 3
.Os
.Sh NAME
@ -94,7 +94,7 @@ for mandatory access control labels.
.Xr acl 3 ,
.Xr extattr 3 ,
.Xr libbsm 3 ,
.Xr libcapsicum 3 ,
.Xr libcasper 3 ,
.Xr mac 3 ,
.Xr capsicum 4 ,
.Xr ffs 7 ,

View File

@ -1,46 +0,0 @@
# $FreeBSD$
LIB= capsicum
SHLIB_MAJOR= 0
SHLIBDIR?= /lib
SRCS= libcapsicum.c
SRCS+= libcapsicum_dns.c
SRCS+= libcapsicum_grp.c
SRCS+= libcapsicum_pwd.c
SRCS+= libcapsicum_random.c
SRCS+= libcapsicum_service.c
SRCS+= libcapsicum_sysctl.c
INCS= libcapsicum.h
INCS+= libcapsicum_dns.h
INCS+= libcapsicum_grp.h
INCS+= libcapsicum_pwd.h
INCS+= libcapsicum_random.h
INCS+= libcapsicum_service.h
INCS+= libcapsicum_sysctl.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libnv
WARNS?= 6
MAN+= libcapsicum.3
MLINKS+=libcapsicum.3 cap_init.3
MLINKS+=libcapsicum.3 cap_wrap.3
MLINKS+=libcapsicum.3 cap_unwrap.3
MLINKS+=libcapsicum.3 cap_sock.3
MLINKS+=libcapsicum.3 cap_clone.3
MLINKS+=libcapsicum.3 cap_close.3
MLINKS+=libcapsicum.3 cap_limit_get.3
MLINKS+=libcapsicum.3 cap_limit_set.3
MLINKS+=libcapsicum.3 cap_send_nvlist.3
MLINKS+=libcapsicum.3 cap_recv_nvlist.3
MLINKS+=libcapsicum.3 cap_xfer_nvlist.3
MLINKS+=libcapsicum.3 cap_service_open.3
.include <bsd.lib.mk>

View File

@ -1,19 +0,0 @@
# $FreeBSD$
# Autogenerated - do NOT edit!
DIRDEPS = \
gnu/lib/csu \
gnu/lib/libgcc \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
lib/libnv \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

View File

@ -1,365 +0,0 @@
/*-
* Copyright (c) 2012-2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/nv.h>
#include <assert.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libcapsicum.h"
#include "libcapsicum_dns.h"
static struct hostent hent;
static void
hostent_free(struct hostent *hp)
{
unsigned int ii;
free(hp->h_name);
hp->h_name = NULL;
if (hp->h_aliases != NULL) {
for (ii = 0; hp->h_aliases[ii] != NULL; ii++)
free(hp->h_aliases[ii]);
free(hp->h_aliases);
hp->h_aliases = NULL;
}
if (hp->h_addr_list != NULL) {
for (ii = 0; hp->h_addr_list[ii] != NULL; ii++)
free(hp->h_addr_list[ii]);
free(hp->h_addr_list);
hp->h_addr_list = NULL;
}
}
static struct hostent *
hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
{
unsigned int ii, nitems;
char nvlname[64];
int n;
hostent_free(hp);
hp->h_name = strdup(nvlist_get_string(nvl, "name"));
if (hp->h_name == NULL)
goto fail;
hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype");
hp->h_length = (int)nvlist_get_number(nvl, "length");
nitems = (unsigned int)nvlist_get_number(nvl, "naliases");
hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1);
if (hp->h_aliases == NULL)
goto fail;
for (ii = 0; ii < nitems; ii++) {
n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
assert(n > 0 && n < (int)sizeof(nvlname));
hp->h_aliases[ii] =
strdup(nvlist_get_string(nvl, nvlname));
if (hp->h_aliases[ii] == NULL)
goto fail;
}
hp->h_aliases[ii] = NULL;
nitems = (unsigned int)nvlist_get_number(nvl, "naddrs");
hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1);
if (hp->h_addr_list == NULL)
goto fail;
for (ii = 0; ii < nitems; ii++) {
hp->h_addr_list[ii] = malloc(hp->h_length);
if (hp->h_addr_list[ii] == NULL)
goto fail;
n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
assert(n > 0 && n < (int)sizeof(nvlname));
bcopy(nvlist_get_binary(nvl, nvlname, NULL),
hp->h_addr_list[ii], hp->h_length);
}
hp->h_addr_list[ii] = NULL;
return (hp);
fail:
hostent_free(hp);
h_errno = NO_RECOVERY;
return (NULL);
}
struct hostent *
cap_gethostbyname(cap_channel_t *chan, const char *name)
{
return (cap_gethostbyname2(chan, name, AF_INET));
}
struct hostent *
cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
{
struct hostent *hp;
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "gethostbyname");
nvlist_add_number(nvl, "family", (uint64_t)type);
nvlist_add_string(nvl, "name", name);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
}
if (nvlist_get_number(nvl, "error") != 0) {
h_errno = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (NULL);
}
hp = hostent_unpack(nvl, &hent);
nvlist_destroy(nvl);
return (hp);
}
struct hostent *
cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
int type)
{
struct hostent *hp;
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "gethostbyaddr");
nvlist_add_binary(nvl, "addr", addr, (size_t)len);
nvlist_add_number(nvl, "family", (uint64_t)type);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
}
if (nvlist_get_number(nvl, "error") != 0) {
h_errno = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (NULL);
}
hp = hostent_unpack(nvl, &hent);
nvlist_destroy(nvl);
return (hp);
}
static struct addrinfo *
addrinfo_unpack(const nvlist_t *nvl)
{
struct addrinfo *ai;
const void *addr;
size_t addrlen;
const char *canonname;
addr = nvlist_get_binary(nvl, "ai_addr", &addrlen);
ai = malloc(sizeof(*ai) + addrlen);
if (ai == NULL)
return (NULL);
ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags");
ai->ai_family = (int)nvlist_get_number(nvl, "ai_family");
ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype");
ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol");
ai->ai_addrlen = (socklen_t)addrlen;
canonname = nvlist_get_string(nvl, "ai_canonname");
if (canonname != NULL) {
ai->ai_canonname = strdup(canonname);
if (ai->ai_canonname == NULL) {
free(ai);
return (NULL);
}
} else {
ai->ai_canonname = NULL;
}
ai->ai_addr = (void *)(ai + 1);
bcopy(addr, ai->ai_addr, addrlen);
ai->ai_next = NULL;
return (ai);
}
int
cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct addrinfo *firstai, *prevai, *curai;
unsigned int ii;
const nvlist_t *nvlai;
char nvlname[64];
nvlist_t *nvl;
int error, n;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getaddrinfo");
nvlist_add_string(nvl, "hostname", hostname);
nvlist_add_string(nvl, "servname", servname);
if (hints != NULL) {
nvlist_add_number(nvl, "hints.ai_flags",
(uint64_t)hints->ai_flags);
nvlist_add_number(nvl, "hints.ai_family",
(uint64_t)hints->ai_family);
nvlist_add_number(nvl, "hints.ai_socktype",
(uint64_t)hints->ai_socktype);
nvlist_add_number(nvl, "hints.ai_protocol",
(uint64_t)hints->ai_protocol);
}
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (error);
}
nvlai = NULL;
firstai = prevai = curai = NULL;
for (ii = 0; ; ii++) {
n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
assert(n > 0 && n < (int)sizeof(nvlname));
if (!nvlist_exists_nvlist(nvl, nvlname))
break;
nvlai = nvlist_get_nvlist(nvl, nvlname);
curai = addrinfo_unpack(nvlai);
if (curai == NULL)
break;
if (prevai != NULL)
prevai->ai_next = curai;
else if (firstai == NULL)
firstai = curai;
prevai = curai;
}
nvlist_destroy(nvl);
if (curai == NULL && nvlai != NULL) {
if (firstai == NULL)
freeaddrinfo(firstai);
return (EAI_MEMORY);
}
*res = firstai;
return (0);
}
int
cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
nvlist_t *nvl;
int error;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getnameinfo");
nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen);
nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
nvlist_add_number(nvl, "flags", (uint64_t)flags);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (error);
}
if (host != NULL)
strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1);
if (serv != NULL)
strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1);
nvlist_destroy(nvl);
return (0);
}
static void
limit_remove(nvlist_t *limits, const char *prefix)
{
const char *name;
size_t prefixlen;
void *cookie;
prefixlen = strlen(prefix);
again:
cookie = NULL;
while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
if (strncmp(name, prefix, prefixlen) == 0) {
nvlist_free(limits, name);
goto again;
}
}
}
int
cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
size_t ntypes)
{
nvlist_t *limits;
unsigned int i;
char nvlname[64];
int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL)
limits = nvlist_create(0);
else
limit_remove(limits, "type");
for (i = 0; i < ntypes; i++) {
n = snprintf(nvlname, sizeof(nvlname), "type%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_string(limits, nvlname, types[i]);
}
return (cap_limit_set(chan, limits));
}
int
cap_dns_family_limit(cap_channel_t *chan, const int *families,
size_t nfamilies)
{
nvlist_t *limits;
unsigned int i;
char nvlname[64];
int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL)
limits = nvlist_create(0);
else
limit_remove(limits, "family");
for (i = 0; i < nfamilies; i++) {
n = snprintf(nvlname, sizeof(nvlname), "family%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_number(limits, nvlname, (uint64_t)families[i]);
}
return (cap_limit_set(chan, limits));
}

View File

@ -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_ */

View File

@ -1,391 +0,0 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/nv.h>
#include <assert.h>
#include <errno.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libcapsicum.h"
#include "libcapsicum_pwd.h"
static struct passwd gpwd;
static char *gbuffer;
static size_t gbufsize;
static int
passwd_resize(void)
{
char *buf;
if (gbufsize == 0)
gbufsize = 1024;
else
gbufsize *= 2;
buf = gbuffer;
gbuffer = realloc(buf, gbufsize);
if (gbuffer == NULL) {
free(buf);
gbufsize = 0;
return (ENOMEM);
}
memset(gbuffer, 0, gbufsize);
return (0);
}
static int
passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
char **bufferp, size_t *bufsizep)
{
const char *str;
size_t len;
str = nvlist_get_string(nvl, fieldname);
len = strlcpy(*bufferp, str, *bufsizep);
if (len >= *bufsizep)
return (ERANGE);
*fieldp = *bufferp;
*bufferp += len + 1;
*bufsizep -= len + 1;
return (0);
}
static int
passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
size_t bufsize)
{
int error;
if (!nvlist_exists_string(nvl, "pw_name"))
return (EINVAL);
memset(pwd, 0, sizeof(*pwd));
error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
&bufsize);
if (error != 0)
return (error);
pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
&bufsize);
if (error != 0)
return (error);
pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
return (0);
}
static int
cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
struct passwd **result)
{
nvlist_t *nvl;
bool getpw_r;
int error;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", cmd);
if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
/* Add nothing. */
} else if (strcmp(cmd, "getpwnam") == 0 ||
strcmp(cmd, "getpwnam_r") == 0) {
nvlist_add_string(nvl, "name", login);
} else if (strcmp(cmd, "getpwuid") == 0 ||
strcmp(cmd, "getpwuid_r") == 0) {
nvlist_add_number(nvl, "uid", (uint64_t)uid);
} else {
abort();
}
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
assert(errno != 0);
*result = NULL;
return (errno);
}
error = (int)nvlist_get_number(nvl, "error");
if (error != 0) {
nvlist_destroy(nvl);
*result = NULL;
return (error);
}
if (!nvlist_exists_string(nvl, "pw_name")) {
/* Not found. */
nvlist_destroy(nvl);
*result = NULL;
return (0);
}
getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
for (;;) {
error = passwd_unpack(nvl, pwd, buffer, bufsize);
if (getpw_r || error != ERANGE)
break;
assert(buffer == gbuffer);
assert(bufsize == gbufsize);
error = passwd_resize();
if (error != 0)
break;
/* Update pointers after resize. */
buffer = gbuffer;
bufsize = gbufsize;
}
nvlist_destroy(nvl);
if (error == 0)
*result = pwd;
else
*result = NULL;
return (error);
}
static struct passwd *
cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
uid_t uid)
{
struct passwd *result;
int error, serrno;
serrno = errno;
error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
gbufsize, &result);
if (error != 0) {
errno = error;
return (NULL);
}
errno = serrno;
return (result);
}
struct passwd *
cap_getpwent(cap_channel_t *chan)
{
return (cap_getpwcommon(chan, "getpwent", NULL, 0));
}
struct passwd *
cap_getpwnam(cap_channel_t *chan, const char *login)
{
return (cap_getpwcommon(chan, "getpwnam", login, 0));
}
struct passwd *
cap_getpwuid(cap_channel_t *chan, uid_t uid)
{
return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
}
int
cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **result)
{
return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
bufsize, result));
}
int
cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
char *buffer, size_t bufsize, struct passwd **result)
{
return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
bufsize, result));
}
int
cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **result)
{
return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
bufsize, result));
}
int
cap_setpassent(cap_channel_t *chan, int stayopen)
{
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setpassent");
nvlist_add_bool(nvl, "stayopen", stayopen != 0);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
errno = nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (0);
}
nvlist_destroy(nvl);
return (1);
}
static void
cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
{
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", cmd);
/* Ignore any errors, we have no way to report them. */
nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
}
void
cap_setpwent(cap_channel_t *chan)
{
cap_set_end_pwent(chan, "setpwent");
}
void
cap_endpwent(cap_channel_t *chan)
{
cap_set_end_pwent(chan, "endpwent");
}
int
cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
{
nvlist_t *limits, *nvl;
unsigned int i;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL) {
limits = nvlist_create(0);
} else {
if (nvlist_exists_nvlist(limits, "cmds"))
nvlist_free_nvlist(limits, "cmds");
}
nvl = nvlist_create(0);
for (i = 0; i < ncmds; i++)
nvlist_add_null(nvl, cmds[i]);
nvlist_move_nvlist(limits, "cmds", nvl);
return (cap_limit_set(chan, limits));
}
int
cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
size_t nfields)
{
nvlist_t *limits, *nvl;
unsigned int i;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL) {
limits = nvlist_create(0);
} else {
if (nvlist_exists_nvlist(limits, "fields"))
nvlist_free_nvlist(limits, "fields");
}
nvl = nvlist_create(0);
for (i = 0; i < nfields; i++)
nvlist_add_null(nvl, fields[i]);
nvlist_move_nvlist(limits, "fields", nvl);
return (cap_limit_set(chan, limits));
}
int
cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
size_t nnames, uid_t *uids, size_t nuids)
{
nvlist_t *limits, *users;
char nvlname[64];
unsigned int i;
int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL) {
limits = nvlist_create(0);
} else {
if (nvlist_exists_nvlist(limits, "users"))
nvlist_free_nvlist(limits, "users");
}
users = nvlist_create(0);
for (i = 0; i < nuids; i++) {
n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
}
for (i = 0; i < nnames; i++) {
n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_string(users, nvlname, names[i]);
}
nvlist_move_nvlist(limits, "users", users);
return (cap_limit_set(chan, limits));
}

View File

@ -1,97 +0,0 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/nv.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "msgio.h"
#include "libcapsicum.h"
#include "libcapsicum_impl.h"
#include "libcapsicum_service.h"
cap_channel_t *
cap_service_open(const cap_channel_t *chan, const char *name)
{
cap_channel_t *newchan;
nvlist_t *nvl;
int sock, error;
sock = -1;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "open");
nvlist_add_string(nvl, "service", name);
if (fd_is_valid(STDERR_FILENO))
nvlist_add_descriptor(nvl, "stderrfd", STDERR_FILENO);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (NULL);
error = (int)nvlist_get_number(nvl, "error");
if (error != 0) {
nvlist_destroy(nvl);
errno = error;
return (NULL);
}
sock = nvlist_take_descriptor(nvl, "chanfd");
assert(sock >= 0);
nvlist_destroy(nvl);
nvl = NULL;
if (cred_send(sock) == -1)
goto fail;
newchan = cap_wrap(sock);
if (newchan == NULL)
goto fail;
return (newchan);
fail:
error = errno;
close(sock);
errno = error;
return (NULL);
}
int
cap_service_limit(const cap_channel_t *chan, const char * const *names,
size_t nnames)
{
nvlist_t *limits;
unsigned int i;
limits = nvlist_create(0);
for (i = 0; i < nnames; i++)
nvlist_add_null(limits, names[i]);
return (cap_limit_set(chan, limits));
}

View File

@ -1,86 +0,0 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/nv.h>
#include <errno.h>
#include <string.h>
#include "libcapsicum.h"
#include "libcapsicum_sysctl.h"
int
cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
size_t *oldlenp, const void *newp, size_t newlen)
{
nvlist_t *nvl;
const uint8_t *retoldp;
uint8_t operation;
size_t oldlen;
operation = 0;
if (oldp != NULL)
operation |= CAP_SYSCTL_READ;
if (newp != NULL)
operation |= CAP_SYSCTL_WRITE;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "sysctl");
nvlist_add_string(nvl, "name", name);
nvlist_add_number(nvl, "operation", (uint64_t)operation);
if (oldp == NULL && oldlenp != NULL)
nvlist_add_null(nvl, "justsize");
else if (oldlenp != NULL)
nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
if (newp != NULL)
nvlist_add_binary(nvl, "newp", newp, newlen);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_get_number(nvl, "error") != 0) {
errno = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (-1);
}
if (oldp == NULL && oldlenp != NULL) {
*oldlenp = (size_t)nvlist_get_number(nvl, "oldlen");
} else if (oldp != NULL) {
retoldp = nvlist_get_binary(nvl, "oldp", &oldlen);
memcpy(oldp, retoldp, oldlen);
if (oldlenp != NULL)
*oldlenp = oldlen;
}
nvlist_destroy(nvl);
return (0);
}

View File

@ -1,19 +1,6 @@
# $FreeBSD$
LIB= casper
SUBDIR= libcasper
SUBDIR+= services
SHLIB_MAJOR= 0
SHLIBDIR?= /lib
SRCS= libcasper.c
INCS= libcasper.h
LIBADD= capsicum nv pjdlog
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libpjdlog
CFLAGS+=-I${.CURDIR}/../../sbin/casper
WARNS?= 6
.include <bsd.lib.mk>
.include <bsd.subdir.mk>

View File

@ -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_ */

View File

@ -0,0 +1,38 @@
# $FreeBSD$
LIB= casper
SHLIB_MAJOR= 0
SHLIBDIR?= /lib
SRCS= libcasper.c
SRCS+= libcasper_impl.c
SRCS+= libcasper_service.c
SRCS+= service.c
SRCS+= zygote.c
INCS= libcasper.h
INCS+= libcasper_service.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
WARNS?= 6
MAN+= libcasper.3
MLINKS+=libcasper.3 cap_init.3
MLINKS+=libcasper.3 cap_wrap.3
MLINKS+=libcasper.3 cap_unwrap.3
MLINKS+=libcasper.3 cap_sock.3
MLINKS+=libcasper.3 cap_clone.3
MLINKS+=libcasper.3 cap_close.3
MLINKS+=libcasper.3 cap_limit_get.3
MLINKS+=libcasper.3 cap_limit_set.3
MLINKS+=libcasper.3 cap_send_nvlist.3
MLINKS+=libcasper.3 cap_recv_nvlist.3
MLINKS+=libcasper.3 cap_xfer_nvlist.3
MLINKS+=libcasper.3 cap_service_open.3
.include <bsd.lib.mk>

View File

@ -27,8 +27,8 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 2, 2015
.Dt LIBCAPSICUM 3
.Dd February 25, 2016
.Dt LIBCASPER 3
.Os
.Sh NAME
.Nm cap_init ,
@ -45,9 +45,9 @@
.Nm cap_service_open
.Nd "library for handling application capabilities"
.Sh LIBRARY
.Lb libcapsicum
.Lb libcasper
.Sh SYNOPSIS
.In libcapsicum.h
.In libcasper.h
.In nv.h
.Ft "cap_channel_t *"
.Fn cap_init "void"
@ -71,24 +71,18 @@
.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.
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
.Xr casperd 8
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
.Xr casperd 8
daemon obtained with the
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
@ -96,9 +90,7 @@ function.
.Pp
The
.Fn cap_init
function opens capability to the
.Xr casperd 8
daemon.
function opens capability to the casper process.
.Pp
The
.Fn cap_wrap
@ -231,9 +223,8 @@ 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
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
@ -243,10 +234,10 @@ const char *ipstr = "127.0.0.1";
struct in_addr ip;
struct hostent *hp;
/* Open capability to the Casper daemon. */
/* Open capability to the Casper. */
capcas = cap_init();
if (capcas == NULL)
err(1, "Unable to contact Casper daemon");
err(1, "Unable to contact Casper");
/* Enter capability mode sandbox. */
if (cap_enter() < 0 && errno != ENOSYS)
@ -290,11 +281,15 @@ printf("Name associated with %s is %s.\\n", ipstr, hp->h_name);
.Xr inet_aton 3 ,
.Xr nv 3 ,
.Xr capsicum 4 ,
.Xr unix 4 ,
.Xr casperd 8
.Xr unix 4
.Sh AUTHORS
The
.Nm libcapsicum
.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
.

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2012-2013 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -32,19 +33,18 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/nv.h>
#include <sys/procdesc.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libcapsicum.h"
#include "libcapsicum_impl.h"
#include "libcasper.h"
#include "libcasper_impl.h"
/*
* Structure describing communication channel between two separated processes.
@ -58,44 +58,61 @@ struct cap_channel {
int cch_magic;
/* Socket descriptor for IPC. */
int cch_sock;
/* Process descriptor for casper. */
int cch_pd;
};
bool
fd_is_valid(int fd)
static bool
cap_add_pd(cap_channel_t *chan, int pd)
{
return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
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;
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;
if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
sock) == -1) {
return (NULL);
}
chan = cap_wrap(sock);
if (chan == NULL) {
serrno = errno;
close(sock);
errno = serrno;
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);
}
return (chan);
/* Error. */
serrno = errno;
close(sock[0]);
close(sock[1]);
errno = serrno;
return (NULL);
}
cap_channel_t *
@ -109,6 +126,7 @@ cap_wrap(int sock)
chan = malloc(sizeof(*chan));
if (chan != NULL) {
chan->cch_sock = sock;
chan->cch_pd = -1;
chan->cch_magic = CAP_CHANNEL_MAGIC;
}
@ -124,6 +142,8 @@ cap_unwrap(cap_channel_t *chan)
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);
@ -172,6 +192,8 @@ cap_close(cap_channel_t *chan)
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);
}
@ -264,3 +286,52 @@ cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
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));
}

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2012-2013 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -29,8 +30,10 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_H_
#define _LIBCAPSICUM_H_
#ifndef _LIBCASPER_H_
#define _LIBCASPER_H_
#include <sys/types.h>
#ifndef _NVLIST_T_DECLARED
#define _NVLIST_T_DECLARED
@ -47,10 +50,17 @@ typedef struct cap_channel cap_channel_t;
#endif
/*
* The function opens unrestricted communication channel to Casper.
* 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.
*/
@ -88,16 +98,6 @@ int cap_limit_set(const cap_channel_t *chan, nvlist_t *limits);
*/
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.
*/
@ -112,4 +112,4 @@ nvlist_t *cap_recv_nvlist(const cap_channel_t *chan, int flags);
*/
nvlist_t *cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags);
#endif /* !_LIBCAPSICUM_H_ */
#endif /* !_LIBCASPER_H_ */

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -29,12 +30,15 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_SERVICE_H_
#define _LIBCAPSICUM_SERVICE_H_
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
cap_channel_t *cap_service_open(const cap_channel_t *chan, const char *name);
#include "libcasper_impl.h"
int cap_service_limit(const cap_channel_t *chan, const char * const *names,
size_t nnames);
bool
fd_is_valid(int fd)
{
#endif /* !_LIBCAPSICUM_SERVICE_H_ */
return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
}

View File

@ -0,0 +1,82 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _LIBCASPER_IMPL_H_
#define _LIBCASPER_IMPL_H_
#include <stdbool.h>
#include "libcasper.h"
#include "libcasper_service.h"
struct service;
struct service_connection;
bool fd_is_valid(int fd);
/* Private service functions. */
struct service *service_alloc(const char *name,
service_limit_func_t *limitfunc,
service_command_func_t *commandfunc);
void service_free(struct service *service);
void service_message(struct service *service,
struct service_connection *sconn);
void service_start(struct service *service, int sock);
const char *service_name(struct service *service);
/* Private service connection functions. */
struct service_connection *service_connection_add(struct service *service,
int sock, const nvlist_t *limits);
void service_connection_remove(
struct service *service,
struct service_connection *sconn);
int service_connection_clone(
struct service *service,
struct service_connection *sconn);
struct service_connection *service_connection_first(
struct service *service);
struct service_connection *service_connection_next(
struct service_connection *sconn);
cap_channel_t *service_connection_get_chan(
const struct service_connection *sconn);
int service_connection_get_sock(
const struct service_connection *sconn);
const nvlist_t *service_connection_get_limits(
const struct service_connection *sconn);
void service_connection_set_limits(
struct service_connection *sconn,
nvlist_t *limits);
/* Private libcasper functions. */
void casper_main_loop(int fd);
#endif /* !_LIBCASPER_IMPL_H_ */

View File

@ -0,0 +1,277 @@
/*-
* Copyright (c) 2012 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/nv.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libcasper_impl.h"
#include "zygote.h"
struct casper_service {
struct service *cs_service;
TAILQ_ENTRY(casper_service) cs_next;
};
static TAILQ_HEAD(, casper_service) casper_services =
TAILQ_HEAD_INITIALIZER(casper_services);
#define CORE_CASPER_NAME "core.casper"
#define CSERVICE_IS_CORE(service) \
(strcmp(service_name(service->cs_service), CORE_CASPER_NAME) == 0)
static struct casper_service *
service_find(const char *name)
{
struct casper_service *casserv;
TAILQ_FOREACH(casserv, &casper_services, cs_next) {
if (strcmp(service_name(casserv->cs_service), name) == 0)
break;
}
return (casserv);
}
struct casper_service *
service_register(const char *name, service_limit_func_t *limitfunc,
service_command_func_t *commandfunc)
{
struct casper_service *casserv;
if (commandfunc == NULL)
return (NULL);
if (name == NULL || name[0] == '\0')
return (NULL);
if (service_find(name) != NULL)
return (NULL);
casserv = malloc(sizeof(*casserv));
if (casserv == NULL)
return (NULL);
casserv->cs_service = service_alloc(name, limitfunc, commandfunc);
if (casserv->cs_service == NULL) {
free(casserv);
return (NULL);
}
TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next);
return (casserv);
}
static bool
casper_allowed_service(const nvlist_t *limits, const char *service)
{
if (limits == NULL)
return (true);
if (nvlist_exists_null(limits, service))
return (true);
return (false);
}
static int
casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
{
const char *name;
int type;
void *cookie;
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
if (type != NV_TYPE_NULL)
return (EINVAL);
if (!casper_allowed_service(oldlimits, name))
return (ENOTCAPABLE);
}
return (0);
}
static void
service_execute(int chanfd)
{
struct service *service;
nvlist_t *nvl;
int procfd;
nvl = nvlist_recv(chanfd, 0);
if (nvl == NULL)
exit(1);
service = (struct service *)(uintptr_t)nvlist_take_number(nvl,
"service");
//XXX: We should remove this?
procfd = nvlist_take_descriptor(nvl, "procfd");
nvlist_destroy(nvl);
service_start(service, chanfd);
/* Not reached. */
exit(1);
}
static int
casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
nvlist_t *nvlout)
{
struct casper_service *casserv;
const char *servname;
nvlist_t *nvl;
int chanfd, procfd, error;
if (strcmp(cmd, "open") != 0)
return (EINVAL);
if (!nvlist_exists_string(nvlin, "service"))
return (EINVAL);
servname = nvlist_get_string(nvlin, "service");
casserv = service_find(servname);
if (casserv == NULL)
return (ENOENT);
if (!casper_allowed_service(limits, servname))
return (ENOTCAPABLE);
if (zygote_clone(service_execute, &chanfd, &procfd) == -1)
return (errno);
nvl = nvlist_create(0);
nvlist_add_number(nvl, "service",
(uint64_t)(uintptr_t)casserv->cs_service);
nvlist_move_descriptor(nvl, "procfd", procfd);
if (nvlist_send(chanfd, nvl) == -1) {
error = errno;
nvlist_destroy(nvl);
close(chanfd);
return (error);
}
nvlist_destroy(nvl);
nvlist_move_descriptor(nvlout, "chanfd", chanfd);
return (0);
}
static void
service_register_core(int fd)
{
struct casper_service *casserv;
struct service_connection *sconn;
casserv = service_register(CORE_CASPER_NAME, casper_limit,
casper_command);
sconn = service_connection_add(casserv->cs_service, fd, NULL);
if (sconn == NULL) {
close(fd);
abort();
}
}
void
casper_main_loop(int fd)
{
fd_set fds;
struct casper_service *casserv;
struct service_connection *sconn, *sconntmp;
int sock, maxfd, ret;
if (zygote_init() < 0)
exit(1);
/*
* Register core services.
*/
service_register_core(fd);
for (;;) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
maxfd = -1;
TAILQ_FOREACH(casserv, &casper_services, cs_next) {
/* We handle only core services. */
if (!CSERVICE_IS_CORE(casserv))
continue;
for (sconn = service_connection_first(casserv->cs_service);
sconn != NULL;
sconn = service_connection_next(sconn)) {
sock = service_connection_get_sock(sconn);
FD_SET(sock, &fds);
maxfd = sock > maxfd ? sock : maxfd;
}
}
if (maxfd == -1) {
/* Nothing to do. */
exit(0);
}
maxfd++;
assert(maxfd <= (int)FD_SETSIZE);
ret = select(maxfd, &fds, NULL, NULL, NULL);
assert(ret == -1 || ret > 0); /* select() cannot timeout */
if (ret == -1) {
if (errno == EINTR)
continue;
exit(1);
}
TAILQ_FOREACH(casserv, &casper_services, cs_next) {
/* We handle only core services. */
if (!CSERVICE_IS_CORE(casserv))
continue;
for (sconn = service_connection_first(casserv->cs_service);
sconn != NULL; sconn = sconntmp) {
/*
* Prepare for connection to be removed from
* the list on failure.
*/
sconntmp = service_connection_next(sconn);
sock = service_connection_get_sock(sconn);
if (FD_ISSET(sock, &fds)) {
service_message(casserv->cs_service,
sconn);
}
}
}
}
}

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -29,18 +30,31 @@
* $FreeBSD$
*/
#ifndef _LIBCASPER_IMPL_H_
#define _LIBCASPER_IMPL_H_
#ifndef _LIBCASPER_SERVICE_H_
#define _LIBCASPER_SERVICE_H_
#include "libcasper.h"
#ifndef _NVLIST_T_DECLARED
#define _NVLIST_T_DECLARED
struct nvlist;
struct service;
struct service_connection;
typedef struct nvlist nvlist_t;
#endif
struct service * service_alloc(const char *name,
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);
void service_free(struct service *service);
void service_message(struct service *service, struct service_connection *sconn);
#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_IMPL_H_ */
#endif /* !_LIBCASPER_SERVICE_H_ */

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -31,11 +32,8 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/capsicum.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/nv.h>
#include <assert.h>
@ -50,10 +48,8 @@ __FBSDID("$FreeBSD$");
#include <strings.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcasper.h>
#include <libcasper_impl.h>
#include <pjdlog.h>
#include "libcasper.h"
#include "libcasper_impl.h"
/*
* Currently there is only one service_connection per service.
@ -114,7 +110,7 @@ service_free(struct service *service)
{
struct service_connection *sconn;
PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
assert(service->s_magic == SERVICE_MAGIC);
service->s_magic = 0;
while ((sconn = service_connection_first(service)) != NULL)
@ -130,17 +126,14 @@ service_connection_add(struct service *service, int sock,
struct service_connection *sconn;
int serrno;
PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
assert(service->s_magic == SERVICE_MAGIC);
sconn = malloc(sizeof(*sconn));
if (sconn == NULL) {
pjdlog_error("Unable to allocate memory for service connection.");
if (sconn == NULL)
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);
@ -151,7 +144,6 @@ service_connection_add(struct service *service, int sock,
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;
@ -168,8 +160,8 @@ 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);
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;
@ -206,10 +198,10 @@ service_connection_first(struct service *service)
{
struct service_connection *sconn;
PJDLOG_ASSERT(service->s_magic == SERVICE_MAGIC);
assert(service->s_magic == SERVICE_MAGIC);
sconn = TAILQ_FIRST(&service->s_connections);
PJDLOG_ASSERT(sconn == NULL ||
assert(sconn == NULL ||
sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
return (sconn);
}
@ -218,10 +210,10 @@ struct service_connection *
service_connection_next(struct service_connection *sconn)
{
PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
sconn = TAILQ_NEXT(sconn, sc_next);
PJDLOG_ASSERT(sconn == NULL ||
assert(sconn == NULL ||
sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
return (sconn);
}
@ -230,7 +222,7 @@ cap_channel_t *
service_connection_get_chan(const struct service_connection *sconn)
{
PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
return (sconn->sc_chan);
}
@ -239,7 +231,7 @@ int
service_connection_get_sock(const struct service_connection *sconn)
{
PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
return (cap_sock(sconn->sc_chan));
}
@ -248,7 +240,7 @@ const nvlist_t *
service_connection_get_limits(const struct service_connection *sconn)
{
PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
assert(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
return (sconn->sc_limits);
}
@ -258,38 +250,12 @@ service_connection_set_limits(struct service_connection *sconn,
nvlist_t *limits)
{
PJDLOG_ASSERT(sconn->sc_magic == SERVICE_CONNECTION_MAGIC);
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)
{
@ -299,12 +265,6 @@ service_message(struct service *service, struct service_connection *sconn)
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;
}
@ -313,15 +273,16 @@ service_message(struct service *service, struct service_connection *sconn)
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 (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. */
@ -354,14 +315,9 @@ service_message(struct service *service, struct service_connection *sconn)
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");
if (cap_send_nvlist(service_connection_get_chan(sconn), nvlout) == -1)
service_connection_remove(service, sconn);
}
nvlist_destroy(nvlout);
}
@ -374,28 +330,26 @@ fd_add(fd_set *fdsp, int maxfd, int fd)
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[])
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 *service;
struct service_connection *sconn, *sconntmp;
fd_set fds;
int maxfd, nfds, serrno;
int maxfd, nfds;
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);
}
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);
@ -406,17 +360,16 @@ service_start(const char *name, int sock, service_limit_func_t *limitfunc,
service_connection_get_sock(sconn));
}
PJDLOG_ASSERT(maxfd >= 0);
PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE);
assert(maxfd >= 0);
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");
exit(1);
continue;
} else if (nfds == 0) {
/* Timeout. */
PJDLOG_ABORT("select() timeout");
continue;
abort();
}
for (sconn = service_connection_first(service); sconn != NULL;
@ -437,5 +390,5 @@ service_start(const char *name, int sock, service_limit_func_t *limitfunc,
}
}
return (0);
exit(0);
}

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2012 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -45,10 +46,6 @@ __FBSDID("$FreeBSD$");
#include <strings.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_impl.h>
#include <pjdlog.h>
#include "zygote.h"
/* Zygote info. */
@ -126,8 +123,7 @@ zygote_main(int sock)
setproctitle("zygote");
if (pjdlog_mode_get() != PJDLOG_MODE_STD)
stdnull();
stdnull();
for (fd = STDERR_FILENO + 1; fd < sock; fd++)
close(fd);
closefrom(sock + 1);
@ -136,7 +132,7 @@ zygote_main(int sock)
nvlin = nvlist_recv(sock, 0);
if (nvlin == NULL) {
if (errno == ENOTCONN) {
/* Casperd exited. */
/* Casper exited. */
exit(0);
}
continue;

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2012 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@ -34,7 +35,7 @@
typedef void zygote_func_t(int);
int zygote_init(void);
int zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp);
int zygote_init(void);
int zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp);
#endif /* !_ZYGOTE_H_ */

View File

@ -0,0 +1,9 @@
# $FreeBSD$
SUBDIR= cap_dns
SUBDIR+= cap_grp
SUBDIR+= cap_pwd
SUBDIR+= cap_random
SUBDIR+= cap_sysctl
.include <bsd.subdir.mk>

View File

@ -0,0 +1,20 @@
# $FreeBSD$
LIB= cap_dns
SHLIB_MAJOR= 0
SHLIBDIR?= /lib/casper
INCSDIR?= ${INCLUDEDIR}/casper
SRCS= cap_dns.c
INCS= cap_dns.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libcasper
WARNS?= 6
.include <bsd.lib.mk>

View File

@ -30,6 +30,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/dnv.h>
#include <sys/nv.h>
#include <netinet/in.h>
@ -38,12 +39,341 @@ __FBSDID("$FreeBSD$");
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_dns.h>
#include <libcasper.h>
#include <pjdlog.h>
#include <libcasper_service.h>
#include "cap_dns.h"
static struct hostent hent;
static void
hostent_free(struct hostent *hp)
{
unsigned int ii;
free(hp->h_name);
hp->h_name = NULL;
if (hp->h_aliases != NULL) {
for (ii = 0; hp->h_aliases[ii] != NULL; ii++)
free(hp->h_aliases[ii]);
free(hp->h_aliases);
hp->h_aliases = NULL;
}
if (hp->h_addr_list != NULL) {
for (ii = 0; hp->h_addr_list[ii] != NULL; ii++)
free(hp->h_addr_list[ii]);
free(hp->h_addr_list);
hp->h_addr_list = NULL;
}
}
static struct hostent *
hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
{
unsigned int ii, nitems;
char nvlname[64];
int n;
hostent_free(hp);
hp->h_name = strdup(nvlist_get_string(nvl, "name"));
if (hp->h_name == NULL)
goto fail;
hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype");
hp->h_length = (int)nvlist_get_number(nvl, "length");
nitems = (unsigned int)nvlist_get_number(nvl, "naliases");
hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1);
if (hp->h_aliases == NULL)
goto fail;
for (ii = 0; ii < nitems; ii++) {
n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
assert(n > 0 && n < (int)sizeof(nvlname));
hp->h_aliases[ii] =
strdup(nvlist_get_string(nvl, nvlname));
if (hp->h_aliases[ii] == NULL)
goto fail;
}
hp->h_aliases[ii] = NULL;
nitems = (unsigned int)nvlist_get_number(nvl, "naddrs");
hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1);
if (hp->h_addr_list == NULL)
goto fail;
for (ii = 0; ii < nitems; ii++) {
hp->h_addr_list[ii] = malloc(hp->h_length);
if (hp->h_addr_list[ii] == NULL)
goto fail;
n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
assert(n > 0 && n < (int)sizeof(nvlname));
bcopy(nvlist_get_binary(nvl, nvlname, NULL),
hp->h_addr_list[ii], hp->h_length);
}
hp->h_addr_list[ii] = NULL;
return (hp);
fail:
hostent_free(hp);
h_errno = NO_RECOVERY;
return (NULL);
}
struct hostent *
cap_gethostbyname(cap_channel_t *chan, const char *name)
{
return (cap_gethostbyname2(chan, name, AF_INET));
}
struct hostent *
cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
{
struct hostent *hp;
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "gethostbyname");
nvlist_add_number(nvl, "family", (uint64_t)type);
nvlist_add_string(nvl, "name", name);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
}
if (nvlist_get_number(nvl, "error") != 0) {
h_errno = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (NULL);
}
hp = hostent_unpack(nvl, &hent);
nvlist_destroy(nvl);
return (hp);
}
struct hostent *
cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
int type)
{
struct hostent *hp;
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "gethostbyaddr");
nvlist_add_binary(nvl, "addr", addr, (size_t)len);
nvlist_add_number(nvl, "family", (uint64_t)type);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
h_errno = NO_RECOVERY;
return (NULL);
}
if (nvlist_get_number(nvl, "error") != 0) {
h_errno = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (NULL);
}
hp = hostent_unpack(nvl, &hent);
nvlist_destroy(nvl);
return (hp);
}
static struct addrinfo *
addrinfo_unpack(const nvlist_t *nvl)
{
struct addrinfo *ai;
const void *addr;
size_t addrlen;
const char *canonname;
addr = nvlist_get_binary(nvl, "ai_addr", &addrlen);
ai = malloc(sizeof(*ai) + addrlen);
if (ai == NULL)
return (NULL);
ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags");
ai->ai_family = (int)nvlist_get_number(nvl, "ai_family");
ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype");
ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol");
ai->ai_addrlen = (socklen_t)addrlen;
canonname = dnvlist_get_string(nvl, "ai_canonname", NULL);
if (canonname != NULL) {
ai->ai_canonname = strdup(canonname);
if (ai->ai_canonname == NULL) {
free(ai);
return (NULL);
}
} else {
ai->ai_canonname = NULL;
}
ai->ai_addr = (void *)(ai + 1);
bcopy(addr, ai->ai_addr, addrlen);
ai->ai_next = NULL;
return (ai);
}
int
cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct addrinfo *firstai, *prevai, *curai;
unsigned int ii;
const nvlist_t *nvlai;
char nvlname[64];
nvlist_t *nvl;
int error, n;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getaddrinfo");
if (hostname != NULL)
nvlist_add_string(nvl, "hostname", hostname);
if (servname != NULL)
nvlist_add_string(nvl, "servname", servname);
if (hints != NULL) {
nvlist_add_number(nvl, "hints.ai_flags",
(uint64_t)hints->ai_flags);
nvlist_add_number(nvl, "hints.ai_family",
(uint64_t)hints->ai_family);
nvlist_add_number(nvl, "hints.ai_socktype",
(uint64_t)hints->ai_socktype);
nvlist_add_number(nvl, "hints.ai_protocol",
(uint64_t)hints->ai_protocol);
}
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (error);
}
nvlai = NULL;
firstai = prevai = curai = NULL;
for (ii = 0; ; ii++) {
n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
assert(n > 0 && n < (int)sizeof(nvlname));
if (!nvlist_exists_nvlist(nvl, nvlname))
break;
nvlai = nvlist_get_nvlist(nvl, nvlname);
curai = addrinfo_unpack(nvlai);
if (curai == NULL)
break;
if (prevai != NULL)
prevai->ai_next = curai;
else if (firstai == NULL)
firstai = curai;
prevai = curai;
}
nvlist_destroy(nvl);
if (curai == NULL && nvlai != NULL) {
if (firstai == NULL)
freeaddrinfo(firstai);
return (EAI_MEMORY);
}
*res = firstai;
return (0);
}
int
cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
nvlist_t *nvl;
int error;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getnameinfo");
nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen);
nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
nvlist_add_number(nvl, "flags", (uint64_t)flags);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (error);
}
if (host != NULL && nvlist_exists_string(nvl, "host"))
strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1);
if (serv != NULL && nvlist_exists_string(nvl, "serv"))
strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1);
nvlist_destroy(nvl);
return (0);
}
static void
limit_remove(nvlist_t *limits, const char *prefix)
{
const char *name;
size_t prefixlen;
void *cookie;
prefixlen = strlen(prefix);
again:
cookie = NULL;
while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
if (strncmp(name, prefix, prefixlen) == 0) {
nvlist_free(limits, name);
goto again;
}
}
}
int
cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
size_t ntypes)
{
nvlist_t *limits;
unsigned int i;
char nvlname[64];
int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL)
limits = nvlist_create(0);
else
limit_remove(limits, "type");
for (i = 0; i < ntypes; i++) {
n = snprintf(nvlname, sizeof(nvlname), "type%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_string(limits, nvlname, types[i]);
}
return (cap_limit_set(chan, limits));
}
int
cap_dns_family_limit(cap_channel_t *chan, const int *families,
size_t nfamilies)
{
nvlist_t *limits;
unsigned int i;
char nvlname[64];
int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL)
limits = nvlist_create(0);
else
limit_remove(limits, "family");
for (i = 0; i < nfamilies; i++) {
n = snprintf(nvlname, sizeof(nvlname), "family%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_number(limits, nvlname, (uint64_t)families[i]);
}
return (cap_limit_set(chan, limits));
}
/*
* Service functions.
*/
static bool
dns_allowed_type(const nvlist_t *limits, const char *type)
{
@ -246,8 +576,10 @@ dns_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
if (error != 0)
goto out;
nvlist_move_string(nvlout, "host", host);
nvlist_move_string(nvlout, "serv", serv);
if (host != NULL)
nvlist_move_string(nvlout, "host", host);
if (serv != NULL)
nvlist_move_string(nvlout, "serv", serv);
out:
if (error != 0) {
free(host);
@ -267,7 +599,8 @@ addrinfo_pack(const struct addrinfo *ai)
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);
if (ai->ai_canonname != NULL)
nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname);
return (nvl);
}
@ -285,11 +618,9 @@ dns_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
if (!dns_allowed_type(limits, "ADDR"))
return (NO_RECOVERY);
hostname = nvlist_get_string(nvlin, "hostname");
servname = nvlist_get_string(nvlin, "servname");
hostname = dnvlist_get_string(nvlin, "hostname", NULL);
servname = dnvlist_get_string(nvlin, "servname", NULL);
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,
@ -427,10 +758,4 @@ dns_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
return (error);
}
int
main(int argc, char *argv[])
{
return (service_start("system.dns", PARENT_FILENO, dns_limit,
dns_command, argc, argv));
}
CREATE_SERVICE("system.dns", dns_limit, dns_command);

View File

@ -29,8 +29,8 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_DNS_H_
#define _LIBCAPSICUM_DNS_H_
#ifndef _CAP_DNS_H_
#define _CAP_DNS_H_
#include <sys/socket.h> /* socklen_t */
@ -54,4 +54,4 @@ int cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
int cap_dns_family_limit(cap_channel_t *chan, const int *families,
size_t nfamilies);
#endif /* !_LIBCAPSICUM_DNS_H_ */
#endif /* !_CAP_DNS_H_ */

View File

@ -0,0 +1,20 @@
# $FreeBSD$
LIB= cap_grp
SHLIB_MAJOR= 0
SHLIBDIR?= /lib/casper
INCSDIR?= ${INCLUDEDIR}/casper
SRCS= cap_grp.c
INCS= cap_grp.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libcasper
WARNS?= 6
.include <bsd.lib.mk>

View File

@ -39,10 +39,11 @@ __FBSDID("$FreeBSD$");
#include <grp.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libcapsicum.h"
#include "libcapsicum_grp.h"
#include <libcasper.h>
#include <libcasper_service.h>
#include "cap_grp.h"
static struct group ggrp;
static char *gbuffer;
@ -436,3 +437,351 @@ cap_grp_limit_groups(cap_channel_t *chan, const char * const *names,
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);

View File

@ -29,8 +29,8 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_GRP_H_
#define _LIBCAPSICUM_GRP_H_
#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);
@ -54,4 +54,4 @@ int cap_grp_limit_fields(cap_channel_t *chan, const char * const *fields,
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_ */
#endif /* !_CAP_GRP_H_ */

View File

@ -0,0 +1,20 @@
# $FreeBSD$
LIB= cap_pwd
SHLIB_MAJOR= 0
SHLIBDIR?= /lib/casper
INCSDIR?= ${INCLUDEDIR}/casper
SRCS= cap_pwd.c
INCS= cap_pwd.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libcasper
WARNS?= 6
.include <bsd.lib.mk>

View File

@ -30,17 +30,372 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/nv.h>
#include <assert.h>
#include <errno.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcasper.h>
#include <pjdlog.h>
#include <libcasper_service.h>
#include "cap_pwd.h"
static struct passwd gpwd;
static char *gbuffer;
static size_t gbufsize;
static int
passwd_resize(void)
{
char *buf;
if (gbufsize == 0)
gbufsize = 1024;
else
gbufsize *= 2;
buf = gbuffer;
gbuffer = realloc(buf, gbufsize);
if (gbuffer == NULL) {
free(buf);
gbufsize = 0;
return (ENOMEM);
}
memset(gbuffer, 0, gbufsize);
return (0);
}
static int
passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
char **bufferp, size_t *bufsizep)
{
const char *str;
size_t len;
str = nvlist_get_string(nvl, fieldname);
len = strlcpy(*bufferp, str, *bufsizep);
if (len >= *bufsizep)
return (ERANGE);
*fieldp = *bufferp;
*bufferp += len + 1;
*bufsizep -= len + 1;
return (0);
}
static int
passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
size_t bufsize)
{
int error;
if (!nvlist_exists_string(nvl, "pw_name"))
return (EINVAL);
memset(pwd, 0, sizeof(*pwd));
error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
&bufsize);
if (error != 0)
return (error);
pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
&bufsize);
if (error != 0)
return (error);
error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
&bufsize);
if (error != 0)
return (error);
pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
return (0);
}
static int
cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
struct passwd **result)
{
nvlist_t *nvl;
bool getpw_r;
int error;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", cmd);
if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
/* Add nothing. */
} else if (strcmp(cmd, "getpwnam") == 0 ||
strcmp(cmd, "getpwnam_r") == 0) {
nvlist_add_string(nvl, "name", login);
} else if (strcmp(cmd, "getpwuid") == 0 ||
strcmp(cmd, "getpwuid_r") == 0) {
nvlist_add_number(nvl, "uid", (uint64_t)uid);
} else {
abort();
}
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL) {
assert(errno != 0);
*result = NULL;
return (errno);
}
error = (int)nvlist_get_number(nvl, "error");
if (error != 0) {
nvlist_destroy(nvl);
*result = NULL;
return (error);
}
if (!nvlist_exists_string(nvl, "pw_name")) {
/* Not found. */
nvlist_destroy(nvl);
*result = NULL;
return (0);
}
getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
for (;;) {
error = passwd_unpack(nvl, pwd, buffer, bufsize);
if (getpw_r || error != ERANGE)
break;
assert(buffer == gbuffer);
assert(bufsize == gbufsize);
error = passwd_resize();
if (error != 0)
break;
/* Update pointers after resize. */
buffer = gbuffer;
bufsize = gbufsize;
}
nvlist_destroy(nvl);
if (error == 0)
*result = pwd;
else
*result = NULL;
return (error);
}
static struct passwd *
cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
uid_t uid)
{
struct passwd *result;
int error, serrno;
serrno = errno;
error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
gbufsize, &result);
if (error != 0) {
errno = error;
return (NULL);
}
errno = serrno;
return (result);
}
struct passwd *
cap_getpwent(cap_channel_t *chan)
{
return (cap_getpwcommon(chan, "getpwent", NULL, 0));
}
struct passwd *
cap_getpwnam(cap_channel_t *chan, const char *login)
{
return (cap_getpwcommon(chan, "getpwnam", login, 0));
}
struct passwd *
cap_getpwuid(cap_channel_t *chan, uid_t uid)
{
return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
}
int
cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **result)
{
return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
bufsize, result));
}
int
cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
char *buffer, size_t bufsize, struct passwd **result)
{
return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
bufsize, result));
}
int
cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **result)
{
return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
bufsize, result));
}
int
cap_setpassent(cap_channel_t *chan, int stayopen)
{
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "setpassent");
nvlist_add_bool(nvl, "stayopen", stayopen != 0);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (0);
if (nvlist_get_number(nvl, "error") != 0) {
errno = nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (0);
}
nvlist_destroy(nvl);
return (1);
}
static void
cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
{
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", cmd);
/* Ignore any errors, we have no way to report them. */
nvlist_destroy(cap_xfer_nvlist(chan, nvl, 0));
}
void
cap_setpwent(cap_channel_t *chan)
{
cap_set_end_pwent(chan, "setpwent");
}
void
cap_endpwent(cap_channel_t *chan)
{
cap_set_end_pwent(chan, "endpwent");
}
int
cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
{
nvlist_t *limits, *nvl;
unsigned int i;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL) {
limits = nvlist_create(0);
} else {
if (nvlist_exists_nvlist(limits, "cmds"))
nvlist_free_nvlist(limits, "cmds");
}
nvl = nvlist_create(0);
for (i = 0; i < ncmds; i++)
nvlist_add_null(nvl, cmds[i]);
nvlist_move_nvlist(limits, "cmds", nvl);
return (cap_limit_set(chan, limits));
}
int
cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
size_t nfields)
{
nvlist_t *limits, *nvl;
unsigned int i;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL) {
limits = nvlist_create(0);
} else {
if (nvlist_exists_nvlist(limits, "fields"))
nvlist_free_nvlist(limits, "fields");
}
nvl = nvlist_create(0);
for (i = 0; i < nfields; i++)
nvlist_add_null(nvl, fields[i]);
nvlist_move_nvlist(limits, "fields", nvl);
return (cap_limit_set(chan, limits));
}
int
cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
size_t nnames, uid_t *uids, size_t nuids)
{
nvlist_t *limits, *users;
char nvlname[64];
unsigned int i;
int n;
if (cap_limit_get(chan, &limits) < 0)
return (-1);
if (limits == NULL) {
limits = nvlist_create(0);
} else {
if (nvlist_exists_nvlist(limits, "users"))
nvlist_free_nvlist(limits, "users");
}
users = nvlist_create(0);
for (i = 0; i < nuids; i++) {
n = snprintf(nvlname, sizeof(nvlname), "uid%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_number(users, nvlname, (uint64_t)uids[i]);
}
for (i = 0; i < nnames; i++) {
n = snprintf(nvlname, sizeof(nvlname), "name%u", i);
assert(n > 0 && n < (int)sizeof(nvlname));
nvlist_add_string(users, nvlname, names[i]);
}
nvlist_move_nvlist(limits, "users", users);
return (cap_limit_set(chan, limits));
}
/*
* Service functions.
*/
static bool
pwd_allowed_cmd(const nvlist_t *limits, const char *cmd)
{
@ -111,7 +466,7 @@ pwd_allowed_user(const nvlist_t *limits, const char *uname, uid_t uid)
}
break;
default:
PJDLOG_ABORT("Unexpected type %d.", type);
abort();
}
}
@ -264,7 +619,8 @@ pwd_pack(const nvlist_t *limits, const struct passwd *pwd, nvlist_t *nvl)
}
static int
pwd_getpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
pwd_getpwent(const nvlist_t *limits, const nvlist_t *nvlin __unused,
nvlist_t *nvlout)
{
struct passwd *pwd;
@ -289,7 +645,7 @@ pwd_getpwnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
if (!nvlist_exists_string(nvlin, "name"))
return (EINVAL);
name = nvlist_get_string(nvlin, "name");
PJDLOG_ASSERT(name != NULL);
assert(name != NULL);
errno = 0;
pwd = getpwnam(name);
@ -323,7 +679,8 @@ pwd_getpwuid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
}
static int
pwd_setpassent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
pwd_setpassent(const nvlist_t *limits __unused, const nvlist_t *nvlin,
nvlist_t *nvlout __unused)
{
int stayopen;
@ -336,7 +693,8 @@ pwd_setpassent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
}
static int
pwd_setpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
pwd_setpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
nvlist_t *nvlout __unused)
{
setpwent();
@ -345,7 +703,8 @@ pwd_setpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
}
static int
pwd_endpwent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
pwd_endpwent(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
nvlist_t *nvlout __unused)
{
endpwent();
@ -421,10 +780,4 @@ pwd_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
return (error);
}
int
main(int argc, char *argv[])
{
return (service_start("system.pwd", PARENT_FILENO, pwd_limit,
pwd_command, argc, argv));
}
CREATE_SERVICE("system.pwd", pwd_limit, pwd_command);

View File

@ -29,8 +29,8 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_PWD_H_
#define _LIBCAPSICUM_PWD_H_
#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);
@ -54,4 +54,4 @@ int cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
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_ */
#endif /* !_CAP_PWD_H_ */

View File

@ -0,0 +1,20 @@
# $FreeBSD$
LIB= cap_random
SHLIB_MAJOR= 0
SHLIBDIR?= /lib/casper
INCSDIR?= ${INCLUDEDIR}/casper
SRCS= cap_random.c
INCS= cap_random.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libcasper
WARNS?= 6
.include <bsd.lib.mk>

View File

@ -34,10 +34,14 @@ __FBSDID("$FreeBSD$");
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libcapsicum.h"
#include "libcapsicum_random.h"
#include <libcasper.h>
#include <libcasper_service.h>
#include "cap_random.h"
#define MAXSIZE (1024 * 1024)
@ -78,3 +82,36 @@ cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes)
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);

View File

@ -29,9 +29,9 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_RANDOM_H_
#define _LIBCAPSICUM_RANDOM_H_
#ifndef _CAP_RANDOM_H_
#define _CAP_RANDOM_H_
int cap_random_buf(cap_channel_t *chan, void *buf, size_t nbytes);
#endif /* !_LIBCAPSICUM_RANDOM_H_ */
#endif /* !_CAP_RANDOM_H_ */

View File

@ -0,0 +1,20 @@
# $FreeBSD$
LIB= cap_sysctl
SHLIB_MAJOR= 0
SHLIBDIR?= /lib/casper
INCSDIR?= ${INCLUDEDIR}/casper
SRCS= cap_sysctl.c
INCS= cap_sysctl.h
LIBADD= nv
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../libcasper
WARNS?= 6
.include <bsd.lib.mk>

View File

@ -34,15 +34,66 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/nv.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <libcapsicum.h>
#include <libcapsicum_sysctl.h>
#include <libcasper.h>
#include <pjdlog.h>
#include <libcasper_service.h>
#include "cap_sysctl.h"
int
cap_sysctlbyname(cap_channel_t *chan, const char *name, void *oldp,
size_t *oldlenp, const void *newp, size_t newlen)
{
nvlist_t *nvl;
const uint8_t *retoldp;
uint8_t operation;
size_t oldlen;
operation = 0;
if (oldp != NULL)
operation |= CAP_SYSCTL_READ;
if (newp != NULL)
operation |= CAP_SYSCTL_WRITE;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "sysctl");
nvlist_add_string(nvl, "name", name);
nvlist_add_number(nvl, "operation", (uint64_t)operation);
if (oldp == NULL && oldlenp != NULL)
nvlist_add_null(nvl, "justsize");
else if (oldlenp != NULL)
nvlist_add_number(nvl, "oldlen", (uint64_t)*oldlenp);
if (newp != NULL)
nvlist_add_binary(nvl, "newp", newp, newlen);
nvl = cap_xfer_nvlist(chan, nvl, 0);
if (nvl == NULL)
return (-1);
if (nvlist_get_number(nvl, "error") != 0) {
errno = (int)nvlist_get_number(nvl, "error");
nvlist_destroy(nvl);
return (-1);
}
if (oldp == NULL && oldlenp != NULL) {
*oldlenp = (size_t)nvlist_get_number(nvl, "oldlen");
} else if (oldp != NULL) {
retoldp = nvlist_get_binary(nvl, "oldp", &oldlen);
memcpy(oldp, retoldp, oldlen);
if (oldlenp != NULL)
*oldlenp = oldlen;
}
nvlist_destroy(nvl);
return (0);
}
/*
* Service functions.
*/
static int
sysctl_check_one(const nvlist_t *nvl, bool islimit)
{
@ -119,7 +170,7 @@ sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation)
cookie = NULL;
while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
PJDLOG_ASSERT(type == NV_TYPE_NUMBER);
assert(type == NV_TYPE_NUMBER);
operation = nvlist_get_number(limits, name);
if ((operation & choperation) != choperation)
@ -147,11 +198,10 @@ sysctl_allowed(const nvlist_t *limits, const char *chname, uint64_t choperation)
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;
int type;
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
@ -196,7 +246,7 @@ sysctl_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
if (!nvlist_exists_binary(nvlin, "newp"))
return (EINVAL);
newp = nvlist_get_binary(nvlin, "newp", &newlen);
PJDLOG_ASSERT(newp != NULL && newlen > 0);
assert(newp != NULL && newlen > 0);
} else {
newp = NULL;
newlen = 0;
@ -240,10 +290,4 @@ sysctl_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
return (0);
}
int
main(int argc, char *argv[])
{
return (service_start("system.sysctl", PARENT_FILENO, sysctl_limit,
sysctl_command, argc, argv));
}
CREATE_SERVICE("system.sysctl", sysctl_limit, sysctl_command);

View File

@ -29,8 +29,8 @@
* $FreeBSD$
*/
#ifndef _LIBCAPSICUM_SYSCTL_H_
#define _LIBCAPSICUM_SYSCTL_H_
#ifndef _CAP_SYSCTL_H_
#define _CAP_SYSCTL_H_
#define CAP_SYSCTL_READ 0x01
#define CAP_SYSCTL_WRITE 0x02
@ -40,4 +40,4 @@
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_ */
#endif /* !_CAP_SYSCTL_H_ */

View File

@ -5,7 +5,6 @@
SUBDIR= ${_atf} \
${_atrun} \
${_casper} \
${_comsat} \
${_dma} \
getty \
@ -38,10 +37,6 @@ _atrun= atrun
SUBDIR+= bootpd
.endif
.if ${MK_CASPER} != "no"
_casper= casper
.endif
.if ${MK_FINGER} != "no"
SUBDIR+= fingerd
.endif

View File

@ -1,11 +0,0 @@
# $FreeBSD$
.include <bsd.own.mk>
SUBDIR= dns
SUBDIR+=grp
SUBDIR+=pwd
SUBDIR+=random
SUBDIR+=sysctl
.include <bsd.subdir.mk>

View File

@ -1,21 +0,0 @@
# $FreeBSD$
.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
PROG= dns
SRCS= dns.c
LIBADD= casper nv
BINDIR= /libexec/casper
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
CFLAGS+=-I${.CURDIR}/../../../sbin/casper
MAN=
.include <bsd.prog.mk>

View File

@ -1,21 +0,0 @@
# $FreeBSD$
.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
PROG= grp
SRCS= grp.c
LIBADD= casper nv pjdlog
BINDIR= /libexec/casper
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
CFLAGS+=-I${.CURDIR}/../../../sbin/casper
MAN=
.include <bsd.prog.mk>

View File

@ -1,390 +0,0 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/nv.h>
#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <stdlib.h>
#include <string.h>
#include <libcapsicum.h>
#include <libcasper.h>
#include <pjdlog.h>
static bool
grp_allowed_cmd(const nvlist_t *limits, const char *cmd)
{
if (limits == NULL)
return (true);
/*
* If no limit was set on allowed commands, then all commands
* are allowed.
*/
if (!nvlist_exists_nvlist(limits, "cmds"))
return (true);
limits = nvlist_get_nvlist(limits, "cmds");
return (nvlist_exists_null(limits, cmd));
}
static int
grp_allowed_cmds(const nvlist_t *oldlimits, const nvlist_t *newlimits)
{
const char *name;
void *cookie;
int type;
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
if (type != NV_TYPE_NULL)
return (EINVAL);
if (!grp_allowed_cmd(oldlimits, name))
return (ENOTCAPABLE);
}
return (0);
}
static bool
grp_allowed_group(const nvlist_t *limits, const char *gname, gid_t gid)
{
const char *name;
void *cookie;
int type;
if (limits == NULL)
return (true);
/*
* If no limit was set on allowed groups, then all groups are allowed.
*/
if (!nvlist_exists_nvlist(limits, "groups"))
return (true);
limits = nvlist_get_nvlist(limits, "groups");
cookie = NULL;
while ((name = nvlist_next(limits, &type, &cookie)) != NULL) {
switch (type) {
case NV_TYPE_NUMBER:
if (gid != (gid_t)-1 &&
nvlist_get_number(limits, name) == (uint64_t)gid) {
return (true);
}
break;
case NV_TYPE_STRING:
if (gname != NULL &&
strcmp(nvlist_get_string(limits, name),
gname) == 0) {
return (true);
}
break;
default:
PJDLOG_ABORT("Unexpected type %d.", type);
}
}
return (false);
}
static int
grp_allowed_groups(const nvlist_t *oldlimits, const nvlist_t *newlimits)
{
const char *name, *gname;
void *cookie;
gid_t gid;
int type;
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
switch (type) {
case NV_TYPE_NUMBER:
gid = (gid_t)nvlist_get_number(newlimits, name);
gname = NULL;
break;
case NV_TYPE_STRING:
gid = (gid_t)-1;
gname = nvlist_get_string(newlimits, name);
break;
default:
return (EINVAL);
}
if (!grp_allowed_group(oldlimits, gname, gid))
return (ENOTCAPABLE);
}
return (0);
}
static bool
grp_allowed_field(const nvlist_t *limits, const char *field)
{
if (limits == NULL)
return (true);
/*
* If no limit was set on allowed fields, then all fields are allowed.
*/
if (!nvlist_exists_nvlist(limits, "fields"))
return (true);
limits = nvlist_get_nvlist(limits, "fields");
return (nvlist_exists_null(limits, field));
}
static int
grp_allowed_fields(const nvlist_t *oldlimits, const nvlist_t *newlimits)
{
const char *name;
void *cookie;
int type;
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
if (type != NV_TYPE_NULL)
return (EINVAL);
if (!grp_allowed_field(oldlimits, name))
return (ENOTCAPABLE);
}
return (0);
}
static bool
grp_pack(const nvlist_t *limits, const struct group *grp, nvlist_t *nvl)
{
char nvlname[64];
int n;
if (grp == NULL)
return (true);
/*
* If either name or GID is allowed, we allow it.
*/
if (!grp_allowed_group(limits, grp->gr_name, grp->gr_gid))
return (false);
if (grp_allowed_field(limits, "gr_name"))
nvlist_add_string(nvl, "gr_name", grp->gr_name);
else
nvlist_add_string(nvl, "gr_name", "");
if (grp_allowed_field(limits, "gr_passwd"))
nvlist_add_string(nvl, "gr_passwd", grp->gr_passwd);
else
nvlist_add_string(nvl, "gr_passwd", "");
if (grp_allowed_field(limits, "gr_gid"))
nvlist_add_number(nvl, "gr_gid", (uint64_t)grp->gr_gid);
else
nvlist_add_number(nvl, "gr_gid", (uint64_t)-1);
if (grp_allowed_field(limits, "gr_mem") && grp->gr_mem[0] != NULL) {
unsigned int ngroups;
for (ngroups = 0; grp->gr_mem[ngroups] != NULL; ngroups++) {
n = snprintf(nvlname, sizeof(nvlname), "gr_mem[%u]",
ngroups);
assert(n > 0 && n < sizeof(nvlname));
nvlist_add_string(nvl, nvlname, grp->gr_mem[ngroups]);
}
nvlist_add_number(nvl, "gr_nmem", (uint64_t)ngroups);
}
return (true);
}
static int
grp_getgrent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
struct group *grp;
for (;;) {
errno = 0;
grp = getgrent();
if (errno != 0)
return (errno);
if (grp_pack(limits, grp, nvlout))
return (0);
}
/* NOTREACHED */
}
static int
grp_getgrnam(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
struct group *grp;
const char *name;
if (!nvlist_exists_string(nvlin, "name"))
return (EINVAL);
name = nvlist_get_string(nvlin, "name");
PJDLOG_ASSERT(name != NULL);
errno = 0;
grp = getgrnam(name);
if (errno != 0)
return (errno);
(void)grp_pack(limits, grp, nvlout);
return (0);
}
static int
grp_getgrgid(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
struct group *grp;
gid_t gid;
if (!nvlist_exists_number(nvlin, "gid"))
return (EINVAL);
gid = (gid_t)nvlist_get_number(nvlin, "gid");
errno = 0;
grp = getgrgid(gid);
if (errno != 0)
return (errno);
(void)grp_pack(limits, grp, nvlout);
return (0);
}
static int
grp_setgroupent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
int stayopen;
if (!nvlist_exists_bool(nvlin, "stayopen"))
return (EINVAL);
stayopen = nvlist_get_bool(nvlin, "stayopen") ? 1 : 0;
return (setgroupent(stayopen) == 0 ? EFAULT : 0);
}
static int
grp_setgrent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
return (setgrent() == 0 ? EFAULT : 0);
}
static int
grp_endgrent(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
{
endgrent();
return (0);
}
static int
grp_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
{
const nvlist_t *limits;
const char *name;
void *cookie;
int error, type;
if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "cmds") &&
!nvlist_exists_nvlist(newlimits, "cmds")) {
return (ENOTCAPABLE);
}
if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "fields") &&
!nvlist_exists_nvlist(newlimits, "fields")) {
return (ENOTCAPABLE);
}
if (oldlimits != NULL && nvlist_exists_nvlist(oldlimits, "groups") &&
!nvlist_exists_nvlist(newlimits, "groups")) {
return (ENOTCAPABLE);
}
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
if (type != NV_TYPE_NVLIST)
return (EINVAL);
limits = nvlist_get_nvlist(newlimits, name);
if (strcmp(name, "cmds") == 0)
error = grp_allowed_cmds(oldlimits, limits);
else if (strcmp(name, "fields") == 0)
error = grp_allowed_fields(oldlimits, limits);
else if (strcmp(name, "groups") == 0)
error = grp_allowed_groups(oldlimits, limits);
else
error = EINVAL;
if (error != 0)
return (error);
}
return (0);
}
static int
grp_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
nvlist_t *nvlout)
{
int error;
if (!grp_allowed_cmd(limits, cmd))
return (ENOTCAPABLE);
if (strcmp(cmd, "getgrent") == 0 || strcmp(cmd, "getgrent_r") == 0)
error = grp_getgrent(limits, nvlin, nvlout);
else if (strcmp(cmd, "getgrnam") == 0 || strcmp(cmd, "getgrnam_r") == 0)
error = grp_getgrnam(limits, nvlin, nvlout);
else if (strcmp(cmd, "getgrgid") == 0 || strcmp(cmd, "getgrgid_r") == 0)
error = grp_getgrgid(limits, nvlin, nvlout);
else if (strcmp(cmd, "setgroupent") == 0)
error = grp_setgroupent(limits, nvlin, nvlout);
else if (strcmp(cmd, "setgrent") == 0)
error = grp_setgrent(limits, nvlin, nvlout);
else if (strcmp(cmd, "endgrent") == 0)
error = grp_endgrent(limits, nvlin, nvlout);
else
error = EINVAL;
return (error);
}
int
main(int argc, char *argv[])
{
return (service_start("system.grp", PARENT_FILENO, grp_limit,
grp_command, argc, argv));
}

View File

@ -1,21 +0,0 @@
# $FreeBSD$
.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
PROG= pwd
SRCS= pwd.c
LIBADD= casper nv pjdlog
BINDIR= /libexec/casper
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
CFLAGS+=-I${.CURDIR}/../../../sbin/casper
MAN=
.include <bsd.prog.mk>

View File

@ -1,21 +0,0 @@
# $FreeBSD$
.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
PROG= random
SRCS= random.c
LIBADD= casper nv
BINDIR= /libexec/casper
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
CFLAGS+=-I${.CURDIR}/../../../sbin/casper
MAN=
.include <bsd.prog.mk>

View File

@ -1,82 +0,0 @@
/*-
* Copyright (c) 2012-2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/nv.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <libcapsicum.h>
#include <libcasper.h>
#include <pjdlog.h>
#define MAXSIZE (1024 * 1024)
static int
random_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
nvlist_t *nvlout)
{
void *data;
size_t size;
if (strcmp(cmd, "generate") != 0)
return (EINVAL);
if (!nvlist_exists_number(nvlin, "size"))
return (EINVAL);
size = (size_t)nvlist_get_number(nvlin, "size");
if (size == 0 || size > MAXSIZE)
return (EINVAL);
data = malloc(size);
if (data == NULL)
return (ENOMEM);
arc4random_buf(data, size);
nvlist_move_binary(nvlout, "data", data, size);
return (0);
}
int
main(int argc, char *argv[])
{
/*
* TODO: Sandbox this.
*/
return (service_start("system.random", PARENT_FILENO, NULL,
random_command, argc, argv));
}

View File

@ -1,21 +0,0 @@
# $FreeBSD$
.PATH: ${.CURDIR} ${.CURDIR}/../../../sbin/casper
PROG= sysctl
SRCS= sysctl.c
LIBADD= casper nv pjdlog
BINDIR= /libexec/casper
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../../../lib/libcapsicum
CFLAGS+=-I${.CURDIR}/../../../lib/libcasper
CFLAGS+=-I${.CURDIR}/../../../lib/libpjdlog
CFLAGS+=-I${.CURDIR}/../../../sbin/casper
MAN=
.include <bsd.prog.mk>

View File

@ -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_

View File

@ -71,7 +71,6 @@ SUBDIR=adjkerntz \
umount
SUBDIR.${MK_ATM}+= atm
SUBDIR.${MK_CASPER}+= casperd
SUBDIR.${MK_CCD}+= ccdconfig
SUBDIR.${MK_CXX}+= devd
SUBDIR.${MK_HAST}+= hastctl

View File

@ -1,17 +0,0 @@
# $FreeBSD$
PROG= casperd
SRCS= casperd.c zygote.c
LIBADD= casper nv pjdlog util
MAN= casperd.8
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${.CURDIR}/../../lib/libcapsicum
CFLAGS+=-I${.CURDIR}/../../lib/libcasper
CFLAGS+=-I${.CURDIR}/../../lib/libnv
CFLAGS+=-I${.CURDIR}/../../lib/libpjdlog
.include <bsd.prog.mk>

View File

@ -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.

View File

@ -1,721 +0,0 @@
/*-
* Copyright (c) 2012 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/capsicum.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/nv.h>
#include <assert.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libutil.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_impl.h>
#include <libcasper.h>
#include <libcasper_impl.h>
#include <msgio.h>
#include <pjdlog.h>
#include "msgio.h"
#include "zygote.h"
#define CASPERD_PIDFILE "/var/run/casperd.pid"
#define CASPERD_SERVCONFDIR "/etc/casper"
#define CASPERD_SOCKPATH "/var/run/casper"
typedef void service_function_t(struct service_connection *, const nvlist_t *,
nvlist_t *);
struct casper_service {
const char *cs_name;
const char *cs_execpath;
struct service *cs_service;
nvlist_t *cs_attrs;
TAILQ_ENTRY(casper_service) cs_next;
};
static TAILQ_HEAD(, casper_service) casper_services =
TAILQ_HEAD_INITIALIZER(casper_services);
#define SERVICE_IS_CORE(service) ((service)->cs_execpath == NULL)
static void service_external_execute(int chanfd);
#define KEEP_ERRNO(work) do { \
int _serrno; \
\
_serrno = errno; \
work; \
errno = _serrno; \
} while (0)
static struct casper_service *
service_find(const char *name)
{
struct casper_service *casserv;
TAILQ_FOREACH(casserv, &casper_services, cs_next) {
if (strcmp(casserv->cs_name, name) == 0)
break;
}
return (casserv);
}
/*
* Function always consumes the given attrs.
*/
static void
service_register(nvlist_t *attrs)
{
struct casper_service *casserv;
const char *name;
PJDLOG_ASSERT(nvlist_exists_string(attrs, "name"));
PJDLOG_ASSERT(nvlist_exists_string(attrs, "execpath") ||
(nvlist_exists_number(attrs, "commandfunc") &&
nvlist_exists_number(attrs, "limitfunc")));
name = nvlist_get_string(attrs, "name");
PJDLOG_ASSERT(name != NULL);
if (name[0] == '\0') {
pjdlog_error("Unable to register service with an empty name.");
nvlist_destroy(attrs);
return;
}
if (service_find(name) != NULL) {
pjdlog_error("Service \"%s\" is already registered.", name);
nvlist_destroy(attrs);
return;
}
casserv = malloc(sizeof(*casserv));
if (casserv == NULL) {
pjdlog_errno(LOG_ERR, "Unable to register service \"%s\"",
name);
nvlist_destroy(attrs);
return;
}
casserv->cs_name = name;
if (nvlist_exists_string(attrs, "execpath")) {
struct stat sb;
PJDLOG_ASSERT(!nvlist_exists_number(attrs, "commandfunc"));
PJDLOG_ASSERT(!nvlist_exists_number(attrs, "limitfunc"));
casserv->cs_service = NULL;
casserv->cs_execpath = nvlist_get_string(attrs, "execpath");
if (casserv->cs_execpath == NULL ||
casserv->cs_execpath[0] == '\0') {
pjdlog_error("Unable to register service with an empty execpath.");
free(casserv);
nvlist_destroy(attrs);
return;
}
if (stat(casserv->cs_execpath, &sb) == -1) {
pjdlog_errno(LOG_ERR,
"Unable to register service \"%s\", problem with executable \"%s\"",
name, casserv->cs_execpath);
free(casserv);
nvlist_destroy(attrs);
return;
}
} else /* if (nvlist_exists_number(attrs, "commandfunc")) */ {
PJDLOG_ASSERT(!nvlist_exists_string(attrs, "execpath"));
casserv->cs_execpath = NULL;
casserv->cs_service = service_alloc(name,
(void *)(uintptr_t)nvlist_get_number(attrs, "limitfunc"),
(void *)(uintptr_t)nvlist_get_number(attrs, "commandfunc"));
if (casserv->cs_service == NULL) {
pjdlog_errno(LOG_ERR,
"Unable to register service \"%s\"", name);
free(casserv);
nvlist_destroy(attrs);
return;
}
}
casserv->cs_attrs = attrs;
TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next);
pjdlog_debug(1, "Service %s successfully registered.",
casserv->cs_name);
}
static bool
casper_allowed_service(const nvlist_t *limits, const char *service)
{
if (limits == NULL)
return (true);
if (nvlist_exists_null(limits, service))
return (true);
return (false);
}
static int
casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
{
const char *name;
int type;
void *cookie;
cookie = NULL;
while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
if (type != NV_TYPE_NULL)
return (EINVAL);
if (!casper_allowed_service(oldlimits, name))
return (ENOTCAPABLE);
}
return (0);
}
static int
casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
nvlist_t *nvlout)
{
struct casper_service *casserv;
const char *servname;
nvlist_t *nvl;
int chanfd, execfd, procfd, error;
if (strcmp(cmd, "open") != 0)
return (EINVAL);
if (!nvlist_exists_string(nvlin, "service"))
return (EINVAL);
servname = nvlist_get_string(nvlin, "service");
casserv = service_find(servname);
if (casserv == NULL)
return (ENOENT);
if (!casper_allowed_service(limits, servname))
return (ENOTCAPABLE);
#ifdef O_EXEC_WORKING
execfd = open(casserv->cs_execpath, O_EXEC);
#else
execfd = open(casserv->cs_execpath, O_RDONLY);
#endif
if (execfd < -1) {
error = errno;
pjdlog_errno(LOG_ERR,
"Unable to open executable '%s' of service '%s'",
casserv->cs_execpath, casserv->cs_name);
return (error);
}
if (zygote_clone(service_external_execute, &chanfd, &procfd) == -1) {
error = errno;
close(execfd);
return (error);
}
nvl = nvlist_create(0);
nvlist_add_string(nvl, "service", casserv->cs_name);
if (nvlist_exists_descriptor(nvlin, "stderrfd")) {
nvlist_move_descriptor(nvl, "stderrfd",
nvlist_take_descriptor(nvlin, "stderrfd"));
}
nvlist_move_descriptor(nvl, "execfd", execfd);
nvlist_move_descriptor(nvl, "procfd", procfd);
if (nvlist_send(chanfd, nvl) == -1) {
error = errno;
pjdlog_errno(LOG_ERR, "Unable to send nvlist");
nvlist_destroy(nvl);
close(chanfd);
return (error);
}
nvlist_destroy(nvl);
nvlist_move_descriptor(nvlout, "chanfd", chanfd);
return (0);
}
static void
fdswap(int *fd0, int *fd1)
{
int tmpfd;
PJDLOG_VERIFY((tmpfd = dup(*fd0)) != -1);
PJDLOG_VERIFY(dup2(*fd1, *fd0) != -1);
PJDLOG_VERIFY(dup2(tmpfd, *fd1) != -1);
close(tmpfd);
tmpfd = *fd0;
*fd0 = *fd1;
*fd1 = tmpfd;
}
static void
fdmove(int *oldfdp, int newfd)
{
if (*oldfdp != newfd) {
PJDLOG_VERIFY(dup2(*oldfdp, newfd) != -1);
close(*oldfdp);
*oldfdp = newfd;
}
}
static void
fdcloexec(int fd)
{
int flags;
flags = fcntl(fd, F_GETFD);
PJDLOG_ASSERT(flags != -1);
if ((flags & FD_CLOEXEC) != 0)
PJDLOG_VERIFY(fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) != -1);
}
static void
service_register_core(void)
{
nvlist_t *nvl;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "name", "core.casper");
nvlist_add_number(nvl, "limitfunc", (uint64_t)(uintptr_t)casper_limit);
nvlist_add_number(nvl, "commandfunc",
(uint64_t)(uintptr_t)casper_command);
service_register(nvl);
}
static int
setup_creds(int sock)
{
struct cmsgcred cred;
if (cred_recv(sock, &cred) == -1)
return (-1);
if (setgroups((int)cred.cmcred_ngroups, cred.cmcred_groups) == -1)
return (-1);
if (setgid(cred.cmcred_groups[0]) == -1)
return (-1);
if (setuid(cred.cmcred_euid) == -1)
return (-1);
return (0);
}
static void
service_external_execute(int chanfd)
{
char *service, *argv[3];
int stderrfd, execfd, procfd;
nvlist_t *nvl;
nvl = nvlist_recv(chanfd, 0);
if (nvl == NULL)
pjdlog_exit(1, "Unable to receive nvlist");
service = nvlist_take_string(nvl, "service");
PJDLOG_ASSERT(service != NULL);
if (nvlist_exists_descriptor(nvl, "stderrfd")) {
stderrfd = nvlist_take_descriptor(nvl, "stderrfd");
} else {
stderrfd = open(_PATH_DEVNULL, O_RDWR);
if (stderrfd < 0)
pjdlog_exit(1, "Unable to open %s", _PATH_DEVNULL);
}
execfd = nvlist_take_descriptor(nvl, "execfd");
procfd = nvlist_take_descriptor(nvl, "procfd");
nvlist_destroy(nvl);
/*
* Move all descriptors into right slots.
*/
if (stderrfd != STDERR_FILENO) {
if (chanfd == STDERR_FILENO)
fdswap(&stderrfd, &chanfd);
else if (execfd == STDERR_FILENO)
fdswap(&stderrfd, &execfd);
else if (procfd == STDERR_FILENO)
fdswap(&stderrfd, &procfd);
fdmove(&stderrfd, STDERR_FILENO);
}
fdcloexec(stderrfd);
if (chanfd != PARENT_FILENO) {
if (execfd == PARENT_FILENO)
fdswap(&chanfd, &execfd);
else if (procfd == PARENT_FILENO)
fdswap(&chanfd, &procfd);
fdmove(&chanfd, PARENT_FILENO);
}
fdcloexec(chanfd);
if (execfd != EXECUTABLE_FILENO) {
if (procfd == EXECUTABLE_FILENO)
fdswap(&execfd, &procfd);
fdmove(&execfd, EXECUTABLE_FILENO);
}
fdcloexec(execfd);
if (procfd != PROC_FILENO)
fdmove(&procfd, PROC_FILENO);
fdcloexec(procfd);
/*
* Use credentials of the caller process.
*/
setup_creds(chanfd);
argv[0] = service;
asprintf(&argv[1], "%d", pjdlog_debug_get());
argv[2] = NULL;
fexecve(execfd, argv, NULL);
pjdlog_exit(1, "Unable to execute service %s", service);
}
static void
service_register_external_one(const char *dirpath, int dfd,
const char *filename)
{
char execpath[FILENAME_MAX];
nvlist_t *nvl;
ssize_t done;
int fd;
fd = openat(dfd, filename, O_RDONLY);
if (fd == -1) {
pjdlog_errno(LOG_ERR, "Unable to open \"%s/%s\"", dirpath,
filename);
return;
}
done = read(fd, execpath, sizeof(execpath));
if (done == -1) {
pjdlog_errno(LOG_ERR, "Unable to read content of \"%s/%s\"",
dirpath, filename);
close(fd);
return;
}
close(fd);
if (done == sizeof(execpath)) {
pjdlog_error("Executable path too long in \"%s/%s\".", dirpath,
filename);
return;
}
execpath[done] = '\0';
while (done > 0) {
if (execpath[--done] == '\n')
execpath[done] = '\0';
}
nvl = nvlist_create(0);
nvlist_add_string(nvl, "name", filename);
nvlist_add_string(nvl, "execpath", execpath);
if (nvlist_error(nvl) != 0) {
pjdlog_common(LOG_ERR, 0, nvlist_error(nvl),
"Unable to allocate attributes for service \"%s/%s\"",
dirpath, filename);
nvlist_destroy(nvl);
return;
}
service_register(nvl);
/* service_register() consumed nvl. */
}
static uint8_t
file_type(int dfd, const char *filename)
{
struct stat sb;
if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename);
return (DT_UNKNOWN);
}
return (IFTODT(sb.st_mode));
}
static void
service_register_external(const char *dirpath)
{
DIR *dirp;
struct dirent *dp;
int dfd;
dirp = opendir(dirpath);
if (dirp == NULL) {
pjdlog_errno(LOG_WARNING, "Unable to open \"%s\"", dirpath);
return;
}
dfd = dirfd(dirp);
PJDLOG_ASSERT(dfd >= 0);
while ((dp = readdir(dirp)) != NULL) {
dp->d_type = file_type(dfd, dp->d_name);
/* We are only interested in regular files, skip the rest. */
if (dp->d_type != DT_REG) {
pjdlog_debug(1,
"File \"%s/%s\" is not a regular file, skipping.",
dirpath, dp->d_name);
continue;
}
service_register_external_one(dirpath, dfd, dp->d_name);
}
closedir(dirp);
}
static void
casper_accept(int lsock)
{
struct casper_service *casserv;
struct service_connection *sconn;
int sock;
sock = accept(lsock, NULL, NULL);
if (sock == -1) {
pjdlog_errno(LOG_ERR, "Unable to accept casper connection");
return;
}
casserv = service_find("core.casper");
PJDLOG_ASSERT(casserv != NULL);
sconn = service_connection_add(casserv->cs_service, sock, NULL);
if (sconn == NULL) {
close(sock);
return;
}
}
static void
main_loop(int lqlen, const char *sockpath, struct pidfh *pfh)
{
fd_set fds;
struct sockaddr_un sun;
struct casper_service *casserv;
struct service_connection *sconn, *sconntmp;
int lsock, sock, maxfd, ret;
mode_t oldumask;
lsock = socket(AF_UNIX, SOCK_STREAM, 0);
if (lsock == -1)
pjdlog_exit(1, "Unable to create socket");
(void)unlink(sockpath);
bzero(&sun, sizeof(sun));
sun.sun_family = AF_UNIX;
PJDLOG_VERIFY(strlcpy(sun.sun_path, sockpath, sizeof(sun.sun_path)) <
sizeof(sun.sun_path));
sun.sun_len = SUN_LEN(&sun);
oldumask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
if (bind(lsock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
pjdlog_exit(1, "Unable to bind to %s", sockpath);
(void)umask(oldumask);
if (listen(lsock, lqlen) == -1)
pjdlog_exit(1, "Unable to listen on %s", sockpath);
for (;;) {
FD_ZERO(&fds);
FD_SET(lsock, &fds);
maxfd = lsock;
TAILQ_FOREACH(casserv, &casper_services, cs_next) {
/* We handle only core services. */
if (!SERVICE_IS_CORE(casserv))
continue;
for (sconn = service_connection_first(casserv->cs_service);
sconn != NULL;
sconn = service_connection_next(sconn)) {
sock = service_connection_get_sock(sconn);
FD_SET(sock, &fds);
maxfd = sock > maxfd ? sock : maxfd;
}
}
maxfd++;
PJDLOG_ASSERT(maxfd <= (int)FD_SETSIZE);
ret = select(maxfd, &fds, NULL, NULL, NULL);
PJDLOG_ASSERT(ret == -1 || ret > 0); /* select() cannot timeout */
if (ret == -1) {
if (errno == EINTR)
continue;
KEEP_ERRNO((void)pidfile_remove(pfh));
pjdlog_exit(1, "select() failed");
}
if (FD_ISSET(lsock, &fds))
casper_accept(lsock);
TAILQ_FOREACH(casserv, &casper_services, cs_next) {
/* We handle only core services. */
if (!SERVICE_IS_CORE(casserv))
continue;
for (sconn = service_connection_first(casserv->cs_service);
sconn != NULL; sconn = sconntmp) {
/*
* Prepare for connection to be removed from
* the list on failure.
*/
sconntmp = service_connection_next(sconn);
sock = service_connection_get_sock(sconn);
if (FD_ISSET(sock, &fds)) {
service_message(casserv->cs_service,
sconn);
}
}
}
}
}
static void
usage(void)
{
pjdlog_exitx(1,
"usage: casperd [-Fhv] [-D servconfdir] [-P pidfile] [-S sockpath]");
}
int
main(int argc, char *argv[])
{
struct pidfh *pfh;
const char *pidfile, *servconfdir, *sockpath;
pid_t otherpid;
int ch, debug, lqlen;
bool foreground;
pjdlog_init(PJDLOG_MODE_STD);
debug = 0;
foreground = false;
lqlen = SOMAXCONN;
pidfile = CASPERD_PIDFILE;
servconfdir = CASPERD_SERVCONFDIR;
sockpath = CASPERD_SOCKPATH;
while ((ch = getopt(argc, argv, "D:Fhl:P:S:v")) != -1) {
switch (ch) {
case 'D':
servconfdir = optarg;
break;
case 'F':
foreground = true;
break;
case 'l':
lqlen = strtol(optarg, NULL, 0);
if (lqlen < 1)
lqlen = SOMAXCONN;
break;
case 'P':
pidfile = optarg;
break;
case 'S':
sockpath = optarg;
break;
case 'v':
debug++;
break;
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 0)
usage();
if (!foreground)
pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
pjdlog_prefix_set("(casperd) ");
pjdlog_debug_set(debug);
if (zygote_init() < 0)
pjdlog_exit(1, "Unable to create zygote process");
pfh = pidfile_open(pidfile, 0600, &otherpid);
if (pfh == NULL) {
if (errno == EEXIST) {
pjdlog_exitx(1, "casperd already running, pid: %jd.",
(intmax_t)otherpid);
}
pjdlog_errno(LOG_WARNING, "Cannot open or create pidfile %s",
pidfile);
}
if (!foreground) {
if (daemon(0, 0) == -1) {
KEEP_ERRNO((void)pidfile_remove(pfh));
pjdlog_exit(1, "Unable to go into background");
}
}
/* Write PID to a file. */
if (pidfile_write(pfh) == -1) {
pjdlog_errno(LOG_WARNING, "Unable to write to pidfile %s",
pidfile);
} else {
pjdlog_debug(1, "PID stored in %s.", pidfile);
}
/*
* Register core services.
*/
service_register_core();
/*
* Register external services.
*/
service_register_external(servconfdir);
/*
* Wait for connections.
*/
main_loop(lqlen, sockpath, pfh);
}

View File

@ -11,8 +11,9 @@ WARNS?= 3
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)

View File

@ -9,7 +9,8 @@ DIRDEPS = \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcapsicum \
lib/libcasper/libcasper \
lib/libcasper/services \
lib/libcompiler_rt \
lib/libipsec \
lib/libnv \

View File

@ -75,10 +75,10 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <arpa/inet.h>
#ifdef HAVE_LIBCAPSICUM
#include <libcapsicum.h>
#include <libcapsicum_dns.h>
#include <libcapsicum_service.h>
#ifdef HAVE_LIBCASPER
#include <libcasper.h>
#include <casper/cap_dns.h>
#endif
#ifdef IPSEC
@ -204,13 +204,13 @@ static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
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 @@ main(int argc, char *const *argv)
if (options & F_PINGFILLED) {
fill((char *)datap, payload);
}
#ifdef HAVE_LIBCAPSICUM
#ifdef HAVE_LIBCASPER
capdns = capdns_setup();
#endif
if (source) {
@ -562,7 +562,7 @@ main(int argc, char *const *argv)
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 @@ main(int argc, char *const *argv)
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 @@ main(int argc, char *const *argv)
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 @@ main(int argc, char *const *argv)
if (options & F_NUMERIC)
cansandbox = true;
#ifdef HAVE_LIBCAPSICUM
#ifdef HAVE_LIBCASPER
else if (capdns != NULL)
cansandbox = true;
#endif
@ -1704,7 +1704,7 @@ pr_addr(struct in_addr ina)
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 @@ fill(char *bp, char *patp)
}
}
#ifdef HAVE_LIBCAPSICUM
#ifdef HAVE_LIBCASPER
static cap_channel_t *
capdns_setup(void)
{
@ -1797,10 +1797,8 @@ capdns_setup(void)
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 @@ capdns_setup(void)
return (capdnsloc);
}
#endif /* HAVE_LIBCAPSICUM */
#endif /* HAVE_LIBCASPER */
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define SECOPT " [-P policy]"

View File

@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd July 25, 2015
.Dd February 25, 2016
.Dt CAPSICUM 4
.Os
.Sh NAME
@ -104,9 +104,8 @@ associated with file descriptors; described in greater detail in
.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

View File

@ -30,7 +30,6 @@ LIBBZ2?= ${DESTDIR}${LIBDIR}/libbz2.a
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

View File

@ -68,8 +68,12 @@ _LIBRARIES= \
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 @@ _DP_bsnmp= crypto
.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 @@ LIBTERMCAPWDIR= ${LIBNCURSESWDIR}
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})

View File

@ -894,10 +894,6 @@ DIRDEPS.powerpc= \
DIRDEPS+= usr.bin/dtc
.endif
.if ${MK_CASPER} == "yes"
DIRDEPS+= sbin/casperd
.endif
DIRDEPS+= ${DIRDEPS.${MACHINE}:U}

View File

@ -33,7 +33,6 @@ DIRDEPS = \
lib/libc++ \
lib/libcalendar \
lib/libcam \
lib/libcasper \
lib/libcom_err/doc \
lib/libcompat \
lib/libcompiler_rt \
@ -187,4 +186,15 @@ DIRDEPS+= \
DIRDEPS+= lib/libnandfs
.endif
.if ${MK_CASPER} != "no"
DIRDEPS+= \
lib/libcasper \
lib/libcasper/services/cap_dns \
lib/libcasper/services/cap_grp \
lib/libcasper/services/cap_pwd \
lib/libcasper/services/cap_random \
lib/libcasper/services/cap_sysctl \
.endif
.include <dirdeps.mk>

View File

@ -10,11 +10,6 @@ DIRDEPS = \
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 \

View File

@ -12,7 +12,6 @@ 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}
@ -22,7 +21,7 @@ all: ${SERVTEST}
.for SERVICE in ${SERVICES}
${SERVICE}.t: ${SERVICE}.c
${CC} ${CFLAGS} ${@:.t=.c} -o $@ -lcapsicum -lnv
${CC} ${CFLAGS} ${@:.t=.c} -o $@ -lnv -lcasper -lcap_${@:.t=}
.endfor

View File

@ -44,9 +44,9 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_dns.h>
#include <libcapsicum_service.h>
#include <libcasper.h>
#include <casper/cap_dns.h>
static int ntest = 1;

View File

@ -41,9 +41,9 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_grp.h>
#include <libcapsicum_service.h>
#include <libcasper.h>
#include <casper/cap_grp.h>
static int ntest = 1;

View File

@ -41,9 +41,9 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_pwd.h>
#include <libcapsicum_service.h>
#include <libcasper.h>
#include <casper/cap_pwd.h>
static int ntest = 1;

View File

@ -44,9 +44,9 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include <libcapsicum.h>
#include <libcapsicum_service.h>
#include <libcapsicum_sysctl.h>
#include <libcasper.h>
#include <casper/cap_sysctl.h>
/*
* We need some sysctls to perform the tests on.

View File

@ -11,8 +11,10 @@ CFLAGS+= -I${.CURDIR}/../ktrace -I${.CURDIR} -I${.CURDIR}/../.. -I.
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

View File

@ -61,7 +61,7 @@ extern int errno;
#include <sys/un.h>
#include <sys/queue.h>
#include <sys/wait.h>
#ifdef HAVE_LIBCAPSICUM
#ifdef HAVE_LIBCASPER
#include <sys/nv.h>
#endif
#include <arpa/inet.h>
@ -70,12 +70,6 @@ extern int errno;
#include <err.h>
#include <grp.h>
#include <inttypes.h>
#ifdef HAVE_LIBCAPSICUM
#include <libcapsicum.h>
#include <libcapsicum_grp.h>
#include <libcapsicum_pwd.h>
#include <libcapsicum_service.h>
#endif
#include <locale.h>
#include <netdb.h>
#include <nl_types.h>
@ -91,6 +85,13 @@ extern int errno;
#include "ktrace.h"
#include "kdump_subr.h"
#ifdef HAVE_LIBCASPER
#include <libcasper.h>
#include <casper/cap_grp.h>
#include <casper/cap_pwd.h>
#endif
u_int abidump(struct ktr_header *);
int fetchprocinfo(struct ktr_header *, u_int *);
int fread_tail(void *, int, int);
@ -151,7 +152,7 @@ struct proc_info
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 @@ localtime_init(void)
(void)localtime(&ltime);
}
#ifdef HAVE_LIBCAPSICUM
#ifdef HAVE_LIBCASPER
static int
cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp)
{
@ -189,8 +190,8 @@ cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp)
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 @@ cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp)
*capgrpp = capgrploc;
return (0);
}
#endif /* HAVE_LIBCAPSICUM */
#endif /* HAVE_LIBCASPER */
int
main(int argc, char *argv[])
@ -302,7 +303,7 @@ main(int argc, char *argv[])
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 @@ ktrstat(struct stat *statp)
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 @@ ktrstat(struct stat *statp)
if (resolv == 0) {
grp = NULL;
} else {
#ifdef HAVE_LIBCAPSICUM
#ifdef HAVE_LIBCASPER
if (capgrp != NULL)
grp = cap_getgrgid(capgrp, statp->st_gid);
else

View File

@ -177,8 +177,9 @@ CFLAGS+= -DLBL_ALIGN
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

View File

@ -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