void fs_x11(void) { #ifdef HAVE_X11 int display = x11_display(); if (display <= 0) return; char *x11file; if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) errExit("asprintf"); struct stat s; if (stat(x11file, &s) == -1) return; // keep a copy of real /tmp/.X11-unix directory in WHITELIST_TMP_DIR int rv = mkdir(RUN_WHITELIST_X11_DIR, 1777); if (rv == -1) errExit("mkdir"); if (chown(RUN_WHITELIST_X11_DIR, 0, 0) < 0) errExit("chown"); if (chmod(RUN_WHITELIST_X11_DIR, 1777) < 0) errExit("chmod"); if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /tmp/.X11-unix if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /tmp/.X11-unix directory\n"); if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting tmpfs on /tmp"); fs_logger("tmpfs /tmp/.X11-unix"); // create an empty file FILE *fp = fopen(x11file, "w"); if (!fp) { fprintf(stderr, "Error: cannot create empty file in x11 directory\n"); exit(1); } // set file properties SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode); fclose(fp); // mount char *wx11file; if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1) errExit("asprintf"); if (mount(wx11file, x11file, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); fs_logger2("whitelist", x11file); free(x11file); free(wx11file); // block access to RUN_WHITELIST_X11_DIR if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, "none", MS_BIND, "mode=400,gid=0") == -1) errExit("mount"); fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); #endif }
void platform_get_x11_auth(char *display, int *protocol, unsigned char *data, int *datalen) { FILE *fp; char *command; int maxsize = *datalen; char *localbuf; int proto = -1; display = x11_display(display); /* * Normally we should run `xauth list DISPLAYNAME'. However, * there's an oddity when the display is local: the display * `localhost:0' (or `:0') should become just `:0'. */ if (!strncmp(display, "localhost:", 10) || !strncmp(display, "unix:", 5)) command = dupprintf("xauth list %s 2>/dev/null", strchr(display, ':')); else command = dupprintf("xauth list %s 2>/dev/null", display); sfree(display); fp = popen(command, "r"); sfree(command); if (!fp) return; /* assume no auth */ localbuf = snewn(maxsize, char); while (1) { /* * Read a line from stdin, and attempt to parse it into a * display name (ignored), auth protocol, and auth string. */ int c, i, hexdigit; char protoname[64]; /* Skip the display name. */ while (c = getc(fp), c != EOF && c != '\n' && !isspace(c)); if (c == EOF) break; if (c == '\n') continue; /* Skip white space. */ while (c != EOF && c != '\n' && isspace(c)) c = getc(fp); if (c == EOF) break; if (c == '\n') continue; /* Read the auth protocol name, and see if it matches any we * know about. */ i = 0; while (c != EOF && c != '\n' && !isspace(c)) { if (i < lenof(protoname)-1) protoname[i++] = c; c = getc(fp); } protoname[i] = '\0'; for (i = X11_NO_AUTH; ++i < X11_NAUTHS ;) { if (!strcmp(protoname, x11_authnames[i])) break; } if (i >= X11_NAUTHS || i <= proto) { /* Unrecognised protocol name, or a worse one than we already have. * Skip this line. */ while (c != EOF && c != '\n') c = getc(fp); if (c == EOF) break; } proto = i; /* Skip white space. */ while (c != EOF && c != '\n' && isspace(c)) c = getc(fp); if (c == EOF) break; if (c == '\n') continue; /* * Now grab pairs of hex digits and shove them into `data'. */ i = 0; hexdigit = -1; while (c != EOF && c != '\n') { int hexval = -1; if (c >= 'A' && c <= 'F') hexval = c + 10 - 'A'; if (c >= 'a' && c <= 'f') hexval = c + 10 - 'a'; if (c >= '0' && c <= '9') hexval = c - '0'; if (hexval >= 0) { if (hexdigit >= 0) { hexdigit = (hexdigit << 4) + hexval; if (i < maxsize) localbuf[i++] = hexdigit; hexdigit = -1; } else hexdigit = hexval; } c = getc(fp); } *datalen = i; *protocol = proto; memcpy(data, localbuf, i); /* Nonetheless, continue looping round; we might find a better one. */ } pclose(fp); sfree(localbuf); }