1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-18 02:19:39 +00:00

Add libjail, a (somewhat) simpler interface to the jail_set and jail_get

system calls and the security.jail.param sysctls.

Approved by:	bz (mentor)
This commit is contained in:
Jamie Gritton 2009-06-24 18:18:35 +00:00
parent 9d81738f8f
commit de6f37045c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=194869
16 changed files with 1634 additions and 652 deletions

View File

@ -47,6 +47,7 @@
.ds doc-str-Lb-libfetch File Transfer Library (libfetch, \-lfetch)
.ds doc-str-Lb-libgeom Userland API Library for kernel GEOM subsystem (libgeom, \-lgeom)
.ds doc-str-Lb-libipx IPX Address Conversion Support Library (libipx, \-lipx)
.ds doc-str-Lb-libjail Jail Library (libjail, \-ljail)
.ds doc-str-Lb-libkiconv Kernel side iconv library (libkiconv, \-lkiconv)
.ds doc-str-Lb-libkse N:M Threading Library (libkse, \-lkse)
.ds doc-str-Lb-libmd Message Digest (MD4, MD5, etc.) Support Library (libmd, \-lmd)

View File

@ -35,8 +35,8 @@ SUBDIR= ${_csu} libc libbsm libauditd libcom_err libcrypt libelf libkvm msun \
libcalendar libcam libcompat libdevinfo libdevstat libdisk \
libdwarf libedit libexpat libfetch libftpio libgeom ${_libgpib} \
${_libgssapi} ${_librpcsec_gss} libipsec \
${_libipx} libkiconv libmagic libmemstat ${_libmilter} ${_libmp} \
${_libncp} ${_libngatm} libopie libpam libpcap \
${_libipx} libjail libkiconv libmagic libmemstat ${_libmilter} \
${_libmp} ${_libncp} ${_libngatm} libopie libpam libpcap \
${_libpmc} libproc librt ${_libsdp} ${_libsm} ${_libsmb} \
${_libsmdb} \
${_libsmutil} libstand ${_libtelnet} ${_libthr} libthread_db libufs \

29
lib/libjail/Makefile Normal file
View File

@ -0,0 +1,29 @@
# $FreeBSD$
LIB= jail
SHLIBDIR?= /lib
SHLIB_MAJOR= 1
SRCS= jail.c jail_getid.c
INCS= jail.h
MAN= jail.3
MLINKS+=jail.3 jail_getid.3
MLINKS+=jail.3 jail_getname.3
MLINKS+=jail.3 jail_getv.3
MLINKS+=jail.3 jail_setv.3
MLINKS+=jail.3 jailparam.3
MLINKS+=jail.3 jailparam_all.3
MLINKS+=jail.3 jailparam_init.3
MLINKS+=jail.3 jailparam_import.3
MLINKS+=jail.3 jailparam_import_raw.3
MLINKS+=jail.3 jailparam_get.3
MLINKS+=jail.3 jailparam_set.3
MLINKS+=jail.3 jailparam_export.3
MLINKS+=jail.3 jailparam_free.3
CFLAGS+=-I${.CURDIR}
WARNS?= 6
.include <bsd.lib.mk>

275
lib/libjail/jail.3 Normal file
View File

@ -0,0 +1,275 @@
.\" Copyright (c) 2009 James Gritton.
.\" All rights reserved.
.\"
.\" 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 AUTHOR 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 AUTHOR 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 June 24, 2009
.Dt JAIL 3
.Os
.Sh NAME
.Nm jail_getid ,
.Nm jail_getname ,
.Nm jail_setv ,
.Nm jail_getv ,
.Nm jailparam_all ,
.Nm jailparam_init ,
.Nm jailparam_import ,
.Nm jailparam_import_raw ,
.Nm jailparam_set ,
.Nm jailparam_get ,
.Nm jailparam_export ,
.Nm jailparam_free ,
.Nd create and manage system jails
.Sh LIBRARY
.Lb libjail
.Sh SYNOPSIS
.In sys/param.h
.In sys/jail.h
.In jail.h
.Vt extern char jail_errmsg[] ;
.Ft int
.Fn jail_getid "const char *name"
.Ft char *
.Fn jail_getname "int jid"
.Ft int
.Fn jail_setv "int flags" ...
.Ft int
.Fn jail_getv "int flags" ...
.Ft int
.Fn jailparam_all "struct jailparam **jpp"
.Ft int
.Fn jailparam_init "struct jailparam *jp" "const char *name"
.Ft int
.Fn jailparam_import "struct jailparam *jp" "const char *value"
.Ft int
.Fn jailparam_import_raw "struct jailparam *jp" "void *value" "size_t valuelen"
.Ft int
.Fn jailparam_set "struct jailparam *jp" "unsigned njp" "int flags"
.Ft int
.Fn jailparam_get "struct jailparam *jp" "unsigned njp" "int flags"
.Ft char *
.Fn jailparam_export "struct jailparam *jp"
.Ft void
.Fn jailparam_free "struct jailparam *jp" "unsigned njp"
.Sh DESCRIPTION
The
.Nm jail
library is an interface to the
.Xr jail_set 2
and
.Xr jail_get 2
system calls, and the
.Va security.jail.param
MIB entries.
It simplifies the conversion of prison parameters between internal and
string formats, allowing the setting and querying of prisons without
knowing the parameter formats.
.Pp
The
.Fn jail_getid
function returns the JID of the jail identified by
.Ar name ,
or \-1 if the jail does not exist.
.Pp
The
.Fn jail_getname
function returns the name of the jail identified by
.Ar jid ,
or NULL if the jail does not exist.
.Pp
The
.Fn jail_setv
function takes a null-terminated list of name and value strings,
and passes it to
.Xr jail_set 2 .
.Pp
The
.Fn jail_getv
function takes a null-terminated list of name and value strings,
and passes it to
.Xr jail_get 2 .
It is the caller's responsibility to ensure that the value strings point
to buffers large enough to hold the string representation of the
returned parameters.
.Pp
The
.Fn jailparam_all
function sets
.Ar jpp
to a list of all known jail parameters, and returns the number of
parameters.
The list should later be freed with
.Fn jailparam_free
and
.Xr free 3 .
.Pp
The
.Fn jailparam_init
function clears a parameter record and copies the
.Ar name
to it. After use, it should be freed with
.Fn jailparam_free .
.Pp
The
.Fn jailparam_import
function adds a
.Ar value
to a parameter record, converting it from a string to its native form.
The
.Fn jailparam_import_raw
function adds a value without performing any conversion.
.Pp
The
.Fn jailparam_set
function passes a list of parameters to
.Xr jail_set 2 .
The parameters are assumed to have been created with
.Fn jailparam_init
and
.Fn jailparam_import .
.Pp
The
.Fn jailparam_get
function function passes a list of parameters to
.Xr jail_get 2 .
The parameters are assumed to have been created with
.Fn jailparam_init
or
.Fn jailparam_list ,
with one parameter (the key) having been given a value with
.Fn jailparam_import .
.Pp
The
.Fn jailparam_export
function returns the string equivalent of a parameter value.
The returned string should freed after use.
.Pp
The
.Fn jailparam_free
function frees the stored names and values in a parameter list.
If the list itself came from
.Fn jailparam_all ,
it should be freed as well.
.Sh EXAMPLES
Set the hostname of jail
.Dq foo
to
.Dq foo.bar :
.Bd -literal -offset indent
jail_setv(JAIL_UPDATE, "name", "foo", "host.hostname", "foo.bar",
NULL);
.Ed
.Pp
OR:
.Bd -literal -offset indent
struct jailparam params[2];
jailparam_init(&params[0], "name");
jailparam_import(&params[0], "foo");
jailparam_init(&params[1], "host.hostname");
jailparam_import(&params[1], "foo.bar");
jailparam_set(params, 2, JAIL_UPDATE);
jailparam_free(params, 2);
.Ed
.Pp
Retrieve the hostname of jail
.Dq foo :
.Bd -literal -offset indent
char hostname[MAXHOSTNAMELEN];
jail_getv(0, "name", "foo", "host.hostname", hostname, NULL);
.Ed
.Pp
OR:
.Bd -literal -offset indent
struct jailparam params[2];
jailparam_init(&params[0], "name");
jailparam_import(&params[0], "foo");
jailparam_init(&params[1], "host.hostname");
jailparam_get(params, 2, 0);
hostname = jailparam_export(&params[1]);
jailparam_free(params, 2);
.Ed
.Sh RETURN VALUES
The
.Fn jail_getid ,
.Fn jail_setv ,
.Fn jail_getv ,
.Fn jailparam_set
and
.Fn jailparam_get
functions return a JID on success, or \-1 on error.
.Pp
The
.Fn jail_getname
and
.Fn jailparam_export
functions return a dynamically allocated string on success, or NULL on error.
.Pp
The
.Fn jailparam_all
function returns the number of parameters on success, or \-1 on error.
.Pp
The
.Fn jailparam_init ,
.Fn jailparam_import
and
.Fn jailparam_import_raw
functions return 0 on success, or \-1 on error.
.Pp
Whenever an error is returned,
.Va errno
is set, and the global string
.Va jail_errmsg
contains a descrption of the error, possibly from
.Xr jail_set 2
or
.Xr jail_get 2 .
.Sh ERRORS
The
.Nm jail
functions may return errors from
.Xr jail_set 2 ,
.Xr jail_get 2 ,
.Xr malloc 3
or
.Xr sysctl 3 .
In addition, the following errors are possible:
.Bl -tag -width Er
.It Bq Er EINVAL
A prameter value cannot be convert from the passed string to its
internal form.
.It Bq Er ENOENT
The named parameter does not exist.
.It Bq Er ENOENT
A parameter is of an unknown type.
.Sh SEE ALSO
.Xr jail 2 ,
.Xr jail 8 ,
.Xr sysctl 3
.Sh HISTORY
The
.Nm jail
library first appeared in
.Fx 8.0 .
.Sh AUTHORS
.An James Gritton

