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_ZFS_DATASET, 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, dying_warned, 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 dying_warned = 0; 382 while ((j = next_jail())) 383 { 384 if (j->flags & JF_FAILED) { 385 error = 1; 386 if (j->comparam == NULL) { 387 dep_done(j, 0); 388 continue; 389 } 390 } 391 if (!(j->flags & JF_PARAMS)) 392 { 393 j->flags |= JF_PARAMS; 394 if (dflag) 395 add_param(j, NULL, IP_ALLOW_DYING, NULL); 396 if (check_intparams(j) < 0) 397 continue; 398 if ((j->flags & (JF_START | JF_SET)) && 399 import_params(j) < 0) 400 continue; 401 } 402 if (j->intparams[IP_ALLOW_DYING] && !dying_warned) { 403 warnx("%s", "the 'allow.dying' parameter and '-d' flag" 404 "are deprecated and have no effect."); 405 dying_warned = 1; 406 } 407 if (!j->jid) 408 running_jid(j); 409 if (finish_command(j)) 410 continue; 411 412 switch (j->flags & JF_OP_MASK) { 413 /* 414 * These operations just turn into a different op 415 * depending on the jail's current status. 416 */ 417 case JF_START_SET: 418 j->flags = j->jid < 0 ? JF_START : JF_SET; 419 break; 420 case JF_SET_RESTART: 421 if (j->jid < 0) { 422 jail_quoted_warnx(j, "not found", 423 "no jail specified"); 424 failed(j); 425 continue; 426 } 427 j->flags = rdtun_params(j, 0) ? JF_RESTART : JF_SET; 428 if (j->flags == JF_RESTART) 429 dep_reset(j); 430 break; 431 case JF_START_SET_RESTART: 432 j->flags = j->jid < 0 ? JF_START 433 : rdtun_params(j, 0) ? JF_RESTART : JF_SET; 434 if (j->flags == JF_RESTART) 435 dep_reset(j); 436 } 437 438 switch (j->flags & JF_OP_MASK) { 439 case JF_START: 440 if (j->comparam == NULL) { 441 if (j->jid > 0 && 442 !(j->flags & (JF_DEPEND | JF_WILD))) { 443 jail_quoted_warnx(j, "already exists", 444 NULL); 445 failed(j); 446 continue; 447 } 448 if (dep_check(j)) 449 continue; 450 if (j->jid > 0) 451 goto jail_create_done; 452 j->comparam = startcommands; 453 j->comstring = NULL; 454 } 455 if (next_command(j)) 456 continue; 457 jail_create_done: 458 clear_persist(j); 459 if (jfp != NULL) 460 print_jail(jfp, j, oldcl, 1); 461 dep_done(j, 0); 462 break; 463 464 case JF_SET: 465 if (j->jid < 0 && !(j->flags & JF_DEPEND)) { 466 jail_quoted_warnx(j, "not found", 467 "no jail specified"); 468 failed(j); 469 continue; 470 } 471 if (dep_check(j)) 472 continue; 473 if (!(j->flags & JF_DEPEND)) { 474 if (rdtun_params(j, 1) < 0 || 475 update_jail(j) < 0) 476 continue; 477 if (verbose >= 0 && (j->name || verbose > 0)) 478 jail_note(j, "updated\n"); 479 } 480 dep_done(j, 0); 481 break; 482 483 case JF_STOP: 484 case JF_RESTART: 485 if (j->comparam == NULL) { 486 if (dep_check(j)) 487 continue; 488 if (j->jid < 0) { 489 if (!(j->flags & (JF_DEPEND|JF_WILD))) { 490 if (verbose >= 0) 491 jail_quoted_warnx(j, 492 "not found", NULL); 493 failed(j); 494 } 495 goto jail_remove_done; 496 } 497 j->comparam = stopcommands; 498 j->comstring = NULL; 499 } else if ((j->flags & JF_FAILED) && j->jid > 0) 500 goto jail_remove_done; 501 if (next_command(j)) 502 continue; 503 jail_remove_done: 504 dep_done(j, 0); 505 if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { 506 j->comparam = NULL; 507 j->flags &= ~JF_STOP; 508 dep_reset(j); 509 requeue(j, j->ndeps ? &depend : &ready); 510 } 511 break; 512 } 513 } 514 515 if (jfp != NULL) 516 fclose(jfp); 517 exit(error); 518 } 519 520 /* 521 * Mark a jail's failure for future handling. 522 */ 523 void 524 failed(struct cfjail *j) 525 { 526 j->flags |= JF_FAILED; 527 TAILQ_REMOVE(j->queue, j, tq); 528 TAILQ_INSERT_HEAD(&ready, j, tq); 529 j->queue = &ready; 530 } 531 532 /* 533 * Exit slightly more gracefully when out of memory. 534 */ 535 void * 536 emalloc(size_t size) 537 { 538 void *p; 539 540 p = malloc(size); 541 if (!p) 542 err(1, "malloc"); 543 return p; 544 } 545 546 void * 547 erealloc(void *ptr, size_t size) 548 { 549 void *p; 550 551 p = realloc(ptr, size); 552 if (!p) 553 err(1, "malloc"); 554 return p; 555 } 556 557 char * 558 estrdup(const char *str) 559 { 560 char *ns; 561 562 ns = strdup(str); 563 if (!ns) 564 err(1, "malloc"); 565 return ns; 566 } 567 568 /* 569 * Print a message including an optional jail name. 570 */ 571 void 572 jail_note(const struct cfjail *j, const char *fmt, ...) 573 { 574 va_list ap, tap; 575 char *cs; 576 size_t len; 577 578 va_start(ap, fmt); 579 va_copy(tap, ap); 580 len = vsnprintf(NULL, 0, fmt, tap); 581 va_end(tap); 582 cs = alloca(len + 1); 583 (void)vsnprintf(cs, len + 1, fmt, ap); 584 va_end(ap); 585 if (j->name) 586 printf("%s: %s", j->name, cs); 587 else 588 printf("%s", cs); 589 } 590 591 /* 592 * Print a warning message including an optional jail name. 593 */ 594 void 595 jail_warnx(const struct cfjail *j, const char *fmt, ...) 596 { 597 va_list ap, tap; 598 char *cs; 599 size_t len; 600 601 va_start(ap, fmt); 602 va_copy(tap, ap); 603 len = vsnprintf(NULL, 0, fmt, tap); 604 va_end(tap); 605 cs = alloca(len + 1); 606 (void)vsnprintf(cs, len + 1, fmt, ap); 607 va_end(ap); 608 if (j->name) 609 warnx("%s: %s", j->name, cs); 610 else 611 warnx("%s", cs); 612 } 613 614 /* 615 * Create a new jail. 616 */ 617 int 618 create_jail(struct cfjail *j) 619 { 620 struct stat st; 621 struct jailparam *jp, *setparams, *sjp; 622 const char *path; 623 int dopersist, ns; 624 625 /* 626 * Check the jail's path, with a better error message than jail_set 627 * gives. 628 */ 629 if ((path = string_param(j->intparams[KP_PATH]))) { 630 if (j->name != NULL && path[0] != '/') { 631 jail_warnx(j, "path %s: not an absolute pathname", 632 path); 633 return -1; 634 } 635 if (stat(path, &st) < 0) { 636 jail_warnx(j, "path %s: %s", path, strerror(errno)); 637 return -1; 638 } 639 if (!S_ISDIR(st.st_mode)) { 640 jail_warnx(j, "path %s: %s", path, strerror(ENOTDIR)); 641 return -1; 642 } 643 } 644 645 /* 646 * Copy all the parameters, except that "persist" is always set when 647 * there are commands to run later. 648 */ 649 dopersist = !bool_param(j->intparams[KP_PERSIST]) && 650 (j->intparams[IP_EXEC_START] || j->intparams[IP_COMMAND] || 651 j->intparams[IP_EXEC_POSTSTART]); 652 sjp = setparams = 653 alloca((j->njp + dopersist) * sizeof(struct jailparam)); 654 if (dopersist && jailparam_init(sjp++, "persist") < 0) { 655 jail_warnx(j, "%s", jail_errmsg); 656 return -1; 657 } 658 for (jp = j->jp; jp < j->jp + j->njp; jp++) 659 if (!dopersist || !equalopts(jp->jp_name, "persist")) 660 *sjp++ = *jp; 661 ns = sjp - setparams; 662 663 j->jid = jailparam_set_note(j, setparams, ns, JAIL_CREATE); 664 if (j->jid < 0) { 665 jail_warnx(j, "%s", jail_errmsg); 666 failed(j); 667 } 668 if (dopersist) { 669 jailparam_free(setparams, 1); 670 if (j->jid > 0) 671 j->flags |= JF_PERSIST; 672 } 673 return j->jid; 674 } 675 676 /* 677 * Remove a temporarily set "persist" parameter. 678 */ 679 static void 680 clear_persist(struct cfjail *j) 681 { 682 struct iovec jiov[4]; 683 int jid; 684 685 if (!(j->flags & JF_PERSIST)) 686 return; 687 j->flags &= ~JF_PERSIST; 688 jiov[0].iov_base = __DECONST(char *, "jid"); 689 jiov[0].iov_len = sizeof("jid"); 690 jiov[1].iov_base = &j->jid; 691 jiov[1].iov_len = sizeof(j->jid); 692 jiov[2].iov_base = __DECONST(char *, "nopersist"); 693 jiov[2].iov_len = sizeof("nopersist"); 694 jiov[3].iov_base = NULL; 695 jiov[3].iov_len = 0; 696 jid = jail_set(jiov, 4, JAIL_UPDATE); 697 if (verbose > 0) 698 jail_note(j, "jail_set(JAIL_UPDATE) jid=%d nopersist%s%s\n", 699 j->jid, jid < 0 ? ": " : "", 700 jid < 0 ? strerror(errno) : ""); 701 } 702 703 /* 704 * Set a jail's parameters. 705 */ 706 static int 707 update_jail(struct cfjail *j) 708 { 709 struct jailparam *jp, *setparams, *sjp; 710 int ns, jid; 711 712 ns = 0; 713 for (jp = j->jp; jp < j->jp + j->njp; jp++) 714 if (!JP_RDTUN(jp)) 715 ns++; 716 if (ns == 0) 717 return 0; 718 sjp = setparams = alloca(++ns * sizeof(struct jailparam)); 719 if (jailparam_init(sjp, "jid") < 0 || 720 jailparam_import_raw(sjp, &j->jid, sizeof j->jid) < 0) { 721 jail_warnx(j, "%s", jail_errmsg); 722 failed(j); 723 return -1; 724 } 725 for (jp = j->jp; jp < j->jp + j->njp; jp++) 726 if (!JP_RDTUN(jp)) 727 *++sjp = *jp; 728 729 jid = jailparam_set_note(j, setparams, ns, JAIL_UPDATE); 730 if (jid < 0) { 731 jail_warnx(j, "%s", jail_errmsg); 732 failed(j); 733 } 734 jailparam_free(setparams, 1); 735 return jid; 736 } 737 738 /* 739 * Return if a jail set would change any create-only parameters. 740 */ 741 static int 742 rdtun_params(struct cfjail *j, int dofail) 743 { 744 struct jailparam *jp, *rtparams, *rtjp; 745 const void *jp_value; 746 size_t jp_valuelen; 747 int nrt, rval, bool_true; 748 749 if (j->flags & JF_RDTUN) 750 return 0; 751 j->flags |= JF_RDTUN; 752 nrt = 0; 753 for (jp = j->jp; jp < j->jp + j->njp; jp++) 754 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 755 nrt++; 756 if (nrt == 0) 757 return 0; 758 rtjp = rtparams = alloca(++nrt * sizeof(struct jailparam)); 759 if (jailparam_init(rtjp, "jid") < 0 || 760 jailparam_import_raw(rtjp, &j->jid, sizeof j->jid) < 0) { 761 jail_warnx(j, "%s", jail_errmsg); 762 exit(1); 763 } 764 for (jp = j->jp; jp < j->jp + j->njp; jp++) 765 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 766 *++rtjp = *jp; 767 rtjp->jp_value = NULL; 768 } 769 rval = 0; 770 if (jailparam_get(rtparams, nrt, 0) > 0) { 771 rtjp = rtparams + 1; 772 for (jp = j->jp; rtjp < rtparams + nrt; jp++) { 773 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 774 jp_value = jp->jp_value; 775 jp_valuelen = jp->jp_valuelen; 776 if (jp_value == NULL && jp_valuelen > 0) { 777 if (jp->jp_flags & (JP_BOOL | 778 JP_NOBOOL | JP_JAILSYS)) { 779 bool_true = 1; 780 jp_value = &bool_true; 781 jp_valuelen = sizeof(bool_true); 782 } else if ((jp->jp_ctltype & CTLTYPE) == 783 CTLTYPE_STRING) 784 jp_value = ""; 785 else 786 jp_valuelen = 0; 787 } 788 if (rtjp->jp_valuelen != jp_valuelen || 789 (CTLTYPE_STRING ? strncmp(rtjp->jp_value, 790 jp_value, jp_valuelen) 791 : memcmp(rtjp->jp_value, jp_value, 792 jp_valuelen))) { 793 if (dofail) { 794 jail_warnx(j, "%s cannot be " 795 "changed after creation", 796 jp->jp_name); 797 failed(j); 798 rval = -1; 799 } else 800 rval = 1; 801 break; 802 } 803 rtjp++; 804 } 805 } 806 } 807 for (rtjp = rtparams + 1; rtjp < rtparams + nrt; rtjp++) 808 rtjp->jp_name = NULL; 809 jailparam_free(rtparams, nrt); 810 return rval; 811 } 812 813 /* 814 * Get the jail's jid if it is running. 815 */ 816 static void 817 running_jid(struct cfjail *j) 818 { 819 struct iovec jiov[2]; 820 const char *pval; 821 char *ep; 822 int jid; 823 824 if ((pval = string_param(j->intparams[KP_JID]))) { 825 if (!(jid = strtol(pval, &ep, 10)) || *ep) { 826 j->jid = -1; 827 return; 828 } 829 jiov[0].iov_base = __DECONST(char *, "jid"); 830 jiov[0].iov_len = sizeof("jid"); 831 jiov[1].iov_base = &jid; 832 jiov[1].iov_len = sizeof(jid); 833 } else if ((pval = string_param(j->intparams[KP_NAME]))) { 834 jiov[0].iov_base = __DECONST(char *, "name"); 835 jiov[0].iov_len = sizeof("name"); 836 jiov[1].iov_len = strlen(pval) + 1; 837 jiov[1].iov_base = alloca(jiov[1].iov_len); 838 strcpy(jiov[1].iov_base, pval); 839 } else { 840 j->jid = -1; 841 return; 842 } 843 j->jid = jail_get(jiov, 2, 0); 844 } 845 846 static void 847 jail_quoted_warnx(const struct cfjail *j, const char *name_msg, 848 const char *noname_msg) 849 { 850 const char *pval; 851 852 if ((pval = j->name) || (pval = string_param(j->intparams[KP_JID])) || 853 (pval = string_param(j->intparams[KP_NAME]))) 854 warnx("\"%s\" %s", pval, name_msg); 855 else 856 warnx("%s", noname_msg); 857 } 858 859 /* 860 * Set jail parameters and possibly print them out. 861 */ 862 static int 863 jailparam_set_note(const struct cfjail *j, struct jailparam *jp, unsigned njp, 864 int flags) 865 { 866 char *value; 867 int jid; 868 unsigned i; 869 870 jid = jailparam_set(jp, njp, flags); 871 if (verbose > 0) { 872 jail_note(j, "jail_set(%s)", 873 (flags & (JAIL_CREATE | JAIL_UPDATE)) == JAIL_CREATE 874 ? "JAIL_CREATE" : "JAIL_UPDATE"); 875 for (i = 0; i < njp; i++) { 876 printf(" %s", jp[i].jp_name); 877 if (jp[i].jp_value == NULL) 878 continue; 879 putchar('='); 880 value = jailparam_export(jp + i); 881 if (value == NULL) 882 err(1, "jailparam_export"); 883 quoted_print(stdout, value); 884 free(value); 885 } 886 if (jid < 0) 887 printf(": %s", strerror(errno)); 888 printf("\n"); 889 } 890 return jid; 891 } 892 893 /* 894 * Print a jail record. 895 */ 896 static void 897 print_jail(FILE *fp, struct cfjail *j, int oldcl, int running) 898 { 899 struct cfparam *p; 900 int printsep; 901 902 if (oldcl) { 903 if (running) 904 fprintf(fp, "%d%s", j->jid, separator); 905 print_param(fp, j->intparams[KP_PATH], ',', 0); 906 fputs(separator, fp); 907 print_param(fp, j->intparams[KP_HOST_HOSTNAME], ',', 0); 908 fputs(separator, fp); 909 #ifdef INET 910 print_param(fp, j->intparams[KP_IP4_ADDR], ',', 0); 911 #ifdef INET6 912 if (j->intparams[KP_IP4_ADDR] && 913 !TAILQ_EMPTY(&j->intparams[KP_IP4_ADDR]->val) && 914 j->intparams[KP_IP6_ADDR] && 915 !TAILQ_EMPTY(&j->intparams[KP_IP6_ADDR]->val)) 916 putc(',', fp); 917 #endif 918 #endif 919 #ifdef INET6 920 print_param(fp, j->intparams[KP_IP6_ADDR], ',', 0); 921 #endif 922 fputs(separator, fp); 923 print_param(fp, j->intparams[IP_COMMAND], ' ', 0); 924 } else { 925 printsep = 0; 926 if (running) { 927 fprintf(fp, "jid=%d", j->jid); 928 printsep = 1; 929 } 930 TAILQ_FOREACH(p, &j->params, tq) 931 if (strcmp(p->name, "jid")) { 932 if (printsep) 933 fputs(separator, fp); 934 else 935 printsep = 1; 936 print_param(fp, p, ',', 1); 937 } 938 } 939 putc('\n', fp); 940 } 941 942 /* 943 * Exhibit list of all configured non-wildcard jails 944 */ 945 static void 946 show_jails(void) 947 { 948 struct cfjail *j; 949 950 TAILQ_FOREACH(j, &cfjails, tq) 951 print_jail(stdout, j, 0, 0); 952 } 953 954 /* 955 * Print a parameter value, or a name=value pair. 956 */ 957 static void 958 print_param(FILE *fp, const struct cfparam *p, int sep, int doname) 959 { 960 const struct cfstring *s, *ts; 961 962 if (doname) 963 fputs(p->name, fp); 964 if (p == NULL || TAILQ_EMPTY(&p->val)) 965 return; 966 if (doname) 967 putc('=', fp); 968 TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 969 quoted_print(fp, s->s); 970 if (ts != NULL) 971 putc(sep, fp); 972 } 973 } 974 975 /* 976 * Print a string with quotes around spaces. 977 */ 978 static void 979 quoted_print(FILE *fp, char *str) 980 { 981 int c, qc; 982 char *p = str; 983 984 qc = !*p ? '"' 985 : strchr(p, '\'') ? '"' 986 : strchr(p, '"') ? '\'' 987 : strchr(p, ' ') || strchr(p, '\t') ? '"' 988 : 0; 989 if (qc) 990 putc(qc, fp); 991 while ((c = *p++)) { 992 if (c == '\\' || c == qc) 993 putc('\\', fp); 994 putc(c, fp); 995 } 996 if (qc) 997 putc(qc, fp); 998 } 999 1000 static void 1001 usage(void) 1002 { 1003 1004 (void)fprintf(stderr, 1005 "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1006 " -[cmr] param=value ... [command=command ...]\n" 1007 " jail [-dqv] [-f file] -[cmr] [jail]\n" 1008 " jail [-qv] [-f file] -[rR] ['*' | jail ...]\n" 1009 " jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1010 " [-n jailname] [-s securelevel]\n" 1011 " path hostname ip[,...] command ...\n" 1012 " jail [-f file] -e separator\n"); 1013 exit(1); 1014 } 1015