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