972
lib/libjail/jail.c Normal file
View File

@ -0,0 +1,972 @@
/*-
* Copyright (c) 2009 James Gritton.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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/param.h>
#include <sys/types.h>
#include <sys/jail.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "jail.h"
#define SJPARAM "security.jail.param"
#define JPS_IN_ADDR 1
#define JPS_IN6_ADDR 2
#define ARRAY_SANITY 5
#define ARRAY_SLOP 5
static int jailparam_vlist(struct jailparam **jpp, va_list ap);
static int jailparam_type(struct jailparam *jp);
static char *noname(const char *name);
static char *nononame(const char *name);
char jail_errmsg[JAIL_ERRMSGLEN];
/*
* Import a null-terminated parameter list and set a jail with the flags
* and parameters.
*/
int
jail_setv(int flags, ...)
{
va_list ap;
struct jailparam *jp;
int njp;
va_start(ap, flags);
njp = jailparam_vlist(&jp, ap);
va_end(ap);
if (njp < 0)
return (njp);
return (jailparam_set(jp, njp, flags));
}
/*
* Read a null-terminated parameter list, get the referenced jail, and export
* the parameters to the list.
*/
int
jail_getv(int flags, ...)
{
va_list ap, tap;
struct jailparam *jp;
char *valarg;
const char *value;
int njp, i, jid, namekey, zero;
va_start(ap, flags);
va_copy(tap, ap);
njp = jailparam_vlist(&jp, tap);
va_end(tap);
if (njp < 0)
return (njp);
/*
* See if the name is the search key. If so, we don't want to write
* it back in case it's a read-only string.
*/
namekey = 1;
zero = 0;
for (i = 0; i < njp; i++) {
if (!strcmp(jp->jp_name, "lastjid") ||
(!strcmp(jp->jp_name, "jid") &&
memcmp(jp->jp_value, &zero, sizeof(zero))))
namekey = 0;
}
jid = jailparam_get(jp, njp, flags);
if (jid < 0) {
va_end(ap);
return (-1);
}
for (i = 0; i < njp; i++) {
(void)va_arg(ap, char *);
value = jailparam_export(jp + i);
if (value == NULL) {
va_end(ap);
return (-1);
}
valarg = va_arg(ap, char *);
if (!namekey || strcmp(jp[i].jp_name, "name"))
/* It's up to the caller to ensure there's room. */
strcpy(valarg, value);
}
va_end(ap);
return (jid);
}
/*
* Return a list of all known parameters.
*/
int
jailparam_all(struct jailparam **jpp)
{
struct jailparam *jp;
char *nname;
size_t mlen1, mlen2, buflen;
int njp, nlist;
int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
char buf[MAXPATHLEN];
njp = 0;
nlist = 32;
jp = malloc(nlist * sizeof(*jp));
if (jp == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (-1);
}
mib1[0] = 0;
mib1[1] = 2;
mlen1 = CTL_MAXNAME - 2;
if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctlnametomib(" SJPARAM "): %s", strerror(errno));
goto error;
}
for (;; njp++) {
/* Get the next parameter. */
mlen2 = sizeof(mib2);
if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(0.2): %s", strerror(errno));
goto error;
}
if (mib2[0] != mib1[2] || mib2[1] != mib1[3] ||
mib2[2] != mib1[4])
break;
/* Convert it to an ascii name. */
memcpy(mib1 + 2, mib2, mlen2);
mlen1 = mlen2 / sizeof(int);
mib1[1] = 1;
buflen = sizeof(buf);
if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(0.1): %s", strerror(errno));
goto error;
}
/* Add the parameter to the list */
if (njp >= nlist) {
nlist *= 2;
jp = realloc(jp, nlist * sizeof(jp));
if (jp == NULL) {
jailparam_free(jp, njp);
return (-1);
}
}
if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0)
goto error;
if (jailparam_type(jp + njp) < 0) {
njp++;
goto error;
}
/* Convert nobool parameters to bool. */
if (jp[njp].jp_flags & JP_NOBOOL) {
nname = nononame(jp[njp].jp_name);
if (nname == NULL) {
njp++;
goto error;
}
free(jp[njp].jp_name);
jp[njp].jp_name = nname;
jp[njp].jp_flags ^= JP_BOOL | JP_NOBOOL;
}
mib1[1] = 2;
}
jp = realloc(jp, njp * sizeof(*jp));
*jpp = jp;
return (njp);
error:
jailparam_free(jp, njp);
free(jp);
return (-1);
}
/*
* Clear a jail parameter and copy in its name.
*/
int
jailparam_init(struct jailparam *jp, const char *name)
{
memset(jp, 0, sizeof(*jp));
jp->jp_name = strdup(name);
if (jp->jp_name == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (-1);
}
return (0);
}
/*
* Put a name and value into a jail parameter element, converting the value
* to internal form.
*/
int
jailparam_import(struct jailparam *jp, const char *value)
{
char *p, *ep, *tvalue;
const char *avalue;
int i, nval, fw;
if (!jp->jp_ctltype && jailparam_type(jp) < 0)
goto error;
if (value == NULL)
return (0);
if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) {
jp->jp_value = strdup(value);
if (!jp->jp_value) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
goto error;
}
return (0);
}
nval = 1;
if (jp->jp_elemlen) {
if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) {
jp->jp_value = strdup("");
if (value == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
goto error;
}
jp->jp_valuelen = 0;
return (0);
}
for (p = strchr(value, ','); p; p = strchr(p + 1, ','))
nval++;
jp->jp_valuelen = jp->jp_elemlen * nval;
}
jp->jp_value = malloc(jp->jp_valuelen);
if (!jp->jp_value) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
goto error;
}
avalue = value;
for (i = 0; i < nval; i++) {
fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ",");
switch (jp->jp_ctltype & CTLTYPE) {
case CTLTYPE_INT:
if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) {
if (!strncasecmp(avalue, "true", 4))
((int *)jp->jp_value)[i] = 1;
else if (!strncasecmp(avalue, "false", 5))
((int *)jp->jp_value)[i] = 0;
else {
snprintf(jail_errmsg,
JAIL_ERRMSGLEN,
"%s: unknown boolean value \"%.*s\"",
jp->jp_name, fw, avalue);
errno = EINVAL;
goto error;
}
break;
}
((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10);
integer_test:
if (ep != avalue + fw) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"%s: non-integer value \"%.*s\"",
jp->jp_name, fw, avalue);
errno = EINVAL;
goto error;
}
break;
case CTLTYPE_UINT:
((unsigned *)jp->jp_value)[i] =
strtoul(avalue, &ep, 10);
goto integer_test;
case CTLTYPE_LONG:
((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10);
goto integer_test;
case CTLTYPE_ULONG:
((unsigned long *)jp->jp_value)[i] =
strtoul(avalue, &ep, 10);
goto integer_test;
case CTLTYPE_QUAD:
((int64_t *)jp->jp_value)[i] =
strtoimax(avalue, &ep, 10);
goto integer_test;
case CTLTYPE_STRUCT:
tvalue = alloca(fw + 1);
strlcpy(tvalue, avalue, fw + 1);
switch (jp->jp_structtype) {
case JPS_IN_ADDR:
if (inet_pton(AF_INET, tvalue,
&((struct in_addr *)jp->jp_value)[i]) != 1)
{
snprintf(jail_errmsg,
JAIL_ERRMSGLEN,
"%s: not an IPv4 address: %s",
jp->jp_name, tvalue);
errno = EINVAL;
goto error;
}
break;
case JPS_IN6_ADDR:
if (inet_pton(AF_INET6, tvalue,
&((struct in6_addr *)jp->jp_value)[i]) != 1)
{
snprintf(jail_errmsg,
JAIL_ERRMSGLEN,
"%s: not an IPv6 address: %s",
jp->jp_name, tvalue);
errno = EINVAL;
goto error;
}
break;
default:
goto unknown_type;
}
break;
default:
unknown_type:
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"unknown type for %s", jp->jp_name);
errno = ENOENT;
goto error;
}
avalue += fw + 1;
}
return (0);
error:
free(jp->jp_value);
jp->jp_value = NULL;
return (-1);
}
/*
* Put a name and value into a jail parameter element, copying the value
* but not altering it.
*/
int
jailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen)
{
jp->jp_value = value;
jp->jp_valuelen = valuelen;
jp->jp_flags |= JP_RAWVALUE;
return (0);
}
/*
* Run the jail_set and jail_get system calls on a parameter list.
*/
int
jailparam_set(struct jailparam *jp, unsigned njp, int flags)
{
struct iovec *jiov;
char *nname;
int i, jid;
unsigned j;
jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
for (i = j = 0; j < njp; j++) {
jiov[i].iov_base = jp[j].jp_name;
jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
i++;
if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) {
/*
* Set booleans without values. If one have a value of
* zero, change it to (or from) its "no" counterpart.
*/
jiov[i].iov_base = NULL;
jiov[i].iov_len = 0;
if (jp[j].jp_value != NULL &&
jp[j].jp_valuelen == sizeof(int) &&
!*(int *)jp[j].jp_value) {
nname = jp[j].jp_flags & JP_BOOL
? noname(jiov[i].iov_base)
: nononame(jiov[i].iov_base);
if (nname == NULL)
return (-1);
free(jp[j].jp_name);
jiov[i].iov_base = jp[j].jp_name = nname;
}
} else {
jiov[i].iov_base = jp[j].jp_value;
jiov[i].iov_len =
(jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING
? strlen(jp[j].jp_value) + 1
: jp[j].jp_valuelen;
}
i++;
}
*(const void **)&jiov[i].iov_base = "errmsg";
jiov[i].iov_len = sizeof("errmsg");
i++;
jiov[i].iov_base = jail_errmsg;
jiov[i].iov_len = JAIL_ERRMSGLEN;
i++;
jail_errmsg[0] = 0;
jid = jail_set(jiov, i, flags);
if (jid < 0 && !jail_errmsg[0])
snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s",
strerror(errno));
return (jid);
}
int
jailparam_get(struct jailparam *jp, unsigned njp, int flags)
{
struct iovec *jiov;
struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key;
int i, ai, ki, jid, arrays, sanity;
unsigned j;
/* Find the key and any array parameters. */
jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
jp_lastjid = jp_jid = jp_name = NULL;
arrays = 0;
for (ai = j = 0; j < njp; j++) {
if (!strcmp(jp[j].jp_name, "lastjid"))
jp_lastjid = jp + j;
else if (!strcmp(jp[j].jp_name, "jid"))
jp_jid = jp + j;
else if (!strcmp(jp[j].jp_name, "name"))
jp_name = jp + j;
else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
arrays = 1;
jiov[ai].iov_base = jp[j].jp_name;
jiov[ai].iov_len = strlen(jp[j].jp_name) + 1;
ai++;
jiov[ai].iov_base = NULL;
jiov[ai].iov_len = 0;
ai++;
}
}
jp_key = jp_lastjid ? jp_lastjid :
jp_jid && jp_jid->jp_valuelen == sizeof(int) &&
*(int *)jp_jid->jp_value ? jp_jid : jp_name;
if (jp_key == NULL || jp_key->jp_value == NULL) {
strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN);
errno = ENOENT;
return (-1);
}
ki = ai;
jiov[ki].iov_base = jp_key->jp_name;
jiov[ki].iov_len = strlen(jp_key->jp_name) + 1;
ki++;
jiov[ki].iov_base = jp_key->jp_value;
jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING
? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen;
ki++;
*(const void **)&jiov[ki].iov_base = "errmsg";
jiov[ki].iov_len = sizeof("errmsg");
ki++;
jiov[ki].iov_base = jail_errmsg;
jiov[ki].iov_len = JAIL_ERRMSGLEN;
ki++;
jail_errmsg[0] = 0;
if (arrays && jail_get(jiov, ki, flags) < 0) {
if (!jail_errmsg[0])
snprintf(jail_errmsg, sizeof(jail_errmsg),
"jail_get: %s", strerror(errno));
return (-1);
}
/* Allocate storage for all parameters. */
for (ai = j = 0, i = ki; j < njp; j++) {
if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
ai++;
jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP;
jiov[ai].iov_base = jp[j].jp_value =
malloc(jiov[ai].iov_len);
if (jiov[ai].iov_base == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (-1);
}
memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
ai++;
} else if (jp + j != jp_key) {
jiov[i].iov_base = jp[j].jp_name;
jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
i++;
jiov[i].iov_base = jp[j].jp_value =
malloc(jp[j].jp_valuelen);
if (jiov[i].iov_base == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (-1);
}
jiov[i].iov_len = jp[j].jp_valuelen;
memset(jiov[i].iov_base, 0, jiov[i].iov_len);
i++;
}
}
/*
* Get the prison. If there are array elements, retry a few times
* in case their sizes changed from under us.
*/
for (sanity = 0;; sanity++) {
jid = jail_get(jiov, i, flags);
if (jid >= 0 || !arrays || sanity == ARRAY_SANITY ||
errno != EINVAL || jail_errmsg[0])
break;
for (ai = j = 0; j < njp; j++) {
if (jp[j].jp_elemlen &&
!(jp[j].jp_flags & JP_RAWVALUE)) {
ai++;
free(jiov[ai].iov_base);
jiov[ai].iov_base = jp[j].jp_value = NULL;
jiov[ai].iov_len = 0;
ai++;
}
}
if (jail_get(jiov, ki, flags) < 0)
break;
for (ai = j = 0; j < njp; j++) {
if (jp[j].jp_elemlen &&
!(jp[j].jp_flags & JP_RAWVALUE)) {
ai++;
jiov[ai].iov_len +=
jp[j].jp_elemlen * ARRAY_SLOP;
jiov[ai].iov_base = jp[j].jp_value =
malloc(jiov[ai].iov_len);
if (jiov[ai].iov_base == NULL) {
strerror_r(errno, jail_errmsg,
JAIL_ERRMSGLEN);
return (-1);
}
memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
ai++;
}
}
}
if (jid < 0 && !jail_errmsg[0])
snprintf(jail_errmsg, sizeof(jail_errmsg),
"jail_get: %s", strerror(errno));
for (ai = j = 0, i = ki; j < njp; j++) {
if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
ai++;
jp[j].jp_valuelen = jiov[ai].iov_len;
ai++;
} else if (jp + j != jp_key) {
i++;
jp[j].jp_valuelen = jiov[i].iov_len;
i++;
}
}
return (jid);
}
/*
* Convert a jail parameter's value to external form.
*/
char *
jailparam_export(struct jailparam *jp)
{
char *value, *tvalue, **values;
size_t valuelen;
int i, nval;
char valbuf[INET6_ADDRSTRLEN];
if (!jp->jp_ctltype && jailparam_type(jp) < 0)
return (NULL);
if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) {
value = strdup(jp->jp_value);
if (value == NULL)
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (value);
}
nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1;
if (nval == 0) {
value = strdup("");
if (value == NULL)
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (value);
}
values = alloca(nval * sizeof(char *));
valuelen = 0;
for (i = 0; i < nval; i++) {
switch (jp->jp_ctltype & CTLTYPE) {
case CTLTYPE_INT:
if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) {
strlcpy(valbuf,
((int *)jp->jp_value)[i] ? "true" : "false",
sizeof(valbuf));
break;
}
snprintf(valbuf, sizeof(valbuf), "%d",
((int *)jp->jp_value)[i]);
break;
case CTLTYPE_UINT:
snprintf(valbuf, sizeof(valbuf), "%u",
((unsigned *)jp->jp_value)[i]);
break;
case CTLTYPE_LONG:
snprintf(valbuf, sizeof(valbuf), "%ld",
((long *)jp->jp_value)[i]);
break;
case CTLTYPE_ULONG:
snprintf(valbuf, sizeof(valbuf), "%lu",
((unsigned long *)jp->jp_value)[i]);
break;
case CTLTYPE_QUAD:
snprintf(valbuf, sizeof(valbuf), "%jd",
(intmax_t)((int64_t *)jp->jp_value)[i]);
break;
case CTLTYPE_STRUCT:
switch (jp->jp_structtype) {
case JPS_IN_ADDR:
if (inet_ntop(AF_INET,
&((struct in_addr *)jp->jp_value)[i],
valbuf, sizeof(valbuf)) == NULL) {
strerror_r(errno, jail_errmsg,
JAIL_ERRMSGLEN);
return (NULL);
}
break;
case JPS_IN6_ADDR:
if (inet_ntop(AF_INET6,
&((struct in6_addr *)jp->jp_value)[i],
valbuf, sizeof(valbuf)) == NULL) {
strerror_r(errno, jail_errmsg,
JAIL_ERRMSGLEN);
return (NULL);
}
break;
default:
goto unknown_type;
}
break;
default:
unknown_type:
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"unknown type for %s", jp->jp_name);
errno = ENOENT;
return (NULL);
}
valuelen += strlen(valbuf) + 1;
values[i] = alloca(valuelen);
strcpy(values[i], valbuf);
}
value = malloc(valuelen + 1);
if (value == NULL)
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
else {
tvalue = value;
for (i = 0; i < nval; i++) {
strcpy(tvalue, values[i]);
if (i < nval - 1) {
tvalue += strlen(values[i]);
*tvalue++ = ',';
}
}
}
return (value);
}
/*
* Free the contents of a jail parameter list (but not thst list itself).
*/
void
jailparam_free(struct jailparam *jp, unsigned njp)
{
unsigned j;
for (j = 0; j < njp; j++) {
free(jp[j].jp_name);
if (!(jp[j].jp_flags & JP_RAWVALUE))
free(jp[j].jp_value);
}
}
/*
* Create and import an array of jail parameters, given a list of name and
* value strings, terminated by a null name.
*/
static int
jailparam_vlist(struct jailparam **jpp, va_list ap)
{
va_list tap;
struct jailparam *jp;
char *name, *value;
int njp;
va_copy(tap, ap);
for (njp = 0; va_arg(tap, char *) != NULL; njp++)
(void)va_arg(tap, char *);
va_end(tap);
jp = calloc(njp, sizeof(struct jailparam));
if (jp == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (-1);
}
for (njp = 0; (name = va_arg(ap, char *)) != NULL; njp++) {
value = va_arg(ap, char *);
if (jailparam_init(jp + njp, name) < 0 ||
jailparam_import(jp + njp, value) < 0) {
jailparam_free(jp, njp);
free(jp);
return (-1);
}
}
*jpp = jp;
return (njp);
}
/*
* Find a parameter's type and size from its MIB.
*/
static int
jailparam_type(struct jailparam *jp)
{
char *p, *nname;
size_t miblen, desclen;
int isarray;
struct {
int i;
char s[MAXPATHLEN];
} desc;
int mib[CTL_MAXNAME];
/* The "lastjid" parameter isn't real. */
if (!strcmp(jp->jp_name, "lastjid")) {
jp->jp_valuelen = sizeof(int);
jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR;
return (0);
}
/* Find the sysctl that describes the parameter. */
mib[0] = 0;
mib[1] = 3;
snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", jp->jp_name);
miblen = sizeof(mib) - 2 * sizeof(int);
if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) {
if (errno != ENOENT) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(0.3.%s): %s", jp->jp_name, strerror(errno));
return (-1);
}
/*
* The parameter probably doesn't exist. But it might be
* the "no" counterpart to a boolean.
*/
nname = nononame(jp->jp_name);
if (nname != NULL) {
snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname);
free(nname);
miblen = sizeof(mib) - 2 * sizeof(int);
if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
strlen(desc.s)) >= 0) {
mib[1] = 4;
desclen = sizeof(desc);
if (sysctl(mib, (miblen / sizeof(int)) + 2,
&desc, &desclen, NULL, 0) < 0) {
snprintf(jail_errmsg,
JAIL_ERRMSGLEN,
"sysctl(0.4.%s): %s", desc.s,
strerror(errno));
return (-1);
}
if ((desc.i & CTLTYPE) == CTLTYPE_INT &&
desc.s[0] == 'B') {
jp->jp_ctltype = desc.i;
jp->jp_flags |= JP_NOBOOL;
jp->jp_valuelen = sizeof(int);
return (0);
}
}
}
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"unknown parameter: %s", jp->jp_name);
errno = ENOENT;
return (-1);
}
mib[1] = 4;
desclen = sizeof(desc);
if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen,
NULL, 0) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(0.4.%s): %s", jp->jp_name, strerror(errno));
return (-1);
}
/* See if this is an array type. */
p = strchr(desc.s, '\0');
isarray = 0;
if (p - 2 < desc.s || strcmp(p - 2, ",a"))
isarray = 0;
else {
isarray = 1;
p[-2] = 0;
}
/* Look for types we understand */
jp->jp_ctltype = desc.i;
switch (desc.i & CTLTYPE) {
case CTLTYPE_INT:
if (desc.s[0] == 'B')
jp->jp_flags |=
(desc.s[1] == 'N') ? JP_NOBOOL : JP_BOOL;
case CTLTYPE_UINT:
jp->jp_valuelen = sizeof(int);
break;
case CTLTYPE_LONG:
case CTLTYPE_ULONG:
jp->jp_valuelen = sizeof(long);
break;
case CTLTYPE_QUAD:
jp->jp_valuelen = sizeof(int64_t);
break;
case CTLTYPE_STRING:
desc.s[0] = 0;
desclen = sizeof(desc.s);
if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen,
NULL, 0) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(" SJPARAM ".%s): %s", jp->jp_name,
strerror(errno));
return (-1);
}
jp->jp_valuelen = strtoul(desc.s, NULL, 10);
break;
case CTLTYPE_STRUCT:
if (!strcmp(desc.s, "S,in_addr")) {
jp->jp_structtype = JPS_IN_ADDR;
jp->jp_valuelen = sizeof(struct in_addr);
} else if (!strcmp(desc.s, "S,in6_addr")) {
jp->jp_structtype = JPS_IN6_ADDR;
jp->jp_valuelen = sizeof(struct in6_addr);
} else {
desclen = 0;
if (sysctl(mib + 2, miblen / sizeof(int),
NULL, &jp->jp_valuelen, NULL, 0) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(" SJPARAM ".%s): %s", jp->jp_name,
strerror(errno));
return (-1);
}
}
break;
case CTLTYPE_NODE:
/*
* A node isn't normally a parameter, but may be a boolean
* if its "no" counterpart exists.
*/
nname = noname(jp->jp_name);
if (nname == NULL)
return (-1);
mib[1] = 3;
snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname);
free(nname);
miblen = sizeof(mib) - 2 * sizeof(int);
if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
strlen(desc.s)) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"unknown parameter: %s", jp->jp_name);
return (-1);
}
mib[1] = 4;
desclen = sizeof(desc);
if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen,
NULL, 0) < 0) {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"sysctl(0.4.%s): %s", desc.s, strerror(errno));
return (-1);
}
if ((desc.i & CTLTYPE) != CTLTYPE_INT || desc.s[0] != 'B') {
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"unknown parameter: %s", jp->jp_name);
errno = ENOENT;
return (-1);
}
jp->jp_valuelen = sizeof(int);
jp->jp_ctltype = desc.i;
jp->jp_flags |= JP_BOOL;
break;
default:
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
"unknown type for %s", jp->jp_name);
errno = ENOENT;
return (-1);
}
if (isarray) {
jp->jp_elemlen = jp->jp_valuelen;
jp->jp_valuelen = 0;
}
return (0);
}
/*
* Change a boolean parameter name into its "no" counterpart or vice versa.
*/
static char *
noname(const char *name)
{
char *nname, *p;
nname = malloc(strlen(name) + 3);
if (nname == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (NULL);
}
p = strrchr(name, '.');
if (p != NULL)
sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1);
else
sprintf(nname, "no%s", name);
return (nname);
}
static char *
nononame(const char *name)
{
char *p, *nname;
p = strrchr(name, '.');
if (strncmp(p ? p + 1 : name, "no", 2)) {
snprintf(jail_errmsg, sizeof(jail_errmsg),
"mismatched boolean: %s", name);
errno = EINVAL;
return (NULL);
}
nname = malloc(strlen(name) - 1);
if (nname == NULL) {
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return (NULL);
}
if (p != NULL)
sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3);
else
strcpy(nname, name + 2);
return (nname);
}

