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