aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/faudit/dbus.c2
-rw-r--r--src/firejail/bandwidth.c8
-rw-r--r--src/firejail/checkcfg.c4
-rw-r--r--src/firejail/cmdline.c12
-rw-r--r--src/firejail/env.c11
-rw-r--r--src/firejail/firejail.h5
-rw-r--r--src/firejail/fs.c14
-rw-r--r--src/firejail/fs_home.c5
-rw-r--r--src/firejail/join.c47
-rw-r--r--src/firejail/main.c193
-rw-r--r--src/firejail/network.txt2
-rw-r--r--src/firejail/no_sandbox.c7
-rw-r--r--src/firejail/restricted_shell.c33
-rw-r--r--src/firejail/sandbox.c45
-rw-r--r--src/firejail/x11.c100
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
29int cmdline_length(int argc, char **argv, int index) { 29static 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
65void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { 67static 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
133void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { 137void 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
268extern char *arg_audit_prog; // audit 270extern char *arg_audit_prog; // audit
269extern int arg_apparmor; // apparmor 271extern int arg_apparmor; // apparmor
270 272
273extern int login_shell;
271extern int parent_to_child_fds[2]; 274extern int parent_to_child_fds[2];
272extern int child_to_parent_fds[2]; 275extern int child_to_parent_fds[2];
273extern pid_t sandbox_pid; 276extern pid_t sandbox_pid;
@@ -278,6 +281,7 @@ extern int fullargc;
278 281
279// main.c 282// main.c
280void check_user_namespace(void); 283void check_user_namespace(void);
284char *guess_shell(void);
281 285
282// sandbox.c 286// sandbox.c
283int sandbox(void* sandbox_arg); 287int sandbox(void* sandbox_arg);
@@ -358,7 +362,6 @@ void shut(pid_t pid);
358void shut_name(const char *name); 362void shut_name(const char *name);
359 363
360// restricted_shell.c 364// restricted_shell.c
361extern char *restricted_user;
362int restricted_shell(const char *user); 365int 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
33static void skel(const char *homedir, uid_t u, gid_t g) { 33static 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
105int arg_audit = 0; // audit 105int arg_audit = 0; // audit
106char *arg_audit_prog; // audit 106char *arg_audit_prog; // audit
107int arg_apparmor; // apparmor 107int arg_apparmor; // apparmor
108int login_shell = 0;
108 109
109int parent_to_child_fds[2]; 110int parent_to_child_fds[2];
110int child_to_parent_fds[2]; 111int 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
762char *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
15net_configure_sandbox_ip(br) { 15net_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