68
lib/libjail/jail.h Normal file
View File

@ -0,0 +1,68 @@
/*-
* Copyright (c) 2009 James Gritton.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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 _JAIL_H
#define _JAIL_H
#define JP_RAWVALUE 0x01
#define JP_BOOL 0x02
#define JP_NOBOOL 0x04
#define JAIL_ERRMSGLEN 1024
extern char jail_errmsg[];
struct jailparam {
char *jp_name;
void *jp_value;
size_t jp_valuelen;
size_t jp_elemlen;
int jp_ctltype;
int jp_structtype;
unsigned jp_flags;
};
__BEGIN_DECLS
extern int jail_getid(const char *name);
extern char *jail_getname(int jid);
extern int jail_setv(int flags, ...);
extern int jail_getv(int flags, ...);
extern int jailparam_all(struct jailparam **jpp);
extern int jailparam_init(struct jailparam *jp, const char *name);
extern int jailparam_import(struct jailparam *jp, const char *value);
extern int jailparam_import_raw(struct jailparam *jp, void *value,
size_t valuelen);
extern int jailparam_set(struct jailparam *jp, unsigned njp, int flags);
extern int jailparam_get(struct jailparam *jp, unsigned njp, int flags);
extern char *jailparam_export(struct jailparam *jp);
extern void jailparam_free(struct jailparam *jp, unsigned njp);
__END_DECLS
#endif /* _JAIL_H */

