diff options
-rw-r--r-- | src/firejail/firejail.h | 6 | ||||
-rw-r--r-- | src/firejail/main.c | 20 | ||||
-rw-r--r-- | src/firejail/usage.c | 5 | ||||
-rw-r--r-- | src/firejail/x11.c | 200 |
4 files changed, 210 insertions, 21 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 0e2ae16c2..d729504a2 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -527,10 +527,10 @@ void fs_mkdir(const char *name); | |||
527 | 527 | ||
528 | // x11.c | 528 | // x11.c |
529 | void fs_x11(void); | 529 | void fs_x11(void); |
530 | void x11_start(int argc, char **argv); | ||
531 | int x11_display(void); | 530 | int x11_display(void); |
532 | // return 1 if xpra is installed on the system | 531 | void x11_start(int argc, char **argv); |
533 | int x11_check_xpra(void); | 532 | void x11_start_xpra(int argc, char **argv); |
533 | void x11_start_xephyr(int argc, char **argv); | ||
534 | 534 | ||
535 | // ls.c | 535 | // ls.c |
536 | #define SANDBOX_FS_LS 0 | 536 | #define SANDBOX_FS_LS 0 |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 1f8907e4c..0269ff585 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -287,6 +287,26 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
287 | exit(1); | 287 | exit(1); |
288 | } | 288 | } |
289 | } | 289 | } |
290 | else if (strcmp(argv[i], "--x11=xpra") == 0) { | ||
291 | if (checkcfg(CFG_X11)) { | ||
292 | x11_start_xpra(argc, argv); | ||
293 | exit(0); | ||
294 | } | ||
295 | else { | ||
296 | fprintf(stderr, "Error: --x11 feature is disabled in Firejail configuration file\n"); | ||
297 | exit(1); | ||
298 | } | ||
299 | } | ||
300 | else if (strcmp(argv[i], "--x11=xephyr") == 0) { | ||
301 | if (checkcfg(CFG_X11)) { | ||
302 | x11_start_xephyr(argc, argv); | ||
303 | exit(0); | ||
304 | } | ||
305 | else { | ||
306 | fprintf(stderr, "Error: --x11 feature is disabled in Firejail configuration file\n"); | ||
307 | exit(1); | ||
308 | } | ||
309 | } | ||
290 | #endif | 310 | #endif |
291 | #ifdef HAVE_NETWORK | 311 | #ifdef HAVE_NETWORK |
292 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { | 312 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 7bc6ea47a..da5fd4e2f 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -245,7 +245,10 @@ void usage(void) { | |||
245 | printf(" --user=new_user - switch the user before starting the sandbox.\n\n"); | 245 | printf(" --user=new_user - switch the user before starting the sandbox.\n\n"); |
246 | printf(" --version - print program version and exit.\n\n"); | 246 | printf(" --version - print program version and exit.\n\n"); |
247 | printf(" --whitelist=dirname_or_filename - whitelist directory or file.\n\n"); | 247 | printf(" --whitelist=dirname_or_filename - whitelist directory or file.\n\n"); |
248 | printf(" --x11 - enable x11 server.\n\n"); | 248 | printf(" --x11 - enable X11 server. The software checks first if Xpra is installed,\n"); |
249 | printf("\tthen it checks if Xephyr is installed.\n\n"); | ||
250 | printf(" --x11=xpra - enable Xpra X11 server.\n\n"); | ||
251 | printf(" --x11=xephyr - enable Xephyr X11 server. The window size is 800x600.\n\n"); | ||
249 | printf(" --zsh - use /usr/bin/zsh as default shell.\n\n"); | 252 | printf(" --zsh - use /usr/bin/zsh as default shell.\n\n"); |
250 | printf("\n"); | 253 | printf("\n"); |
251 | printf("\n"); | 254 | printf("\n"); |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index a7bd9fd29..10e89ea7e 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <sys/mount.h> | 27 | #include <sys/mount.h> |
28 | 28 | ||
29 | // return 1 if xpra is installed on the system | 29 | // return 1 if xpra is installed on the system |
30 | int x11_check_xpra(void) { | 30 | static int x11_check_xpra(void) { |
31 | struct stat s; | 31 | struct stat s; |
32 | 32 | ||
33 | // check xpra | 33 | // check xpra |
@@ -37,6 +37,42 @@ int x11_check_xpra(void) { | |||
37 | return 1; | 37 | return 1; |
38 | } | 38 | } |
39 | 39 | ||
40 | // return 1 if xephyr is installed on the system | ||
41 | static int x11_check_xephyr(void) { | ||
42 | struct stat s; | ||
43 | |||
44 | // check xpra | ||
45 | if (stat("/usr/bin/Xephyr", &s) == -1) | ||
46 | return 0; | ||
47 | |||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | static int random_display_number(void) { | ||
52 | int i; | ||
53 | int found = 1; | ||
54 | int display; | ||
55 | for (i = 0; i < 100; i++) { | ||
56 | display = rand() % 1024; | ||
57 | if (display < 10) | ||
58 | continue; | ||
59 | char *fname; | ||
60 | if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) | ||
61 | errExit("asprintf"); | ||
62 | struct stat s; | ||
63 | if (stat(fname, &s) == -1) { | ||
64 | found = 1; | ||
65 | break; | ||
66 | } | ||
67 | } | ||
68 | if (!found) { | ||
69 | fprintf(stderr, "Error: cannot pick up a random X11 display number, exiting...\n"); | ||
70 | exit(1); | ||
71 | } | ||
72 | |||
73 | return display; | ||
74 | } | ||
75 | |||
40 | // return display number, -1 if not configured | 76 | // return display number, -1 if not configured |
41 | int x11_display(void) { | 77 | int x11_display(void) { |
42 | // extract display | 78 | // extract display |
@@ -120,7 +156,9 @@ void fs_x11(void) { | |||
120 | 156 | ||
121 | 157 | ||
122 | #ifdef HAVE_X11 | 158 | #ifdef HAVE_X11 |
123 | void x11_start(int argc, char **argv) { | 159 | //$ Xephyr -ac -br -noreset -screen 800x600 :22 & |
160 | //$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox | ||
161 | void x11_start_xephyr(int argc, char **argv) { | ||
124 | EUID_ASSERT(); | 162 | EUID_ASSERT(); |
125 | int i; | 163 | int i; |
126 | struct stat s; | 164 | struct stat s; |
@@ -136,29 +174,129 @@ void x11_start(int argc, char **argv) { | |||
136 | 174 | ||
137 | // check xpra | 175 | // check xpra |
138 | if (x11_check_xpra() == 0) { | 176 | if (x11_check_xpra() == 0) { |
139 | fprintf(stderr, "\nError: Xpra program was not found in /usr/bin directory, please install it:\n"); | 177 | fprintf(stderr, "\nError: Xephyr program was not found in /usr/bin directory, please install it:\n"); |
140 | fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); | 178 | fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xserver-xephyr\n"); |
141 | exit(0); | 179 | exit(0); |
142 | } | 180 | } |
143 | 181 | ||
144 | int display; | 182 | int display = random_display_number(); |
145 | int found = 1; | 183 | |
146 | for (i = 0; i < 100; i++) { | 184 | // start xephyr |
147 | display = rand() % 1024; | 185 | char *cmd1; |
148 | if (display < 10) | 186 | if (asprintf(&cmd1, "Xephyr -ac -br -noreset -screen 800x600 :%d", display) == -1) |
187 | errExit("asprintf"); | ||
188 | |||
189 | int len = 50; // DISPLAY... | ||
190 | for (i = 0; i < argc; i++) { | ||
191 | len += strlen(argv[i]) + 1; // + ' ' | ||
192 | } | ||
193 | |||
194 | char *cmd2 = malloc(len + 1); // + '\0' | ||
195 | if (!cmd2) | ||
196 | errExit("malloc"); | ||
197 | |||
198 | sprintf(cmd2, "DISPLAY=:%d ", display); | ||
199 | char *ptr = cmd2 + strlen(cmd2); | ||
200 | for (i = 0; i < argc; i++) { | ||
201 | if (strcmp(argv[i], "--x11") == 0) | ||
149 | continue; | 202 | continue; |
150 | char *fname; | 203 | ptr += sprintf(ptr, "%s ", argv[i]); |
151 | if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) | 204 | } |
152 | errExit("asprintf"); | 205 | if (arg_debug) |
153 | if (stat(fname, &s) == -1) { | 206 | printf("xephyr server: %s\n", cmd1); |
154 | found = 1; | 207 | if (arg_debug) |
208 | printf("xephyr client: %s\n", cmd2); | ||
209 | |||
210 | signal(SIGHUP,SIG_IGN); // fix sleep(1) below | ||
211 | server = fork(); | ||
212 | if (server < 0) | ||
213 | errExit("fork"); | ||
214 | if (server == 0) { | ||
215 | if (arg_debug) | ||
216 | printf("Starting xpra...\n"); | ||
217 | |||
218 | char *a[4]; | ||
219 | a[0] = "/bin/bash"; | ||
220 | a[1] = "-c"; | ||
221 | a[2] = cmd1; | ||
222 | a[3] = NULL; | ||
223 | |||
224 | execvp(a[0], a); | ||
225 | perror("execvp"); | ||
226 | exit(1); | ||
227 | } | ||
228 | |||
229 | // check X11 socket | ||
230 | char *fname; | ||
231 | if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) | ||
232 | errExit("asprintf"); | ||
233 | int n = 0; | ||
234 | // wait for x11 server to start | ||
235 | while (++n < 10) { | ||
236 | sleep(1); | ||
237 | if (stat(fname, &s) == 0) | ||
155 | break; | 238 | break; |
156 | } | 239 | }; |
240 | |||
241 | if (n == 10) { | ||
242 | fprintf(stderr, "Error: failed to start xpra\n"); | ||
243 | exit(1); | ||
157 | } | 244 | } |
158 | if (!found) { | 245 | free(fname); |
159 | fprintf(stderr, "Error: cannot pick up a random X11 display number, exiting...\n"); | 246 | sleep(1); |
247 | |||
248 | if (arg_debug) { | ||
249 | printf("X11 sockets: "); fflush(0); | ||
250 | int rv = system("ls /tmp/.X11-unix"); | ||
251 | (void) rv; | ||
252 | } | ||
253 | |||
254 | // run attach command | ||
255 | client = fork(); | ||
256 | if (client < 0) | ||
257 | errExit("fork"); | ||
258 | if (client == 0) { | ||
259 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); | ||
260 | char *a[4]; | ||
261 | a[0] = "/bin/bash"; | ||
262 | a[1] = "-c"; | ||
263 | a[2] = cmd2; | ||
264 | a[3] = NULL; | ||
265 | |||
266 | execvp(a[0], a); | ||
267 | perror("execvp"); | ||
160 | exit(1); | 268 | exit(1); |
161 | } | 269 | } |
270 | sleep(1); | ||
271 | |||
272 | if (!arg_quiet) | ||
273 | printf("Xphyr server pid %d, client pid %d\n", server, client); | ||
274 | |||
275 | exit(0); | ||
276 | } | ||
277 | |||
278 | void x11_start_xpra(int argc, char **argv) { | ||
279 | EUID_ASSERT(); | ||
280 | int i; | ||
281 | struct stat s; | ||
282 | pid_t client = 0; | ||
283 | pid_t server = 0; | ||
284 | |||
285 | |||
286 | // unfortunately, xpra does a number of wired things when started by root user!!! | ||
287 | if (getuid() == 0) { | ||
288 | fprintf(stderr, "Error: this feature is not available when running as root\n"); | ||
289 | exit(1); | ||
290 | } | ||
291 | |||
292 | // check xpra | ||
293 | if (x11_check_xpra() == 0) { | ||
294 | fprintf(stderr, "\nError: Xpra program was not found in /usr/bin directory, please install it:\n"); | ||
295 | fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); | ||
296 | exit(0); | ||
297 | } | ||
298 | |||
299 | int display = random_display_number(); | ||
162 | 300 | ||
163 | // build the start command | 301 | // build the start command |
164 | int len = 50; // xpra start... | 302 | int len = 50; // xpra start... |
@@ -255,4 +393,32 @@ void x11_start(int argc, char **argv) { | |||
255 | 393 | ||
256 | exit(0); | 394 | exit(0); |
257 | } | 395 | } |
396 | |||
397 | void x11_start(int argc, char **argv) { | ||
398 | EUID_ASSERT(); | ||
399 | int i; | ||
400 | struct stat s; | ||
401 | pid_t client = 0; | ||
402 | pid_t server = 0; | ||
403 | |||
404 | |||
405 | // unfortunately, xpra does a number of wired things when started by root user!!! | ||
406 | if (getuid() == 0) { | ||
407 | fprintf(stderr, "Error: this feature is not available when running as root\n"); | ||
408 | exit(1); | ||
409 | } | ||
410 | |||
411 | // check xpra | ||
412 | if (x11_check_xpra() == 1) | ||
413 | x11_start_xpra(argc, argv); | ||
414 | else if (x11_check_xephyr() == 1) | ||
415 | x11_start_xephyr(argc, argv); | ||
416 | else { | ||
417 | fprintf(stderr, "\nError: Xpra or Xephyr not found in /usr/bin directory, please install one of them:\n"); | ||
418 | fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); | ||
419 | fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xserver-xephyr\n"); | ||
420 | exit(0); | ||
421 | } | ||
422 | } | ||
423 | |||
258 | #endif | 424 | #endif |