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