104
lib/libjail/jail_getid.c Normal file
View File

@ -0,0 +1,104 @@
/*-
* Copyright (c) 2009 James Gritton.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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/param.h>
#include <sys/types.h>
#include <sys/jail.h>
#include <sys/uio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jail.h"
/*
* Return the JID corresponding to a jail name.
*/
int
jail_getid(const char *name)
{
char *ep;
int jid;
struct iovec jiov[4];
jid = strtoul(name, &ep, 10);
if (*name && !*ep)
return jid;
*(const void **)&jiov[0].iov_base = "name";
jiov[0].iov_len = sizeof("name");
jiov[1].iov_len = strlen(name) + 1;
jiov[1].iov_base = alloca(jiov[1].iov_len);
strcpy(jiov[1].iov_base, name);
*(const void **)&jiov[2].iov_base = "errmsg";
jiov[2].iov_len = sizeof("errmsg");
jiov[3].iov_base = jail_errmsg;
jiov[3].iov_len = JAIL_ERRMSGLEN;
jail_errmsg[0] = 0;
jid = jail_get(jiov, 4, 0);
if (jid < 0 && !jail_errmsg[0])
snprintf(jail_errmsg, JAIL_ERRMSGLEN, "jail_get: %s",
strerror(errno));
return jid;
}
/*
* Return the name corresponding to a JID.
*/
char *
jail_getname(int jid)
{
struct iovec jiov[6];
char *name;
char namebuf[MAXHOSTNAMELEN];
*(const void **)&jiov[0].iov_base = "jid";
jiov[0].iov_len = sizeof("jid");
jiov[1].iov_base = &jid;
jiov[1].iov_len = sizeof(jid);
*(const void **)&jiov[2].iov_base = "name";
jiov[2].iov_len = sizeof("name");
jiov[3].iov_base = namebuf;
jiov[3].iov_len = sizeof(namebuf);
*(const void **)&jiov[4].iov_base = "errmsg";
jiov[4].iov_len = sizeof("errmsg");
jiov[5].iov_base = jail_errmsg;
jiov[5].iov_len = JAIL_ERRMSGLEN;
jail_errmsg[0] = 0;
jid = jail_get(jiov, 6, 0);
if (jid < 0 && !jail_errmsg[0])
snprintf(jail_errmsg, JAIL_ERRMSGLEN, "jail_get: %s",
strerror(errno));
name = strdup(namebuf);
if (name == NULL)
strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
return name;
}

View File

