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