jail.c revision 194869
150472Speter/*- 23515Sache * Copyright (c) 2009 James Gritton. 3217309Snwhitehorn * All rights reserved. 4156813Sru * 5217309Snwhitehorn * Redistribution and use in source and binary forms, with or without 6252129Sbapt * modification, are permitted provided that the following conditions 7251843Sbapt * are met: 8251843Sbapt * 1. Redistributions of source code must retain the above copyright 9251843Sbapt * notice, this list of conditions and the following disclaimer. 10251843Sbapt * 2. Redistributions in binary form must reproduce the above copyright 11251843Sbapt * notice, this list of conditions and the following disclaimer in the 12251843Sbapt * documentation and/or other materials provided with the distribution. 13217309Snwhitehorn * 14217309Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1512983Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16275040Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17275040Sdteske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18275040Sdteske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19251843Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20217309Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21251845Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 223515Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 233515Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/lib/libjail/jail.c 194869 2009-06-24 18:18:35Z jamie $"); 29 30#include <sys/param.h> 31#include <sys/types.h> 32#include <sys/jail.h> 33#include <sys/socket.h> 34#include <sys/sysctl.h> 35 36#include <arpa/inet.h> 37#include <netinet/in.h> 38 39#include <errno.h> 40#include <inttypes.h> 41#include <stdio.h> 42#include <stdarg.h> 43#include <stdlib.h> 44#include <string.h> 45 46#include "jail.h" 47 48#define SJPARAM "security.jail.param" 49 50#define JPS_IN_ADDR 1 51#define JPS_IN6_ADDR 2 52 53#define ARRAY_SANITY 5 54#define ARRAY_SLOP 5 55 56 57static int jailparam_vlist(struct jailparam **jpp, va_list ap); 58static int jailparam_type(struct jailparam *jp); 59static char *noname(const char *name); 60static char *nononame(const char *name); 61 62char jail_errmsg[JAIL_ERRMSGLEN]; 63 64 65/* 66 * Import a null-terminated parameter list and set a jail with the flags 67 * and parameters. 68 */ 69int 70jail_setv(int flags, ...) 71{ 72 va_list ap; 73 struct jailparam *jp; 74 int njp; 75 76 va_start(ap, flags); 77 njp = jailparam_vlist(&jp, ap); 78 va_end(ap); 79 if (njp < 0) 80 return (njp); 81 return (jailparam_set(jp, njp, flags)); 82} 83 84/* 85 * Read a null-terminated parameter list, get the referenced jail, and export 86 * the parameters to the list. 87 */ 88int 89jail_getv(int flags, ...) 90{ 91 va_list ap, tap; 92 struct jailparam *jp; 93 char *valarg; 94 const char *value; 95 int njp, i, jid, namekey, zero; 96 97 va_start(ap, flags); 98 va_copy(tap, ap); 99 njp = jailparam_vlist(&jp, tap); 100 va_end(tap); 101 if (njp < 0) 102 return (njp); 103 /* 104 * See if the name is the search key. If so, we don't want to write 105 * it back in case it's a read-only string. 106 */ 107 namekey = 1; 108 zero = 0; 109 for (i = 0; i < njp; i++) { 110 if (!strcmp(jp->jp_name, "lastjid") || 111 (!strcmp(jp->jp_name, "jid") && 112 memcmp(jp->jp_value, &zero, sizeof(zero)))) 113 namekey = 0; 114 } 115 jid = jailparam_get(jp, njp, flags); 116 if (jid < 0) { 117 va_end(ap); 118 return (-1); 119 } 120 for (i = 0; i < njp; i++) { 121 (void)va_arg(ap, char *); 122 value = jailparam_export(jp + i); 123 if (value == NULL) { 124 va_end(ap); 125 return (-1); 126 } 127 valarg = va_arg(ap, char *); 128 if (!namekey || strcmp(jp[i].jp_name, "name")) 129 /* It's up to the caller to ensure there's room. */ 130 strcpy(valarg, value); 131 } 132 va_end(ap); 133 return (jid); 134} 135 136/* 137 * Return a list of all known parameters. 138 */ 139int 140jailparam_all(struct jailparam **jpp) 141{ 142 struct jailparam *jp; 143 char *nname; 144 size_t mlen1, mlen2, buflen; 145 int njp, nlist; 146 int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; 147 char buf[MAXPATHLEN]; 148 149 njp = 0; 150 nlist = 32; 151 jp = malloc(nlist * sizeof(*jp)); 152 if (jp == NULL) { 153 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 154 return (-1); 155 } 156 mib1[0] = 0; 157 mib1[1] = 2; 158 mlen1 = CTL_MAXNAME - 2; 159 if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) { 160 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 161 "sysctlnametomib(" SJPARAM "): %s", strerror(errno)); 162 goto error; 163 } 164 for (;; njp++) { 165 /* Get the next parameter. */ 166 mlen2 = sizeof(mib2); 167 if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) { 168 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 169 "sysctl(0.2): %s", strerror(errno)); 170 goto error; 171 } 172 if (mib2[0] != mib1[2] || mib2[1] != mib1[3] || 173 mib2[2] != mib1[4]) 174 break; 175 /* Convert it to an ascii name. */ 176 memcpy(mib1 + 2, mib2, mlen2); 177 mlen1 = mlen2 / sizeof(int); 178 mib1[1] = 1; 179 buflen = sizeof(buf); 180 if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) { 181 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 182 "sysctl(0.1): %s", strerror(errno)); 183 goto error; 184 } 185 /* Add the parameter to the list */ 186 if (njp >= nlist) { 187 nlist *= 2; 188 jp = realloc(jp, nlist * sizeof(jp)); 189 if (jp == NULL) { 190 jailparam_free(jp, njp); 191 return (-1); 192 } 193 } 194 if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0) 195 goto error; 196 if (jailparam_type(jp + njp) < 0) { 197 njp++; 198 goto error; 199 } 200 /* Convert nobool parameters to bool. */ 201 if (jp[njp].jp_flags & JP_NOBOOL) { 202 nname = nononame(jp[njp].jp_name); 203 if (nname == NULL) { 204 njp++; 205 goto error; 206 } 207 free(jp[njp].jp_name); 208 jp[njp].jp_name = nname; 209 jp[njp].jp_flags ^= JP_BOOL | JP_NOBOOL; 210 } 211 mib1[1] = 2; 212 } 213 jp = realloc(jp, njp * sizeof(*jp)); 214 *jpp = jp; 215 return (njp); 216 217 error: 218 jailparam_free(jp, njp); 219 free(jp); 220 return (-1); 221} 222 223/* 224 * Clear a jail parameter and copy in its name. 225 */ 226int 227jailparam_init(struct jailparam *jp, const char *name) 228{ 229 230 memset(jp, 0, sizeof(*jp)); 231 jp->jp_name = strdup(name); 232 if (jp->jp_name == NULL) { 233 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 234 return (-1); 235 } 236 return (0); 237} 238 239/* 240 * Put a name and value into a jail parameter element, converting the value 241 * to internal form. 242 */ 243int 244jailparam_import(struct jailparam *jp, const char *value) 245{ 246 char *p, *ep, *tvalue; 247 const char *avalue; 248 int i, nval, fw; 249 250 if (!jp->jp_ctltype && jailparam_type(jp) < 0) 251 goto error; 252 if (value == NULL) 253 return (0); 254 if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 255 jp->jp_value = strdup(value); 256 if (!jp->jp_value) { 257 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 258 goto error; 259 } 260 return (0); 261 } 262 nval = 1; 263 if (jp->jp_elemlen) { 264 if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) { 265 jp->jp_value = strdup(""); 266 if (value == NULL) { 267 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 268 goto error; 269 } 270 jp->jp_valuelen = 0; 271 return (0); 272 } 273 for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) 274 nval++; 275 jp->jp_valuelen = jp->jp_elemlen * nval; 276 } 277 jp->jp_value = malloc(jp->jp_valuelen); 278 if (!jp->jp_value) { 279 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 280 goto error; 281 } 282 avalue = value; 283 for (i = 0; i < nval; i++) { 284 fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ","); 285 switch (jp->jp_ctltype & CTLTYPE) { 286 case CTLTYPE_INT: 287 if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { 288 if (!strncasecmp(avalue, "true", 4)) 289 ((int *)jp->jp_value)[i] = 1; 290 else if (!strncasecmp(avalue, "false", 5)) 291 ((int *)jp->jp_value)[i] = 0; 292 else { 293 snprintf(jail_errmsg, 294 JAIL_ERRMSGLEN, 295 "%s: unknown boolean value \"%.*s\"", 296 jp->jp_name, fw, avalue); 297 errno = EINVAL; 298 goto error; 299 } 300 break; 301 } 302 ((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 303 integer_test: 304 if (ep != avalue + fw) { 305 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 306 "%s: non-integer value \"%.*s\"", 307 jp->jp_name, fw, avalue); 308 errno = EINVAL; 309 goto error; 310 } 311 break; 312 case CTLTYPE_UINT: 313 ((unsigned *)jp->jp_value)[i] = 314 strtoul(avalue, &ep, 10); 315 goto integer_test; 316 case CTLTYPE_LONG: 317 ((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10); 318 goto integer_test; 319 case CTLTYPE_ULONG: 320 ((unsigned long *)jp->jp_value)[i] = 321 strtoul(avalue, &ep, 10); 322 goto integer_test; 323 case CTLTYPE_QUAD: 324 ((int64_t *)jp->jp_value)[i] = 325 strtoimax(avalue, &ep, 10); 326 goto integer_test; 327 case CTLTYPE_STRUCT: 328 tvalue = alloca(fw + 1); 329 strlcpy(tvalue, avalue, fw + 1); 330 switch (jp->jp_structtype) { 331 case JPS_IN_ADDR: 332 if (inet_pton(AF_INET, tvalue, 333 &((struct in_addr *)jp->jp_value)[i]) != 1) 334 { 335 snprintf(jail_errmsg, 336 JAIL_ERRMSGLEN, 337 "%s: not an IPv4 address: %s", 338 jp->jp_name, tvalue); 339 errno = EINVAL; 340 goto error; 341 } 342 break; 343 case JPS_IN6_ADDR: 344 if (inet_pton(AF_INET6, tvalue, 345 &((struct in6_addr *)jp->jp_value)[i]) != 1) 346 { 347 snprintf(jail_errmsg, 348 JAIL_ERRMSGLEN, 349 "%s: not an IPv6 address: %s", 350 jp->jp_name, tvalue); 351 errno = EINVAL; 352 goto error; 353 } 354 break; 355 default: 356 goto unknown_type; 357 } 358 break; 359 default: 360 unknown_type: 361 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 362 "unknown type for %s", jp->jp_name); 363 errno = ENOENT; 364 goto error; 365 } 366 avalue += fw + 1; 367 } 368 return (0); 369 370 error: 371 free(jp->jp_value); 372 jp->jp_value = NULL; 373 return (-1); 374} 375 376/* 377 * Put a name and value into a jail parameter element, copying the value 378 * but not altering it. 379 */ 380int 381jailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen) 382{ 383 384 jp->jp_value = value; 385 jp->jp_valuelen = valuelen; 386 jp->jp_flags |= JP_RAWVALUE; 387 return (0); 388} 389 390/* 391 * Run the jail_set and jail_get system calls on a parameter list. 392 */ 393int 394jailparam_set(struct jailparam *jp, unsigned njp, int flags) 395{ 396 struct iovec *jiov; 397 char *nname; 398 int i, jid; 399 unsigned j; 400 401 jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 402 for (i = j = 0; j < njp; j++) { 403 jiov[i].iov_base = jp[j].jp_name; 404 jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 405 i++; 406 if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) { 407 /* 408 * Set booleans without values. If one have a value of 409 * zero, change it to (or from) its "no" counterpart. 410 */ 411 jiov[i].iov_base = NULL; 412 jiov[i].iov_len = 0; 413 if (jp[j].jp_value != NULL && 414 jp[j].jp_valuelen == sizeof(int) && 415 !*(int *)jp[j].jp_value) { 416 nname = jp[j].jp_flags & JP_BOOL 417 ? noname(jiov[i].iov_base) 418 : nononame(jiov[i].iov_base); 419 if (nname == NULL) 420 return (-1); 421 free(jp[j].jp_name); 422 jiov[i].iov_base = jp[j].jp_name = nname; 423 } 424 } else { 425 jiov[i].iov_base = jp[j].jp_value; 426 jiov[i].iov_len = 427 (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING 428 ? strlen(jp[j].jp_value) + 1 429 : jp[j].jp_valuelen; 430 } 431 i++; 432 } 433 *(const void **)&jiov[i].iov_base = "errmsg"; 434 jiov[i].iov_len = sizeof("errmsg"); 435 i++; 436 jiov[i].iov_base = jail_errmsg; 437 jiov[i].iov_len = JAIL_ERRMSGLEN; 438 i++; 439 jail_errmsg[0] = 0; 440 jid = jail_set(jiov, i, flags); 441 if (jid < 0 && !jail_errmsg[0]) 442 snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s", 443 strerror(errno)); 444 return (jid); 445} 446 447int 448jailparam_get(struct jailparam *jp, unsigned njp, int flags) 449{ 450 struct iovec *jiov; 451 struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key; 452 int i, ai, ki, jid, arrays, sanity; 453 unsigned j; 454 455 /* Find the key and any array parameters. */ 456 jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1)); 457 jp_lastjid = jp_jid = jp_name = NULL; 458 arrays = 0; 459 for (ai = j = 0; j < njp; j++) { 460 if (!strcmp(jp[j].jp_name, "lastjid")) 461 jp_lastjid = jp + j; 462 else if (!strcmp(jp[j].jp_name, "jid")) 463 jp_jid = jp + j; 464 else if (!strcmp(jp[j].jp_name, "name")) 465 jp_name = jp + j; 466 else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 467 arrays = 1; 468 jiov[ai].iov_base = jp[j].jp_name; 469 jiov[ai].iov_len = strlen(jp[j].jp_name) + 1; 470 ai++; 471 jiov[ai].iov_base = NULL; 472 jiov[ai].iov_len = 0; 473 ai++; 474 } 475 } 476 jp_key = jp_lastjid ? jp_lastjid : 477 jp_jid && jp_jid->jp_valuelen == sizeof(int) && 478 *(int *)jp_jid->jp_value ? jp_jid : jp_name; 479 if (jp_key == NULL || jp_key->jp_value == NULL) { 480 strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN); 481 errno = ENOENT; 482 return (-1); 483 } 484 ki = ai; 485 jiov[ki].iov_base = jp_key->jp_name; 486 jiov[ki].iov_len = strlen(jp_key->jp_name) + 1; 487 ki++; 488 jiov[ki].iov_base = jp_key->jp_value; 489 jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING 490 ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen; 491 ki++; 492 *(const void **)&jiov[ki].iov_base = "errmsg"; 493 jiov[ki].iov_len = sizeof("errmsg"); 494 ki++; 495 jiov[ki].iov_base = jail_errmsg; 496 jiov[ki].iov_len = JAIL_ERRMSGLEN; 497 ki++; 498 jail_errmsg[0] = 0; 499 if (arrays && jail_get(jiov, ki, flags) < 0) { 500 if (!jail_errmsg[0]) 501 snprintf(jail_errmsg, sizeof(jail_errmsg), 502 "jail_get: %s", strerror(errno)); 503 return (-1); 504 } 505 /* Allocate storage for all parameters. */ 506 for (ai = j = 0, i = ki; j < njp; j++) { 507 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 508 ai++; 509 jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP; 510 jiov[ai].iov_base = jp[j].jp_value = 511 malloc(jiov[ai].iov_len); 512 if (jiov[ai].iov_base == NULL) { 513 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 514 return (-1); 515 } 516 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 517 ai++; 518 } else if (jp + j != jp_key) { 519 jiov[i].iov_base = jp[j].jp_name; 520 jiov[i].iov_len = strlen(jp[j].jp_name) + 1; 521 i++; 522 jiov[i].iov_base = jp[j].jp_value = 523 malloc(jp[j].jp_valuelen); 524 if (jiov[i].iov_base == NULL) { 525 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 526 return (-1); 527 } 528 jiov[i].iov_len = jp[j].jp_valuelen; 529 memset(jiov[i].iov_base, 0, jiov[i].iov_len); 530 i++; 531 } 532 } 533 /* 534 * Get the prison. If there are array elements, retry a few times 535 * in case their sizes changed from under us. 536 */ 537 for (sanity = 0;; sanity++) { 538 jid = jail_get(jiov, i, flags); 539 if (jid >= 0 || !arrays || sanity == ARRAY_SANITY || 540 errno != EINVAL || jail_errmsg[0]) 541 break; 542 for (ai = j = 0; j < njp; j++) { 543 if (jp[j].jp_elemlen && 544 !(jp[j].jp_flags & JP_RAWVALUE)) { 545 ai++; 546 free(jiov[ai].iov_base); 547 jiov[ai].iov_base = jp[j].jp_value = NULL; 548 jiov[ai].iov_len = 0; 549 ai++; 550 } 551 } 552 if (jail_get(jiov, ki, flags) < 0) 553 break; 554 for (ai = j = 0; j < njp; j++) { 555 if (jp[j].jp_elemlen && 556 !(jp[j].jp_flags & JP_RAWVALUE)) { 557 ai++; 558 jiov[ai].iov_len += 559 jp[j].jp_elemlen * ARRAY_SLOP; 560 jiov[ai].iov_base = jp[j].jp_value = 561 malloc(jiov[ai].iov_len); 562 if (jiov[ai].iov_base == NULL) { 563 strerror_r(errno, jail_errmsg, 564 JAIL_ERRMSGLEN); 565 return (-1); 566 } 567 memset(jiov[ai].iov_base, 0, jiov[ai].iov_len); 568 ai++; 569 } 570 } 571 } 572 if (jid < 0 && !jail_errmsg[0]) 573 snprintf(jail_errmsg, sizeof(jail_errmsg), 574 "jail_get: %s", strerror(errno)); 575 for (ai = j = 0, i = ki; j < njp; j++) { 576 if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) { 577 ai++; 578 jp[j].jp_valuelen = jiov[ai].iov_len; 579 ai++; 580 } else if (jp + j != jp_key) { 581 i++; 582 jp[j].jp_valuelen = jiov[i].iov_len; 583 i++; 584 } 585 } 586 return (jid); 587} 588 589/* 590 * Convert a jail parameter's value to external form. 591 */ 592char * 593jailparam_export(struct jailparam *jp) 594{ 595 char *value, *tvalue, **values; 596 size_t valuelen; 597 int i, nval; 598 char valbuf[INET6_ADDRSTRLEN]; 599 600 if (!jp->jp_ctltype && jailparam_type(jp) < 0) 601 return (NULL); 602 if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) { 603 value = strdup(jp->jp_value); 604 if (value == NULL) 605 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 606 return (value); 607 } 608 nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1; 609 if (nval == 0) { 610 value = strdup(""); 611 if (value == NULL) 612 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 613 return (value); 614 } 615 values = alloca(nval * sizeof(char *)); 616 valuelen = 0; 617 for (i = 0; i < nval; i++) { 618 switch (jp->jp_ctltype & CTLTYPE) { 619 case CTLTYPE_INT: 620 if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { 621 strlcpy(valbuf, 622 ((int *)jp->jp_value)[i] ? "true" : "false", 623 sizeof(valbuf)); 624 break; 625 } 626 snprintf(valbuf, sizeof(valbuf), "%d", 627 ((int *)jp->jp_value)[i]); 628 break; 629 case CTLTYPE_UINT: 630 snprintf(valbuf, sizeof(valbuf), "%u", 631 ((unsigned *)jp->jp_value)[i]); 632 break; 633 case CTLTYPE_LONG: 634 snprintf(valbuf, sizeof(valbuf), "%ld", 635 ((long *)jp->jp_value)[i]); 636 break; 637 case CTLTYPE_ULONG: 638 snprintf(valbuf, sizeof(valbuf), "%lu", 639 ((unsigned long *)jp->jp_value)[i]); 640 break; 641 case CTLTYPE_QUAD: 642 snprintf(valbuf, sizeof(valbuf), "%jd", 643 (intmax_t)((int64_t *)jp->jp_value)[i]); 644 break; 645 case CTLTYPE_STRUCT: 646 switch (jp->jp_structtype) { 647 case JPS_IN_ADDR: 648 if (inet_ntop(AF_INET, 649 &((struct in_addr *)jp->jp_value)[i], 650 valbuf, sizeof(valbuf)) == NULL) { 651 strerror_r(errno, jail_errmsg, 652 JAIL_ERRMSGLEN); 653 654 return (NULL); 655 } 656 break; 657 case JPS_IN6_ADDR: 658 if (inet_ntop(AF_INET6, 659 &((struct in6_addr *)jp->jp_value)[i], 660 valbuf, sizeof(valbuf)) == NULL) { 661 strerror_r(errno, jail_errmsg, 662 JAIL_ERRMSGLEN); 663 664 return (NULL); 665 } 666 break; 667 default: 668 goto unknown_type; 669 } 670 break; 671 default: 672 unknown_type: 673 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 674 "unknown type for %s", jp->jp_name); 675 errno = ENOENT; 676 return (NULL); 677 } 678 valuelen += strlen(valbuf) + 1; 679 values[i] = alloca(valuelen); 680 strcpy(values[i], valbuf); 681 } 682 value = malloc(valuelen + 1); 683 if (value == NULL) 684 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 685 else { 686 tvalue = value; 687 for (i = 0; i < nval; i++) { 688 strcpy(tvalue, values[i]); 689 if (i < nval - 1) { 690 tvalue += strlen(values[i]); 691 *tvalue++ = ','; 692 } 693 } 694 } 695 return (value); 696} 697 698/* 699 * Free the contents of a jail parameter list (but not thst list itself). 700 */ 701void 702jailparam_free(struct jailparam *jp, unsigned njp) 703{ 704 unsigned j; 705 706 for (j = 0; j < njp; j++) { 707 free(jp[j].jp_name); 708 if (!(jp[j].jp_flags & JP_RAWVALUE)) 709 free(jp[j].jp_value); 710 } 711} 712 713/* 714 * Create and import an array of jail parameters, given a list of name and 715 * value strings, terminated by a null name. 716 */ 717static int 718jailparam_vlist(struct jailparam **jpp, va_list ap) 719{ 720 va_list tap; 721 struct jailparam *jp; 722 char *name, *value; 723 int njp; 724 725 va_copy(tap, ap); 726 for (njp = 0; va_arg(tap, char *) != NULL; njp++) 727 (void)va_arg(tap, char *); 728 va_end(tap); 729 jp = calloc(njp, sizeof(struct jailparam)); 730 if (jp == NULL) { 731 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 732 return (-1); 733 } 734 735 for (njp = 0; (name = va_arg(ap, char *)) != NULL; njp++) { 736 value = va_arg(ap, char *); 737 if (jailparam_init(jp + njp, name) < 0 || 738 jailparam_import(jp + njp, value) < 0) { 739 jailparam_free(jp, njp); 740 free(jp); 741 return (-1); 742 } 743 } 744 *jpp = jp; 745 return (njp); 746} 747 748/* 749 * Find a parameter's type and size from its MIB. 750 */ 751static int 752jailparam_type(struct jailparam *jp) 753{ 754 char *p, *nname; 755 size_t miblen, desclen; 756 int isarray; 757 struct { 758 int i; 759 char s[MAXPATHLEN]; 760 } desc; 761 int mib[CTL_MAXNAME]; 762 763 /* The "lastjid" parameter isn't real. */ 764 if (!strcmp(jp->jp_name, "lastjid")) { 765 jp->jp_valuelen = sizeof(int); 766 jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR; 767 return (0); 768 } 769 770 /* Find the sysctl that describes the parameter. */ 771 mib[0] = 0; 772 mib[1] = 3; 773 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", jp->jp_name); 774 miblen = sizeof(mib) - 2 * sizeof(int); 775 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) { 776 if (errno != ENOENT) { 777 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 778 "sysctl(0.3.%s): %s", jp->jp_name, strerror(errno)); 779 return (-1); 780 } 781 /* 782 * The parameter probably doesn't exist. But it might be 783 * the "no" counterpart to a boolean. 784 */ 785 nname = nononame(jp->jp_name); 786 if (nname != NULL) { 787 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname); 788 free(nname); 789 miblen = sizeof(mib) - 2 * sizeof(int); 790 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 791 strlen(desc.s)) >= 0) { 792 mib[1] = 4; 793 desclen = sizeof(desc); 794 if (sysctl(mib, (miblen / sizeof(int)) + 2, 795 &desc, &desclen, NULL, 0) < 0) { 796 snprintf(jail_errmsg, 797 JAIL_ERRMSGLEN, 798 "sysctl(0.4.%s): %s", desc.s, 799 strerror(errno)); 800 return (-1); 801 } 802 if ((desc.i & CTLTYPE) == CTLTYPE_INT && 803 desc.s[0] == 'B') { 804 jp->jp_ctltype = desc.i; 805 jp->jp_flags |= JP_NOBOOL; 806 jp->jp_valuelen = sizeof(int); 807 return (0); 808 } 809 } 810 } 811 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 812 "unknown parameter: %s", jp->jp_name); 813 errno = ENOENT; 814 return (-1); 815 } 816 mib[1] = 4; 817 desclen = sizeof(desc); 818 if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, 819 NULL, 0) < 0) { 820 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 821 "sysctl(0.4.%s): %s", jp->jp_name, strerror(errno)); 822 return (-1); 823 } 824 /* See if this is an array type. */ 825 p = strchr(desc.s, '\0'); 826 isarray = 0; 827 if (p - 2 < desc.s || strcmp(p - 2, ",a")) 828 isarray = 0; 829 else { 830 isarray = 1; 831 p[-2] = 0; 832 } 833 /* Look for types we understand */ 834 jp->jp_ctltype = desc.i; 835 switch (desc.i & CTLTYPE) { 836 case CTLTYPE_INT: 837 if (desc.s[0] == 'B') 838 jp->jp_flags |= 839 (desc.s[1] == 'N') ? JP_NOBOOL : JP_BOOL; 840 case CTLTYPE_UINT: 841 jp->jp_valuelen = sizeof(int); 842 break; 843 case CTLTYPE_LONG: 844 case CTLTYPE_ULONG: 845 jp->jp_valuelen = sizeof(long); 846 break; 847 case CTLTYPE_QUAD: 848 jp->jp_valuelen = sizeof(int64_t); 849 break; 850 case CTLTYPE_STRING: 851 desc.s[0] = 0; 852 desclen = sizeof(desc.s); 853 if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen, 854 NULL, 0) < 0) { 855 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 856 "sysctl(" SJPARAM ".%s): %s", jp->jp_name, 857 strerror(errno)); 858 return (-1); 859 } 860 jp->jp_valuelen = strtoul(desc.s, NULL, 10); 861 break; 862 case CTLTYPE_STRUCT: 863 if (!strcmp(desc.s, "S,in_addr")) { 864 jp->jp_structtype = JPS_IN_ADDR; 865 jp->jp_valuelen = sizeof(struct in_addr); 866 } else if (!strcmp(desc.s, "S,in6_addr")) { 867 jp->jp_structtype = JPS_IN6_ADDR; 868 jp->jp_valuelen = sizeof(struct in6_addr); 869 } else { 870 desclen = 0; 871 if (sysctl(mib + 2, miblen / sizeof(int), 872 NULL, &jp->jp_valuelen, NULL, 0) < 0) { 873 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 874 "sysctl(" SJPARAM ".%s): %s", jp->jp_name, 875 strerror(errno)); 876 return (-1); 877 } 878 } 879 break; 880 case CTLTYPE_NODE: 881 /* 882 * A node isn't normally a parameter, but may be a boolean 883 * if its "no" counterpart exists. 884 */ 885 nname = noname(jp->jp_name); 886 if (nname == NULL) 887 return (-1); 888 mib[1] = 3; 889 snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname); 890 free(nname); 891 miblen = sizeof(mib) - 2 * sizeof(int); 892 if (sysctl(mib, 2, mib + 2, &miblen, desc.s, 893 strlen(desc.s)) < 0) { 894 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 895 "unknown parameter: %s", jp->jp_name); 896 return (-1); 897 } 898 mib[1] = 4; 899 desclen = sizeof(desc); 900 if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, 901 NULL, 0) < 0) { 902 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 903 "sysctl(0.4.%s): %s", desc.s, strerror(errno)); 904 return (-1); 905 } 906 if ((desc.i & CTLTYPE) != CTLTYPE_INT || desc.s[0] != 'B') { 907 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 908 "unknown parameter: %s", jp->jp_name); 909 errno = ENOENT; 910 return (-1); 911 } 912 jp->jp_valuelen = sizeof(int); 913 jp->jp_ctltype = desc.i; 914 jp->jp_flags |= JP_BOOL; 915 break; 916 default: 917 snprintf(jail_errmsg, JAIL_ERRMSGLEN, 918 "unknown type for %s", jp->jp_name); 919 errno = ENOENT; 920 return (-1); 921 } 922 if (isarray) { 923 jp->jp_elemlen = jp->jp_valuelen; 924 jp->jp_valuelen = 0; 925 } 926 return (0); 927} 928 929/* 930 * Change a boolean parameter name into its "no" counterpart or vice versa. 931 */ 932static char * 933noname(const char *name) 934{ 935 char *nname, *p; 936 937 nname = malloc(strlen(name) + 3); 938 if (nname == NULL) { 939 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 940 return (NULL); 941 } 942 p = strrchr(name, '.'); 943 if (p != NULL) 944 sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 945 else 946 sprintf(nname, "no%s", name); 947 return (nname); 948} 949 950static char * 951nononame(const char *name) 952{ 953 char *p, *nname; 954 955 p = strrchr(name, '.'); 956 if (strncmp(p ? p + 1 : name, "no", 2)) { 957 snprintf(jail_errmsg, sizeof(jail_errmsg), 958 "mismatched boolean: %s", name); 959 errno = EINVAL; 960 return (NULL); 961 } 962 nname = malloc(strlen(name) - 1); 963 if (nname == NULL) { 964 strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); 965 return (NULL); 966 } 967 if (p != NULL) 968 sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 969 else 970 strcpy(nname, name + 2); 971 return (nname); 972} 973