@ -69,6 +69,7 @@ LIBISC?= ${DESTDIR}${LIBDIR}/libisc.a
LIBISCCC?= ${DESTDIR}${LIBDIR}/libisccc.a
LIBISCCFG?= ${DESTDIR}${LIBDIR}/libisccfg.a
.endif
LIBJAIL?= ${DESTDIR}${LIBDIR}/libjail.a
LIBKADM5CLNT?= ${DESTDIR}${LIBDIR}/libkadm5clnt.a
LIBKADM5SRV?= ${DESTDIR}${LIBDIR}/libkadm5srv.a
LIBKAFS5?= ${DESTDIR}${LIBDIR}/libkafs5.a

View File

@ -1,5 +1,7 @@
# $FreeBSD$
PROG= killall
DPADD= ${LIBJAIL}
LDADD= -ljail
.include <bsd.prog.mk>

View File

@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <fcntl.h>
#include <dirent.h>
#include <jail.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -101,7 +102,6 @@ nosig(char *name)
int
main(int ac, char **av)
{
struct iovec jparams[2];
struct kinfo_proc *procs = NULL, *newprocs;
struct stat sb;
struct passwd *pw;
@ -162,18 +162,9 @@ main(int ac, char **av)
jflag++;
if (*av == NULL)
errx(1, "must specify jail");
jid = strtoul(*av, &ep, 10);
if (!**av || *ep) {
*(const void **)&jparams[0].iov_base =
"name";
jparams[0].iov_len = sizeof("name");
jparams[1].iov_base = *av;
jparams[1].iov_len = strlen(*av) + 1;
jid = jail_get(jparams, 2, 0);
if (jid < 0)
errx(1, "unknown jail: %s",
*av);
}
jid = jail_getid(*av);
if (jid < 0)
errx(1, "%s", jail_errmsg);
if (jail_attach(jid) == -1)
err(1, "jail_attach(%d)", jid);
break;

View File

@ -4,8 +4,8 @@
PROG= jail
MAN= jail.8
DPADD= ${LIBUTIL}
LDADD= -lutil
DPADD= ${LIBJAIL} ${LIBUTIL}
LDADD= -ljail -lutil
WARNS?= 6

View File

@ -32,7 +32,6 @@ __FBSDID("$FreeBSD$");
#include <sys/jail.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@ -41,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <grp.h>
#include <jail.h>
#include <login_cap.h>
#include <netdb.h>
#include <paths.h>
@ -50,15 +50,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#define SJPARAM "security.jail.param"
#define ERRMSG_SIZE 256
struct param {
struct iovec name;
struct iovec value;
};
static struct param *params;
static struct jailparam *params;
static char **param_values;
static int nparams;
@ -113,7 +105,6 @@ int
main(int argc, char **argv)
{
login_cap_t *lcap = NULL;
struct iovec rparams[2];
struct passwd *pwd = NULL;
gid_t *groups;
size_t sysvallen;
@ -121,8 +112,8 @@ main(int argc, char **argv)
int hflag, iflag, Jflag, lflag, rflag, uflag, Uflag;
long ngroups_max;
unsigned pi;
char *ep, *jailname, *securelevel, *username, *JidFile;
char errmsg[ERRMSG_SIZE], enforce_statfs[4];
char *jailname, *securelevel, *username, *JidFile;
char enforce_statfs[4];
static char *cleanenv;
const char *shell, *p = NULL;
FILE *fp;
@ -176,16 +167,9 @@ main(int argc, char **argv)
jail_set_flags |= JAIL_UPDATE;
break;
case 'r':
jid = strtoul(optarg, &ep, 10);
if (!*optarg || *ep) {
*(const void **)&rparams[0].iov_base = "name";
rparams[0].iov_len = sizeof("name");
rparams[1].iov_base = optarg;
rparams[1].iov_len = strlen(optarg) + 1;
jid = jail_get(rparams, 2, 0);
if (jid < 0)
errx(1, "unknown jail: %s", optarg);
}
jid = jail_getid(optarg);
if (jid < 0)
errx(1, "%s", jail_errmsg);
rflag = 1;
break;
default:
@ -280,21 +264,16 @@ main(int argc, char **argv)
if (ip6_addr != NULL)
set_param("ip6.addr", ip6_addr);
#endif
errmsg[0] = 0;
set_param("errmsg", errmsg);
if (Jflag) {
fp = fopen(JidFile, "w");
if (fp == NULL)
errx(1, "Could not create JidFile: %s", JidFile);
}
jid = jail_set(&params->name, 2 * nparams,
jid = jailparam_set(params, nparams,
jail_set_flags ? jail_set_flags : JAIL_CREATE | JAIL_ATTACH);
if (jid < 0) {
if (errmsg[0] != '\0')
errx(1, "%s", errmsg);
err(1, "jail_set");
}
if (jid < 0)
errx(1, "%s", jail_errmsg);
if (iflag) {
printf("%d\n", jid);
fflush(stdout);
@ -303,10 +282,9 @@ main(int argc, char **argv)
if (jail_set_flags) {
fprintf(fp, "jid=%d", jid);
for (i = 0; i < nparams; i++)
if (strcmp(params[i].name.iov_base, "jid") &&
strcmp(params[i].name.iov_base, "errmsg")) {
if (strcmp(params[i].jp_name, "jid")) {
fprintf(fp, " %s",
(char *)params[i].name.iov_base);
(char *)params[i].jp_name);
if (param_values[i]) {
putc('=', fp);
quoted_print(fp,
@ -316,19 +294,19 @@ main(int argc, char **argv)
fprintf(fp, "\n");
} else {
for (i = 0; i < nparams; i++)
if (!strcmp(params[i].name.iov_base, "path"))
if (!strcmp(params[i].jp_name, "path"))
break;
#ifdef INET6
fprintf(fp, "%d\t%s\t%s\t%s%s%s\t%s\n",
jid, i < nparams
? (char *)params[i].value.iov_base : argv[0],
? (char *)params[i].jp_value : argv[0],
argv[1], ip4_addr ? ip4_addr : "",
ip4_addr && ip4_addr[0] && ip6_addr && ip6_addr[0]
? "," : "", ip6_addr ? ip6_addr : "", argv[3]);
#else
fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
jid, i < nparams
? (char *)params[i].value.iov_base : argv[0],
? (char *)params[i].jp_value : argv[0],
argv[1], ip4_addr ? ip4_addr : "", argv[3]);
#endif
}
@ -497,14 +475,8 @@ quoted_print(FILE *fp, char *str)
static void
set_param(const char *name, char *value)
{
struct param *param;
char *ep, *p;
size_t buflen, mlen;
int i, nval, mib[CTL_MAXNAME];
struct {
int i;
char s[MAXPATHLEN];
} buf;
struct jailparam *param;
int i;
static int paramlistsize;
@ -517,9 +489,10 @@ set_param(const char *name, char *value)
/* Check for repeat parameters */
for (i = 0; i < nparams; i++)
if (!strcmp(name, params[i].name.iov_base)) {
if (!strcmp(name, params[i].jp_name)) {
jailparam_free(params + i, 1);
memcpy(params + i, params + i + 1,
(--nparams - i) * sizeof(struct param));
(--nparams - i) * sizeof(struct jailparam));
break;
}
@ -542,141 +515,9 @@ set_param(const char *name, char *value)
/* Look up the paramter. */
param_values[nparams] = value;
param = params + nparams++;
*(const void **)&param->name.iov_base = name;
param->name.iov_len = strlen(name) + 1;
/* Trivial values - no value or errmsg. */
if (value == NULL) {
param->value.iov_base = NULL;
param->value.iov_len = 0;
return;
}
if (!strcmp(name, "errmsg")) {
param->value.iov_base = value;
param->value.iov_len = ERRMSG_SIZE;
return;
}
mib[0] = 0;
mib[1] = 3;
snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name);
mlen = sizeof(mib) - 2 * sizeof(int);
if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0)
errx(1, "unknown parameter: %s", name);
mib[1] = 4;
buflen = sizeof(buf);
if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0)
err(1, "sysctl(0.4.%s)", name);
/*
* See if this is an array type.
* Treat non-arrays as an array of one.
*/
p = strchr(buf.s, '\0');
nval = 1;
if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) {
if (value[0] == '\0' ||
(value[0] == '-' && value[1] == '\0')) {
param->value.iov_base = value;
param->value.iov_len = 0;
return;
}
p[-2] = 0;
for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) {
*p = '\0';
nval++;
}
}
/* Set the values according to the parameter type. */
switch (buf.i & CTLTYPE) {
case CTLTYPE_INT:
case CTLTYPE_UINT:
param->value.iov_len = nval * sizeof(int);
break;
case CTLTYPE_LONG:
case CTLTYPE_ULONG:
param->value.iov_len = nval * sizeof(long);
break;
case CTLTYPE_STRUCT:
if (!strcmp(buf.s, "S,in_addr"))
param->value.iov_len = nval * sizeof(struct in_addr);
#ifdef INET6
else if (!strcmp(buf.s, "S,in6_addr"))
param->value.iov_len = nval * sizeof(struct in6_addr);
#endif
else
errx(1, "%s: unknown parameter structure (%s)",
name, buf.s);
break;
case CTLTYPE_STRING:
if (!strcmp(name, "path")) {
param->value.iov_base = malloc(MAXPATHLEN);
if (param->value.iov_base == NULL)
err(1, "malloc");
if (realpath(value, param->value.iov_base) == NULL)
err(1, "%s: realpath(%s)", name, value);
if (chdir(param->value.iov_base) != 0)
err(1, "chdir: %s",
(char *)param->value.iov_base);
} else
param->value.iov_base = value;
param->value.iov_len = strlen(param->value.iov_base) + 1;
return;
default:
errx(1, "%s: unknown parameter type %d (%s)",
name, buf.i, buf.s);
}
param->value.iov_base = malloc(param->value.iov_len);
for (i = 0; i < nval; i++) {
switch (buf.i & CTLTYPE) {
case CTLTYPE_INT:
((int *)param->value.iov_base)[i] =
strtol(value, &ep, 10);
if (ep[0] != '\0')
errx(1, "%s: non-integer value \"%s\"",
name, value);
break;
case CTLTYPE_UINT:
((unsigned *)param->value.iov_base)[i] =
strtoul(value, &ep, 10);
if (ep[0] != '\0')
errx(1, "%s: non-integer value \"%s\"",
name, value);
break;
case CTLTYPE_LONG:
((long *)param->value.iov_base)[i] =
strtol(value, &ep, 10);
if (ep[0] != '\0')
errx(1, "%s: non-integer value \"%s\"",
name, value);
break;
case CTLTYPE_ULONG:
((unsigned long *)param->value.iov_base)[i] =
strtoul(value, &ep, 10);
if (ep[0] != '\0')
errx(1, "%s: non-integer value \"%s\"",
name, value);
break;
case CTLTYPE_STRUCT:
if (!strcmp(buf.s, "S,in_addr")) {
if (inet_pton(AF_INET, value,
&((struct in_addr *)
param->value.iov_base)[i]) != 1)
errx(1, "%s: not an IPv4 address: %s",
name, value);
}
#ifdef INET6
else if (!strcmp(buf.s, "S,in6_addr")) {
if (inet_pton(AF_INET6, value,
&((struct in6_addr *)
param->value.iov_base)[i]) != 1)
errx(1, "%s: not an IPv6 address: %s",
name, value);
}
#endif
}
if (i > 0)
value[-1] = ',';
value = strchr(value, '\0') + 1;
}
if (jailparam_init(param, name) < 0 ||
jailparam_import(param, value) < 0)
errx(1, "%s", jail_errmsg);
}
static void

View File

@ -2,8 +2,8 @@
PROG= jexec
MAN= jexec.8
DPADD= ${LIBUTIL}
LDADD= -lutil
DPADD= ${LIBJAIL} ${LIBUTIL}
LDADD= -ljail -lutil
WARNS?= 6
.include <bsd.prog.mk>

View File

@ -31,13 +31,13 @@
#include <sys/jail.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <err.h>
#include <errno.h>
#include <jail.h>
#include <limits.h>
#include <login_cap.h>
#include <stdio.h>
@ -67,14 +67,13 @@ static void usage(void);
int
main(int argc, char *argv[])
{
struct iovec params[2];
int jid;
login_cap_t *lcap = NULL;
struct passwd *pwd = NULL;
gid_t *groups = NULL;
int ch, ngroups, uflag, Uflag;
long ngroups_max;
char *ep, *username;
char *username;
ch = uflag = Uflag = 0;
username = NULL;
@ -107,18 +106,11 @@ main(int argc, char *argv[])
usage();
if (uflag)
GET_USER_INFO;
jid = strtoul(argv[0], &ep, 10);
if (!*argv[0] || *ep) {
*(const void **)&params[0].iov_base = "name";
params[0].iov_len = sizeof("name");
params[1].iov_base = argv[0];
params[1].iov_len = strlen(argv[0]) + 1;
jid = jail_get(params, 2, 0);
if (jid < 0)
errx(1, "Unknown jail: %s", argv[0]);
}
jid = jail_getid(argv[0]);
if (jid < 0)
errx(1, "%s", jail_errmsg);
if (jail_attach(jid) == -1)
err(1, "jail_attach(): %d", jid);
err(1, "jail_attach(%d)", jid);
if (chdir("/") == -1)
err(1, "chdir(): /");
if (username != NULL) {

View File

@ -2,6 +2,9 @@
PROG= jls
MAN= jls.8
DPADD= ${LIBJAIL}
LDADD= -ljail
WARNS?= 6
.include <bsd.prog.mk>

View File

@ -33,32 +33,21 @@ __FBSDID("$FreeBSD$");
#include <sys/jail.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <err.h>
#include <errno.h>
#include <jail.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SJPARAM "security.jail.param"
#define ARRAY_SLOP 5
#define CTLTYPE_BOOL (CTLTYPE + 1)
#define CTLTYPE_NOBOOL (CTLTYPE + 2)
#define CTLTYPE_IPADDR (CTLTYPE + 3)
#define CTLTYPE_IP6ADDR (CTLTYPE + 4)
#define PARAM_KEY 0x01
#define PARAM_USER 0x02
#define PARAM_ARRAY 0x04
#define PARAM_OPT 0x08
#define PARAM_WR 0x10
#define JP_USER 0x01000000
#define JP_OPT 0x02000000
#define PRINT_DEFAULT 0x01
#define PRINT_HEADER 0x02
@ -67,31 +56,17 @@ __FBSDID("$FreeBSD$");
#define PRINT_SKIP 0x10
#define PRINT_VERBOSE 0x20
struct param {
char *name;
void *value;
size_t size;
int type;
unsigned flags;
int noparent;
};
struct iovec2 {
struct iovec name;
struct iovec value;
};
static struct param *params;
static struct jailparam *params;
static int *param_noparent;
static int nparams;
static char errmsg[256];
static int add_param(const char *name, void *value, unsigned flags);
static int get_param(const char *name, struct param *param);
static int add_param(const char *name, void *value, size_t valuelen,
struct jailparam *source, unsigned flags);
static int sort_param(const void *a, const void *b);
static char *noname(const char *name);
static char *nononame(const char *name);
static int print_jail(int pflags, int jflags);
static void quoted_print(char *str, int len);
static void quoted_print(char *str);
int
main(int argc, char **argv)
@ -136,50 +111,54 @@ main(int argc, char **argv)
/* Add the parameters to print. */
if (optind == argc) {
if (pflags & PRINT_VERBOSE) {
add_param("jid", NULL, PARAM_USER);
add_param("host.hostname", NULL, PARAM_USER);
add_param("path", NULL, PARAM_USER);
add_param("name", NULL, PARAM_USER);
add_param("dying", NULL, PARAM_USER);
add_param("cpuset.id", NULL, PARAM_USER);
add_param("ip4.addr", NULL, PARAM_USER);
add_param("ip6.addr", NULL, PARAM_USER | PARAM_OPT);
add_param("jid", NULL, (size_t)0, NULL, JP_USER);
add_param("host.hostname", NULL, (size_t)0, NULL,
JP_USER);
add_param("path", NULL, (size_t)0, NULL, JP_USER);
add_param("name", NULL, (size_t)0, NULL, JP_USER);
add_param("dying", NULL, (size_t)0, NULL, JP_USER);
add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER);
add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER);
add_param("ip6.addr", NULL, (size_t)0, NULL,
JP_USER | JP_OPT);
} else {
pflags = (pflags &
~(PRINT_NAMEVAL | PRINT_SKIP | PRINT_VERBOSE)) |
PRINT_DEFAULT;
add_param("jid", NULL, PARAM_USER);
add_param("ip4.addr", NULL, PARAM_USER);
add_param("host.hostname", NULL, PARAM_USER);
add_param("path", NULL, PARAM_USER);
add_param("jid", NULL, (size_t)0, NULL, JP_USER);
add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER);
add_param("host.hostname", NULL, (size_t)0, NULL,
JP_USER);
add_param("path", NULL, (size_t)0, NULL, JP_USER);
}
} else
while (optind < argc)
add_param(argv[optind++], NULL, PARAM_USER);
add_param(argv[optind++], NULL, (size_t)0, NULL,
JP_USER);
if (pflags & PRINT_SKIP) {
/* Check for parameters with boolean parents. */
for (i = 0; i < nparams; i++) {
if ((params[i].flags & PARAM_USER) &&
(dot = strchr(params[i].name, '.'))) {
if ((params[i].jp_flags & JP_USER) &&
(dot = strchr(params[i].jp_name, '.'))) {
*dot = 0;
nname = noname(params[i].name);
nname = noname(params[i].jp_name);
*dot = '.';
params[i].noparent =
add_param(nname, NULL, PARAM_OPT);
param_noparent[i] =
add_param(nname, NULL, (size_t)0, NULL,
JP_OPT);
free(nname);
}
}
}
/* Add the index key and errmsg parameters. */
/* Add the index key parameters. */
if (jid != 0)
add_param("jid", &jid, PARAM_KEY);
add_param("jid", &jid, sizeof(jid), NULL, 0);
else if (jname != NULL)
add_param("name", jname, PARAM_KEY);
add_param("name", jname, strlen(jname), NULL, 0);
else
add_param("lastjid", &lastjid, PARAM_KEY);
add_param("errmsg", errmsg, PARAM_KEY);
add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0);
/* Print a header line if requested. */
if (pflags & PRINT_VERBOSE)
@ -192,105 +171,63 @@ main(int argc, char **argv)
"Hostname Path\n");
else if (pflags & PRINT_HEADER) {
for (i = spc = 0; i < nparams; i++)
if (params[i].flags & PARAM_USER) {
if (params[i].jp_flags & JP_USER) {
if (spc)
putchar(' ');
else
spc = 1;
fputs(params[i].name, stdout);
fputs(params[i].jp_name, stdout);
}
putchar('\n');
}
/* Fetch the jail(s) and print the paramters. */
if (jid != 0 || jname != NULL) {
if (print_jail(pflags, jflags) < 0) {
if (errmsg[0])
errx(1, "%s", errmsg);
err(1, "jail_get");
}
if (print_jail(pflags, jflags) < 0)
errx(1, "%s", jail_errmsg);
} else {
for (lastjid = 0;
(lastjid = print_jail(pflags, jflags)) >= 0; )
;
if (errno != 0 && errno != ENOENT) {
if (errmsg[0])
errx(1, "%s", errmsg);
err(1, "jail_get");
}
if (errno != 0 && errno != ENOENT)
errx(1, "%s", jail_errmsg);
}
return (0);
}
static int
add_param(const char *name, void *value, unsigned flags)
add_param(const char *name, void *value, size_t valuelen,
struct jailparam *source, unsigned flags)
{
struct param *param;
char *nname;
size_t mlen1, mlen2, buflen;
int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
struct jailparam *param, *tparams;
int i, tnparams;
char buf[MAXPATHLEN];
static int paramlistsize;
/* The pseudo-parameter "all" scans the list of available parameters. */
if (!strcmp(name, "all")) {
tnparams = nparams;
mib1[0] = 0;
mib1[1] = 2;
mlen1 = CTL_MAXNAME - 2;
if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0)
err(1, "sysctlnametomib(" SJPARAM ")");
for (;;) {
/* Get the next parameter. */
mlen2 = sizeof(mib2);
if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0)
err(1, "sysctl(0.2)");
if (mib2[0] != mib1[2] || mib2[1] != mib1[3] ||
mib2[2] != mib1[4])
break;
/* Convert it to an ascii name. */
memcpy(mib1 + 2, mib2, mlen2);
mlen1 = mlen2 / sizeof(int);
mib1[1] = 1;
buflen = sizeof(buf);
if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0)
err(1, "sysctl(0.1)");
add_param(buf + sizeof(SJPARAM), NULL, flags);
/*
* Convert nobool parameters to bool if their
* counterpart is a node, ortherwise discard them.
*/
param = &params[nparams - 1];
if (param->type == CTLTYPE_NOBOOL) {
nname = nononame(param->name);
if (get_param(nname, param) >= 0 &&
param->type != CTLTYPE_NODE) {
free(nname);
nparams--;
} else {
free(param->name);
param->name = nname;
param->type = CTLTYPE_BOOL;
param->size = sizeof(int);
param->value = NULL;
}
}
mib1[1] = 2;
}
qsort(params + tnparams, (size_t)(nparams - tnparams),
sizeof(struct param), sort_param);
tnparams = jailparam_all(&tparams);
if (tnparams < 0)
errx(1, "%s", jail_errmsg);
qsort(tparams, (size_t)tnparams, sizeof(struct jailparam),
sort_param);
for (i = 0; i < tnparams; i++)
add_param(tparams[i].jp_name, NULL, (size_t)0,
tparams + i, flags);
free(tparams);
return -1;
}
/* Check for repeat parameters. */
for (i = 0; i < nparams; i++)
if (!strcmp(name, params[i].name)) {
params[i].value = value;
params[i].flags |= flags;
if (!strcmp(name, params[i].jp_name)) {
if (value != NULL && jailparam_import_raw(params + i,
value, valuelen) < 0)
errx(1, "%s", jail_errmsg);
params[i].jp_flags |= flags;
if (source != NULL)
jailparam_free(source, 1);
return i;
}
@ -298,151 +235,57 @@ add_param(const char *name, void *value, unsigned flags)
if (!nparams) {
paramlistsize = 32;
params = malloc(paramlistsize * sizeof(*params));
if (params == NULL)
param_noparent =
malloc(paramlistsize * sizeof(*param_noparent));
if (params == NULL || param_noparent == NULL)
err(1, "malloc");
} else if (nparams >= paramlistsize) {
paramlistsize *= 2;
params = realloc(params, paramlistsize * sizeof(*params));
if (params == NULL)
param_noparent = realloc(param_noparent,
paramlistsize * sizeof(*param_noparent));
if (params == NULL || param_noparent == NULL)
err(1, "realloc");
}
/* Look up the parameter. */
param_noparent[nparams] = -1;
param = params + nparams++;
memset(param, 0, sizeof *param);
param->name = strdup(name);
if (param->name == NULL)
err(1, "strdup");
param->flags = flags;
param->noparent = -1;
/* We have to know about pseudo-parameters without asking. */
if (!strcmp(param->name, "lastjid")) {
param->type = CTLTYPE_INT;
param->size = sizeof(int);
goto got_type;
if (source != NULL) {
*param = *source;
param->jp_flags |= flags;
return param - params;
}
if (!strcmp(param->name, "errmsg")) {
param->type = CTLTYPE_STRING;
param->size = sizeof(errmsg);
goto got_type;
}
if (get_param(name, param) < 0) {
if (errno != ENOENT)
err(1, "sysctl(0.3.%s)", name);
/* See if this the "no" part of an existing boolean. */
if ((nname = nononame(name))) {
i = get_param(nname, param);
free(nname);
if (i >= 0 && param->type == CTLTYPE_BOOL) {
param->type = CTLTYPE_NOBOOL;
goto got_type;
}
}
if (flags & PARAM_OPT) {
if (jailparam_init(param, name) < 0)
errx(1, "%s", jail_errmsg);
param->jp_flags = flags;
if ((value != NULL ? jailparam_import_raw(param, value, valuelen)
: jailparam_import(param, value)) < 0) {
if (flags & JP_OPT) {
nparams--;
return -1;
return (-1);
}
errx(1, "unknown parameter: %s", name);
errx(1, "%s", jail_errmsg);
}
if (param->type == CTLTYPE_NODE) {
/*
* A node isn't normally a parameter, but may be a boolean
* if its "no" counterpart exists.
*/
nname = noname(name);
i = get_param(nname, param);
free(nname);
if (i >= 0 && param->type == CTLTYPE_NOBOOL) {
param->type = CTLTYPE_BOOL;
goto got_type;
}
errx(1, "unknown parameter: %s", name);
}
got_type:
param->value = value;
return param - params;
}
static int
get_param(const char *name, struct param *param)
{
char *p;
size_t buflen, mlen;
int mib[CTL_MAXNAME];
struct {
int i;
char s[MAXPATHLEN];
} buf;
/* Look up the MIB. */
mib[0] = 0;
mib[1] = 3;
snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name);
mlen = sizeof(mib) - 2 * sizeof(int);
if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0)
return (-1);
/* Get the type and size. */
mib[1] = 4;
buflen = sizeof(buf);
if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0)
err(1, "sysctl(0.4.%s)", name);
param->type = buf.i & CTLTYPE;
if (buf.i & (CTLFLAG_WR | CTLFLAG_TUN))
param->flags |= PARAM_WR;
p = strchr(buf.s, '\0');
if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) {
p[-2] = 0;
param->flags |= PARAM_ARRAY;
}
switch (param->type) {
case CTLTYPE_INT:
/* An integer parameter might be a boolean. */
if (buf.s[0] == 'B')
param->type = buf.s[1] == 'N'
? CTLTYPE_NOBOOL : CTLTYPE_BOOL;
case CTLTYPE_UINT:
param->size = sizeof(int);
break;
case CTLTYPE_LONG:
case CTLTYPE_ULONG:
param->size = sizeof(long);
break;
case CTLTYPE_STRUCT:
if (!strcmp(buf.s, "S,in_addr")) {
param->type = CTLTYPE_IPADDR;
param->size = sizeof(struct in_addr);
} else if (!strcmp(buf.s, "S,in6_addr")) {
param->type = CTLTYPE_IP6ADDR;
param->size = sizeof(struct in6_addr);
}
break;
case CTLTYPE_STRING:
buf.s[0] = 0;
sysctl(mib + 2, mlen / sizeof(int), buf.s, &buflen, NULL, 0);
param->size = strtoul(buf.s, NULL, 10);
if (param->size == 0)
param->size = BUFSIZ;
}
return (0);
}
static int
sort_param(const void *a, const void *b)
{
const struct param *parama, *paramb;
const struct jailparam *parama, *paramb;
char *ap, *bp;
/* Put top-level parameters first. */
parama = a;
paramb = b;
ap = strchr(parama->name, '.');
bp = strchr(paramb->name, '.');
ap = strchr(parama->jp_name, '.');
bp = strchr(paramb->jp_name, '.');
if (ap && !bp)
return (1);
if (bp && !ap)
return (-1);
return (strcmp(parama->name, paramb->name));
return (strcmp(parama->jp_name, paramb->jp_name));
}
static char *
@ -483,126 +326,38 @@ static int
print_jail(int pflags, int jflags)
{
char *nname;
int i, ai, jid, count, sanity, spc;
char **param_values;
int i, ai, jid, count, spc;
char ipbuf[INET6_ADDRSTRLEN];
static struct iovec2 *iov, *aiov;
static int narray, nkey;
/* Set up the parameter list(s) the first time around. */
if (iov == NULL) {
iov = malloc(nparams * sizeof(struct iovec2));
if (iov == NULL)
err(1, "malloc");
for (i = narray = 0; i < nparams; i++) {
iov[i].name.iov_base = params[i].name;
iov[i].name.iov_len = strlen(params[i].name) + 1;
iov[i].value.iov_base = params[i].value;
iov[i].value.iov_len =
params[i].type == CTLTYPE_STRING &&
params[i].value != NULL &&
((char *)params[i].value)[0] != '\0'
? strlen(params[i].value) + 1 : params[i].size;
if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) {
narray++;
if (params[i].flags & PARAM_KEY)
nkey++;
}
}
if (narray > nkey) {
aiov = malloc(narray * sizeof(struct iovec2));
if (aiov == NULL)
err(1, "malloc");
for (i = ai = 0; i < nparams; i++)
if (params[i].flags &
(PARAM_KEY | PARAM_ARRAY))
aiov[ai++] = iov[i];
}
}
/* If there are array parameters, find their sizes. */
if (aiov != NULL) {
for (ai = 0; ai < narray; ai++)
if (aiov[ai].value.iov_base == NULL)
aiov[ai].value.iov_len = 0;
if (jail_get((struct iovec *)aiov, 2 * narray, jflags) < 0)
return (-1);
}
/* Allocate storage for all parameters. */
for (i = ai = 0; i < nparams; i++) {
if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) {
if (params[i].flags & PARAM_ARRAY) {
iov[i].value.iov_len = aiov[ai].value.iov_len +
ARRAY_SLOP * params[i].size;
iov[i].value.iov_base =
malloc(iov[i].value.iov_len);
}
ai++;
} else
iov[i].value.iov_base = malloc(params[i].size);
if (iov[i].value.iov_base == NULL)
err(1, "malloc");
if (params[i].value == NULL)
memset(iov[i].value.iov_base, 0, iov[i].value.iov_len);
}
/*
* Get the actual prison. If there are array elements, retry a few
* times in case the size changed from under us.
*/
if ((jid = jail_get((struct iovec *)iov, 2 * nparams, jflags)) < 0) {
if (errno != EINVAL || aiov == NULL || errmsg[0])
return (-1);
for (sanity = 0;; sanity++) {
if (sanity == 10)
return (-1);
for (ai = 0; ai < narray; ai++)
if (params[i].flags & PARAM_ARRAY)
aiov[ai].value.iov_len = 0;
if (jail_get((struct iovec *)iov, 2 * narray, jflags) <
0)
return (-1);
for (i = ai = 0; i < nparams; i++) {
if (!(params[i].flags &
(PARAM_KEY | PARAM_ARRAY)))
continue;
if (params[i].flags & PARAM_ARRAY) {
iov[i].value.iov_len =
aiov[ai].value.iov_len +
ARRAY_SLOP * params[i].size;
iov[i].value.iov_base =
realloc(iov[i].value.iov_base,
iov[i].value.iov_len);
if (iov[i].value.iov_base == NULL)
err(1, "malloc");
}
ai++;
}
}
}
jid = jailparam_get(params, nparams, jflags);
if (jid < 0)
return jid;
if (pflags & PRINT_VERBOSE) {
printf("%6d %-29.29s %.74s\n"
"%6s %-29.29s %.74s\n"
"%6s %-6d\n",
*(int *)iov[0].value.iov_base,
(char *)iov[1].value.iov_base,
(char *)iov[2].value.iov_base,
*(int *)params[0].jp_value,
(char *)params[1].jp_value,
(char *)params[2].jp_value,
"",
(char *)iov[3].value.iov_base,
*(int *)iov[4].value.iov_base ? "DYING" : "ACTIVE",
(char *)params[3].jp_value,
*(int *)params[4].jp_value ? "DYING" : "ACTIVE",
"",
*(int *)iov[5].value.iov_base);
count = iov[6].value.iov_len / sizeof(struct in_addr);
*(int *)params[5].jp_value);
count = params[6].jp_valuelen / sizeof(struct in_addr);
for (ai = 0; ai < count; ai++)
if (inet_ntop(AF_INET,
&((struct in_addr *)iov[6].value.iov_base)[ai],
&((struct in_addr *)params[6].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
err(1, "inet_ntop");
else
printf("%6s %-15.15s\n", "", ipbuf);
if (!strcmp(params[7].name, "ip6.addr")) {
count = iov[7].value.iov_len / sizeof(struct in6_addr);
if (!strcmp(params[7].jp_name, "ip6.addr")) {
count = params[7].jp_valuelen / sizeof(struct in6_addr);
for (ai = 0; ai < count; ai++)
if (inet_ntop(AF_INET6, &((struct in_addr *)
iov[7].value.iov_base)[ai],
if (inet_ntop(AF_INET6,
&((struct in_addr *)params[7].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
err(1, "inet_ntop");
else
@ -610,19 +365,28 @@ print_jail(int pflags, int jflags)
}
} else if (pflags & PRINT_DEFAULT)
printf("%6d %-15.15s %-29.29s %.74s\n",
*(int *)iov[0].value.iov_base,
iov[1].value.iov_len == 0 ? "-"
: inet_ntoa(*(struct in_addr *)iov[1].value.iov_base),
(char *)iov[2].value.iov_base,
(char *)iov[3].value.iov_base);
*(int *)params[0].jp_value,
params[1].jp_valuelen == 0 ? "-"
: inet_ntoa(*(struct in_addr *)params[1].jp_value),
(char *)params[2].jp_value,
(char *)params[3].jp_value);
else {
param_values = alloca(nparams * sizeof(*param_values));
for (i = 0; i < nparams; i++) {
if (!(params[i].jp_flags & JP_USER))
continue;
param_values[i] = jailparam_export(params + i);
if (param_values[i] == NULL)
errx(1, "%s", jail_errmsg);
}
for (i = spc = 0; i < nparams; i++) {
if (!(params[i].flags & PARAM_USER))
if (!(params[i].jp_flags & JP_USER))
continue;
if ((pflags & PRINT_SKIP) &&
((!(params[i].flags & PARAM_WR)) ||
(params[i].noparent >= 0 &&
*(int *)iov[params[i].noparent].value.iov_base)))
((!(params[i].jp_ctltype &
(CTLFLAG_WR | CTLFLAG_TUN))) ||
(param_noparent[i] >= 0 &&
*(int *)params[param_noparent[i]].jp_value)))
continue;
if (spc)
putchar(' ');
@ -633,109 +397,48 @@ print_jail(int pflags, int jflags)
* Generally "name=value", but for booleans
* either "name" or "noname".
*/
switch (params[i].type) {
case CTLTYPE_BOOL:
if (*(int *)iov[i].value.iov_base)
printf("%s", params[i].name);
if (params[i].jp_flags &
(JP_BOOL | JP_NOBOOL)) {
if (*(int *)params[i].jp_value)
printf("%s", params[i].jp_name);
else {
nname = noname(params[i].name);
nname = (params[i].jp_flags &
JP_NOBOOL) ?
nononame(params[i].jp_name)
: noname(params[i].jp_name);
printf("%s", nname);
free(nname);
}
break;
case CTLTYPE_NOBOOL:
if (*(int *)iov[i].value.iov_base)
printf("%s", params[i].name);
else {
nname =
nononame(params[i].name);
printf("%s", nname);
free(nname);
}
break;
default:
printf("%s=", params[i].name);
continue;
}
printf("%s=", params[i].jp_name);
}
count = params[i].flags & PARAM_ARRAY
? iov[i].value.iov_len / params[i].size : 1;
if (count == 0) {
if (params[i].jp_valuelen == 0) {
if (pflags & PRINT_QUOTED)
printf("\"\"");
else if (!(pflags & PRINT_NAMEVAL))
putchar('-');
}
for (ai = 0; ai < count; ai++) {
if (ai > 0)
putchar(',');
switch (params[i].type) {
case CTLTYPE_INT:
printf("%d", ((int *)
iov[i].value.iov_base)[ai]);
break;
case CTLTYPE_UINT:
printf("%u", ((int *)
iov[i].value.iov_base)[ai]);
break;
case CTLTYPE_IPADDR:
if (inet_ntop(AF_INET,
&((struct in_addr *)
iov[i].value.iov_base)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
err(1, "inet_ntop");
else
printf("%s", ipbuf);
break;
case CTLTYPE_IP6ADDR:
if (inet_ntop(AF_INET6,
&((struct in6_addr *)
iov[i].value.iov_base)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
err(1, "inet_ntop");
else
printf("%s", ipbuf);
break;
case CTLTYPE_LONG:
printf("%ld", ((long *)
iov[i].value.iov_base)[ai]);
case CTLTYPE_ULONG:
printf("%lu", ((long *)
iov[i].value.iov_base)[ai]);
break;
case CTLTYPE_STRING:
if (pflags & PRINT_QUOTED)
quoted_print((char *)
iov[i].value.iov_base,
params[i].size);
else
printf("%.*s",
(int)params[i].size,
(char *)
iov[i].value.iov_base);
break;
case CTLTYPE_BOOL:
case CTLTYPE_NOBOOL:
if (!(pflags & PRINT_NAMEVAL))
printf(((int *)
iov[i].value.iov_base)[ai]
? "true" : "false");
}
}
} else
quoted_print(param_values[i]);
}
putchar('\n');
for (i = 0; i < nparams; i++)
if (params[i].jp_flags & JP_USER)
free(param_values[i]);
}
for (i = 0; i < nparams; i++)
if (params[i].value == NULL)
free(iov[i].value.iov_base);
if (!(params[i].jp_flags & JP_RAWVALUE)) {
free(params[i].jp_value);
params[i].jp_value = NULL;
}
return (jid);
}
static void
quoted_print(char *str, int len)
quoted_print(char *str)
{
int c, qc;
char *p = str;
char *ep = str + len;
/* An empty string needs quoting. */
if (!*p) {
@ -753,7 +456,7 @@ quoted_print(char *str, int len)
: 0;
if (qc)
putchar(qc);
while (p < ep && (c = *p++)) {
while ((c = *p++)) {
if (c == '\\' || c == qc)
putchar('\\');
putchar(c);