summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorrunge <runge>2004-05-22 03:30:31 +0000
committerrunge <runge>2004-05-22 03:30:31 +0000
commit0130bdb9d6c61e0446ab514816041f1b9283410a (patch)
tree58699f5088c885a8487da5017b5e37a4f7bb0a6a /contrib
parentdd26262a369b8da6b612017a6095882ca4469816 (diff)
downloadlibtdevnc-0130bdb9d6c61e0446ab514816041f1b9283410a.tar.gz
libtdevnc-0130bdb9d6c61e0446ab514816041f1b9283410a.zip
x11vnc: -gone, -passwdfile, -o logfile; add view-only to -accept
Diffstat (limited to 'contrib')
-rw-r--r--contrib/ChangeLog7
-rw-r--r--contrib/x11vnc.c707
2 files changed, 577 insertions, 137 deletions
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index 04d6575..9e468f6 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,10 @@
+2004-05-21 Karl Runge <runge@karlrunge.com>
+ * -accept: add view-only decision and other improvements.
+ * add -gone command option for when a client leaves.
+ Thanks to Jesus Alvarez for these ideas.
+ * -passwdfile to keep passwd off of cmd line.
+ * -o logfile send stderr to a logfile.
+
2004-05-14 Karl Runge <runge@karlrunge.com>
* improvements to -accept popup: yes/no buttons and timeout.
* less fprintf under -q so '-q -inetd' has no stderr output.
diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c
index d1543ce..144b280 100644
--- a/contrib/x11vnc.c
+++ b/contrib/x11vnc.c
@@ -131,7 +131,7 @@
#endif
/* date +'"lastmod: %Y-%m-%d";' */
-char lastmod[] = "lastmod: 2004-05-14";
+char lastmod[] = "lastmod: 2004-05-21";
/* X and rfb framebuffer */
@@ -207,6 +207,7 @@ hint_t *hint_list;
int shared = 0; /* share vnc display. */
char *allow_list = NULL; /* for -allow and -localhost */
char *accept_cmd = NULL; /* for -accept */
+char *gone_cmd = NULL; /* for -gone */
int view_only = 0; /* clients can only watch. */
int inetd = 0; /* spawned from inetd(1) */
int connect_once = 1; /* disconnect after first connection session. */
@@ -353,6 +354,7 @@ void clean_up_exit (int ret) {
XTestDiscard(dpy);
X_UNLOCK;
+ fflush(stderr);
exit(ret);
}
@@ -437,12 +439,19 @@ void set_signals(void) {
X_UNLOCK;
}
+int run_user_command(char *, rfbClientPtr);
+
int accepted_client = 0;
void client_gone(rfbClientPtr client) {
client_count--;
rfbLog("client_count: %d\n", client_count);
+ if (gone_cmd) {
+ rfbLog("client_gone: using cmd for: %s\n", client->host);
+ run_user_command(gone_cmd, client);
+ }
+
if (inetd) {
rfbLog("viewer exited.\n");
clean_up_exit(0);
@@ -506,7 +515,7 @@ int check_access(char *addr) {
* We go through this pain to avoid dependency on libXt.
*/
-int ugly_accept_window(char *addr, int timeout) {
+int ugly_accept_window(char *addr, int X, int Y, int timeout, char *mode) {
#define t2x2_width 16
#define t2x2_height 16
@@ -534,22 +543,62 @@ static char t2x2_bits[] = {
double waited = 0.0;
/* strings and geometries y/n */
- KeyCode key_y, key_n;
- char str1[100];
- char str2[] = "To accept: press \"y\" or click the \"Yes\" button";
- char str3[] = "To reject: press \"n\" or click the \"No\" button";
- char str4[] = "Yes";
- char str5[] = "No";
- int x, y, w = 345, h = 125, ret = 0;
+ KeyCode key_y, key_n, key_v;
+ char strh[100];
+ char str1_b[] = "To accept: press \"y\" or click the \"Yes\" button";
+ char str2_b[] = "To reject: press \"n\" or click the \"No\" button";
+ char str3_b[] = "View only: press \"v\" or click the \"View\" button";
+ char str1_m[] = "To accept: click the \"Yes\" button";
+ char str2_m[] = "To reject: click the \"No\" button";
+ char str3_m[] = "View only: click the \"View\" button";
+ char str1_k[] = "To accept: press \"y\"";
+ char str2_k[] = "To reject: press \"n\"";
+ char str3_k[] = "View only: press \"v\"";
+ char *str1, *str2, *str3;
+ char str_y[] = "Yes";
+ char str_n[] = "No";
+ char str_v[] = "View";
+ int x, y, w = 345, h = 150, ret = 0;
int X_sh = 20, Y_sh = 30, dY = 20;
- int Ye_x = 20, Ye_y = 0, Ye_w = 40, Ye_h = 20;
- int No_x = 70, No_y = 0, No_w = 40, No_h = 20;
-
+ int Ye_x = 20, Ye_y = 0, Ye_w = 45, Ye_h = 20;
+ int No_x = 75, No_y = 0, No_w = 45, No_h = 20;
+ int Vi_x = 130, Vi_y = 0, Vi_w = 45, Vi_h = 20;
+
+ if (!strcmp(mode, "mouse_only")) {
+ str1 = str1_m;
+ str2 = str2_m;
+ str3 = str3_m;
+ } else if (!strcmp(mode, "key_only")) {
+ str1 = str1_k;
+ str2 = str2_k;
+ str3 = str3_k;
+ h -= dY;
+ } else {
+ str1 = str1_b;
+ str2 = str2_b;
+ str3 = str3_b;
+ }
+ if (view_only) {
+ h -= dY;
+ }
- x = (dpy_x - w)/2;
- y = (dpy_y - h)/2;
- if (x < 0) x = 0;
- if (y < 0) y = 0;
+ if (X < -dpy_x) {
+ x = (dpy_x - w)/2; /* large negative: center */
+ if (x < 0) x = 0;
+ } else if (X < 0) {
+ x = dpy_x + X - w; /* from lower right */
+ } else {
+ x = X; /* from upper left */
+ }
+
+ if (Y < -dpy_y) {
+ y = (dpy_y - h)/2;
+ if (y < 0) y = 0;
+ } else if (Y < 0) {
+ y = dpy_y + Y - h;
+ } else {
+ y = Y;
+ }
X_LOCK;
@@ -593,12 +642,13 @@ static char t2x2_bits[] = {
XMapWindow(dpy, awin);
XFlush(dpy);
- sprintf(str1, "x11vnc: accept connection from %s?", addr);
+ sprintf(strh, "x11vnc: accept connection from %s?", addr);
key_y = XKeysymToKeycode(dpy, XStringToKeysym("y"));
key_n = XKeysymToKeycode(dpy, XStringToKeysym("n"));
+ key_v = XKeysymToKeycode(dpy, XStringToKeysym("v"));
while (1) {
- int out = -1, l1, l2, l3, l4, l5, x, y, tw;
+ int out = -1, x, y, tw, k;
if (XCheckWindowEvent(dpy, awin, evmask, &ev)) {
; /* proceed to handling */
@@ -623,29 +673,55 @@ static char t2x2_bits[] = {
while (XCheckTypedEvent(dpy, Expose, &ev)) {
;
}
- l1 = strlen(str1); l2 = strlen(str2);
- l3 = strlen(str3); l4 = strlen(str4); l5 = strlen(str5);
+ k=0;
+
+ /* instructions */
+ XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
+ strh, strlen(strh));
+ XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
+ str1, strlen(str1));
+ XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
+ str2, strlen(str2));
+ if (! view_only) {
+ XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
+ str3, strlen(str3));
+ }
- XDrawString(dpy, awin, gc, X_sh, Y_sh+0*dY, str1, l1);
- XDrawString(dpy, awin, gc, X_sh, Y_sh+1*dY, str2, l2);
- XDrawString(dpy, awin, gc, X_sh, Y_sh+2*dY, str3, l3);
+ if (!strcmp(mode, "key_only")) {
+ break;
+ }
- Ye_y = Y_sh+3*dY;
- No_y = Y_sh+3*dY;
+ /* buttons */
+ Ye_y = Y_sh+k*dY;
+ No_y = Y_sh+k*dY;
+ Vi_y = Y_sh+k*dY;
XDrawRectangle(dpy, awin, gc, Ye_x, Ye_y, Ye_w, Ye_h);
XDrawRectangle(dpy, awin, gc, No_x, No_y, No_w, No_h);
+ if (! view_only) {
+ XDrawRectangle(dpy, awin, gc, Vi_x, Vi_y,
+ Vi_w, Vi_h);
+ }
- tw = XTextWidth(font_info, str4, l4);
+ tw = XTextWidth(font_info, str_y, strlen(str_y));
tw = (Ye_w - tw)/2;
if (tw < 0) tw = 1;
XDrawString(dpy, awin, gc, Ye_x+tw, Ye_y+Ye_h-5,
- str4, l4);
+ str_y, strlen(str_y));
- tw = XTextWidth(font_info, str5, l5);
+ tw = XTextWidth(font_info, str_n, strlen(str_n));
tw = (No_w - tw)/2;
if (tw < 0) tw = 1;
XDrawString(dpy, awin, gc, No_x+tw, No_y+No_h-5,
- str5, l5);
+ str_n, strlen(str_n));
+
+ if (! view_only) {
+ tw = XTextWidth(font_info, str_v,
+ strlen(str_v));
+ tw = (Vi_w - tw)/2;
+ if (tw < 0) tw = 1;
+ XDrawString(dpy, awin, gc, Vi_x+tw, Vi_y+Vi_h-5,
+ str_v, strlen(str_v));
+ }
break;
@@ -659,20 +735,29 @@ static char t2x2_bits[] = {
case ButtonPress:
x = ev.xbutton.x;
y = ev.xbutton.y;
- if (x > No_x && x < No_x+No_w && y > No_y
+ if (!strcmp(mode, "key_only")) {
+ ;
+ } else if (x > No_x && x < No_x+No_w && y > No_y
&& y < No_y+No_h) {
out = 0;
} else if (x > Ye_x && x < Ye_x+Ye_w && y > Ye_y
&& y < Ye_y+Ye_h) {
out = 1;
+ } else if (! view_only && x > Vi_x && x < Vi_x+Vi_w
+ && y > Vi_y && y < Vi_y+Ye_h) {
+ out = 2;
}
break;
case KeyPress:
- if (ev.xkey.keycode == key_y) {
+ if (!strcmp(mode, "mouse_only")) {
+ ;
+ } else if (ev.xkey.keycode == key_y) {
out = 1;
} else if (ev.xkey.keycode == key_n) {
out = 0;
+ } else if (! view_only && ev.xkey.keycode == key_v) {
+ out = 2;
}
break;
default:
@@ -693,12 +778,172 @@ static char t2x2_bits[] = {
}
/*
+ * utility to run a user supplied command setting some RFB_ env vars.
+ * used by, e.g., accept_client() and client_gone()
+ */
+int run_user_command(char *cmd, rfbClientPtr client) {
+ char *dpystr = DisplayString(dpy);
+ static char *display_env = NULL;
+ static char env_rfb_client_id[100];
+ static char env_rfb_client_ip[100];
+ static char env_rfb_client_port[100];
+ static char env_rfb_x11vnc_pid[100];
+ char *addr = client->host;
+ int rc, fromlen, fromport;
+ struct sockaddr_in from;
+
+ if (addr == NULL || addr[0] == '\0') {
+ addr = "unknown-host";
+ }
+
+ /* set RFB_CLIENT_ID to semi unique id for command to use */
+ sprintf(env_rfb_client_id, "RFB_CLIENT_ID=%d", (int) client);
+ putenv(env_rfb_client_id);
+
+ /* set RFB_CLIENT_IP to IP addr for command to use */
+ sprintf(env_rfb_client_ip, "RFB_CLIENT_IP=%s", addr);
+ putenv(env_rfb_client_ip);
+
+ /* set RFB_X11VNC_PID to our pid for command to use */
+ sprintf(env_rfb_x11vnc_pid, "RFB_X11VNC_PID=%d", (int) getpid());
+ putenv(env_rfb_x11vnc_pid);
+
+ /* set RFB_CLIENT_PORT to peer port for command to use */
+ fromlen = sizeof(from);
+ memset(&from, 0, sizeof(from));
+ fromport = -1;
+ if (!getpeername(client->sock, (struct sockaddr *)&from, &fromlen)) {
+ fromport = ntohs(from.sin_port);
+ }
+ sprintf(env_rfb_client_port, "RFB_CLIENT_PORT=%d", fromport);
+ putenv(env_rfb_client_port);
+
+ /*
+ * Better set DISPLAY to the one we are polling, if they
+ * want something trickier, they can handle on their own
+ * via environment, etc. XXX really should save/restore old.
+ */
+ if (display_env == NULL) {
+ display_env = (char *) malloc(strlen(dpystr)+10);
+ }
+ sprintf(display_env, "DISPLAY=%s", dpystr);
+ putenv(display_env);
+
+ rfbLog("running command:\n");
+ rfbLog(" %s\n", cmd);
+
+ rc = system(cmd);
+
+ if (rc >= 256) {
+ rc = rc/256;
+ }
+ rfbLog("command returned: %d\n", rc);
+
+ sprintf(env_rfb_client_id, "RFB_CLIENT_ID=");
+ putenv(env_rfb_client_id);
+
+ sprintf(env_rfb_client_ip, "RFB_CLIENT_IP=");
+ putenv(env_rfb_client_ip);
+
+ sprintf(env_rfb_client_port, "RFB_CLIENT_PORT=");
+ putenv(env_rfb_client_port);
+
+ sprintf(env_rfb_x11vnc_pid, "RFB_X11VNC_PID=");
+ putenv(env_rfb_x11vnc_pid);
+
+ return rc;
+}
+
+/*
+ * process a "yes:0,no:*,view:3" type action list comparing to command
+ * return code rc. * means the default action with no other match.
+ */
+int action_match(char *action, int rc) {
+ char *p, *q, *s = strdup(action);
+ int cases[4], i, result;
+ char *labels[4];
+
+ labels[1] = "yes";
+ labels[2] = "no";
+ labels[3] = "view";
+
+ rfbLog("accept_client: process action line: %s\n",
+ action);
+
+ for (i=1; i <= 3; i++) {
+ cases[i] = -2;
+ }
+
+ p = strtok(s, ",");
+ while (p) {
+ if ((q = strchr(p, ':')) != NULL) {
+ int in, k;
+ *q = '\0';
+ q++;
+ if (strstr(p, "yes") == p) {
+ k = 1;
+ } else if (strstr(p, "no") == p) {
+ k = 2;
+ } else if (strstr(p, "view") == p) {
+ k = 3;
+ } else {
+ rfbLog("bad action line: %s\n", action);
+ clean_up_exit(1);
+ }
+ if (*q == '*') {
+ cases[k] = -1;
+ } else if (sscanf(q, "%d", &in) == 1) {
+ if (in < 0) {
+ rfbLog("bad action line: %s\n", action);
+ clean_up_exit(1);
+ }
+ cases[k] = in;
+ } else {
+ rfbLog("bad action line: %s\n", action);
+ clean_up_exit(1);
+ }
+ } else {
+ rfbLog("bad action line: %s\n", action);
+ clean_up_exit(1);
+ }
+ p = strtok(NULL, ",");
+ }
+ free(s);
+
+ result = -1;
+ for (i=1; i <= 3; i++) {
+ if (cases[i] == -1) {
+ rfbLog("accept_client: default action is case=%d %s\n",
+ i, labels[i]);
+ result = i;
+ break;
+ }
+ }
+ if (result == -1) {
+ rfbLog("accept_client: no default action\n");
+ }
+ for (i=1; i <= 3; i++) {
+ if (cases[i] >= 0 && cases[i] == rc) {
+ rfbLog("accept_client: matched action is case=%d %s\n",
+ i, labels[i]);
+ result = i;
+ break;
+ }
+ }
+ if (result < 0) {
+ rfbLog("no action match: %s rc=%d set to no\n", action, rc);
+ result = 2;
+ }
+ return result;
+}
+
+/*
* Simple routine to prompt the user on the X display whether an incoming
* client should be allowed to connect or not. If a gui is involved it
* will be running in the environment/context of the X11 DISPLAY.
*
* The command supplied via -accept is run as is (i.e. no string
- * substitution) with the RFB_CLIENT environment variable set to the
+ * substitution) with the RFB_CLIENT_IP environment variable set to the
* incoming client's numerical IP address.
*
* If the external command exits with 0 the client is accepted, otherwise
@@ -710,9 +955,11 @@ static char t2x2_bits[] = {
* popup: use internal X widgets for prompting.
*
*/
-int accept_client(char *addr) {
+int accept_client(rfbClientPtr client) {
+
char xmessage[200], *cmd = NULL;
- static char rfb_client_env[100], *display_env = NULL;
+ char *addr = client->host;
+ char *action = NULL;
if (accept_cmd == NULL) {
return 1; /* no command specified, so we accept */
@@ -722,63 +969,131 @@ int accept_client(char *addr) {
addr = "unknown-host";
}
- if (!strcmp(accept_cmd, "xmessage")) {
- /* make our own command using xmessage(1) */
- sprintf(xmessage, "xmessage -buttons yes:0,no:2 -center "
- "'x11vnc: accept connection from %s?'", addr);
- cmd = xmessage;
-
- } else if (strstr(accept_cmd, "popup:") == accept_cmd ||
- !strcmp(accept_cmd, "popup")) {
- int timeout = 120;
- char *p;
+ if (strstr(accept_cmd, "popup") == accept_cmd) {
+ /* use our builtin popup button */
+
+ /* (popup|popupkey|popupmouse)[+-X+-Y][:timeout] */
+
+ int ret, timeout = 120;
+ int x = -64000, y = -64000;
+ char *p, *mode;
+
+ /* extract timeout */
if ((p = strchr(accept_cmd, ':')) != NULL) {
int in;
if (sscanf(p+1, "%d", &in) == 1) {
timeout = in;
}
}
+ /* extract geometry */
+ if ((p = strpbrk(accept_cmd, "+-")) != NULL) {
+ int x1, y1;
+ if (sscanf(p, "+%d+%d", &x1, &y1) == 2) {
+ x = x1;
+ y = y1;
+ } else if (sscanf(p, "+%d-%d", &x1, &y1) == 2) {
+ x = x1;
+ y = -y1;
+ } else if (sscanf(p, "-%d+%d", &x1, &y1) == 2) {
+ x = -x1;
+ y = y1;
+ } else if (sscanf(p, "-%d-%d", &x1, &y1) == 2) {
+ x = -x1;
+ y = -y1;
+ }
+ }
+
+ /* find mode: mouse, key, or both */
+ if (strstr(accept_cmd, "popupmouse") == accept_cmd) {
+ mode = "mouse_only";
+ } else if (strstr(accept_cmd, "popupkey") == accept_cmd) {
+ mode = "key_only";
+ } else {
+ mode = "both";
+ }
+
rfbLog("accept_client: using builtin popup for: %s\n", addr);
- if (ugly_accept_window(addr, timeout)) {
+ if ((ret = ugly_accept_window(addr, x, y, timeout, mode))) {
+ if (ret == 2) {
+ rfbLog("accept_client: viewonly: %s\n", addr);
+ client->viewOnly = TRUE;
+ }
rfbLog("accept_client: popup accepted: %s\n", addr);
return 1;
} else {
rfbLog("accept_client: popup rejected: %s\n", addr);
return 0;
}
+
+ } else if (!strcmp(accept_cmd, "xmessage")) {
+ /* make our own command using xmessage(1) */
+
+ if (view_only) {
+ sprintf(xmessage, "xmessage -buttons yes:0,no:2 -center"
+ " 'x11vnc: accept connection from %s?'", addr);
+ } else {
+ sprintf(xmessage, "xmessage -buttons yes:0,no:2,"
+ "view-only:3 -center" " 'x11vnc: accept connection"
+ " from %s?'", addr);
+ action = "yes:0,no:*,view:3";
+ }
+ cmd = xmessage;
+
} else {
+ /* use the user supplied command: */
+
cmd = accept_cmd;
+
+ /* extract any action prefix: yes:N,no:M,view:K */
+ if (strstr(accept_cmd, "yes:") == accept_cmd) {
+ char *p;
+ if ((p = strpbrk(accept_cmd, " \t")) != NULL) {
+ int i;
+ cmd = p;
+ p = accept_cmd;
+ for (i=0; i<200; i++) {
+ if (*p == ' ' || *p == '\t') {
+ xmessage[i] = '\0';
+ break;
+ }
+ xmessage[i] = *p;
+ p++;
+ }
+ xmessage[200-1] = '\0';
+ action = xmessage;
+ }
+ }
}
if (cmd) {
int rc;
- char *dpystr = DisplayString(dpy);
- /* set RFB_CLIENT to IP addr for command to use */
- sprintf(rfb_client_env, "RFB_CLIENT=%s", addr);
- putenv(rfb_client_env);
+ rfbLog("accept_client: using cmd for: %s\n", addr);
+ rc = run_user_command(cmd, client);
- /*
- * Better set DISPLAY to the one we are polling, if they
- * want something trickier, they can handle on their own
- * via environment, etc. XXX really should save/restore old.
- */
- if (display_env == NULL) {
- display_env = (char *) malloc(strlen(dpystr)+10);
- }
- sprintf(display_env, "DISPLAY=%s", dpystr);
- putenv(display_env);
+ if (action) {
+ int result;
- rfbLog("accept_client: running command:\n");
- rfbLog(" %s\n", cmd);
- rc = system(cmd);
- if (rc >= 256) {
- rc = rc/256;
- }
- rfbLog("accept_client: command returned: %d\n", rc);
+ if (rc < 0) {
+ rfbLog("accept_client: cannot use negative "
+ "rc: %d, action %s\n", rc, action);
+ result = 2;
+ } else {
+ result = action_match(action, rc);
+ }
- sprintf(rfb_client_env, "RFB_CLIENT=");
- putenv(rfb_client_env);
+ if (result == 1) {
+ rc = 0;
+ } else if (result == 2) {
+ rc = 1;
+ } else if (result == 3) {
+ rc = 0;
+ rfbLog("accept_client: viewonly: %s\n", addr);
+ client->viewOnly = TRUE;
+ } else {
+ rc = 1; /* NOTREACHED */
+ }
+ }
if (rc == 0) {
rfbLog("accept_client: accepted: %s\n", addr);
@@ -1014,7 +1329,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
allow_list ? allow_list : "(null)" );
return(RFB_CLIENT_REFUSE);
}
- if (! accept_client(client->host)) {
+ if (! accept_client(client)) {
rfbLog("denying client: %s local user rejected connection.\n",
client->host);
rfbLog("denying client: accept_cmd=\"%s\"\n",
@@ -1024,6 +1339,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
if (view_only) {
client->clientData = (void *) -1;
+ client->viewOnly = TRUE;
} else {
client->clientData = (void *) 0;
}
@@ -1262,7 +1578,8 @@ void tweak_mod(signed char mod, rfbBool down) {
}
}
-static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
+static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
+ rfbClientPtr client) {
KeyCode k;
int tweak = 0;
if (debug_keyboard) {
@@ -1273,6 +1590,9 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr
if (view_only) {
return;
}
+ if (client->viewOnly) {
+ return;
+ }
#define ADJUSTMOD(sym, state) \
if (keysym == sym) { \
@@ -1333,6 +1653,9 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
if (view_only) {
return;
}
+ if (client->viewOnly) {
+ return;
+ }
last_keyboard_client = client;
if (keyremaps) {
@@ -1669,7 +1992,9 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) {
if (view_only) {
return;
}
-
+ if (client->viewOnly) {
+ return;
+ }
if (mask >= 0) {
/*
@@ -2376,6 +2701,9 @@ void watch_xevents() {
*/
void xcut_receive(char *text, int len, rfbClientPtr cl) {
+ if (cl->viewOnly) {
+ return;
+ }
if (text == NULL || len == 0) {
return;
}
@@ -5419,7 +5747,7 @@ void print_help() {
"Once x11vnc establishes connections with the X11 server and starts\n"
"listening as a VNC server it will print out a string: PORT=XXXX where\n"
"XXXX is typically 5900 (the default VNC port). One would next run something\n"
-"like this on the local machine: \"vncviewer host:N\" where N is XXXX - 5900.\n"
+"like this on the local machine: \"vncviewer host:N\" where N is XXXX - 5900.\n"
"\n"
"By default x11vnc will not allow the screen to be shared and it will\n"
"exit as soon as a client disconnects. See -shared and -forever below\n"
@@ -5439,68 +5767,113 @@ void print_help() {
" as the pointer moves from window to window (slow).\n"
"-notruecolor Force 8bpp indexed color even if it looks like TrueColor.\n"
"\n"
-"-visual n Experimental option: probably does not do what you think.\n"
-" It simply *forces* the visual used for the framebuffer;\n"
-" this may be a bad thing... It is useful for testing and\n"
-" for some workarounds. n may be a decimal number, or 0x\n"
-" hex. Run xdpyinfo(1) for the values. One may also use\n"
-" \"TrueColor\", etc. see <X11/X.h> for a list. If the\n"
-" string ends in \":m\" the visual depth is forced to be m.\n"
+"-visual n Experimental option: probably does not do what you\n"
+" think. It simply *forces* the visual used for the\n"
+" framebuffer; this may be a bad thing... It is useful for\n"
+" testing and for some workarounds. n may be a decimal\n"
+" number, or 0x hex. Run xdpyinfo(1) for the values.\n"
+" One may also use \"TrueColor\", etc. see <X11/X.h>\n"
+" for a list. If the string ends in \":m\" for better\n"
+" or for worse the visual depth is forced to be m.\n"
"\n"
-"-viewonly Clients can only watch (default %s).\n"
+"-viewonly All clients can only watch (default %s).\n"
"-shared VNC display is shared (default %s).\n"
"-forever Keep listening for more connections rather than exiting\n"
" as soon as the first client(s) disconnect. Same as -many\n"
-"-connect string For use with \"vncviewer -listen\" reverse connections. If\n"
-" string has the form \"host\" or \"host:port\" the connection\n"
-" is made once at startup. Use commas for a list. If string\n"
-" contains \"/\" it is a file to periodically check for new\n"
-" hosts. The first line is read and then file is truncated.\n"
+"-connect string For use with \"vncviewer -listen\" reverse connections.\n"
+" If string has the form \"host\" or \"host:port\"\n"
+" the connection is made once at startup. Use commas\n"
+" for a list. If string contains \"/\" it is a file to\n"
+" periodically check for new hosts. The first line is\n"
+" read and then file is truncated.\n"
"-vncconnect Monitor the VNC_CONNECT X property set by vncconnect(1).\n"
"-auth file Set the X authority file to be \"file\", equivalent to\n"
" setting the XAUTHORITY env. var to \"file\" before startup.\n"
"-allow addr1[,addr2..] Only allow client connections from IP addresses matching\n"
-" the comma separated list of numerical addresses. Can be\n"
-" a prefix, e.g. \"192.168.100.\" to match a simple subnet,\n"
-" for more control build libvncserver with libwrap support.\n"
+" the comma separated list of numerical addresses.\n"
+" Can be a prefix, e.g. \"192.168.100.\" to match a\n"
+" simple subnet, for more control build libvncserver with\n"
+" libwrap support.\n"
"-localhost Same as -allow 127.0.0.1\n"
-"-accept string Prompt user at the X11 display whether an incoming\n"
-" client should be allowed to connect. \"string\" is an\n"
-" external command run via system(3). Be sure to quote\n"
-" \"string\" if it contains spaces, etc. The RFB_CLIENT env.\n"
-" variable will be set to the client's IP number. If the\n"
-" external command returns 0 the client is accepted,\n"
-" otherwise the client is rejected.\n"
+"-passwdfile filename Specify libvncserver -passwd via the first line of file\n"
+" \"filename\" instead of via command line. Note: this\n"
+" is a simple plaintext passwd, see also -rfbauth below.\n"
+"-accept string Run a command (possibly to prompt the user at the\n"
+" X11 display) to decide whether an incoming client\n"
+" should be allowed to connect or not. \"string\" is\n"
+" an external command run via system(3) (see below for\n"
+" special cases). Be sure to quote \"string\" if it\n"
+" contains spaces, etc. The RFB_CLIENT_IP environment\n"
+" variable will be set to the incoming client IP number\n"
+" and the port in RFB_CLIENT_PORT (or -1 if unavailable).\n"
+" The x11vnc process id will be in RFB_X11VNC_PID and a\n"
+" client id number in RFB_CLIENT_ID. If the external\n"
+" command returns 0 the client is accepted, otherwise\n"
+" the client is rejected. See below for an extension to\n"
+" accept a client view-only.\n"
+"\n"
+" If \"string\" is \"popup\" then a builtin popup window\n"
+" is used. The popup will time out after 120 seconds,\n"
+" use \"popup:N\" to modify the timeout to N seconds\n"
+" (use 0 for no timeout)\n"
+"\n"
+" If \"string\" is \"xmessage\" then an xmessage(1)\n"
+" invocation is used for the command.\n"
+"\n"
+" Both \"popup\" and \"xmessage\" will present an option\n"
+" for accepting the client \"View-Only\" (the client\n"
+" can only watch). This option will not be presented if\n"
+" -viewonly has been specified, in which case the entire\n"
+" display is view only.\n"
"\n"
-" If string is \"xmessage\" then an xmessage(1) invocation\n"
-" is used for the command. If string is \"popup\" then a\n"
-" builtin popup window is used. The popup will time out\n"
-" after 120 seconds, use \"popup:N\" to modify the timeout\n"
-" to N seconds (use 0 for no timeout)\n"
+" If the user supplied command is prefixed with something\n"
+" like \"yes:0,no:*,view:3 mycommand ...\" then this\n"
+" associates the numerical command return code with\n"
+" the actions: accept, reject, and accept-view-only,\n"
+" respectively. Use \"*\" instead of a number to indicate\n"
+" the default action (in case the command returns an\n"
+" unexpected value). E.g. \"no:*\" is a good choice.\n"
"\n"
" Note that x11vnc blocks while the external command or\n"
" or popup is running (other clients may see no updates\n"
" during this period).\n"
+"\n"
+" More -accept tricks: use \"popupmouse\" to only allow\n"
+" mouse clicks in the builtin popup to be recognized.\n"
+" Similarly use \"popupkey\" to only recognize keystroke\n"
+" responses. All 3 of the popup keywords can be followed\n"
+" by +N+M to supply a position for the popup window.\n"
+" The default is to center the popup window.\n"
+"\n"
+"-gone string As -accept string, except to run a user supplied command\n"
+" when a client goes away (disconnects). Unlike -accept,\n"
+" the command return code is not interpreted by x11vnc.\n"
+"\n"
"-inetd Launched by inetd(1): stdio instead of listening socket.\n"
" Note: if you are not redirecting stderr to a log file\n"
-" you must also specify -q as the first argument.\n"
+" you must also specify the -q option.\n"
"\n"
"-noshm Do not use the MIT-SHM extension for the polling.\n"
-" remote displays can be polled this way: be careful\n"
-" this can use large amounts of network bandwidth. Also\n"
-" of use if machine has a limited number of shm segments.\n"
+" Remote displays can be polled this way: be careful this\n"
+" can use large amounts of network bandwidth. This is\n"
+" also of use if the local machine has a limited number\n"
+" of shm segments and -onetile is not sufficient.\n"
"-flipbyteorder Sometimes needed if remotely polled host has different\n"
" endianness. Ignored unless -noshm is set.\n"
"-blackout string Black out rectangles on the screen. string is a comma\n"
" separated list of WxH+X+Y type geometries for each rect.\n"
-"-xinerama If your screen is composed of multiple monitors glued\n"
-" together via XINERAMA, and that screen is non-rectangular\n"
-" this option will try to guess the areas to black out.\n"
+"-xinerama If your screen is composed of multiple monitors\n"
+" glued together via XINERAMA, and that screen is\n"
+" non-rectangular this option will try to guess the areas\n"
+" to black out (if your system has libXinerama).\n"
"\n"
-"-q Be quiet by printing less informational output to stderr.\n"
-" Same as -quiet\n"
-"-bg Go into the background after screen setup.\n"
-" Something like this could be useful in a script:\n"
+"-o logfile Write stderr messages to file \"logfile\" instead of\n"
+" to the terminal. Same as -logfile.\n"
+"-q Be quiet by printing less informational output to\n"
+" stderr. Same as -quiet.\n"
+"-bg Go into the background after screen setup. Messages to\n"
+" stderr are lost unless -o logfile is used. Something\n"
+" like this could be useful in a script:\n"
" port=`ssh $host \"x11vnc -display :0 -bg\" | grep PORT`\n"
" port=`echo \"$port\" | sed -e 's/PORT=//'`\n"
" port=`expr $port - 5900`\n"
@@ -5518,7 +5891,8 @@ void print_help() {
"-nofb Ignore framebuffer: only process keyboard and pointer.\n"
"-nosel Do not manage exchange of X selection/cutbuffer.\n"
"-noprimary Do not poll the PRIMARY selection for changes and send\n"
-" back to clients. PRIMARY is set for received changes.\n"
+" back to clients. PRIMARY is still set on received\n"
+" changes, however.\n"
"\n"
"-nocursor Do not have the viewer show a local cursor.\n"
"-mouse Draw a 2nd cursor at the current X pointer position.\n"
@@ -5532,7 +5906,7 @@ void print_help() {
"-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this\n"
" maps buttons I -> L, etc., e.g. -buttonmap 13-31\n"
"\n"
-" Button presses can also be mapped to keysyms: replace\n"
+" Button presses can also be mapped to keystrokes: replace\n"
" a button digit on the right of the dash with :<sym>:\n"
" or :<sym1>+<sym2>: etc. for multiple keys. For example,\n"
" if the viewing machine has a mouse-wheel (buttons 4 5)\n"
@@ -5540,11 +5914,11 @@ void print_help() {
" -buttonmap 12345-123:Prior::Next:\n"
" -buttonmap 12345-123:Up+Up+Up::Down+Down+Down:\n"
"\n"
-" If you include a modifier like \"Shift_L\" the modifier's\n"
-" up/down state is toggled, e.g. to send \"The\" use\n"
-" :Shift_L+t+Shift_L+h+e: (the 1st one is shift down and\n"
-" the 2nd one is shift up). (note: the initial state of\n"
-" the modifier is ignored and not reset)\n"
+" If you include a modifier like \"Shift_L\" the\n"
+" modifier's up/down state is toggled, e.g. to send\n"
+" \"The\" use :Shift_L+t+Shift_L+h+e: (the 1st one is\n"
+" shift down and the 2nd one is shift up). (note: the\n"
+" initial state of the modifier is ignored and not reset)\n"
" To include button events use \"Button1\", ... etc.\n"
"\n"
"-nodragging Do not update the display during mouse dragging events\n"
@@ -5561,17 +5935,17 @@ void print_help() {
"-debug_pointer Print debugging output for every pointer event.\n"
"-debug_keyboard Print debugging output for every keyboard event.\n"
"\n"
-"-defer time Time in ms to wait for updates before sending to\n"
-" client [rfbDeferUpdateTime] (default %d).\n"
-"-wait time Time in ms to pause between screen polls. Used\n"
-" to cut down on load (default %d).\n"
-"-nap Monitor activity and if low take longer naps between\n"
+"-defer time Time in ms to wait for updates before sending to client\n"
+" [rfbDeferUpdateTime] (default %d).\n"
+"-wait time Time in ms to pause between screen polls. Used to cut\n"
+" down on load (default %d).\n"
+"-nap Monitor activity and if low take longer naps between\n"
" polls to really cut down load when idle (default %s).\n"
-"-sigpipe string Broken pipe (SIGPIPE) handling. string can be \"ignore\"\n"
-" or \"exit\", for the 1st libvncserver will handle the\n"
-" abrupt loss of a client and continue, for the 2nd x11vnc\n"
-" will cleanup and exit at the 1st broken connection.\n"
-" Default is \"ignore\".\n"
+"-sigpipe string Broken pipe (SIGPIPE) handling. \"string\" can be\n"
+" \"ignore\" or \"exit\". For \"ignore\" libvncserver\n"
+" will handle the abrupt loss of a client and continue,\n"
+" for \"exit\" x11vnc will cleanup and exit at the 1st\n"
+" broken connection. Default is \"ignore\".\n"
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
"-threads Whether or not to use the threaded libvncserver\n"
"-nothreads algorithm [rfbRunEventLoop] (default %s).\n"
@@ -5582,8 +5956,8 @@ void print_help() {
"-onetile Do not use the new copy_tiles() framebuffer mechanism,\n"
" just use 1 shm tile for polling. Same as -old_copytile.\n"
" Limits shm segments used to 3.\n"
-"-gaps n Heuristic to fill in gaps in rows or cols of n or less\n"
-" tiles. Used to improve text paging (default %d).\n"
+"-gaps n Heuristic to fill in gaps in rows or cols of n or\n"
+" less tiles. Used to improve text paging (default %d).\n"
"-grow n Heuristic to grow islands of changed tiles n or wider\n"
" by checking the tile near the boundary (default %d).\n"
"-fuzz n Tolerance in pixels to mark a tiles edges as changed\n"
@@ -5692,6 +6066,8 @@ int main(int argc, char** argv) {
char *use_dpy = NULL;
char *auth_file = NULL;
char *arg, *visual_str = NULL;
+ char *logfile = NULL;
+ char *passwdfile = NULL;
int pw_loc = -1;
int dt = 0;
int bg = 0;
@@ -5699,7 +6075,7 @@ int main(int argc, char** argv) {
int got_deferupdate = 0, got_defer = 0;
/* used to pass args we do not know about to rfbGetScreen(): */
- int argc2 = 1; char *argv2[100];
+ int argc2 = 1; char *argv2[128];
argv2[0] = strdup(argv[0]);
@@ -5728,6 +6104,8 @@ int main(int argc, char** argv) {
force_indexed_color = 1;
} else if (!strcmp(arg, "-viewonly")) {
view_only = 1;
+ } else if (!strcmp(arg, "-passwdfile")) {
+ passwdfile = argv[++i];
} else if (!strcmp(arg, "-shared")) {
shared = 1;
} else if (!strcmp(arg, "-auth")) {
@@ -5738,6 +6116,8 @@ int main(int argc, char** argv) {
allow_list = "127.0.0.1";
} else if (!strcmp(arg, "-accept")) {
accept_cmd = argv[++i];
+ } else if (!strcmp(arg, "-gone")) {
+ gone_cmd = argv[++i];
} else if (!strcmp(arg, "-many")
|| !strcmp(arg, "-forever")) {
connect_once = 0;
@@ -5845,6 +6225,8 @@ int main(int argc, char** argv) {
} else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")
|| !strcmp(arg, "-?")) {
print_help();
+ } else if (!strcmp(arg, "-o") || !strcmp(arg, "-logfile")) {
+ logfile = argv[++i];
} else if (!strcmp(arg, "-q") || !strcmp(arg, "-quiet")) {
quiet = 1;
#ifdef LIBVNCSERVER_HAVE_SETSID
@@ -5873,16 +6255,39 @@ int main(int argc, char** argv) {
if (!strcmp(arg, "-nevershared")) {
got_nevershared = 1;
}
- /* otherwise copy it for use below. */
- if (!quiet && !inetd && i != pw_loc && i != pw_loc+1) {
- fprintf(stderr, "passing arg to libvncserver: %s\n",
- arg);
- }
+ /* otherwise copy it for libvncserver use below. */
if (argc2 < 100) {
argv2[argc2++] = strdup(arg);
}
}
}
+ if (logfile) {
+ int n;
+ if ((n = open(logfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
+ fprintf(stderr, "error opening logfile: %s\n", logfile);
+ perror("open");
+ exit(1);
+ }
+ if (dup2(n, 2) < 0) {
+ fprintf(stderr, "dup2 failed\n");
+ perror("dup2");
+ exit(1);
+ }
+ if (n > 2) {
+ close(n);
+ }
+ }
+ if (! quiet && ! inetd) {
+ int i;
+ for (i=1; i < argc2; i++) {
+ fprintf(stderr, "passing arg to libvncserver: %s\n",
+ argv2[i]);
+ if (!strcmp(argv2[i], "-passwd")) {
+ i++;
+ }
+ }
+ }
+
/*
* If -passwd was used, clear it out of argv. This does not
@@ -5899,6 +6304,26 @@ int main(int argc, char** argv) {
*p++ = '\0';
}
}
+ } else if (passwdfile) {
+ char line[512];
+ FILE *in;
+ in = fopen(passwdfile, "r");
+ if (in == NULL) {
+ fprintf(stderr, "cannot open passwdfile: %s\n",
+ passwdfile);
+ perror("fopen");
+ exit(1);
+ }
+ if (fgets(line, 512, in) != NULL) {
+ line[strlen(line)-1] = '\0';
+ argv2[argc2++] = "-passwd";
+ argv2[argc2++] = strdup(line);
+ } else {
+ fprintf(stderr, "cannot read passwdfile: %s\n",
+ passwdfile);
+ perror("fgets");
+ exit(1);
+ }
}
/* fixup settings that do not make sense */
@@ -5968,10 +6393,16 @@ int main(int argc, char** argv) {
fprintf(stderr, "shared: %d\n", shared);
fprintf(stderr, "authfile: %s\n", auth_file ? auth_file
: "null");
+ fprintf(stderr, "passfile: %s\n", passwdfile ? passwdfile
+ : "null");
+ fprintf(stderr, "logfile: %s\n", logfile ? logfile
+ : "null");
fprintf(stderr, "allow: %s\n", allow_list ? allow_list
: "null");
fprintf(stderr, "accept: %s\n", accept_cmd ? accept_cmd
: "null");
+ fprintf(stderr, "gone: %s\n", gone_cmd ? gone_cmd
+ : "null");
fprintf(stderr, "conn_once: %d\n", connect_once);
fprintf(stderr, "connect: %s\n", client_connect
? client_connect : "null");
@@ -6296,7 +6727,9 @@ int main(int argc, char** argv) {
n = open("/dev/null", O_RDONLY);
dup2(n, 0);
dup2(n, 1);
- dup2(n, 2);
+ if (! logfile) {
+ dup2(n, 2);
+ }
if (n > 2) {
close(n);
}