diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/faudit/dbus.c | 2 | ||||
-rw-r--r-- | src/firejail/bandwidth.c | 8 | ||||
-rw-r--r-- | src/firejail/checkcfg.c | 4 | ||||
-rw-r--r-- | src/firejail/cmdline.c | 12 | ||||
-rw-r--r-- | src/firejail/env.c | 11 | ||||
-rw-r--r-- | src/firejail/firejail.h | 5 | ||||
-rw-r--r-- | src/firejail/fs.c | 14 | ||||
-rw-r--r-- | src/firejail/fs_home.c | 5 | ||||
-rw-r--r-- | src/firejail/join.c | 47 | ||||
-rw-r--r-- | src/firejail/main.c | 193 | ||||
-rw-r--r-- | src/firejail/network.txt | 2 | ||||
-rw-r--r-- | src/firejail/no_sandbox.c | 7 | ||||
-rw-r--r-- | src/firejail/restricted_shell.c | 33 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 45 | ||||
-rw-r--r-- | src/firejail/x11.c | 100 |
15 files changed, 333 insertions, 155 deletions
diff --git a/src/faudit/dbus.c b/src/faudit/dbus.c index 1edce5802..64f5d8ae4 100644 --- a/src/faudit/dbus.c +++ b/src/faudit/dbus.c | |||
@@ -63,8 +63,6 @@ void dbus_test(void) { | |||
63 | if (ptr) | 63 | if (ptr) |
64 | *ptr = '\0'; | 64 | *ptr = '\0'; |
65 | check_session_bus(sockfile); | 65 | check_session_bus(sockfile); |
66 | |||
67 | sockfile -= 13; | ||
68 | } | 66 | } |
69 | free(bus); | 67 | free(bus); |
70 | } | 68 | } |
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c index 34c5ca509..5ff67b644 100644 --- a/src/firejail/bandwidth.c +++ b/src/firejail/bandwidth.c | |||
@@ -459,13 +459,15 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in | |||
459 | if (setregid(0, 0)) | 459 | if (setregid(0, 0)) |
460 | errExit("setregid"); | 460 | errExit("setregid"); |
461 | 461 | ||
462 | assert(cfg.shell); | ||
463 | |||
462 | char *arg[4]; | 464 | char *arg[4]; |
463 | arg[0] = "/bin/bash"; | 465 | arg[0] = cfg.shell; |
464 | arg[1] = "-c"; | 466 | arg[1] = "-c"; |
465 | arg[2] = cmd; | 467 | arg[2] = cmd; |
466 | arg[3] = NULL; | 468 | arg[3] = NULL; |
467 | execvp("/bin/bash", arg); | 469 | execvp(arg[0], arg); |
468 | 470 | ||
469 | // it will never get here | 471 | // it will never get here |
470 | exit(0); | 472 | errExit("execvp"); |
471 | } | 473 | } |
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index 3b60dafb6..019b54773 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -50,7 +50,7 @@ int checkcfg(int val) { | |||
50 | FILE *fp = fopen(fname, "r"); | 50 | FILE *fp = fopen(fname, "r"); |
51 | if (!fp) { | 51 | if (!fp) { |
52 | #ifdef HAVE_GLOBALCFG | 52 | #ifdef HAVE_GLOBALCFG |
53 | fprintf(stderr, "Warning: Firejail configuration file %s not found\n", fname); | 53 | fprintf(stderr, "Error: Firejail configuration file %s not found\n", fname); |
54 | exit(1); | 54 | exit(1); |
55 | #else | 55 | #else |
56 | initialized = 1; | 56 | initialized = 1; |
@@ -317,7 +317,7 @@ void print_compiletime_support(void) { | |||
317 | #endif | 317 | #endif |
318 | ); | 318 | ); |
319 | 319 | ||
320 | printf("\t- X11 snadboxing support is %s\n", | 320 | printf("\t- X11 sandboxing support is %s\n", |
321 | #ifdef HAVE_X11 | 321 | #ifdef HAVE_X11 |
322 | "enabled" | 322 | "enabled" |
323 | #else | 323 | #else |
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c index 48cbaffb7..cadf4795d 100644 --- a/src/firejail/cmdline.c +++ b/src/firejail/cmdline.c | |||
@@ -26,7 +26,9 @@ | |||
26 | #include <assert.h> | 26 | #include <assert.h> |
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | 28 | ||
29 | int cmdline_length(int argc, char **argv, int index) { | 29 | static int cmdline_length(int argc, char **argv, int index) { |
30 | assert(index != -1); | ||
31 | |||
30 | unsigned i,j; | 32 | unsigned i,j; |
31 | int len = 0; | 33 | int len = 0; |
32 | unsigned argcnt = argc - index; | 34 | unsigned argcnt = argc - index; |
@@ -62,7 +64,9 @@ int cmdline_length(int argc, char **argv, int index) { | |||
62 | return len; | 64 | return len; |
63 | } | 65 | } |
64 | 66 | ||
65 | void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { | 67 | static void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { |
68 | assert(index != -1); | ||
69 | |||
66 | unsigned i,j; | 70 | unsigned i,j; |
67 | unsigned argcnt = argc - index; | 71 | unsigned argcnt = argc - index; |
68 | bool in_quotes = false; | 72 | bool in_quotes = false; |
@@ -131,6 +135,10 @@ void quote_cmdline(char *command_line, char *window_title, int len, int argc, ch | |||
131 | } | 135 | } |
132 | 136 | ||
133 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { | 137 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { |
138 | // index == -1 could happen if we have --shell=none and no program was specified | ||
139 | // the program should exit with an error before entering this function | ||
140 | assert(index != -1); | ||
141 | |||
134 | int len = cmdline_length(argc, argv, index); | 142 | int len = cmdline_length(argc, argv, index); |
135 | if (len > ARG_MAX) { | 143 | if (len > ARG_MAX) { |
136 | errno = E2BIG; | 144 | errno = E2BIG; |
diff --git a/src/firejail/env.c b/src/firejail/env.c index 79d6b81e3..c05abadca 100644 --- a/src/firejail/env.c +++ b/src/firejail/env.c | |||
@@ -121,19 +121,16 @@ void env_defaults(void) { | |||
121 | errExit("setenv"); | 121 | errExit("setenv"); |
122 | if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, | 122 | if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, |
123 | errExit("setenv"); | 123 | errExit("setenv"); |
124 | if (arg_zsh && setenv("SHELL", "/usr/bin/zsh", 1) < 0) | ||
125 | errExit("setenv"); | ||
126 | if (arg_csh && setenv("SHELL", "/bin/csh", 1) < 0) | ||
127 | errExit("setenv"); | ||
128 | if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0) | 124 | if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0) |
129 | errExit("setenv"); | 125 | errExit("setenv"); |
130 | // set prompt color to green | 126 | // set prompt color to green |
131 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' | 127 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' |
132 | if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) | 128 | // if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) |
133 | errExit("setenv"); | 129 | // errExit("setenv"); |
134 | 130 | ||
135 | // set the window title | 131 | // set the window title |
136 | printf("\033]0;firejail %s\007", cfg.window_title);fflush(0); | 132 | printf("\033]0;firejail %s\007", cfg.window_title); |
133 | fflush(0); | ||
137 | } | 134 | } |
138 | 135 | ||
139 | // parse and store the environment setting | 136 | // parse and store the environment setting |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index ee70f19f1..1fed3fcdf 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #include "../include/common.h" | 22 | #include "../include/common.h" |
23 | #include "../include/euid_common.h" | 23 | #include "../include/euid_common.h" |
24 | 24 | ||
25 | // debug restricted shell | ||
26 | //#define DEBUG_RESTRICTED_SHELL | ||
25 | 27 | ||
26 | // filesystem | 28 | // filesystem |
27 | #define RUN_FIREJAIL_BASEDIR "/run" | 29 | #define RUN_FIREJAIL_BASEDIR "/run" |
@@ -268,6 +270,7 @@ extern int arg_audit; // audit | |||
268 | extern char *arg_audit_prog; // audit | 270 | extern char *arg_audit_prog; // audit |
269 | extern int arg_apparmor; // apparmor | 271 | extern int arg_apparmor; // apparmor |
270 | 272 | ||
273 | extern int login_shell; | ||
271 | extern int parent_to_child_fds[2]; | 274 | extern int parent_to_child_fds[2]; |
272 | extern int child_to_parent_fds[2]; | 275 | extern int child_to_parent_fds[2]; |
273 | extern pid_t sandbox_pid; | 276 | extern pid_t sandbox_pid; |
@@ -278,6 +281,7 @@ extern int fullargc; | |||
278 | 281 | ||
279 | // main.c | 282 | // main.c |
280 | void check_user_namespace(void); | 283 | void check_user_namespace(void); |
284 | char *guess_shell(void); | ||
281 | 285 | ||
282 | // sandbox.c | 286 | // sandbox.c |
283 | int sandbox(void* sandbox_arg); | 287 | int sandbox(void* sandbox_arg); |
@@ -358,7 +362,6 @@ void shut(pid_t pid); | |||
358 | void shut_name(const char *name); | 362 | void shut_name(const char *name); |
359 | 363 | ||
360 | // restricted_shell.c | 364 | // restricted_shell.c |
361 | extern char *restricted_user; | ||
362 | int restricted_shell(const char *user); | 365 | int restricted_shell(const char *user); |
363 | 366 | ||
364 | // arp.c | 367 | // arp.c |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index c152abe0d..484b99537 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1141,13 +1141,13 @@ int fs_check_chroot_dir(const char *rootdir) { | |||
1141 | free(name); | 1141 | free(name); |
1142 | 1142 | ||
1143 | // check /bin/bash | 1143 | // check /bin/bash |
1144 | if (asprintf(&name, "%s/bin/bash", rootdir) == -1) | 1144 | // if (asprintf(&name, "%s/bin/bash", rootdir) == -1) |
1145 | errExit("asprintf"); | 1145 | // errExit("asprintf"); |
1146 | if (stat(name, &s) == -1) { | 1146 | // if (stat(name, &s) == -1) { |
1147 | fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); | 1147 | // fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); |
1148 | return 1; | 1148 | // return 1; |
1149 | } | 1149 | // } |
1150 | free(name); | 1150 | // free(name); |
1151 | 1151 | ||
1152 | // check x11 socket directory | 1152 | // check x11 socket directory |
1153 | if (getenv("FIREJAIL_X11")) { | 1153 | if (getenv("FIREJAIL_X11")) { |
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index c1e983c16..d328d5f1c 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -32,8 +32,9 @@ | |||
32 | 32 | ||
33 | static void skel(const char *homedir, uid_t u, gid_t g) { | 33 | static void skel(const char *homedir, uid_t u, gid_t g) { |
34 | char *fname; | 34 | char *fname; |
35 | |||
35 | // zsh | 36 | // zsh |
36 | if (arg_zsh) { | 37 | if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) { |
37 | // copy skel files | 38 | // copy skel files |
38 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) | 39 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) |
39 | errExit("asprintf"); | 40 | errExit("asprintf"); |
@@ -63,7 +64,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
63 | free(fname); | 64 | free(fname); |
64 | } | 65 | } |
65 | // csh | 66 | // csh |
66 | else if (arg_csh) { | 67 | else if (!arg_shell_none && strcmp(cfg.shell,"/bin/csh") == 0) { |
67 | // copy skel files | 68 | // copy skel files |
68 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) | 69 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) |
69 | errExit("asprintf"); | 70 | errExit("asprintf"); |
diff --git a/src/firejail/join.c b/src/firejail/join.c index 0b5b6a34a..632715fea 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -330,32 +330,15 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
330 | } | 330 | } |
331 | } | 331 | } |
332 | 332 | ||
333 | // run cmdline trough /bin/bash | 333 | // run cmdline trough shell |
334 | if (cfg.command_line == NULL) { | 334 | if (cfg.command_line == NULL) { |
335 | assert(cfg.shell); | ||
335 | 336 | ||
336 | // replace the process with a shell | 337 | // replace the process with a shell |
337 | if (cfg.shell) | 338 | execlp(cfg.shell, cfg.shell, NULL); |
338 | execlp(cfg.shell, cfg.shell, NULL); | ||
339 | else if (arg_zsh) | ||
340 | execlp("/usr/bin/zsh", "/usr/bin/zsh", NULL); | ||
341 | else if (arg_csh) | ||
342 | execlp("/bin/csh", "/bin/csh", NULL); | ||
343 | else { | ||
344 | struct stat s; | ||
345 | if (stat("/bin/bash", &s) == 0) | ||
346 | execlp("/bin/bash", "/bin/bash", NULL); | ||
347 | else if (stat("/usr/bin/zsh", &s) == 0) | ||
348 | execlp("/usr/bin/zsh", "/usr/bin/zsh", NULL); | ||
349 | else if (stat("/bin/csh", &s) == 0) | ||
350 | execlp("/bin/csh", "/bin/csh", NULL); | ||
351 | else if (stat("/bin/sh", &s) == 0) | ||
352 | execlp("/bin/sh", "/bin/sh", NULL); | ||
353 | } | ||
354 | 339 | ||
355 | // no shell found, print an error and exit | 340 | // it should never get here |
356 | fprintf(stderr, "Error: no POSIX shell found\n"); | 341 | errExit("execlp"); |
357 | sleep(5); | ||
358 | exit(1); | ||
359 | } | 342 | } |
360 | else { | 343 | else { |
361 | // run the command supplied by the user | 344 | // run the command supplied by the user |
@@ -398,19 +381,10 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
398 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); | 381 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); |
399 | exit(1); | 382 | exit(1); |
400 | } else { | 383 | } else { |
401 | // choose the shell requested by the user, or use bash as default | 384 | assert(cfg.shell); |
402 | char *sh; | 385 | |
403 | if (cfg.shell) | ||
404 | sh = cfg.shell; | ||
405 | else if (arg_zsh) | ||
406 | sh = "/usr/bin/zsh"; | ||
407 | else if (arg_csh) | ||
408 | sh = "/bin/csh"; | ||
409 | else | ||
410 | sh = "/bin/bash"; | ||
411 | |||
412 | char *arg[5]; | 386 | char *arg[5]; |
413 | arg[0] = sh; | 387 | arg[0] = cfg.shell; |
414 | arg[1] = "-c"; | 388 | arg[1] = "-c"; |
415 | if (arg_debug) | 389 | if (arg_debug) |
416 | printf("Starting %s\n", cfg.command_line); | 390 | printf("Starting %s\n", cfg.command_line); |
@@ -423,7 +397,10 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
423 | arg[3] = cfg.command_line; | 397 | arg[3] = cfg.command_line; |
424 | arg[4] = NULL; | 398 | arg[4] = NULL; |
425 | } | 399 | } |
426 | execvp("/bin/bash", arg); | 400 | execvp(arg[0], arg); |
401 | |||
402 | // it should never get here | ||
403 | errExit("execvp"); | ||
427 | } | 404 | } |
428 | } | 405 | } |
429 | 406 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index 120809456..8de5f9a6e 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -105,6 +105,7 @@ int arg_appimage = 0; // appimage | |||
105 | int arg_audit = 0; // audit | 105 | int arg_audit = 0; // audit |
106 | char *arg_audit_prog; // audit | 106 | char *arg_audit_prog; // audit |
107 | int arg_apparmor; // apparmor | 107 | int arg_apparmor; // apparmor |
108 | int login_shell = 0; | ||
108 | 109 | ||
109 | int parent_to_child_fds[2]; | 110 | int parent_to_child_fds[2]; |
110 | int child_to_parent_fds[2]; | 111 | int child_to_parent_fds[2]; |
@@ -238,7 +239,8 @@ void check_user_namespace(void) { | |||
238 | stat("/proc/self/gid_map", &s3) == 0) | 239 | stat("/proc/self/gid_map", &s3) == 0) |
239 | arg_noroot = 1; | 240 | arg_noroot = 1; |
240 | else { | 241 | else { |
241 | fprintf(stderr, "Warning: user namespaces not available in the current kernel.\n"); | 242 | if (!arg_quiet || arg_debug) |
243 | fprintf(stderr, "Warning: user namespaces not available in the current kernel.\n"); | ||
242 | arg_noroot = 0; | 244 | arg_noroot = 0; |
243 | } | 245 | } |
244 | } | 246 | } |
@@ -566,7 +568,18 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
566 | #endif | 568 | #endif |
567 | else if (strncmp(argv[i], "--join=", 7) == 0) { | 569 | else if (strncmp(argv[i], "--join=", 7) == 0) { |
568 | logargs(argc, argv); | 570 | logargs(argc, argv); |
569 | 571 | ||
572 | if (arg_shell_none) { | ||
573 | if (argc <= (i+1)) { | ||
574 | fprintf(stderr, "Error: --shell=none set, but no command specified\n"); | ||
575 | exit(1); | ||
576 | } | ||
577 | cfg.original_program_index = i + 1; | ||
578 | } | ||
579 | |||
580 | if (!cfg.shell && !arg_shell_none) | ||
581 | cfg.shell = guess_shell(); | ||
582 | |||
570 | // join sandbox by pid or by name | 583 | // join sandbox by pid or by name |
571 | pid_t pid; | 584 | pid_t pid; |
572 | if (read_pid(argv[i] + 7, &pid) == 0) | 585 | if (read_pid(argv[i] + 7, &pid) == 0) |
@@ -574,6 +587,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
574 | else | 587 | else |
575 | join_name(argv[i] + 7, argc, argv, i + 1); | 588 | join_name(argv[i] + 7, argc, argv, i + 1); |
576 | exit(0); | 589 | exit(0); |
590 | |||
577 | } | 591 | } |
578 | #ifdef HAVE_NETWORK | 592 | #ifdef HAVE_NETWORK |
579 | else if (strncmp(argv[i], "--join-network=", 15) == 0) { | 593 | else if (strncmp(argv[i], "--join-network=", 15) == 0) { |
@@ -745,6 +759,25 @@ static void detect_quiet(int argc, char **argv) { | |||
745 | } | 759 | } |
746 | } | 760 | } |
747 | 761 | ||
762 | char *guess_shell(void) { | ||
763 | char *shell; | ||
764 | // shells in order of preference | ||
765 | char *shells[] = {"/bin/bash", "/bin/csh", "/usr/bin/zsh", "/bin/sh", "/bin/ash", NULL }; | ||
766 | |||
767 | int i = 0; | ||
768 | while (shells[i] != NULL) { | ||
769 | struct stat s; | ||
770 | // access call checks as real UID/GID, not as effective UID/GID | ||
771 | if (stat(shells[i], &s) == 0 && access(shells[i], R_OK) == 0) { | ||
772 | shell = shells[i]; | ||
773 | break; | ||
774 | } | ||
775 | i++; | ||
776 | } | ||
777 | |||
778 | return shell; | ||
779 | } | ||
780 | |||
748 | //******************************************* | 781 | //******************************************* |
749 | // Main program | 782 | // Main program |
750 | //******************************************* | 783 | //******************************************* |
@@ -883,6 +916,41 @@ int main(int argc, char **argv) { | |||
883 | if (strcmp(comm, "sshd") == 0) { | 916 | if (strcmp(comm, "sshd") == 0) { |
884 | arg_quiet = 1; | 917 | arg_quiet = 1; |
885 | parent_sshd = 1; | 918 | parent_sshd = 1; |
919 | |||
920 | #ifdef DEBUG_RESTRICTED_SHELL | ||
921 | {EUID_ROOT(); | ||
922 | FILE *fp = fopen("/firelog", "w"); | ||
923 | if (fp) { | ||
924 | int i; | ||
925 | fprintf(fp, "argc %d: ", argc); | ||
926 | for (i = 0; i < argc; i++) | ||
927 | fprintf(fp, "#%s# ", argv[i]); | ||
928 | fprintf(fp, "\n"); | ||
929 | fclose(fp); | ||
930 | } | ||
931 | EUID_USER();} | ||
932 | #endif | ||
933 | // run sftp and scp directly without any sandboxing | ||
934 | // regular login has argv[0] == "-firejail" | ||
935 | if (*argv[0] != '-') { | ||
936 | if (strcmp(argv[1], "-c") == 0 && argc > 2) { | ||
937 | if (strcmp(argv[2], "/usr/lib/openssh/sftp-server") == 0 || | ||
938 | strncmp(argv[2], "scp ", 4) == 0) { | ||
939 | #ifdef DEBUG_RESTRICTED_SHELL | ||
940 | {EUID_ROOT(); | ||
941 | FILE *fp = fopen("/firelog", "a"); | ||
942 | if (fp) { | ||
943 | fprintf(fp, "run without a sandbox\n"); | ||
944 | fclose(fp); | ||
945 | } | ||
946 | EUID_USER();} | ||
947 | #endif | ||
948 | |||
949 | drop_privs(1); | ||
950 | run_no_sandbox(argc, argv); | ||
951 | } | ||
952 | } | ||
953 | } | ||
886 | } | 954 | } |
887 | free(comm); | 955 | free(comm); |
888 | } | 956 | } |
@@ -890,8 +958,25 @@ int main(int argc, char **argv) { | |||
890 | 958 | ||
891 | // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users | 959 | // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users |
892 | if (*argv[0] == '-' || parent_sshd) { | 960 | if (*argv[0] == '-' || parent_sshd) { |
961 | if (argc == 1) | ||
962 | login_shell = 1; | ||
893 | fullargc = restricted_shell(cfg.username); | 963 | fullargc = restricted_shell(cfg.username); |
894 | if (fullargc) { | 964 | if (fullargc) { |
965 | |||
966 | #ifdef DEBUG_RESTRICTED_SHELL | ||
967 | {EUID_ROOT(); | ||
968 | FILE *fp = fopen("/firelog", "a"); | ||
969 | if (fp) { | ||
970 | fprintf(fp, "fullargc %d: ", fullargc); | ||
971 | int i; | ||
972 | for (i = 0; i < fullargc; i++) | ||
973 | fprintf(fp, "#%s# ", fullargv[i]); | ||
974 | fprintf(fp, "\n"); | ||
975 | fclose(fp); | ||
976 | } | ||
977 | EUID_USER();} | ||
978 | #endif | ||
979 | |||
895 | int j; | 980 | int j; |
896 | for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++) | 981 | for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++) |
897 | fullargv[j] = argv[i]; | 982 | fullargv[j] = argv[i]; |
@@ -899,6 +984,20 @@ int main(int argc, char **argv) { | |||
899 | // replace argc/argv with fullargc/fullargv | 984 | // replace argc/argv with fullargc/fullargv |
900 | argv = fullargv; | 985 | argv = fullargv; |
901 | argc = j; | 986 | argc = j; |
987 | |||
988 | #ifdef DEBUG_RESTRICTED_SHELL | ||
989 | {EUID_ROOT(); | ||
990 | FILE *fp = fopen("/firelog", "a"); | ||
991 | if (fp) { | ||
992 | fprintf(fp, "argc %d: ", argc); | ||
993 | int i; | ||
994 | for (i = 0; i < argc; i++) | ||
995 | fprintf(fp, "#%s# ", argv[i]); | ||
996 | fprintf(fp, "\n"); | ||
997 | fclose(fp); | ||
998 | } | ||
999 | EUID_USER();} | ||
1000 | #endif | ||
902 | } | 1001 | } |
903 | } | 1002 | } |
904 | else { | 1003 | else { |
@@ -1582,7 +1681,8 @@ int main(int argc, char **argv) { | |||
1582 | errExit("strdup"); | 1681 | errExit("strdup"); |
1583 | 1682 | ||
1584 | if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac, &intf->mtu)) { | 1683 | if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac, &intf->mtu)) { |
1585 | fprintf(stderr, "Warning: interface %s is not configured\n", intf->dev); | 1684 | if (!arg_quiet || arg_debug) |
1685 | fprintf(stderr, "Warning: interface %s is not configured\n", intf->dev); | ||
1586 | } | 1686 | } |
1587 | intf->configured = 1; | 1687 | intf->configured = 1; |
1588 | } | 1688 | } |
@@ -1913,26 +2013,26 @@ int main(int argc, char **argv) { | |||
1913 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | 2013 | fprintf(stderr, "Error: --shell=none was already specified.\n"); |
1914 | return 1; | 2014 | return 1; |
1915 | } | 2015 | } |
1916 | if (arg_zsh || cfg.shell ) { | 2016 | if (cfg.shell) { |
1917 | fprintf(stderr, "Error: only one default user shell can be specified\n"); | 2017 | fprintf(stderr, "Error: only one default user shell can be specified\n"); |
1918 | return 1; | 2018 | return 1; |
1919 | } | 2019 | } |
1920 | arg_csh = 1; | 2020 | cfg.shell = "/bin/csh"; |
1921 | } | 2021 | } |
1922 | else if (strcmp(argv[i], "--zsh") == 0) { | 2022 | else if (strcmp(argv[i], "--zsh") == 0) { |
1923 | if (arg_shell_none) { | 2023 | if (arg_shell_none) { |
1924 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | 2024 | fprintf(stderr, "Error: --shell=none was already specified.\n"); |
1925 | return 1; | 2025 | return 1; |
1926 | } | 2026 | } |
1927 | if (arg_csh || cfg.shell ) { | 2027 | if (cfg.shell) { |
1928 | fprintf(stderr, "Error: only one default user shell can be specified\n"); | 2028 | fprintf(stderr, "Error: only one default user shell can be specified\n"); |
1929 | return 1; | 2029 | return 1; |
1930 | } | 2030 | } |
1931 | arg_zsh = 1; | 2031 | cfg.shell = "/bin/zsh"; |
1932 | } | 2032 | } |
1933 | else if (strcmp(argv[i], "--shell=none") == 0) { | 2033 | else if (strcmp(argv[i], "--shell=none") == 0) { |
1934 | arg_shell_none = 1; | 2034 | arg_shell_none = 1; |
1935 | if (arg_csh || arg_zsh || cfg.shell) { | 2035 | if (cfg.shell) { |
1936 | fprintf(stderr, "Error: a shell was already specified\n"); | 2036 | fprintf(stderr, "Error: a shell was already specified\n"); |
1937 | return 1; | 2037 | return 1; |
1938 | } | 2038 | } |
@@ -1944,7 +2044,7 @@ int main(int argc, char **argv) { | |||
1944 | } | 2044 | } |
1945 | invalid_filename(argv[i] + 8); | 2045 | invalid_filename(argv[i] + 8); |
1946 | 2046 | ||
1947 | if (arg_csh || arg_zsh || cfg.shell) { | 2047 | if (cfg.shell) { |
1948 | fprintf(stderr, "Error: only one user shell can be specified\n"); | 2048 | fprintf(stderr, "Error: only one user shell can be specified\n"); |
1949 | return 1; | 2049 | return 1; |
1950 | } | 2050 | } |
@@ -1954,9 +2054,18 @@ int main(int argc, char **argv) { | |||
1954 | fprintf(stderr, "Error: invalid shell\n"); | 2054 | fprintf(stderr, "Error: invalid shell\n"); |
1955 | exit(1); | 2055 | exit(1); |
1956 | } | 2056 | } |
1957 | 2057 | ||
1958 | // access call checks as real UID/GID, not as effective UID/GID | 2058 | // access call checks as real UID/GID, not as effective UID/GID |
1959 | if (access(cfg.shell, R_OK)) { | 2059 | if(cfg.chrootdir) { |
2060 | char *shellpath; | ||
2061 | if (asprintf(&shellpath, "%s%s", cfg.chrootdir, cfg.shell) == -1) | ||
2062 | errExit("asprintf"); | ||
2063 | if (access(shellpath, R_OK)) { | ||
2064 | fprintf(stderr, "Error: cannot access shell file in chroot\n"); | ||
2065 | exit(1); | ||
2066 | } | ||
2067 | free(shellpath); | ||
2068 | } else if (access(cfg.shell, R_OK)) { | ||
1960 | fprintf(stderr, "Error: cannot access shell file\n"); | 2069 | fprintf(stderr, "Error: cannot access shell file\n"); |
1961 | exit(1); | 2070 | exit(1); |
1962 | } | 2071 | } |
@@ -1999,10 +2108,18 @@ int main(int argc, char **argv) { | |||
1999 | break; | 2108 | break; |
2000 | } | 2109 | } |
2001 | } | 2110 | } |
2111 | |||
2112 | // prog_index could still be -1 if no program was specified | ||
2113 | if (prog_index == -1 && arg_shell_none) { | ||
2114 | fprintf(stderr, "shell=none configured, but no program specified\n"); | ||
2115 | exit(1); | ||
2116 | } | ||
2002 | 2117 | ||
2003 | // check trace configuration | 2118 | // check trace configuration |
2004 | if (arg_trace && arg_tracelog) | 2119 | if (arg_trace && arg_tracelog) { |
2005 | fprintf(stderr, "Warning: --trace and --tracelog are mutually exclusive; --tracelog disabled\n"); | 2120 | if (!arg_quiet || arg_debug) |
2121 | fprintf(stderr, "Warning: --trace and --tracelog are mutually exclusive; --tracelog disabled\n"); | ||
2122 | } | ||
2006 | 2123 | ||
2007 | // check user namespace (--noroot) options | 2124 | // check user namespace (--noroot) options |
2008 | if (arg_noroot) { | 2125 | if (arg_noroot) { |
@@ -2026,27 +2143,23 @@ int main(int argc, char **argv) { | |||
2026 | free(msg); | 2143 | free(msg); |
2027 | } | 2144 | } |
2028 | 2145 | ||
2029 | // build the sandbox command | 2146 | // guess shell if unspecified |
2030 | if (prog_index == -1 && arg_zsh) { | 2147 | if (!arg_shell_none && !cfg.shell) { |
2031 | cfg.command_line = "/usr/bin/zsh"; | 2148 | cfg.shell = guess_shell(); |
2032 | cfg.window_title = "/usr/bin/zsh"; | 2149 | if (!cfg.shell) { |
2033 | cfg.command_name = "zsh"; | 2150 | fprintf(stderr, "Error: unable to guess your shell, please set explicitly by using --shell option.\n"); |
2034 | } | 2151 | exit(1); |
2035 | else if (prog_index == -1 && arg_csh) { | 2152 | } |
2036 | cfg.command_line = "/bin/csh"; | 2153 | if (arg_debug) |
2037 | cfg.window_title = "/bin/csh"; | 2154 | printf("Autoselecting %s as shell\n", cfg.shell); |
2038 | cfg.command_name = "csh"; | ||
2039 | } | 2155 | } |
2040 | else if (prog_index == -1 && cfg.shell) { | 2156 | |
2157 | // build the sandbox command | ||
2158 | if (prog_index == -1 && cfg.shell) { | ||
2041 | cfg.command_line = cfg.shell; | 2159 | cfg.command_line = cfg.shell; |
2042 | cfg.window_title = cfg.shell; | 2160 | cfg.window_title = cfg.shell; |
2043 | cfg.command_name = cfg.shell; | 2161 | cfg.command_name = cfg.shell; |
2044 | } | 2162 | } |
2045 | else if (prog_index == -1) { | ||
2046 | cfg.command_line = "/bin/bash"; | ||
2047 | cfg.window_title = "/bin/bash"; | ||
2048 | cfg.command_name = "bash"; | ||
2049 | } | ||
2050 | else if (arg_appimage) { | 2163 | else if (arg_appimage) { |
2051 | if (arg_debug) | 2164 | if (arg_debug) |
2052 | printf("Configuring appimage environment\n"); | 2165 | printf("Configuring appimage environment\n"); |
@@ -2056,6 +2169,10 @@ int main(int argc, char **argv) { | |||
2056 | else { | 2169 | else { |
2057 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); | 2170 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); |
2058 | } | 2171 | } |
2172 | /* else { | ||
2173 | fprintf(stderr, "Error: command must be specified when --shell=none used.\n"); | ||
2174 | exit(1); | ||
2175 | }*/ | ||
2059 | 2176 | ||
2060 | assert(cfg.command_name); | 2177 | assert(cfg.command_name); |
2061 | if (arg_debug) | 2178 | if (arg_debug) |
@@ -2086,10 +2203,14 @@ int main(int argc, char **argv) { | |||
2086 | 2203 | ||
2087 | // use default.profile as the default | 2204 | // use default.profile as the default |
2088 | if (!custom_profile && !arg_noprofile) { | 2205 | if (!custom_profile && !arg_noprofile) { |
2089 | if (cfg.chrootdir) | 2206 | if (cfg.chrootdir) { |
2090 | fprintf(stderr, "Warning: default profile disabled by --chroot option\n"); | 2207 | if (!arg_quiet || arg_debug) |
2091 | else if (arg_overlay) | 2208 | fprintf(stderr, "Warning: default profile disabled by --chroot option\n"); |
2092 | fprintf(stderr, "Warning: default profile disabled by --overlay option\n"); | 2209 | } |
2210 | else if (arg_overlay) { | ||
2211 | if (!arg_quiet || arg_debug) | ||
2212 | fprintf(stderr, "Warning: default profile disabled by --overlay option\n"); | ||
2213 | } | ||
2093 | else { | 2214 | else { |
2094 | // try to load a default profile | 2215 | // try to load a default profile |
2095 | char *profile_name = DEFAULT_USER_PROFILE; | 2216 | char *profile_name = DEFAULT_USER_PROFILE; |
@@ -2152,11 +2273,13 @@ int main(int argc, char **argv) { | |||
2152 | errExit("pipe"); | 2273 | errExit("pipe"); |
2153 | 2274 | ||
2154 | if (arg_noroot && arg_overlay) { | 2275 | if (arg_noroot && arg_overlay) { |
2155 | fprintf(stderr, "Warning: --overlay and --noroot are mutually exclusive, noroot disabled\n"); | 2276 | if (!arg_quiet || arg_debug) |
2277 | fprintf(stderr, "Warning: --overlay and --noroot are mutually exclusive, noroot disabled\n"); | ||
2156 | arg_noroot = 0; | 2278 | arg_noroot = 0; |
2157 | } | 2279 | } |
2158 | else if (arg_noroot && cfg.chrootdir) { | 2280 | else if (arg_noroot && cfg.chrootdir) { |
2159 | fprintf(stderr, "Warning: --chroot and --noroot are mutually exclusive, noroot disabled\n"); | 2281 | if (!arg_quiet || arg_debug) |
2282 | fprintf(stderr, "Warning: --chroot and --noroot are mutually exclusive, noroot disabled\n"); | ||
2160 | arg_noroot = 0; | 2283 | arg_noroot = 0; |
2161 | } | 2284 | } |
2162 | 2285 | ||
diff --git a/src/firejail/network.txt b/src/firejail/network.txt index 673d5b941..f6df0f485 100644 --- a/src/firejail/network.txt +++ b/src/firejail/network.txt | |||
@@ -13,7 +13,7 @@ net_configure_bridge(br, device) { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | net_configure_sandbox_ip(br) { | 15 | net_configure_sandbox_ip(br) { |
16 | if br->ip_snadbox | 16 | if br->ip_sandbox |
17 | check br->ipsandbox inside the bridge network | 17 | check br->ipsandbox inside the bridge network |
18 | arp_check(br->ipsandbox) // send an arp req to check if anybody else is using this address | 18 | arp_check(br->ipsandbox) // send an arp req to check if anybody else is using this address |
19 | else | 19 | else |
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index f1fd04aec..80ed72dca 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c | |||
@@ -172,6 +172,8 @@ void run_no_sandbox(int argc, char **argv) { | |||
172 | int len = 0; | 172 | int len = 0; |
173 | int i; | 173 | int i; |
174 | for (i = 1; i < argc; i++) { | 174 | for (i = 1; i < argc; i++) { |
175 | if (i == 1 && strcmp(argv[i], "-c") == 0) | ||
176 | continue; | ||
175 | if (*argv[i] == '-') | 177 | if (*argv[i] == '-') |
176 | continue; | 178 | continue; |
177 | break; | 179 | break; |
@@ -202,8 +204,9 @@ void run_no_sandbox(int argc, char **argv) { | |||
202 | } | 204 | } |
203 | 205 | ||
204 | // start the program in /bin/sh | 206 | // start the program in /bin/sh |
205 | fprintf(stderr, "Warning: an existing sandbox was detected. " | 207 | if (!arg_quiet) |
206 | "%s will run without any additional sandboxing features in a /bin/sh shell\n", command); | 208 | fprintf(stderr, "Warning: an existing sandbox was detected. " |
209 | "%s will run without any additional sandboxing features in a /bin/sh shell\n", command); | ||
207 | int rv = system(command); | 210 | int rv = system(command); |
208 | (void) rv; | 211 | (void) rv; |
209 | if (allocated) | 212 | if (allocated) |
diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c index ee6e94957..24ce27c2e 100644 --- a/src/firejail/restricted_shell.c +++ b/src/firejail/restricted_shell.c | |||
@@ -40,7 +40,7 @@ int restricted_shell(const char *user) { | |||
40 | char buf[MAX_READ]; | 40 | char buf[MAX_READ]; |
41 | while (fgets(buf, MAX_READ, fp)) { | 41 | while (fgets(buf, MAX_READ, fp)) { |
42 | lineno++; | 42 | lineno++; |
43 | 43 | ||
44 | // remove empty spaces at the beginning of the line | 44 | // remove empty spaces at the beginning of the line |
45 | char *ptr = buf; | 45 | char *ptr = buf; |
46 | while (*ptr == ' ' || *ptr == '\t') { | 46 | while (*ptr == ' ' || *ptr == '\t') { |
@@ -48,7 +48,7 @@ int restricted_shell(const char *user) { | |||
48 | } | 48 | } |
49 | if (*ptr == '\n' || *ptr == '#') | 49 | if (*ptr == '\n' || *ptr == '#') |
50 | continue; | 50 | continue; |
51 | 51 | ||
52 | // parse line | 52 | // parse line |
53 | char *usr = ptr; | 53 | char *usr = ptr; |
54 | char *args = strchr(usr, ':'); | 54 | char *args = strchr(usr, ':'); |
@@ -56,6 +56,7 @@ int restricted_shell(const char *user) { | |||
56 | fprintf(stderr, "Error: users.conf line %d\n", lineno); | 56 | fprintf(stderr, "Error: users.conf line %d\n", lineno); |
57 | exit(1); | 57 | exit(1); |
58 | } | 58 | } |
59 | |||
59 | *args = '\0'; | 60 | *args = '\0'; |
60 | args++; | 61 | args++; |
61 | ptr = strchr(args, '\n'); | 62 | ptr = strchr(args, '\n'); |
@@ -70,29 +71,41 @@ int restricted_shell(const char *user) { | |||
70 | found = 1; | 71 | found = 1; |
71 | break; | 72 | break; |
72 | } | 73 | } |
74 | ptr2++; | ||
73 | } | 75 | } |
74 | if (!found) | 76 | if (!found) |
75 | continue; | 77 | continue; |
76 | 78 | ||
77 | // process user | 79 | // process user |
78 | if (strcmp(user, usr) == 0) { | 80 | if (strcmp(user, usr) == 0) { |
79 | restricted_user = strdup(user); | ||
80 | // extract program arguments | 81 | // extract program arguments |
81 | 82 | ||
82 | fullargv[0] = "firejail"; | 83 | fullargv[0] = "firejail"; |
83 | int i; | 84 | int i; |
84 | ptr = args; | 85 | ptr = args; |
85 | for (i = 1; i < MAX_ARGS; i++) { | 86 | for (i = 1; i < MAX_ARGS; i++) { |
86 | fullargv[i] = ptr; | 87 | // skip blanks |
87 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | 88 | while (*ptr == ' ' || *ptr == '\t') |
88 | ptr++; | 89 | ptr++; |
90 | fullargv[i] = ptr; | ||
91 | #ifdef DEBUG_RESTRICTED_SHELL | ||
92 | {EUID_ROOT(); | ||
93 | FILE *fp = fopen("/firelog", "a"); | ||
94 | if (fp) { | ||
95 | fprintf(fp, "i %d ptr #%s#\n", i, fullargv[i]); | ||
96 | fclose(fp); | ||
97 | } | ||
98 | EUID_USER();} | ||
99 | #endif | ||
100 | |||
89 | if (*ptr != '\0') { | 101 | if (*ptr != '\0') { |
102 | // go to the end of the word | ||
103 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | ||
104 | ptr++; | ||
90 | *ptr ='\0'; | 105 | *ptr ='\0'; |
91 | fullargv[i] = strdup(fullargv[i]); | 106 | fullargv[i] = strdup(fullargv[i]); |
92 | if (fullargv[i] == NULL) { | 107 | if (fullargv[i] == NULL) |
93 | fprintf(stderr, "Error: cannot allocate memory\n"); | 108 | errExit("strdup"); |
94 | exit(1); | ||
95 | } | ||
96 | ptr++; | 109 | ptr++; |
97 | while (*ptr == ' ' || *ptr == '\t') | 110 | while (*ptr == ' ' || *ptr == '\t') |
98 | ptr++; | 111 | ptr++; |
@@ -108,7 +121,7 @@ int restricted_shell(const char *user) { | |||
108 | } | 121 | } |
109 | } | 122 | } |
110 | fclose(fp); | 123 | fclose(fp); |
111 | 124 | ||
112 | return 0; | 125 | return 0; |
113 | } | 126 | } |
114 | 127 | ||
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index a131d9e91..8178cfc8e 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -325,30 +325,27 @@ static void start_application(void) { | |||
325 | // start the program using a shell | 325 | // start the program using a shell |
326 | //**************************************** | 326 | //**************************************** |
327 | else { | 327 | else { |
328 | // choose the shell requested by the user, or use bash as default | 328 | assert(cfg.shell); |
329 | char *sh; | 329 | assert(cfg.command_line); |
330 | if (cfg.shell) | 330 | |
331 | sh = cfg.shell; | ||
332 | else if (arg_zsh) | ||
333 | sh = "/usr/bin/zsh"; | ||
334 | else if (arg_csh) | ||
335 | sh = "/bin/csh"; | ||
336 | else | ||
337 | sh = "/bin/bash"; | ||
338 | |||
339 | char *arg[5]; | 331 | char *arg[5]; |
340 | int index = 0; | 332 | int index = 0; |
341 | arg[index++] = sh; | 333 | arg[index++] = cfg.shell; |
342 | arg[index++] = "-c"; | 334 | if (login_shell) { |
343 | assert(cfg.command_line); | 335 | arg[index++] = "-l"; |
344 | if (arg_debug) | 336 | if (arg_debug) |
345 | printf("Starting %s\n", cfg.command_line); | 337 | printf("Starting %s login shell\n", cfg.shell); |
346 | if (arg_doubledash) | 338 | } else { |
347 | arg[index++] = "--"; | 339 | arg[index++] = "-c"; |
348 | arg[index++] = cfg.command_line; | 340 | if (arg_debug) |
341 | printf("Running %s command through %s\n", cfg.command_line, cfg.shell); | ||
342 | if (arg_doubledash) | ||
343 | arg[index++] = "--"; | ||
344 | arg[index++] = cfg.command_line; | ||
345 | } | ||
349 | arg[index] = NULL; | 346 | arg[index] = NULL; |
350 | assert(index < 5); | 347 | assert(index < 5); |
351 | 348 | ||
352 | if (arg_debug) { | 349 | if (arg_debug) { |
353 | char *msg; | 350 | char *msg; |
354 | if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) | 351 | if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) |
@@ -356,7 +353,7 @@ static void start_application(void) { | |||
356 | logmsg(msg); | 353 | logmsg(msg); |
357 | free(msg); | 354 | free(msg); |
358 | } | 355 | } |
359 | 356 | ||
360 | if (arg_debug) { | 357 | if (arg_debug) { |
361 | int i; | 358 | int i; |
362 | for (i = 0; i < 5; i++) { | 359 | for (i = 0; i < 5; i++) { |
@@ -365,12 +362,12 @@ static void start_application(void) { | |||
365 | printf("execvp argument %d: %s\n", i, arg[i]); | 362 | printf("execvp argument %d: %s\n", i, arg[i]); |
366 | } | 363 | } |
367 | } | 364 | } |
368 | 365 | ||
369 | if (!arg_command && !arg_quiet) | 366 | if (!arg_command && !arg_quiet) |
370 | printf("Child process initialized\n"); | 367 | printf("Child process initialized\n"); |
371 | execvp(sh, arg); | 368 | execvp(arg[0], arg); |
372 | } | 369 | } |
373 | 370 | ||
374 | perror("execvp"); | 371 | perror("execvp"); |
375 | exit(1); // it should never get here!!! | 372 | exit(1); // it should never get here!!! |
376 | } | 373 | } |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index 58908e9df..ed6fa3741 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <fcntl.h> | ||
23 | #include <unistd.h> | 24 | #include <unistd.h> |
24 | #include <signal.h> | 25 | #include <signal.h> |
25 | #include <stdlib.h> | 26 | #include <stdlib.h> |
@@ -164,7 +165,7 @@ void x11_start_xephyr(int argc, char **argv) { | |||
164 | EUID_ASSERT(); | 165 | EUID_ASSERT(); |
165 | size_t i; | 166 | size_t i; |
166 | struct stat s; | 167 | struct stat s; |
167 | pid_t client = 0; | 168 | pid_t jail = 0; |
168 | pid_t server = 0; | 169 | pid_t server = 0; |
169 | 170 | ||
170 | setenv("FIREJAIL_X11", "yes", 1); | 171 | setenv("FIREJAIL_X11", "yes", 1); |
@@ -255,7 +256,7 @@ void x11_start_xephyr(int argc, char **argv) { | |||
255 | } | 256 | } |
256 | 257 | ||
257 | // remove --x11 arg | 258 | // remove --x11 arg |
258 | char *client_argv[argc+2]; | 259 | char *jail_argv[argc+2]; |
259 | size_t j = 0; | 260 | size_t j = 0; |
260 | for (i = 0; i < argc; i++) { | 261 | for (i = 0; i < argc; i++) { |
261 | if (strcmp(argv[i], "--x11") == 0) | 262 | if (strcmp(argv[i], "--x11") == 0) |
@@ -264,18 +265,18 @@ void x11_start_xephyr(int argc, char **argv) { | |||
264 | continue; | 265 | continue; |
265 | if (strcmp(argv[i], "--x11=xephyr") == 0) | 266 | if (strcmp(argv[i], "--x11=xephyr") == 0) |
266 | continue; | 267 | continue; |
267 | client_argv[j] = argv[i]; | 268 | jail_argv[j] = argv[i]; |
268 | j++; | 269 | j++; |
269 | } | 270 | } |
270 | client_argv[j] = NULL; | 271 | jail_argv[j] = NULL; |
271 | 272 | ||
272 | assert(j < argc+2); // no overrun | 273 | assert(j < argc+2); // no overrun |
273 | 274 | ||
274 | if (arg_debug) { | 275 | if (arg_debug) { |
275 | size_t i = 0; | 276 | size_t i = 0; |
276 | printf("xephyr client:"); | 277 | printf("xephyr client:"); |
277 | while (client_argv[i]!=NULL) { | 278 | while (jail_argv[i]!=NULL) { |
278 | printf(" \"%s\"", client_argv[i]); | 279 | printf(" \"%s\"", jail_argv[i]); |
279 | i++; | 280 | i++; |
280 | } | 281 | } |
281 | putchar('\n'); | 282 | putchar('\n'); |
@@ -322,13 +323,14 @@ void x11_start_xephyr(int argc, char **argv) { | |||
322 | 323 | ||
323 | setenv("DISPLAY", display_str, 1); | 324 | setenv("DISPLAY", display_str, 1); |
324 | // run attach command | 325 | // run attach command |
325 | client = fork(); | 326 | jail = fork(); |
326 | if (client < 0) | 327 | if (jail < 0) |
327 | errExit("fork"); | 328 | errExit("fork"); |
328 | if (client == 0) { | 329 | if (jail == 0) { |
329 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); | 330 | if (!arg_quiet) |
331 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); | ||
330 | 332 | ||
331 | execvp(client_argv[0], client_argv); | 333 | execvp(jail_argv[0], jail_argv); |
332 | perror("execvp"); | 334 | perror("execvp"); |
333 | exit(1); | 335 | exit(1); |
334 | } | 336 | } |
@@ -337,16 +339,21 @@ void x11_start_xephyr(int argc, char **argv) { | |||
337 | free(display_str); | 339 | free(display_str); |
338 | free(temp); | 340 | free(temp); |
339 | 341 | ||
340 | // wait for either server or client termination | 342 | // wait for either server or jail termination |
341 | pid_t pid = wait(); | 343 | pid_t pid = wait(NULL); |
342 | 344 | ||
343 | // see which process terminated and kill other | 345 | // see which process terminated and kill other |
344 | if (pid == server) { | 346 | if (pid == server) { |
345 | kill(client, SIGTERM); | 347 | kill(jail, SIGTERM); |
346 | } else if (pid == client) { | 348 | } else if (pid == jail) { |
347 | kill(server, SIGTERM); | 349 | kill(server, SIGTERM); |
348 | } | 350 | } |
349 | 351 | ||
352 | // without this closing Xephyr window may mess your terminal: | ||
353 | // "monitoring" process will release terminal before | ||
354 | // jail process ends and releases terminal | ||
355 | wait(NULL); // fulneral | ||
356 | |||
350 | exit(0); | 357 | exit(0); |
351 | } | 358 | } |
352 | 359 | ||
@@ -381,6 +388,13 @@ void x11_start_xpra(int argc, char **argv) { | |||
381 | // build the start command | 388 | // build the start command |
382 | char *server_argv[] = { "xpra", "start", display_str, "--no-daemon", NULL }; | 389 | char *server_argv[] = { "xpra", "start", display_str, "--no-daemon", NULL }; |
383 | 390 | ||
391 | int fd_null = -1; | ||
392 | if (arg_quiet) { | ||
393 | fd_null = open("/dev/null", O_RDWR); | ||
394 | if (fd_null == -1) | ||
395 | errExit("open"); | ||
396 | } | ||
397 | |||
384 | // start | 398 | // start |
385 | server = fork(); | 399 | server = fork(); |
386 | if (server < 0) | 400 | if (server < 0) |
@@ -388,6 +402,12 @@ void x11_start_xpra(int argc, char **argv) { | |||
388 | if (server == 0) { | 402 | if (server == 0) { |
389 | if (arg_debug) | 403 | if (arg_debug) |
390 | printf("Starting xpra...\n"); | 404 | printf("Starting xpra...\n"); |
405 | |||
406 | if (arg_quiet && fd_null != -1) { | ||
407 | dup2(fd_null,0); | ||
408 | dup2(fd_null,1); | ||
409 | dup2(fd_null,2); | ||
410 | } | ||
391 | 411 | ||
392 | execvp(server_argv[0], server_argv); | 412 | execvp(server_argv[0], server_argv); |
393 | perror("execvp"); | 413 | perror("execvp"); |
@@ -404,8 +424,7 @@ void x11_start_xpra(int argc, char **argv) { | |||
404 | sleep(1); | 424 | sleep(1); |
405 | if (stat(fname, &s) == 0) | 425 | if (stat(fname, &s) == 0) |
406 | break; | 426 | break; |
407 | }; | 427 | } |
408 | // sleep(1); | ||
409 | 428 | ||
410 | if (n == 10) { | 429 | if (n == 10) { |
411 | fprintf(stderr, "Error: failed to start xpra\n"); | 430 | fprintf(stderr, "Error: failed to start xpra\n"); |
@@ -427,7 +446,15 @@ void x11_start_xpra(int argc, char **argv) { | |||
427 | if (client < 0) | 446 | if (client < 0) |
428 | errExit("fork"); | 447 | errExit("fork"); |
429 | if (client == 0) { | 448 | if (client == 0) { |
430 | printf("\n*** Attaching to xpra display %d ***\n\n", display); | 449 | if (arg_quiet && fd_null != -1) { |
450 | dup2(fd_null,0); | ||
451 | dup2(fd_null,1); | ||
452 | dup2(fd_null,2); | ||
453 | } | ||
454 | |||
455 | if (!arg_quiet) | ||
456 | printf("\n*** Attaching to xpra display %d ***\n\n", display); | ||
457 | |||
431 | execvp(attach_argv[0], attach_argv); | 458 | execvp(attach_argv[0], attach_argv); |
432 | perror("execvp"); | 459 | perror("execvp"); |
433 | exit(1); | 460 | exit(1); |
@@ -458,7 +485,8 @@ void x11_start_xpra(int argc, char **argv) { | |||
458 | if (jail < 0) | 485 | if (jail < 0) |
459 | errExit("fork"); | 486 | errExit("fork"); |
460 | if (jail == 0) { | 487 | if (jail == 0) { |
461 | execvp(firejail_argv[0], firejail_argv); | 488 | if (firejail_argv[0]) // shut up llvm scan-build |
489 | execvp(firejail_argv[0], firejail_argv); | ||
462 | perror("execvp"); | 490 | perror("execvp"); |
463 | exit(1); | 491 | exit(1); |
464 | } | 492 | } |
@@ -466,26 +494,54 @@ void x11_start_xpra(int argc, char **argv) { | |||
466 | if (!arg_quiet) | 494 | if (!arg_quiet) |
467 | printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail); | 495 | printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail); |
468 | 496 | ||
497 | sleep(1); // let jail start | ||
498 | |||
469 | // wait for jail or server to end | 499 | // wait for jail or server to end |
470 | while (1) { | 500 | while (1) { |
471 | pid_t pid = wait(); | 501 | pid_t pid = wait(NULL); |
472 | 502 | ||
473 | if (pid == jail) { | 503 | if (pid == jail) { |
474 | sleep(3); // FIXME: find better way to wait for xpra | ||
475 | char *stop_argv[] = { "xpra", "stop", display_str, NULL }; | 504 | char *stop_argv[] = { "xpra", "stop", display_str, NULL }; |
476 | pid_t stop = fork(); | 505 | pid_t stop = fork(); |
477 | if (stop < 0) | 506 | if (stop < 0) |
478 | errExit("fork"); | 507 | errExit("fork"); |
479 | if (stop == 0) { | 508 | if (stop == 0) { |
509 | if (arg_quiet && fd_null != -1) { | ||
510 | dup2(fd_null,0); | ||
511 | dup2(fd_null,1); | ||
512 | dup2(fd_null,2); | ||
513 | } | ||
480 | execvp(stop_argv[0], stop_argv); | 514 | execvp(stop_argv[0], stop_argv); |
481 | perror("execvp"); | 515 | perror("execvp"); |
482 | exit(1); | 516 | exit(1); |
483 | } | 517 | } |
484 | sleep(3); | 518 | |
519 | // wait for xpra server to stop, 10 seconds limit | ||
520 | while (++n < 10) { | ||
521 | sleep(1); | ||
522 | pid = waitpid(server, NULL, WNOHANG); | ||
523 | if (pid == server) | ||
524 | break; | ||
525 | } | ||
526 | |||
527 | if (arg_debug) | ||
528 | if (n == 10) | ||
529 | printf("failed to stop xpra server gratefully\n"); | ||
530 | else | ||
531 | printf("xpra server successfully stoped in %d secs\n", n); | ||
532 | |||
533 | // kill xpra server and xpra client | ||
485 | kill(client, SIGTERM); | 534 | kill(client, SIGTERM); |
486 | kill(server, SIGTERM); | 535 | kill(server, SIGTERM); |
487 | exit(0); | 536 | exit(0); |
488 | } | 537 | } |
538 | else if (pid == server) { | ||
539 | // kill firejail process | ||
540 | kill(jail, SIGTERM); | ||
541 | // kill xpra client (should die with server, but...) | ||
542 | kill(client, SIGTERM); | ||
543 | exit(0); | ||
544 | } | ||
489 | } | 545 | } |
490 | } | 546 | } |
491 | 547 | ||