Author: jamie Date: Wed Jun 24 18:18:35 2009 New Revision: 194869 URL: http://svn.freebsd.org/changeset/base/194869
Log: 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) Added: head/lib/libjail/ head/lib/libjail/Makefile (contents, props changed) head/lib/libjail/jail.3 (contents, props changed) head/lib/libjail/jail.c (contents, props changed) head/lib/libjail/jail.h (contents, props changed) head/lib/libjail/jail_getid.c (contents, props changed) Modified: head/gnu/usr.bin/groff/tmac/mdoc.local head/lib/Makefile head/share/mk/bsd.libnames.mk head/usr.bin/killall/Makefile head/usr.bin/killall/killall.c head/usr.sbin/jail/Makefile head/usr.sbin/jail/jail.c head/usr.sbin/jexec/Makefile head/usr.sbin/jexec/jexec.c head/usr.sbin/jls/Makefile head/usr.sbin/jls/jls.c Modified: head/gnu/usr.bin/groff/tmac/mdoc.local ============================================================================== --- head/gnu/usr.bin/groff/tmac/mdoc.local Wed Jun 24 18:12:16 2009 (r194868) +++ head/gnu/usr.bin/groff/tmac/mdoc.local Wed Jun 24 18:18:35 2009 (r194869) @@ -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) Modified: head/lib/Makefile ============================================================================== --- head/lib/Makefile Wed Jun 24 18:12:16 2009 (r194868) +++ head/lib/Makefile Wed Jun 24 18:18:35 2009 (r194869) @@ -35,8 +35,8 @@ SUBDIR= ${_csu} libc libbsm libauditd li 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 \ Added: head/lib/libjail/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libjail/Makefile Wed Jun 24 18:18:35 2009 (r194869) @@ -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> Added: head/lib/libjail/jail.3 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libjail/jail.3 Wed Jun 24 18:18:35 2009 (r194869) @@ -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(¶ms[0], "name"); +jailparam_import(¶ms[0], "foo"); +jailparam_init(¶ms[1], "host.hostname"); +jailparam_import(¶ms[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(¶ms[0], "name"); +jailparam_import(¶ms[0], "foo"); +jailparam_init(¶ms[1], "host.hostname"); +jailparam_get(params, 2, 0); +hostname = jailparam_export(¶ms[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 Added: head/lib/libjail/jail.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libjail/jail.c Wed Jun 24 18:18:35 2009 (r194869) @@ -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); *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"