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(&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

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"

Reply via email to