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: releng/10.3/lib/libjail/jail.c 241197 2012-10-04 19:07:05Z jamie $"); 29194869Sjamie 30194869Sjamie#include <sys/param.h> 31194869Sjamie#include <sys/types.h> 32194869Sjamie#include <sys/jail.h> 33194869Sjamie#include <sys/socket.h> 34194869Sjamie#include <sys/sysctl.h> 35194869Sjamie 36194869Sjamie#include <arpa/inet.h> 37194869Sjamie#include <netinet/in.h> 38194869Sjamie 39194869Sjamie#include <errno.h> 40194869Sjamie#include <inttypes.h> 41194869Sjamie#include <stdio.h> 42194869Sjamie#include <stdarg.h> 43194869Sjamie#include <stdlib.h> 44194869Sjamie#include <string.h> 45194869Sjamie 46194869Sjamie#include "jail.h" 47194869Sjamie 48194869Sjamie#define SJPARAM "security.jail.param" 49194869Sjamie 50194869Sjamie#define JPS_IN_ADDR 1 51194869Sjamie#define JPS_IN6_ADDR 2 52194869Sjamie 53194869Sjamie#define ARRAY_SANITY 5 54194869Sjamie#define ARRAY_SLOP 5 55194869Sjamie 56194869Sjamie 57195870Sjamiestatic int jailparam_import_enum(const char **values, int nvalues, 58195870Sjamie const char *valstr, size_t valsize, int *value); 59194869Sjamiestatic int jailparam_type(struct jailparam *jp); 60194869Sjamiestatic char *noname(const char *name); 61194869Sjamiestatic char *nononame(const char *name); 62194869Sjamie 63194869Sjamiechar jail_errmsg[JAIL_ERRMSGLEN]; 64194869Sjamie 65195870Sjamiestatic const char *bool_values[] = { "false", "true" }; 66195870Sjamiestatic const char *jailsys_values[] = { "disable", "new", "inherit" }; 67194869Sjamie 68195870Sjamie 69194869Sjamie/* 70194869Sjamie * Import a null-terminated parameter list and set a jail with the flags 71194869Sjamie * and parameters. 72194869Sjamie */ 73194869Sjamieint 74194869Sjamiejail_setv(int flags, ...) 75194869Sjamie{ 76210133Sjamie va_list ap, tap; 77194869Sjamie struct jailparam *jp; 78210133Sjamie const char *name, *value; 79210133Sjamie int njp, jid; 80194869Sjamie 81210133Sjamie /* Create the parameter list and import the parameters. */ 82194869Sjamie va_start(ap, flags); 83210133Sjamie va_copy(tap, ap); 84210133Sjamie for (njp = 0; va_arg(tap, char *) != NULL; njp++) 85210133Sjamie (void)va_arg(tap, char *); 86210133Sjamie va_end(tap); 87210133Sjamie jp = alloca(njp * sizeof(struct jailparam)); 88241197Sjamie for (njp = 0; (name = va_arg(ap, char *)) != NULL;) { 89210133Sjamie value = va_arg(ap, char *); 90241197Sjamie if (jailparam_init(jp + njp, name) < 0) 91241197Sjamie goto error; 92241197Sjamie if (jailparam_import(jp + njp++, value) < 0) 93241197Sjamie goto error; 94210133Sjamie } 95194869Sjamie va_end(ap); 96210133Sjamie jid = jailparam_set(jp, njp, flags); 97210133Sjamie jailparam_free(jp, njp); 98210133Sjamie return (jid); 99241197Sjamie 100241197Sjamie error: 101241197Sjamie jailparam_free(jp, njp); 102241197Sjamie va_end(ap); 103241197Sjamie return (-1); 104194869Sjamie} 105194869Sjamie 106194869Sjamie/* 107194869Sjamie * Read a null-terminated parameter list, get the referenced jail, and export 108194869Sjamie * the parameters to the list. 109194869Sjamie */ 110194869Sjamieint 111194869Sjamiejail_getv(int flags, ...) 112194869Sjamie{ 113194869Sjamie va_list ap, tap; 114210133Sjamie struct jailparam *jp, *jp_lastjid, *jp_jid, *jp_name, *jp_key; 115210133Sjamie char *valarg, *value; 116210133Sjamie const char *name, *key_value, *lastjid_value, *jid_value, *name_value; 117210133Sjamie int njp, i, jid; 118194869Sjamie 119210133Sjamie /* Create the parameter list and find the key. */ 120194869Sjamie va_start(ap, flags); 121194869Sjamie va_copy(tap, ap); 122210133Sjamie for (njp = 0; va_arg(tap, char *) != NULL; njp++) 123210133Sjamie (void)va_arg(tap, char *); 124194869Sjamie va_end(tap); 125210133Sjamie 126210133Sjamie jp = alloca(njp * sizeof(struct jailparam)); 127210133Sjamie va_copy(tap, ap); 128210133Sjamie jp_lastjid = jp_jid = jp_name = NULL; 129210133Sjamie lastjid_value = jid_value = name_value = NULL; 130210133Sjamie for (njp = 0; (name = va_arg(tap, char *)) != NULL; njp++) { 131210133Sjamie value = va_arg(tap, char *); 132210133Sjamie if (jailparam_init(jp + njp, name) < 0) { 133210133Sjamie va_end(tap); 134210133Sjamie goto error; 135210133Sjamie } 136210133Sjamie if (!strcmp(jp[njp].jp_name, "lastjid")) { 137210133Sjamie jp_lastjid = jp + njp; 138210133Sjamie lastjid_value = value; 139210133Sjamie } else if (!strcmp(jp[njp].jp_name, "jid")) { 140210133Sjamie jp_jid = jp + njp; 141210133Sjamie jid_value = value; 142210133Sjamie } if (!strcmp(jp[njp].jp_name, "name")) { 143210133Sjamie jp_name = jp + njp; 144210133Sjamie name_value = value; 145210133Sjamie } 146194869Sjamie } 147210133Sjamie va_end(tap); 148210133Sjamie /* Import the key parameter. */ 149210133Sjamie if (jp_lastjid != NULL) { 150210133Sjamie jp_key = jp_lastjid; 151210133Sjamie key_value = lastjid_value; 152210133Sjamie } else if (jp_jid != NULL && strtol(jid_value, NULL, 10) != 0) { 153210133Sjamie jp_key = jp_jid; 154210133Sjamie key_value = jid_value; 155210133Sjamie } else if (jp_name != NULL) { 156210133Sjamie jp_key = jp_name; 157210133Sjamie key_value = name_value; 158210133Sjamie } else { 159210133Sjamie strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 160210133Sjamie errno = ENOENT; 161210133Sjamie goto error; 162210133Sjamie } 163210133Sjamie if (jailparam_import(jp_key, key_value) < 0) 164210133Sjamie goto error; 165210133Sjamie /* Get the jail and export the parameters. */ 166194869Sjamie jid = jailparam_get(jp, njp, flags); 167210133Sjamie if (jid < 0) 168210133Sjamie goto error; 169194869Sjamie for (i = 0; i < njp; i++) { 170194869Sjamie (void)va_arg(ap, char *); 171194869Sjamie valarg = va_arg(ap, char *); 172210133Sjamie if (jp + i != jp_key) { 173194869Sjamie /* It's up to the caller to ensure there's room. */ 174210133Sjamie if ((jp[i].jp_ctltype & CTLTYPE) == CTLTYPE_STRING) 175210133Sjamie strcpy(valarg, jp[i].jp_value); 176210133Sjamie else { 177210133Sjamie value = jailparam_export(jp + i); 178210133Sjamie if (value == NULL) 179210133Sjamie goto error; 180210133Sjamie strcpy(valarg, value); 181210133Sjamie free(value); 182210133Sjamie } 183210133Sjamie } 184194869Sjamie } 185210133Sjamie jailparam_free(jp, njp); 186194869Sjamie va_end(ap); 187194869Sjamie return (jid); 188210133Sjamie 189210133Sjamie error: 190210133Sjamie jailparam_free(jp, njp); 191210133Sjamie va_end(ap); 192210133Sjamie return (-1); 193194869Sjamie} 194194869Sjamie 195194869Sjamie/* 196194869Sjamie * Return a list of all known parameters. 197194869Sjamie */ 198194869Sjamieint 199194869Sjamiejailparam_all(struct jailparam **jpp) 200194869Sjamie{ 201241197Sjamie struct jailparam *jp, *tjp; 202194869Sjamie size_t mlen1, mlen2, buflen; 203194869Sjamie int njp, nlist; 204194869Sjamie int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; 205194869Sjamie char buf[MAXPATHLEN]; 206194869Sjamie 207194869Sjamie njp = 0; 208194869Sjamie nlist = 32; 209194869Sjamie jp = malloc(nlist * sizeof(*jp)); 210194869Sjamie if (jp == NULL) { 211194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 212194869Sjamie return (-1); 213194869Sjamie } 214194869Sjamie mib1[0] = 0; 215194869Sjamie mib1[1] = 2; 216194869Sjamie mlen1 = CTL_MAXNAME - 2; 217194869Sjamie if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) { 218194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 219194869Sjamie "sysctlnametomib(" SJPARAM "): %s", strerror(errno)); 220194869Sjamie goto error; 221194869Sjamie } 222194869Sjamie for (;; njp++) { 223194869Sjamie /* Get the next parameter. */ 224194869Sjamie mlen2 = sizeof(mib2); 225194869Sjamie if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) { 226194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 227194869Sjamie "sysctl(0.2): %s", strerror(errno)); 228194869Sjamie goto error; 229194869Sjamie } 230194869Sjamie if (mib2[0] != mib1[2] || mib2[1] != mib1[3] || 231194869Sjamie mib2[2] != mib1[4]) 232194869Sjamie break; 233194869Sjamie /* Convert it to an ascii name. */ 234194869Sjamie memcpy(mib1 + 2, mib2, mlen2); 235194869Sjamie mlen1 = mlen2 / sizeof(int); 236194869Sjamie mib1[1] = 1; 237194869Sjamie buflen = sizeof(buf); 238194869Sjamie if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) { 239194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 240194869Sjamie "sysctl(0.1): %s", strerror(errno)); 241194869Sjamie goto error; 242194869Sjamie } 243195870Sjamie if (buf[buflen - 2] == '.') 244195870Sjamie buf[buflen - 2] = '\0'; 245194869Sjamie /* Add the parameter to the list */ 246194869Sjamie if (njp >= nlist) { 247194869Sjamie nlist *= 2; 248241197Sjamie tjp = realloc(jp, nlist * sizeof(*jp)); 249241197Sjamie if (tjp == NULL) 250241197Sjamie goto error; 251241197Sjamie jp = tjp; 252194869Sjamie } 253194869Sjamie if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0) 254194869Sjamie goto error; 255194869Sjamie mib1[1] = 2; 256194869Sjamie } 257194869Sjamie jp = realloc(jp, njp * sizeof(*jp)); 258194869Sjamie *jpp = jp; 259194869Sjamie return (njp); 260194869Sjamie 261194869Sjamie error: 262194869Sjamie jailparam_free(jp, njp); 263194869Sjamie free(jp); 264194869Sjamie return (-1); 265194869Sjamie} 266194869Sjamie 267194869Sjamie/* 268194869Sjamie * Clear a jail parameter and copy in its name. 269194869Sjamie */ 270194869Sjamieint 271194869Sjamiejailparam_init(struct jailparam *jp, const char *name) 272194869Sjamie{ 273194869Sjamie 274194869Sjamie memset(jp, 0, sizeof(*jp)); 275194869Sjamie jp->jp_name = strdup(name); 276194869Sjamie if (jp->jp_name == NULL) { 277194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 278194869Sjamie return (-1); 279194869Sjamie } 280214434Sjamie if (jailparam_type(jp) < 0) { 281214434Sjamie jailparam_free(jp, 1); 282241197Sjamie jp->jp_name = NULL; 283241197Sjamie jp->jp_value = NULL; 284214434Sjamie return (-1); 285214434Sjamie } 286194869Sjamie return (0); 287194869Sjamie} 288194869Sjamie 289194869Sjamie/* 290194869Sjamie * Put a name and value into a jail parameter element, converting the value 291194869Sjamie * to internal form. 292194869Sjamie */ 293194869Sjamieint 294194869Sjamiejailparam_import(struct jailparam *jp, const char *value) 295194869Sjamie{ 296194869Sjamie char *p, *ep, *tvalue; 297194869Sjamie const char *avalue; 298194869Sjamie int i, nval, fw; 299194869Sjamie 300194869Sjamie if (value == NULL) 301194869Sjamie return (0); 302194869Sjamie if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 303194869Sjamie jp->jp_value = strdup(value); 304195011Sjamie if (jp->jp_value == NULL) { 305194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 306195011Sjamie return (-1); 307194869Sjamie } 308194869Sjamie return (0); 309194869Sjamie } 310194869Sjamie nval = 1; 311194869Sjamie if (jp->jp_elemlen) { 312194869Sjamie if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) { 313194869Sjamie jp->jp_value = strdup(""); 314195011Sjamie if (jp->jp_value == NULL) { 315194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 316195011Sjamie return (-1); 317194869Sjamie } 318194869Sjamie jp->jp_valuelen = 0; 319194869Sjamie return (0); 320194869Sjamie } 321194869Sjamie for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) 322194869Sjamie nval++; 323194869Sjamie jp->jp_valuelen = jp->jp_elemlen * nval; 324194869Sjamie } 325194869Sjamie jp->jp_value = malloc(jp->jp_valuelen); 326195011Sjamie if (jp->jp_value == NULL) { 327194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 328195011Sjamie return (-1); 329194869Sjamie } 330194869Sjamie avalue = value; 331194869Sjamie for (i = 0; i < nval; i++) { 332194869Sjamie fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ","); 333194869Sjamie switch (jp->jp_ctltype & CTLTYPE) { 334194869Sjamie case CTLTYPE_INT: 335194869Sjamie if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { 336195870Sjamie if (!jailparam_import_enum(bool_values, 2, 337195870Sjamie avalue, fw, &((int *)jp->jp_value)[i])) { 338194869Sjamie snprintf(jail_errmsg, 339195870Sjamie JAIL_ERRMSGLEN, "%s: " 340195870Sjamie "unknown boolean value \"%.*s\"", 341194869Sjamie jp->jp_name, fw, avalue); 342194869Sjamie errno = EINVAL; 343194869Sjamie goto error; 344194869Sjamie } 345194869Sjamie break; 346194869Sjamie } 347195870Sjamie if (jp->jp_flags & JP_JAILSYS) { 348195870Sjamie /* 349195870Sjamie * Allow setting a jailsys parameter to "new" 350195870Sjamie * in a booleanesque fashion. 351195870Sjamie */ 352195870Sjamie if (value[0] == '\0') 353195870Sjamie ((int *)jp->jp_value)[i] = JAIL_SYS_NEW; 354195870Sjamie else if (!jailparam_import_enum(jailsys_values, 355195870Sjamie sizeof(jailsys_values) / 356195870Sjamie sizeof(jailsys_values[0]), avalue, fw, 357195870Sjamie &((int *)jp->jp_value)[i])) { 358195870Sjamie snprintf(jail_errmsg, 359195870Sjamie JAIL_ERRMSGLEN, "%s: " 360195870Sjamie "unknown jailsys value \"%.*s\"", 361195870Sjamie jp->jp_name, fw, avalue); 362195870Sjamie errno = EINVAL; 363195870Sjamie goto error; 364195870Sjamie } 365195870Sjamie break; 366195870Sjamie } 367194869Sjamie ((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 368194869Sjamie integer_test: 369194869Sjamie if (ep != avalue + fw) { 370194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 371194869Sjamie "%s: non-integer value \"%.*s\"", 372194869Sjamie jp->jp_name, fw, avalue); 373194869Sjamie errno = EINVAL; 374194869Sjamie goto error; 375194869Sjamie } 376194869Sjamie break; 377194869Sjamie case CTLTYPE_UINT: 378194869Sjamie ((unsigned *)jp->jp_value)[i] = 379194869Sjamie strtoul(avalue, &ep, 10); 380194869Sjamie goto integer_test; 381194869Sjamie case CTLTYPE_LONG: 382194869Sjamie ((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 383194869Sjamie goto integer_test; 384194869Sjamie case CTLTYPE_ULONG: 385194869Sjamie ((unsigned long *)jp->jp_value)[i] = 386194869Sjamie strtoul(avalue, &ep, 10); 387194869Sjamie goto integer_test; 388217616Smdf case CTLTYPE_S64: 389194869Sjamie ((int64_t *)jp->jp_value)[i] = 390194869Sjamie strtoimax(avalue, &ep, 10); 391194869Sjamie goto integer_test; 392217616Smdf case CTLTYPE_U64: 393217616Smdf ((uint64_t *)jp->jp_value)[i] = 394217616Smdf strtoumax(avalue, &ep, 10); 395217616Smdf goto integer_test; 396194869Sjamie case CTLTYPE_STRUCT: 397194869Sjamie tvalue = alloca(fw + 1); 398194869Sjamie strlcpy(tvalue, avalue, fw + 1); 399194869Sjamie switch (jp->jp_structtype) { 400194869Sjamie case JPS_IN_ADDR: 401194869Sjamie if (inet_pton(AF_INET, tvalue, 402194869Sjamie &((struct in_addr *)jp->jp_value)[i]) != 1) 403194869Sjamie { 404194869Sjamie snprintf(jail_errmsg, 405194869Sjamie JAIL_ERRMSGLEN, 406194869Sjamie "%s: not an IPv4 address: %s", 407194869Sjamie jp->jp_name, tvalue); 408194869Sjamie errno = EINVAL; 409194869Sjamie goto error; 410194869Sjamie } 411194869Sjamie break; 412194869Sjamie case JPS_IN6_ADDR: 413194869Sjamie if (inet_pton(AF_INET6, tvalue, 414194869Sjamie &((struct in6_addr *)jp->jp_value)[i]) != 1) 415194869Sjamie { 416194869Sjamie snprintf(jail_errmsg, 417194869Sjamie JAIL_ERRMSGLEN, 418194869Sjamie "%s: not an IPv6 address: %s", 419194869Sjamie jp->jp_name, tvalue); 420194869Sjamie errno = EINVAL; 421194869Sjamie goto error; 422194869Sjamie } 423194869Sjamie break; 424194869Sjamie default: 425194869Sjamie goto unknown_type; 426194869Sjamie } 427194869Sjamie break; 428194869Sjamie default: 429194869Sjamie unknown_type: 430194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 431194869Sjamie "unknown type for %s", jp->jp_name); 432194869Sjamie errno = ENOENT; 433194869Sjamie goto error; 434194869Sjamie } 435194869Sjamie avalue += fw + 1; 436194869Sjamie } 437194869Sjamie return (0); 438194869Sjamie 439194869Sjamie error: 440194869Sjamie free(jp->jp_value); 441194869Sjamie jp->jp_value = NULL; 442194869Sjamie return (-1); 443194869Sjamie} 444194869Sjamie 445195870Sjamiestatic int 446195870Sjamiejailparam_import_enum(const char **values, int nvalues, const char *valstr, 447195870Sjamie size_t valsize, int *value) 448195870Sjamie{ 449195870Sjamie char *ep; 450195870Sjamie int i; 451195870Sjamie 452195870Sjamie for (i = 0; i < nvalues; i++) 453195870Sjamie if (valsize == strlen(values[i]) && 454195870Sjamie !strncasecmp(valstr, values[i], valsize)) { 455195870Sjamie *value = i; 456195870Sjamie return 1; 457195870Sjamie } 458195870Sjamie *value = strtol(valstr, &ep, 10); 459195870Sjamie return (ep == valstr + valsize); 460195870Sjamie} 461195870Sjamie 462194869Sjamie/* 463194869Sjamie * Put a name and value into a jail parameter element, copying the value 464194869Sjamie * but not altering it. 465194869Sjamie */ 466194869Sjamieint 467194869Sjamiejailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen) 468194869Sjamie{ 469194869Sjamie 470194869Sjamie jp->jp_value = value; 471194869Sjamie jp->jp_valuelen = valuelen; 472194869Sjamie jp->jp_flags |= JP_RAWVALUE; 473194869Sjamie return (0); 474194869Sjamie} 475194869Sjamie 476194869Sjamie/* 477194869Sjamie * Run the jail_set and jail_get system calls on a parameter list. 478194869Sjamie */ 479194869Sjamieint 480194869Sjamiejailparam_set(struct jailparam *jp, unsigned njp, int flags) 481194869Sjamie{ 482194869Sjamie struct iovec *jiov; 483194869Sjamie char *nname; 484195011Sjamie int i, jid, bool0; 485194869Sjamie unsigned j; 486194869Sjamie 487194869Sjamie jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 488195011Sjamie bool0 = 0; 489194869Sjamie for (i = j = 0; j < njp; j++) { 490194869Sjamie jiov[i].iov_base = jp[j].jp_name; 491194869Sjamie jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 492194869Sjamie i++; 493194869Sjamie if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) { 494194869Sjamie /* 495195011Sjamie * Set booleans without values. If one has a value of 496194869Sjamie * zero, change it to (or from) its "no" counterpart. 497194869Sjamie */ 498194869Sjamie jiov[i].iov_base = NULL; 499194869Sjamie jiov[i].iov_len = 0; 500194869Sjamie if (jp[j].jp_value != NULL && 501194869Sjamie jp[j].jp_valuelen == sizeof(int) && 502194869Sjamie !*(int *)jp[j].jp_value) { 503195011Sjamie bool0 = 1; 504194869Sjamie nname = jp[j].jp_flags & JP_BOOL 505195011Sjamie ? noname(jp[j].jp_name) 506195011Sjamie : nononame(jp[j].jp_name); 507195011Sjamie if (nname == NULL) { 508195011Sjamie njp = j; 509195011Sjamie jid = -1; 510195011Sjamie goto done; 511195011Sjamie } 512195011Sjamie jiov[i - 1].iov_base = nname; 513195011Sjamie jiov[i - 1].iov_len = strlen(nname) + 1; 514195011Sjamie 515194869Sjamie } 516194869Sjamie } else { 517195870Sjamie /* 518195870Sjamie * Try to fill in missing values with an empty string. 519195870Sjamie */ 520195870Sjamie if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 && 521195870Sjamie jailparam_import(jp + j, "") < 0) { 522195870Sjamie njp = j; 523195870Sjamie jid = -1; 524195870Sjamie goto done; 525195870Sjamie } 526194869Sjamie jiov[i].iov_base = jp[j].jp_value; 527194869Sjamie jiov[i].iov_len = 528194869Sjamie (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING 529194869Sjamie ? strlen(jp[j].jp_value) + 1 530194869Sjamie : jp[j].jp_valuelen; 531194869Sjamie } 532194869Sjamie i++; 533194869Sjamie } 534194869Sjamie *(const void **)&jiov[i].iov_base = "errmsg"; 535194869Sjamie jiov[i].iov_len = sizeof("errmsg"); 536194869Sjamie i++; 537194869Sjamie jiov[i].iov_base = jail_errmsg; 538194869Sjamie jiov[i].iov_len = JAIL_ERRMSGLEN; 539194869Sjamie i++; 540194869Sjamie jail_errmsg[0] = 0; 541194869Sjamie jid = jail_set(jiov, i, flags); 542194869Sjamie if (jid < 0 && !jail_errmsg[0]) 543194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s", 544194869Sjamie strerror(errno)); 545195011Sjamie done: 546195011Sjamie if (bool0) 547195011Sjamie for (j = 0; j < njp; j++) 548195011Sjamie if ((jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) && 549195011Sjamie jp[j].jp_value != NULL && 550195011Sjamie jp[j].jp_valuelen == sizeof(int) && 551195011Sjamie !*(int *)jp[j].jp_value) 552195011Sjamie free(jiov[j * 2].iov_base); 553194869Sjamie return (jid); 554194869Sjamie} 555194869Sjamie 556194869Sjamieint 557194869Sjamiejailparam_get(struct jailparam *jp, unsigned njp, int flags) 558194869Sjamie{ 559194869Sjamie struct iovec *jiov; 560194869Sjamie struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key; 561194869Sjamie int i, ai, ki, jid, arrays, sanity; 562194869Sjamie unsigned j; 563194869Sjamie 564195011Sjamie /* 565195011Sjamie * Get the types for all parameters. 566195011Sjamie * Find the key and any array parameters. 567195011Sjamie */ 568194869Sjamie jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 569194869Sjamie jp_lastjid = jp_jid = jp_name = NULL; 570194869Sjamie arrays = 0; 571194869Sjamie for (ai = j = 0; j < njp; j++) { 572194869Sjamie if (!strcmp(jp[j].jp_name, "lastjid")) 573194869Sjamie jp_lastjid = jp + j; 574194869Sjamie else if (!strcmp(jp[j].jp_name, "jid")) 575194869Sjamie jp_jid = jp + j; 576194869Sjamie else if (!strcmp(jp[j].jp_name, "name")) 577194869Sjamie jp_name = jp + j; 578194869Sjamie else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 579194869Sjamie arrays = 1; 580194869Sjamie jiov[ai].iov_base = jp[j].jp_name; 581194869Sjamie jiov[ai].iov_len = strlen(jp[j].jp_name) + 1; 582194869Sjamie ai++; 583194869Sjamie jiov[ai].iov_base = NULL; 584194869Sjamie jiov[ai].iov_len = 0; 585194869Sjamie ai++; 586194869Sjamie } 587194869Sjamie } 588194869Sjamie jp_key = jp_lastjid ? jp_lastjid : 589194869Sjamie jp_jid && jp_jid->jp_valuelen == sizeof(int) && 590200623Sjamie jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name; 591194869Sjamie if (jp_key == NULL || jp_key->jp_value == NULL) { 592194869Sjamie strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 593194869Sjamie errno = ENOENT; 594194869Sjamie return (-1); 595194869Sjamie } 596194869Sjamie ki = ai; 597194869Sjamie jiov[ki].iov_base = jp_key->jp_name; 598194869Sjamie jiov[ki].iov_len = strlen(jp_key->jp_name) + 1; 599194869Sjamie ki++; 600194869Sjamie jiov[ki].iov_base = jp_key->jp_value; 601194869Sjamie jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING 602194869Sjamie ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen; 603194869Sjamie ki++; 604194869Sjamie *(const void **)&jiov[ki].iov_base = "errmsg"; 605194869Sjamie jiov[ki].iov_len = sizeof("errmsg"); 606194869Sjamie ki++; 607194869Sjamie jiov[ki].iov_base = jail_errmsg; 608194869Sjamie jiov[ki].iov_len = JAIL_ERRMSGLEN; 609194869Sjamie ki++; 610194869Sjamie jail_errmsg[0] = 0; 611194869Sjamie if (arrays && jail_get(jiov, ki, flags) < 0) { 612194869Sjamie if (!jail_errmsg[0]) 613194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), 614194869Sjamie "jail_get: %s", strerror(errno)); 615194869Sjamie return (-1); 616194869Sjamie } 617194869Sjamie /* Allocate storage for all parameters. */ 618194869Sjamie for (ai = j = 0, i = ki; j < njp; j++) { 619194869Sjamie if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 620194869Sjamie ai++; 621194869Sjamie jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP; 622195011Sjamie if (jp[j].jp_valuelen >= jiov[ai].iov_len) 623195011Sjamie jiov[ai].iov_len = jp[j].jp_valuelen; 624195011Sjamie else { 625195011Sjamie jp[j].jp_valuelen = jiov[ai].iov_len; 626195011Sjamie if (jp[j].jp_value != NULL) 627195011Sjamie free(jp[j].jp_value); 628195011Sjamie jp[j].jp_value = malloc(jp[j].jp_valuelen); 629195011Sjamie if (jp[j].jp_value == NULL) { 630195011Sjamie strerror_r(errno, jail_errmsg, 631195011Sjamie JAIL_ERRMSGLEN); 632195011Sjamie return (-1); 633195011Sjamie } 634194869Sjamie } 635195011Sjamie jiov[ai].iov_base = jp[j].jp_value; 636194869Sjamie memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 637194869Sjamie ai++; 638194869Sjamie } else if (jp + j != jp_key) { 639194869Sjamie jiov[i].iov_base = jp[j].jp_name; 640194869Sjamie jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 641194869Sjamie i++; 642195011Sjamie if (jp[j].jp_value == NULL && 643195011Sjamie !(jp[j].jp_flags & JP_RAWVALUE)) { 644195011Sjamie jp[j].jp_value = malloc(jp[j].jp_valuelen); 645195011Sjamie if (jp[j].jp_value == NULL) { 646195011Sjamie strerror_r(errno, jail_errmsg, 647195011Sjamie JAIL_ERRMSGLEN); 648195011Sjamie return (-1); 649195011Sjamie } 650194869Sjamie } 651195011Sjamie jiov[i].iov_base = jp[j].jp_value; 652194869Sjamie jiov[i].iov_len = jp[j].jp_valuelen; 653194869Sjamie memset(jiov[i].iov_base, 0, jiov[i].iov_len); 654194869Sjamie i++; 655194869Sjamie } 656194869Sjamie } 657194869Sjamie /* 658194869Sjamie * Get the prison. If there are array elements, retry a few times 659194869Sjamie * in case their sizes changed from under us. 660194869Sjamie */ 661194869Sjamie for (sanity = 0;; sanity++) { 662194869Sjamie jid = jail_get(jiov, i, flags); 663194869Sjamie if (jid >= 0 || !arrays || sanity == ARRAY_SANITY || 664194869Sjamie errno != EINVAL || jail_errmsg[0]) 665194869Sjamie break; 666194869Sjamie for (ai = j = 0; j < njp; j++) { 667194869Sjamie if (jp[j].jp_elemlen && 668194869Sjamie !(jp[j].jp_flags & JP_RAWVALUE)) { 669194869Sjamie ai++; 670195011Sjamie jiov[ai].iov_base = NULL; 671194869Sjamie jiov[ai].iov_len = 0; 672194869Sjamie ai++; 673194869Sjamie } 674194869Sjamie } 675194869Sjamie if (jail_get(jiov, ki, flags) < 0) 676194869Sjamie break; 677194869Sjamie for (ai = j = 0; j < njp; j++) { 678194869Sjamie if (jp[j].jp_elemlen && 679194869Sjamie !(jp[j].jp_flags & JP_RAWVALUE)) { 680194869Sjamie ai++; 681194869Sjamie jiov[ai].iov_len += 682194869Sjamie jp[j].jp_elemlen * ARRAY_SLOP; 683195011Sjamie if (jp[j].jp_valuelen >= jiov[ai].iov_len) 684195011Sjamie jiov[ai].iov_len = jp[j].jp_valuelen; 685195011Sjamie else { 686195011Sjamie jp[j].jp_valuelen = jiov[ai].iov_len; 687195011Sjamie if (jp[j].jp_value != NULL) 688195011Sjamie free(jp[j].jp_value); 689195011Sjamie jp[j].jp_value = 690195011Sjamie malloc(jiov[ai].iov_len); 691195011Sjamie if (jp[j].jp_value == NULL) { 692195011Sjamie strerror_r(errno, jail_errmsg, 693195011Sjamie JAIL_ERRMSGLEN); 694195011Sjamie return (-1); 695195011Sjamie } 696194869Sjamie } 697195011Sjamie jiov[ai].iov_base = jp[j].jp_value; 698194869Sjamie memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 699194869Sjamie ai++; 700194869Sjamie } 701194869Sjamie } 702194869Sjamie } 703194869Sjamie if (jid < 0 && !jail_errmsg[0]) 704194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), 705194869Sjamie "jail_get: %s", strerror(errno)); 706194869Sjamie for (ai = j = 0, i = ki; j < njp; j++) { 707194869Sjamie if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 708194869Sjamie ai++; 709194869Sjamie jp[j].jp_valuelen = jiov[ai].iov_len; 710194869Sjamie ai++; 711194869Sjamie } else if (jp + j != jp_key) { 712194869Sjamie i++; 713194869Sjamie jp[j].jp_valuelen = jiov[i].iov_len; 714194869Sjamie i++; 715194869Sjamie } 716194869Sjamie } 717194869Sjamie return (jid); 718194869Sjamie} 719194869Sjamie 720194869Sjamie/* 721194869Sjamie * Convert a jail parameter's value to external form. 722194869Sjamie */ 723194869Sjamiechar * 724194869Sjamiejailparam_export(struct jailparam *jp) 725194869Sjamie{ 726212073Sjamie size_t *valuelens; 727194869Sjamie char *value, *tvalue, **values; 728194869Sjamie size_t valuelen; 729195870Sjamie int i, nval, ival; 730194869Sjamie char valbuf[INET6_ADDRSTRLEN]; 731194869Sjamie 732194869Sjamie if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 733194869Sjamie value = strdup(jp->jp_value); 734194869Sjamie if (value == NULL) 735194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 736194869Sjamie return (value); 737194869Sjamie } 738194869Sjamie nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1; 739194869Sjamie if (nval == 0) { 740194869Sjamie value = strdup(""); 741194869Sjamie if (value == NULL) 742194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 743194869Sjamie return (value); 744194869Sjamie } 745194869Sjamie values = alloca(nval * sizeof(char *)); 746212073Sjamie valuelens = alloca(nval * sizeof(size_t)); 747194869Sjamie valuelen = 0; 748194869Sjamie for (i = 0; i < nval; i++) { 749194869Sjamie switch (jp->jp_ctltype & CTLTYPE) { 750194869Sjamie case CTLTYPE_INT: 751195870Sjamie ival = ((int *)jp->jp_value)[i]; 752195870Sjamie if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && 753195870Sjamie (unsigned)ival < 2) { 754195870Sjamie strlcpy(valbuf, bool_values[ival], 755194869Sjamie sizeof(valbuf)); 756194869Sjamie break; 757194869Sjamie } 758195870Sjamie if ((jp->jp_flags & JP_JAILSYS) && 759195870Sjamie (unsigned)ival < sizeof(jailsys_values) / 760195870Sjamie sizeof(jailsys_values[0])) { 761195870Sjamie strlcpy(valbuf, jailsys_values[ival], 762195870Sjamie sizeof(valbuf)); 763195870Sjamie break; 764195870Sjamie } 765195870Sjamie snprintf(valbuf, sizeof(valbuf), "%d", ival); 766194869Sjamie break; 767194869Sjamie case CTLTYPE_UINT: 768194869Sjamie snprintf(valbuf, sizeof(valbuf), "%u", 769194869Sjamie ((unsigned *)jp->jp_value)[i]); 770194869Sjamie break; 771194869Sjamie case CTLTYPE_LONG: 772194869Sjamie snprintf(valbuf, sizeof(valbuf), "%ld", 773194869Sjamie ((long *)jp->jp_value)[i]); 774194869Sjamie break; 775194869Sjamie case CTLTYPE_ULONG: 776194869Sjamie snprintf(valbuf, sizeof(valbuf), "%lu", 777194869Sjamie ((unsigned long *)jp->jp_value)[i]); 778194869Sjamie break; 779217616Smdf case CTLTYPE_S64: 780194869Sjamie snprintf(valbuf, sizeof(valbuf), "%jd", 781194869Sjamie (intmax_t)((int64_t *)jp->jp_value)[i]); 782194869Sjamie break; 783217616Smdf case CTLTYPE_U64: 784217616Smdf snprintf(valbuf, sizeof(valbuf), "%ju", 785217616Smdf (uintmax_t)((uint64_t *)jp->jp_value)[i]); 786217616Smdf break; 787194869Sjamie case CTLTYPE_STRUCT: 788194869Sjamie switch (jp->jp_structtype) { 789194869Sjamie case JPS_IN_ADDR: 790194869Sjamie if (inet_ntop(AF_INET, 791194869Sjamie &((struct in_addr *)jp->jp_value)[i], 792194869Sjamie valbuf, sizeof(valbuf)) == NULL) { 793194869Sjamie strerror_r(errno, jail_errmsg, 794194869Sjamie JAIL_ERRMSGLEN); 795194869Sjamie return (NULL); 796194869Sjamie } 797194869Sjamie break; 798194869Sjamie case JPS_IN6_ADDR: 799194869Sjamie if (inet_ntop(AF_INET6, 800194869Sjamie &((struct in6_addr *)jp->jp_value)[i], 801194869Sjamie valbuf, sizeof(valbuf)) == NULL) { 802194869Sjamie strerror_r(errno, jail_errmsg, 803194869Sjamie JAIL_ERRMSGLEN); 804194869Sjamie return (NULL); 805194869Sjamie } 806194869Sjamie break; 807194869Sjamie default: 808194869Sjamie goto unknown_type; 809194869Sjamie } 810194869Sjamie break; 811194869Sjamie default: 812194869Sjamie unknown_type: 813194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 814194869Sjamie "unknown type for %s", jp->jp_name); 815194869Sjamie errno = ENOENT; 816194869Sjamie return (NULL); 817194869Sjamie } 818212073Sjamie valuelens[i] = strlen(valbuf) + 1; 819212073Sjamie valuelen += valuelens[i]; 820212073Sjamie values[i] = alloca(valuelens[i]); 821194869Sjamie strcpy(values[i], valbuf); 822194869Sjamie } 823212073Sjamie value = malloc(valuelen); 824194869Sjamie if (value == NULL) 825194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 826194869Sjamie else { 827194869Sjamie tvalue = value; 828194869Sjamie for (i = 0; i < nval; i++) { 829194869Sjamie strcpy(tvalue, values[i]); 830194869Sjamie if (i < nval - 1) { 831212073Sjamie tvalue += valuelens[i]; 832212073Sjamie tvalue[-1] = ','; 833194869Sjamie } 834194869Sjamie } 835194869Sjamie } 836194869Sjamie return (value); 837194869Sjamie} 838194869Sjamie 839194869Sjamie/* 840212073Sjamie * Free the contents of a jail parameter list (but not the list itself). 841194869Sjamie */ 842194869Sjamievoid 843194869Sjamiejailparam_free(struct jailparam *jp, unsigned njp) 844194869Sjamie{ 845194869Sjamie unsigned j; 846194869Sjamie 847194869Sjamie for (j = 0; j < njp; j++) { 848194869Sjamie free(jp[j].jp_name); 849194869Sjamie if (!(jp[j].jp_flags & JP_RAWVALUE)) 850194869Sjamie free(jp[j].jp_value); 851194869Sjamie } 852194869Sjamie} 853194869Sjamie 854194869Sjamie/* 855194869Sjamie * Find a parameter's type and size from its MIB. 856194869Sjamie */ 857194869Sjamiestatic int 858194869Sjamiejailparam_type(struct jailparam *jp) 859194869Sjamie{ 860235799Sjamie char *p, *name, *nname; 861194869Sjamie size_t miblen, desclen; 862235291Sjamie int i, isarray; 863194869Sjamie struct { 864194869Sjamie int i; 865194869Sjamie char s[MAXPATHLEN]; 866194869Sjamie } desc; 867194869Sjamie int mib[CTL_MAXNAME]; 868194869Sjamie 869194869Sjamie /* The "lastjid" parameter isn't real. */ 870235799Sjamie name = jp->jp_name; 871235799Sjamie if (!strcmp(name, "lastjid")) { 872194869Sjamie jp->jp_valuelen = sizeof(int); 873194869Sjamie jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR; 874194869Sjamie return (0); 875194869Sjamie } 876194869Sjamie 877194869Sjamie /* Find the sysctl that describes the parameter. */ 878194869Sjamie mib[0] = 0; 879194869Sjamie mib[1] = 3; 880235799Sjamie snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 881194869Sjamie miblen = sizeof(mib) - 2 * sizeof(int); 882194869Sjamie if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) { 883194869Sjamie if (errno != ENOENT) { 884194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 885235799Sjamie "sysctl(0.3.%s): %s", name, strerror(errno)); 886194869Sjamie return (-1); 887194869Sjamie } 888194869Sjamie /* 889194869Sjamie * The parameter probably doesn't exist. But it might be 890194869Sjamie * the "no" counterpart to a boolean. 891194869Sjamie */ 892235799Sjamie nname = nononame(name); 893232342Sjamie if (nname == NULL) { 894232342Sjamie unknown_parameter: 895232342Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 896232342Sjamie "unknown parameter: %s", jp->jp_name); 897232342Sjamie errno = ENOENT; 898232342Sjamie return (-1); 899194869Sjamie } 900235799Sjamie name = alloca(strlen(nname) + 1); 901235799Sjamie strcpy(name, nname); 902232342Sjamie free(nname); 903235799Sjamie snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name); 904232342Sjamie miblen = sizeof(mib) - 2 * sizeof(int); 905232342Sjamie if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 906232342Sjamie strlen(desc.s)) < 0) 907232342Sjamie goto unknown_parameter; 908232342Sjamie jp->jp_flags |= JP_NOBOOL; 909194869Sjamie } 910195870Sjamie mib_desc: 911194869Sjamie mib[1] = 4; 912194869Sjamie desclen = sizeof(desc); 913194869Sjamie if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, 914194869Sjamie NULL, 0) < 0) { 915194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 916235799Sjamie "sysctl(0.4.%s): %s", name, strerror(errno)); 917194869Sjamie return (-1); 918194869Sjamie } 919232342Sjamie jp->jp_ctltype = desc.i; 920232342Sjamie /* If this came from removing a "no", it better be a boolean. */ 921232342Sjamie if (jp->jp_flags & JP_NOBOOL) { 922232342Sjamie if ((desc.i & CTLTYPE) == CTLTYPE_INT && desc.s[0] == 'B') { 923232342Sjamie jp->jp_valuelen = sizeof(int); 924232342Sjamie return (0); 925232342Sjamie } 926232342Sjamie else if ((desc.i & CTLTYPE) != CTLTYPE_NODE) 927232342Sjamie goto unknown_parameter; 928232342Sjamie } 929194869Sjamie /* See if this is an array type. */ 930194869Sjamie p = strchr(desc.s, '\0'); 931194869Sjamie isarray = 0; 932194869Sjamie if (p - 2 < desc.s || strcmp(p - 2, ",a")) 933194869Sjamie isarray = 0; 934194869Sjamie else { 935194869Sjamie isarray = 1; 936194869Sjamie p[-2] = 0; 937194869Sjamie } 938212074Sjamie /* Look for types we understand. */ 939194869Sjamie switch (desc.i & CTLTYPE) { 940194869Sjamie case CTLTYPE_INT: 941194869Sjamie if (desc.s[0] == 'B') 942195870Sjamie jp->jp_flags |= JP_BOOL; 943195870Sjamie else if (!strcmp(desc.s, "E,jailsys")) 944195870Sjamie jp->jp_flags |= JP_JAILSYS; 945194869Sjamie case CTLTYPE_UINT: 946194869Sjamie jp->jp_valuelen = sizeof(int); 947194869Sjamie break; 948194869Sjamie case CTLTYPE_LONG: 949194869Sjamie case CTLTYPE_ULONG: 950194869Sjamie jp->jp_valuelen = sizeof(long); 951194869Sjamie break; 952217616Smdf case CTLTYPE_S64: 953217616Smdf case CTLTYPE_U64: 954194869Sjamie jp->jp_valuelen = sizeof(int64_t); 955194869Sjamie break; 956194869Sjamie case CTLTYPE_STRING: 957194869Sjamie desc.s[0] = 0; 958194869Sjamie desclen = sizeof(desc.s); 959194869Sjamie if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen, 960194869Sjamie NULL, 0) < 0) { 961194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 962235799Sjamie "sysctl(" SJPARAM ".%s): %s", name, 963194869Sjamie strerror(errno)); 964194869Sjamie return (-1); 965194869Sjamie } 966194869Sjamie jp->jp_valuelen = strtoul(desc.s, NULL, 10); 967194869Sjamie break; 968194869Sjamie case CTLTYPE_STRUCT: 969194869Sjamie if (!strcmp(desc.s, "S,in_addr")) { 970194869Sjamie jp->jp_structtype = JPS_IN_ADDR; 971194869Sjamie jp->jp_valuelen = sizeof(struct in_addr); 972194869Sjamie } else if (!strcmp(desc.s, "S,in6_addr")) { 973194869Sjamie jp->jp_structtype = JPS_IN6_ADDR; 974194869Sjamie jp->jp_valuelen = sizeof(struct in6_addr); 975194869Sjamie } else { 976194869Sjamie desclen = 0; 977194869Sjamie if (sysctl(mib + 2, miblen / sizeof(int), 978194869Sjamie NULL, &jp->jp_valuelen, NULL, 0) < 0) { 979194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 980235799Sjamie "sysctl(" SJPARAM ".%s): %s", name, 981194869Sjamie strerror(errno)); 982194869Sjamie return (-1); 983194869Sjamie } 984194869Sjamie } 985194869Sjamie break; 986194869Sjamie case CTLTYPE_NODE: 987235291Sjamie /* 988235291Sjamie * A node might be described by an empty-named child, 989235291Sjamie * which would be immediately before or after the node itself. 990235291Sjamie */ 991195870Sjamie mib[1] = 1; 992195870Sjamie miblen += sizeof(int); 993235291Sjamie for (i = -1; i <= 1; i += 2) { 994235291Sjamie mib[(miblen / sizeof(int)) + 1] = 995235291Sjamie mib[(miblen / sizeof(int))] + i; 996235291Sjamie desclen = sizeof(desc.s); 997235291Sjamie if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, 998235291Sjamie &desclen, NULL, 0) < 0) { 999235291Sjamie if (errno == ENOENT) 1000235291Sjamie continue; 1001235291Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1002235291Sjamie "sysctl(0.1): %s", strerror(errno)); 1003235291Sjamie return (-1); 1004235291Sjamie } 1005235799Sjamie if (desclen == sizeof(SJPARAM) + strlen(name) + 2 && 1006235291Sjamie memcmp(SJPARAM ".", desc.s, sizeof(SJPARAM)) == 0 && 1007235799Sjamie memcmp(name, desc.s + sizeof(SJPARAM), 1008235291Sjamie desclen - sizeof(SJPARAM) - 2) == 0 && 1009235291Sjamie desc.s[desclen - 2] == '.') 1010235291Sjamie goto mib_desc; 1011194869Sjamie } 1012235291Sjamie goto unknown_parameter; 1013194869Sjamie default: 1014194869Sjamie snprintf(jail_errmsg, JAIL_ERRMSGLEN, 1015194869Sjamie "unknown type for %s", jp->jp_name); 1016194869Sjamie errno = ENOENT; 1017194869Sjamie return (-1); 1018194869Sjamie } 1019194869Sjamie if (isarray) { 1020194869Sjamie jp->jp_elemlen = jp->jp_valuelen; 1021194869Sjamie jp->jp_valuelen = 0; 1022194869Sjamie } 1023194869Sjamie return (0); 1024194869Sjamie} 1025194869Sjamie 1026194869Sjamie/* 1027194869Sjamie * Change a boolean parameter name into its "no" counterpart or vice versa. 1028194869Sjamie */ 1029194869Sjamiestatic char * 1030194869Sjamienoname(const char *name) 1031194869Sjamie{ 1032194869Sjamie char *nname, *p; 1033194869Sjamie 1034194869Sjamie nname = malloc(strlen(name) + 3); 1035194869Sjamie if (nname == NULL) { 1036194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1037194869Sjamie return (NULL); 1038194869Sjamie } 1039194869Sjamie p = strrchr(name, '.'); 1040194869Sjamie if (p != NULL) 1041194869Sjamie sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 1042194869Sjamie else 1043194869Sjamie sprintf(nname, "no%s", name); 1044194869Sjamie return (nname); 1045194869Sjamie} 1046194869Sjamie 1047194869Sjamiestatic char * 1048194869Sjamienononame(const char *name) 1049194869Sjamie{ 1050194869Sjamie char *p, *nname; 1051194869Sjamie 1052194869Sjamie p = strrchr(name, '.'); 1053194869Sjamie if (strncmp(p ? p + 1 : name, "no", 2)) { 1054194869Sjamie snprintf(jail_errmsg, sizeof(jail_errmsg), 1055194869Sjamie "mismatched boolean: %s", name); 1056194869Sjamie errno = EINVAL; 1057194869Sjamie return (NULL); 1058194869Sjamie } 1059194869Sjamie nname = malloc(strlen(name) - 1); 1060194869Sjamie if (nname == NULL) { 1061194869Sjamie strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 1062194869Sjamie return (NULL); 1063194869Sjamie } 1064194869Sjamie if (p != NULL) 1065194869Sjamie sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 1066194869Sjamie else 1067194869Sjamie strcpy(nname, name + 2); 1068194869Sjamie return (nname); 1069194869Sjamie} 1070