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