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