x11vnc: -proxy, -ssh options. ncache bug in -8to24, Selection "targets" bugfix.

pull/1/head
runge 17 years ago
parent be9dc49025
commit 81ef0b9345

@ -1,6 +1,6 @@
#!/bin/bash
VERSION="0.9.3"
VERSION="0.9.4"
cd "$(dirname "$0")"

@ -1721,10 +1721,12 @@ if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, dno
call_count++;
/* clip to display just in case: */
if (!ncache) {
x1 = nfix(x1, dpy_x);
y1 = nfix(y1, dpy_y);
x2 = nfix(x2, dpy_x+1);
y2 = nfix(y2, dpy_y+1);
}
if (wireframe_in_progress) {
/*
@ -1765,6 +1767,7 @@ if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, dno
idx = (int) (*uc);
if (0 && line % 100 == 0 && j % 32 == 0) fprintf(stderr, "%d %d %u x1=%d y1=%d\n", line, j, root_rgb[idx], x1, y1);
#if 0
if (do_hibits) {
hi = idx << 24;

@ -1,3 +1,9 @@
2007-10-27 Karl Runge <runge@karlrunge.com>
* x11vnc: fix ncache bug and others under -8to24, -ssh
option, socks and other proxies in -proxy option.
compiler warnings. fix TARGETS selection request bug
(java, konsole).
2007-10-03 Karl Runge <runge@karlrunge.com>
* x11vnc: add xfce to createdisplay

File diff suppressed because it is too large Load Diff

@ -133,6 +133,10 @@ void clean_up_exit (int ret) {
if (avahi) {
avahi_cleanup();
}
if (ssh_pid > 0) {
kill(ssh_pid, SIGTERM);
ssh_pid = 0;
}
#ifdef MACOSX
if (client_connect_file) {

@ -1610,6 +1610,544 @@ static void check_connect_file(char *file) {
}
}
static int socks5_proxy(char *host, int port, int sock) {
unsigned char buf[512], tmp[2];
char reply[512];
int len, n, i, j = 0;
memset(buf, 0, 512);
memset(reply, 0, 512);
buf[0] = 0x5;
buf[1] = 0x1;
buf[2] = 0x0;
write(sock, buf, 3);
n = read(sock, buf, 2);
if (n != 2) {
rfbLog("socks5_proxy: read error: %d\n", n);
close(sock);
return 0;
}
if (buf[0] != 0x5 || buf[1] != 0x0) {
rfbLog("socks5_proxy: handshake error: %d %d\n", (int) buf[0], (int) buf[1]);
close(sock);
return 0;
}
buf[0] = 0x5;
buf[1] = 0x1;
buf[2] = 0x0;
buf[3] = 0x3;
buf[4] = (unsigned char) strlen(host);
strcat((char *) buf+5, host);
len = 5 + strlen(host);
buf[len] = (unsigned char) (port >> 8);
buf[len+1] = (unsigned char) (port & 0xff);
write(sock, buf, len+2);
for (i=0; i<4; i++) {
int n;
n = read(sock, tmp, 1);
j++;
if (n < 0) {
if (errno != EINTR) {
break;
} else {
i--;
if (j > 100) {
break;
}
continue;
}
}
if (n == 0) {
break;
}
reply[i] = tmp[0];
}
if (reply[3] == 0x1) {
read(sock, reply+4, 4 + 2);
} else if (reply[3] == 0x3) {
n = read(sock, tmp, 1);
reply[4] = tmp[0];
read(sock, reply+5, (int) reply[4] + 2);
} else if (reply[3] == 0x4) {
read(sock, reply+4, 16 + 2);
}
if (0) {
int i;
for (i=0; i<len+2; i++) {
fprintf(stderr, "b[%d]: %d\n", i, (int) buf[i]);
}
for (i=0; i<len+2; i++) {
fprintf(stderr, "r[%d]: %d\n", i, (int) reply[i]);
}
}
if (reply[0] == 0x5 && reply[1] == 0x0 && reply[2] == 0x0) {
rfbLog("SOCKS5 connect OK to %s:%d sock=%d\n", host, port, sock);
return 1;
} else {
rfbLog("SOCKS5 error to %s:%d sock=%d\n", host, port, sock);
close(sock);
return 0;
}
}
static int socks_proxy(char *host, int port, int sock) {
unsigned char buf[512], tmp[2];
char reply[16];
int socks4a = 0, len, i, j = 0, d1, d2, d3, d4;
memset(buf, 0, 512);
buf[0] = 0x4;
buf[1] = 0x1;
buf[2] = (unsigned char) (port >> 8);
buf[3] = (unsigned char) (port & 0xff);
if (strlen(host) > 256) {
rfbLog("socks_proxy: hostname too long: %s\n", host);
close(sock);
return 0;
}
if (!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) {
buf[4] = 127;
buf[5] = 0;
buf[6] = 0;
buf[7] = 1;
} else if (sscanf(host, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) == 4) {
buf[4] = (unsigned char) d1;
buf[5] = (unsigned char) d2;
buf[6] = (unsigned char) d3;
buf[7] = (unsigned char) d4;
} else {
buf[4] = 0x0;
buf[5] = 0x0;
buf[6] = 0x0;
buf[7] = 0x3;
socks4a = 1;
}
len = 8;
strcat((char *)buf+8, "nobody");
len += strlen("nobody") + 1;
if (socks4a) {
strcat((char *) buf+8+strlen("nobody") + 1, host);
len += strlen(host) + 1;
}
write(sock, buf, len);
for (i=0; i<8; i++) {
int n;
n = read(sock, tmp, 1);
j++;
if (n < 0) {
if (errno != EINTR) {
break;
} else {
i--;
if (j > 100) {
break;
}
continue;
}
}
if (n == 0) {
break;
}
reply[i] = tmp[0];
}
if (0) {
int i;
for (i=0; i<len; i++) {
fprintf(stderr, "b[%d]: %d\n", i, (int) buf[i]);
}
for (i=0; i<8; i++) {
fprintf(stderr, "r[%d]: %d\n", i, (int) reply[i]);
}
}
if (reply[0] == 0x0 && reply[1] == 0x5a) {
if (socks4a) {
rfbLog("SOCKS4a connect OK to %s:%d sock=%d\n", host, port, sock);
} else {
rfbLog("SOCKS4 connect OK to %s:%d sock=%d\n", host, port, sock);
}
return 1;
} else {
if (socks4a) {
rfbLog("SOCKS4a error to %s:%d sock=%d\n", host, port, sock);
} else {
rfbLog("SOCKS4 error to %s:%d sock=%d\n", host, port, sock);
}
close(sock);
return 0;
}
}
#define PXY_HTTP 1
#define PXY_GET 2
#define PXY_SOCKS 3
#define PXY_SOCKS5 4
#define PXY_SSH 5
#define PXY 3
static int pxy_get_sock;
static int pconnect(int psock, char *host, int port, int type, char *http_path, char *gethost, int getport) {
char reply[4096];
int i, ok, len;
char *req;
pxy_get_sock = -1;
if (type == PXY_SOCKS) {
return socks_proxy(host, port, psock);
}
if (type == PXY_SOCKS5) {
return socks5_proxy(host, port, psock);
}
if (type == PXY_SSH) {
return 1;
}
len = strlen("CONNECT ") + strlen(host);
if (type == PXY_GET) {
len += strlen(http_path) + strlen(gethost);
len += strlen("host=") + 1 + strlen("port=") + 1 + 1;
}
len += 1 + 20 + strlen("HTTP/1.1\r\n") + 1;
req = (char *)malloc(len);
if (type == PXY_GET) {
int noquery = 0;
char *t = strstr(http_path, "__END__");
if (t) {
noquery = 1;
*t = '\0';
}
if (noquery) {
sprintf(req, "GET %s HTTP/1.1\r\n", http_path);
} else {
sprintf(req, "GET %shost=%s&port=%d HTTP/1.1\r\n", http_path, host, port);
}
} else {
sprintf(req, "CONNECT %s:%d HTTP/1.1\r\n", host, port);
}
rfbLog("http proxy: %s", req);
write(psock, req, strlen(req));
if (type == PXY_GET) {
char *t = "Connection: close\r\n";
write(psock, t, strlen(t));
}
if (type == PXY_GET) {
sprintf(req, "Host: %s:%d\r\n", gethost, getport);
rfbLog("http proxy: %s", req);
sprintf(req, "Host: %s:%d\r\n\r\n", gethost, getport);
} else {
sprintf(req, "Host: %s:%d\r\n", host, port);
rfbLog("http proxy: %s", req);
sprintf(req, "Host: %s:%d\r\n\r\n", host, port);
}
write(psock, req, strlen(req));
ok = 0;
reply[0] = '\0';
for (i=0; i<4096; i++) {
int n;
req[0] = req[1] = '\0';
n = read(psock, req, 1);
if (n < 0) {
if (errno != EINTR) {
break;
} else {
continue;
}
}
if (n == 0) {
break;
}
strcat(reply, req);
if (strstr(reply, "\r\n\r\n")) {
if (strstr(reply, "HTTP/") == reply) {
char *q = strchr(reply, ' ');
if (q) {
q++;
if (q[0] == '2' && q[1] == '0' && q[2] == '0' && q[3] == ' ') {
ok = 1;
}
}
}
break;
}
}
if (type == PXY_GET) {
char *t1 = strstr(reply, "VNC-IP-Port: ");
char *t2 = strstr(reply, "VNC-Host-Port: ");
char *s, *newhost = NULL;
int newport = 0;
fprintf(stderr, "%s\n", reply);
if (t1) {
t1 += strlen("VNC-IP-Port: ");
s = strstr(t1, ":");
if (s) {
*s = '\0';
newhost = strdup(t1);
newport = atoi(s+1);
}
} else if (t2) {
t2 += strlen("VNC-Host-Port: ");
s = strstr(t2, ":");
if (s) {
*s = '\0';
newhost = strdup(t2);
newport = atoi(s+1);
}
}
if (newhost && newport > 0) {
rfbLog("proxy GET reconnect to: %s:%d\n", newhost, newport);
pxy_get_sock = rfbConnectToTcpAddr(newhost, newport);
}
}
free(req);
return ok;
}
static int proxy_connect(char *host, int port) {
char *p, *q, *str;
int i, n, pxy[PXY],pxy_p[PXY];
int psock = -1;
char *pxy_h[PXY], *pxy_g[PXY];
if (! connect_proxy) {
return -1;
}
str = strdup(connect_proxy);
for (i=0; i<PXY; i++) {
pxy[i] = 0;
pxy_p[i] = 0;
pxy_h[i] = NULL;
pxy_g[i] = NULL;
}
n = 0;
p = str;
while (p) {
char *hp, *c, *s = NULL;
q = strchr(p, ',');
if (q) {
*q = '\0';
}
if (n==0) fprintf(stderr, "\n");
rfbLog("proxy_connect[%d]: %s\n", n+1, p);
pxy[n] = 0;
pxy_p[n] = 0;
pxy_h[n] = NULL;
pxy_g[n] = NULL;
if (strstr(p, "socks://") == p) {
hp = strstr(p, "://") + 3;
pxy[n] = PXY_SOCKS;
} else if (strstr(p, "socks4://") == p) {
hp = strstr(p, "://") + 3;
pxy[n] = PXY_SOCKS;
} else if (strstr(p, "socks5://") == p) {
hp = strstr(p, "://") + 3;
pxy[n] = PXY_SOCKS5;
} else if (strstr(p, "ssh://") == p) {
if (n != 0) {
rfbLog("ssh:// proxy must be the first one\n");
clean_up_exit(1);
}
hp = strstr(p, "://") + 3;
pxy[n] = PXY_SSH;
} else if (strstr(p, "http://") == p) {
hp = strstr(p, "://") + 3;
pxy[n] = PXY_HTTP;
} else if (strstr(p, "https://") == p) {
hp = strstr(p, "://") + 3;
pxy[n] = PXY_HTTP;
} else {
hp = p;
pxy[n] = PXY_HTTP;
}
c = strstr(hp, ":");
if (!c && pxy[n] == PXY_SSH) {
char *hp2 = (char *) malloc(strlen(hp) + 5);
sprintf(hp2, "%s:1", hp);
hp = hp2;
c = strstr(hp, ":");
}
if (!c) {
pxy[n] = 0;
if (q) {
*q = ',';
p = q + 1;
} else {
p = NULL;
}
continue;
}
if (pxy[n] == PXY_HTTP) {
s = strstr(c, "/");
if (s) {
pxy[n] = PXY_GET;
pxy_g[n] = strdup(s);
*s = '\0';
}
}
pxy_p[n] = atoi(c+1);
if (pxy_p[n] <= 0) {
pxy[n] = 0;
pxy_p[n] = 0;
if (q) {
*q = ',';
p = q + 1;
} else {
p = NULL;
}
continue;
}
*c = '\0';
pxy_h[n] = strdup(hp);
if (++n >= PXY) {
break;
}
if (q) {
*q = ',';
p = q + 1;
} else {
p = NULL;
}
}
free(str);
if (!n) {
psock = -1;
goto pxy_clean;
}
if (pxy[0] == PXY_SSH) {
int rc, len = 0;
char *cmd, *ssh;
int sport = find_free_port(7300, 8000);
if (getenv("SSH")) {
ssh = getenv("SSH");
} else {
ssh = "ssh";
}
len = 200 + strlen(ssh) + strlen(pxy_h[0]) + strlen(host);
cmd = (char *) malloc(len);
if (n == 1) {
if (pxy_p[0] <= 1) {
sprintf(cmd, "%s -f -L '%d:%s:%d' '%s' 'sleep 20'", ssh, sport, host, port, pxy_h[0]);
} else {
sprintf(cmd, "%s -f -p %d -L '%d:%s:%d' '%s' 'sleep 20'", ssh, pxy_p[0], sport, host, port, pxy_h[0]);
}
} else {
if (pxy_p[0] <= 1) {
sprintf(cmd, "%s -f -L '%d:%s:%d' '%s' 'sleep 20'", ssh, sport, pxy_h[1], pxy_p[1], pxy_h[0]);
} else {
sprintf(cmd, "%s -f -p %d -L '%d:%s:%d' '%s' 'sleep 20'", ssh, pxy_p[0], sport, pxy_h[1], pxy_p[1], pxy_h[0]);
}
}
if (no_external_cmds || !cmd_ok("ssh")) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", cmd);
rfbLog(" exiting.\n");
clean_up_exit(1);
}
close_exec_fds();
fprintf(stderr, "\n");
rfbLog("running: %s\n", cmd);
rc = system(cmd);
free(cmd);
if (rc != 0) {
psock = -1;
goto pxy_clean;
}
psock = rfbConnectToTcpAddr("localhost", sport);
} else {
psock = rfbConnectToTcpAddr(pxy_h[0], pxy_p[0]);
}
if (psock < 0) {
psock = -1;
goto pxy_clean;
}
rfbLog("opened socket to proxy: %s:%d\n", pxy_h[0], pxy_p[0]);
if (n >= 2) {
if (! pconnect(psock, pxy_h[1], pxy_p[1], pxy[0], pxy_g[0], pxy_h[0], pxy_p[0])) {
close(psock); psock = -1; goto pxy_clean;
}
if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
if (n >= 3) {
if (! pconnect(psock, pxy_h[2], pxy_p[2], pxy[1], pxy_g[1], pxy_h[1], pxy_p[1])) {
close(psock); psock = -1; goto pxy_clean;
}
if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
if (! pconnect(psock, host, port, pxy[2], pxy_g[2], pxy_h[2], pxy_p[2])) {
close(psock); psock = -1; goto pxy_clean;
}
if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
} else {
if (! pconnect(psock, host, port, pxy[1], pxy_g[1], pxy_h[1], pxy_p[1])) {
close(psock); psock = -1; goto pxy_clean;
}
if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
}
} else {
if (! pconnect(psock, host, port, pxy[0], pxy_g[0], pxy_h[0], pxy_p[0])) {
close(psock); psock = -1; goto pxy_clean;
}
if (pxy_get_sock >= 0) {close(psock); psock = pxy_get_sock;}
}
pxy_clean:
for (i=0; i < PXY; i++) {
if (pxy_h[i] != NULL) {
free(pxy_h[i]);
}
if (pxy_g[i] != NULL) {
free(pxy_g[i]);
}
}
return psock;
}
/*
* Do a reverse connect for a single "host" or "host:port"
*/
@ -1654,15 +2192,13 @@ static int do_reverse_connect(char *str) {
*p = '\0';
}
#if 0
if (use_openssl && !getenv("X11VNC_SSL_ALLOW_REVERSE")) {
rfbLog("reverse connections disabled in -ssl mode.\n");
return 0;
}
#endif
if (use_openssl) {
int vncsock = rfbConnectToTcpAddr(host, rport);
int vncsock;
if (connect_proxy) {
vncsock = proxy_connect(host, rport);
} else {
vncsock = rfbConnectToTcpAddr(host, rport);
}
if (vncsock < 0) {
rfbLog("reverse_connect: failed to connect to: %s\n", str);
return 0;
@ -1702,7 +2238,17 @@ static int do_reverse_connect(char *str) {
}
}
if (connect_proxy != NULL) {
int sock = proxy_connect(host, rport);
if (sock >= 0) {
cl = rfbNewClient(screen, sock);
} else {
return 0;
}
} else {
cl = rfbReverseConnection(screen, host, rport);
}
free(host);
if (cl == NULL) {

@ -400,7 +400,7 @@ void print_help(int mode) {
"-http_ssl As -http, but force lookup for ssl classes subdir.\n"
#endif
"\n"
"-avahi Use the Avahi/mDNS ZeroConf protocol to advertize\n"
"-avahi Use the Avahi/mDNS ZeroConf protocol to advertise\n"
" this VNC server to the local network. (Related terms:\n"
" Rendezvous, Bonjour). Depending on your setup, you\n"
" may need to start avahi-daemon and open udp port 5353\n"
@ -432,8 +432,67 @@ void print_help(int mode) {
"-connect_or_exit str As with -connect, except if none of the reverse\n"
" connections succeed, then x11vnc shutdowns immediately.\n"
"\n"
" If you do not want x11vnc to listen on ANY interface\n"
" use -rfbport 0\n"
" By the way, if you do not want x11vnc to listen on\n"
" ANY interface use -rfbport 0 which is handy for the\n"
" -connect_or_exit mode.\n"
"\n"
"-proxy string Use proxy in string (e.g. host:port) as a proxy for\n"
" making reverse connections (-connect or -connect_or_exit\n"
" options).\n"
"\n"
" Web proxies are supported, but note by default most of\n"
" them only support destination connections to ports 443\n"
" or 563, so this might not be very useful (the viewer\n"
" would need to listen on that port or the router would\n"
" have to do a port redirection).\n"
"\n"
" A web proxy may be specified by either \"host:port\"\n"
" or \"http://host:port\" (the port is required even if\n"
" it is the common choices 80 or 8080)\n"
"\n"
" SOCKS4, SOCKS4a, and SOCKS5 are also supported.\n"
" SOCKS proxies normally do not have restrictions on the\n"
" destination port number.\n"
"\n"
" Use a format like this: socks://host:port or\n"
" socks5://host:port. Note that ssh -D does not support\n"
" SOCKS4a, so use socks5://. For socks:// SOCKS4 is used\n"
" on a numerical IP and \"localhost\", otherwise SOCKS4a\n"
" is used (and so the proxy tries to do the DNS lookup).\n"
"\n"
" An experimental mode is \"-proxy http://host:port/...\"\n"
" Note the \"/\" after the port that distinguishes it from\n"
" a normal web proxy. The port must be supplied even if\n"
" it is the default 80. For this mode a GET is done to\n"
" the supplied URL with the string host=H&port=P appended.\n"
" H and P will be the -connect reverse connect host\n"
" and port. Use the string \"__END__\" to disable the\n"
" appending. The basic idea here is that maybe some cgi\n"
" script provides the actual viewer hookup and tunnelling.\n"
" How to actually achieve this within cgi, php, etc. is\n"
" not clear... A custom web server or apache module\n"
" would be straight-forward.\n"
"\n"
" Another experimental mode is \"-proxy ssh://user@host\"\n"
" in which case a SSH tunnel is used for the proxying.\n"
" \"user@\" is not needed unless your unix username is\n"
" different on \"host\". For a non-standard SSH port\n"
" use ssh://user@host:port. If proxies are chained (see\n"
" next paragraph) then the ssh one must be the first one.\n"
" If ssh-agent is not active, then the ssh password needs\n"
" to be entered in the terminal where x11vnc is running.\n"
" Examples:\n"
"\n"
" -connect localhost:0 -proxy ssh://me@friends-pc:2222\n"
"\n"
" -connect snoopy:0 -proxy ssh://ssh.company.com\n"
"\n"
" Multiple proxies may be chained together in case one\n"
" needs to ricochet off of a number of hosts to finally\n"
" reach the VNC viewer. Up to 3 may be chained, separate\n"
" them by commas in the order they are to be connected to.\n"
" E.g.: http://host1:port1,socks5://host2:port2 or three\n"
" like: first,second,third\n"
"\n"
"-vncconnect Monitor the VNC_CONNECT X property set by the standard\n"
"-novncconnect VNC program vncconnect(1). When the property is\n"
@ -578,7 +637,7 @@ void print_help(int mode) {
" If multiple non-blank lines exist in the file they are\n"
" all taken as valid passwords. Blank lines are ignored.\n"
" Password lines may be \"commented out\" (ignored) if\n"
" they begin with the charactor \"#\" or the line contains\n"
" they begin with the character \"#\" or the line contains\n"
" the string \"__SKIP__\". Lines may be annotated by use\n"
" of the \"__COMM__\" string: from it to the end of the\n"
" line is ignored. An empty password may be specified\n"
@ -721,7 +780,7 @@ void print_help(int mode) {
"-unixpw_nis [list] As -unixpw above, however do not use su(1) but rather\n"
" use the traditional getpwnam(3) + crypt(3) method to\n"
" verify passwords. All of the above -unixpw options and\n"
" contraints apply.\n"
" constraints apply.\n"
"\n"
" This mode requires that the encrypted passwords be\n"
" readable. Encrypted passwords stored in /etc/shadow\n"
@ -1090,6 +1149,11 @@ void print_help(int mode) {
" with libssl support it will exit immediately when -ssl\n"
" is prescribed.\n"
"\n"
" The VNC Viewer-side needs support SSL as well.\n"
" See this URL and also the discussion below for ideas\n"
" on how to enable SSL support for the viewer:\n"
" http://www.karlrunge.com/x11vnc/#faq-ssl-tunnel-viewers\n"
"\n"
" [pem] is optional, use \"-ssl /path/to/mycert.pem\"\n"
" to specify a PEM certificate file to use to identify\n"
" and provide a key for this server. See openssl(1) for\n"
@ -1098,12 +1162,12 @@ void print_help(int mode) {
" The connecting VNC viewer SSL tunnel can optionally\n"
" authenticate this server if they have the public\n"
" key part of the certificate (or a common certificate\n"
" authority, CA, is a more sophisicated way to verify\n"
" authority, CA, is a more sophisticated way to verify\n"
" this server's cert, see -sslGenCA below). This is\n"
" used to prevent man-in-the-middle attacks. Otherwise,\n"
" if the VNC viewer accepts this server's key without\n"
" verification, at least the traffic is protected\n"
" from passive sniffing on the network (but NOT from\n"
" from passive sniffing on the network (but *NOT* from\n"
" man-in-the-middle attacks).\n"
"\n"
" If [pem] is not supplied and the openssl(1) utility\n"
@ -1136,6 +1200,8 @@ void print_help(int mode) {
" made based on your answers to its prompts for info such\n"
" as OrganizationalName, CommonName, etc.\n"
"\n"
" We expect most users to use \"-ssl SAVE\".\n"
"\n"
" Use \"SAVE-<string>\" and \"SAVE_PROMPT-<string>\"\n"
" to refer to the file ~/.vnc/certs/server-<string>.pem\n"
" instead. E.g. \"SAVE-charlie\" will store to the file\n"
@ -1146,20 +1212,14 @@ void print_help(int mode) {
"\n"
" Example: x11vnc -ssl SAVE -display :0 ...\n"
"\n"
#if 0
" Reverse connections are disabled in -ssl mode because\n"
" there is no way to ensure that data channel will\n"
" be encrypted. Set X11VNC_SSL_ALLOW_REVERSE=1 to\n"
" override this.\n"
"\n"
#endif
" Your VNC viewer will also need to be able to connect\n"
" Your VNC viewer will need to be able to connect\n"
" via SSL. See the discussion below under -stunnel and\n"
" the FAQ (ss_vncviewer script) for how this might be\n"
" achieved. E.g. on Unix it is easy to write a shell\n"
" script that starts up stunnel and then vncviewer.\n"
" Also in the x11vnc source a SSL enabled Java VNC Viewer\n"
" applet is provided in the classes/ssl directory.\n"
" http://www.karlrunge.com/x11vnc/#faq-ssl-tunnel-viewers\n"
" for how this might be achieved. E.g. on Unix it is\n"
" easy to write a shell script that starts up stunnel\n"
" and then vncviewer. Also in the x11vnc source a SSL\n"
" enabled Java VNC Viewer applet is provided in the\n"
" classes/ssl directory.\n"
"\n"
"-ssltimeout n Set SSL read timeout to n seconds. In some situations\n"
" (i.e. an iconified viewer in Windows) the viewer stops\n"
@ -1326,7 +1386,7 @@ void print_help(int mode) {
" Once you have generated the CA you can distribute\n"
" its certificate part, [dir]/CA/cacert.pem, to other\n"
" workstations where VNC viewers will be run. One will\n"
" need to \"import\" this certicate in the applications,\n"
" need to \"import\" this certificate in the applications,\n"
" e.g. Web browser, Java applet plugin, stunnel, etc.\n"
" Next, you can create and sign keys using the CA with\n"
" the -sslGenCert option below.\n"
@ -1400,7 +1460,7 @@ void print_help(int mode) {
" Similar to -sslGenCA, you will be prompted to fill\n"
" in some information that will be recorded in the\n"
" certificate when it is created. Tip: if you know\n"
" the fully-quailified hostname other people will be\n"
" the fully-qualified hostname other people will be\n"
" connecting to you can use that as the CommonName \"CN\"\n"
" to avoid some applications (e.g. web browsers and java\n"
" plugin) complaining it does not match the hostname.\n"
@ -1408,7 +1468,7 @@ void print_help(int mode) {
" You will also need to supply the CA private key\n"
" passphrase to unlock the private key created from\n"
" -sslGenCA. This private key is used to sign the server\n"
" or client certicate.\n"
" or client certificate.\n"
"\n"
" The \"server\" certs can be used by x11vnc directly by\n"
" pointing to them via the -ssl [pem] option. The default\n"
@ -1621,13 +1681,51 @@ void print_help(int mode) {
"\n"
" This spares the user from having to type in\n"
" https://mygateway.com/?PORT=443 into their web\n"
" browser. Note taht port 443 is the default https port;\n"
" other ports must be explicity indicated, for example:\n"
" browser. Note that port 443 is the default https port;\n"
" other ports must be explicitly indicated, for example:\n"
" https://mygateway.com:8000/?PORT=8000. To avoid having\n"
" to include the PORT= in the browser URL, simply supply\n"
" \"-httpsredir\" to x11vnc.\n"
"\n"
#endif
"-ssh user@host:disp Create a remote listening port on machine \"host\"\n"
" via a SSH tunnel using the -R rport:localhost:lport\n"
" method. lport will be the local x11vnc listening port,\n"
" so a connection to rport (5900+disp) on \"host\"\n"
" will reach x11vnc. E.g. fred@snoopy.com:0\n"
"\n"
" This could be useful if a firewall/router prevents\n"
" incoming connections to the x11vnc machine, but\n"
" the ssh machine \"host\" can be reached by the VNC\n"
" viewer. \"user@\" is not needed unless the remote unix\n"
" username differs from the current one.\n"
"\n"
" By default the remote sshd is usually configured to\n"
" only listen on localhost for rport, so the viewer may\n"
" need to ssh -L redir to \"host\" as well (See SSVNC to\n"
" automate this). The sshd setting GatewayPorts enables\n"
" listening on all interfaces for rport; viewers can\n"
" reach it more easily.\n"
"\n"
" \"disp\" is the VNC display for the remote SSH side,\n"
" e.g. 0 corresponds to port 5900, etc. If disp is\n"
" greater than 200 the value is used as the port. Use a\n"
" negative value to force a low port, e.g. host:-80 will\n"
" use port 80.\n"
"\n"
" If ssh-agent is not active, then the ssh password needs\n"
" to be entered in the terminal where x11vnc is running.\n"
"\n"
" By default the remote ssh will issue a 'sleep 300' to\n"
" wait for the incoming connection for 5 mins. To modify\n"
" this use user@host:disp+secs.\n"
"\n"
" If the remote SSH server is on a non-standard port\n"
" (i.e. not 22) use user@host:port:disp+secs.\n"
"\n"
" Note that the ssh process may NOT be killed when\n"
" x11vnc exits. It tries by looking at ps(1) output.\n"
"\n"
"-usepw If no other password method was supplied on the command\n"
" line, first look for ~/.vnc/passwd and if found use it\n"
" with -rfbauth; next, look for ~/.vnc/passwdfile and\n"
@ -1674,7 +1772,7 @@ void print_help(int mode) {
" in RFB_CLIENT_COUNT. RFB_MODE will be \"accept\".\n"
" RFB_STATE will be PROTOCOL_VERSION, SECURITY_TYPE,\n"
" AUTHENTICATION, INITIALISATION, NORMAL, or UNKNOWN\n"
" indicating up to which state the client has acheived.\n"
" indicating up to which state the client has achieved.\n"
" RFB_LOGIN_VIEWONLY will be 0, 1, or -1 (unknown).\n"
" RFB_USERNAME, RFB_LOGIN_TIME, and RFB_CURRENT_TIME may\n"
" also be set.\n"
@ -2913,7 +3011,7 @@ void print_help(int mode) {
"-nowait_bog Do not detect if the screen polling is \"bogging down\"\n"
" and sleep more. Some activities with no user input can\n"
" slow things down a lot: consider a large terminal window\n"
" with a long build running in it continously streaming\n"
" with a long build running in it continuously streaming\n"
" text output. By default x11vnc will try to detect this\n"
" (3 screen polls in a row each longer than 0.25 sec with\n"
" no user input), and sleep up to 1.5 secs to let things\n"
@ -3110,7 +3208,7 @@ void print_help(int mode) {
" so take care.\n"
"\n"
" If the string begins with \"video\", see the VIDEO4LINUX\n"
" discusion below where the device may be queried for\n"
" discussion below where the device may be queried for\n"
" (and possibly set) the framebuffer parameters.\n"
"\n"
" If the string begins with \"console\", \"/dev/fb\", or\n"
@ -3668,10 +3766,10 @@ void print_help(int mode) {
" nohttp disable http client connections.\n"
" deny deny any new connections, same as \"lock\"\n"
" nodeny allow new connections, same as \"unlock\"\n"
" avahi enable avahi service advertizing.\n"
" noavahi disable avahi service advertizing.\n"
" mdns enable avahi service advertizing.\n"
" nomdns disable avahi service advertizing.\n"
" avahi enable avahi service advertising.\n"
" noavahi disable avahi service advertising.\n"
" mdns enable avahi service advertising.\n"
" nomdns disable avahi service advertising.\n"
/* access, filename */
" connect:host do reverse connection to host, \"host\"\n"
" may be a comma separated list of hosts\n"
@ -3684,6 +3782,8 @@ void print_help(int mode) {
" If you know the client internal hex ID,\n"
" e.g. 0x3 (returned by \"-query clients\"\n"
" and RFB_CLIENT_ID) you can use that too.\n"
" proxy:host:port set reverse connection proxy (empty to\n"
" disable).\n"
/* access */
" allowonce:host For the next connection only, allow\n"
" connection from \"host\".\n"
@ -3819,11 +3919,14 @@ void print_help(int mode) {
" noncache_no_moveraise disable no_moveraise mode.\n"
" ncache_no_dtchange enable ncache_no_dtchange mode.\n"
" noncache_no_dtchange disable ncache_no_dtchange mode.\n"
" ncache_old_wm enable ncache_old_wm mode.\n"
" noncache_old_wm disable ncache_old_wm mode.\n"
" ncache_no_rootpixmap enable ncache_no_rootpixmap.\n"
" noncache_no_rootpixmap disable ncache_no_rootpixmap.\n"
" ncache_reset_rootpixmap recheck the root pixmap, ncrp\n"
" ncache_keep_anims enable ncache_keep_anims.\n"
" noncache_keep_anims disable ncache_keep_anims.\n"
" ncache_pad:n set -ncache_pad to n.\n"
" wireframe enable -wireframe mode. same as \"wf\"\n"
" nowireframe disable -wireframe mode. same as \"nowf\"\n"
" wireframe:str enable -wireframe mode string.\n"
@ -3981,8 +4084,8 @@ void print_help(int mode) {
" 8to24_opts 24to32 no24to32 visual scale scale_cursor\n"
" viewonly noviewonly shared noshared forever noforever\n"
" once timeout tightfilexfer notightfilexfer ultrafilexfer\n"
" noultrafilexfer rfbversion deny lock nodeny unlock\n"
" avahi mdns noavahi nomdns connect allowonce allow\n"
" noultrafilexfer rfbversion deny lock nodeny unlock avahi\n"
" mdns noavahi nomdns connect proxy allowonce allow\n"
" localhost nolocalhost listen lookup nolookup accept\n"
" afteraccept gone shm noshm flipbyteorder noflipbyteorder\n"
" onetile noonetile solid_color solid nosolid blackout\n"
@ -4004,12 +4107,12 @@ void print_help(int mode) {
" nodragging ncache_cr noncache_cr ncache_no_moveraise\n"
" noncache_no_moveraise ncache_no_dtchange\n"
" noncache_no_dtchange ncache_no_rootpixmap\n"
" noncache_no_rootpixmap ncache_reset_rootpixmap\n"
" noncache_no_rootpixmap ncache_reset_rootpixmap ncrp\n"
" ncache_keep_anims noncache_keep_anims ncache_old_wm\n"
" noncache_old_wm ncache noncache ncache_size debug_ncache\n"
" nodebug_ncache wireframe_mode wireframe wf nowireframe\n"
" nowf wireframelocal wfl nowireframelocal nowfl\n"
" wirecopyrect wcr nowirecopyrect nowcr scr_area\n"
" noncache_old_wm ncache_pad ncache noncache ncache_size\n"
" debug_ncache nodebug_ncache wireframe_mode wireframe wf\n"
" nowireframe nowf wireframelocal wfl nowireframelocal\n"
" nowfl wirecopyrect wcr nowirecopyrect nowcr scr_area\n"
" scr_skip scr_inc scr_keys scr_term scr_keyrepeat\n"
" scr_parms scrollcopyrect scr noscrollcopyrect noscr\n"
" fixscreen noxrecord xrecord reset_record pointer_mode\n"
@ -4074,7 +4177,7 @@ void print_help(int mode) {
" command was processed by querying for any new settings.\n"
" Note however that there is timeout of a few seconds so\n"
" if the x11vnc takes longer than that to process the\n"
" requests the requestor will think that a failure has\n"
" requests the requester will think that a failure has\n"
" taken place.\n"
"\n"
"-noremote Do not process any remote control commands or queries.\n"
@ -4120,7 +4223,7 @@ void print_help(int mode) {
" associated options is:\n"
"\n"
" stunnel, ssl, unixpw, WAIT, id, accept, afteraccept,\n"
" gone, pipeinput, v4l-info, rawfb-setup, dt, gui,\n"
" gone, pipeinput, v4l-info, rawfb-setup, dt, gui, ssh,\n"
" storepasswd, passwdfile, custom_passwd, crash.\n"
"\n"
" See each option's help to learn the associated external\n"
@ -4257,7 +4360,7 @@ void xopen_display_fail_message(char *disp) {
" the secret key that\n");
fprintf(stderr, " allows x11vnc to connect to the desired"
" X DISPLAY.\n");
fprintf(stderr, " - You can explicity indicate which MIT-MAGIC-COOKIE"
fprintf(stderr, " - You can explicitly indicate which MIT-MAGIC-COOKIE"
" file should be used\n");
fprintf(stderr, " by the -auth option, e.g.:\n");
fprintf(stderr, " x11vnc -auth /home/someuser/.Xauthority"

@ -1755,7 +1755,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (khints && keysym < 0x100) {
/* low keysyms, ascii, only */
int ks = (int) keysym;
int ok = 1, lbest, l;
int ok = 1, lbest = 0, l;
short sbest = -1;
for (l=0; l < found; l++) {
if (kc_f[l] < 0x100) {
@ -1820,7 +1820,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
/* next just check for "best" one that is down */
if (Kc_f == -1 && anydown) {
int l;
int best = -1, lbest;
int best = -1, lbest = 0;
/*
* If it is already down, that is
* a great hint. Use it.

@ -1,5 +1,7 @@
/* -- macosxCGP.c -- */
void macosxCGP_unused(void) {}
#if (defined(__MACH__) && defined(__APPLE__))
#include <ApplicationServices/ApplicationServices.h>

@ -5,6 +5,7 @@
* and the other stuff, otherwise it does not work properly, mouse drags
* will not work!!
*/
void macosxCGS_unused(void) {}
#if (defined(__MACH__) && defined(__APPLE__))

@ -35,6 +35,8 @@ int https_port_redir = 0;
char *ssl_verify = NULL;
int ssl_initialized = 0;
int ssl_timeout_secs = -1;
char *ssh_str = NULL;
pid_t ssh_pid = 0;
int usepw = USEPW;
char *blackout_str = NULL; /* -blackout */
int blackout_ptr = 0;
@ -176,6 +178,7 @@ char *client_connect = NULL; /* strings for -connect option */
char *client_connect_file = NULL;
int connect_or_exit = 0;
int vnc_connect = 1; /* -vncconnect option */
char *connect_proxy = NULL;
int show_cursor = 1; /* show cursor shapes */
int show_multiple_cursors = 0; /* show X when on root background, etc */

@ -35,6 +35,8 @@ extern int https_port_redir;
extern char *ssl_verify;
extern int ssl_initialized;
extern int ssl_timeout_secs;
extern char *ssh_str;
extern pid_t ssh_pid;
extern int usepw;
extern char *blackout_str;
extern int blackout_ptr;
@ -148,6 +150,7 @@ extern char *client_connect;
extern char *client_connect_file;
extern int connect_or_exit;
extern int vnc_connect;
extern char *connect_proxy;
extern int show_cursor;
extern int show_multiple_cursors;

@ -1380,6 +1380,25 @@ char *process_remote_cmd(char *cmd, int stringonly) {
/* this is a reverse connection */
reverse_connect(p);
} else if (strstr(p, "proxy") == p) {
COLON_CHECK("proxy:")
if (query) {
snprintf(buf, bufn, "ans=%s%s%s", p, co,
NONUL(connect_proxy));
goto qry;
}
p += strlen("proxy:");
if (connect_proxy) {
free(connect_proxy);
connect_proxy = NULL;
}
if (!strcmp(p, "") || !strcasecmp(p, "none")) {
rfbLog("remote_cmd: disabled -proxy\n");
} else {
connect_proxy = strdup(p);
rfbLog("remote_cmd: set -proxy %s\n", connect_proxy);
}
} else if (strstr(p, "allowonce") == p) {
COLON_CHECK("allowonce:")
if (query) {
@ -2910,6 +2929,18 @@ char *process_remote_cmd(char *cmd, int stringonly) {
ncache_old_wm = 0;
rfbLog("remote_cmd: disabled -ncache_old_wm\n");
} else if (strstr(p, "ncache_pad") == p) {
int orig = ncache_pad, n;
COLON_CHECK("ncache_pad:")
if (query) {
snprintf(buf, bufn, "ans=%s%s%d", p, co, ncache_pad);
goto qry;
}
p += strlen("ncache_pad:");
n = atoi(p);
rfbLog("remote_cmd: setting ncache_pad %d to: %d\n", orig, n);
} else if (!strcmp(p, "ncache")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, !!ncache);

@ -25,6 +25,7 @@
#include "macosxCG.h"
#include "avahi.h"
#include "solid.h"
#include "inet.h"
#include <rfb/rfbclient.h>
@ -1242,7 +1243,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
unsigned int vals[1024], val;
int x, y, fd, w = 1024, h = 768;
if (strstr(n, "0x")) {
if (sscanf(n, "0x%lx", &val) != 1) {
if (sscanf(n, "0x%x", &val) != 1) {
val = 0;
}
}

@ -62,6 +62,7 @@ void selection_request(XEvent *ev, char *type) {
char *str;
unsigned int length;
unsigned char *data;
static Atom xa_targets = None;
# ifndef XA_LENGTH
unsigned long XA_LENGTH;
# endif
@ -103,34 +104,69 @@ void selection_request(XEvent *ev, char *type) {
req_event->target, req_event->property);
}
if (xa_targets == None) {
xa_targets = XInternAtom(dpy, "TARGETS", False);
}
/* the window may have gone away, so trap errors */
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
if (ev->xselectionrequest.target == XA_LENGTH) {
/* length request */
int ret;
long llength = (long) length;
XChangeProperty(ev->xselectionrequest.display,
ret = XChangeProperty(ev->xselectionrequest.display,
ev->xselectionrequest.requestor,
ev->xselectionrequest.property,
ev->xselectionrequest.target, 32, PropModeReplace,
(unsigned char *) &length, sizeof(unsigned int));
(unsigned char *) &llength, 1); /* had sizeof(unsigned int) = 4 before... */
if (debug_sel) {
rfbLog("LENGTH: XChangeProperty() -> %d\n", ret);
}
} else if (xa_targets != None && ev->xselectionrequest.target == xa_targets) {
/* targets request */
int ret;
Atom targets[2];
targets[0] = (Atom) xa_targets;
targets[1] = (Atom) XA_STRING;
data = (unsigned char *)str;
ret = XChangeProperty(ev->xselectionrequest.display,
ev->xselectionrequest.requestor,
ev->xselectionrequest.property,
ev->xselectionrequest.target, 32, PropModeReplace,
(unsigned char *) targets, 2);
if (debug_sel) {
rfbLog("TARGETS: XChangeProperty() -> %d -- sz1: %d sz2: %d\n",
ret, sizeof(targets[0]), sizeof(targets)/sizeof(targets[0]));
}
} else {
/* data request */
int ret;
data = (unsigned char *)str;
XChangeProperty(ev->xselectionrequest.display,
ret = XChangeProperty(ev->xselectionrequest.display,
ev->xselectionrequest.requestor,
ev->xselectionrequest.property,
ev->xselectionrequest.target, 8, PropModeReplace,
data, length);
if (debug_sel) {
rfbLog("DATA: XChangeProperty() -> %d\n", ret);
}
}
if (! trapped_xerror) {
XSendEvent(req_event->display, req_event->requestor, False, 0,
int ret = XSendEvent(req_event->display, req_event->requestor, False, 0,
(XEvent *)&notify_event);
if (debug_sel) {
rfbLog("XSendEvent() -> %d\n", ret);
}
}
if (trapped_xerror) {
rfbLog("selection_request: ignored XError while sending "

@ -382,8 +382,10 @@ Tuning
ncache_cr
ncache_no_moveraise
ncache_no_dtchange
ncache_old_wm
ncache_no_rootpixmap
ncache_keep_anims
ncache_pad:
=RA ncache_reset_rootpixmap
=GAL LOFF
--

@ -393,8 +393,10 @@ char gui_code[] = "";
" ncache_cr\n"
" ncache_no_moveraise\n"
" ncache_no_dtchange\n"
" ncache_old_wm\n"
" ncache_no_rootpixmap\n"
" ncache_keep_anims\n"
" ncache_pad:\n"
" =RA ncache_reset_rootpixmap\n"
" =GAL LOFF\n"
" --\n"

@ -1314,6 +1314,7 @@ void user_supplied_opts(char *opts) {
static void vnc_redirect_timeout (int sig) {
write(2, "timeout: no clients connected.\n", 31);
if (sig) {};
exit(0);
}
@ -1513,6 +1514,10 @@ int wait_for_client(int *argc, char** argv, int http) {
initialize_signals();
if (ssh_str != NULL) {
ssh_remote_tunnel(ssh_str, screen->port);
}
if (! raw_fb) {
chg_raw_fb = 1;
/* kludge to get RAWFB_RET with dpy == NULL guards */
@ -1600,7 +1605,6 @@ int wait_for_client(int *argc, char** argv, int http) {
accept_openssl(OPENSSL_INETD, -1);
}
} else {
int gotone = 0;
if (first_conn_timeout) {
if (first_conn_timeout < 0) {
first_conn_timeout = -first_conn_timeout;

@ -151,6 +151,14 @@ int get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h,
*w = attr.width;
*h = attr.height;
#if 0
/* more accurate, but the animation is bogus anyway */
if (attr.border_width > 0) {
*w += 2 * attr.border_width;
*h += 2 * attr.border_width;
}
#endif
if (win != NULL) {
*win = descend_pointer(5, c, NULL, 0);
}
@ -871,6 +879,7 @@ static void draw_box(int x, int y, int w, int h, int restore) {
memcpy(dst, src, (x1-x0)*pixelsize);
}
if (y_min >= 0) {
if (0) fprintf(stderr, "Mark-1 %d %d %d %d\n", x0, y_min, x1, y_max+1);
mark_rect_as_modified(x0, y_min, x1, y_max+1, 0);
}
save[i]->saved = 0;
@ -1012,6 +1021,7 @@ if (0) fprintf(stderr, " DrawBox: %04dx%04d+%04d+%04d B=%d rest=%d lw=%d %.4f\n
}
/* mark it for sending: */
if (save[i]->saved) {
if (0) fprintf(stderr, "Mark-2 %d %d %d %d\n", x0, y_min, x1, y_max+1);
mark_rect_as_modified(x0, y_min, x1, y_max+1, 0);
}
}
@ -1859,9 +1869,19 @@ if (0 || debug_scroll > 1) fprintf(stderr, "<<<-rfbDoCopyRect req: %d mod: %d cp
src = main_fb + (y1-dy)*stride + (x1-dx)*Bpp;
} else if (c == 1) {
if (! cmap8to24_fb || cmap8to24_fb == rfb_fb) {
if (!cmap8to24 || !cmap8to24_fb) {
continue;
}
if (cmap8to24_fb == rfb_fb) {
if (mode == DCR_FBOnly) {
;
} else if (mode == DCR_Direct) {
;
} else if (mode == DCR_Normal) {
continue;
}
}
if (0) fprintf(stderr, "copyrect: cmap8to24_fb: mode=%d\n", mode);
if (cmap8to24 && depth == 8) {
Bpp = 4 * Bpp0;
stride = 4 * stride0;
@ -3257,6 +3277,7 @@ if (db2) fprintf(stderr, "sw: %d/%lx\n", k, swin);
stack_list[k].y = attr.y;
stack_list[k].width = attr.width;
stack_list[k].height = attr.height;
stack_list[k].border_width = attr.border_width;
stack_list[k].depth = attr.depth;
stack_list[k].class = attr.class;
stack_list[k].backing_store =
@ -3276,6 +3297,7 @@ if (db2) fprintf(stderr, "sw: %d/%lx\n", k, swin);
attr.depth = stack_list[k].depth;
attr.width = stack_list[k].width;
attr.height = stack_list[k].height;
attr.border_width = stack_list[k].border_width;
attr.map_state = stack_list[k].map_state;
if (attr.map_state != IsViewable) {
@ -4981,9 +5003,9 @@ if ((ncache || db) && ncdb) fprintf(stderr, "sent_copyrect: %d - obs: %d frame:
rfbPE(1000);
wireframe_in_progress = 0;
if (0) {
/* No longer needed. see draw_box() */
if (frame_changed && cmap8to24 && multivis_count) {
if (1) {
/* In principle no longer needed... see draw_box() */
if (frame_changed && cmap8to24 /* && multivis_count */) {
/* handle -8to24 kludge, mark area and check 8bpp... */
int x1, x2, y1, y2, f = 16;
x1 = nmin(box_x, orig_x) - f;
@ -4994,8 +5016,16 @@ if ((ncache || db) && ncdb) fprintf(stderr, "sent_copyrect: %d - obs: %d frame:
x2 = nfix(x2, dpy_x+1);
y1 = nfix(y1, dpy_y);
y2 = nfix(y2, dpy_y+1);
if (0) {
check_for_multivis();
mark_rect_as_modified(x1, y1, x2, y2, 0);
} else {
if (1) {
bpp8to24(x1, y1, x2, y2);
} else {
bpp8to24(0, 0, dpy_x, dpy_y);
}
}
}
}
@ -6011,9 +6041,16 @@ int lookup_old_stack_index(int ic) {
cache_list[k].y = attr.y; \
cache_list[k].width = attr.width; \
cache_list[k].height = attr.height; \
cache_list[k].border_width = attr.border_width; \
cache_list[k].map_state = attr.map_state; \
cache_list[k].time = dnow();
#if 0
cache_list[k].width = attr.width + 2*attr.border_width; \
cache_list[k].height = attr.height + 2*attr.border_width; \
#endif
#define CLEAR(k) \
if (0) fprintf(stderr, "CLEAR(%d)\n", k); \
cache_list[k].bs_x = -1; \
@ -8119,7 +8156,9 @@ void set_ncache_xrootpmap(void) {
dst += main_bytes_per_line;
}
XDestroyImage(image);
X_UNLOCK;
scale_mark_xrootpmap();
X_LOCK;
} else {
int yn = (ncache+1) * dpy_y;
zero_fb(0, yn, dpy_x, yn + dpy_y);

@ -405,7 +405,7 @@ double rfac(void) {
}
void check_allinput_rate(void) {
static double last_all_input_check = 0.0, last_all_input_start = 0.0;
static double last_all_input_check = 0.0;
static int set = 0;
if (! set) {
set = 1;

@ -315,6 +315,7 @@ void update_stack_list(void) {
stack_list[k].y = attr.y;
stack_list[k].width = attr.width;
stack_list[k].height = attr.height;
stack_list[k].border_width = attr.border_width;
stack_list[k].depth = attr.depth;
stack_list[k].class = attr.class;
stack_list[k].backing_store = attr.backing_store;

@ -9,6 +9,7 @@ typedef struct winattr {
int valid;
int x, y;
int width, height;
int border_width;
int depth;
int class;
int backing_store;

@ -2,7 +2,7 @@
.TH X11VNC "1" "October 2007" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.9.3, lastmod: 2007-09-30
version: 0.9.4, lastmod: 2007-10-27
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@ -472,7 +472,7 @@ As \fB-http,\fR but force lookup for ssl classes subdir.
.PP
\fB-avahi\fR
.IP
Use the Avahi/mDNS ZeroConf protocol to advertize
Use the Avahi/mDNS ZeroConf protocol to advertise
this VNC server to the local network. (Related terms:
Rendezvous, Bonjour). Depending on your setup, you
may need to start avahi-daemon and open udp port 5353
@ -513,8 +513,69 @@ is running as root (e.g. via
As with \fB-connect,\fR except if none of the reverse
connections succeed, then x11vnc shutdowns immediately.
.IP
If you do not want x11vnc to listen on ANY interface
use \fB-rfbport\fR 0
By the way, if you do not want x11vnc to listen on
ANY interface use \fB-rfbport\fR 0 which is handy for the
\fB-connect_or_exit\fR mode.
.PP
\fB-proxy\fR \fIstring\fR
.IP
Use proxy in string (e.g. host:port) as a proxy for
making reverse connections (-connect or \fB-connect_or_exit\fR
options).
.IP
Web proxies are supported, but note by default most of
them only support destination connections to ports 443
or 563, so this might not be very useful (the viewer
would need to listen on that port or the router would
have to do a port redirection).
.IP
A web proxy may be specified by either "host:port"
or "http://host:port" (the port is required even if
it is the common choices 80 or 8080)
.IP
SOCKS4, SOCKS4a, and SOCKS5 are also supported.
SOCKS proxies normally do not have restrictions on the
destination port number.
.IP
Use a format like this: socks://host:port or
socks5://host:port. Note that ssh \fB-D\fR does not support
SOCKS4a, so use socks5://. For socks:// SOCKS4 is used
on a numerical IP and "localhost", otherwise SOCKS4a
is used (and so the proxy tries to do the DNS lookup).
.IP
An experimental mode is "\fB-proxy\fR \fIhttp://host:port/...\fR"
Note the "/" after the port that distinguishes it from
a normal web proxy. The port must be supplied even if
it is the default 80. For this mode a GET is done to
the supplied URL with the string host=H&port=P appended.
H and P will be the \fB-connect\fR reverse connect host
and port. Use the string "__END__" to disable the
appending. The basic idea here is that maybe some cgi
script provides the actual viewer hookup and tunnelling.
How to actually achieve this within cgi, php, etc. is
not clear... A custom web server or apache module
would be straight-forward.
.IP
Another experimental mode is "\fB-proxy\fR \fIssh://user@host\fR"
in which case a SSH tunnel is used for the proxying.
"user@" is not needed unless your unix username is
different on "host". For a non-standard SSH port
use ssh://user@host:port. If proxies are chained (see
next paragraph) then the ssh one must be the first one.
If ssh-agent is not active, then the ssh password needs
to be entered in the terminal where x11vnc is running.
Examples:
.IP
\fB-connect\fR localhost:0 \fB-proxy\fR ssh://me@friends-pc:2222
.IP
\fB-connect\fR snoopy:0 \fB-proxy\fR ssh://ssh.company.com
.IP
Multiple proxies may be chained together in case one
needs to ricochet off of a number of hosts to finally
reach the VNC viewer. Up to 3 may be chained, separate
them by commas in the order they are to be connected to.
E.g.: http://host1:port1,socks5://host2:port2 or three
like: first,second,third
.PP
\fB-vncconnect,\fR \fB-novncconnect\fR
.IP
@ -692,7 +753,7 @@ File format for \fB-passwdfile:\fR
If multiple non-blank lines exist in the file they are
all taken as valid passwords. Blank lines are ignored.
Password lines may be "commented out" (ignored) if
they begin with the charactor "#" or the line contains
they begin with the character "#" or the line contains
the string "__SKIP__". Lines may be annotated by use
of the "__COMM__" string: from it to the end of the
line is ignored. An empty password may be specified
@ -856,7 +917,7 @@ use the traditional
.IR crypt (3)
method to
verify passwords. All of the above \fB-unixpw\fR options and
contraints apply.
constraints apply.
.IP
This mode requires that the encrypted passwords be
readable. Encrypted passwords stored in /etc/shadow
@ -1278,6 +1339,11 @@ into x11vnc at build time. If x11vnc is not built
with libssl support it will exit immediately when \fB-ssl\fR
is prescribed.
.IP
The VNC Viewer-side needs support SSL as well.
See this URL and also the discussion below for ideas
on how to enable SSL support for the viewer:
http://www.karlrunge.com/x11vnc/#faq-ssl-tunnel-viewers
.IP
[pem] is optional, use "\fB-ssl\fR \fI/path/to/mycert.pem\fR"
to specify a PEM certificate file to use to identify
and provide a key for this server. See
@ -1288,12 +1354,12 @@ more info about PEMs and the \fB-sslGenCert\fR option below.
The connecting VNC viewer SSL tunnel can optionally
authenticate this server if they have the public
key part of the certificate (or a common certificate
authority, CA, is a more sophisicated way to verify
authority, CA, is a more sophisticated way to verify
this server's cert, see \fB-sslGenCA\fR below). This is
used to prevent man-in-the-middle attacks. Otherwise,
if the VNC viewer accepts this server's key without
verification, at least the traffic is protected
from passive sniffing on the network (but NOT from
from passive sniffing on the network (but *NOT* from
man-in-the-middle attacks).
.IP
If [pem] is not supplied and the
@ -1331,6 +1397,8 @@ is "SAVE_PROMPT" the server.pem certificate will be
made based on your answers to its prompts for info such
as OrganizationalName, CommonName, etc.
.IP
We expect most users to use "\fB-ssl\fR \fISAVE\fR".
.IP
Use "SAVE-<string>" and "SAVE_PROMPT-<string>"
to refer to the file ~/.vnc/certs/server-<string>.pem
instead. E.g. "SAVE-charlie" will store to the file
@ -1341,13 +1409,14 @@ default ~/.vnc/certs
.IP
Example: x11vnc \fB-ssl\fR SAVE \fB-display\fR :0 ...
.IP
Your VNC viewer will also need to be able to connect
Your VNC viewer will need to be able to connect
via SSL. See the discussion below under \fB-stunnel\fR and
the FAQ (ss_vncviewer script) for how this might be
achieved. E.g. on Unix it is easy to write a shell
script that starts up stunnel and then vncviewer.
Also in the x11vnc source a SSL enabled Java VNC Viewer
applet is provided in the classes/ssl directory.
http://www.karlrunge.com/x11vnc/#faq-ssl-tunnel-viewers
for how this might be achieved. E.g. on Unix it is
easy to write a shell script that starts up stunnel
and then vncviewer. Also in the x11vnc source a SSL
enabled Java VNC Viewer applet is provided in the
classes/ssl directory.
.PP
\fB-ssltimeout\fR \fIn\fR
.IP
@ -1525,7 +1594,7 @@ You will also need to supply a passphrase of at least
Once you have generated the CA you can distribute
its certificate part, [dir]/CA/cacert.pem, to other
workstations where VNC viewers will be run. One will
need to "import" this certicate in the applications,
need to "import" this certificate in the applications,
e.g. Web browser, Java applet plugin, stunnel, etc.
Next, you can create and sign keys using the CA with
the \fB-sslGenCert\fR option below.
@ -1603,7 +1672,7 @@ delete the line.
Similar to \fB-sslGenCA,\fR you will be prompted to fill
in some information that will be recorded in the
certificate when it is created. Tip: if you know
the fully-quailified hostname other people will be
the fully-qualified hostname other people will be
connecting to you can use that as the CommonName "CN"
to avoid some applications (e.g. web browsers and java
plugin) complaining it does not match the hostname.
@ -1611,7 +1680,7 @@ plugin) complaining it does not match the hostname.
You will also need to supply the CA private key
passphrase to unlock the private key created from
\fB-sslGenCA.\fR This private key is used to sign the server
or client certicate.
or client certificate.
.IP
The "server" certs can be used by x11vnc directly by
pointing to them via the \fB-ssl\fR [pem] option. The default
@ -1844,12 +1913,54 @@ redir from mygateway.com:443 to workstation:5900.
.IP
This spares the user from having to type in
https://mygateway.com/?PORT=443 into their web
browser. Note taht port 443 is the default https port;
other ports must be explicity indicated, for example:
browser. Note that port 443 is the default https port;
other ports must be explicitly indicated, for example:
https://mygateway.com:8000/?PORT=8000. To avoid having
to include the PORT= in the browser URL, simply supply
"\fB-httpsredir\fR" to x11vnc.
.PP
\fB-ssh\fR \fIuser@host:disp\fR
.IP
Create a remote listening port on machine "host"
via a SSH tunnel using the \fB-R\fR rport:localhost:lport
method. lport will be the local x11vnc listening port,
so a connection to rport (5900+disp) on "host"
will reach x11vnc. E.g. fred@snoopy.com:0
.IP
This could be useful if a firewall/router prevents
incoming connections to the x11vnc machine, but
the ssh machine "host" can be reached by the VNC
viewer. "user@" is not needed unless the remote unix
username differs from the current one.
.IP
By default the remote sshd is usually configured to
only listen on localhost for rport, so the viewer may
need to ssh \fB-L\fR redir to "host" as well (See SSVNC to
automate this). The sshd setting GatewayPorts enables
listening on all interfaces for rport; viewers can
reach it more easily.
.IP
"disp" is the VNC display for the remote SSH side,
e.g. 0 corresponds to port 5900, etc. If disp is
greater than 200 the value is used as the port. Use a
negative value to force a low port, e.g. host:-80 will
use port 80.
.IP
If ssh-agent is not active, then the ssh password needs
to be entered in the terminal where x11vnc is running.
.IP
By default the remote ssh will issue a 'sleep 300' to
wait for the incoming connection for 5 mins. To modify
this use user@host:disp+secs.
.IP
If the remote SSH server is on a non-standard port
(i.e. not 22) use user@host:port:disp+secs.
.IP
Note that the ssh process may NOT be killed when
x11vnc exits. It tries by looking at
.IR ps (1)
output.
.PP
\fB-usepw\fR
.IP
If no other password method was supplied on the command
@ -1912,7 +2023,7 @@ RFB_CLIENT_ID, and the number of other connected clients
in RFB_CLIENT_COUNT. RFB_MODE will be "accept".
RFB_STATE will be PROTOCOL_VERSION, SECURITY_TYPE,
AUTHENTICATION, INITIALISATION, NORMAL, or UNKNOWN
indicating up to which state the client has acheived.
indicating up to which state the client has achieved.
RFB_LOGIN_VIEWONLY will be 0, 1, or -1 (unknown).
RFB_USERNAME, RFB_LOGIN_TIME, and RFB_CURRENT_TIME may
also be set.
@ -3406,7 +3517,7 @@ are moving the mouse or typing. Default: 2.00
Do not detect if the screen polling is "bogging down"
and sleep more. Some activities with no user input can
slow things down a lot: consider a large terminal window
with a long build running in it continously streaming
with a long build running in it continuously streaming
text output. By default x11vnc will try to detect this
(3 screen polls in a row each longer than 0.25 sec with
no user input), and sleep up to 1.5 secs to let things
@ -3672,7 +3783,7 @@ determining WxHxB, etc. These are often done as root
so take care.
.IP
If the string begins with "video", see the VIDEO4LINUX
discusion below where the device may be queried for
discussion below where the device may be queried for
(and possibly set) the framebuffer parameters.
.IP
If the string begins with "console", "/dev/fb", or
@ -4319,13 +4430,13 @@ deny deny any new connections, same as "lock"
.IP
nodeny allow new connections, same as "unlock"
.IP
avahi enable avahi service advertizing.
avahi enable avahi service advertising.
.IP
noavahi disable avahi service advertizing.
noavahi disable avahi service advertising.
.IP
mdns enable avahi service advertizing.
mdns enable avahi service advertising.
.IP
nomdns disable avahi service advertizing.
nomdns disable avahi service advertising.
.IP
connect:host do reverse connection to host, "host"
may be a comma separated list of hosts
@ -4340,6 +4451,9 @@ If you know the client internal hex ID,
e.g. 0x3 (returned by "\fB-query\fR \fIclients\fR"
and RFB_CLIENT_ID) you can use that too.
.IP
proxy:host:port set reverse connection proxy (empty to
disable).
.IP
allowonce:host For the next connection only, allow
connection from "host".
.IP
@ -4578,6 +4692,10 @@ ncache_no_dtchange enable ncache_no_dtchange mode.
.IP
noncache_no_dtchange disable ncache_no_dtchange mode.
.IP
ncache_old_wm enable ncache_old_wm mode.
.IP
noncache_old_wm disable ncache_old_wm mode.
.IP
ncache_no_rootpixmap enable ncache_no_rootpixmap.
.IP
noncache_no_rootpixmap disable ncache_no_rootpixmap.
@ -4588,6 +4706,8 @@ ncache_keep_anims enable ncache_keep_anims.
.IP
noncache_keep_anims disable ncache_keep_anims.
.IP
ncache_pad:n set \fB-ncache_pad\fR to n.
.IP
wireframe enable \fB-wireframe\fR mode. same as "wf"
.IP
nowireframe disable \fB-wireframe\fR mode. same as "nowf"
@ -4873,8 +4993,8 @@ nooverlay_yescursor overlay_nocursor 8to24 no8to24
8to24_opts 24to32 no24to32 visual scale scale_cursor
viewonly noviewonly shared noshared forever noforever
once timeout tightfilexfer notightfilexfer ultrafilexfer
noultrafilexfer rfbversion deny lock nodeny unlock
avahi mdns noavahi nomdns connect allowonce allow
noultrafilexfer rfbversion deny lock nodeny unlock avahi
mdns noavahi nomdns connect proxy allowonce allow
localhost nolocalhost listen lookup nolookup accept
afteraccept gone shm noshm flipbyteorder noflipbyteorder
onetile noonetile solid_color solid nosolid blackout
@ -4896,12 +5016,12 @@ xwarp noxwarppointer noxwarp buttonmap dragging
nodragging ncache_cr noncache_cr ncache_no_moveraise
noncache_no_moveraise ncache_no_dtchange
noncache_no_dtchange ncache_no_rootpixmap
noncache_no_rootpixmap ncache_reset_rootpixmap
noncache_no_rootpixmap ncache_reset_rootpixmap ncrp
ncache_keep_anims noncache_keep_anims ncache_old_wm
noncache_old_wm ncache noncache ncache_size debug_ncache
nodebug_ncache wireframe_mode wireframe wf nowireframe
nowf wireframelocal wfl nowireframelocal nowfl
wirecopyrect wcr nowirecopyrect nowcr scr_area
noncache_old_wm ncache_pad ncache noncache ncache_size
debug_ncache nodebug_ncache wireframe_mode wireframe wf
nowireframe nowf wireframelocal wfl nowireframelocal
nowfl wirecopyrect wcr nowirecopyrect nowcr scr_area
scr_skip scr_inc scr_keys scr_term scr_keyrepeat
scr_parms scrollcopyrect scr noscrollcopyrect noscr
fixscreen noxrecord xrecord reset_record pointer_mode
@ -4969,7 +5089,7 @@ This allows for a reliable way to see if the \fB-remote\fR
command was processed by querying for any new settings.
Note however that there is timeout of a few seconds so
if the x11vnc takes longer than that to process the
requests the requestor will think that a failure has
requests the requester will think that a failure has
taken place.
.PP
\fB-noremote,\fR \fB-yesremote\fR
@ -5037,7 +5157,7 @@ external commands that can be run. The full list of
associated options is:
.IP
stunnel, ssl, unixpw, WAIT, id, accept, afteraccept,
gone, pipeinput, v4l-info, rawfb-setup, dt, gui,
gone, pipeinput, v4l-info, rawfb-setup, dt, gui, ssh,
storepasswd, passwdfile, custom_passwd, crash.
.IP
See each option's help to learn the associated external

@ -398,6 +398,7 @@ static int tsdo_timeout_flag;
static void tsdo_timeout (int sig) {
tsdo_timeout_flag = 1;
if (sig) {};
}
#define TASKMAX 32
@ -474,6 +475,7 @@ int tsdo(int port, int lsock, int *conn) {
raw_xfer(rsock, csock, csock);
exit(0);
}
return 0;
}
void set_redir_properties(void);
@ -570,7 +572,7 @@ void terminal_services(char *list) {
for (i=0; i<n; i++) {
atom[i] = XInternAtom(dpy, tag[i], False);
if (db) fprintf(stderr, "tag: %s atom: %d\n", tag[i], atom[i]);
if (db) fprintf(stderr, "tag: %s atom: %d\n", tag[i], (int) atom[i]);
if (atom[i] == None) {
continue;
}
@ -897,7 +899,7 @@ void check_redir_services(void) {
Atom a;
char prop[513];
time_t tsd_last;
int i, restart = 0;
int restart = 0;
pid_t pid = 0;
if (! dpy) {
@ -962,6 +964,130 @@ void check_redir_services(void) {
#endif
}
void ssh_remote_tunnel(char *instr, int lport) {
char *p, *q, *cmd, *ssh;
char *s = strdup(instr);
int sleep = 300, disp = 0, sport = 0;
int rc, len, rport;
/* user@host:port:disp+secs */
/* +sleep */
q = strrchr(s, '+');
if (q) {
sleep = atoi(q+1);
if (sleep <= 0) {
sleep = 1;
}
*q = '\0';
}
/* :disp */
q = strrchr(s, ':');
if (q) {
disp = atoi(q+1);
*q = '\0';
}
/* :sshport */
q = strrchr(s, ':');
if (q) {
sport = atoi(q+1);
*q = '\0';
}
if (getenv("SSH")) {
ssh = getenv("SSH");
} else {
ssh = "ssh";
}
len = 0;
len += strlen(ssh) + strlen(s) + 500;
cmd = (char *) malloc(len);
if (disp >= 0 && disp <= 200) {
rport = disp + 5900;
} else if (disp < 0) {
rport = -disp;
} else {
rport = disp;
}
if (sport > 0) {
sprintf(cmd, "%s -f -p %d -R '%d:localhost:%d' '%s' 'sleep %d'", ssh, sport, rport, lport, s, sleep);
} else {
sprintf(cmd, "%s -f -R '%d:localhost:%d' '%s' 'sleep %d'", ssh, rport, lport, s, sleep);
}
if (no_external_cmds || !cmd_ok("ssh")) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", cmd);
rfbLog(" exiting.\n");
clean_up_exit(1);
}
close_exec_fds();
fprintf(stderr, "\n");
rfbLog("running: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
free(cmd);
free(s);
rfbLog("ssh remote listen failed.\n");
clean_up_exit(1);
}
if (1) {
FILE *pipe;
int mypid = (int) getpid();
int bestpid = -1;
int best = -1;
char line[1024];
char *ps = "ps -ef";
/* not portable... but it is really good to terminate the ssh when done. */
/* ps -ef | egrep 'ssh2.*-R.*5907:localhost:5900.*runge@celias.lbl.gov.*sleep 300' | grep -v grep | awk '{print $2}' */
if (strstr(UT.sysname, "Linux")) {
ps = "ps wwwwwaux";
} else if (strstr(UT.sysname, "BSD")) {
ps = "ps wwwwwaux";
}
sprintf(cmd, "env COLUMNS=256 %s | egrep '%s.*-R *%d:localhost:%d.*%s.*sleep *%d' | grep -v grep | awk '{print $2}'", ps, ssh, rport, lport, s, sleep);
pipe = popen(cmd, "r");
if (pipe) {
while (fgets(line, 1024, pipe) != NULL) {
int p = atoi(line);
if (p > 0) {
int score;
if (p > mypid) {
score = p - mypid;
} else {
score = p - mypid + 32768;
if (score < 0) {
score = 32768;
}
}
if (best < 0 || score < best) {
best = score;
bestpid = p;
}
}
}
pclose(pipe);
}
if (bestpid != -1) {
ssh_pid = (pid_t) bestpid;
rfbLog("guessed ssh pid=%d, will terminate it on exit.\n", bestpid);
}
}
free(cmd);
free(s);
}
void check_filexfer(void) {
static time_t last_check = 0;
rfbClientIteratorPtr iter;
@ -2463,6 +2589,9 @@ int main(int argc, char* argv[]) {
if (!strcmp(arg, "-connect_or_exit")) {
connect_or_exit = 1;
}
} else if (!strcmp(arg, "-proxy")) {
CHECK_ARGC
connect_proxy = strdup(argv[++i]);
} else if (!strcmp(arg, "-vncconnect")) {
vnc_connect = 1;
} else if (!strcmp(arg, "-novncconnect")) {
@ -2672,6 +2801,9 @@ int main(int argc, char* argv[]) {
#endif
} else if (!strcmp(arg, "-nopw")) {
nopw = 1;
} else if (!strcmp(arg, "-ssh")) {
CHECK_ARGC
ssh_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-usepw")) {
usepw = 1;
} else if (!strcmp(arg, "-storepasswd")) {
@ -3670,7 +3802,7 @@ int main(int argc, char* argv[]) {
if (! s) s = getenv("SSH_CLIENT");
if (! s) s = "SSH_CONNECTION";
fprintf(stderr, "\n");
rfbLog("Skipping -ssl/-stunnel contraint in"
rfbLog("Skipping -ssl/-stunnel constraint in"
" -unixpw\n");
rfbLog("mode, assuming your SSH encryption"
" is: %s\n", s);
@ -4568,6 +4700,9 @@ if (0) fprintf(stderr, "XA: %s\n", getenv("XAUTHORITY"));
if (try_http && ! got_httpdir && check_httpdir()) {
http_connections(1);
}
if (ssh_str != NULL) {
ssh_remote_tunnel(ssh_str, screen->port);
}
}
initialize_tiles();

@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.3 lastmod: 2007-09-30";
char lastmod[] = "0.9.4 lastmod: 2007-10-27";
/* X display info */

@ -633,6 +633,7 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
scr_attr_cache[i].y = attr.y;
scr_attr_cache[i].width = attr.width;
scr_attr_cache[i].height = attr.height;
scr_attr_cache[i].border_width = attr.border_width;
scr_attr_cache[i].depth = attr.depth;
scr_attr_cache[i].class = attr.class;
scr_attr_cache[i].backing_store =

Loading…
Cancel
Save