aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--RELNOTES5
-rw-r--r--src/firejail/bandwidth.c1
-rw-r--r--src/firejail/fs_bin.c1
-rw-r--r--src/firejail/fs_etc.c1
-rw-r--r--src/firejail/ls.c192
-rw-r--r--src/firejail/netfilter.c3
-rw-r--r--src/firejail/run_symlink.c1
-rw-r--r--src/firejail/sandbox.c16
-rw-r--r--src/firejail/sbox.c1
-rw-r--r--src/firejail/util.c6
-rw-r--r--src/firejail/x11.c13
11 files changed, 105 insertions, 135 deletions
diff --git a/RELNOTES b/RELNOTES
index 44d313999..3a9ccaa4b 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,8 +1,11 @@
1firejail (0.9.45) baseline; urgency=low 1firejail (0.9.45) baseline; urgency=low
2 * development version, work in progress 2 * development version, work in progress
3 * security: overwrite /etc/resolv.conf found by Martin Carpenter 3 * security: overwrite /etc/resolv.conf found by Martin Carpenter
4 * secuirty: TOCTOU exploit for --get and --put found by Daniel Hodson
5 * security: invalid environment exploit found by Martin Carpener
6 * security: split most of networking code in a separate executable
7 * security: split seccomp filter code code in a separate executable
4 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm) 8 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm)
5 * feature: split most of networking code in a separate executable
6 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire 9 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire
7 * bugfixes 10 * bugfixes
8 -- netblue30 <netblue30@yahoo.com> Sun, 23 Oct 2016 08:00:00 -0500 11 -- netblue30 <netblue30@yahoo.com> Sun, 23 Oct 2016 08:00:00 -0500
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c
index 4a1df9c67..ab9714afe 100644
--- a/src/firejail/bandwidth.c
+++ b/src/firejail/bandwidth.c
@@ -462,6 +462,7 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in
462 arg[1] = "-c"; 462 arg[1] = "-c";
463 arg[2] = cmd; 463 arg[2] = cmd;
464 arg[3] = NULL; 464 arg[3] = NULL;
465 assert(getenv("LD_PRELOAD") == NULL);
465 execvp(arg[0], arg); 466 execvp(arg[0], arg);
466 467
467 // it will never get here 468 // it will never get here
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
index f59944735..d6fee0608 100644
--- a/src/firejail/fs_bin.c
+++ b/src/firejail/fs_bin.c
@@ -191,6 +191,7 @@ static void duplicate(char *fname) {
191 char *f; 191 char *f;
192 if (asprintf(&f, "%s/%s", RUN_BIN_DIR, fname) == -1) 192 if (asprintf(&f, "%s/%s", RUN_BIN_DIR, fname) == -1)
193 errExit("asprintf"); 193 errExit("asprintf");
194 assert(getenv("LD_PRELOAD") == NULL);
194 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", actual_path, f, NULL); 195 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", actual_path, f, NULL);
195 perror("execlp"); 196 perror("execlp");
196 _exit(1); 197 _exit(1);
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index b86d5eb74..4f3417236 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -105,6 +105,7 @@ static void duplicate(char *fname) {
105 char *f; 105 char *f;
106 if (asprintf(&f, "/etc/%s", fname) == -1) 106 if (asprintf(&f, "/etc/%s", fname) == -1)
107 errExit("asprintf"); 107 errExit("asprintf");
108 assert(getenv("LD_PRELOAD") == NULL);
108 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", "--parents", f, RUN_MNT_DIR, NULL); 109 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", "--parents", f, RUN_MNT_DIR, NULL);
109 perror("execlp"); 110 perror("execlp");
110 _exit(1); 111 _exit(1);
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index dba82be0b..7c5585324 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -324,22 +324,24 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
324 324
325 // get file from sandbox and store it in the current directory 325 // get file from sandbox and store it in the current directory
326 else if (op == SANDBOX_FS_GET) { 326 else if (op == SANDBOX_FS_GET) {
327 // check source file (sandbox) 327 char *src_fname =fname1;
328 char *src_fname; 328 char *dest_fname = strrchr(fname1, '/');
329 if (asprintf(&src_fname, "%s%s", rootdir, fname1) == -1) 329 if (!dest_fname || *(++dest_fname) == '\0') {
330 errExit("asprintf"); 330 fprintf(stderr, "Error: invalid file name %s\n", fname1);
331 EUID_ROOT();
332 struct stat s;
333 if (stat(src_fname, &s) == -1) {
334 fprintf(stderr, "Error: Cannot access %s\n", fname1);
335 exit(1);
336 }
337 if (is_dir(src_fname)) {
338 fprintf(stderr, "Error: source file name is a directory\n");
339 exit(1); 331 exit(1);
340 } 332 }
341 333
342 // try to open the source file - we need to chroot 334 EUID_ROOT();
335 if (arg_debug)
336 printf("copy %s to %s\n", src_fname, dest_fname);
337
338 // create a user-owned temporary file in /run/firejail directory
339 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX";
340 int fd = mkstemp(tmp_fname);
341 SET_PERMS_FD(fd, getuid(), getgid(), 0600);
342 close(fd);
343
344 // copy the source file into the temporary file - we need to chroot
343 pid_t child = fork(); 345 pid_t child = fork();
344 if (child < 0) 346 if (child < 0)
345 errExit("fork"); 347 errExit("fork");
@@ -353,11 +355,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
353 // drop privileges 355 // drop privileges
354 drop_privs(0); 356 drop_privs(0);
355 357
356 // try to read the file 358 // copy the file
357 if (access(fname1, R_OK) == -1) { 359 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600))
358 fprintf(stderr, "Error: Cannot read %s\n", fname1); 360 _exit(1);
359 exit(1);
360 }
361 _exit(0); 361 _exit(0);
362 } 362 }
363 363
@@ -365,74 +365,54 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
365 int status = 0; 365 int status = 0;
366 waitpid(child, &status, 0); 366 waitpid(child, &status, 0);
367 if (WIFEXITED(status) && WEXITSTATUS(status) == 0); 367 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
368 else 368 else {
369 exit(1); 369 unlink(tmp_fname);
370 EUID_USER();
371
372 // check destination file (host)
373 char *dest_fname = strrchr(fname1, '/');
374 if (!dest_fname || *(++dest_fname) == '\0') {
375 fprintf(stderr, "Error: invalid file name %s\n", fname1);
376 exit(1); 370 exit(1);
377 } 371 }
378 372
379 if (access(dest_fname, F_OK) == -1) { 373 // copy the temporary file into the destionation file
380 // try to create the file as a regular user 374 child = fork();
381 pid_t child = fork(); 375 if (child < 0)
382 if (child < 0) 376 errExit("fork");
383 errExit("fork"); 377 if (child == 0) {
384 if (child == 0) { 378 // drop privileges
385 // drop privileges 379 drop_privs(0);
386 drop_privs(0); 380
387 381 // copy the file
388 FILE *fp = fopen(dest_fname, "w"); 382 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600))
389 if (!fp) { 383 _exit(1);
390 fprintf(stderr, "Error: cannot create %s\n", dest_fname); 384 _exit(0);
391 exit(1);
392 }
393 fclose(fp);
394 _exit(0);
395 }
396
397 // wait for the child to finish
398 int status = 0;
399 waitpid(child, &status, 0);
400 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
401 else
402 exit(1);
403 } 385 }
386
387 // wait for the child to finish
388 status = 0;
389 waitpid(child, &status, 0);
390 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
404 else { 391 else {
405 if (access(dest_fname, W_OK) == -1) { 392 unlink(tmp_fname);
406 fprintf(stderr, "Error: cannot write %s\n", dest_fname); 393 exit(1);
407 exit(1);
408 }
409 } 394 }
410 395
411 // copy file 396 // remove the temporary file
412 if (arg_debug) 397 unlink(tmp_fname);
413 printf("copy %s to %s\n", src_fname, dest_fname);
414 EUID_ROOT();
415 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
416 fprintf(stderr, "Error: transfer failed\n");
417 else
418 printf("Transfer complete\n");
419 EUID_USER(); 398 EUID_USER();
420 } 399 }
421 // get file from host and store it in the sandbox 400 // get file from host and store it in the sandbox
422 else if (op == SANDBOX_FS_PUT && path2) { 401 else if (op == SANDBOX_FS_PUT && path2) {
423 // verify the source file 402 char *src_fname =fname1;
424 const char *src_fname = path1; 403 char *dest_fname = fname2;
425 struct stat s; 404
426 if (stat(src_fname, &s) == -1) { 405 EUID_ROOT();
427 fprintf(stderr, "Error: Cannot access %s\n", fname1); 406 if (arg_debug)
428 exit(1); 407 printf("copy %s to %s\n", src_fname, dest_fname);
429 } 408
430 if (is_dir(src_fname)) { 409 // create a user-owned temporary file in /run/firejail directory
431 fprintf(stderr, "Error: source file name is a directory\n"); 410 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX";
432 exit(1); 411 int fd = mkstemp(tmp_fname);
433 } 412 SET_PERMS_FD(fd, getuid(), getgid(), 0600);
434 413 close(fd);
435 // try to open the source file 414
415 // copy the source file into the temporary file - we need to chroot
436 pid_t child = fork(); 416 pid_t child = fork();
437 if (child < 0) 417 if (child < 0)
438 errExit("fork"); 418 errExit("fork");
@@ -440,11 +420,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
440 // drop privileges 420 // drop privileges
441 drop_privs(0); 421 drop_privs(0);
442 422
443 // try to read the file 423 // copy the file
444 if (access(src_fname, R_OK) == -1) { 424 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600))
445 fprintf(stderr, "Error: Cannot read %s\n", src_fname); 425 _exit(1);
446 exit(1);
447 }
448 _exit(0); 426 _exit(0);
449 } 427 }
450 428
@@ -452,20 +430,12 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
452 int status = 0; 430 int status = 0;
453 waitpid(child, &status, 0); 431 waitpid(child, &status, 0);
454 if (WIFEXITED(status) && WEXITSTATUS(status) == 0); 432 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
455 else 433 else {
456 exit(1); 434 unlink(tmp_fname);
457
458 // check destination file (sandbox)
459 char *dest_fname;
460 if (asprintf(&dest_fname, "%s%s", rootdir, fname2) == -1)
461 errExit("asprintf");
462 EUID_ROOT();
463 if (is_dir(dest_fname)) {
464 fprintf(stderr, "Error: destination file name is a directory inside the sandbox\n");
465 exit(1); 435 exit(1);
466 } 436 }
467 437
468 // check write access on destination 438 // copy the temporary file into the destionation file
469 child = fork(); 439 child = fork();
470 if (child < 0) 440 if (child < 0)
471 errExit("fork"); 441 errExit("fork");
@@ -475,25 +445,13 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
475 errExit("chroot"); 445 errExit("chroot");
476 if (chdir("/") < 0) 446 if (chdir("/") < 0)
477 errExit("chdir"); 447 errExit("chdir");
478 448
479 // drop privileges 449 // drop privileges
480 drop_privs(0); 450 drop_privs(0);
481 451
482 if (access(path2, F_OK) == -1) { 452 // copy the file
483 FILE *fp = fopen(path2, "w"); 453 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600))
484 if (!fp) { 454 _exit(1);
485 fprintf(stderr, "Error: cannot create %s\n", path2);
486 exit(1);
487 }
488 fclose(fp);
489 }
490 else {
491 if (access(path2, W_OK) == -1) {
492 fprintf(stderr, "Error: cannot write %s\n", path2);
493 exit(1);
494 }
495 }
496
497 _exit(0); 455 _exit(0);
498 } 456 }
499 457
@@ -501,17 +459,13 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
501 status = 0; 459 status = 0;
502 waitpid(child, &status, 0); 460 waitpid(child, &status, 0);
503 if (WIFEXITED(status) && WEXITSTATUS(status) == 0); 461 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
504 else 462 else {
463 unlink(tmp_fname);
505 exit(1); 464 exit(1);
506 465 }
507 // copy file 466
508 if (arg_debug) 467 // remove the temporary file
509 printf("copy %s to %s\n", src_fname, dest_fname); 468 unlink(tmp_fname);
510 EUID_ROOT();
511 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
512 fprintf(stderr, "Error: transfer failed\n");
513 else
514 printf("Transfer complete\n");
515 EUID_USER(); 469 EUID_USER();
516 } 470 }
517 471
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c
index c1f9a2c37..efef45d90 100644
--- a/src/firejail/netfilter.c
+++ b/src/firejail/netfilter.c
@@ -144,6 +144,7 @@ void netfilter(const char *fname) {
144 144
145 // wipe out environment variables 145 // wipe out environment variables
146 environ = NULL; 146 environ = NULL;
147 assert(getenv("LD_PRELOAD") == NULL);
147 execl(iptables_restore, iptables_restore, NULL); 148 execl(iptables_restore, iptables_restore, NULL);
148 perror("execl"); 149 perror("execl");
149 _exit(1); 150 _exit(1);
@@ -163,6 +164,7 @@ void netfilter(const char *fname) {
163 if (setregid(0, 0)) 164 if (setregid(0, 0))
164 errExit("setregid"); 165 errExit("setregid");
165 environ = NULL; 166 environ = NULL;
167 assert(getenv("LD_PRELOAD") == NULL);
166 execl(iptables, iptables, "-vL", NULL); 168 execl(iptables, iptables, "-vL", NULL);
167 perror("execl"); 169 perror("execl");
168 _exit(1); 170 _exit(1);
@@ -257,6 +259,7 @@ void netfilter6(const char *fname) {
257 259
258 // wipe out environment variables 260 // wipe out environment variables
259 environ = NULL; 261 environ = NULL;
262 assert(getenv("LD_PRELOAD") == NULL);
260 execl(ip6tables_restore, ip6tables_restore, NULL); 263 execl(ip6tables_restore, ip6tables_restore, NULL);
261 perror("execl"); 264 perror("execl");
262 _exit(1); 265 _exit(1);
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c
index 020e70b80..8aa2fe53f 100644
--- a/src/firejail/run_symlink.c
+++ b/src/firejail/run_symlink.c
@@ -106,6 +106,7 @@ void run_symlink(int argc, char **argv) {
106 a[i + 2] = argv[i + 1]; 106 a[i + 2] = argv[i + 1];
107 } 107 }
108 a[i + 2] = NULL; 108 a[i + 2] = NULL;
109 assert(getenv("LD_PRELOAD") == NULL);
109 execvp(a[0], a); 110 execvp(a[0], a);
110 111
111 perror("execvp"); 112 perror("execvp");
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 3942e4da6..e3c95283d 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -260,6 +260,7 @@ void start_audit(void) {
260 char *audit_prog; 260 char *audit_prog;
261 if (asprintf(&audit_prog, "%s/firejail/faudit", LIBDIR) == -1) 261 if (asprintf(&audit_prog, "%s/firejail/faudit", LIBDIR) == -1)
262 errExit("asprintf"); 262 errExit("asprintf");
263 assert(getenv("LD_PRELOAD") == NULL);
263 execl(audit_prog, audit_prog, NULL); 264 execl(audit_prog, audit_prog, NULL);
264 perror("execl"); 265 perror("execl");
265 exit(1); 266 exit(1);
@@ -268,6 +269,15 @@ void start_audit(void) {
268void start_application(void) { 269void start_application(void) {
269//if (setsid() == -1) 270//if (setsid() == -1)
270//errExit("setsid"); 271//errExit("setsid");
272
273 // set environment
274 env_defaults();
275 env_apply();
276 if (arg_debug) {
277 printf("starting application\n");
278 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD"));
279 }
280
271 //**************************************** 281 //****************************************
272 // audit 282 // audit
273 //**************************************** 283 //****************************************
@@ -787,12 +797,6 @@ assert(0);
787 } 797 }
788 } 798 }
789 799
790 // set environment
791 env_defaults();
792
793 // set user-supplied environment variables
794 env_apply();
795
796 // set nice 800 // set nice
797 if (arg_nice) { 801 if (arg_nice) {
798 errno = 0; 802 errno = 0;
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
index 6499b7005..a5a067090 100644
--- a/src/firejail/sbox.c
+++ b/src/firejail/sbox.c
@@ -165,6 +165,7 @@ int sbox_run(unsigned filter, int num, ...) {
165 else if (filter & SBOX_USER) 165 else if (filter & SBOX_USER)
166 drop_privs(1); 166 drop_privs(1);
167 167
168 assert(getenv("LD_PRELOAD") == NULL);
168 if (arg[0]) // get rid of scan-build warning 169 if (arg[0]) // get rid of scan-build warning
169 execvp(arg[0], arg); 170 execvp(arg[0], arg);
170 else 171 else
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 9752504e5..a7712441e 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -176,12 +176,6 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
176 assert(srcname); 176 assert(srcname);
177 assert(destname); 177 assert(destname);
178 178
179 struct stat s;
180 if (stat(destname, &s) == 0) {
181 fprintf(stderr, "Error: file %s already exists\n", destname);
182 return -1;
183 }
184
185 // open source 179 // open source
186 int src = open(srcname, O_RDONLY); 180 int src = open(srcname, O_RDONLY);
187 if (src < 0) { 181 if (src < 0) {
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index c79f1a74e..6cba95501 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -311,7 +311,8 @@ void x11_start_xephyr(int argc, char **argv) {
311 if (server == 0) { 311 if (server == 0) {
312 if (arg_debug) 312 if (arg_debug)
313 printf("Starting xephyr...\n"); 313 printf("Starting xephyr...\n");
314 314
315 assert(getenv("LD_PRELOAD") == NULL);
315 execvp(server_argv[0], server_argv); 316 execvp(server_argv[0], server_argv);
316 perror("execvp"); 317 perror("execvp");
317 _exit(1); 318 _exit(1);
@@ -353,6 +354,7 @@ void x11_start_xephyr(int argc, char **argv) {
353 if (!arg_quiet) 354 if (!arg_quiet)
354 printf("\n*** Attaching to Xephyr display %d ***\n\n", display); 355 printf("\n*** Attaching to Xephyr display %d ***\n\n", display);
355 356
357 assert(getenv("LD_PRELOAD") == NULL);
356 execvp(jail_argv[0], jail_argv); 358 execvp(jail_argv[0], jail_argv);
357 perror("execvp"); 359 perror("execvp");
358 _exit(1); 360 _exit(1);
@@ -432,6 +434,7 @@ void x11_start_xpra(int argc, char **argv) {
432 dup2(fd_null,2); 434 dup2(fd_null,2);
433 } 435 }
434 436
437 assert(getenv("LD_PRELOAD") == NULL);
435 execvp(server_argv[0], server_argv); 438 execvp(server_argv[0], server_argv);
436 perror("execvp"); 439 perror("execvp");
437 _exit(1); 440 _exit(1);
@@ -478,6 +481,7 @@ void x11_start_xpra(int argc, char **argv) {
478 if (!arg_quiet) 481 if (!arg_quiet)
479 printf("\n*** Attaching to xpra display %d ***\n\n", display); 482 printf("\n*** Attaching to xpra display %d ***\n\n", display);
480 483
484 assert(getenv("LD_PRELOAD") == NULL);
481 execvp(attach_argv[0], attach_argv); 485 execvp(attach_argv[0], attach_argv);
482 perror("execvp"); 486 perror("execvp");
483 _exit(1); 487 _exit(1);
@@ -508,6 +512,7 @@ void x11_start_xpra(int argc, char **argv) {
508 if (jail < 0) 512 if (jail < 0)
509 errExit("fork"); 513 errExit("fork");
510 if (jail == 0) { 514 if (jail == 0) {
515 assert(getenv("LD_PRELOAD") == NULL);
511 if (firejail_argv[0]) // shut up llvm scan-build 516 if (firejail_argv[0]) // shut up llvm scan-build
512 execvp(firejail_argv[0], firejail_argv); 517 execvp(firejail_argv[0], firejail_argv);
513 perror("execvp"); 518 perror("execvp");
@@ -534,6 +539,7 @@ void x11_start_xpra(int argc, char **argv) {
534 dup2(fd_null,1); 539 dup2(fd_null,1);
535 dup2(fd_null,2); 540 dup2(fd_null,2);
536 } 541 }
542 assert(getenv("LD_PRELOAD") == NULL);
537 execvp(stop_argv[0], stop_argv); 543 execvp(stop_argv[0], stop_argv);
538 perror("execvp"); 544 perror("execvp");
539 _exit(1); 545 _exit(1);
@@ -664,11 +670,12 @@ void x11_xorg(void) {
664 errExit("setreuid"); 670 errExit("setreuid");
665 if (setregid(0, 0) < 0) 671 if (setregid(0, 0) < 0)
666 errExit("setregid"); 672 errExit("setregid");
667 673
668 char *display = getenv("DISPLAY"); 674 char *display = getenv("DISPLAY");
669 if (!display) 675 if (!display)
670 display = ":0.0"; 676 display = ":0.0";
671 677
678 assert(getenv("LD_PRELOAD") == NULL);
672 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-f", RUN_XAUTHORITY_SEC_FILE, 679 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-f", RUN_XAUTHORITY_SEC_FILE,
673 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL); 680 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL);
674 681