1194869Sjamie/*- 2194869Sjamie * Copyright (c) 2009 James Gritton. 3194869Sjamie * All rights reserved. 4194869Sjamie * 5194869Sjamie * Redistribution and use in source and binary forms, with or without 6194869Sjamie * modification, are permitted provided that the following conditions 7194869Sjamie * are met: 8194869Sjamie * 1. Redistributions of source code must retain the above copyright 9194869Sjamie * notice, this list of conditions and the following disclaimer. 10194869Sjamie * 2. Redistributions in binary form must reproduce the above copyright 11194869Sjamie * notice, this list of conditions and the following disclaimer in the 12194869Sjamie * documentation and/or other materials provided with the distribution. 13194869Sjamie * 14194869Sjamie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194869Sjamie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194869Sjamie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194869Sjamie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194869Sjamie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194869Sjamie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194869Sjamie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194869Sjamie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194869Sjamie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194869Sjamie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194869Sjamie * SUCH DAMAGE. 25194869Sjamie */ 26194869Sjamie 27194869Sjamie#include <sys/cdefs.h> 28194869Sjamie__FBSDID("$FreeBSD: stable/10/lib/libjail/jail.c 337880 2018-08-15 22:32:55Z jamie $"); 29194869Sjamie 30194869Sjamie#include <sys/param.h> 31194869Sjamie#include <sys/types.h> 32194869Sjamie#include <sys/jail.h> 33337876Sjamie#include <sys/linker.h> 34194869Sjamie#include <sys/socket.h> 35194869Sjamie#include <sys/sysctl.h> 36194869Sjamie 37194869Sjamie#include <arpa/inet.h> 38194869Sjamie#include <netinet/in.h> 39194869Sjamie 40194869Sjamie#include <errno.h> 41194869Sjamie#include <inttypes.h> 42194869Sjamie#include <stdio.h> 43194869Sjamie#include <stdarg.h> 44194869Sjamie#include <stdlib.h> 45194869Sjamie#include <string.h> 46194869Sjamie 47194869Sjamie#include "jail.h" 48194869Sjamie 49194869Sjamie#define SJPARAM "security.jail.param" 50194869Sjamie 51194869Sjamie#define JPS_IN_ADDR 1 52194869Sjamie#define JPS_IN6_ADDR 2 53194869Sjamie 54194869Sjamie#define ARRAY_SANITY 5 55194869Sjamie#define ARRAY_SLOP 5 56194869Sjamie 57194869Sjamie 58195870Sjamiestatic int jailparam_import_enum(const char **values, int nvalues, 59195870Sjamie const char *valstr, size_t valsize, int *value); 60194869Sjamiestatic int jailparam_type(struct jailparam *jp); 61337876Sjamiestatic int kldload_param(const char *name); 62194869Sjamiestatic char *noname(const char *name); 63194869Sjamiestatic char *nononame(const char *name); 64194869Sjamie 65194869Sjamiechar jail_errmsg[JAIL_ERRMSGLEN]; 66194869Sjamie 67195870Sjamiestatic const char *bool_values[] = { "false", "true" }; 68195870Sjamiestatic const char *jailsys_values[] = { "disable", "new", "inherit" }; 69194869Sjamie 70195870Sjamie 71194869Sjamie/* 72194869Sjamie * Import a null-terminated parameter list and set a jail with the flags 73194869Sjamie * and parameters. 74194869Sjamie */ 75194869Sjamieint 76194869Sjamiejail_setv(int flags, ...) 77194869Sjamie{ 78210133Sjamie va_list ap, tap; 79194869Sjamie struct jailparam *jp; 80210133Sjamie const char *name, *value; 81210133Sjamie int njp, jid; 82194869Sjamie 83210133Sjamie /* Create the parameter list and import the parameters. */ 84194869Sjamie va_start(ap, flags); 85210133Sjamie va_copy(tap, ap); 86210133Sjamie for (njp = 0; va_arg(tap, char *) != NULL; njp++) 87210133Sjamie (void)va_arg(tap, char *); 88210133Sjamie va_end(tap); 89210133Sjamie jp = alloca(njp * sizeof(struct jailparam)); 90241197Sjamie for (njp = 0; (name = va_arg(ap, char *)) != NULL;) { 91210133Sjamie value = va_arg(ap, char *); 92241197Sjamie if (jailparam_init(jp + njp, name) < 0) 93241197Sjamie goto error; 94241197Sjamie if (jailparam_import(jp + njp++, value) < 0) 95241197Sjamie goto error; 96210133Sjamie } 97194869Sjamie va_end(ap); 98210133Sjamie jid = jailparam_set(jp, njp, flags); 99210133Sjamie jailparam_free(jp, njp); 100210133Sjamie return (jid); 101241197Sjamie 102241197Sjamie error: 103241197Sjamie jailparam_free(jp, njp); 104241197Sjamie va_end(ap); 105241197Sjamie return (-1); 106194869Sjamie} 107194869Sjamie 108194869Sjamie/* 109194869Sjamie * Read a null-terminated parameter list, get the referenced jail, and export 110194869Sjamie * the parameters to the list. 111194869Sjamie */ 112194869Sjamieint 113194869Sjamiejail_getv(int flags, ...) 114194869Sjamie{ 115194869Sjamie va_list ap, tap; 116210133Sjamie struct jailparam *jp, *jp_lastjid, *jp_jid, *jp_name, *jp_key; 117210133Sjamie char *valarg, *value; 118210133Sjamie const char *name, *key_value, *lastjid_value, *jid_value, *name_value; 119210133Sjamie int njp, i, jid; 120194869Sjamie 121210133Sjamie /* Create the parameter list and find the key. */ 122194869Sjamie va_start(ap, flags); 123194869Sjamie va_copy(tap, ap); 124210133Sjamie for (njp = 0; va_arg(tap, char *) != NULL; njp++) 125210133Sjamie (void)va_arg(tap, char *); 126194869Sjamie va_end(tap); 127210133Sjamie 128210133Sjamie jp = alloca(njp * sizeof(struct jailparam)); 129210133Sjamie va_copy(tap, ap); 130210133Sjamie jp_lastjid = jp_jid = jp_name = NULL; 131210133Sjamie lastjid_value = jid_value = name_value = NULL; 132210133Sjamie for (njp = 0; (name = va_arg(tap, char *)) != NULL; njp++) { 133210133Sjamie value = va_arg(tap, char *); 134210133Sjamie if (jailparam_init(jp + njp, name) < 0) { 135210133Sjamie va_end(tap); 136210133Sjamie goto error; 137210133Sjamie } 138210133Sjamie if (!strcmp(jp[njp].jp_name, "lastjid")) { 139210133Sjamie jp_lastjid = jp + njp; 140210133Sjamie lastjid_value = value; 141210133Sjamie } else if (!strcmp(jp[njp].jp_name, "jid")) { 142210133Sjamie jp_jid = jp + njp; 143210133Sjamie jid_value = value; 144210133Sjamie } if (!strcmp(jp[njp].jp_name, "name")) { 145210133Sjamie jp_name = jp + njp; 146210133Sjamie name_value = value; 147210133Sjamie } 148194869Sjamie } 149210133Sjamie va_end(tap); 150210133Sjamie /* Import the key parameter. */ 151210133Sjamie if (jp_lastjid != NULL) { 152210133Sjamie jp_key = jp_lastjid; 153210133Sjamie key_value = lastjid_value; 154210133Sjamie } else if (jp_jid != NULL && strtol(jid_value, NULL, 10) != 0) { 155210133Sjamie jp_key = jp_jid; 156210133Sjamie key_value = jid_value; 157210133Sjamie } else if (jp_name != NULL) { 158210133Sjamie jp_key = jp_name; 159210133Sjamie key_value = name_value; 160210133Sjamie } else { 161210133Sjamie strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 162210133Sjamie errno = ENOENT; 163210133Sjamie goto error; 164210133Sjamie } 165210133Sjamie if (jailparam_import(jp_key, key_value) < 0) 166210133Sjamie goto error; 167210133Sjamie /* Get the jail and export the parameters. */ 168194869Sjamie jid = jailparam_get(jp, njp, flags); 169210133Sjamie if (jid < 0) 170210133Sjamie goto error; 171194869Sjamie for (i = 0; i < njp; i++) { 172194869Sjamie (void)va_arg(ap, char *); 173194869Sjamie valarg = va_arg(ap, char *); 174210133Sjamie if (jp + i != jp_key) { 175194869Sjamie /* It's up to the caller to ensure there's room. */ 176210133Sjamie if ((jp[i].jp_ctltype & CTLTYPE) == CTLTYPE_STRING) 177210133Sjamie strcpy(valarg, jp[i].jp_value); 178210133Sjamie else { 179210133Sjamie value = jailparam_export(jp + i); 180210133Sjamie if (value == NULL) 181210133Sjamie goto error; 182210133Sjamie strcpy(valarg, value); 183210133Sjamie free(value); 184210133Sjamie } 185210133Sjamie } 186194869Sjamie } 187210133Sjamie jailparam_free(jp, njp); 188194869Sjamie va_end(ap); 189194869Sjamie return (jid); 190210133Sjamie 191210133Sjamie error: 192210133Sjamie jailparam_free(jp, njp); 193210133Sjamie va_end(ap); 194210133Sjamie return (-1); 195194869Sjamie} 196194869Sjamie 197194869Sjamie/* 198194869Sjamie * Return a list of all known parameters. 199194869Sjamie */ 200194869Sjamieint 201194869Sjamiejailparam_all(struct jailparam **jpp) 202194869Sjamie{ 203241197Sjamie struct jailparam *jp, *tjp; 204194869Sjamie size_t mlen1, mlen2, buflen; 205194869Sjamie int njp, nlist; 206194869Sjamie int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; 207194869Sjamie char buf[MAXPATHLEN]; 208194869Sjamie 209194869Sjamie njp = 0; 210194869Sjamie nlist = 32; 211194869Sjamie jp = malloc(nlist * sizeof(*jp)); 212194869Sjamie if (jp == NULL) { 213194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 214194869Sjamie return (-1); 215194869Sjamie } 216194869Sjamie mib1[0] = 0; 217194869Sjamie mib1[1] = 2; 218194869Sjamie mlen1 = CTL_MAXNAME - 2; 219194869Sjamie if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) { 220194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 221194869Sjamie "sysctlnametomib(" SJPARAM "): %s", strerror(errno)); 222194869Sjamie goto error; 223194869Sjamie } 224194869Sjamie for (;; njp++) { 225194869Sjamie /* Get the next parameter. */ 226194869Sjamie mlen2 = sizeof(mib2); 227194869Sjamie if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) { 228194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 229194869Sjamie "sysctl(0.2): %s", strerror(errno)); 230194869Sjamie goto error; 231194869Sjamie } 232194869Sjamie if (mib2[0] != mib1[2] || mib2[1] != mib1[3] || 233194869Sjamie mib2[2] != mib1[4]) 234194869Sjamie break; 235194869Sjamie /* Convert it to an ascii name. */ 236194869Sjamie memcpy(mib1 + 2, mib2, mlen2); 237194869Sjamie mlen1 = mlen2 / sizeof(int); 238194869Sjamie mib1[1] = 1; 239194869Sjamie buflen = sizeof(buf); 240194869Sjamie if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) { 241194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 242194869Sjamie "sysctl(0.1): %s", strerror(errno)); 243194869Sjamie goto error; 244194869Sjamie } 245195870Sjamie if (buf[buflen - 2] == '.') 246195870Sjamie buf[buflen - 2] = '\0'; 247194869Sjamie /* Add the parameter to the list */ 248194869Sjamie if (njp >= nlist) { 249194869Sjamie nlist *= 2; 250241197Sjamie tjp = realloc(jp, nlist * sizeof(*jp)); 251241197Sjamie if (tjp == NULL) 252241197Sjamie goto error; 253241197Sjamie jp = tjp; 254194869Sjamie } 255194869Sjamie if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0) 256194869Sjamie goto error; 257194869Sjamie mib1[1] = 2; 258194869Sjamie } 259194869Sjamie jp = realloc(jp, njp * sizeof(*jp)); 260194869Sjamie *jpp = jp; 261194869Sjamie return (njp); 262194869Sjamie 263194869Sjamie error: 264194869Sjamie jailparam_free(jp, njp); 265194869Sjamie free(jp); 266194869Sjamie return (-1); 267194869Sjamie} 268194869Sjamie 269194869Sjamie/* 270194869Sjamie * Clear a jail parameter and copy in its name. 271194869Sjamie */ 272194869Sjamieint 273194869Sjamiejailparam_init(struct jailparam *jp, const char *name) 274194869Sjamie{ 275194869Sjamie 276194869Sjamie memset(jp, 0, sizeof(*jp)); 277194869Sjamie jp->jp_name = strdup(name); 278194869Sjamie if (jp->jp_name == NULL) { 279194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 280194869Sjamie return (-1); 281194869Sjamie } 282214434Sjamie if (jailparam_type(jp) < 0) { 283214434Sjamie jailparam_free(jp, 1); 284241197Sjamie jp->jp_name = NULL; 285241197Sjamie jp->jp_value = NULL; 286214434Sjamie return (-1); 287214434Sjamie } 288194869Sjamie return (0); 289194869Sjamie} 290194869Sjamie 291194869Sjamie/* 292194869Sjamie * Put a name and value into a jail parameter element, converting the value 293194869Sjamie * to internal form. 294194869Sjamie */ 295194869Sjamieint 296194869Sjamiejailparam_import(struct jailparam *jp, const char *value) 297194869Sjamie{ 298194869Sjamie char *p, *ep, *tvalue; 299194869Sjamie const char *avalue; 300194869Sjamie int i, nval, fw; 301194869Sjamie 302194869Sjamie if (value == NULL) 303194869Sjamie return (0); 304194869Sjamie if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 305194869Sjamie jp->jp_value = strdup(value); 306195011Sjamie if (jp->jp_value == NULL) { 307194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 308195011Sjamie return (-1); 309194869Sjamie } 310194869Sjamie return (0); 311194869Sjamie } 312194869Sjamie nval = 1; 313194869Sjamie if (jp->jp_elemlen) { 314194869Sjamie if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) { 315194869Sjamie jp->jp_value = strdup(""); 316195011Sjamie if (jp->jp_value == NULL) { 317194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 318195011Sjamie return (-1); 319194869Sjamie } 320194869Sjamie jp->jp_valuelen = 0; 321194869Sjamie return (0); 322194869Sjamie } 323194869Sjamie for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) 324194869Sjamie nval++; 325194869Sjamie jp->jp_valuelen = jp->jp_elemlen * nval; 326194869Sjamie } 327194869Sjamie jp->jp_value = malloc(jp->jp_valuelen); 328195011Sjamie if (jp->jp_value == NULL) { 329194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 330195011Sjamie return (-1); 331194869Sjamie } 332194869Sjamie avalue = value; 333194869Sjamie for (i = 0; i < nval; i++) { 334194869Sjamie fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ","); 335194869Sjamie switch (jp->jp_ctltype & CTLTYPE) { 336194869Sjamie case CTLTYPE_INT: 337194869Sjamie if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { 338195870Sjamie if (!jailparam_import_enum(bool_values, 2, 339195870Sjamie avalue, fw, &((int *)jp->jp_value)[i])) { 340194869Sjamie snprintf(jail_errmsg, 341195870Sjamie JAIL_ERRMSGLEN, "%s: " 342195870Sjamie "unknown boolean value \"%.*s\"", 343194869Sjamie jp->jp_name, fw, avalue); 344194869Sjamie errno = EINVAL; 345194869Sjamie goto error; 346194869Sjamie } 347194869Sjamie break; 348194869Sjamie } 349195870Sjamie if (jp->jp_flags & JP_JAILSYS) { 350195870Sjamie /* 351195870Sjamie * Allow setting a jailsys parameter to "new" 352195870Sjamie * in a booleanesque fashion. 353195870Sjamie */ 354195870Sjamie if (value[0] == '\0') 355195870Sjamie ((int *)jp->jp_value)[i] = JAIL_SYS_NEW; 356195870Sjamie else if (!jailparam_import_enum(jailsys_values, 357195870Sjamie sizeof(jailsys_values) / 358195870Sjamie sizeof(jailsys_values[0]), avalue, fw, 359195870Sjamie &((int *)jp->jp_value)[i])) { 360195870Sjamie snprintf(jail_errmsg, 361195870Sjamie JAIL_ERRMSGLEN, "%s: " 362195870Sjamie "unknown jailsys value \"%.*s\"", 363195870Sjamie jp->jp_name, fw, avalue); 364195870Sjamie errno = EINVAL; 365195870Sjamie goto error; 366195870Sjamie } 367195870Sjamie break; 368195870Sjamie } 369194869Sjamie ((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 370194869Sjamie integer_test: 371194869Sjamie if (ep != avalue + fw) { 372194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 373194869Sjamie "%s: non-integer value \"%.*s\"", 374194869Sjamie jp->jp_name, fw, avalue); 375194869Sjamie errno = EINVAL; 376194869Sjamie goto error; 377194869Sjamie } 378194869Sjamie break; 379194869Sjamie case CTLTYPE_UINT: 380194869Sjamie ((unsigned *)jp->jp_value)[i] = 381194869Sjamie strtoul(avalue, &ep, 10); 382194869Sjamie goto integer_test; 383194869Sjamie case CTLTYPE_LONG: 384194869Sjamie ((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 385194869Sjamie goto integer_test; 386194869Sjamie case CTLTYPE_ULONG: 387194869Sjamie ((unsigned long *)jp->jp_value)[i] = 388194869Sjamie strtoul(avalue, &ep, 10); 389194869Sjamie goto integer_test; 390217616Smdf case CTLTYPE_S64: 391194869Sjamie ((int64_t *)jp->jp_value)[i] = 392194869Sjamie strtoimax(avalue, &ep, 10); 393194869Sjamie goto integer_test; 394217616Smdf case CTLTYPE_U64: 395217616Smdf ((uint64_t *)jp->jp_value)[i] = 396217616Smdf strtoumax(avalue, &ep, 10); 397217616Smdf goto integer_test; 398194869Sjamie case CTLTYPE_STRUCT: 399194869Sjamie tvalue = alloca(fw + 1); 400194869Sjamie strlcpy(tvalue, avalue, fw + 1); 401194869Sjamie switch (jp->jp_structtype) { 402194869Sjamie case JPS_IN_ADDR: 403194869Sjamie if (inet_pton(AF_INET, tvalue, 404194869Sjamie &((struct in_addr *)jp->jp_value)[i]) != 1) 405194869Sjamie { 406194869Sjamie snprintf(jail_errmsg, 407194869Sjamie JAIL_ERRMSGLEN, 408194869Sjamie "%s: not an IPv4 address: %s", 409194869Sjamie jp->jp_name, tvalue); 410194869Sjamie errno = EINVAL; 411194869Sjamie goto error; 412194869Sjamie } 413194869Sjamie break; 414194869Sjamie case JPS_IN6_ADDR: 415194869Sjamie if (inet_pton(AF_INET6, tvalue, 416194869Sjamie &((struct in6_addr *)jp->jp_value)[i]) != 1) 417194869Sjamie { 418194869Sjamie snprintf(jail_errmsg, 419194869Sjamie JAIL_ERRMSGLEN, 420194869Sjamie "%s: not an IPv6 address: %s", 421194869Sjamie jp->jp_name, tvalue); 422194869Sjamie errno = EINVAL; 423194869Sjamie goto error; 424194869Sjamie } 425194869Sjamie break; 426194869Sjamie default: 427194869Sjamie goto unknown_type; 428194869Sjamie } 429194869Sjamie break; 430194869Sjamie default: 431194869Sjamie unknown_type: 432194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 433194869Sjamie "unknown type for %s", jp->jp_name); 434194869Sjamie errno = ENOENT; 435194869Sjamie goto error; 436194869Sjamie } 437194869Sjamie avalue += fw + 1; 438194869Sjamie } 439194869Sjamie return (0); 440194869Sjamie 441194869Sjamie error: 442194869Sjamie free(jp->jp_value); 443194869Sjamie jp->jp_value = NULL; 444194869Sjamie return (-1); 445194869Sjamie} 446194869Sjamie 447195870Sjamiestatic int 448195870Sjamiejailparam_import_enum(const char **values, int nvalues, const char *valstr, 449195870Sjamie size_t valsize, int *value) 450195870Sjamie{ 451195870Sjamie char *ep; 452195870Sjamie int i; 453195870Sjamie 454195870Sjamie for (i = 0; i < nvalues; i++) 455195870Sjamie if (valsize == strlen(values[i]) && 456195870Sjamie !strncasecmp(valstr, values[i], valsize)) { 457195870Sjamie *value = i; 458195870Sjamie return 1; 459195870Sjamie } 460195870Sjamie *value = strtol(valstr, &ep, 10); 461195870Sjamie return (ep == valstr + valsize); 462195870Sjamie} 463195870Sjamie 464194869Sjamie/* 465194869Sjamie * Put a name and value into a jail parameter element, copying the value 466194869Sjamie * but not altering it. 467194869Sjamie */ 468194869Sjamieint 469194869Sjamiejailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen) 470194869Sjamie{ 471194869Sjamie 472194869Sjamie jp->jp_value = value; 473194869Sjamie jp->jp_valuelen = valuelen; 474194869Sjamie jp->jp_flags |= JP_RAWVALUE; 475194869Sjamie return (0); 476194869Sjamie} 477194869Sjamie 478194869Sjamie/* 479194869Sjamie * Run the jail_set and jail_get system calls on a parameter list. 480194869Sjamie */ 481194869Sjamieint 482194869Sjamiejailparam_set(struct jailparam *jp, unsigned njp, int flags) 483194869Sjamie{ 484194869Sjamie struct iovec *jiov; 485194869Sjamie char *nname; 486195011Sjamie int i, jid, bool0; 487194869Sjamie unsigned j; 488194869Sjamie 489194869Sjamie jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 490195011Sjamie bool0 = 0; 491194869Sjamie for (i = j = 0; j < njp; j++) { 492194869Sjamie jiov[i].iov_base = jp[j].jp_name; 493194869Sjamie jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 494194869Sjamie i++; 495194869Sjamie if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) { 496194869Sjamie /* 497195011Sjamie * Set booleans without values. If one has a value of 498194869Sjamie * zero, change it to (or from) its "no" counterpart. 499194869Sjamie */ 500194869Sjamie jiov[i].iov_base = NULL; 501194869Sjamie jiov[i].iov_len = 0; 502194869Sjamie if (jp[j].jp_value != NULL && 503194869Sjamie jp[j].jp_valuelen == sizeof(int) && 504194869Sjamie !*(int *)jp[j].jp_value) { 505195011Sjamie bool0 = 1; 506194869Sjamie nname = jp[j].jp_flags & JP_BOOL 507195011Sjamie ? noname(jp[j].jp_name) 508195011Sjamie : nononame(jp[j].jp_name); 509195011Sjamie if (nname == NULL) { 510195011Sjamie njp = j; 511195011Sjamie jid = -1; 512195011Sjamie goto done; 513195011Sjamie } 514195011Sjamie jiov[i - 1].iov_base = nname; 515195011Sjamie jiov[i - 1].iov_len = strlen(nname) + 1; 516194869Sjamie } 517337880Sjamie /* 518337880Sjamie * Load filesystem modules associated with allow.mount 519337880Sjamie * permissions. Ignore failure, since the module may 520337880Sjamie * be static, and even a failure to load is not a jail 521337880Sjamie * error. 522337880Sjamie */ 523337880Sjamie if (strncmp(jp[j].jp_name, "allow.mount.", 12) == 0) { 524337880Sjamie if (kldload(jp[j].jp_name + 12) < 0 && 525337880Sjamie errno == ENOENT && 526337880Sjamie strncmp(jp[j].jp_name + 12, "no", 2) == 0) 527337880Sjamie (void)kldload(jp[j].jp_name + 14); 528337880Sjamie } 529194869Sjamie } else { 530195870Sjamie /* 531195870Sjamie * Try to fill in missing values with an empty string. 532195870Sjamie */ 533195870Sjamie if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 && 534195870Sjamie jailparam_import(jp + j, "") < 0) { 535195870Sjamie njp = j; 536195870Sjamie jid = -1; 537195870Sjamie goto done; 538195870Sjamie } 539194869Sjamie jiov[i].iov_base = jp[j].jp_value; 540194869Sjamie jiov[i].iov_len = 541194869Sjamie (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING 542194869Sjamie ? strlen(jp[j].jp_value) + 1 543194869Sjamie : jp[j].jp_valuelen; 544194869Sjamie } 545194869Sjamie i++; 546194869Sjamie } 547194869Sjamie *(const void **)&jiov[i].iov_base = "errmsg"; 548194869Sjamie jiov[i].iov_len = sizeof("errmsg"); 549194869Sjamie i++; 550194869Sjamie jiov[i].iov_base = jail_errmsg; 551194869Sjamie jiov[i].iov_len = JAIL_ERRMSGLEN; 552194869Sjamie i++; 553194869Sjamie jail_errmsg[0] = 0; 554194869Sjamie jid = jail_set(jiov, i, flags); 555194869Sjamie if (jid < 0 && !jail_errmsg[0]) 556194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s", 557194869Sjamie strerror(errno)); 558195011Sjamie done: 559195011Sjamie if (bool0) 560195011Sjamie for (j = 0; j < njp; j++) 561195011Sjamie if ((jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) && 562195011Sjamie jp[j].jp_value != NULL && 563195011Sjamie jp[j].jp_valuelen == sizeof(int) && 564195011Sjamie !*(int *)jp[j].jp_value) 565195011Sjamie free(jiov[j * 2].iov_base); 566194869Sjamie return (jid); 567194869Sjamie} 568194869Sjamie 569194869Sjamieint 570194869Sjamiejailparam_get(struct jailparam *jp, unsigned njp, int flags) 571194869Sjamie{ 572194869Sjamie struct iovec *jiov; 573194869Sjamie struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key; 574194869Sjamie int i, ai, ki, jid, arrays, sanity; 575194869Sjamie unsigned j; 576194869Sjamie 577195011Sjamie /* 578195011Sjamie * Get the types for all parameters. 579195011Sjamie * Find the key and any array parameters. 580195011Sjamie */ 581194869Sjamie jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 582194869Sjamie jp_lastjid = jp_jid = jp_name = NULL; 583194869Sjamie arrays = 0; 584194869Sjamie for (ai = j = 0; j < njp; j++) { 585194869Sjamie if (!strcmp(jp[j].jp_name, "lastjid")) 586194869Sjamie jp_lastjid = jp + j; 587194869Sjamie else if (!strcmp(jp[j].jp_name, "jid")) 588194869Sjamie jp_jid = jp + j; 589194869Sjamie else if (!strcmp(jp[j].jp_name, "name")) 590194869Sjamie jp_name = jp + j; 591194869Sjamie else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 592194869Sjamie arrays = 1; 593194869Sjamie jiov[ai].iov_base = jp[j].jp_name; 594194869Sjamie jiov[ai].iov_len = strlen(jp[j].jp_name) + 1; 595194869Sjamie ai++; 596194869Sjamie jiov[ai].iov_base = NULL; 597194869Sjamie jiov[ai].iov_len = 0; 598194869Sjamie ai++; 599194869Sjamie } 600194869Sjamie } 601194869Sjamie jp_key = jp_lastjid ? jp_lastjid : 602194869Sjamie jp_jid && jp_jid->jp_valuelen == sizeof(int) && 603200623Sjamie jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name; 604194869Sjamie if (jp_key == NULL || jp_key->jp_value == NULL) { 605194869Sjamie strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 606194869Sjamie errno = ENOENT; 607194869Sjamie return (-1); 608194869Sjamie } 609194869Sjamie ki = ai; 610194869Sjamie jiov[ki].iov_base = jp_key->jp_name; 611194869Sjamie jiov[ki].iov_len = strlen(jp_key->jp_name) + 1; 612194869Sjamie ki++; 613194869Sjamie jiov[ki].iov_base = jp_key->jp_value; 614194869Sjamie jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING 615194869Sjamie ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen; 616194869Sjamie ki++; 617194869Sjamie *(const void **)&jiov[ki].iov_base = "errmsg"; 618194869Sjamie jiov[ki].iov_len = sizeof("errmsg"); 619194869Sjamie ki++; 620194869Sjamie jiov[ki].iov_base = jail_errmsg; 621194869Sjamie jiov[ki].iov_len = JAIL_ERRMSGLEN; 622194869Sjamie ki++; 623194869Sjamie jail_errmsg[0] = 0; 624194869Sjamie if (arrays && jail_get(jiov, ki, flags) < 0) { 625194869Sjamie if (!jail_errmsg[0]) 626194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), 627194869Sjamie "jail_get: %s", strerror(errno)); 628194869Sjamie return (-1); 629194869Sjamie } 630194869Sjamie /* Allocate storage for all parameters. */ 631194869Sjamie for (ai = j = 0, i = ki; j < njp; j++) { 632194869Sjamie if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 633194869Sjamie ai++; 634194869Sjamie jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP; 635195011Sjamie if (jp[j].jp_valuelen >= jiov[ai].iov_len) 636195011Sjamie jiov[ai].iov_len = jp[j].jp_valuelen; 637195011Sjamie else { 638195011Sjamie jp[j].jp_valuelen = jiov[ai].iov_len; 639195011Sjamie if (jp[j].jp_value != NULL) 640195011Sjamie free(jp[j].jp_value); 641195011Sjamie jp[j].jp_value = malloc(jp[j].jp_valuelen); 642195011Sjamie if (jp[j].jp_value == NULL) { 643195011Sjamie strerror_r(errno, jail_errmsg, 644195011Sjamie JAIL_ERRMSGLEN); 645195011Sjamie return (-1); 646195011Sjamie } 647194869Sjamie } 648195011Sjamie jiov[ai].iov_base = jp[j].jp_value; 649194869Sjamie memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 650194869Sjamie ai++; 651194869Sjamie } else if (jp + j != jp_key) { 652194869Sjamie jiov[i].iov_base = jp[j].jp_name; 653194869Sjamie jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 654194869Sjamie i++; 655195011Sjamie if (jp[j].jp_value == NULL && 656195011Sjamie !(jp[j].jp_flags & JP_RAWVALUE)) { 657195011Sjamie jp[j].jp_value = malloc(jp[j].jp_valuelen); 658195011Sjamie if (jp[j].jp_value == NULL) { 659195011Sjamie strerror_r(errno, jail_errmsg, 660195011Sjamie JAIL_ERRMSGLEN); 661195011Sjamie return (-1); 662195011Sjamie } 663194869Sjamie } 664195011Sjamie jiov[i].iov_base = jp[j].jp_value; 665194869Sjamie jiov[i].iov_len = jp[j].jp_valuelen; 666194869Sjamie memset(jiov[i].iov_base, 0, jiov[i].iov_len); 667194869Sjamie i++; 668194869Sjamie } 669194869Sjamie } 670194869Sjamie /* 671194869Sjamie * Get the prison. If there are array elements, retry a few times 672194869Sjamie * in case their sizes changed from under us. 673194869Sjamie */ 674194869Sjamie for (sanity = 0;; sanity++) { 675194869Sjamie jid = jail_get(jiov, i, flags); 676194869Sjamie if (jid >= 0 || !arrays || sanity == ARRAY_SANITY || 677194869Sjamie errno != EINVAL || jail_errmsg[0]) 678194869Sjamie break; 679194869Sjamie for (ai = j = 0; j < njp; j++) { 680194869Sjamie if (jp[j].jp_elemlen && 681194869Sjamie !(jp[j].jp_flags & JP_RAWVALUE)) { 682194869Sjamie ai++; 683195011Sjamie jiov[ai].iov_base = NULL; 684194869Sjamie jiov[ai].iov_len = 0; 685194869Sjamie ai++; 686194869Sjamie } 687194869Sjamie } 688194869Sjamie if (jail_get(jiov, ki, flags) < 0) 689194869Sjamie break; 690194869Sjamie for (ai = j = 0; j < njp; j++) { 691194869Sjamie if (jp[j].jp_elemlen && 692194869Sjamie !(jp[j].jp_flags & JP_RAWVALUE)) { 693194869Sjamie ai++; 694194869Sjamie jiov[ai].iov_len += 695194869Sjamie jp[j].jp_elemlen * ARRAY_SLOP; 696195011Sjamie if (jp[j].jp_valuelen >= jiov[ai].iov_len) 697195011Sjamie jiov[ai].iov_len = jp[j].jp_valuelen; 698195011Sjamie else { 699195011Sjamie jp[j].jp_valuelen = jiov[ai].iov_len; 700195011Sjamie if (jp[j].jp_value != NULL) 701195011Sjamie free(jp[j].jp_value); 702195011Sjamie jp[j].jp_value = 703195011Sjamie malloc(jiov[ai].iov_len); 704195011Sjamie if (jp[j].jp_value == NULL) { 705195011Sjamie strerror_r(errno, jail_errmsg, 706195011Sjamie JAIL_ERRMSGLEN); 707195011Sjamie return (-1); 708195011Sjamie } 709194869Sjamie } 710195011Sjamie jiov[ai].iov_base = jp[j].jp_value; 711194869Sjamie memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 712194869Sjamie ai++; 713194869Sjamie } 714194869Sjamie } 715194869Sjamie } 716194869Sjamie if (jid < 0 && !jail_errmsg[0]) 717194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), 718194869Sjamie "jail_get: %s", strerror(errno)); 719194869Sjamie for (ai = j = 0, i = ki; j < njp; j++) { 720194869Sjamie if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 721194869Sjamie ai++; 722194869Sjamie jp[j].jp_valuelen = jiov[ai].iov_len; 723194869Sjamie ai++; 724194869Sjamie } else if (jp + j != jp_key) { 725194869Sjamie i++; 726194869Sjamie jp[j].jp_valuelen = jiov[i].iov_len; 727194869Sjamie i++; 728194869Sjamie } 729194869Sjamie } 730194869Sjamie return (jid); 731194869Sjamie} 732194869Sjamie 733194869Sjamie/* 734194869Sjamie * Convert a jail parameter's value to external form. 735194869Sjamie */ 736194869Sjamiechar * 737194869Sjamiejailparam_export(struct jailparam *jp) 738194869Sjamie{ 739212073Sjamie size_t *valuelens; 740194869Sjamie char *value, *tvalue, **values; 741194869Sjamie size_t valuelen; 742195870Sjamie int i, nval, ival; 743194869Sjamie char valbuf[INET6_ADDRSTRLEN]; 744194869Sjamie 745194869Sjamie if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 746194869Sjamie value = strdup(jp->jp_value); 747194869Sjamie if (value == NULL) 748194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 749194869Sjamie return (value); 750194869Sjamie } 751194869Sjamie nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1; 752194869Sjamie if (nval == 0) { 753194869Sjamie value = strdup(""); 754194869Sjamie if (value == NULL) 755194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 756194869Sjamie return (value); 757194869Sjamie } 758194869Sjamie values = alloca(nval * sizeof(char *)); 759212073Sjamie valuelens = alloca(nval * sizeof(size_t)); 760194869Sjamie valuelen = 0; 761194869Sjamie for (i = 0; i < nval; i++) { 762194869Sjamie switch (jp->jp_ctltype & CTLTYPE) { 763194869Sjamie case CTLTYPE_INT: 764195870Sjamie ival = ((int *)jp->jp_value)[i]; 765195870Sjamie if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && 766195870Sjamie (unsigned)ival < 2) { 767195870Sjamie strlcpy(valbuf, bool_values[ival], 768194869Sjamie sizeof(valbuf)); 769194869Sjamie break; 770194869Sjamie } 771195870Sjamie if ((jp->jp_flags & JP_JAILSYS) && 772195870Sjamie (unsigned)ival < sizeof(jailsys_values) / 773195870Sjamie sizeof(jailsys_values[0])) { 774195870Sjamie strlcpy(valbuf, jailsys_values[ival], 775195870Sjamie sizeof(valbuf)); 776195870Sjamie break; 777195870Sjamie } 778195870Sjamie snprintf(valbuf, sizeof(valbuf), "%d", ival); 779194869Sjamie break; 780194869Sjamie case CTLTYPE_UINT: 781194869Sjamie snprintf(valbuf, sizeof(valbuf), "%u", 782194869Sjamie ((unsigned *)jp->jp_value)[i]); 783194869Sjamie break; 784194869Sjamie case CTLTYPE_LONG: 785194869Sjamie snprintf(valbuf, sizeof(valbuf), "%ld", 786194869Sjamie ((long *)jp->jp_value)[i]); 787194869Sjamie break; 788194869Sjamie case CTLTYPE_ULONG: 789194869Sjamie snprintf(valbuf, sizeof(valbuf), "%lu", 790194869Sjamie ((unsigned long *)jp->jp_value)[i]); 791194869Sjamie break; 792217616Smdf case CTLTYPE_S64: 793194869Sjamie snprintf(valbuf, sizeof(valbuf), "%jd", 794194869Sjamie (intmax_t)((int64_t *)jp->jp_value)[i]); 795194869Sjamie break; 796217616Smdf case CTLTYPE_U64: 797217616Smdf snprintf(valbuf, sizeof(valbuf), "%ju", 798217616Smdf (uintmax_t)((uint64_t *)jp->jp_value)[i]); 799217616Smdf break; 800194869Sjamie case CTLTYPE_STRUCT: 801194869Sjamie switch (jp->jp_structtype) { 802194869Sjamie case JPS_IN_ADDR: 803194869Sjamie if (inet_ntop(AF_INET, 804194869Sjamie &((struct in_addr *)jp->jp_value)[i], 805194869Sjamie valbuf, sizeof(valbuf)) == NULL) { 806194869Sjamie strerror_r(errno, jail_errmsg, 807194869Sjamie JAIL_ERRMSGLEN); 808194869Sjamie return (NULL); 809194869Sjamie } 810194869Sjamie break; 811194869Sjamie case JPS_IN6_ADDR: 812194869Sjamie if (inet_ntop(AF_INET6, 813194869Sjamie &((struct in6_addr *)jp->jp_value)[i], 814194869Sjamie valbuf, sizeof(valbuf)) == NULL) { 815194869Sjamie strerror_r(errno, jail_errmsg, 816194869Sjamie JAIL_ERRMSGLEN); 817194869Sjamie return (NULL); 818194869Sjamie } 819194869Sjamie break; 820194869Sjamie default: 821194869Sjamie goto unknown_type; 822194869Sjamie } 823194869Sjamie break; 824194869Sjamie default: 825194869Sjamie unknown_type: 826194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 827194869Sjamie "unknown type for %s", jp->jp_name); 828194869Sjamie errno = ENOENT; 829194869Sjamie return (NULL); 830194869Sjamie } 831212073Sjamie valuelens[i] = strlen(valbuf) + 1; 832212073Sjamie valuelen += valuelens[i]; 833212073Sjamie values[i] = alloca(valuelens[i]); 834194869Sjamie strcpy(values[i], valbuf); 835194869Sjamie } 836212073Sjamie value = malloc(valuelen); 837194869Sjamie if (value == NULL) 838194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 839194869Sjamie else { 840194869Sjamie tvalue = value; 841194869Sjamie for (i = 0; i < nval; i++) { 842194869Sjamie strcpy(tvalue, values[i]); 843194869Sjamie if (i < nval - 1) { 844212073Sjamie tvalue += valuelens[i]; 845212073Sjamie tvalue[-1] = ','; 846194869Sjamie } 847194869Sjamie } 848194869Sjamie } 849194869Sjamie return (value); 850194869Sjamie} 851194869Sjamie 852194869Sjamie/* 853212073Sjamie * Free the contents of a jail parameter list (but not the list itself). 854194869Sjamie */ 855194869Sjamievoid 856194869Sjamiejailparam_free(struct jailparam *jp, unsigned njp) 857194869Sjamie{ 858194869Sjamie unsigned j; 859194869Sjamie 860194869Sjamie for (j = 0; j < njp; j++) { 861194869Sjamie free(jp[j].jp_name); 862194869Sjamie if (!(jp[j].jp_flags & JP_RAWVALUE)) 863194869Sjamie free(jp[j].jp_value); 864194869Sjamie } 865194869Sjamie} 866194869Sjamie 867194869Sjamie/* 868194869Sjamie * Find a parameter's type and size from its MIB. 869194869Sjamie */ 870194869Sjamiestatic int 871194869Sjamiejailparam_type(struct jailparam *jp) 872194869Sjamie{ 873235799Sjamie char *p, *name, *nname; 874194869Sjamie size_t miblen, desclen; 875235291Sjamie int i, isarray; 876194869Sjamie struct { 877194869Sjamie int i; 878194869Sjamie char s[MAXPATHLEN]; 879194869Sjamie } desc; 880194869Sjamie int mib[CTL_MAXNAME]; 881194869Sjamie 882194869Sjamie /* The "lastjid" parameter isn't real. */ 883235799Sjamie name = jp->jp_name; 884235799Sjamie if (!strcmp(name, "lastjid")) { 885194869Sjamie jp->jp_valuelen = sizeof(int); 886194869Sjamie jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR; 887194869Sjamie return (0); 888194869Sjamie } 889194869Sjamie 890194869Sjamie /* Find the sysctl that describes the parameter. */ 891194869Sjamie mib[0] = 0; 892194869Sjamie mib[1] = 3; 893235799Sjamie snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 894194869Sjamie miblen = sizeof(mib) - 2 * sizeof(int); 895194869Sjamie if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) { 896194869Sjamie if (errno != ENOENT) { 897194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 898235799Sjamie "sysctl(0.3.%s): %s", name, strerror(errno)); 899194869Sjamie return (-1); 900194869Sjamie } 901337876Sjamie if (kldload_param(name) >= 0 && sysctl(mib, 2, mib + 2, &miblen, 902337876Sjamie desc.s, strlen(desc.s)) >= 0) 903337876Sjamie goto mib_desc; 904194869Sjamie /* 905194869Sjamie * The parameter probably doesn't exist. But it might be 906194869Sjamie * the "no" counterpart to a boolean. 907194869Sjamie */ 908235799Sjamie nname = nononame(name); 909232342Sjamie if (nname == NULL) { 910232342Sjamie unknown_parameter: 911232342Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 912232342Sjamie "unknown parameter: %s", jp->jp_name); 913232342Sjamie errno = ENOENT; 914232342Sjamie return (-1); 915194869Sjamie } 916235799Sjamie name = alloca(strlen(nname) + 1); 917235799Sjamie strcpy(name, nname); 918232342Sjamie free(nname); 919235799Sjamie snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 920232342Sjamie miblen = sizeof(mib) - 2 * sizeof(int); 921232342Sjamie if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 922232342Sjamie strlen(desc.s)) < 0) 923232342Sjamie goto unknown_parameter; 924232342Sjamie jp->jp_flags |= JP_NOBOOL; 925194869Sjamie } 926195870Sjamie mib_desc: 927194869Sjamie mib[1] = 4; 928194869Sjamie desclen = sizeof(desc); 929194869Sjamie if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, 930194869Sjamie NULL, 0) < 0) { 931194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 932235799Sjamie "sysctl(0.4.%s): %s", name, strerror(errno)); 933194869Sjamie return (-1); 934194869Sjamie } 935232342Sjamie jp->jp_ctltype = desc.i; 936232342Sjamie /* If this came from removing a "no", it better be a boolean. */ 937232342Sjamie if (jp->jp_flags & JP_NOBOOL) { 938232342Sjamie if ((desc.i & CTLTYPE) == CTLTYPE_INT && desc.s[0] == 'B') { 939232342Sjamie jp->jp_valuelen = sizeof(int); 940232342Sjamie return (0); 941232342Sjamie } 942232342Sjamie else if ((desc.i & CTLTYPE) != CTLTYPE_NODE) 943232342Sjamie goto unknown_parameter; 944232342Sjamie } 945194869Sjamie /* See if this is an array type. */ 946194869Sjamie p = strchr(desc.s, '\0'); 947194869Sjamie isarray = 0; 948194869Sjamie if (p - 2 < desc.s || strcmp(p - 2, ",a")) 949194869Sjamie isarray = 0; 950194869Sjamie else { 951194869Sjamie isarray = 1; 952194869Sjamie p[-2] = 0; 953194869Sjamie } 954212074Sjamie /* Look for types we understand. */ 955194869Sjamie switch (desc.i & CTLTYPE) { 956194869Sjamie case CTLTYPE_INT: 957194869Sjamie if (desc.s[0] == 'B') 958195870Sjamie jp->jp_flags |= JP_BOOL; 959195870Sjamie else if (!strcmp(desc.s, "E,jailsys")) 960195870Sjamie jp->jp_flags |= JP_JAILSYS; 961194869Sjamie case CTLTYPE_UINT: 962194869Sjamie jp->jp_valuelen = sizeof(int); 963194869Sjamie break; 964194869Sjamie case CTLTYPE_LONG: 965194869Sjamie case CTLTYPE_ULONG: 966194869Sjamie jp->jp_valuelen = sizeof(long); 967194869Sjamie break; 968217616Smdf case CTLTYPE_S64: 969217616Smdf case CTLTYPE_U64: 970194869Sjamie jp->jp_valuelen = sizeof(int64_t); 971194869Sjamie break; 972194869Sjamie case CTLTYPE_STRING: 973194869Sjamie desc.s[0] = 0; 974194869Sjamie desclen = sizeof(desc.s); 975194869Sjamie if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen, 976194869Sjamie NULL, 0) < 0) { 977194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 978235799Sjamie "sysctl(" SJPARAM ".%s): %s", name, 979194869Sjamie strerror(errno)); 980194869Sjamie return (-1); 981194869Sjamie } 982194869Sjamie jp->jp_valuelen = strtoul(desc.s, NULL, 10); 983194869Sjamie break; 984194869Sjamie case CTLTYPE_STRUCT: 985194869Sjamie if (!strcmp(desc.s, "S,in_addr")) { 986194869Sjamie jp->jp_structtype = JPS_IN_ADDR; 987194869Sjamie jp->jp_valuelen = sizeof(struct in_addr); 988194869Sjamie } else if (!strcmp(desc.s, "S,in6_addr")) { 989194869Sjamie jp->jp_structtype = JPS_IN6_ADDR; 990194869Sjamie jp->jp_valuelen = sizeof(struct in6_addr); 991194869Sjamie } else { 992194869Sjamie desclen = 0; 993194869Sjamie if (sysctl(mib + 2, miblen / sizeof(int), 994194869Sjamie NULL, &jp->jp_valuelen, NULL, 0) < 0) { 995194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 996235799Sjamie "sysctl(" SJPARAM ".%s): %s", name, 997194869Sjamie strerror(errno)); 998194869Sjamie return (-1); 999194869Sjamie } 1000194869Sjamie } 1001194869Sjamie break; 1002194869Sjamie case CTLTYPE_NODE: 1003235291Sjamie /* 1004235291Sjamie * A node might be described by an empty-named child, 1005235291Sjamie * which would be immediately before or after the node itself. 1006235291Sjamie */ 1007195870Sjamie mib[1] = 1; 1008195870Sjamie miblen += sizeof(int); 1009235291Sjamie for (i = -1; i <= 1; i += 2) { 1010235291Sjamie mib[(miblen / sizeof(int)) + 1] = 1011235291Sjamie mib[(miblen / sizeof(int))] + i; 1012235291Sjamie desclen = sizeof(desc.s); 1013235291Sjamie if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, 1014235291Sjamie &desclen, NULL, 0) < 0) { 1015235291Sjamie if (errno == ENOENT) 1016235291Sjamie continue; 1017235291Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1018235291Sjamie "sysctl(0.1): %s", strerror(errno)); 1019235291Sjamie return (-1); 1020235291Sjamie } 1021235799Sjamie if (desclen == sizeof(SJPARAM) + strlen(name) + 2 && 1022235291Sjamie memcmp(SJPARAM ".", desc.s, sizeof(SJPARAM)) == 0 && 1023235799Sjamie memcmp(name, desc.s + sizeof(SJPARAM), 1024235291Sjamie desclen - sizeof(SJPARAM) - 2) == 0 && 1025235291Sjamie desc.s[desclen - 2] == '.') 1026235291Sjamie goto mib_desc; 1027194869Sjamie } 1028235291Sjamie goto unknown_parameter; 1029194869Sjamie default: 1030194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1031194869Sjamie "unknown type for %s", jp->jp_name); 1032194869Sjamie errno = ENOENT; 1033194869Sjamie return (-1); 1034194869Sjamie } 1035194869Sjamie if (isarray) { 1036194869Sjamie jp->jp_elemlen = jp->jp_valuelen; 1037194869Sjamie jp->jp_valuelen = 0; 1038194869Sjamie } 1039194869Sjamie return (0); 1040194869Sjamie} 1041194869Sjamie 1042194869Sjamie/* 1043337876Sjamie * Attempt to load a kernel module matching an otherwise nonexistent parameter. 1044337876Sjamie */ 1045337876Sjamiestatic int 1046337876Sjamiekldload_param(const char *name) 1047337876Sjamie{ 1048337876Sjamie int kl; 1049337876Sjamie 1050337876Sjamie if (strcmp(name, "linux") == 0 || strncmp(name, "linux.", 6) == 0) 1051337876Sjamie kl = kldload("linux"); 1052337876Sjamie else if (strcmp(name, "sysvmsg") == 0 || strcmp(name, "sysvsem") == 0 || 1053337876Sjamie strcmp(name, "sysvshm") == 0) 1054337876Sjamie kl = kldload(name); 1055337876Sjamie else { 1056337876Sjamie errno = ENOENT; 1057337876Sjamie return (-1); 1058337876Sjamie } 1059337876Sjamie if (kl < 0 && errno == EEXIST) { 1060337876Sjamie /* 1061337876Sjamie * In the module is already loaded, then it must not contain 1062337876Sjamie * the parameter. 1063337876Sjamie */ 1064337876Sjamie errno = ENOENT; 1065337876Sjamie } 1066337876Sjamie return kl; 1067337876Sjamie} 1068337876Sjamie 1069337876Sjamie/* 1070194869Sjamie * Change a boolean parameter name into its "no" counterpart or vice versa. 1071194869Sjamie */ 1072194869Sjamiestatic char * 1073194869Sjamienoname(const char *name) 1074194869Sjamie{ 1075194869Sjamie char *nname, *p; 1076194869Sjamie 1077194869Sjamie nname = malloc(strlen(name) + 3); 1078194869Sjamie if (nname == NULL) { 1079194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1080194869Sjamie return (NULL); 1081194869Sjamie } 1082194869Sjamie p = strrchr(name, '.'); 1083194869Sjamie if (p != NULL) 1084194869Sjamie sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 1085194869Sjamie else 1086194869Sjamie sprintf(nname, "no%s", name); 1087194869Sjamie return (nname); 1088194869Sjamie} 1089194869Sjamie 1090194869Sjamiestatic char * 1091194869Sjamienononame(const char *name) 1092194869Sjamie{ 1093194869Sjamie char *p, *nname; 1094194869Sjamie 1095194869Sjamie p = strrchr(name, '.'); 1096194869Sjamie if (strncmp(p ? p + 1 : name, "no", 2)) { 1097194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), 1098194869Sjamie "mismatched boolean: %s", name); 1099194869Sjamie errno = EINVAL; 1100194869Sjamie return (NULL); 1101194869Sjamie } 1102194869Sjamie nname = malloc(strlen(name) - 1); 1103194869Sjamie if (nname == NULL) { 1104194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1105194869Sjamie return (NULL); 1106194869Sjamie } 1107194869Sjamie if (p != NULL) 1108194869Sjamie sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 1109194869Sjamie else 1110194869Sjamie strcpy(nname, name + 2); 1111194869Sjamie return (nname); 1112194869Sjamie} 1113