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