Deleted Added
full compact
command.c (246804) command.c (248854)
1/*-
2 * Copyright (c) 2011 James Gritton
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2011 James Gritton
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/usr.sbin/jail/command.c 246804 2013-02-14 19:27:52Z jamie $");
28__FBSDID("$FreeBSD: head/usr.sbin/jail/command.c 248854 2013-03-28 21:02:49Z jamie $");
29
30#include <sys/types.h>
31#include <sys/event.h>
32#include <sys/mount.h>
33#include <sys/stat.h>
34#include <sys/sysctl.h>
35#include <sys/user.h>
36#include <sys/wait.h>
37
38#include <err.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <kvm.h>
42#include <login_cap.h>
43#include <paths.h>
44#include <pwd.h>
45#include <signal.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50
51#include "jailp.h"
52
53#define DEFAULT_STOP_TIMEOUT 10
54#define PHASH_SIZE 256
55
56LIST_HEAD(phhead, phash);
57
58struct phash {
59 LIST_ENTRY(phash) le;
60 struct cfjail *j;
61 pid_t pid;
62};
63
64int paralimit = -1;
65
66extern char **environ;
67
68static int run_command(struct cfjail *j);
69static int add_proc(struct cfjail *j, pid_t pid);
70static void clear_procs(struct cfjail *j);
71static struct cfjail *find_proc(pid_t pid);
72static int term_procs(struct cfjail *j);
73static int get_user_info(struct cfjail *j, const char *username,
74 const struct passwd **pwdp, login_cap_t **lcapp);
75static int check_path(struct cfjail *j, const char *pname, const char *path,
76 int isfile, const char *umount_type);
77
78static struct cfjails sleeping = TAILQ_HEAD_INITIALIZER(sleeping);
79static struct cfjails runnable = TAILQ_HEAD_INITIALIZER(runnable);
80static struct cfstring dummystring = { .len = 1 };
81static struct phhead phash[PHASH_SIZE];
82static int kq;
83
84/*
85 * Run the next command associated with a jail.
86 */
87int
88next_command(struct cfjail *j)
89{
90 enum intparam comparam;
29
30#include <sys/types.h>
31#include <sys/event.h>
32#include <sys/mount.h>
33#include <sys/stat.h>
34#include <sys/sysctl.h>
35#include <sys/user.h>
36#include <sys/wait.h>
37
38#include <err.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <kvm.h>
42#include <login_cap.h>
43#include <paths.h>
44#include <pwd.h>
45#include <signal.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50
51#include "jailp.h"
52
53#define DEFAULT_STOP_TIMEOUT 10
54#define PHASH_SIZE 256
55
56LIST_HEAD(phhead, phash);
57
58struct phash {
59 LIST_ENTRY(phash) le;
60 struct cfjail *j;
61 pid_t pid;
62};
63
64int paralimit = -1;
65
66extern char **environ;
67
68static int run_command(struct cfjail *j);
69static int add_proc(struct cfjail *j, pid_t pid);
70static void clear_procs(struct cfjail *j);
71static struct cfjail *find_proc(pid_t pid);
72static int term_procs(struct cfjail *j);
73static int get_user_info(struct cfjail *j, const char *username,
74 const struct passwd **pwdp, login_cap_t **lcapp);
75static int check_path(struct cfjail *j, const char *pname, const char *path,
76 int isfile, const char *umount_type);
77
78static struct cfjails sleeping = TAILQ_HEAD_INITIALIZER(sleeping);
79static struct cfjails runnable = TAILQ_HEAD_INITIALIZER(runnable);
80static struct cfstring dummystring = { .len = 1 };
81static struct phhead phash[PHASH_SIZE];
82static int kq;
83
84/*
85 * Run the next command associated with a jail.
86 */
87int
88next_command(struct cfjail *j)
89{
90 enum intparam comparam;
91 int create_failed;
91 int create_failed, stopping;
92
93 if (paralimit == 0) {
94 requeue(j, &runnable);
95 return 1;
96 }
97 create_failed = (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED;
92
93 if (paralimit == 0) {
94 requeue(j, &runnable);
95 return 1;
96 }
97 create_failed = (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED;
98 stopping = (j->flags & JF_STOP) != 0;
98 comparam = *j->comparam;
99 for (;;) {
100 if (j->comstring == NULL) {
101 j->comparam += create_failed ? -1 : 1;
102 switch ((comparam = *j->comparam)) {
103 case IP__NULL:
104 return 0;
105 case IP_MOUNT_DEVFS:
106 if (!bool_param(j->intparams[IP_MOUNT_DEVFS]))
107 continue;
108 /* FALLTHROUGH */
109 case IP__OP:
110 case IP_STOP_TIMEOUT:
111 j->comstring = &dummystring;
112 break;
113 default:
114 if (j->intparams[comparam] == NULL)
115 continue;
99 comparam = *j->comparam;
100 for (;;) {
101 if (j->comstring == NULL) {
102 j->comparam += create_failed ? -1 : 1;
103 switch ((comparam = *j->comparam)) {
104 case IP__NULL:
105 return 0;
106 case IP_MOUNT_DEVFS:
107 if (!bool_param(j->intparams[IP_MOUNT_DEVFS]))
108 continue;
109 /* FALLTHROUGH */
110 case IP__OP:
111 case IP_STOP_TIMEOUT:
112 j->comstring = &dummystring;
113 break;
114 default:
115 if (j->intparams[comparam] == NULL)
116 continue;
116 j->comstring = create_failed
117 j->comstring = create_failed || (stopping &&
118 (j->intparams[comparam]->flags & PF_REV))
117 ? TAILQ_LAST(&j->intparams[comparam]->val,
118 cfstrings)
119 : TAILQ_FIRST(&j->intparams[comparam]->val);
120 }
121 } else {
122 j->comstring = j->comstring == &dummystring ? NULL :
119 ? TAILQ_LAST(&j->intparams[comparam]->val,
120 cfstrings)
121 : TAILQ_FIRST(&j->intparams[comparam]->val);
122 }
123 } else {
124 j->comstring = j->comstring == &dummystring ? NULL :
123 create_failed
125 create_failed || (stopping &&
126 (j->intparams[comparam]->flags & PF_REV))
124 ? TAILQ_PREV(j->comstring, cfstrings, tq)
125 : TAILQ_NEXT(j->comstring, tq);
126 }
127 if (j->comstring == NULL || j->comstring->len == 0 ||
128 (create_failed && (comparam == IP_EXEC_PRESTART ||
129 comparam == IP_EXEC_START || comparam == IP_COMMAND ||
130 comparam == IP_EXEC_POSTSTART)))
131 continue;
132 switch (run_command(j)) {
133 case -1:
134 failed(j);
135 /* FALLTHROUGH */
136 case 1:
137 return 1;
138 }
139 }
140}
141
142/*
143 * Check command exit status
144 */
145int
146finish_command(struct cfjail *j)
147{
148 int error;
149
150 if (!(j->flags & JF_SLEEPQ))
151 return 0;
152 j->flags &= ~JF_SLEEPQ;
153 if (*j->comparam == IP_STOP_TIMEOUT)
154 {
155 j->flags &= ~JF_TIMEOUT;
156 j->pstatus = 0;
157 return 0;
158 }
159 paralimit++;
160 if (!TAILQ_EMPTY(&runnable))
161 requeue(TAILQ_FIRST(&runnable), &ready);
162 error = 0;
163 if (j->flags & JF_TIMEOUT) {
164 j->flags &= ~JF_TIMEOUT;
165 if (*j->comparam != IP_STOP_TIMEOUT) {
166 jail_warnx(j, "%s: timed out", j->comline);
167 failed(j);
168 error = -1;
169 } else if (verbose > 0)
170 jail_note(j, "timed out\n");
171 } else if (j->pstatus != 0) {
172 if (WIFSIGNALED(j->pstatus))
173 jail_warnx(j, "%s: exited on signal %d",
174 j->comline, WTERMSIG(j->pstatus));
175 else
176 jail_warnx(j, "%s: failed", j->comline);
177 j->pstatus = 0;
178 failed(j);
179 error = -1;
180 }
181 free(j->comline);
182 j->comline = NULL;
183 return error;
184}
185
186/*
187 * Check for finished processes or timeouts.
188 */
189struct cfjail *
190next_proc(int nonblock)
191{
192 struct kevent ke;
193 struct timespec ts;
194 struct timespec *tsp;
195 struct cfjail *j;
196
197 if (!TAILQ_EMPTY(&sleeping)) {
198 again:
199 tsp = NULL;
200 if ((j = TAILQ_FIRST(&sleeping)) && j->timeout.tv_sec) {
201 clock_gettime(CLOCK_REALTIME, &ts);
202 ts.tv_sec = j->timeout.tv_sec - ts.tv_sec;
203 ts.tv_nsec = j->timeout.tv_nsec - ts.tv_nsec;
204 if (ts.tv_nsec < 0) {
205 ts.tv_sec--;
206 ts.tv_nsec += 1000000000;
207 }
208 if (ts.tv_sec < 0 ||
209 (ts.tv_sec == 0 && ts.tv_nsec == 0)) {
210 j->flags |= JF_TIMEOUT;
211 clear_procs(j);
212 return j;
213 }
214 tsp = &ts;
215 }
216 if (nonblock) {
217 ts.tv_sec = 0;
218 ts.tv_nsec = 0;
219 tsp = &ts;
220 }
221 switch (kevent(kq, NULL, 0, &ke, 1, tsp)) {
222 case -1:
223 if (errno != EINTR)
224 err(1, "kevent");
225 goto again;
226 case 0:
227 if (!nonblock) {
228 j = TAILQ_FIRST(&sleeping);
229 j->flags |= JF_TIMEOUT;
230 clear_procs(j);
231 return j;
232 }
233 break;
234 case 1:
235 (void)waitpid(ke.ident, NULL, WNOHANG);
236 if ((j = find_proc(ke.ident))) {
237 j->pstatus = ke.data;
238 return j;
239 }
240 goto again;
241 }
242 }
243 return NULL;
244}
245
246/*
247 * Run a single command for a jail, possible inside the jail.
248 */
249static int
250run_command(struct cfjail *j)
251{
252 const struct passwd *pwd;
253 const struct cfstring *comstring, *s;
254 login_cap_t *lcap;
255 char **argv;
256 char *cs, *comcs, *devpath;
257 const char *jidstr, *conslog, *path, *ruleset, *term, *username;
258 enum intparam comparam;
259 size_t comlen;
260 pid_t pid;
261 int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout;
262#if defined(INET) || defined(INET6)
263 char *addr;
264#endif
265
266 static char *cleanenv;
267
268 /* Perform some operations that aren't actually commands */
269 comparam = *j->comparam;
270 down = j->flags & (JF_STOP | JF_FAILED);
271 switch (comparam) {
272 case IP_STOP_TIMEOUT:
273 return term_procs(j);
274
275 case IP__OP:
276 if (down) {
277 if (jail_remove(j->jid) < 0 && errno == EPERM) {
278 jail_warnx(j, "jail_remove: %s",
279 strerror(errno));
280 return -1;
281 }
282 if (verbose > 0 || (verbose == 0 && (j->flags & JF_STOP
283 ? note_remove : j->name != NULL)))
284 jail_note(j, "removed\n");
285 j->jid = -1;
286 if (j->flags & JF_STOP)
287 dep_done(j, DF_LIGHT);
288 else
289 j->flags &= ~JF_PERSIST;
290 } else {
291 if (create_jail(j) < 0)
292 return -1;
293 if (iflag)
294 printf("%d\n", j->jid);
295 if (verbose >= 0 && (j->name || verbose > 0))
296 jail_note(j, "created\n");
297 dep_done(j, DF_LIGHT);
298 }
299 return 0;
300
301 default: ;
302 }
303 /*
304 * Collect exec arguments. Internal commands for network and
305 * mounting build their own argument lists.
306 */
307 comstring = j->comstring;
308 bg = 0;
309 switch (comparam) {
310#ifdef INET
311 case IP__IP4_IFADDR:
312 argv = alloca(8 * sizeof(char *));
313 *(const char **)&argv[0] = _PATH_IFCONFIG;
314 if ((cs = strchr(comstring->s, '|'))) {
315 argv[1] = alloca(cs - comstring->s + 1);
316 strlcpy(argv[1], comstring->s, cs - comstring->s + 1);
317 addr = cs + 1;
318 } else {
319 *(const char **)&argv[1] =
320 string_param(j->intparams[IP_INTERFACE]);
321 addr = comstring->s;
322 }
323 *(const char **)&argv[2] = "inet";
324 if (!(cs = strchr(addr, '/'))) {
325 argv[3] = addr;
326 *(const char **)&argv[4] = "netmask";
327 *(const char **)&argv[5] = "255.255.255.255";
328 argc = 6;
329 } else if (strchr(cs + 1, '.')) {
330 argv[3] = alloca(cs - addr + 1);
331 strlcpy(argv[3], addr, cs - addr + 1);
332 *(const char **)&argv[4] = "netmask";
333 *(const char **)&argv[5] = cs + 1;
334 argc = 6;
335 } else {
336 argv[3] = addr;
337 argc = 4;
338 }
339 *(const char **)&argv[argc] = down ? "-alias" : "alias";
340 argv[argc + 1] = NULL;
341 break;
342#endif
343
344#ifdef INET6
345 case IP__IP6_IFADDR:
346 argv = alloca(8 * sizeof(char *));
347 *(const char **)&argv[0] = _PATH_IFCONFIG;
348 if ((cs = strchr(comstring->s, '|'))) {
349 argv[1] = alloca(cs - comstring->s + 1);
350 strlcpy(argv[1], comstring->s, cs - comstring->s + 1);
351 addr = cs + 1;
352 } else {
353 *(const char **)&argv[1] =
354 string_param(j->intparams[IP_INTERFACE]);
355 addr = comstring->s;
356 }
357 *(const char **)&argv[2] = "inet6";
358 argv[3] = addr;
359 if (!(cs = strchr(addr, '/'))) {
360 *(const char **)&argv[4] = "prefixlen";
361 *(const char **)&argv[5] = "128";
362 argc = 6;
363 } else
364 argc = 4;
365 *(const char **)&argv[argc] = down ? "-alias" : "alias";
366 argv[argc + 1] = NULL;
367 break;
368#endif
369
370 case IP_VNET_INTERFACE:
371 argv = alloca(5 * sizeof(char *));
372 *(const char **)&argv[0] = _PATH_IFCONFIG;
373 argv[1] = comstring->s;
374 *(const char **)&argv[2] = down ? "-vnet" : "vnet";
375 jidstr = string_param(j->intparams[KP_JID]);
376 *(const char **)&argv[3] =
377 jidstr ? jidstr : string_param(j->intparams[KP_NAME]);
378 argv[4] = NULL;
379 break;
380
381 case IP_MOUNT:
382 case IP__MOUNT_FROM_FSTAB:
383 argv = alloca(8 * sizeof(char *));
384 comcs = alloca(comstring->len + 1);
385 strcpy(comcs, comstring->s);
386 argc = 0;
387 for (cs = strtok(comcs, " \t\f\v\r\n"); cs && argc < 4;
388 cs = strtok(NULL, " \t\f\v\r\n"))
389 argv[argc++] = cs;
390 if (argc == 0)
391 return 0;
392 if (argc < 3) {
393 jail_warnx(j, "%s: %s: missing information",
394 j->intparams[comparam]->name, comstring->s);
395 return -1;
396 }
397 if (check_path(j, j->intparams[comparam]->name, argv[1], 0,
398 down ? argv[2] : NULL) < 0)
399 return -1;
400 if (down) {
401 argv[4] = NULL;
402 argv[3] = argv[1];
403 *(const char **)&argv[0] = "/sbin/umount";
404 } else {
405 if (argc == 4) {
406 argv[7] = NULL;
407 argv[6] = argv[1];
408 argv[5] = argv[0];
409 argv[4] = argv[3];
410 *(const char **)&argv[3] = "-o";
411 } else {
412 argv[5] = NULL;
413 argv[4] = argv[1];
414 argv[3] = argv[0];
415 }
416 *(const char **)&argv[0] = _PATH_MOUNT;
417 }
418 *(const char **)&argv[1] = "-t";
419 break;
420
421 case IP_MOUNT_DEVFS:
422 argv = alloca(7 * sizeof(char *));
423 path = string_param(j->intparams[KP_PATH]);
424 if (path == NULL) {
425 jail_warnx(j, "mount.devfs: no path");
426 return -1;
427 }
428 devpath = alloca(strlen(path) + 5);
429 sprintf(devpath, "%s/dev", path);
430 if (check_path(j, "mount.devfs", devpath, 0,
431 down ? "devfs" : NULL) < 0)
432 return -1;
433 if (down) {
434 *(const char **)&argv[0] = "/sbin/umount";
435 argv[1] = devpath;
436 argv[2] = NULL;
437 } else {
438 *(const char **)&argv[0] = _PATH_MOUNT;
439 *(const char **)&argv[1] = "-t";
440 *(const char **)&argv[2] = "devfs";
441 ruleset = string_param(j->intparams[KP_DEVFS_RULESET]);
442 if (!ruleset)
443 ruleset = "4"; /* devfsrules_jail */
444 argv[3] = alloca(11 + strlen(ruleset));
445 sprintf(argv[3], "-oruleset=%s", ruleset);
446 *(const char **)&argv[4] = ".";
447 argv[5] = devpath;
448 argv[6] = NULL;
449 }
450 break;
451
452 case IP_COMMAND:
453 if (j->name != NULL)
454 goto default_command;
455 argc = 0;
456 TAILQ_FOREACH(s, &j->intparams[IP_COMMAND]->val, tq)
457 argc++;
458 argv = alloca((argc + 1) * sizeof(char *));
459 argc = 0;
460 TAILQ_FOREACH(s, &j->intparams[IP_COMMAND]->val, tq)
461 argv[argc++] = s->s;
462 argv[argc] = NULL;
463 j->comstring = &dummystring;
464 break;
465
466 default:
467 default_command:
468 if ((cs = strpbrk(comstring->s, "!\"$&'()*;<>?[\\]`{|}~")) &&
469 !(cs[0] == '&' && cs[1] == '\0')) {
470 argv = alloca(4 * sizeof(char *));
471 *(const char **)&argv[0] = _PATH_BSHELL;
472 *(const char **)&argv[1] = "-c";
473 argv[2] = comstring->s;
474 argv[3] = NULL;
475 } else {
476 if (cs) {
477 *cs = 0;
478 bg = 1;
479 }
480 comcs = alloca(comstring->len + 1);
481 strcpy(comcs, comstring->s);
482 argc = 0;
483 for (cs = strtok(comcs, " \t\f\v\r\n"); cs;
484 cs = strtok(NULL, " \t\f\v\r\n"))
485 argc++;
486 argv = alloca((argc + 1) * sizeof(char *));
487 strcpy(comcs, comstring->s);
488 argc = 0;
489 for (cs = strtok(comcs, " \t\f\v\r\n"); cs;
490 cs = strtok(NULL, " \t\f\v\r\n"))
491 argv[argc++] = cs;
492 argv[argc] = NULL;
493 }
494 }
495 if (argv[0] == NULL)
496 return 0;
497
498 if (int_param(j->intparams[IP_EXEC_TIMEOUT], &timeout) &&
499 timeout != 0) {
500 clock_gettime(CLOCK_REALTIME, &j->timeout);
501 j->timeout.tv_sec += timeout;
502 } else
503 j->timeout.tv_sec = 0;
504
505 injail = comparam == IP_EXEC_START || comparam == IP_COMMAND ||
506 comparam == IP_EXEC_STOP;
507 clean = bool_param(j->intparams[IP_EXEC_CLEAN]);
508 username = string_param(j->intparams[injail
509 ? IP_EXEC_JAIL_USER : IP_EXEC_SYSTEM_USER]);
510 sjuser = bool_param(j->intparams[IP_EXEC_SYSTEM_JAIL_USER]);
511
512 consfd = 0;
513 if (injail &&
514 (conslog = string_param(j->intparams[IP_EXEC_CONSOLELOG]))) {
515 if (check_path(j, "exec.consolelog", conslog, 1, NULL) < 0)
516 return -1;
517 consfd =
518 open(conslog, O_WRONLY | O_CREAT | O_APPEND, DEFFILEMODE);
519 if (consfd < 0) {
520 jail_warnx(j, "open %s: %s", conslog, strerror(errno));
521 return -1;
522 }
523 }
524
525 comlen = 0;
526 for (i = 0; argv[i]; i++)
527 comlen += strlen(argv[i]) + 1;
528 j->comline = cs = emalloc(comlen);
529 for (i = 0; argv[i]; i++) {
530 strcpy(cs, argv[i]);
531 if (argv[i + 1]) {
532 cs += strlen(argv[i]) + 1;
533 cs[-1] = ' ';
534 }
535 }
536 if (verbose > 0)
537 jail_note(j, "run command%s%s%s: %s\n",
538 injail ? " in jail" : "", username ? " as " : "",
539 username ? username : "", j->comline);
540
541 pid = fork();
542 if (pid < 0)
543 err(1, "fork");
544 if (pid > 0) {
545 if (bg || !add_proc(j, pid)) {
546 free(j->comline);
547 j->comline = NULL;
548 return 0;
549 } else {
550 paralimit--;
551 return 1;
552 }
553 }
554 if (bg)
555 setsid();
556
557 /* Set up the environment and run the command */
558 pwd = NULL;
559 lcap = NULL;
560 if ((clean || username) && injail && sjuser &&
561 get_user_info(j, username, &pwd, &lcap) < 0)
562 exit(1);
563 if (injail) {
564 /* jail_attach won't chdir along with its chroot. */
565 path = string_param(j->intparams[KP_PATH]);
566 if (path && chdir(path) < 0) {
567 jail_warnx(j, "chdir %s: %s", path, strerror(errno));
568 exit(1);
569 }
570 if (int_param(j->intparams[IP_EXEC_FIB], &fib) &&
571 setfib(fib) < 0) {
572 jail_warnx(j, "setfib: %s", strerror(errno));
573 exit(1);
574 }
575 if (jail_attach(j->jid) < 0) {
576 jail_warnx(j, "jail_attach: %s", strerror(errno));
577 exit(1);
578 }
579 }
580 if (clean || username) {
581 if (!(injail && sjuser) &&
582 get_user_info(j, username, &pwd, &lcap) < 0)
583 exit(1);
584 if (clean) {
585 term = getenv("TERM");
586 environ = &cleanenv;
587 setenv("PATH", "/bin:/usr/bin", 0);
588 if (term != NULL)
589 setenv("TERM", term, 1);
590 }
591 if (setusercontext(lcap, pwd, pwd->pw_uid, username
592 ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN
593 : LOGIN_SETPATH | LOGIN_SETENV) < 0) {
594 jail_warnx(j, "setusercontext %s: %s", pwd->pw_name,
595 strerror(errno));
596 exit(1);
597 }
598 login_close(lcap);
599 setenv("USER", pwd->pw_name, 1);
600 setenv("HOME", pwd->pw_dir, 1);
601 setenv("SHELL",
602 *pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL, 1);
603 if (clean && chdir(pwd->pw_dir) < 0) {
604 jail_warnx(j, "chdir %s: %s",
605 pwd->pw_dir, strerror(errno));
606 exit(1);
607 }
608 endpwent();
609 }
610
611 if (consfd != 0 && (dup2(consfd, 1) < 0 || dup2(consfd, 2) < 0)) {
612 jail_warnx(j, "exec.consolelog: %s", strerror(errno));
613 exit(1);
614 }
615 closefrom(3);
616 execvp(argv[0], argv);
617 jail_warnx(j, "exec %s: %s", argv[0], strerror(errno));
618 exit(1);
619}
620
621/*
622 * Add a process to the hash, tied to a jail.
623 */
624static int
625add_proc(struct cfjail *j, pid_t pid)
626{
627 struct kevent ke;
628 struct cfjail *tj;
629 struct phash *ph;
630
631 if (!kq && (kq = kqueue()) < 0)
632 err(1, "kqueue");
633 EV_SET(&ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
634 if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
635 if (errno == ESRCH)
636 return 0;
637 err(1, "kevent");
638 }
639 ph = emalloc(sizeof(struct phash));
640 ph->j = j;
641 ph->pid = pid;
642 LIST_INSERT_HEAD(&phash[pid % PHASH_SIZE], ph, le);
643 j->nprocs++;
644 j->flags |= JF_SLEEPQ;
645 if (j->timeout.tv_sec == 0)
646 requeue(j, &sleeping);
647 else {
648 /* File the jail in the sleep queue acording to its timeout. */
649 TAILQ_REMOVE(j->queue, j, tq);
650 TAILQ_FOREACH(tj, &sleeping, tq) {
651 if (!tj->timeout.tv_sec ||
652 j->timeout.tv_sec < tj->timeout.tv_sec ||
653 (j->timeout.tv_sec == tj->timeout.tv_sec &&
654 j->timeout.tv_nsec <= tj->timeout.tv_nsec)) {
655 TAILQ_INSERT_BEFORE(tj, j, tq);
656 break;
657 }
658 }
659 if (tj == NULL)
660 TAILQ_INSERT_TAIL(&sleeping, j, tq);
661 j->queue = &sleeping;
662 }
663 return 1;
664}
665
666/*
667 * Remove any processes from the hash that correspond to a jail.
668 */
669static void
670clear_procs(struct cfjail *j)
671{
672 struct kevent ke;
673 struct phash *ph, *tph;
674 int i;
675
676 j->nprocs = 0;
677 for (i = 0; i < PHASH_SIZE; i++)
678 LIST_FOREACH_SAFE(ph, &phash[i], le, tph)
679 if (ph->j == j) {
680 EV_SET(&ke, ph->pid, EVFILT_PROC, EV_DELETE,
681 NOTE_EXIT, 0, NULL);
682 (void)kevent(kq, &ke, 1, NULL, 0, NULL);
683 LIST_REMOVE(ph, le);
684 free(ph);
685 }
686}
687
688/*
689 * Find the jail that corresponds to an exited process.
690 */
691static struct cfjail *
692find_proc(pid_t pid)
693{
694 struct cfjail *j;
695 struct phash *ph;
696
697 LIST_FOREACH(ph, &phash[pid % PHASH_SIZE], le)
698 if (ph->pid == pid) {
699 j = ph->j;
700 LIST_REMOVE(ph, le);
701 free(ph);
702 return --j->nprocs ? NULL : j;
703 }
704 return NULL;
705}
706
707/*
708 * Send SIGTERM to all processes in a jail and wait for them to die.
709 */
710static int
711term_procs(struct cfjail *j)
712{
713 struct kinfo_proc *ki;
714 int i, noted, pcnt, timeout;
715
716 static kvm_t *kd;
717
718 if (!int_param(j->intparams[IP_STOP_TIMEOUT], &timeout))
719 timeout = DEFAULT_STOP_TIMEOUT;
720 else if (timeout == 0)
721 return 0;
722
723 if (kd == NULL) {
724 kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
725 if (kd == NULL)
726 return 0;
727 }
728
729 ki = kvm_getprocs(kd, KERN_PROC_PROC, 0, &pcnt);
730 if (ki == NULL)
731 return 0;
732 noted = 0;
733 for (i = 0; i < pcnt; i++)
734 if (ki[i].ki_jid == j->jid &&
735 kill(ki[i].ki_pid, SIGTERM) == 0) {
736 (void)add_proc(j, ki[i].ki_pid);
737 if (verbose > 0) {
738 if (!noted) {
739 noted = 1;
740 jail_note(j, "sent SIGTERM to:");
741 }
742 printf(" %d", ki[i].ki_pid);
743 }
744 }
745 if (noted)
746 printf("\n");
747 if (j->nprocs > 0) {
748 clock_gettime(CLOCK_REALTIME, &j->timeout);
749 j->timeout.tv_sec += timeout;
750 return 1;
751 }
752 return 0;
753}
754
755/*
756 * Look up a user in the passwd and login.conf files.
757 */
758static int
759get_user_info(struct cfjail *j, const char *username,
760 const struct passwd **pwdp, login_cap_t **lcapp)
761{
762 const struct passwd *pwd;
763
764 *pwdp = pwd = username ? getpwnam(username) : getpwuid(getuid());
765 if (pwd == NULL) {
766 if (errno)
767 jail_warnx(j, "getpwnam%s%s: %s", username ? " " : "",
768 username ? username : "", strerror(errno));
769 else if (username)
770 jail_warnx(j, "%s: no such user", username);
771 else
772 jail_warnx(j, "unknown uid %d", getuid());
773 return -1;
774 }
775 *lcapp = login_getpwclass(pwd);
776 if (*lcapp == NULL) {
777 jail_warnx(j, "getpwclass %s: %s", pwd->pw_name,
778 strerror(errno));
779 return -1;
780 }
781 /* Set the groups while the group file is still available */
782 if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
783 jail_warnx(j, "initgroups %s: %s", pwd->pw_name,
784 strerror(errno));
785 return -1;
786 }
787 return 0;
788}
789
790/*
791 * Make sure a mount or consolelog path is a valid absolute pathname
792 * with no symlinks.
793 */
794static int
795check_path(struct cfjail *j, const char *pname, const char *path, int isfile,
796 const char *umount_type)
797{
798 struct stat st, mpst;
799 struct statfs stfs;
800 char *tpath, *p;
801 const char *jailpath;
802 size_t jplen;
803
804 if (path[0] != '/') {
805 jail_warnx(j, "%s: %s: not an absolute pathname",
806 pname, path);
807 return -1;
808 }
809 /*
810 * Only check for symlinks in components below the jail's path,
811 * since that's where the security risk lies.
812 */
813 jailpath = string_param(j->intparams[KP_PATH]);
814 if (jailpath == NULL)
815 jailpath = "";
816 jplen = strlen(jailpath);
817 if (!strncmp(path, jailpath, jplen) && path[jplen] == '/') {
818 tpath = alloca(strlen(path) + 1);
819 strcpy(tpath, path);
820 for (p = tpath + jplen; p != NULL; ) {
821 p = strchr(p + 1, '/');
822 if (p)
823 *p = '\0';
824 if (lstat(tpath, &st) < 0) {
825 if (errno == ENOENT && isfile && !p)
826 break;
827 jail_warnx(j, "%s: %s: %s", pname, tpath,
828 strerror(errno));
829 return -1;
830 }
831 if (S_ISLNK(st.st_mode)) {
832 jail_warnx(j, "%s: %s is a symbolic link",
833 pname, tpath);
834 return -1;
835 }
836 if (p)
837 *p = '/';
838 }
839 }
840 if (umount_type != NULL) {
841 if (stat(path, &st) < 0 || statfs(path, &stfs) < 0) {
842 jail_warnx(j, "%s: %s: %s", pname, path,
843 strerror(errno));
844 return -1;
845 }
846 if (stat(stfs.f_mntonname, &mpst) < 0) {
847 jail_warnx(j, "%s: %s: %s", pname, stfs.f_mntonname,
848 strerror(errno));
849 return -1;
850 }
851 if (st.st_ino != mpst.st_ino) {
852 jail_warnx(j, "%s: %s: not a mount point",
853 pname, path);
854 return -1;
855 }
856 if (strcmp(stfs.f_fstypename, umount_type)) {
857 jail_warnx(j, "%s: %s: not a %s mount",
858 pname, path, umount_type);
859 return -1;
860 }
861 }
862 return 0;
863}
127 ? TAILQ_PREV(j->comstring, cfstrings, tq)
128 : TAILQ_NEXT(j->comstring, tq);
129 }
130 if (j->comstring == NULL || j->comstring->len == 0 ||
131 (create_failed && (comparam == IP_EXEC_PRESTART ||
132 comparam == IP_EXEC_START || comparam == IP_COMMAND ||
133 comparam == IP_EXEC_POSTSTART)))
134 continue;
135 switch (run_command(j)) {
136 case -1:
137 failed(j);
138 /* FALLTHROUGH */
139 case 1:
140 return 1;
141 }
142 }
143}
144
145/*
146 * Check command exit status
147 */
148int
149finish_command(struct cfjail *j)
150{
151 int error;
152
153 if (!(j->flags & JF_SLEEPQ))
154 return 0;
155 j->flags &= ~JF_SLEEPQ;
156 if (*j->comparam == IP_STOP_TIMEOUT)
157 {
158 j->flags &= ~JF_TIMEOUT;
159 j->pstatus = 0;
160 return 0;
161 }
162 paralimit++;
163 if (!TAILQ_EMPTY(&runnable))
164 requeue(TAILQ_FIRST(&runnable), &ready);
165 error = 0;
166 if (j->flags & JF_TIMEOUT) {
167 j->flags &= ~JF_TIMEOUT;
168 if (*j->comparam != IP_STOP_TIMEOUT) {
169 jail_warnx(j, "%s: timed out", j->comline);
170 failed(j);
171 error = -1;
172 } else if (verbose > 0)
173 jail_note(j, "timed out\n");
174 } else if (j->pstatus != 0) {
175 if (WIFSIGNALED(j->pstatus))
176 jail_warnx(j, "%s: exited on signal %d",
177 j->comline, WTERMSIG(j->pstatus));
178 else
179 jail_warnx(j, "%s: failed", j->comline);
180 j->pstatus = 0;
181 failed(j);
182 error = -1;
183 }
184 free(j->comline);
185 j->comline = NULL;
186 return error;
187}
188
189/*
190 * Check for finished processes or timeouts.
191 */
192struct cfjail *
193next_proc(int nonblock)
194{
195 struct kevent ke;
196 struct timespec ts;
197 struct timespec *tsp;
198 struct cfjail *j;
199
200 if (!TAILQ_EMPTY(&sleeping)) {
201 again:
202 tsp = NULL;
203 if ((j = TAILQ_FIRST(&sleeping)) && j->timeout.tv_sec) {
204 clock_gettime(CLOCK_REALTIME, &ts);
205 ts.tv_sec = j->timeout.tv_sec - ts.tv_sec;
206 ts.tv_nsec = j->timeout.tv_nsec - ts.tv_nsec;
207 if (ts.tv_nsec < 0) {
208 ts.tv_sec--;
209 ts.tv_nsec += 1000000000;
210 }
211 if (ts.tv_sec < 0 ||
212 (ts.tv_sec == 0 && ts.tv_nsec == 0)) {
213 j->flags |= JF_TIMEOUT;
214 clear_procs(j);
215 return j;
216 }
217 tsp = &ts;
218 }
219 if (nonblock) {
220 ts.tv_sec = 0;
221 ts.tv_nsec = 0;
222 tsp = &ts;
223 }
224 switch (kevent(kq, NULL, 0, &ke, 1, tsp)) {
225 case -1:
226 if (errno != EINTR)
227 err(1, "kevent");
228 goto again;
229 case 0:
230 if (!nonblock) {
231 j = TAILQ_FIRST(&sleeping);
232 j->flags |= JF_TIMEOUT;
233 clear_procs(j);
234 return j;
235 }
236 break;
237 case 1:
238 (void)waitpid(ke.ident, NULL, WNOHANG);
239 if ((j = find_proc(ke.ident))) {
240 j->pstatus = ke.data;
241 return j;
242 }
243 goto again;
244 }
245 }
246 return NULL;
247}
248
249/*
250 * Run a single command for a jail, possible inside the jail.
251 */
252static int
253run_command(struct cfjail *j)
254{
255 const struct passwd *pwd;
256 const struct cfstring *comstring, *s;
257 login_cap_t *lcap;
258 char **argv;
259 char *cs, *comcs, *devpath;
260 const char *jidstr, *conslog, *path, *ruleset, *term, *username;
261 enum intparam comparam;
262 size_t comlen;
263 pid_t pid;
264 int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout;
265#if defined(INET) || defined(INET6)
266 char *addr;
267#endif
268
269 static char *cleanenv;
270
271 /* Perform some operations that aren't actually commands */
272 comparam = *j->comparam;
273 down = j->flags & (JF_STOP | JF_FAILED);
274 switch (comparam) {
275 case IP_STOP_TIMEOUT:
276 return term_procs(j);
277
278 case IP__OP:
279 if (down) {
280 if (jail_remove(j->jid) < 0 && errno == EPERM) {
281 jail_warnx(j, "jail_remove: %s",
282 strerror(errno));
283 return -1;
284 }
285 if (verbose > 0 || (verbose == 0 && (j->flags & JF_STOP
286 ? note_remove : j->name != NULL)))
287 jail_note(j, "removed\n");
288 j->jid = -1;
289 if (j->flags & JF_STOP)
290 dep_done(j, DF_LIGHT);
291 else
292 j->flags &= ~JF_PERSIST;
293 } else {
294 if (create_jail(j) < 0)
295 return -1;
296 if (iflag)
297 printf("%d\n", j->jid);
298 if (verbose >= 0 && (j->name || verbose > 0))
299 jail_note(j, "created\n");
300 dep_done(j, DF_LIGHT);
301 }
302 return 0;
303
304 default: ;
305 }
306 /*
307 * Collect exec arguments. Internal commands for network and
308 * mounting build their own argument lists.
309 */
310 comstring = j->comstring;
311 bg = 0;
312 switch (comparam) {
313#ifdef INET
314 case IP__IP4_IFADDR:
315 argv = alloca(8 * sizeof(char *));
316 *(const char **)&argv[0] = _PATH_IFCONFIG;
317 if ((cs = strchr(comstring->s, '|'))) {
318 argv[1] = alloca(cs - comstring->s + 1);
319 strlcpy(argv[1], comstring->s, cs - comstring->s + 1);
320 addr = cs + 1;
321 } else {
322 *(const char **)&argv[1] =
323 string_param(j->intparams[IP_INTERFACE]);
324 addr = comstring->s;
325 }
326 *(const char **)&argv[2] = "inet";
327 if (!(cs = strchr(addr, '/'))) {
328 argv[3] = addr;
329 *(const char **)&argv[4] = "netmask";
330 *(const char **)&argv[5] = "255.255.255.255";
331 argc = 6;
332 } else if (strchr(cs + 1, '.')) {
333 argv[3] = alloca(cs - addr + 1);
334 strlcpy(argv[3], addr, cs - addr + 1);
335 *(const char **)&argv[4] = "netmask";
336 *(const char **)&argv[5] = cs + 1;
337 argc = 6;
338 } else {
339 argv[3] = addr;
340 argc = 4;
341 }
342 *(const char **)&argv[argc] = down ? "-alias" : "alias";
343 argv[argc + 1] = NULL;
344 break;
345#endif
346
347#ifdef INET6
348 case IP__IP6_IFADDR:
349 argv = alloca(8 * sizeof(char *));
350 *(const char **)&argv[0] = _PATH_IFCONFIG;
351 if ((cs = strchr(comstring->s, '|'))) {
352 argv[1] = alloca(cs - comstring->s + 1);
353 strlcpy(argv[1], comstring->s, cs - comstring->s + 1);
354 addr = cs + 1;
355 } else {
356 *(const char **)&argv[1] =
357 string_param(j->intparams[IP_INTERFACE]);
358 addr = comstring->s;
359 }
360 *(const char **)&argv[2] = "inet6";
361 argv[3] = addr;
362 if (!(cs = strchr(addr, '/'))) {
363 *(const char **)&argv[4] = "prefixlen";
364 *(const char **)&argv[5] = "128";
365 argc = 6;
366 } else
367 argc = 4;
368 *(const char **)&argv[argc] = down ? "-alias" : "alias";
369 argv[argc + 1] = NULL;
370 break;
371#endif
372
373 case IP_VNET_INTERFACE:
374 argv = alloca(5 * sizeof(char *));
375 *(const char **)&argv[0] = _PATH_IFCONFIG;
376 argv[1] = comstring->s;
377 *(const char **)&argv[2] = down ? "-vnet" : "vnet";
378 jidstr = string_param(j->intparams[KP_JID]);
379 *(const char **)&argv[3] =
380 jidstr ? jidstr : string_param(j->intparams[KP_NAME]);
381 argv[4] = NULL;
382 break;
383
384 case IP_MOUNT:
385 case IP__MOUNT_FROM_FSTAB:
386 argv = alloca(8 * sizeof(char *));
387 comcs = alloca(comstring->len + 1);
388 strcpy(comcs, comstring->s);
389 argc = 0;
390 for (cs = strtok(comcs, " \t\f\v\r\n"); cs && argc < 4;
391 cs = strtok(NULL, " \t\f\v\r\n"))
392 argv[argc++] = cs;
393 if (argc == 0)
394 return 0;
395 if (argc < 3) {
396 jail_warnx(j, "%s: %s: missing information",
397 j->intparams[comparam]->name, comstring->s);
398 return -1;
399 }
400 if (check_path(j, j->intparams[comparam]->name, argv[1], 0,
401 down ? argv[2] : NULL) < 0)
402 return -1;
403 if (down) {
404 argv[4] = NULL;
405 argv[3] = argv[1];
406 *(const char **)&argv[0] = "/sbin/umount";
407 } else {
408 if (argc == 4) {
409 argv[7] = NULL;
410 argv[6] = argv[1];
411 argv[5] = argv[0];
412 argv[4] = argv[3];
413 *(const char **)&argv[3] = "-o";
414 } else {
415 argv[5] = NULL;
416 argv[4] = argv[1];
417 argv[3] = argv[0];
418 }
419 *(const char **)&argv[0] = _PATH_MOUNT;
420 }
421 *(const char **)&argv[1] = "-t";
422 break;
423
424 case IP_MOUNT_DEVFS:
425 argv = alloca(7 * sizeof(char *));
426 path = string_param(j->intparams[KP_PATH]);
427 if (path == NULL) {
428 jail_warnx(j, "mount.devfs: no path");
429 return -1;
430 }
431 devpath = alloca(strlen(path) + 5);
432 sprintf(devpath, "%s/dev", path);
433 if (check_path(j, "mount.devfs", devpath, 0,
434 down ? "devfs" : NULL) < 0)
435 return -1;
436 if (down) {
437 *(const char **)&argv[0] = "/sbin/umount";
438 argv[1] = devpath;
439 argv[2] = NULL;
440 } else {
441 *(const char **)&argv[0] = _PATH_MOUNT;
442 *(const char **)&argv[1] = "-t";
443 *(const char **)&argv[2] = "devfs";
444 ruleset = string_param(j->intparams[KP_DEVFS_RULESET]);
445 if (!ruleset)
446 ruleset = "4"; /* devfsrules_jail */
447 argv[3] = alloca(11 + strlen(ruleset));
448 sprintf(argv[3], "-oruleset=%s", ruleset);
449 *(const char **)&argv[4] = ".";
450 argv[5] = devpath;
451 argv[6] = NULL;
452 }
453 break;
454
455 case IP_COMMAND:
456 if (j->name != NULL)
457 goto default_command;
458 argc = 0;
459 TAILQ_FOREACH(s, &j->intparams[IP_COMMAND]->val, tq)
460 argc++;
461 argv = alloca((argc + 1) * sizeof(char *));
462 argc = 0;
463 TAILQ_FOREACH(s, &j->intparams[IP_COMMAND]->val, tq)
464 argv[argc++] = s->s;
465 argv[argc] = NULL;
466 j->comstring = &dummystring;
467 break;
468
469 default:
470 default_command:
471 if ((cs = strpbrk(comstring->s, "!\"$&'()*;<>?[\\]`{|}~")) &&
472 !(cs[0] == '&' && cs[1] == '\0')) {
473 argv = alloca(4 * sizeof(char *));
474 *(const char **)&argv[0] = _PATH_BSHELL;
475 *(const char **)&argv[1] = "-c";
476 argv[2] = comstring->s;
477 argv[3] = NULL;
478 } else {
479 if (cs) {
480 *cs = 0;
481 bg = 1;
482 }
483 comcs = alloca(comstring->len + 1);
484 strcpy(comcs, comstring->s);
485 argc = 0;
486 for (cs = strtok(comcs, " \t\f\v\r\n"); cs;
487 cs = strtok(NULL, " \t\f\v\r\n"))
488 argc++;
489 argv = alloca((argc + 1) * sizeof(char *));
490 strcpy(comcs, comstring->s);
491 argc = 0;
492 for (cs = strtok(comcs, " \t\f\v\r\n"); cs;
493 cs = strtok(NULL, " \t\f\v\r\n"))
494 argv[argc++] = cs;
495 argv[argc] = NULL;
496 }
497 }
498 if (argv[0] == NULL)
499 return 0;
500
501 if (int_param(j->intparams[IP_EXEC_TIMEOUT], &timeout) &&
502 timeout != 0) {
503 clock_gettime(CLOCK_REALTIME, &j->timeout);
504 j->timeout.tv_sec += timeout;
505 } else
506 j->timeout.tv_sec = 0;
507
508 injail = comparam == IP_EXEC_START || comparam == IP_COMMAND ||
509 comparam == IP_EXEC_STOP;
510 clean = bool_param(j->intparams[IP_EXEC_CLEAN]);
511 username = string_param(j->intparams[injail
512 ? IP_EXEC_JAIL_USER : IP_EXEC_SYSTEM_USER]);
513 sjuser = bool_param(j->intparams[IP_EXEC_SYSTEM_JAIL_USER]);
514
515 consfd = 0;
516 if (injail &&
517 (conslog = string_param(j->intparams[IP_EXEC_CONSOLELOG]))) {
518 if (check_path(j, "exec.consolelog", conslog, 1, NULL) < 0)
519 return -1;
520 consfd =
521 open(conslog, O_WRONLY | O_CREAT | O_APPEND, DEFFILEMODE);
522 if (consfd < 0) {
523 jail_warnx(j, "open %s: %s", conslog, strerror(errno));
524 return -1;
525 }
526 }
527
528 comlen = 0;
529 for (i = 0; argv[i]; i++)
530 comlen += strlen(argv[i]) + 1;
531 j->comline = cs = emalloc(comlen);
532 for (i = 0; argv[i]; i++) {
533 strcpy(cs, argv[i]);
534 if (argv[i + 1]) {
535 cs += strlen(argv[i]) + 1;
536 cs[-1] = ' ';
537 }
538 }
539 if (verbose > 0)
540 jail_note(j, "run command%s%s%s: %s\n",
541 injail ? " in jail" : "", username ? " as " : "",
542 username ? username : "", j->comline);
543
544 pid = fork();
545 if (pid < 0)
546 err(1, "fork");
547 if (pid > 0) {
548 if (bg || !add_proc(j, pid)) {
549 free(j->comline);
550 j->comline = NULL;
551 return 0;
552 } else {
553 paralimit--;
554 return 1;
555 }
556 }
557 if (bg)
558 setsid();
559
560 /* Set up the environment and run the command */
561 pwd = NULL;
562 lcap = NULL;
563 if ((clean || username) && injail && sjuser &&
564 get_user_info(j, username, &pwd, &lcap) < 0)
565 exit(1);
566 if (injail) {
567 /* jail_attach won't chdir along with its chroot. */
568 path = string_param(j->intparams[KP_PATH]);
569 if (path && chdir(path) < 0) {
570 jail_warnx(j, "chdir %s: %s", path, strerror(errno));
571 exit(1);
572 }
573 if (int_param(j->intparams[IP_EXEC_FIB], &fib) &&
574 setfib(fib) < 0) {
575 jail_warnx(j, "setfib: %s", strerror(errno));
576 exit(1);
577 }
578 if (jail_attach(j->jid) < 0) {
579 jail_warnx(j, "jail_attach: %s", strerror(errno));
580 exit(1);
581 }
582 }
583 if (clean || username) {
584 if (!(injail && sjuser) &&
585 get_user_info(j, username, &pwd, &lcap) < 0)
586 exit(1);
587 if (clean) {
588 term = getenv("TERM");
589 environ = &cleanenv;
590 setenv("PATH", "/bin:/usr/bin", 0);
591 if (term != NULL)
592 setenv("TERM", term, 1);
593 }
594 if (setusercontext(lcap, pwd, pwd->pw_uid, username
595 ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN
596 : LOGIN_SETPATH | LOGIN_SETENV) < 0) {
597 jail_warnx(j, "setusercontext %s: %s", pwd->pw_name,
598 strerror(errno));
599 exit(1);
600 }
601 login_close(lcap);
602 setenv("USER", pwd->pw_name, 1);
603 setenv("HOME", pwd->pw_dir, 1);
604 setenv("SHELL",
605 *pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL, 1);
606 if (clean && chdir(pwd->pw_dir) < 0) {
607 jail_warnx(j, "chdir %s: %s",
608 pwd->pw_dir, strerror(errno));
609 exit(1);
610 }
611 endpwent();
612 }
613
614 if (consfd != 0 && (dup2(consfd, 1) < 0 || dup2(consfd, 2) < 0)) {
615 jail_warnx(j, "exec.consolelog: %s", strerror(errno));
616 exit(1);
617 }
618 closefrom(3);
619 execvp(argv[0], argv);
620 jail_warnx(j, "exec %s: %s", argv[0], strerror(errno));
621 exit(1);
622}
623
624/*
625 * Add a process to the hash, tied to a jail.
626 */
627static int
628add_proc(struct cfjail *j, pid_t pid)
629{
630 struct kevent ke;
631 struct cfjail *tj;
632 struct phash *ph;
633
634 if (!kq && (kq = kqueue()) < 0)
635 err(1, "kqueue");
636 EV_SET(&ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
637 if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
638 if (errno == ESRCH)
639 return 0;
640 err(1, "kevent");
641 }
642 ph = emalloc(sizeof(struct phash));
643 ph->j = j;
644 ph->pid = pid;
645 LIST_INSERT_HEAD(&phash[pid % PHASH_SIZE], ph, le);
646 j->nprocs++;
647 j->flags |= JF_SLEEPQ;
648 if (j->timeout.tv_sec == 0)
649 requeue(j, &sleeping);
650 else {
651 /* File the jail in the sleep queue acording to its timeout. */
652 TAILQ_REMOVE(j->queue, j, tq);
653 TAILQ_FOREACH(tj, &sleeping, tq) {
654 if (!tj->timeout.tv_sec ||
655 j->timeout.tv_sec < tj->timeout.tv_sec ||
656 (j->timeout.tv_sec == tj->timeout.tv_sec &&
657 j->timeout.tv_nsec <= tj->timeout.tv_nsec)) {
658 TAILQ_INSERT_BEFORE(tj, j, tq);
659 break;
660 }
661 }
662 if (tj == NULL)
663 TAILQ_INSERT_TAIL(&sleeping, j, tq);
664 j->queue = &sleeping;
665 }
666 return 1;
667}
668
669/*
670 * Remove any processes from the hash that correspond to a jail.
671 */
672static void
673clear_procs(struct cfjail *j)
674{
675 struct kevent ke;
676 struct phash *ph, *tph;
677 int i;
678
679 j->nprocs = 0;
680 for (i = 0; i < PHASH_SIZE; i++)
681 LIST_FOREACH_SAFE(ph, &phash[i], le, tph)
682 if (ph->j == j) {
683 EV_SET(&ke, ph->pid, EVFILT_PROC, EV_DELETE,
684 NOTE_EXIT, 0, NULL);
685 (void)kevent(kq, &ke, 1, NULL, 0, NULL);
686 LIST_REMOVE(ph, le);
687 free(ph);
688 }
689}
690
691/*
692 * Find the jail that corresponds to an exited process.
693 */
694static struct cfjail *
695find_proc(pid_t pid)
696{
697 struct cfjail *j;
698 struct phash *ph;
699
700 LIST_FOREACH(ph, &phash[pid % PHASH_SIZE], le)
701 if (ph->pid == pid) {
702 j = ph->j;
703 LIST_REMOVE(ph, le);
704 free(ph);
705 return --j->nprocs ? NULL : j;
706 }
707 return NULL;
708}
709
710/*
711 * Send SIGTERM to all processes in a jail and wait for them to die.
712 */
713static int
714term_procs(struct cfjail *j)
715{
716 struct kinfo_proc *ki;
717 int i, noted, pcnt, timeout;
718
719 static kvm_t *kd;
720
721 if (!int_param(j->intparams[IP_STOP_TIMEOUT], &timeout))
722 timeout = DEFAULT_STOP_TIMEOUT;
723 else if (timeout == 0)
724 return 0;
725
726 if (kd == NULL) {
727 kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
728 if (kd == NULL)
729 return 0;
730 }
731
732 ki = kvm_getprocs(kd, KERN_PROC_PROC, 0, &pcnt);
733 if (ki == NULL)
734 return 0;
735 noted = 0;
736 for (i = 0; i < pcnt; i++)
737 if (ki[i].ki_jid == j->jid &&
738 kill(ki[i].ki_pid, SIGTERM) == 0) {
739 (void)add_proc(j, ki[i].ki_pid);
740 if (verbose > 0) {
741 if (!noted) {
742 noted = 1;
743 jail_note(j, "sent SIGTERM to:");
744 }
745 printf(" %d", ki[i].ki_pid);
746 }
747 }
748 if (noted)
749 printf("\n");
750 if (j->nprocs > 0) {
751 clock_gettime(CLOCK_REALTIME, &j->timeout);
752 j->timeout.tv_sec += timeout;
753 return 1;
754 }
755 return 0;
756}
757
758/*
759 * Look up a user in the passwd and login.conf files.
760 */
761static int
762get_user_info(struct cfjail *j, const char *username,
763 const struct passwd **pwdp, login_cap_t **lcapp)
764{
765 const struct passwd *pwd;
766
767 *pwdp = pwd = username ? getpwnam(username) : getpwuid(getuid());
768 if (pwd == NULL) {
769 if (errno)
770 jail_warnx(j, "getpwnam%s%s: %s", username ? " " : "",
771 username ? username : "", strerror(errno));
772 else if (username)
773 jail_warnx(j, "%s: no such user", username);
774 else
775 jail_warnx(j, "unknown uid %d", getuid());
776 return -1;
777 }
778 *lcapp = login_getpwclass(pwd);
779 if (*lcapp == NULL) {
780 jail_warnx(j, "getpwclass %s: %s", pwd->pw_name,
781 strerror(errno));
782 return -1;
783 }
784 /* Set the groups while the group file is still available */
785 if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
786 jail_warnx(j, "initgroups %s: %s", pwd->pw_name,
787 strerror(errno));
788 return -1;
789 }
790 return 0;
791}
792
793/*
794 * Make sure a mount or consolelog path is a valid absolute pathname
795 * with no symlinks.
796 */
797static int
798check_path(struct cfjail *j, const char *pname, const char *path, int isfile,
799 const char *umount_type)
800{
801 struct stat st, mpst;
802 struct statfs stfs;
803 char *tpath, *p;
804 const char *jailpath;
805 size_t jplen;
806
807 if (path[0] != '/') {
808 jail_warnx(j, "%s: %s: not an absolute pathname",
809 pname, path);
810 return -1;
811 }
812 /*
813 * Only check for symlinks in components below the jail's path,
814 * since that's where the security risk lies.
815 */
816 jailpath = string_param(j->intparams[KP_PATH]);
817 if (jailpath == NULL)
818 jailpath = "";
819 jplen = strlen(jailpath);
820 if (!strncmp(path, jailpath, jplen) && path[jplen] == '/') {
821 tpath = alloca(strlen(path) + 1);
822 strcpy(tpath, path);
823 for (p = tpath + jplen; p != NULL; ) {
824 p = strchr(p + 1, '/');
825 if (p)
826 *p = '\0';
827 if (lstat(tpath, &st) < 0) {
828 if (errno == ENOENT && isfile && !p)
829 break;
830 jail_warnx(j, "%s: %s: %s", pname, tpath,
831 strerror(errno));
832 return -1;
833 }
834 if (S_ISLNK(st.st_mode)) {
835 jail_warnx(j, "%s: %s is a symbolic link",
836 pname, tpath);
837 return -1;
838 }
839 if (p)
840 *p = '/';
841 }
842 }
843 if (umount_type != NULL) {
844 if (stat(path, &st) < 0 || statfs(path, &stfs) < 0) {
845 jail_warnx(j, "%s: %s: %s", pname, path,
846 strerror(errno));
847 return -1;
848 }
849 if (stat(stfs.f_mntonname, &mpst) < 0) {
850 jail_warnx(j, "%s: %s: %s", pname, stfs.f_mntonname,
851 strerror(errno));
852 return -1;
853 }
854 if (st.st_ino != mpst.st_ino) {
855 jail_warnx(j, "%s: %s: not a mount point",
856 pname, path);
857 return -1;
858 }
859 if (strcmp(stfs.f_fstypename, umount_type)) {
860 jail_warnx(j, "%s: %s: not a %s mount",
861 pname, path, umount_type);
862 return -1;
863 }
864 }
865 return 0;
866}