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