1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1999 Poul-Henning Kamp. 5 * Copyright (c) 2009-2012 James Gritton 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <sys/socket.h> 33 #include <sys/sysctl.h> 34 35 #include <arpa/inet.h> 36 #include <netinet/in.h> 37 38 #include <err.h> 39 #include <errno.h> 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "jailp.h" 47 48 #define JP_RDTUN(jp) (((jp)->jp_ctltype & CTLFLAG_RDTUN) == CTLFLAG_RDTUN) 49 50 struct permspec { 51 const char *name; 52 enum intparam ipnum; 53 int rev; 54 }; 55 56 int iflag; 57 int note_remove; 58 int verbose; 59 const char *separator = "\t"; 60 61 static void clear_persist(struct cfjail *j); 62 static int update_jail(struct cfjail *j); 63 static int rdtun_params(struct cfjail *j, int dofail); 64 static void running_jid(struct cfjail *j); 65 static void jail_quoted_warnx(const struct cfjail *j, const char *name_msg, 66 const char *noname_msg); 67 static int jailparam_set_note(const struct cfjail *j, struct jailparam *jp, 68 unsigned njp, int flags); 69 static void print_jail(FILE *fp, struct cfjail *j, int oldcl, int running); 70 static void print_param(FILE *fp, const struct cfparam *p, int sep, int doname); 71 static void show_jails(void); 72 static void quoted_print(FILE *fp, char *str); 73 static void usage(void) __dead2; 74 75 static struct permspec perm_sysctl[] = { 76 { "security.jail.set_hostname_allowed", KP_ALLOW_SET_HOSTNAME, 0 }, 77 { "security.jail.sysvipc_allowed", KP_ALLOW_SYSVIPC, 0 }, 78 { "security.jail.allow_raw_sockets", KP_ALLOW_RAW_SOCKETS, 0 }, 79 { "security.jail.chflags_allowed", KP_ALLOW_CHFLAGS, 0 }, 80 { "security.jail.mount_allowed", KP_ALLOW_MOUNT, 0 }, 81 { "security.jail.socket_unixiproute_only", KP_ALLOW_SOCKET_AF, 1 }, 82 }; 83 84 static const enum intparam startcommands[] = { 85 IP__NULL, 86 IP_EXEC_PREPARE, 87 #ifdef INET 88 IP__IP4_IFADDR, 89 #endif 90 #ifdef INET6 91 IP__IP6_IFADDR, 92 #endif 93 IP_MOUNT, 94 IP__MOUNT_FROM_FSTAB, 95 IP_MOUNT_DEVFS, 96 IP_MOUNT_FDESCFS, 97 IP_MOUNT_PROCFS, 98 IP_EXEC_PRESTART, 99 IP__OP, 100 IP_EXEC_CREATED, 101 IP_VNET_INTERFACE, 102 IP_EXEC_START, 103 IP_COMMAND, 104 IP_EXEC_POSTSTART, 105 IP__NULL 106 }; 107 108 static const enum intparam stopcommands[] = { 109 IP__NULL, 110 IP_EXEC_PRESTOP, 111 IP_EXEC_STOP, 112 IP_STOP_TIMEOUT, 113 IP__OP, 114 IP_EXEC_POSTSTOP, 115 IP_MOUNT_PROCFS, 116 IP_MOUNT_FDESCFS, 117 IP_MOUNT_DEVFS, 118 IP__MOUNT_FROM_FSTAB, 119 IP_MOUNT, 120 #ifdef INET6 121 IP__IP6_IFADDR, 122 #endif 123 #ifdef INET 124 IP__IP4_IFADDR, 125 #endif 126 IP_EXEC_RELEASE, 127 IP__NULL 128 }; 129 130 int 131 main(int argc, char **argv) 132 { 133 struct stat st; 134 FILE *jfp; 135 struct cfjail *j; 136 char *JidFile; 137 const char *cfname; 138 size_t sysvallen; 139 unsigned op, pi; 140 int ch, docf, dying_warned, error, i, oldcl, sysval; 141 int dflag, eflag, Rflag; 142 #if defined(INET) || defined(INET6) 143 char *cs, *ncs; 144 #endif 145 #if defined(INET) && defined(INET6) 146 struct in6_addr addr6; 147 #endif 148 149 op = 0; 150 dflag = eflag = Rflag = 0; 151 docf = 1; 152 cfname = CONF_FILE; 153 JidFile = NULL; 154 155 while ((ch = getopt(argc, argv, "cde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) { 156 switch (ch) { 157 case 'c': 158 op |= JF_START; 159 break; 160 case 'd': 161 dflag = 1; 162 break; 163 case 'e': 164 eflag = 1; 165 separator = optarg; 166 break; 167 case 'f': 168 cfname = optarg; 169 break; 170 case 'h': 171 #if defined(INET) || defined(INET6) 172 add_param(NULL, NULL, IP_IP_HOSTNAME, NULL); 173 #endif 174 docf = 0; 175 break; 176 case 'i': 177 iflag = 1; 178 verbose = -1; 179 break; 180 case 'J': 181 JidFile = optarg; 182 break; 183 case 'l': 184 add_param(NULL, NULL, IP_EXEC_CLEAN, NULL); 185 docf = 0; 186 break; 187 case 'm': 188 op |= JF_SET; 189 break; 190 case 'n': 191 add_param(NULL, NULL, KP_NAME, optarg); 192 docf = 0; 193 break; 194 case 'p': 195 paralimit = strtol(optarg, NULL, 10); 196 if (paralimit == 0) 197 paralimit = -1; 198 break; 199 case 'q': 200 verbose = -1; 201 break; 202 case 'r': 203 op |= JF_STOP; 204 break; 205 case 'R': 206 op |= JF_STOP; 207 Rflag = 1; 208 break; 209 case 's': 210 add_param(NULL, NULL, KP_SECURELEVEL, optarg); 211 docf = 0; 212 break; 213 case 'u': 214 add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 215 add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, NULL); 216 docf = 0; 217 break; 218 case 'U': 219 add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 220 add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, 221 "false"); 222 docf = 0; 223 break; 224 case 'v': 225 verbose = 1; 226 break; 227 default: 228 usage(); 229 } 230 } 231 argc -= optind; 232 argv += optind; 233 234 if (eflag) { 235 /* Just print list of all configured non-wildcard jails */ 236 if (op || argc > 0) 237 usage(); 238 load_config(cfname); 239 show_jails(); 240 exit(0); 241 } 242 243 /* Find out which of the command line styles this is. */ 244 oldcl = 0; 245 if (!op) { 246 /* Old-style command line with four fixed parameters */ 247 if (argc < 4 || argv[0][0] != '/') 248 usage(); 249 op = JF_START; 250 docf = 0; 251 oldcl = 1; 252 add_param(NULL, NULL, KP_PATH, argv[0]); 253 add_param(NULL, NULL, KP_HOST_HOSTNAME, argv[1]); 254 #if defined(INET) || defined(INET6) 255 if (argv[2][0] != '\0') { 256 for (cs = argv[2];; cs = ncs + 1) { 257 ncs = strchr(cs, ','); 258 if (ncs) 259 *ncs = '\0'; 260 add_param(NULL, NULL, 261 #if defined(INET) && defined(INET6) 262 inet_pton(AF_INET6, cs, &addr6) == 1 263 ? KP_IP6_ADDR : KP_IP4_ADDR, 264 #elif defined(INET) 265 KP_IP4_ADDR, 266 #elif defined(INET6) 267 KP_IP6_ADDR, 268 #endif 269 cs); 270 if (!ncs) 271 break; 272 } 273 } 274 #endif 275 for (i = 3; i < argc; i++) 276 add_param(NULL, NULL, IP_COMMAND, argv[i]); 277 /* Emulate the defaults from security.jail.* sysctls. */ 278 sysvallen = sizeof(sysval); 279 if (sysctlbyname("security.jail.jailed", &sysval, &sysvallen, 280 NULL, 0) == 0 && sysval == 0) { 281 for (pi = 0; pi < sizeof(perm_sysctl) / 282 sizeof(perm_sysctl[0]); pi++) { 283 sysvallen = sizeof(sysval); 284 if (sysctlbyname(perm_sysctl[pi].name, 285 &sysval, &sysvallen, NULL, 0) == 0) 286 add_param(NULL, NULL, 287 perm_sysctl[pi].ipnum, 288 (sysval ? 1 : 0) ^ 289 perm_sysctl[pi].rev 290 ? NULL : "false"); 291 } 292 } 293 } else if (op == JF_STOP) { 294 /* Jail remove, perhaps using the config file */ 295 if (!docf || argc == 0) 296 usage(); 297 if (!Rflag) 298 for (i = 0; i < argc; i++) 299 if (strchr(argv[i], '=')) 300 usage(); 301 if ((docf = !Rflag && 302 (!strcmp(cfname, "-") || stat(cfname, &st) == 0))) 303 load_config(cfname); 304 note_remove = docf || argc > 1 || wild_jail_name(argv[0]); 305 } else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) { 306 /* Single jail specified on the command line */ 307 if (Rflag) 308 usage(); 309 docf = 0; 310 for (i = 0; i < argc; i++) { 311 if (!strncmp(argv[i], "command", 7) && 312 (argv[i][7] == '\0' || argv[i][7] == '=')) { 313 if (argv[i][7] == '=') 314 add_param(NULL, NULL, IP_COMMAND, 315 argv[i] + 8); 316 for (i++; i < argc; i++) 317 add_param(NULL, NULL, IP_COMMAND, 318 argv[i]); 319 } 320 #ifdef INET 321 else if (!strncmp(argv[i], "ip4.addr=", 9)) { 322 for (cs = argv[i] + 9;; cs = ncs + 1) { 323 ncs = strchr(cs, ','); 324 if (ncs) 325 *ncs = '\0'; 326 add_param(NULL, NULL, KP_IP4_ADDR, cs); 327 if (!ncs) 328 break; 329 } 330 } 331 #endif 332 #ifdef INET6 333 else if (!strncmp(argv[i], "ip6.addr=", 9)) { 334 for (cs = argv[i] + 9;; cs = ncs + 1) { 335 ncs = strchr(cs, ','); 336 if (ncs) 337 *ncs = '\0'; 338 add_param(NULL, NULL, KP_IP6_ADDR, cs); 339 if (!ncs) 340 break; 341 } 342 } 343 #endif 344 else 345 add_param(NULL, NULL, 0, argv[i]); 346 } 347 } else { 348 /* From the config file, perhaps with a specified jail */ 349 if (Rflag || !docf) 350 usage(); 351 load_config(cfname); 352 } 353 354 /* Find out which jails will be run. */ 355 dep_setup(docf); 356 error = 0; 357 if (op == JF_STOP) { 358 for (i = 0; i < argc; i++) 359 if (start_state(argv[i], docf, op, Rflag) < 0) 360 error = 1; 361 } else { 362 if (start_state(argv[0], docf, op, 0) < 0) 363 exit(1); 364 } 365 366 jfp = NULL; 367 if (JidFile != NULL) { 368 jfp = fopen(JidFile, "w"); 369 if (jfp == NULL) 370 err(1, "open %s", JidFile); 371 setlinebuf(jfp); 372 } 373 setlinebuf(stdout); 374 375 /* 376 * The main loop: Get an available jail and perform the required 377 * operation on it. When that is done, the jail may be finished, 378 * or it may go back for the next step. 379 */ 380 dying_warned = 0; 381 while ((j = next_jail())) 382 { 383 if (j->flags & JF_FAILED) { 384 error = 1; 385 if (j->comparam == NULL) { 386 dep_done(j, 0); 387 continue; 388 } 389 } 390 if (!(j->flags & JF_PARAMS)) 391 { 392 j->flags |= JF_PARAMS; 393 if (dflag) 394 add_param(j, NULL, IP_ALLOW_DYING, NULL); 395 if (check_intparams(j) < 0) 396 continue; 397 if ((j->flags & (JF_START | JF_SET)) && 398 import_params(j) < 0) 399 continue; 400 } 401 if (j->intparams[IP_ALLOW_DYING] && !dying_warned) { 402 warnx("%s", "the 'allow.dying' parameter and '-d' flag" 403 "are deprecated and have no effect."); 404 dying_warned = 1; 405 } 406 if (!j->jid) 407 running_jid(j); 408 if (finish_command(j)) 409 continue; 410 411 switch (j->flags & JF_OP_MASK) { 412 /* 413 * These operations just turn into a different op 414 * depending on the jail's current status. 415 */ 416 case JF_START_SET: 417 j->flags = j->jid < 0 ? JF_START : JF_SET; 418 break; 419 case JF_SET_RESTART: 420 if (j->jid < 0) { 421 jail_quoted_warnx(j, "not found", 422 "no jail specified"); 423 failed(j); 424 continue; 425 } 426 j->flags = rdtun_params(j, 0) ? JF_RESTART : JF_SET; 427 if (j->flags == JF_RESTART) 428 dep_reset(j); 429 break; 430 case JF_START_SET_RESTART: 431 j->flags = j->jid < 0 ? JF_START 432 : rdtun_params(j, 0) ? JF_RESTART : JF_SET; 433 if (j->flags == JF_RESTART) 434 dep_reset(j); 435 } 436 437 switch (j->flags & JF_OP_MASK) { 438 case JF_START: 439 if (j->comparam == NULL) { 440 if (j->jid > 0 && 441 !(j->flags & (JF_DEPEND | JF_WILD))) { 442 jail_quoted_warnx(j, "already exists", 443 NULL); 444 failed(j); 445 continue; 446 } 447 if (dep_check(j)) 448 continue; 449 if (j->jid > 0) 450 goto jail_create_done; 451 j->comparam = startcommands; 452 j->comstring = NULL; 453 } 454 if (next_command(j)) 455 continue; 456 jail_create_done: 457 clear_persist(j); 458 if (jfp != NULL) 459 print_jail(jfp, j, oldcl, 1); 460 dep_done(j, 0); 461 break; 462 463 case JF_SET: 464 if (j->jid < 0 && !(j->flags & JF_DEPEND)) { 465 jail_quoted_warnx(j, "not found", 466 "no jail specified"); 467 failed(j); 468 continue; 469 } 470 if (dep_check(j)) 471 continue; 472 if (!(j->flags & JF_DEPEND)) { 473 if (rdtun_params(j, 1) < 0 || 474 update_jail(j) < 0) 475 continue; 476 if (verbose >= 0 && (j->name || verbose > 0)) 477 jail_note(j, "updated\n"); 478 } 479 dep_done(j, 0); 480 break; 481 482 case JF_STOP: 483 case JF_RESTART: 484 if (j->comparam == NULL) { 485 if (dep_check(j)) 486 continue; 487 if (j->jid < 0) { 488 if (!(j->flags & (JF_DEPEND|JF_WILD))) { 489 if (verbose >= 0) 490 jail_quoted_warnx(j, 491 "not found", NULL); 492 failed(j); 493 } 494 goto jail_remove_done; 495 } 496 j->comparam = stopcommands; 497 j->comstring = NULL; 498 } else if ((j->flags & JF_FAILED) && j->jid > 0) 499 goto jail_remove_done; 500 if (next_command(j)) 501 continue; 502 jail_remove_done: 503 dep_done(j, 0); 504 if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { 505 j->comparam = NULL; 506 j->flags &= ~JF_STOP; 507 dep_reset(j); 508 requeue(j, j->ndeps ? &depend : &ready); 509 } 510 break; 511 } 512 } 513 514 if (jfp != NULL) 515 fclose(jfp); 516 exit(error); 517 } 518 519 /* 520 * Mark a jail's failure for future handling. 521 */ 522 void 523 failed(struct cfjail *j) 524 { 525 j->flags |= JF_FAILED; 526 TAILQ_REMOVE(j->queue, j, tq); 527 TAILQ_INSERT_HEAD(&ready, j, tq); 528 j->queue = &ready; 529 } 530 531 /* 532 * Exit slightly more gracefully when out of memory. 533 */ 534 void * 535 emalloc(size_t size) 536 { 537 void *p; 538 539 p = malloc(size); 540 if (!p) 541 err(1, "malloc"); 542 return p; 543 } 544 545 void * 546 erealloc(void *ptr, size_t size) 547 { 548 void *p; 549 550 p = realloc(ptr, size); 551 if (!p) 552 err(1, "malloc"); 553 return p; 554 } 555 556 char * 557 estrdup(const char *str) 558 { 559 char *ns; 560 561 ns = strdup(str); 562 if (!ns) 563 err(1, "malloc"); 564 return ns; 565 } 566 567 /* 568 * Print a message including an optional jail name. 569 */ 570 void 571 jail_note(const struct cfjail *j, const char *fmt, ...) 572 { 573 va_list ap, tap; 574 char *cs; 575 size_t len; 576 577 va_start(ap, fmt); 578 va_copy(tap, ap); 579 len = vsnprintf(NULL, 0, fmt, tap); 580 va_end(tap); 581 cs = alloca(len + 1); 582 (void)vsnprintf(cs, len + 1, fmt, ap); 583 va_end(ap); 584 if (j->name) 585 printf("%s: %s", j->name, cs); 586 else 587 printf("%s", cs); 588 } 589 590 /* 591 * Print a warning message including an optional jail name. 592 */ 593 void 594 jail_warnx(const struct cfjail *j, const char *fmt, ...) 595 { 596 va_list ap, tap; 597 char *cs; 598 size_t len; 599 600 va_start(ap, fmt); 601 va_copy(tap, ap); 602 len = vsnprintf(NULL, 0, fmt, tap); 603 va_end(tap); 604 cs = alloca(len + 1); 605 (void)vsnprintf(cs, len + 1, fmt, ap); 606 va_end(ap); 607 if (j->name) 608 warnx("%s: %s", j->name, cs); 609 else 610 warnx("%s", cs); 611 } 612 613 /* 614 * Create a new jail. 615 */ 616 int 617 create_jail(struct cfjail *j) 618 { 619 struct stat st; 620 struct jailparam *jp, *setparams, *sjp; 621 const char *path; 622 int dopersist, ns; 623 624 /* 625 * Check the jail's path, with a better error message than jail_set 626 * gives. 627 */ 628 if ((path = string_param(j->intparams[KP_PATH]))) { 629 if (j->name != NULL && path[0] != '/') { 630 jail_warnx(j, "path %s: not an absolute pathname", 631 path); 632 return -1; 633 } 634 if (stat(path, &st) < 0) { 635 jail_warnx(j, "path %s: %s", path, strerror(errno)); 636 return -1; 637 } 638 if (!S_ISDIR(st.st_mode)) { 639 jail_warnx(j, "path %s: %s", path, strerror(ENOTDIR)); 640 return -1; 641 } 642 } 643 644 /* 645 * Copy all the parameters, except that "persist" is always set when 646 * there are commands to run later. 647 */ 648 dopersist = !bool_param(j->intparams[KP_PERSIST]) && 649 (j->intparams[IP_EXEC_START] || j->intparams[IP_COMMAND] || 650 j->intparams[IP_EXEC_POSTSTART]); 651 sjp = setparams = 652 alloca((j->njp + dopersist) * sizeof(struct jailparam)); 653 if (dopersist && jailparam_init(sjp++, "persist") < 0) { 654 jail_warnx(j, "%s", jail_errmsg); 655 return -1; 656 } 657 for (jp = j->jp; jp < j->jp + j->njp; jp++) 658 if (!dopersist || !equalopts(jp->jp_name, "persist")) 659 *sjp++ = *jp; 660 ns = sjp - setparams; 661 662 j->jid = jailparam_set_note(j, setparams, ns, JAIL_CREATE); 663 if (j->jid < 0) { 664 jail_warnx(j, "%s", jail_errmsg); 665 failed(j); 666 } 667 if (dopersist) { 668 jailparam_free(setparams, 1); 669 if (j->jid > 0) 670 j->flags |= JF_PERSIST; 671 } 672 return j->jid; 673 } 674 675 /* 676 * Remove a temporarily set "persist" parameter. 677 */ 678 static void 679 clear_persist(struct cfjail *j) 680 { 681 struct iovec jiov[4]; 682 int jid; 683 684 if (!(j->flags & JF_PERSIST)) 685 return; 686 j->flags &= ~JF_PERSIST; 687 jiov[0].iov_base = __DECONST(char *, "jid"); 688 jiov[0].iov_len = sizeof("jid"); 689 jiov[1].iov_base = &j->jid; 690 jiov[1].iov_len = sizeof(j->jid); 691 jiov[2].iov_base = __DECONST(char *, "nopersist"); 692 jiov[2].iov_len = sizeof("nopersist"); 693 jiov[3].iov_base = NULL; 694 jiov[3].iov_len = 0; 695 jid = jail_set(jiov, 4, JAIL_UPDATE); 696 if (verbose > 0) 697 jail_note(j, "jail_set(JAIL_UPDATE) jid=%d nopersist%s%s\n", 698 j->jid, jid < 0 ? ": " : "", 699 jid < 0 ? strerror(errno) : ""); 700 } 701 702 /* 703 * Set a jail's parameters. 704 */ 705 static int 706 update_jail(struct cfjail *j) 707 { 708 struct jailparam *jp, *setparams, *sjp; 709 int ns, jid; 710 711 ns = 0; 712 for (jp = j->jp; jp < j->jp + j->njp; jp++) 713 if (!JP_RDTUN(jp)) 714 ns++; 715 if (ns == 0) 716 return 0; 717 sjp = setparams = alloca(++ns * sizeof(struct jailparam)); 718 if (jailparam_init(sjp, "jid") < 0 || 719 jailparam_import_raw(sjp, &j->jid, sizeof j->jid) < 0) { 720 jail_warnx(j, "%s", jail_errmsg); 721 failed(j); 722 return -1; 723 } 724 for (jp = j->jp; jp < j->jp + j->njp; jp++) 725 if (!JP_RDTUN(jp)) 726 *++sjp = *jp; 727 728 jid = jailparam_set_note(j, setparams, ns, JAIL_UPDATE); 729 if (jid < 0) { 730 jail_warnx(j, "%s", jail_errmsg); 731 failed(j); 732 } 733 jailparam_free(setparams, 1); 734 return jid; 735 } 736 737 /* 738 * Return if a jail set would change any create-only parameters. 739 */ 740 static int 741 rdtun_params(struct cfjail *j, int dofail) 742 { 743 struct jailparam *jp, *rtparams, *rtjp; 744 const void *jp_value; 745 size_t jp_valuelen; 746 int nrt, rval, bool_true; 747 748 if (j->flags & JF_RDTUN) 749 return 0; 750 j->flags |= JF_RDTUN; 751 nrt = 0; 752 for (jp = j->jp; jp < j->jp + j->njp; jp++) 753 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 754 nrt++; 755 if (nrt == 0) 756 return 0; 757 rtjp = rtparams = alloca(++nrt * sizeof(struct jailparam)); 758 if (jailparam_init(rtjp, "jid") < 0 || 759 jailparam_import_raw(rtjp, &j->jid, sizeof j->jid) < 0) { 760 jail_warnx(j, "%s", jail_errmsg); 761 exit(1); 762 } 763 for (jp = j->jp; jp < j->jp + j->njp; jp++) 764 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 765 *++rtjp = *jp; 766 rtjp->jp_value = NULL; 767 } 768 rval = 0; 769 if (jailparam_get(rtparams, nrt, 0) > 0) { 770 rtjp = rtparams + 1; 771 for (jp = j->jp; rtjp < rtparams + nrt; jp++) { 772 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 773 jp_value = jp->jp_value; 774 jp_valuelen = jp->jp_valuelen; 775 if (jp_value == NULL && jp_valuelen > 0) { 776 if (jp->jp_flags & (JP_BOOL | 777 JP_NOBOOL | JP_JAILSYS)) { 778 bool_true = 1; 779 jp_value = &bool_true; 780 jp_valuelen = sizeof(bool_true); 781 } else if ((jp->jp_ctltype & CTLTYPE) == 782 CTLTYPE_STRING) 783 jp_value = ""; 784 else 785 jp_valuelen = 0; 786 } 787 if (rtjp->jp_valuelen != jp_valuelen || 788 (CTLTYPE_STRING ? strncmp(rtjp->jp_value, 789 jp_value, jp_valuelen) 790 : memcmp(rtjp->jp_value, jp_value, 791 jp_valuelen))) { 792 if (dofail) { 793 jail_warnx(j, "%s cannot be " 794 "changed after creation", 795 jp->jp_name); 796 failed(j); 797 rval = -1; 798 } else 799 rval = 1; 800 break; 801 } 802 rtjp++; 803 } 804 } 805 } 806 for (rtjp = rtparams + 1; rtjp < rtparams + nrt; rtjp++) 807 rtjp->jp_name = NULL; 808 jailparam_free(rtparams, nrt); 809 return rval; 810 } 811 812 /* 813 * Get the jail's jid if it is running. 814 */ 815 static void 816 running_jid(struct cfjail *j) 817 { 818 struct iovec jiov[2]; 819 const char *pval; 820 char *ep; 821 int jid; 822 823 if ((pval = string_param(j->intparams[KP_JID]))) { 824 if (!(jid = strtol(pval, &ep, 10)) || *ep) { 825 j->jid = -1; 826 return; 827 } 828 jiov[0].iov_base = __DECONST(char *, "jid"); 829 jiov[0].iov_len = sizeof("jid"); 830 jiov[1].iov_base = &jid; 831 jiov[1].iov_len = sizeof(jid); 832 } else if ((pval = string_param(j->intparams[KP_NAME]))) { 833 jiov[0].iov_base = __DECONST(char *, "name"); 834 jiov[0].iov_len = sizeof("name"); 835 jiov[1].iov_len = strlen(pval) + 1; 836 jiov[1].iov_base = alloca(jiov[1].iov_len); 837 strcpy(jiov[1].iov_base, pval); 838 } else { 839 j->jid = -1; 840 return; 841 } 842 j->jid = jail_get(jiov, 2, 0); 843 } 844 845 static void 846 jail_quoted_warnx(const struct cfjail *j, const char *name_msg, 847 const char *noname_msg) 848 { 849 const char *pval; 850 851 if ((pval = j->name) || (pval = string_param(j->intparams[KP_JID])) || 852 (pval = string_param(j->intparams[KP_NAME]))) 853 warnx("\"%s\" %s", pval, name_msg); 854 else 855 warnx("%s", noname_msg); 856 } 857 858 /* 859 * Set jail parameters and possibly print them out. 860 */ 861 static int 862 jailparam_set_note(const struct cfjail *j, struct jailparam *jp, unsigned njp, 863 int flags) 864 { 865 char *value; 866 int jid; 867 unsigned i; 868 869 jid = jailparam_set(jp, njp, flags); 870 if (verbose > 0) { 871 jail_note(j, "jail_set(%s)", 872 (flags & (JAIL_CREATE | JAIL_UPDATE)) == JAIL_CREATE 873 ? "JAIL_CREATE" : "JAIL_UPDATE"); 874 for (i = 0; i < njp; i++) { 875 printf(" %s", jp[i].jp_name); 876 if (jp[i].jp_value == NULL) 877 continue; 878 putchar('='); 879 value = jailparam_export(jp + i); 880 if (value == NULL) 881 err(1, "jailparam_export"); 882 quoted_print(stdout, value); 883 free(value); 884 } 885 if (jid < 0) 886 printf(": %s", strerror(errno)); 887 printf("\n"); 888 } 889 return jid; 890 } 891 892 /* 893 * Print a jail record. 894 */ 895 static void 896 print_jail(FILE *fp, struct cfjail *j, int oldcl, int running) 897 { 898 struct cfparam *p; 899 int printsep; 900 901 if (oldcl) { 902 if (running) 903 fprintf(fp, "%d%s", j->jid, separator); 904 print_param(fp, j->intparams[KP_PATH], ',', 0); 905 fputs(separator, fp); 906 print_param(fp, j->intparams[KP_HOST_HOSTNAME], ',', 0); 907 fputs(separator, fp); 908 #ifdef INET 909 print_param(fp, j->intparams[KP_IP4_ADDR], ',', 0); 910 #ifdef INET6 911 if (j->intparams[KP_IP4_ADDR] && 912 !TAILQ_EMPTY(&j->intparams[KP_IP4_ADDR]->val) && 913 j->intparams[KP_IP6_ADDR] && 914 !TAILQ_EMPTY(&j->intparams[KP_IP6_ADDR]->val)) 915 putc(',', fp); 916 #endif 917 #endif 918 #ifdef INET6 919 print_param(fp, j->intparams[KP_IP6_ADDR], ',', 0); 920 #endif 921 fputs(separator, fp); 922 print_param(fp, j->intparams[IP_COMMAND], ' ', 0); 923 } else { 924 printsep = 0; 925 if (running) { 926 fprintf(fp, "jid=%d", j->jid); 927 printsep = 1; 928 } 929 TAILQ_FOREACH(p, &j->params, tq) 930 if (strcmp(p->name, "jid")) { 931 if (printsep) 932 fputs(separator, fp); 933 else 934 printsep = 1; 935 print_param(fp, p, ',', 1); 936 } 937 } 938 putc('\n', fp); 939 } 940 941 /* 942 * Exhibit list of all configured non-wildcard jails 943 */ 944 static void 945 show_jails(void) 946 { 947 struct cfjail *j; 948 949 TAILQ_FOREACH(j, &cfjails, tq) 950 print_jail(stdout, j, 0, 0); 951 } 952 953 /* 954 * Print a parameter value, or a name=value pair. 955 */ 956 static void 957 print_param(FILE *fp, const struct cfparam *p, int sep, int doname) 958 { 959 const struct cfstring *s, *ts; 960 961 if (doname) 962 fputs(p->name, fp); 963 if (p == NULL || TAILQ_EMPTY(&p->val)) 964 return; 965 if (doname) 966 putc('=', fp); 967 TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 968 quoted_print(fp, s->s); 969 if (ts != NULL) 970 putc(sep, fp); 971 } 972 } 973 974 /* 975 * Print a string with quotes around spaces. 976 */ 977 static void 978 quoted_print(FILE *fp, char *str) 979 { 980 int c, qc; 981 char *p = str; 982 983 qc = !*p ? '"' 984 : strchr(p, '\'') ? '"' 985 : strchr(p, '"') ? '\'' 986 : strchr(p, ' ') || strchr(p, '\t') ? '"' 987 : 0; 988 if (qc) 989 putc(qc, fp); 990 while ((c = *p++)) { 991 if (c == '\\' || c == qc) 992 putc('\\', fp); 993 putc(c, fp); 994 } 995 if (qc) 996 putc(qc, fp); 997 } 998 999 static void 1000 usage(void) 1001 { 1002 1003 (void)fprintf(stderr, 1004 "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1005 " -[cmr] param=value ... [command=command ...]\n" 1006 " jail [-dqv] [-f file] -[cmr] [jail]\n" 1007 " jail [-qv] [-f file] -[rR] ['*' | jail ...]\n" 1008 " jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1009 " [-n jailname] [-s securelevel]\n" 1010 " path hostname ip[,...] command ...\n" 1011 " jail [-f file] -e separator\n"); 1012 exit(1); 1013 } 1014