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 static const enum intparam cleancommands[] = { 132 IP__NULL, 133 IP_EXEC_POSTSTOP, 134 IP_MOUNT_PROCFS, 135 IP_MOUNT_FDESCFS, 136 IP_MOUNT_DEVFS, 137 IP__MOUNT_FROM_FSTAB, 138 IP_MOUNT, 139 #ifdef INET6 140 IP__IP6_IFADDR, 141 #endif 142 #ifdef INET 143 IP__IP4_IFADDR, 144 #endif 145 IP_EXEC_RELEASE, 146 IP__NULL 147 }; 148 149 static const struct { 150 const char *name; 151 enum intparam param; 152 } listparams[] = { 153 #ifdef INET 154 { "ip4.addr", KP_IP4_ADDR }, 155 #endif 156 #ifdef INET6 157 { "ip6.addr", KP_IP6_ADDR }, 158 #endif 159 { "vnet.interface", IP_VNET_INTERFACE }, 160 { "zfs.dataset", IP_ZFS_DATASET }, 161 }; 162 163 int 164 main(int argc, char **argv) 165 { 166 struct stat st; 167 FILE *jfp; 168 struct cfjail *j; 169 char *JidFile; 170 const char *cfname; 171 size_t sysvallen; 172 unsigned op, pi; 173 int ch, docf, dying_warned, error, i, oldcl, sysval; 174 int dflag, eflag, Rflag; 175 #if defined(INET) || defined(INET6) 176 char *cs, *ncs; 177 #endif 178 #if defined(INET) && defined(INET6) 179 struct in6_addr addr6; 180 #endif 181 182 op = 0; 183 dflag = eflag = Rflag = 0; 184 docf = 1; 185 cfname = CONF_FILE; 186 JidFile = NULL; 187 188 while ((ch = getopt(argc, argv, "cCde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) { 189 switch (ch) { 190 case 'c': 191 op |= JF_START; 192 break; 193 case 'C': 194 op |= JF_CLEANUP; 195 break; 196 case 'd': 197 dflag = 1; 198 break; 199 case 'e': 200 eflag = 1; 201 separator = optarg; 202 break; 203 case 'f': 204 cfname = optarg; 205 break; 206 case 'h': 207 #if defined(INET) || defined(INET6) 208 add_param(NULL, NULL, IP_IP_HOSTNAME, NULL); 209 #endif 210 docf = 0; 211 break; 212 case 'i': 213 iflag = 1; 214 verbose = -1; 215 break; 216 case 'J': 217 JidFile = optarg; 218 break; 219 case 'l': 220 add_param(NULL, NULL, IP_EXEC_CLEAN, NULL); 221 docf = 0; 222 break; 223 case 'm': 224 op |= JF_SET; 225 break; 226 case 'n': 227 add_param(NULL, NULL, KP_NAME, optarg); 228 docf = 0; 229 break; 230 case 'p': 231 paralimit = strtol(optarg, NULL, 10); 232 if (paralimit == 0) 233 paralimit = -1; 234 break; 235 case 'q': 236 verbose = -1; 237 break; 238 case 'r': 239 op |= JF_STOP; 240 break; 241 case 'R': 242 op |= JF_STOP; 243 Rflag = 1; 244 break; 245 case 's': 246 add_param(NULL, NULL, KP_SECURELEVEL, optarg); 247 docf = 0; 248 break; 249 case 'u': 250 add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 251 add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, NULL); 252 docf = 0; 253 break; 254 case 'U': 255 add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 256 add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, 257 "false"); 258 docf = 0; 259 break; 260 case 'v': 261 verbose = 1; 262 break; 263 default: 264 usage(); 265 } 266 } 267 argc -= optind; 268 argv += optind; 269 270 if (eflag) { 271 /* Just print list of all configured non-wildcard jails */ 272 if (op || argc > 0) 273 usage(); 274 load_config(cfname); 275 show_jails(); 276 exit(0); 277 } 278 279 /* Find out which of the command line styles this is. */ 280 oldcl = 0; 281 if (!op) { 282 /* Old-style command line with four fixed parameters */ 283 if (argc < 4 || argv[0][0] != '/') 284 usage(); 285 op = JF_START; 286 docf = 0; 287 oldcl = 1; 288 add_param(NULL, NULL, KP_PATH, argv[0]); 289 add_param(NULL, NULL, KP_HOST_HOSTNAME, argv[1]); 290 #if defined(INET) || defined(INET6) 291 if (argv[2][0] != '\0') { 292 for (cs = argv[2];; cs = ncs + 1) { 293 ncs = strchr(cs, ','); 294 if (ncs) 295 *ncs = '\0'; 296 add_param(NULL, NULL, 297 #if defined(INET) && defined(INET6) 298 inet_pton(AF_INET6, cs, &addr6) == 1 299 ? KP_IP6_ADDR : KP_IP4_ADDR, 300 #elif defined(INET) 301 KP_IP4_ADDR, 302 #elif defined(INET6) 303 KP_IP6_ADDR, 304 #endif 305 cs); 306 if (!ncs) 307 break; 308 } 309 } 310 #endif 311 for (i = 3; i < argc; i++) 312 add_param(NULL, NULL, IP_COMMAND, argv[i]); 313 /* Emulate the defaults from security.jail.* sysctls. */ 314 sysvallen = sizeof(sysval); 315 if (sysctlbyname("security.jail.jailed", &sysval, &sysvallen, 316 NULL, 0) == 0 && sysval == 0) { 317 for (pi = 0; pi < sizeof(perm_sysctl) / 318 sizeof(perm_sysctl[0]); pi++) { 319 sysvallen = sizeof(sysval); 320 if (sysctlbyname(perm_sysctl[pi].name, 321 &sysval, &sysvallen, NULL, 0) == 0) 322 add_param(NULL, NULL, 323 perm_sysctl[pi].ipnum, 324 (sysval ? 1 : 0) ^ 325 perm_sysctl[pi].rev 326 ? NULL : "false"); 327 } 328 } 329 } else if (op == JF_STOP) { 330 /* Jail remove, perhaps using the config file */ 331 if (!docf || argc == 0) 332 usage(); 333 if (!Rflag) 334 for (i = 0; i < argc; i++) 335 if (strchr(argv[i], '=')) 336 usage(); 337 if ((docf = !Rflag && 338 (!strcmp(cfname, "-") || stat(cfname, &st) == 0))) 339 load_config(cfname); 340 note_remove = docf || argc > 1 || wild_jail_name(argv[0]); 341 } else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) { 342 /* Single jail specified on the command line */ 343 if (Rflag || (op & JF_CLEANUP)) 344 usage(); 345 docf = 0; 346 for (i = 0; i < argc; i++) { 347 size_t l; 348 349 if (!strncmp(argv[i], "command", 7) && 350 (argv[i][7] == '\0' || argv[i][7] == '=')) { 351 if (argv[i][7] == '=') 352 add_param(NULL, NULL, IP_COMMAND, 353 argv[i] + 8); 354 for (i++; i < argc; i++) 355 add_param(NULL, NULL, IP_COMMAND, 356 argv[i]); 357 continue; 358 } 359 360 /* 361 * Is this parameter a list? 362 */ 363 for (l = 0; l < nitems(listparams); l++) { 364 size_t len; 365 366 len = strlen(listparams[l].name); 367 if (strncmp(argv[i], listparams[l].name, len) || 368 argv[i][len] != '=') 369 continue; 370 371 for (cs = argv[i] + len + 1;; cs = ncs + 1) { 372 ncs = strchr(cs, ','); 373 if (ncs) 374 *ncs = '\0'; 375 add_param(NULL, NULL, 376 listparams[l].param, cs); 377 if (!ncs) 378 break; 379 } 380 break; 381 } 382 if (l == nitems(listparams)) 383 add_param(NULL, NULL, 0, argv[i]); 384 } 385 } else { 386 /* From the config file, perhaps with a specified jail */ 387 if (Rflag || !docf) 388 usage(); 389 load_config(cfname); 390 } 391 392 /* Find out which jails will be run. */ 393 dep_setup(docf); 394 error = 0; 395 if ((op & JF_OP_MASK) == JF_STOP) { 396 for (i = 0; i < argc; i++) 397 if (start_state(argv[i], docf, op, Rflag) < 0) 398 error = 1; 399 } else { 400 if (start_state(argv[0], docf, op, 0) < 0) 401 exit(1); 402 } 403 404 jfp = NULL; 405 if (JidFile != NULL) { 406 jfp = fopen(JidFile, "w"); 407 if (jfp == NULL) 408 err(1, "open %s", JidFile); 409 setlinebuf(jfp); 410 } 411 setlinebuf(stdout); 412 413 /* 414 * The main loop: Get an available jail and perform the required 415 * operation on it. When that is done, the jail may be finished, 416 * or it may go back for the next step. 417 */ 418 dying_warned = 0; 419 while ((j = next_jail())) 420 { 421 if (j->flags & JF_FAILED) { 422 error = 1; 423 if (j->comparam == NULL) { 424 dep_done(j, 0); 425 continue; 426 } 427 } 428 if (!(j->flags & JF_PARAMS)) 429 { 430 j->flags |= JF_PARAMS; 431 if (dflag) 432 add_param(j, NULL, IP_ALLOW_DYING, NULL); 433 if (check_intparams(j) < 0) 434 continue; 435 if ((j->flags & (JF_START | JF_SET)) && 436 import_params(j) < 0) 437 continue; 438 } 439 if (j->intparams[IP_ALLOW_DYING] && !dying_warned) { 440 warnx("%s", "the 'allow.dying' parameter and '-d' flag " 441 "are deprecated and have no effect."); 442 dying_warned = 1; 443 } 444 if (!j->jid) 445 running_jid(j); 446 if (finish_command(j)) 447 continue; 448 449 switch (j->flags & JF_OP_MASK) { 450 /* 451 * These operations just turn into a different op 452 * depending on the jail's current status. 453 */ 454 case JF_START_SET: 455 j->flags = j->jid < 0 456 ? (j->flags & JF_CLEANUP) | JF_START : JF_SET; 457 break; 458 case JF_SET_RESTART: 459 if (j->jid < 0 && !(j->flags & JF_CLEANUP)) { 460 jail_quoted_warnx(j, "not found", 461 "no jail specified"); 462 failed(j); 463 continue; 464 } 465 j->flags = rdtun_params(j, 0) 466 ? (j->flags & JF_CLEANUP) | JF_RESTART : JF_SET; 467 if (j->flags == JF_RESTART) 468 dep_reset(j); 469 break; 470 case JF_START_SET_RESTART: 471 j->flags = j->jid < 0 ? JF_START : rdtun_params(j, 0) 472 ? (j->flags & JF_CLEANUP) | JF_RESTART : JF_SET; 473 if (j->flags == JF_RESTART) 474 dep_reset(j); 475 } 476 477 switch (j->flags & JF_OP_MASK) { 478 case JF_START: 479 if (j->comparam == NULL) { 480 if (j->jid > 0 && 481 !(j->flags & (JF_DEPEND | JF_WILD))) { 482 jail_quoted_warnx(j, "already exists", 483 NULL); 484 failed(j); 485 continue; 486 } 487 if (dep_check(j)) 488 continue; 489 if (j->jid > 0) 490 goto jail_create_done; 491 if (j->flags & JF_CLEANUP) { 492 j->flags |= JF_STOP; 493 j->comparam = cleancommands; 494 } else 495 j->comparam = startcommands; 496 j->comparam = startcommands; 497 j->comstring = NULL; 498 } 499 if (next_command(j)) 500 continue; 501 if (j->flags & JF_STOP) 502 goto jail_remove_done; 503 jail_create_done: 504 clear_persist(j); 505 if (jfp != NULL) 506 print_jail(jfp, j, oldcl, 1); 507 dep_done(j, 0); 508 break; 509 510 case JF_SET: 511 if (j->jid < 0 && !(j->flags & JF_DEPEND)) { 512 jail_quoted_warnx(j, "not found", 513 "no jail specified"); 514 failed(j); 515 continue; 516 } 517 if (dep_check(j)) 518 continue; 519 if (!(j->flags & JF_DEPEND)) { 520 if (rdtun_params(j, 1) < 0 || 521 update_jail(j) < 0) 522 continue; 523 if (verbose >= 0 && (j->name || verbose > 0)) 524 jail_note(j, "updated\n"); 525 } 526 dep_done(j, 0); 527 break; 528 529 case JF_STOP: 530 case JF_RESTART: 531 if (j->comparam == NULL) { 532 if (dep_check(j)) 533 continue; 534 if (j->flags & JF_CLEANUP) { 535 j->comparam = j->jid < 0 536 ? cleancommands : stopcommands; 537 } else if (j->jid < 0) { 538 if (!(j->flags & (JF_DEPEND|JF_WILD))) { 539 if (verbose >= 0) 540 jail_quoted_warnx(j, 541 "not found", NULL); 542 failed(j); 543 } 544 goto jail_remove_done; 545 } 546 else 547 j->comparam = stopcommands; 548 j->comstring = NULL; 549 } else if ((j->flags & JF_FAILED) && j->jid > 0) 550 goto jail_remove_done; 551 if (next_command(j)) 552 continue; 553 jail_remove_done: 554 dep_done(j, 0); 555 if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { 556 j->comparam = NULL; 557 j->flags &= ~(JF_STOP | JF_CLEANUP); 558 dep_reset(j); 559 requeue(j, j->ndeps ? &depend : &ready); 560 } 561 break; 562 } 563 } 564 565 if (jfp != NULL) 566 fclose(jfp); 567 exit(error); 568 } 569 570 /* 571 * Mark a jail's failure for future handling. 572 */ 573 void 574 failed(struct cfjail *j) 575 { 576 j->flags |= JF_FAILED; 577 TAILQ_REMOVE(j->queue, j, tq); 578 TAILQ_INSERT_HEAD(&ready, j, tq); 579 j->queue = &ready; 580 } 581 582 /* 583 * Exit slightly more gracefully when out of memory. 584 */ 585 void * 586 emalloc(size_t size) 587 { 588 void *p; 589 590 p = malloc(size); 591 if (!p) 592 err(1, "malloc"); 593 return p; 594 } 595 596 void * 597 erealloc(void *ptr, size_t size) 598 { 599 void *p; 600 601 p = realloc(ptr, size); 602 if (!p) 603 err(1, "malloc"); 604 return p; 605 } 606 607 char * 608 estrdup(const char *str) 609 { 610 char *ns; 611 612 ns = strdup(str); 613 if (!ns) 614 err(1, "malloc"); 615 return ns; 616 } 617 618 /* 619 * Print a message including an optional jail name. 620 */ 621 void 622 jail_note(const struct cfjail *j, const char *fmt, ...) 623 { 624 va_list ap, tap; 625 char *cs; 626 size_t len; 627 628 va_start(ap, fmt); 629 va_copy(tap, ap); 630 len = vsnprintf(NULL, 0, fmt, tap); 631 va_end(tap); 632 cs = alloca(len + 1); 633 (void)vsnprintf(cs, len + 1, fmt, ap); 634 va_end(ap); 635 if (j->name) 636 printf("%s: %s", j->name, cs); 637 else 638 printf("%s", cs); 639 } 640 641 /* 642 * Print a warning message including an optional jail name. 643 */ 644 void 645 jail_warnx(const struct cfjail *j, const char *fmt, ...) 646 { 647 va_list ap, tap; 648 char *cs; 649 size_t len; 650 651 va_start(ap, fmt); 652 va_copy(tap, ap); 653 len = vsnprintf(NULL, 0, fmt, tap); 654 va_end(tap); 655 cs = alloca(len + 1); 656 (void)vsnprintf(cs, len + 1, fmt, ap); 657 va_end(ap); 658 if (j->name) 659 warnx("%s: %s", j->name, cs); 660 else 661 warnx("%s", cs); 662 } 663 664 /* 665 * Create a new jail. 666 */ 667 int 668 create_jail(struct cfjail *j) 669 { 670 struct stat st; 671 struct jailparam *jp, *setparams, *sjp; 672 const char *path; 673 int dopersist, ns; 674 675 /* 676 * Check the jail's path, with a better error message than jail_set 677 * gives. 678 */ 679 if ((path = string_param(j->intparams[KP_PATH]))) { 680 if (j->name != NULL && path[0] != '/') { 681 jail_warnx(j, "path %s: not an absolute pathname", 682 path); 683 return -1; 684 } 685 if (stat(path, &st) < 0) { 686 jail_warnx(j, "path %s: %s", path, strerror(errno)); 687 return -1; 688 } 689 if (!S_ISDIR(st.st_mode)) { 690 jail_warnx(j, "path %s: %s", path, strerror(ENOTDIR)); 691 return -1; 692 } 693 } 694 695 /* 696 * Copy all the parameters, except that "persist" is always set when 697 * there are commands to run later. 698 */ 699 dopersist = !bool_param(j->intparams[KP_PERSIST]) && 700 (j->intparams[IP_EXEC_START] || j->intparams[IP_COMMAND] || 701 j->intparams[IP_EXEC_POSTSTART]); 702 sjp = setparams = 703 alloca((j->njp + dopersist) * sizeof(struct jailparam)); 704 if (dopersist && jailparam_init(sjp++, "persist") < 0) { 705 jail_warnx(j, "%s", jail_errmsg); 706 return -1; 707 } 708 for (jp = j->jp; jp < j->jp + j->njp; jp++) 709 if (!dopersist || !equalopts(jp->jp_name, "persist")) 710 *sjp++ = *jp; 711 ns = sjp - setparams; 712 713 j->jid = jailparam_set_note(j, setparams, ns, JAIL_CREATE); 714 if (j->jid < 0) { 715 jail_warnx(j, "%s", jail_errmsg); 716 failed(j); 717 } 718 if (dopersist) { 719 jailparam_free(setparams, 1); 720 if (j->jid > 0) 721 j->flags |= JF_PERSIST; 722 } 723 return j->jid; 724 } 725 726 /* 727 * Remove a temporarily set "persist" parameter. 728 */ 729 static void 730 clear_persist(struct cfjail *j) 731 { 732 struct iovec jiov[4]; 733 int jid; 734 735 if (!(j->flags & JF_PERSIST)) 736 return; 737 j->flags &= ~JF_PERSIST; 738 jiov[0].iov_base = __DECONST(char *, "jid"); 739 jiov[0].iov_len = sizeof("jid"); 740 jiov[1].iov_base = &j->jid; 741 jiov[1].iov_len = sizeof(j->jid); 742 jiov[2].iov_base = __DECONST(char *, "nopersist"); 743 jiov[2].iov_len = sizeof("nopersist"); 744 jiov[3].iov_base = NULL; 745 jiov[3].iov_len = 0; 746 jid = jail_set(jiov, 4, JAIL_UPDATE); 747 if (verbose > 0) 748 jail_note(j, "jail_set(JAIL_UPDATE) jid=%d nopersist%s%s\n", 749 j->jid, jid < 0 ? ": " : "", 750 jid < 0 ? strerror(errno) : ""); 751 } 752 753 /* 754 * Set a jail's parameters. 755 */ 756 static int 757 update_jail(struct cfjail *j) 758 { 759 struct jailparam *jp, *setparams, *sjp; 760 int ns, jid; 761 762 ns = 0; 763 for (jp = j->jp; jp < j->jp + j->njp; jp++) 764 if (!JP_RDTUN(jp)) 765 ns++; 766 if (ns == 0) 767 return 0; 768 sjp = setparams = alloca(++ns * sizeof(struct jailparam)); 769 if (jailparam_init(sjp, "jid") < 0 || 770 jailparam_import_raw(sjp, &j->jid, sizeof j->jid) < 0) { 771 jail_warnx(j, "%s", jail_errmsg); 772 failed(j); 773 return -1; 774 } 775 for (jp = j->jp; jp < j->jp + j->njp; jp++) 776 if (!JP_RDTUN(jp)) 777 *++sjp = *jp; 778 779 jid = jailparam_set_note(j, setparams, ns, JAIL_UPDATE); 780 if (jid < 0) { 781 jail_warnx(j, "%s", jail_errmsg); 782 failed(j); 783 } 784 jailparam_free(setparams, 1); 785 return jid; 786 } 787 788 /* 789 * Return if a jail set would change any create-only parameters. 790 */ 791 static int 792 rdtun_params(struct cfjail *j, int dofail) 793 { 794 struct jailparam *jp, *rtparams, *rtjp; 795 const void *jp_value; 796 size_t jp_valuelen; 797 int nrt, rval, bool_true; 798 799 if (j->flags & JF_RDTUN) 800 return 0; 801 j->flags |= JF_RDTUN; 802 nrt = 0; 803 for (jp = j->jp; jp < j->jp + j->njp; jp++) 804 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 805 nrt++; 806 if (nrt == 0) 807 return 0; 808 rtjp = rtparams = alloca(++nrt * sizeof(struct jailparam)); 809 if (jailparam_init(rtjp, "jid") < 0 || 810 jailparam_import_raw(rtjp, &j->jid, sizeof j->jid) < 0) { 811 jail_warnx(j, "%s", jail_errmsg); 812 exit(1); 813 } 814 for (jp = j->jp; jp < j->jp + j->njp; jp++) 815 if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 816 *++rtjp = *jp; 817 rtjp->jp_value = NULL; 818 } 819 rval = 0; 820 if (jailparam_get(rtparams, nrt, 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) 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, 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)", 923 (flags & (JAIL_CREATE | JAIL_UPDATE)) == JAIL_CREATE 924 ? "JAIL_CREATE" : "JAIL_UPDATE"); 925 for (i = 0; i < njp; i++) { 926 printf(" %s", jp[i].jp_name); 927 if (jp[i].jp_value == NULL) 928 continue; 929 putchar('='); 930 value = jailparam_export(jp + i); 931 if (value == NULL) 932 err(1, "jailparam_export"); 933 quoted_print(stdout, value); 934 free(value); 935 } 936 if (jid < 0) 937 printf(": %s", strerror(errno)); 938 printf("\n"); 939 } 940 return jid; 941 } 942 943 /* 944 * Print a jail record. 945 */ 946 static void 947 print_jail(FILE *fp, struct cfjail *j, int oldcl, int running) 948 { 949 struct cfparam *p; 950 int printsep; 951 952 if (oldcl) { 953 if (running) 954 fprintf(fp, "%d%s", j->jid, separator); 955 print_param(fp, j->intparams[KP_PATH], ',', 0); 956 fputs(separator, fp); 957 print_param(fp, j->intparams[KP_HOST_HOSTNAME], ',', 0); 958 fputs(separator, fp); 959 #ifdef INET 960 print_param(fp, j->intparams[KP_IP4_ADDR], ',', 0); 961 #ifdef INET6 962 if (j->intparams[KP_IP4_ADDR] && 963 !TAILQ_EMPTY(&j->intparams[KP_IP4_ADDR]->val) && 964 j->intparams[KP_IP6_ADDR] && 965 !TAILQ_EMPTY(&j->intparams[KP_IP6_ADDR]->val)) 966 putc(',', fp); 967 #endif 968 #endif 969 #ifdef INET6 970 print_param(fp, j->intparams[KP_IP6_ADDR], ',', 0); 971 #endif 972 fputs(separator, fp); 973 print_param(fp, j->intparams[IP_COMMAND], ' ', 0); 974 } else { 975 printsep = 0; 976 if (running) { 977 fprintf(fp, "jid=%d", j->jid); 978 printsep = 1; 979 } 980 TAILQ_FOREACH(p, &j->params, tq) 981 if (strcmp(p->name, "jid")) { 982 if (printsep) 983 fputs(separator, fp); 984 else 985 printsep = 1; 986 print_param(fp, p, ',', 1); 987 } 988 } 989 putc('\n', fp); 990 } 991 992 /* 993 * Exhibit list of all configured non-wildcard jails 994 */ 995 static void 996 show_jails(void) 997 { 998 struct cfjail *j; 999 1000 TAILQ_FOREACH(j, &cfjails, tq) 1001 print_jail(stdout, j, 0, 0); 1002 } 1003 1004 /* 1005 * Print a parameter value, or a name=value pair. 1006 */ 1007 static void 1008 print_param(FILE *fp, const struct cfparam *p, int sep, int doname) 1009 { 1010 const struct cfstring *s, *ts; 1011 1012 if (doname) 1013 fputs(p->name, fp); 1014 if (p == NULL || TAILQ_EMPTY(&p->val)) 1015 return; 1016 if (doname) 1017 putc('=', fp); 1018 TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 1019 quoted_print(fp, s->s); 1020 if (ts != NULL) 1021 putc(sep, fp); 1022 } 1023 } 1024 1025 /* 1026 * Print a string with quotes around spaces. 1027 */ 1028 static void 1029 quoted_print(FILE *fp, char *str) 1030 { 1031 int c, qc; 1032 char *p = str; 1033 1034 qc = !*p ? '"' 1035 : strchr(p, '\'') ? '"' 1036 : strchr(p, '"') ? '\'' 1037 : strchr(p, ' ') || strchr(p, '\t') ? '"' 1038 : 0; 1039 if (qc) 1040 putc(qc, fp); 1041 while ((c = *p++)) { 1042 if (c == '\\' || c == qc) 1043 putc('\\', fp); 1044 putc(c, fp); 1045 } 1046 if (qc) 1047 putc(qc, fp); 1048 } 1049 1050 static void 1051 usage(void) 1052 { 1053 1054 (void)fprintf(stderr, 1055 "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1056 " -[cmr] param=value ... [command=command ...]\n" 1057 " jail [-dqv] [-f file] -[cmr] [jail]\n" 1058 " jail [-qv] [-f file] -[rR] ['*' | jail ...]\n" 1059 " jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1060 " [-n jailname] [-s securelevel]\n" 1061 " path hostname ip[,...] command ...\n" 1062 " jail [-f file] -e separator\n"); 1063 exit(1); 1064 } 1065