1 |
+ |
/* $MidnightBSD$ */ |
2 |
|
/*- |
3 |
|
* Copyright (c) 2011 James Gritton |
4 |
|
* All rights reserved. |
26 |
|
*/ |
27 |
|
|
28 |
|
#include <sys/cdefs.h> |
29 |
< |
__MBSDID("$MidnightBSD$"); |
29 |
> |
__FBSDID("$FreeBSD: stable/10/usr.sbin/jail/command.c 302958 2016-07-17 14:15:08Z jamie $"); |
30 |
|
|
31 |
|
#include <sys/types.h> |
32 |
|
#include <sys/event.h> |
48 |
|
#include <stdlib.h> |
49 |
|
#include <string.h> |
50 |
|
#include <unistd.h> |
51 |
+ |
#include <vis.h> |
52 |
|
|
53 |
|
#include "jailp.h" |
54 |
|
|
93 |
|
int create_failed, stopping; |
94 |
|
|
95 |
|
if (paralimit == 0) { |
96 |
< |
requeue(j, &runnable); |
96 |
> |
if (j->flags & JF_FROM_RUNQ) |
97 |
> |
requeue_head(j, &runnable); |
98 |
> |
else |
99 |
> |
requeue(j, &runnable); |
100 |
|
return 1; |
101 |
|
} |
102 |
+ |
j->flags &= ~JF_FROM_RUNQ; |
103 |
|
create_failed = (j->flags & (JF_STOP | JF_FAILED)) == JF_FAILED; |
104 |
|
stopping = (j->flags & JF_STOP) != 0; |
105 |
|
comparam = *j->comparam; |
112 |
|
case IP_MOUNT_DEVFS: |
113 |
|
if (!bool_param(j->intparams[IP_MOUNT_DEVFS])) |
114 |
|
continue; |
115 |
< |
/* FALLTHROUGH */ |
115 |
> |
j->comstring = &dummystring; |
116 |
> |
break; |
117 |
> |
case IP_MOUNT_FDESCFS: |
118 |
> |
if (!bool_param(j->intparams[IP_MOUNT_FDESCFS])) |
119 |
> |
continue; |
120 |
> |
j->comstring = &dummystring; |
121 |
> |
break; |
122 |
> |
case IP_MOUNT_PROCFS: |
123 |
> |
if (!bool_param(j->intparams[IP_MOUNT_PROCFS])) |
124 |
> |
continue; |
125 |
> |
j->comstring = &dummystring; |
126 |
> |
break; |
127 |
|
case IP__OP: |
128 |
|
case IP_STOP_TIMEOUT: |
129 |
|
j->comstring = &dummystring; |
165 |
|
int |
166 |
|
finish_command(struct cfjail *j) |
167 |
|
{ |
168 |
+ |
struct cfjail *rj; |
169 |
|
int error; |
170 |
|
|
171 |
|
if (!(j->flags & JF_SLEEPQ)) |
172 |
|
return 0; |
173 |
|
j->flags &= ~JF_SLEEPQ; |
174 |
< |
if (*j->comparam == IP_STOP_TIMEOUT) |
157 |
< |
{ |
174 |
> |
if (*j->comparam == IP_STOP_TIMEOUT) { |
175 |
|
j->flags &= ~JF_TIMEOUT; |
176 |
|
j->pstatus = 0; |
177 |
|
return 0; |
178 |
|
} |
179 |
|
paralimit++; |
180 |
< |
if (!TAILQ_EMPTY(&runnable)) |
181 |
< |
requeue(TAILQ_FIRST(&runnable), &ready); |
180 |
> |
if (!TAILQ_EMPTY(&runnable)) { |
181 |
> |
rj = TAILQ_FIRST(&runnable); |
182 |
> |
rj->flags |= JF_FROM_RUNQ; |
183 |
> |
requeue(rj, &ready); |
184 |
> |
} |
185 |
|
error = 0; |
186 |
|
if (j->flags & JF_TIMEOUT) { |
187 |
|
j->flags &= ~JF_TIMEOUT; |
267 |
|
} |
268 |
|
|
269 |
|
/* |
270 |
< |
* Run a single command for a jail, possible inside the jail. |
270 |
> |
* Run a single command for a jail, possibly inside the jail. |
271 |
|
*/ |
272 |
|
static int |
273 |
|
run_command(struct cfjail *j) |
283 |
|
pid_t pid; |
284 |
|
int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout; |
285 |
|
#if defined(INET) || defined(INET6) |
286 |
< |
char *addr; |
286 |
> |
char *addr, *extrap, *p, *val; |
287 |
|
#endif |
288 |
|
|
289 |
|
static char *cleanenv; |
332 |
|
switch (comparam) { |
333 |
|
#ifdef INET |
334 |
|
case IP__IP4_IFADDR: |
335 |
< |
argv = alloca(8 * sizeof(char *)); |
335 |
> |
argc = 0; |
336 |
> |
val = alloca(strlen(comstring->s) + 1); |
337 |
> |
strcpy(val, comstring->s); |
338 |
> |
cs = val; |
339 |
> |
extrap = NULL; |
340 |
> |
while ((p = strchr(cs, ' ')) != NULL && strlen(p) > 1) { |
341 |
> |
if (extrap == NULL) { |
342 |
> |
*p = '\0'; |
343 |
> |
extrap = p + 1; |
344 |
> |
} |
345 |
> |
cs = p + 1; |
346 |
> |
argc++; |
347 |
> |
} |
348 |
> |
|
349 |
> |
argv = alloca((8 + argc) * 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); |
351 |
> |
if ((cs = strchr(val, '|'))) { |
352 |
> |
argv[1] = alloca(cs - val + 1); |
353 |
> |
strlcpy(argv[1], val, cs - val + 1); |
354 |
|
addr = cs + 1; |
355 |
|
} else { |
356 |
|
*(const char **)&argv[1] = |
357 |
|
string_param(j->intparams[IP_INTERFACE]); |
358 |
< |
addr = comstring->s; |
358 |
> |
addr = val; |
359 |
|
} |
360 |
|
*(const char **)&argv[2] = "inet"; |
361 |
|
if (!(cs = strchr(addr, '/'))) { |
373 |
|
argv[3] = addr; |
374 |
|
argc = 4; |
375 |
|
} |
376 |
+ |
|
377 |
+ |
if (!down) { |
378 |
+ |
for (cs = strtok(extrap, " "); cs; cs = strtok(NULL, " ")) { |
379 |
+ |
size_t len = strlen(cs) + 1; |
380 |
+ |
argv[argc] = alloca(len); |
381 |
+ |
strlcpy(argv[argc++], cs, len); |
382 |
+ |
} |
383 |
+ |
} |
384 |
+ |
|
385 |
|
*(const char **)&argv[argc] = down ? "-alias" : "alias"; |
386 |
|
argv[argc + 1] = NULL; |
387 |
|
break; |
389 |
|
|
390 |
|
#ifdef INET6 |
391 |
|
case IP__IP6_IFADDR: |
392 |
< |
argv = alloca(8 * sizeof(char *)); |
392 |
> |
argc = 0; |
393 |
> |
val = alloca(strlen(comstring->s) + 1); |
394 |
> |
strcpy(val, comstring->s); |
395 |
> |
cs = val; |
396 |
> |
extrap = NULL; |
397 |
> |
while ((p = strchr(cs, ' ')) != NULL && strlen(p) > 1) { |
398 |
> |
if (extrap == NULL) { |
399 |
> |
*p = '\0'; |
400 |
> |
extrap = p + 1; |
401 |
> |
} |
402 |
> |
cs = p + 1; |
403 |
> |
argc++; |
404 |
> |
} |
405 |
> |
|
406 |
> |
argv = alloca((8 + argc) * sizeof(char *)); |
407 |
|
*(const char **)&argv[0] = _PATH_IFCONFIG; |
408 |
< |
if ((cs = strchr(comstring->s, '|'))) { |
409 |
< |
argv[1] = alloca(cs - comstring->s + 1); |
410 |
< |
strlcpy(argv[1], comstring->s, cs - comstring->s + 1); |
408 |
> |
if ((cs = strchr(val, '|'))) { |
409 |
> |
argv[1] = alloca(cs - val + 1); |
410 |
> |
strlcpy(argv[1], val, cs - val + 1); |
411 |
|
addr = cs + 1; |
412 |
|
} else { |
413 |
|
*(const char **)&argv[1] = |
414 |
|
string_param(j->intparams[IP_INTERFACE]); |
415 |
< |
addr = comstring->s; |
415 |
> |
addr = val; |
416 |
|
} |
417 |
|
*(const char **)&argv[2] = "inet6"; |
418 |
|
argv[3] = addr; |
422 |
|
argc = 6; |
423 |
|
} else |
424 |
|
argc = 4; |
425 |
+ |
|
426 |
+ |
if (!down) { |
427 |
+ |
for (cs = strtok(extrap, " "); cs; cs = strtok(NULL, " ")) { |
428 |
+ |
size_t len = strlen(cs) + 1; |
429 |
+ |
argv[argc] = alloca(len); |
430 |
+ |
strlcpy(argv[argc++], cs, len); |
431 |
+ |
} |
432 |
+ |
} |
433 |
+ |
|
434 |
|
*(const char **)&argv[argc] = down ? "-alias" : "alias"; |
435 |
|
argv[argc + 1] = NULL; |
436 |
|
break; |
454 |
|
strcpy(comcs, comstring->s); |
455 |
|
argc = 0; |
456 |
|
for (cs = strtok(comcs, " \t\f\v\r\n"); cs && argc < 4; |
457 |
< |
cs = strtok(NULL, " \t\f\v\r\n")) |
457 |
> |
cs = strtok(NULL, " \t\f\v\r\n")) { |
458 |
> |
if (argc <= 1 && strunvis(cs, cs) < 0) { |
459 |
> |
jail_warnx(j, "%s: %s: fstab parse error", |
460 |
> |
j->intparams[comparam]->name, comstring->s); |
461 |
> |
return -1; |
462 |
> |
} |
463 |
|
argv[argc++] = cs; |
464 |
+ |
} |
465 |
|
if (argc == 0) |
466 |
|
return 0; |
467 |
|
if (argc < 3) { |
524 |
|
} |
525 |
|
break; |
526 |
|
|
527 |
+ |
case IP_MOUNT_FDESCFS: |
528 |
+ |
argv = alloca(7 * sizeof(char *)); |
529 |
+ |
path = string_param(j->intparams[KP_PATH]); |
530 |
+ |
if (path == NULL) { |
531 |
+ |
jail_warnx(j, "mount.fdescfs: no path"); |
532 |
+ |
return -1; |
533 |
+ |
} |
534 |
+ |
devpath = alloca(strlen(path) + 8); |
535 |
+ |
sprintf(devpath, "%s/dev/fd", path); |
536 |
+ |
if (check_path(j, "mount.fdescfs", devpath, 0, |
537 |
+ |
down ? "fdescfs" : NULL) < 0) |
538 |
+ |
return -1; |
539 |
+ |
if (down) { |
540 |
+ |
*(const char **)&argv[0] = "/sbin/umount"; |
541 |
+ |
argv[1] = devpath; |
542 |
+ |
argv[2] = NULL; |
543 |
+ |
} else { |
544 |
+ |
*(const char **)&argv[0] = _PATH_MOUNT; |
545 |
+ |
*(const char **)&argv[1] = "-t"; |
546 |
+ |
*(const char **)&argv[2] = "fdescfs"; |
547 |
+ |
*(const char **)&argv[3] = "."; |
548 |
+ |
argv[4] = devpath; |
549 |
+ |
argv[5] = NULL; |
550 |
+ |
} |
551 |
+ |
break; |
552 |
+ |
|
553 |
+ |
case IP_MOUNT_PROCFS: |
554 |
+ |
argv = alloca(7 * sizeof(char *)); |
555 |
+ |
path = string_param(j->intparams[KP_PATH]); |
556 |
+ |
if (path == NULL) { |
557 |
+ |
jail_warnx(j, "mount.procfs: no path"); |
558 |
+ |
return -1; |
559 |
+ |
} |
560 |
+ |
devpath = alloca(strlen(path) + 6); |
561 |
+ |
sprintf(devpath, "%s/proc", path); |
562 |
+ |
if (check_path(j, "mount.procfs", devpath, 0, |
563 |
+ |
down ? "procfs" : NULL) < 0) |
564 |
+ |
return -1; |
565 |
+ |
if (down) { |
566 |
+ |
*(const char **)&argv[0] = "/sbin/umount"; |
567 |
+ |
argv[1] = devpath; |
568 |
+ |
argv[2] = NULL; |
569 |
+ |
} else { |
570 |
+ |
*(const char **)&argv[0] = _PATH_MOUNT; |
571 |
+ |
*(const char **)&argv[1] = "-t"; |
572 |
+ |
*(const char **)&argv[2] = "procfs"; |
573 |
+ |
*(const char **)&argv[3] = "."; |
574 |
+ |
argv[4] = devpath; |
575 |
+ |
argv[5] = NULL; |
576 |
+ |
} |
577 |
+ |
break; |
578 |
+ |
|
579 |
|
case IP_COMMAND: |
580 |
|
if (j->name != NULL) |
581 |
|
goto default_command; |
715 |
|
if (term != NULL) |
716 |
|
setenv("TERM", term, 1); |
717 |
|
} |
718 |
+ |
if (setgid(pwd->pw_gid) < 0) { |
719 |
+ |
jail_warnx(j, "setgid %d: %s", pwd->pw_gid, |
720 |
+ |
strerror(errno)); |
721 |
+ |
exit(1); |
722 |
+ |
} |
723 |
|
if (setusercontext(lcap, pwd, pwd->pw_uid, username |
724 |
|
? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN |
725 |
|
: LOGIN_SETPATH | LOGIN_SETENV) < 0) { |
777 |
|
if (j->timeout.tv_sec == 0) |
778 |
|
requeue(j, &sleeping); |
779 |
|
else { |
780 |
< |
/* File the jail in the sleep queue acording to its timeout. */ |
780 |
> |
/* File the jail in the sleep queue according to its timeout. */ |
781 |
|
TAILQ_REMOVE(j->queue, j, tq); |
782 |
|
TAILQ_FOREACH(tj, &sleeping, tq) { |
783 |
|
if (!tj->timeout.tv_sec || |
893 |
|
{ |
894 |
|
const struct passwd *pwd; |
895 |
|
|
896 |
+ |
errno = 0; |
897 |
|
*pwdp = pwd = username ? getpwnam(username) : getpwuid(getuid()); |
898 |
|
if (pwd == NULL) { |
899 |
|
if (errno) |