x11vnc: more -unixpw mode. -gone popup mode. Change filexfer via -R. Tune SMALL_FOOTPRINT.

pull/1/head
runge 19 years ago
parent f38f67e4e9
commit b03a920cb9

@ -377,7 +377,7 @@ AC_FUNC_VPRINTF
AC_FUNC_FORK AC_FUNC_FORK
AC_CHECK_LIB(nsl,gethostbyname) AC_CHECK_LIB(nsl,gethostbyname)
AC_CHECK_LIB(socket,socket) AC_CHECK_LIB(socket,socket)
AC_CHECK_FUNCS([ftime gethostbyname gethostname gettimeofday inet_ntoa memmove memset mmap mkfifo select socket strchr strcspn strdup strerror strstr setsid getpwuid getpwnam getuid geteuid setuid seteuid setegid waitpid setutxent grantpt]) AC_CHECK_FUNCS([ftime gethostbyname gethostname gettimeofday inet_ntoa memmove memset mmap mkfifo select socket strchr strcspn strdup strerror strstr setsid setpgrp getpwuid getpwnam getuid geteuid setuid setgid seteuid setegid waitpid setutxent grantpt])
# check, if shmget is in cygipc.a # check, if shmget is in cygipc.a
AC_CHECK_LIB(cygipc,shmget) AC_CHECK_LIB(cygipc,shmget)

@ -12,6 +12,13 @@ void check_for_multivis(void);
void bpp8to24(int, int, int, int); void bpp8to24(int, int, int, int);
void mark_8bpp(int); void mark_8bpp(int);
#if SKIP_8TO24
void check_for_multivis(void) {}
void bpp8to24(int x, int y, int z, int t) {}
void mark_8bpp(int x) {}
#else
/* lots... */
static void set_root_cmap(void); static void set_root_cmap(void);
static int check_pointer_in_depth24(void); static int check_pointer_in_depth24(void);
static void parse_cmap8to24(void); static void parse_cmap8to24(void);
@ -1962,3 +1969,5 @@ if (db24 > 1) fprintf(stderr, "mark_8bpp: 0x%lx %d %d %d %d\n", windows_8bpp[i].
} }
} }
#endif /* SKIP_8TO24 */

@ -1,3 +1,7 @@
2006-03-02 Karl Runge <runge@karlrunge.com>
* x11vnc: more tweaks to -unixpw mode. Add -gone popup mode.
Change filexfer via -R. Tune SMALL_FOOTPRINT. gui fixes.
2006-02-24 Karl Runge <runge@karlrunge.com> 2006-02-24 Karl Runge <runge@karlrunge.com>
* x11vnc: -unixpw for Unix password auth, -stunnel to setup * x11vnc: -unixpw for Unix password auth, -stunnel to setup
stunnel(1) for an SSL tunnel on the server end. Add clipboard stunnel(1) for an SSL tunnel on the server end. Add clipboard

File diff suppressed because it is too large Load Diff

@ -39,10 +39,12 @@ void check_new_clients(void);
static rfbClientPtr *client_match(char *str); static rfbClientPtr *client_match(char *str);
static int run_user_command(char *cmd, rfbClientPtr client, char *mode); static int run_user_command(char *cmd, rfbClientPtr client, char *mode);
static void free_client_data(rfbClientPtr client);
static void client_gone(rfbClientPtr client); static void client_gone(rfbClientPtr client);
static int check_access(char *addr); static int check_access(char *addr);
static int ugly_accept_window(char *addr, char *userhost, int X, int Y, static void ugly_geom(char *p, int *x, int *y);
int timeout, char *mode); static int ugly_window(char *addr, char *userhost, int X, int Y,
int timeout, char *mode, int accept);
static int action_match(char *action, int rc); static int action_match(char *action, int rc);
static int accept_client(rfbClientPtr client); static int accept_client(rfbClientPtr client);
static void check_connect_file(char *file); static void check_connect_file(char *file);
@ -490,6 +492,31 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) {
return rc; return rc;
} }
static void free_client_data(rfbClientPtr client) {
if (! client) {
return;
}
if (client->clientData) {
ClientData *cd = (ClientData *) client->clientData;
if (cd) {
if (cd->server_ip) {
free(cd->server_ip);
cd->server_ip = NULL;
}
if (cd->hostname) {
free(cd->hostname);
cd->hostname = NULL;
}
if (cd->username) {
free(cd->username);
cd->username = NULL;
}
}
free(client->clientData);
client->clientData = NULL;
}
}
static int accepted_client = 0; static int accepted_client = 0;
/* /*
@ -520,30 +547,49 @@ static void client_gone(rfbClientPtr client) {
solid_bg(1); solid_bg(1);
} }
if (gone_cmd && *gone_cmd != '\0') { if (gone_cmd && *gone_cmd != '\0') {
rfbLog("client_gone: using cmd for: %s\n", client->host); ClientData *cd = NULL;
run_user_command(gone_cmd, client, "gone"); if (client->clientData) {
cd = (ClientData *) client->clientData;
} }
if (strstr(gone_cmd, "popup") == gone_cmd) {
int x = -64000, y = -64000, timeout = 120;
char *userhost = ident_username(client);
char *addr, *p, *mode;
if (client->clientData) { /* extract timeout */
ClientData *cd = (ClientData *) client->clientData; if ((p = strchr(gone_cmd, ':')) != NULL) {
if (cd) { int in;
if (cd->server_ip) { if (sscanf(p+1, "%d", &in) == 1) {
free(cd->server_ip); timeout = in;
cd->server_ip = NULL;
} }
if (cd->hostname) {
free(cd->hostname);
cd->hostname = NULL;
} }
if (cd->username) { /* extract geometry */
free(cd->username); if ((p = strpbrk(gone_cmd, "+-")) != NULL) {
cd->username = NULL; ugly_geom(p, &x, &y);
}
/* find mode: mouse, key, or both */
if (strstr(gone_cmd, "popupmouse") == gone_cmd) {
mode = "mouse_only";
} else if (strstr(gone_cmd, "popupkey") == gone_cmd) {
mode = "key_only";
} else {
mode = "both";
} }
addr = client->host;
ugly_window(addr, userhost, x, y, timeout, mode, 0);
free(userhost);
} else {
rfbLog("client_gone: using cmd: %s\n", client->host);
run_user_command(gone_cmd, client, "gone");
} }
free(client->clientData);
client->clientData = NULL;
} }
free_client_data(client);
if (inetd) { if (inetd) {
rfbLog("viewer exited.\n"); rfbLog("viewer exited.\n");
clean_up_exit(0); clean_up_exit(0);
@ -722,8 +768,8 @@ static int check_access(char *addr) {
* x11vnc's first (and only) visible widget: accept/reject dialog window. * x11vnc's first (and only) visible widget: accept/reject dialog window.
* We go through this pain to avoid dependency on libXt... * We go through this pain to avoid dependency on libXt...
*/ */
static int ugly_accept_window(char *addr, char *userhost, int X, int Y, static int ugly_window(char *addr, char *userhost, int X, int Y,
int timeout, char *mode) { int timeout, char *mode, int accept) {
#define t2x2_width 16 #define t2x2_width 16
#define t2x2_height 16 #define t2x2_height 16
@ -772,10 +818,17 @@ static unsigned char t2x2_bits[] = {
int Ye_x = 20, Ye_y = 0, Ye_w = 45, Ye_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 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; int Vi_x = 130, Vi_y = 0, Vi_w = 45, Vi_h = 20;
char *sprop = "new x11vnc client";
KeyCode key_o;
if (raw_fb && ! dpy) return 0; /* raw_fb hack */ if (raw_fb && ! dpy) return 0; /* raw_fb hack */
if (!strcmp(mode, "mouse_only")) { if (! accept) {
sprintf(str_y, "OK");
sprop = "x11vnc client disconnected";
h = 110;
} else if (!strcmp(mode, "mouse_only")) {
str1 = str1_m; str1 = str1_m;
str2 = str2_m; str2 = str2_m;
str3 = str3_m; str3 = str3_m;
@ -834,14 +887,14 @@ static unsigned char t2x2_bits[] = {
hints.min_width = w; hints.min_width = w;
hints.min_height = h; hints.min_height = h;
XSetStandardProperties(dpy, awin, "new x11vnc client", "x11vnc query", XSetStandardProperties(dpy, awin, sprop, "x11vnc query", ico, NULL,
ico, NULL, 0, &hints); 0, &hints);
XSelectInput(dpy, awin, evmask); XSelectInput(dpy, awin, evmask);
if (! font_info && (font_info = XLoadQueryFont(dpy, "fixed")) == NULL) { if (! font_info && (font_info = XLoadQueryFont(dpy, "fixed")) == NULL) {
rfbLogEnable(1); rfbLogEnable(1);
rfbLog("ugly_accept_window: cannot locate font fixed.\n"); rfbLog("ugly_window: cannot locate font fixed.\n");
X_UNLOCK; X_UNLOCK;
clean_up_exit(1); clean_up_exit(1);
} }
@ -855,8 +908,14 @@ static unsigned char t2x2_bits[] = {
XMapWindow(dpy, awin); XMapWindow(dpy, awin);
XFlush(dpy); XFlush(dpy);
if (accept) {
snprintf(strh, 100, "x11vnc: accept connection from %s?", addr); snprintf(strh, 100, "x11vnc: accept connection from %s?", addr);
} else {
snprintf(strh, 100, "x11vnc: client disconnected from %s", addr);
}
snprintf(stri, 100, " (%s)", userhost); snprintf(stri, 100, " (%s)", userhost);
key_o = XKeysymToKeycode(dpy, XStringToKeysym("o"));
key_y = XKeysymToKeycode(dpy, XStringToKeysym("y")); key_y = XKeysymToKeycode(dpy, XStringToKeysym("y"));
key_n = XKeysymToKeycode(dpy, XStringToKeysym("n")); key_n = XKeysymToKeycode(dpy, XStringToKeysym("n"));
key_v = XKeysymToKeycode(dpy, XStringToKeysym("v")); key_v = XKeysymToKeycode(dpy, XStringToKeysym("v"));
@ -873,7 +932,7 @@ static unsigned char t2x2_bits[] = {
usleep(ms * 1000); usleep(ms * 1000);
waited += ((double) ms)/1000.; waited += ((double) ms)/1000.;
if (timeout && (int) waited >= timeout) { if (timeout && (int) waited >= timeout) {
rfbLog("accept_client: popup timed out after " rfbLog("ugly_window: popup timed out after "
"%d seconds.\n", timeout); "%d seconds.\n", timeout);
out = 0; out = 0;
ev.type = 0; ev.type = 0;
@ -894,6 +953,7 @@ static unsigned char t2x2_bits[] = {
strh, strlen(strh)); strh, strlen(strh));
XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
stri, strlen(stri)); stri, strlen(stri));
if (accept) {
XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
str1, strlen(str1)); str1, strlen(str1));
XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
@ -902,6 +962,7 @@ static unsigned char t2x2_bits[] = {
XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY,
str3, strlen(str3)); str3, strlen(str3));
} }
}
if (!strcmp(mode, "key_only")) { if (!strcmp(mode, "key_only")) {
break; break;
@ -912,11 +973,14 @@ static unsigned char t2x2_bits[] = {
No_y = Y_sh+k*dY; No_y = Y_sh+k*dY;
Vi_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, Ye_x, Ye_y, Ye_w, Ye_h);
if (accept) {
XDrawRectangle(dpy, awin, gc, No_x, No_y, No_w, No_h); XDrawRectangle(dpy, awin, gc, No_x, No_y, No_w, No_h);
if (! view_only) { if (! view_only) {
XDrawRectangle(dpy, awin, gc, Vi_x, Vi_y, XDrawRectangle(dpy, awin, gc, Vi_x, Vi_y,
Vi_w, Vi_h); Vi_w, Vi_h);
} }
}
tw = XTextWidth(font_info, str_y, strlen(str_y)); tw = XTextWidth(font_info, str_y, strlen(str_y));
tw = (Ye_w - tw)/2; tw = (Ye_w - tw)/2;
@ -924,6 +988,9 @@ static unsigned char t2x2_bits[] = {
XDrawString(dpy, awin, gc, Ye_x+tw, Ye_y+Ye_h-5, XDrawString(dpy, awin, gc, Ye_x+tw, Ye_y+Ye_h-5,
str_y, strlen(str_y)); str_y, strlen(str_y));
if (!accept) {
break;
}
tw = XTextWidth(font_info, str_n, strlen(str_n)); tw = XTextWidth(font_info, str_n, strlen(str_n));
tw = (No_w - tw)/2; tw = (No_w - tw)/2;
if (tw < 0) tw = 1; if (tw < 0) tw = 1;
@ -953,12 +1020,14 @@ static unsigned char t2x2_bits[] = {
y = ev.xbutton.y; y = ev.xbutton.y;
if (!strcmp(mode, "key_only")) { 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 } else if (x > Ye_x && x < Ye_x+Ye_w && y > Ye_y
&& y < Ye_y+Ye_h) { && y < Ye_y+Ye_h) {
out = 1; out = 1;
} else if (! accept) {
;
} else if (x > No_x && x < No_x+No_w && y > No_y
&& y < No_y+No_h) {
out = 0;
} else if (! view_only && x > Vi_x && x < Vi_x+Vi_w } else if (! view_only && x > Vi_x && x < Vi_x+Vi_w
&& y > Vi_y && y < Vi_y+Ye_h) { && y > Vi_y && y < Vi_y+Ye_h) {
out = 2; out = 2;
@ -968,8 +1037,16 @@ static unsigned char t2x2_bits[] = {
case KeyPress: case KeyPress:
if (!strcmp(mode, "mouse_only")) { if (!strcmp(mode, "mouse_only")) {
; ;
} else if (! accept) {
if (ev.xkey.keycode == key_o) {
out = 1;
}
if (ev.xkey.keycode == key_y) {
out = 1;
}
} else if (ev.xkey.keycode == key_y) { } else if (ev.xkey.keycode == key_y) {
out = 1; out = 1;
;
} else if (ev.xkey.keycode == key_n) { } else if (ev.xkey.keycode == key_n) {
out = 0; out = 0;
} else if (! view_only && ev.xkey.keycode == key_v) { } else if (! view_only && ev.xkey.keycode == key_v) {
@ -1082,6 +1159,24 @@ static int action_match(char *action, int rc) {
return result; return result;
} }
static void ugly_geom(char *p, int *x, int *y) {
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;
}
}
/* /*
* Simple routine to prompt the user on the X display whether an incoming * 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 * client should be allowed to connect or not. If a gui is involved it
@ -1133,20 +1228,7 @@ static int accept_client(rfbClientPtr client) {
} }
/* extract geometry */ /* extract geometry */
if ((p = strpbrk(accept_cmd, "+-")) != NULL) { if ((p = strpbrk(accept_cmd, "+-")) != NULL) {
int x1, y1; ugly_geom(p, &x, &y);
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 */ /* find mode: mouse, key, or both */
@ -1159,8 +1241,8 @@ static int accept_client(rfbClientPtr client) {
} }
rfbLog("accept_client: using builtin popup for: %s\n", addr); rfbLog("accept_client: using builtin popup for: %s\n", addr);
if ((ret = ugly_accept_window(addr, userhost, x, y, timeout, if ((ret = ugly_window(addr, userhost, x, y, timeout,
mode))) { mode, 1))) {
free(userhost); free(userhost);
if (ret == 2) { if (ret == 2) {
rfbLog("accept_client: viewonly: %s\n", addr); rfbLog("accept_client: viewonly: %s\n", addr);
@ -1656,19 +1738,10 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
allow_list ? allow_list : "(null)" ); allow_list ? allow_list : "(null)" );
return(RFB_CLIENT_REFUSE); return(RFB_CLIENT_REFUSE);
} }
if (! accept_client(client)) {
rfbLog("denying client: %s local user rejected connection.\n",
client->host);
rfbLog("denying client: accept_cmd=\"%s\"\n",
accept_cmd ? accept_cmd : "(null)" );
return(RFB_CLIENT_REFUSE);
}
client->clientData = (void *) calloc(sizeof(ClientData), 1); client->clientData = (void *) calloc(sizeof(ClientData), 1);
cd = (ClientData *) client->clientData; cd = (ClientData *) client->clientData;
cd->uid = clients_served;
cd->client_port = get_remote_port(client->sock); cd->client_port = get_remote_port(client->sock);
cd->server_port = get_local_port(client->sock); cd->server_port = get_local_port(client->sock);
cd->server_ip = get_local_host(client->sock); cd->server_ip = get_local_host(client->sock);
@ -1679,6 +1752,20 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
cd->login_viewonly = -1; cd->login_viewonly = -1;
cd->login_time = time(0); cd->login_time = time(0);
if (! accept_client(client)) {
rfbLog("denying client: %s local user rejected connection.\n",
client->host);
rfbLog("denying client: accept_cmd=\"%s\"\n",
accept_cmd ? accept_cmd : "(null)" );
free_client_data(client);
return(RFB_CLIENT_REFUSE);
}
cd->uid = clients_served;
client->clientGoneHook = client_gone; client->clientGoneHook = client_gone;
if (client_count) { if (client_count) {
@ -1861,11 +1948,11 @@ void check_new_clients(void) {
if (unixpw_in_progress) { if (unixpw_in_progress) {
int present = 0; int present = 0;
if (time(0) > unixpw_last_try_time + 20) { if (time(0) > unixpw_last_try_time + 30) {
rfbLog("unixpw_deny: timed out waiting for reply.\n"); rfbLog("unixpw_deny: timed out waiting for reply.\n");
unixpw_deny(); unixpw_deny();
return;
} }
return;
} }
if (client_count == last_count) { if (client_count == last_count) {
@ -1895,23 +1982,24 @@ void check_new_clients(void) {
iter = rfbGetClientIterator(screen); iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) { while( (cl = rfbClientIteratorNext(iter)) ) {
ClientData *cd = (ClientData *) cl->clientData; ClientData *cd = (ClientData *) cl->clientData;
char *s;
if (cd->login_viewonly < 0) { if (cd->login_viewonly < 0) {
/* this is a general trigger to initialize things */ /* this is a general trigger to initialize things */
if (cl->viewOnly) { if (cl->viewOnly) {
cd->login_viewonly = 1; cd->login_viewonly = 1;
if (allowed_input_view_only) { s = allowed_input_view_only;
if (s && cd->input[0] == '-') {
cl->viewOnly = FALSE; cl->viewOnly = FALSE;
cd->input[0] = '\0'; cd->input[0] = '\0';
strncpy(cd->input, strncpy(cd->input, s, CILEN);
allowed_input_view_only, CILEN);
} }
} else { } else {
cd->login_viewonly = 0; cd->login_viewonly = 0;
if (allowed_input_normal) { s = allowed_input_normal;
if (s && cd->input[0] == '-') {
cd->input[0] = '\0'; cd->input[0] = '\0';
strncpy(cd->input, strncpy(cd->input, s, CILEN);
allowed_input_normal, CILEN);
} }
} }
if (run_after_accept) { if (run_after_accept) {

@ -402,9 +402,10 @@ void print_help(int mode) {
" full-access passwords)\n" " full-access passwords)\n"
"\n" "\n"
"-unixpw [list] Experimental option: use Unix username and password\n" "-unixpw [list] Experimental option: use Unix username and password\n"
" authentication. x11vnc uses the su(1) program to\n" " authentication. x11vnc uses the su(1) program to verify\n"
" verify the user's password. [list] is an optional\n" " the user's password. [list] is an optional comma\n"
" comma separated list of allowed Unix usernames.\n" " separated list of allowed Unix usernames. See below\n"
" for per-user options that can be applied.\n"
"\n" "\n"
" A familiar \"login:\" and \"Password:\" dialog is\n" " A familiar \"login:\" and \"Password:\" dialog is\n"
" presented to the user on a black screen inside the\n" " presented to the user on a black screen inside the\n"
@ -413,6 +414,22 @@ void print_help(int mode) {
" send one before a 20 second timeout. Existing clients\n" " send one before a 20 second timeout. Existing clients\n"
" are view-only during this period.\n" " are view-only during this period.\n"
"\n" "\n"
" Since the detailed behavior of su(1) can vary from\n"
" OS to OS and for local configurations, please test\n"
" the mode carefully on your systems before using it.\n"
" Try different combinations of valid/invalid usernames\n"
" and passwords.\n"
" \n"
" For example, on FreeBSD and the other BSD's and Tru64\n"
" it does not appear to be possible for the user running\n"
" x11vnc to validate his *own* password via su(1).\n"
" The x11vnc login will always fail in this case.\n"
" A possible workaround would be to start x11vnc as\n"
" root with the \"-users +nobody\" option to immediately\n"
" switch to user nobody. Another source of problems are\n"
" PAM modules that prompt for extra info, e.g. password\n"
" aging modules. These logins will always fail as well.\n"
"\n"
" *IMPORTANT*: to prevent the Unix password being sent in\n" " *IMPORTANT*: to prevent the Unix password being sent in\n"
" *clear text* over the network, two x11vnc options are\n" " *clear text* over the network, two x11vnc options are\n"
" enforced: 1) -localhost and 2) -stunnel. The former\n" " enforced: 1) -localhost and 2) -stunnel. The former\n"
@ -432,6 +449,13 @@ void print_help(int mode) {
" user login (since Unix password or the user's public\n" " user login (since Unix password or the user's public\n"
" key authentication is used by ssh)\n" " key authentication is used by ssh)\n"
"\n" "\n"
" As a convenience, if you ssh(1) in and start x11vnc\n"
" it will look to see if the environment variable\n"
" SSH_CONNECTION is set and appears reasonable. If it\n"
" does, then the stunnel requirement is dropped since\n"
" it is assumed you are using ssh for the encrypted\n"
" tunnelling. Use -stunnel to force stunnel usage.\n"
"\n"
" Set UNIXPW_DISABLE_LOCALHOST=1 to disable the -localhost\n" " Set UNIXPW_DISABLE_LOCALHOST=1 to disable the -localhost\n"
" requirement. One should never do this (i.e. allow the\n" " requirement. One should never do this (i.e. allow the\n"
" Unix passwords to be sniffed on the network).\n" " Unix passwords to be sniffed on the network).\n"
@ -440,23 +464,40 @@ void print_help(int mode) {
" since x11vnc does not make network connections in\n" " since x11vnc does not make network connections in\n"
" that case. Be sure to use encryption from the viewer\n" " that case. Be sure to use encryption from the viewer\n"
" to inetd. One can also have your own stunnel spawn\n" " to inetd. One can also have your own stunnel spawn\n"
" x11vnc in -inetd mode.\n" " x11vnc in -inetd mode. See the FAQ.\n"
"\n"
" The user names in the comma separated [list] can have\n"
" per-user options after a \":\", e.g. \"fred:opts\"\n"
" where \"opts\" is a \"+\" separated list of\n"
" \"viewonly\", \"fullaccess\", \"input=XXXX\", or\n"
" \"deny\", e.g. \"karl,fred:viewonly,boss:input=M\".\n"
" For \"input=\" it is the K,M,B,C describe under -input.\n"
"\n"
" If a user in the list is \"*\" that means those options\n"
" apply to all users. It also means all users are allowed\n"
" to log in. Use \"deny\" to explicitly deny some users\n"
" if you use \"*\" to set a global option.\n"
"\n" "\n"
"-stunnel [pem] Use the stunnel(1) (www.stunnel.org) to provide an\n" "-stunnel [pem] Use the stunnel(1) (www.stunnel.org) to provide an\n"
" encrypted SSL tunnel between viewers and x11vnc.\n" " encrypted SSL tunnel between viewers and x11vnc.\n"
" This requires stunnel be installed on the system and\n" " This requires stunnel be installed on the system and\n"
" available via PATH (n.b. stunnel is often installed in\n" " available via PATH (n.b. stunnel is often installed in\n"
" sbin directories). Version 4.x of stunnel is assumed.\n" " sbin directories). Version 4.x of stunnel is assumed;\n"
" see -stunnel3 below.\n"
"\n" "\n"
" [pem] is optional, use \"-stunnel /path/to/stunnel.pem\"\n" " [pem] is optional, use \"-stunnel /path/to/stunnel.pem\"\n"
" to specify a PEM certificate file to pass to stunnel.\n" " to specify a PEM certificate file to pass to stunnel.\n"
" Whether one is needed or not depends on your stunnel\n"
" configuration.\n"
"\n" "\n"
" stunnel is started up as a child process and any SSL\n" " stunnel is started up as a child process of x11vnc and\n"
" connections it receives are decrypted and sent to x11vnc\n" " any SSL connections stunnel receives are decrypted and\n"
" over a local socket. The strings \"The SSL VNC desktop\n" " sent to x11vnc over a local socket. The strings \"The\n"
" is ...\" and SSLPORT=... are printed out at startup.\n" " SSL VNC desktop is ...\" and SSLPORT=... are printed\n"
" out at startup.\n"
"\n" "\n"
" The -localhost option is enforced by default. Set\n" " The -localhost option is enforced by default to\n"
" avoid people routing around the SSL channel. Set\n"
" STUNNEL_DISABLE_LOCALHOST=1 to disable the requirement.\n" " STUNNEL_DISABLE_LOCALHOST=1 to disable the requirement.\n"
"\n" "\n"
" Your VNC viewer will need to be able to connect via SSL.\n" " Your VNC viewer will need to be able to connect via SSL.\n"
@ -470,7 +511,8 @@ void print_help(int mode) {
" %% vncviewer localhost:1\n" " %% vncviewer localhost:1\n"
"\n" "\n"
" For Windows, stunnel has been ported to it and there\n" " For Windows, stunnel has been ported to it and there\n"
" are probably other such tools available.\n" " are probably other such tools available. See the FAQ\n"
" for more examples.\n"
"\n" "\n"
"-stunnel3 [pem] Use version 3.x stunnel command line syntax instead of\n" "-stunnel3 [pem] Use version 3.x stunnel command line syntax instead of\n"
" version 4.x\n" " version 4.x\n"
@ -558,8 +600,9 @@ void print_help(int mode) {
"-gone string As -accept, except to run a user supplied command when\n" "-gone string As -accept, except to run a user supplied command when\n"
" a client goes away (disconnects). RFB_MODE will be\n" " a client goes away (disconnects). RFB_MODE will be\n"
" set to \"gone\" and the other RFB_* variables are as\n" " set to \"gone\" and the other RFB_* variables are as\n"
" in -accept. Unlike -accept, the command return code\n" " in -accept. The \"popup\" actions apply as well.\n"
" is not interpreted by x11vnc. Example: -gone 'xlock &'\n" " Unlike -accept, the command return code is not\n"
" interpreted by x11vnc. Example: -gone 'xlock &'\n"
"\n" "\n"
"-users list If x11vnc is started as root (say from inetd(1) or from\n" "-users list If x11vnc is started as root (say from inetd(1) or from\n"
" display managers xdm(1), gdm(1), etc), then as soon\n" " display managers xdm(1), gdm(1), etc), then as soon\n"
@ -1766,6 +1809,8 @@ void print_help(int mode) {
" timeout:n reset -timeout to n, if there are\n" " timeout:n reset -timeout to n, if there are\n"
" currently no clients, exit unless one\n" " currently no clients, exit unless one\n"
" connects in the next n secs.\n" " connects in the next n secs.\n"
" filexfer enable filetransfer for new clients.\n"
" nofilexfer disable filetransfer for new clients.\n"
/* access */ /* access */
" http enable http client connections.\n" " http enable http client connections.\n"
" nohttp disable http client connections.\n" " nohttp disable http client connections.\n"
@ -2013,11 +2058,11 @@ void print_help(int mode) {
" truecolor notruecolor overlay nooverlay overlay_cursor\n" " truecolor notruecolor overlay nooverlay overlay_cursor\n"
" overlay_yescursor nooverlay_nocursor nooverlay_cursor\n" " overlay_yescursor nooverlay_nocursor nooverlay_cursor\n"
" nooverlay_yescursor overlay_nocursor 8to24 no8to24\n" " nooverlay_yescursor overlay_nocursor 8to24 no8to24\n"
" 8to24_opts visual scale scale_cursor viewonly\n" " 8to24_opts visual scale scale_cursor viewonly noviewonly\n"
" noviewonly shared noshared forever noforever once\n" " shared noshared forever noforever once timeout filexfer\n"
" timeout filexfer deny lock nodeny unlock connect\n" " nofilexfer deny lock nodeny unlock connect allowonce\n"
" allowonce allow localhost nolocalhost listen lookup\n" " allow localhost nolocalhost listen lookup nolookup\n"
" nolookup accept afteraccept gone shm noshm flipbyteorder\n" " accept afteraccept gone shm noshm flipbyteorder\n"
" noflipbyteorder onetile noonetile solid_color solid\n" " noflipbyteorder onetile noonetile solid_color solid\n"
" nosolid blackout xinerama noxinerama xtrap noxtrap\n" " nosolid blackout xinerama noxinerama xtrap noxtrap\n"
" xrandr noxrandr xrandr_mode padgeom quiet q noquiet\n" " xrandr noxrandr xrandr_mode padgeom quiet q noquiet\n"
@ -2056,15 +2101,15 @@ void print_help(int mode) {
" scale_str scaled_x scaled_y scale_numer scale_denom\n" " scale_str scaled_x scaled_y scale_numer scale_denom\n"
" scale_fac scaling_blend scaling_nomult4 scaling_pad\n" " scale_fac scaling_blend scaling_nomult4 scaling_pad\n"
" scaling_interpolate inetd privremote unsafe safer nocmds\n" " scaling_interpolate inetd privremote unsafe safer nocmds\n"
" passwdfile using_shm logfile o flag rc norc h help V\n" " passwdfile unixpw unixpw_list stunnel stunnel_pem\n"
" version lastmod bg sigpipe threads readrate netrate\n" " using_shm logfile o flag rc norc h help V version\n"
" netlatency pipeinput clients client_count pid ext_xtest\n" " lastmod bg sigpipe threads readrate netrate netlatency\n"
" ext_xtrap ext_xrecord ext_xkb ext_xshm ext_xinerama\n" " pipeinput clients client_count pid ext_xtest ext_xtrap\n"
" ext_overlay ext_xfixes ext_xdamage ext_xrandr rootwin\n" " ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay\n"
" num_buttons button_mask mouse_x mouse_y bpp depth\n" " ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons\n"
" indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y\n" " button_mask mouse_x mouse_y bpp depth indexed_color\n"
" cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd\n" " dpy_x dpy_y wdpy_x wdpy_y off_x off_y cdpy_x cdpy_y\n"
"\n" " coff_x coff_y rfbauth passwd viewpasswd\n"
"-QD variable Just like -query variable, but returns the default\n" "-QD variable Just like -query variable, but returns the default\n"
" value for that parameter (no running x11vnc server\n" " value for that parameter (no running x11vnc server\n"
" is consulted)\n" " is consulted)\n"

@ -17,7 +17,7 @@ char *get_remote_host(int sock);
char *get_local_host(int sock); char *get_local_host(int sock);
char *ident_username(rfbClientPtr client); char *ident_username(rfbClientPtr client);
int find_free_port(int start, int end); int find_free_port(int start, int end);
int have_ssh_env(void);
static int get_port(int sock, int remote); static int get_port(int sock, int remote);
static char *get_host(int sock, int remote); static char *get_host(int sock, int remote);
@ -314,3 +314,54 @@ int find_free_port(int start, int end) {
return 0; return 0;
} }
int have_ssh_env(void) {
char *str, *p = getenv("SSH_CONNECTION");
char *rhost, *rport, *lhost, *lport;
if (! p) return 0;
str = strdup(p);
p = strtok(str, " ");
rhost = p;
p = strtok(NULL, " ");
if (! p) goto fail;
rport = p;
p = strtok(NULL, " ");
if (! p) goto fail;
lhost = p;
p = strtok(NULL, " ");
if (! p) goto fail;
lport = p;
if (0) fprintf(stderr, "%d/%d - '%s' '%s'\n", atoi(rport), atoi(lport), rhost, lhost);
if (atoi(rport) < 0 || atoi(rport) > 65535) {
goto fail;
}
if (atoi(lport) < 0 || atoi(lport) > 65535) {
goto fail;
}
if (!strcmp(rhost, lhost)) {
goto fail;
}
free(str);
return 1;
fail:
fprintf(stderr, "failed:\n");
free(str);
return 0;
}

@ -14,5 +14,6 @@ extern char *get_remote_host(int sock);
extern char *get_local_host(int sock); extern char *get_local_host(int sock);
extern char *ident_username(rfbClientPtr client); extern char *ident_username(rfbClientPtr client);
extern int find_free_port(int start, int end); extern int find_free_port(int start, int end);
extern int have_ssh_env(void);
#endif /* _X11VNC_INET_H */ #endif /* _X11VNC_INET_H */

@ -801,7 +801,7 @@ int sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new) {
return 0; return 0;
} }
#if !LIBVNCSERVER_HAVE_XKEYBOARD #if !LIBVNCSERVER_HAVE_XKEYBOARD || SKIP_XKB
/* empty functions for no xkb */ /* empty functions for no xkb */
static void initialize_xkb_modtweak(void) {} static void initialize_xkb_modtweak(void) {}

@ -1141,6 +1141,36 @@ char *process_remote_cmd(char *cmd, int stringonly) {
first_conn_timeout = to; first_conn_timeout = to;
rfbLog("remote_cmd: set -timeout to %d\n", -to); rfbLog("remote_cmd: set -timeout to %d\n", -to);
} else if (!strcmp(p, "filexfer")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, filexfer);
goto qry;
}
#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
if (! filexfer) {
rfbLog("remote_cmd: enabling -filexfer for new clients.\n");
filexfer = 1;
rfbRegisterTightVNCFileTransferExtension();
}
#else
rfbLog("remote_cmd: -filexfer not supported in this binary.\n");
#endif
} else if (!strcmp(p, "nofilexfer")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, !filexfer);
goto qry;
}
#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
if (filexfer) {
rfbLog("remote_cmd: disabling -filexfer for new clients.\n");
filexfer = 0;
rfbUnregisterTightVNCFileTransferExtension();
}
#else
rfbLog("remote_cmd: -filexfer not supported in this binary.\n");
#endif
} else if (!strcmp(p, "deny") || !strcmp(p, "lock")) { } else if (!strcmp(p, "deny") || !strcmp(p, "lock")) {
if (query) { if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, deny_all); snprintf(buf, bufn, "ans=%s:%d", p, deny_all);
@ -1415,7 +1445,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
host_lookup = 0; host_lookup = 0;
} else if (strstr(p, "accept") == p) { } else if (strstr(p, "accept") == p) {
int doit = 1; int doit = 1, safe = 0;
COLON_CHECK("accept:") COLON_CHECK("accept:")
if (query) { if (query) {
snprintf(buf, bufn, "ans=%s%s%s", p, co, snprintf(buf, bufn, "ans=%s%s%s", p, co,
@ -1423,16 +1453,13 @@ char *process_remote_cmd(char *cmd, int stringonly) {
goto qry; goto qry;
} }
p += strlen("accept:"); p += strlen("accept:");
if (safe_remote_only) { if (!strcmp(p, "") || strstr(p, "popup") == p) { /* skip-cmd-list */
if (icon_mode && !strcmp(p, "")) { /* skip-cmd-list */ safe = 1;
; }
} else if (icon_mode && !strcmp(p, "popup")) { /* skip-cmd-list */ if (safe_remote_only && ! safe) {
;
} else {
rfbLog("unsafe: %s\n", p); rfbLog("unsafe: %s\n", p);
doit = 0; doit = 0;
} }
}
if (doit) { if (doit) {
if (accept_cmd) free(accept_cmd); if (accept_cmd) free(accept_cmd);
@ -1440,31 +1467,39 @@ char *process_remote_cmd(char *cmd, int stringonly) {
} }
} else if (strstr(p, "afteraccept") == p) { } else if (strstr(p, "afteraccept") == p) {
int safe = 0;
COLON_CHECK("afteraccept:") COLON_CHECK("afteraccept:")
if (query) { if (query) {
snprintf(buf, bufn, "ans=%s%s%s", p, co, snprintf(buf, bufn, "ans=%s%s%s", p, co,
NONUL(afteraccept_cmd)); NONUL(afteraccept_cmd));
goto qry; goto qry;
} }
if (safe_remote_only) { p += strlen("afteraccept:");
if (!strcmp(p, "")) { /* skip-cmd-list */
safe = 1;
}
if (safe_remote_only && ! safe) {
rfbLog("unsafe: %s\n", p); rfbLog("unsafe: %s\n", p);
} else { } else {
p += strlen("afteraccept:");
if (afteraccept_cmd) free(afteraccept_cmd); if (afteraccept_cmd) free(afteraccept_cmd);
afteraccept_cmd = strdup(p); afteraccept_cmd = strdup(p);
} }
} else if (strstr(p, "gone") == p) { } else if (strstr(p, "gone") == p) {
int safe = 0;
COLON_CHECK("gone:") COLON_CHECK("gone:")
if (query) { if (query) {
snprintf(buf, bufn, "ans=%s%s%s", p, co, snprintf(buf, bufn, "ans=%s%s%s", p, co,
NONUL(gone_cmd)); NONUL(gone_cmd));
goto qry; goto qry;
} }
if (safe_remote_only) { p += strlen("gone:");
if (!strcmp(p, "") || strstr(p, "popup") == p) { /* skip-cmd-list */
safe = 1;
}
if (safe_remote_only && ! safe) {
rfbLog("unsafe: %s\n", p); rfbLog("unsafe: %s\n", p);
} else { } else {
p += strlen("gone:");
if (gone_cmd) free(gone_cmd); if (gone_cmd) free(gone_cmd);
gone_cmd = strdup(p); gone_cmd = strdup(p);
} }
@ -3669,6 +3704,12 @@ char *process_remote_cmd(char *cmd, int stringonly) {
snprintf(buf, bufn, "aro=%s:%s", p, NONUL(passwdfile)); snprintf(buf, bufn, "aro=%s:%s", p, NONUL(passwdfile));
} else if (!strcmp(p, "unixpw")) { } else if (!strcmp(p, "unixpw")) {
snprintf(buf, bufn, "aro=%s:%d", p, unixpw); snprintf(buf, bufn, "aro=%s:%d", p, unixpw);
} else if (!strcmp(p, "unixpw_list")) {
snprintf(buf, bufn, "aro=%s:%s", p, NONUL(unixpw_list));
} else if (!strcmp(p, "stunnel")) {
snprintf(buf, bufn, "aro=%s:%d", p, use_stunnel);
} else if (!strcmp(p, "stunnel_pem")) {
snprintf(buf, bufn, "aro=%s:%s", p, NONUL(stunnel_pem));
} else if (!strcmp(p, "using_shm")) { } else if (!strcmp(p, "using_shm")) {
snprintf(buf, bufn, "aro=%s:%d", p, !using_shm); snprintf(buf, bufn, "aro=%s:%d", p, !using_shm);
} else if (!strcmp(p, "logfile") || !strcmp(p, "o")) { } else if (!strcmp(p, "logfile") || !strcmp(p, "o")) {

@ -94,6 +94,7 @@ Clients
gone: gone:
vncconnect vncconnect
-- D -- D
filexfer
=D http =D http
httpdir: httpdir:
httpport: httpport:
@ -255,6 +256,8 @@ Permissions
viewpasswd: viewpasswd:
=F passwdfile: =F passwdfile:
=F rfbauth: =F rfbauth:
unixpw
unixpw_list:
=0 storepasswd =0 storepasswd
=GAL LOFF =GAL LOFF
=GAL Misc-Perms:: =GAL Misc-Perms::
@ -262,6 +265,8 @@ Permissions
=0S nevershared =0S nevershared
=0S dontdisconnect =0S dontdisconnect
=SQA deny_all =SQA deny_all
stunnel
=F stunnel_pem:
=GAL LOFF =GAL LOFF
Tuning Tuning
@ -515,6 +520,14 @@ Set the -solid color value.
set helptext(xrandr_mode) " set helptext(xrandr_mode) "
Set the -xrandr mode value. Set the -xrandr mode value.
"
set helptext(unixpw_list) "
Set the -unixpw_list usernames list value.
"
set helptext(stunnel_pem) "
Set the -stunnel pem filename value.
" "
set helptext(wireframe_mode) " set helptext(wireframe_mode) "
@ -3396,9 +3409,11 @@ proc set_widgets {} {
global connected_to_x11vnc item_case item_menu item_entry menu_m global connected_to_x11vnc item_case item_menu item_entry menu_m
foreach item [array names item_case] { foreach item [array names item_case] {
if ![info exists item_case($item)] { continue; }
set case $item_case($item) set case $item_case($item)
# set menu $menu_m($case) if ![info exists item_menu($item)] { continue; }
set menu $item_menu($item) set menu $item_menu($item)
if ![info exists item_entry($item)] { continue; }
set entry $item_entry($item) set entry $item_entry($item)
if {$entry < 0} { if {$entry < 0} {
# skip case under beginner_mode # skip case under beginner_mode
@ -5391,6 +5406,10 @@ proc get_nitem {item} {
set nitem "sb" set nitem "sb"
} elseif {$nitem == "xrandr_mode"} { } elseif {$nitem == "xrandr_mode"} {
set nitem "xrandr" set nitem "xrandr"
} elseif {$nitem == "unixpw_list"} {
set nitem "unixpw"
} elseif {$nitem == "stunnel_pem"} {
set nitem "stunnel"
} elseif {$nitem == "wireframe_mode"} { } elseif {$nitem == "wireframe_mode"} {
set nitem "wireframe" set nitem "wireframe"
} elseif {$nitem == "solid_color"} { } elseif {$nitem == "solid_color"} {
@ -5989,6 +6008,13 @@ if {$tk_version < 8.4} {
set have_labelframes 0 set have_labelframes 0
} }
if {[info exists env(X11VNC_GUI_TEXT_HEIGHT)]} {
set max_text_height $env(X11VNC_GUI_TEXT_HEIGHT)
}
if {[info exists env(X11VNC_GUI_TEXT_WIDTH)]} {
set max_text_width $env(X11VNC_GUI_TEXT_WIDTH)
}
if {"$argv" == "-spit"} { if {"$argv" == "-spit"} {
set fh [open $argv0 r] set fh [open $argv0 r]
puts "#ifndef _TKX11VNC_H" puts "#ifndef _TKX11VNC_H"

@ -105,6 +105,7 @@ char gui_code[] = "";
" gone:\n" " gone:\n"
" vncconnect\n" " vncconnect\n"
" -- D\n" " -- D\n"
" filexfer\n"
" =D http\n" " =D http\n"
" httpdir:\n" " httpdir:\n"
" httpport:\n" " httpport:\n"
@ -266,6 +267,8 @@ char gui_code[] = "";
" viewpasswd:\n" " viewpasswd:\n"
" =F passwdfile:\n" " =F passwdfile:\n"
" =F rfbauth:\n" " =F rfbauth:\n"
" unixpw\n"
" unixpw_list:\n"
" =0 storepasswd\n" " =0 storepasswd\n"
" =GAL LOFF\n" " =GAL LOFF\n"
" =GAL Misc-Perms::\n" " =GAL Misc-Perms::\n"
@ -273,6 +276,8 @@ char gui_code[] = "";
" =0S nevershared\n" " =0S nevershared\n"
" =0S dontdisconnect\n" " =0S dontdisconnect\n"
" =SQA deny_all\n" " =SQA deny_all\n"
" stunnel\n"
" =F stunnel_pem:\n"
" =GAL LOFF\n" " =GAL LOFF\n"
"\n" "\n"
"Tuning\n" "Tuning\n"
@ -528,6 +533,14 @@ char gui_code[] = "";
"Set the -xrandr mode value.\n" "Set the -xrandr mode value.\n"
"\"\n" "\"\n"
"\n" "\n"
" set helptext(unixpw_list) \"\n"
"Set the -unixpw_list usernames list value.\n"
"\"\n"
"\n"
" set helptext(stunnel_pem) \"\n"
"Set the -stunnel pem filename value.\n"
"\"\n"
"\n"
" set helptext(wireframe_mode) \"\n" " set helptext(wireframe_mode) \"\n"
"Set the -wireframe mode string value.\n" "Set the -wireframe mode string value.\n"
"\"\n" "\"\n"
@ -3407,9 +3420,11 @@ char gui_code[] = "";
" global connected_to_x11vnc item_case item_menu item_entry menu_m\n" " global connected_to_x11vnc item_case item_menu item_entry menu_m\n"
"\n" "\n"
" foreach item [array names item_case] {\n" " foreach item [array names item_case] {\n"
" if ![info exists item_case($item)] { continue; }\n"
" set case $item_case($item)\n" " set case $item_case($item)\n"
"# set menu $menu_m($case)\n" " if ![info exists item_menu($item)] { continue; }\n"
" set menu $item_menu($item)\n" " set menu $item_menu($item)\n"
" if ![info exists item_entry($item)] { continue; }\n"
" set entry $item_entry($item)\n" " set entry $item_entry($item)\n"
" if {$entry < 0} {\n" " if {$entry < 0} {\n"
" # skip case under beginner_mode \n" " # skip case under beginner_mode \n"
@ -5402,6 +5417,10 @@ char gui_code[] = "";
" set nitem \"sb\"\n" " set nitem \"sb\"\n"
" } elseif {$nitem == \"xrandr_mode\"} {\n" " } elseif {$nitem == \"xrandr_mode\"} {\n"
" set nitem \"xrandr\"\n" " set nitem \"xrandr\"\n"
" } elseif {$nitem == \"unixpw_list\"} {\n"
" set nitem \"unixpw\"\n"
" } elseif {$nitem == \"stunnel_pem\"} {\n"
" set nitem \"stunnel\"\n"
" } elseif {$nitem == \"wireframe_mode\"} {\n" " } elseif {$nitem == \"wireframe_mode\"} {\n"
" set nitem \"wireframe\"\n" " set nitem \"wireframe\"\n"
" } elseif {$nitem == \"solid_color\"} {\n" " } elseif {$nitem == \"solid_color\"} {\n"
@ -6000,6 +6019,13 @@ char gui_code[] = "";
" set have_labelframes 0\n" " set have_labelframes 0\n"
"}\n" "}\n"
"\n" "\n"
"if {[info exists env(X11VNC_GUI_TEXT_HEIGHT)]} {\n"
" set max_text_height $env(X11VNC_GUI_TEXT_HEIGHT)\n"
"}\n"
"if {[info exists env(X11VNC_GUI_TEXT_WIDTH)]} {\n"
" set max_text_width $env(X11VNC_GUI_TEXT_WIDTH)\n"
"}\n"
"\n"
"if {\"$argv\" == \"-spit\"} {\n" "if {\"$argv\" == \"-spit\"} {\n"
" set fh [open $argv0 r]\n" " set fh [open $argv0 r]\n"
" puts \"#ifndef _TKX11VNC_H\"\n" " puts \"#ifndef _TKX11VNC_H\"\n"

@ -13,39 +13,37 @@ extern char *ptsname(int);
#include "xinerama.h" #include "xinerama.h"
#include <rfb/default8x16.h> #include <rfb/default8x16.h>
/* much to do for it to work on *BSD ... */
#if LIBVNCSERVER_HAVE_FORK #if LIBVNCSERVER_HAVE_FORK
#if LIBVNCSERVER_HAVE_SETSID
#if LIBVNCSERVER_HAVE_SYS_WAIT_H #if LIBVNCSERVER_HAVE_SYS_WAIT_H
#if LIBVNCSERVER_HAVE_PWD_H
#if LIBVNCSERVER_HAVE_SETUID
#if LIBVNCSERVER_HAVE_WAITPID #if LIBVNCSERVER_HAVE_WAITPID
#if LIBVNCSERVER_HAVE_TERMIOS_H
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
#if LIBVNCSERVER_HAVE_GRANTPT
#define UNIXPW #define UNIXPW
#include <sys/ioctl.h>
#include <termios.h>
#endif
#endif
#endif #endif
#endif #endif
#endif #endif
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif #endif
#if LIBVNCSERVER_HAVE_TERMIOS_H
#include <termios.h>
#endif #endif
#if 0
#include <sys/stropts.h>
#endif #endif
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
#define IS_BSD
#endif #endif
void unixpw_screen(int init); void unixpw_screen(int init);
void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init); void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init);
void unixpw_accept(void); void unixpw_accept(char *user);
void unixpw_deny(void); void unixpw_deny(void);
int su_verify(char *user, char *pass);
static int white(void); static int white(void);
static int text_x(void); static int text_x(void);
static int text_y(void); static int text_y(void);
static int su_verify(char *user, char *pass); static void set_db(void);
static void unixpw_verify(char *user, char *pass); static void unixpw_verify(char *user, char *pass);
int unixpw_in_progress = 0; int unixpw_in_progress = 0;
@ -56,6 +54,8 @@ static int in_login = 0, in_passwd = 0, tries = 0;
static int char_row = 0, char_col = 0; static int char_row = 0, char_col = 0;
static int char_x = 0, char_y = 0, char_w = 8, char_h = 16; static int char_x = 0, char_y = 0, char_w = 8, char_h = 16;
static int db = 0;
static int white(void) { static int white(void) {
static unsigned long black_pix = 0, white_pix = 1, set = 0; static unsigned long black_pix = 0, white_pix = 1, set = 0;
@ -108,131 +108,468 @@ void unixpw_screen(int init) {
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
} }
static int su_verify(char *user, char *pass) {
#ifdef UNIXPW #ifdef MAXPATHLEN
int status, fd, sfd; static char slave_str[MAXPATHLEN];
#else
static char slave_str[4096];
#endif
char *get_pty_ptmx(int *fd_p) {
char *slave; char *slave;
pid_t pid, pidw; int fd = -1, i, ndevs = 4, tmp;
struct stat sbuf; char *devs[] = {
"/dev/ptmx",
"/dev/ptm/clone",
"/dev/ptc",
"/dev/ptmx_bsd"
};
if (unixpw_list) { *fd_p = -1;
char *p, *str = strdup(unixpw_list);
int ok = 0;
p = strtok(str, ","); #if LIBVNCSERVER_HAVE_GRANTPT
while (p) {
if (!strcmp(user, p)) { for (i=0; i < ndevs; i++) {
ok = 1;
#ifdef O_NOCTTY
fd = open(devs[i], O_RDWR|O_NOCTTY);
#else
fd = open(devs[i], O_RDWR);
#endif
if (fd >= 0) {
break; break;
} }
p = strtok(NULL, ",");
} }
free(str);
if (! ok) {
return 0;
}
}
if (stat("/bin/su", &sbuf) != 0) {
rfbLogPerror("existence /bin/su");
return 0;
}
if (stat("/bin/true", &sbuf) != 0) {
rfbLogPerror("existence /bin/true");
return 0;
}
fd = open("/dev/ptmx", O_RDWR|O_NOCTTY);
if (fd < 0) { if (fd < 0) {
rfbLogPerror("open /dev/ptmx"); rfbLogPerror("open /dev/ptmx");
return 0; return NULL;
} }
#if 0
#if defined(FIONBIO)
tmp = 1;
ioctl(fd, FIONBIO, &tmp);
#endif
#endif
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCPKT)
tmp = 0;
ioctl(fd, TIOCPKT, (char *) &tmp);
#endif
if (grantpt(fd) != 0) { if (grantpt(fd) != 0) {
rfbLogPerror("grantpt"); rfbLogPerror("grantpt");
close(fd); close(fd);
return 0; return NULL;
} }
if (unlockpt(fd) != 0) { if (unlockpt(fd) != 0) {
rfbLogPerror("unlockpt"); rfbLogPerror("unlockpt");
close(fd); close(fd);
return 0; return NULL;
} }
slave = ptsname(fd); slave = ptsname(fd);
if (! slave) { if (! slave) {
rfbLogPerror("ptsname"); rfbLogPerror("ptsname");
close(fd); close(fd);
return 0; return NULL;
} }
pid = fork(); #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCFLUSH)
if (pid < 0) { ioctl(fd, TIOCFLUSH, (char *) 0);
rfbLogPerror("fork"); #endif
close(fd);
return 0;
strcpy(slave_str, slave);
*fd_p = fd;
return slave_str;
#else
return NULL;
#endif /* GRANTPT */
}
char *get_pty_loop(int *fd_p) {
char *slave;
char master_str[16];
int fd = -1, i;
char c;
*fd_p = -1;
/* for *BSD loop over /dev/ptyXY */
for (c = 'p'; c <= 'z'; c++) {
for (i=0; i < 16; i++) {
sprintf(master_str, "/dev/pty%c%x", c, i);
#ifdef O_NOCTTY
fd = open(master_str, O_RDWR|O_NOCTTY);
#else
fd = open(master_str, O_RDWR);
#endif
if (fd >= 0) {
break;
}
}
if (fd >= 0) {
break;
}
}
if (fd < 0) {
return NULL;
} }
if (pid == 0) { #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCFLUSH)
int ttyfd; ioctl(fd, TIOCFLUSH, (char *) 0);
struct passwd *pw; #endif
close(fd); sprintf(slave_str, "/dev/tty%c%x", c, i);
*fd_p = fd;
return slave_str;
}
char *get_pty(int *fd_p) {
if (getenv("BSD_PTY")) {
return get_pty_loop(fd_p);
}
#ifdef IS_BSD
return get_pty_loop(fd_p);
#else
#if LIBVNCSERVER_HAVE_GRANTPT
return get_pty_ptmx(fd_p);
#else
return get_pty_loop(fd_p);
#endif
#endif
}
void try_to_be_nobody(void) {
#if LIBVNCSERVER_HAVE_PWD_H
struct passwd *pw;
pw = getpwnam("nobody"); pw = getpwnam("nobody");
if (pw) { if (pw) {
#if LIBVNCSERVER_HAVE_SETUID
setuid(pw->pw_uid); setuid(pw->pw_uid);
#endif
#if LIBVNCSERVER_HAVE_SETEUID #if LIBVNCSERVER_HAVE_SETEUID
seteuid(pw->pw_uid); seteuid(pw->pw_uid);
#endif #endif
#if LIBVNCSERVER_HAVE_SETGID
setgid(pw->pw_gid); setgid(pw->pw_gid);
#endif
#if LIBVNCSERVER_HAVE_SETEGID #if LIBVNCSERVER_HAVE_SETEGID
setegid(pw->pw_gid); setegid(pw->pw_gid);
#endif #endif
} }
if (getuid() == 0 || geteuid() == 0) { #endif /* PWD_H */
fprintf(stderr, "could not switch to user nobody.\n"); }
exit(1);
static int slave_fd = -1;
static void close_alarm (int sig) {
if (slave_fd >= 0) {
close(slave_fd);
}
}
int su_verify(char *user, char *pass) {
#ifndef UNIXPW
return 0;
#else
int i, j, status, fd = -1, sfd, tfd;
char *slave, *bin_true = NULL, *bin_su = NULL;
pid_t pid, pidw;
struct stat sbuf;
static int first = 1;
char instr[16];
if (first) {
set_db();
first = 0;
}
if (unixpw_list) {
char *p, *q, *str = strdup(unixpw_list);
int ok = 0;
p = strtok(str, ",");
while (p) {
if ( (q = strchr(p, ':')) != NULL ) {
*q = '\0'; /* get rid of options. */
}
if (!strcmp(user, p) || !strcmp("*", p)) {
ok = 1;
break;
}
p = strtok(NULL, ",");
}
free(str);
if (! ok) {
return 0;
}
}
if (stat("/bin/su", &sbuf) == 0) {
bin_su = "/bin/su";
} else if (stat("/usr/bin/su", &sbuf) == 0) {
bin_su = "/usr/bin/su";
}
if (bin_su == NULL) {
rfbLogPerror("existence /bin/su");
return 0;
}
if (stat("/bin/true", &sbuf) == 0) {
bin_true = "/bin/true";
} if (stat("/usr/bin/true", &sbuf) == 0) {
bin_true = "/usr/bin/true";
}
if (bin_true == NULL) {
rfbLogPerror("existence /bin/true");
return 0;
}
slave = get_pty(&fd);
if (slave == NULL) {
rfbLogPerror("get_pty failed.");
return 0;
} }
if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
if (fd < 0) {
rfbLogPerror("get_pty fd < 0");
return 0;
}
fcntl(fd, F_SETFD, 1);
pid = fork();
if (pid < 0) {
rfbLogPerror("fork");
close(fd);
return 0;
}
if (pid == 0) {
int ttyfd;
char tmp[256];
#if LIBVNCSERVER_HAVE_SETSID
if (setsid() == -1) { if (setsid() == -1) {
perror("setsid"); perror("setsid");
exit(1); exit(1);
} }
#else
if (setpgrp() == -1) {
perror("setpgrp");
exit(1);
}
#ifdef TIOCNOTTY #if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCNOTTY)
ttyfd = open("/dev/tty", O_RDWR); ttyfd = open("/dev/tty", O_RDWR);
if (ttyfd >= 0) { if (ttyfd >= 0) {
(void) ioctl(ttyfd, TIOCNOTTY, (char *)0); (void) ioctl(ttyfd, TIOCNOTTY, (char *) 0);
close(ttyfd); close(ttyfd);
} }
#endif #endif
#endif /* SETSID */
close(0); close(0);
close(1); close(1);
close(2); close(2);
sfd = open(slave, O_RDWR); sfd = open(slave, O_RDWR);
if (sfd < 0) { if (sfd < 0) {
fprintf(stderr, "failed: %s\n", slave);
perror("open");
exit(1); exit(1);
} }
#ifdef TIOCSCTTY /* sfd should be 0 since we closed 0. */
if (ioctl(sfd, TIOCSCTTY, (char *) 0) != 0) {
perror("ioctl"); #ifdef F_SETFL
fcntl (sfd, F_SETFL, O_NONBLOCK);
#endif
if (fcntl(sfd, F_DUPFD, 1) == -1) {
exit(1);
}
if (fcntl(sfd, F_DUPFD, 2) == -1) {
exit(1); exit(1);
} }
unlink("/tmp/isatty");
unlink("/tmp/isastream");
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
#if 0
if (isastream(sfd)) {
tfd = open("/tmp/isastream", O_CREAT|O_WRONLY, 0600);
close(tfd);
ioctl(sfd, I_PUSH, "ptem");
ioctl(sfd, I_PUSH, "ldterm");
ioctl(sfd, I_PUSH, "ttcompat");
}
#endif
#if 1
#if defined(TIOCSCTTY) && !defined(sun) && !defined(hpux)
ioctl(sfd, TIOCSCTTY, (char *) 0);
#endif #endif
execlp("/bin/su", "/bin/su", user, "-c", "/bin/true", #endif
(char *) NULL); if (isatty(sfd)) {
char nam[256];
tfd = open("/tmp/isatty", O_CREAT|O_WRONLY, 0600);
close(tfd);
sprintf(nam, "stty -a < %s > /tmp/isatty 2>&1", slave);
system(nam);
}
#endif /* SYS_IOCTL_H */
chdir("/");
try_to_be_nobody();
#if LIBVNCSERVER_HAVE_GETUID
if (getuid() == 0 || geteuid() == 0) {
exit(1);
}
#else
exit(1);
#endif
set_env("LC_ALL", "C");
set_env("LANG", "C");
set_env("SHELL", "/bin/sh");
execlp(bin_su, bin_su, user, "-c", bin_true, (char *) NULL);
exit(1); exit(1);
} }
if (db) fprintf(stderr, "pid: %d\n", pid);
if (db > 3) {
char cmd[32];
usleep( 100 * 1000 );
sprintf(cmd, "ps wu %d", pid);
system(cmd);
sprintf(cmd, "stty -a < %s", slave);
system(cmd);
}
usleep( 500 * 1000 ); usleep( 500 * 1000 );
/* send the password "early" (i.e. before we drain) */
if (0) {
int k;
for (k = 0; k < strlen(pass); k++) {
write(fd, pass+k, 1);
usleep(100 * 1000);
}
} else {
write(fd, pass, strlen(pass)); write(fd, pass, strlen(pass));
}
/*
* set an alarm for blocking read() to close the master
* (presumably terminating the child. we avoid SIGTERM for now)
*/
slave_fd = fd;
signal(SIGALRM, close_alarm);
alarm(10);
/*
* In addition to checking exit code below, we watch for the
* appearance of the string "Password:". BSD does not seem to
* ask for a password trying to su to yourself.
*/
for (i=0; i<16; i++) {
instr[i] = '\0';
}
j = 0;
for (i=0; i < strlen("Password:"); i++) {
char pstr[] = "password:";
char buf[2];
int n;
buf[0] = '\0';
buf[1] = '\0';
n = read(fd, buf, 1);
if (db == 1) fprintf(stderr, "%d ", n, db > 1 ? buf : "");
if (db > 1) fprintf(stderr, "%s", buf);
if (db > 3 && n == 1 && buf[0] == ':') {
char cmd[32];
usleep( 100 * 1000 );
sprintf(cmd, "ps wu %d", pid);
system(cmd);
sprintf(cmd, "stty -a < %s", slave);
system(cmd);
}
if (n == 1) {
if (isspace(buf[0])) {
continue;
}
instr[j++] = tolower(buf[0]);
}
if (n <= 0 || strstr(pstr, instr) != pstr) {
rfbLog("\"Password:\" did not appear: '%s' n=%d\n",
instr, n);
if (db > 3 && n == 1) {
continue;
}
alarm(0);
signal(SIGALRM, SIG_DFL);
slave_fd = -1;
close(fd);
kill(pid, SIGTERM);
waitpid(pid, &status, WNOHANG);
return 0;
}
}
alarm(0);
signal(SIGALRM, SIG_DFL);
usleep( 250 * 1000 );
#if 0
tcdrain(fd);
#endif
signal(SIGALRM, close_alarm);
alarm(15);
/*
* try to drain the output, hopefully never as much as 4096 (motd?)
* if we don't drain we may block at waitpid. If we close(fd), the
* make cause child to die by signal.
*/
for (i = 0; i<4096; i++) {
char buf[2];
int n;
buf[0] = '\0';
buf[1] = '\0';
n = read(fd, buf, 1);
if (db == 1) fprintf(stderr, "%d ", n, db > 1 ? buf : "");
if (db > 1) fprintf(stderr, "%s", buf);
if (n <= 0) {
break;
}
}
if (db) fprintf(stderr, "\n");
alarm(0);
signal(SIGALRM, SIG_DFL);
slave_fd = -1;
pidw = waitpid(pid, &status, 0); pidw = waitpid(pid, &status, 0);
close(fd); close(fd);
@ -241,26 +578,23 @@ static int su_verify(char *user, char *pass) {
return 0; return 0;
} }
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
return 1; return 1; /* this is the only return of success. */
} else { } else {
return 0; return 0;
} }
#else #endif /* UNIXPW */
return 0;
#endif
} }
static int db = 0;
static void unixpw_verify(char *user, char *pass) { static void unixpw_verify(char *user, char *pass) {
int x, y; int x, y;
char li[] = "Login incorrect"; char li[] = "Login incorrect";
char log[] = "login: "; char log[] = "login: ";
if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "********"); if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "********");
rfbLog("unixpw_verify: %s\n", user);
if (su_verify(user, pass)) { if (su_verify(user, pass)) {
unixpw_accept(); unixpw_accept(user);
return; return;
} }
@ -290,16 +624,20 @@ if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "***
} }
} }
static void set_db(void) {
if (getenv("DEBUG_UNIXPW")) {
db = atoi(getenv("DEBUG_UNIXPW"));
}
}
void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) { void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) {
int x, y, i, nmax = 100; int x, y, i, nmax = 100;
static char user[100], pass[100]; static char user[100], pass[100];
static int u_cnt = 0, p_cnt = 0, first = 1; static int u_cnt = 0, p_cnt = 0, first = 1;
char str[100]; char keystr[100];
if (first) { if (first) {
if (getenv("DEBUG_UNIXPW")) { set_db();
db = atoi(getenv("DEBUG_UNIXPW"));
}
first = 0; first = 0;
} }
@ -319,7 +657,18 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) {
return; return;
} }
if (down) { X_LOCK;
sprintf(keystr, "%s", XKeysymToString(keysym));
X_UNLOCK;
if (db > 2) {
fprintf(stderr, "%s / %s 0x%x %s\n", in_login ? "login":"pass ",
down ? "down":"up ", keysym, keystr);
}
if (keysym == XK_Return || keysym == XK_Linefeed) {
; /* let "up" pass down below for Return case */
} else if (! down) {
return; return;
} }
@ -340,6 +689,14 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) {
if (keysym == XK_Return || keysym == XK_Linefeed) { if (keysym == XK_Return || keysym == XK_Linefeed) {
char pw[] = "Password: "; char pw[] = "Password: ";
if (down) {
/*
* require Up so the Return Up is not processed
* by the normal session after login.
*/
return;
}
in_login = 0; in_login = 0;
in_passwd = 1; in_passwd = 1;
@ -360,23 +717,23 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) {
} }
if (u_cnt >= nmax - 1) { if (u_cnt >= nmax - 1) {
rfbLog("unixpw_deny: username too long\n"); rfbLog("unixpw_deny: username too long\n");
for (i=0; i<nmax; i++) {
user[i] = '\0';
pass[i] = '\0';
}
unixpw_deny(); unixpw_deny();
return; return;
} }
X_LOCK; user[u_cnt++] = keystr[0];
sprintf(str, "%s", XKeysymToString(keysym));
X_UNLOCK;
user[u_cnt++] = str[0];
x = text_x(); x = text_x();
y = text_y(); y = text_y();
if (db) fprintf(stderr, "u_cnt: %d %d/%d ks: 0x%x %s\n", u_cnt, x, y, keysym, str); if (db && db <= 2) fprintf(stderr, "u_cnt: %d %d/%d ks: 0x%x %s\n", u_cnt, x, y, keysym, keystr);
str[1] = '\0'; keystr[1] = '\0';
rfbDrawString(screen, &default8x16Font, x, y, str, white()); rfbDrawString(screen, &default8x16Font, x, y, keystr, white());
mark_rect_as_modified(x, y-char_h, x+char_w, y, 0); mark_rect_as_modified(x, y-char_h, x+char_w, y, 0);
char_col++; char_col++;
@ -390,10 +747,21 @@ if (db) fprintf(stderr, "u_cnt: %d %d/%d ks: 0x%x %s\n", u_cnt, x, y, keysym, s
return; return;
} }
if (keysym == XK_Return || keysym == XK_Linefeed) { if (keysym == XK_Return || keysym == XK_Linefeed) {
if (down) {
/*
* require Up so the Return Up is not processed
* by the normal session after login.
*/
return;
}
in_login = 0; in_login = 0;
in_passwd = 0; in_passwd = 0;
pass[p_cnt++] = '\n'; pass[p_cnt++] = '\n';
unixpw_verify(user, pass); unixpw_verify(user, pass);
for (i=0; i<nmax; i++) {
user[i] = '\0';
pass[i] = '\0';
}
return; return;
} }
if (keysym <= ' ' || keysym >= 0x7f) { if (keysym <= ' ' || keysym >= 0x7f) {
@ -401,14 +769,86 @@ if (db) fprintf(stderr, "u_cnt: %d %d/%d ks: 0x%x %s\n", u_cnt, x, y, keysym, s
} }
if (p_cnt >= nmax - 2) { if (p_cnt >= nmax - 2) {
rfbLog("unixpw_deny: password too long\n"); rfbLog("unixpw_deny: password too long\n");
for (i=0; i<nmax; i++) {
user[i] = '\0';
pass[i] = '\0';
}
unixpw_deny(); unixpw_deny();
return; return;
} }
pass[p_cnt++] = (char) keysym; pass[p_cnt++] = (char) keysym;
} else {
/* should not happen... clean up a bit. */
u_cnt = 0;
p_cnt = 0;
for (i=0; i<nmax; i++) {
user[i] = '\0';
pass[i] = '\0';
}
}
}
static void apply_opts (char *user) {
char *p, *q, *str, *opts = NULL, *opts_star = NULL;
ClientData *cd = (ClientData *) unixpw_client->clientData;
rfbClientPtr cl = unixpw_client;
int i;
if (! unixpw_list) {
return;
}
str = strdup(unixpw_list);
/* apply any per-user options. */
p = strtok(str, ",");
while (p) {
if ( (q = strchr(p, ':')) != NULL ) {
*q = '\0'; /* get rid of options. */
} else {
p = strtok(NULL, ",");
continue;
}
if (!strcmp(user, p)) {
opts = strdup(q+1);
}
if (!strcmp("*", p)) {
opts_star = strdup(q+1);
}
p = strtok(NULL, ",");
}
free(str);
for (i=0; i < 2; i++) {
char *s = (i == 0) ? opts_star : opts;
if (s == NULL) {
continue;
}
p = strtok(s, "+");
while (p) {
if (!strcmp(p, "viewonly")) {
cl->viewOnly = TRUE;
strncpy(cd->input, "-", CILEN);
} else if (!strcmp(p, "fullaccess")) {
cl->viewOnly = FALSE;
strncpy(cd->input, "-", CILEN);
} else if ((q = strstr(p, "input=")) == p) {
q += strlen("input=");
strncpy(cd->input, q, CILEN);
} else if (!strcmp(p, "deny")) {
cl->viewOnly = TRUE;
unixpw_deny();
break;
}
p = strtok(NULL, "+");
}
free(s);
} }
} }
void unixpw_accept(void) { void unixpw_accept(char *user) {
apply_opts(user);
unixpw_in_progress = 0; unixpw_in_progress = 0;
unixpw_client = NULL; unixpw_client = NULL;
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);

@ -5,8 +5,9 @@
extern void unixpw_screen(int init); extern void unixpw_screen(int init);
extern void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init); extern void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init);
extern void unixpw_accept(void); extern void unixpw_accept(char *user);
extern void unixpw_deny(void); extern void unixpw_deny(void);
extern int su_verify(char *user, char *pass);
extern int unixpw_in_progress; extern int unixpw_in_progress;
extern time_t unixpw_last_try_time; extern time_t unixpw_last_try_time;

@ -1,8 +1,8 @@
.\" This file was automatically generated from x11vnc -help output. .\" This file was automatically generated from x11vnc -help output.
.TH X11VNC "1" "February 2006" "x11vnc " "User Commands" .TH X11VNC "1" "March 2006" "x11vnc " "User Commands"
.SH NAME .SH NAME
x11vnc - allow VNC connections to real X11 displays x11vnc - allow VNC connections to real X11 displays
version: 0.8.1, lastmod: 2006-02-24 version: 0.8.1, lastmod: 2006-03-02
.SH SYNOPSIS .SH SYNOPSIS
.B x11vnc .B x11vnc
[OPTION]... [OPTION]...
@ -497,9 +497,10 @@ full-access passwords)
Experimental option: use Unix username and password Experimental option: use Unix username and password
authentication. x11vnc uses the authentication. x11vnc uses the
.IR su (1) .IR su (1)
program to program to verify
verify the user's password. [list] is an optional the user's password. [list] is an optional comma
comma separated list of allowed Unix usernames. separated list of allowed Unix usernames. See below
for per-user options that can be applied.
.IP .IP
A familiar "login:" and "Password:" dialog is A familiar "login:" and "Password:" dialog is
presented to the user on a black screen inside the presented to the user on a black screen inside the
@ -508,6 +509,25 @@ to supply the correct password in 3 tries or does not
send one before a 20 second timeout. Existing clients send one before a 20 second timeout. Existing clients
are view-only during this period. are view-only during this period.
.IP .IP
Since the detailed behavior of
.IR su (1)
can vary from
OS to OS and for local configurations, please test
the mode carefully on your systems before using it.
Try different combinations of valid/invalid usernames
and passwords.
.IP
For example, on FreeBSD and the other BSD's and Tru64
it does not appear to be possible for the user running
x11vnc to validate his *own* password via
.IR su (1).
The x11vnc login will always fail in this case.
A possible workaround would be to start x11vnc as
root with the "\fB-users\fR \fI+nobody\fR" option to immediately
switch to user nobody. Another source of problems are
PAM modules that prompt for extra info, e.g. password
aging modules. These logins will always fail as well.
.IP
*IMPORTANT*: to prevent the Unix password being sent in *IMPORTANT*: to prevent the Unix password being sent in
*clear text* over the network, two x11vnc options are *clear text* over the network, two x11vnc options are
enforced: 1) \fB-localhost\fR and 2) \fB-stunnel.\fR The former enforced: 1) \fB-localhost\fR and 2) \fB-stunnel.\fR The former
@ -531,6 +551,15 @@ with
user login (since Unix password or the user's public user login (since Unix password or the user's public
key authentication is used by ssh) key authentication is used by ssh)
.IP .IP
As a convenience, if you
.IR ssh (1)
in and start x11vnc
it will look to see if the environment variable
SSH_CONNECTION is set and appears reasonable. If it
does, then the stunnel requirement is dropped since
it is assumed you are using ssh for the encrypted
tunnelling. Use \fB-stunnel\fR to force stunnel usage.
.IP
Set UNIXPW_DISABLE_LOCALHOST=1 to disable the \fB-localhost\fR Set UNIXPW_DISABLE_LOCALHOST=1 to disable the \fB-localhost\fR
requirement. One should never do this (i.e. allow the requirement. One should never do this (i.e. allow the
Unix passwords to be sniffed on the network). Unix passwords to be sniffed on the network).
@ -539,7 +568,19 @@ NOTE: in \fB-inetd\fR mode the two settings are not enforced
since x11vnc does not make network connections in since x11vnc does not make network connections in
that case. Be sure to use encryption from the viewer that case. Be sure to use encryption from the viewer
to inetd. One can also have your own stunnel spawn to inetd. One can also have your own stunnel spawn
x11vnc in \fB-inetd\fR mode. x11vnc in \fB-inetd\fR mode. See the FAQ.
.IP
The user names in the comma separated [list] can have
per-user options after a ":", e.g. "fred:opts"
where "opts" is a "+" separated list of
"viewonly", "fullaccess", "input=XXXX", or
"deny", e.g. "karl,fred:viewonly,boss:input=M".
For "input=" it is the K,M,B,C describe under \fB-input.\fR
.IP
If a user in the list is "*" that means those options
apply to all users. It also means all users are allowed
to log in. Use "deny" to explicitly deny some users
if you use "*" to set a global option.
.PP .PP
\fB-stunnel\fR \fI[pem]\fR \fB-stunnel\fR \fI[pem]\fR
.IP .IP
@ -549,17 +590,22 @@ Use the
encrypted SSL tunnel between viewers and x11vnc. encrypted SSL tunnel between viewers and x11vnc.
This requires stunnel be installed on the system and This requires stunnel be installed on the system and
available via PATH (n.b. stunnel is often installed in available via PATH (n.b. stunnel is often installed in
sbin directories). Version 4.x of stunnel is assumed. sbin directories). Version 4.x of stunnel is assumed;
see \fB-stunnel3\fR below.
.IP .IP
[pem] is optional, use "\fB-stunnel\fR \fI/path/to/stunnel.pem\fR" [pem] is optional, use "\fB-stunnel\fR \fI/path/to/stunnel.pem\fR"
to specify a PEM certificate file to pass to stunnel. to specify a PEM certificate file to pass to stunnel.
Whether one is needed or not depends on your stunnel
configuration.
.IP .IP
stunnel is started up as a child process and any SSL stunnel is started up as a child process of x11vnc and
connections it receives are decrypted and sent to x11vnc any SSL connections stunnel receives are decrypted and
over a local socket. The strings "The SSL VNC desktop sent to x11vnc over a local socket. The strings "The
is ..." and SSLPORT=... are printed out at startup. SSL VNC desktop is ..." and SSLPORT=... are printed
out at startup.
.IP .IP
The \fB-localhost\fR option is enforced by default. Set The \fB-localhost\fR option is enforced by default to
avoid people routing around the SSL channel. Set
STUNNEL_DISABLE_LOCALHOST=1 to disable the requirement. STUNNEL_DISABLE_LOCALHOST=1 to disable the requirement.
.IP .IP
Your VNC viewer will need to be able to connect via SSL. Your VNC viewer will need to be able to connect via SSL.
@ -573,7 +619,8 @@ A simple example on Unix using stunnel 3.x is:
% vncviewer localhost:1 % vncviewer localhost:1
.IP .IP
For Windows, stunnel has been ported to it and there For Windows, stunnel has been ported to it and there
are probably other such tools available. are probably other such tools available. See the FAQ
for more examples.
.PP .PP
\fB-stunnel3\fR \fI[pem]\fR \fB-stunnel3\fR \fI[pem]\fR
.IP .IP
@ -685,8 +732,9 @@ Example: \fB-afteraccept\fR 'killall xlock &'
As \fB-accept,\fR except to run a user supplied command when As \fB-accept,\fR except to run a user supplied command when
a client goes away (disconnects). RFB_MODE will be a client goes away (disconnects). RFB_MODE will be
set to "gone" and the other RFB_* variables are as set to "gone" and the other RFB_* variables are as
in \fB-accept.\fR Unlike \fB-accept,\fR the command return code in \fB-accept.\fR The "popup" actions apply as well.
is not interpreted by x11vnc. Example: \fB-gone\fR 'xlock &' Unlike \fB-accept,\fR the command return code is not
interpreted by x11vnc. Example: \fB-gone\fR 'xlock &'
.PP .PP
\fB-users\fR \fIlist\fR \fB-users\fR \fIlist\fR
.IP .IP
@ -2183,6 +2231,10 @@ timeout:n reset \fB-timeout\fR to n, if there are
currently no clients, exit unless one currently no clients, exit unless one
connects in the next n secs. connects in the next n secs.
.IP .IP
filexfer enable filetransfer for new clients.
.IP
nofilexfer disable filetransfer for new clients.
.IP
http enable http client connections. http enable http client connections.
.IP .IP
nohttp disable http client connections. nohttp disable http client connections.
@ -2600,11 +2652,11 @@ nowaitmapped clip flashcmap noflashcmap shiftcmap
truecolor notruecolor overlay nooverlay overlay_cursor truecolor notruecolor overlay nooverlay overlay_cursor
overlay_yescursor nooverlay_nocursor nooverlay_cursor overlay_yescursor nooverlay_nocursor nooverlay_cursor
nooverlay_yescursor overlay_nocursor 8to24 no8to24 nooverlay_yescursor overlay_nocursor 8to24 no8to24
8to24_opts visual scale scale_cursor viewonly 8to24_opts visual scale scale_cursor viewonly noviewonly
noviewonly shared noshared forever noforever once shared noshared forever noforever once timeout filexfer
timeout filexfer deny lock nodeny unlock connect nofilexfer deny lock nodeny unlock connect allowonce
allowonce allow localhost nolocalhost listen lookup allow localhost nolocalhost listen lookup nolookup
nolookup accept afteraccept gone shm noshm flipbyteorder accept afteraccept gone shm noshm flipbyteorder
noflipbyteorder onetile noonetile solid_color solid noflipbyteorder onetile noonetile solid_color solid
nosolid blackout xinerama noxinerama xtrap noxtrap nosolid blackout xinerama noxinerama xtrap noxtrap
xrandr noxrandr xrandr_mode padgeom quiet q noquiet xrandr noxrandr xrandr_mode padgeom quiet q noquiet
@ -2643,14 +2695,15 @@ http_url auth xauth users rootshift clipshift
scale_str scaled_x scaled_y scale_numer scale_denom scale_str scaled_x scaled_y scale_numer scale_denom
scale_fac scaling_blend scaling_nomult4 scaling_pad scale_fac scaling_blend scaling_nomult4 scaling_pad
scaling_interpolate inetd privremote unsafe safer nocmds scaling_interpolate inetd privremote unsafe safer nocmds
passwdfile using_shm logfile o flag rc norc h help V passwdfile unixpw unixpw_list stunnel stunnel_pem
version lastmod bg sigpipe threads readrate netrate using_shm logfile o flag rc norc h help V version
netlatency pipeinput clients client_count pid ext_xtest lastmod bg sigpipe threads readrate netrate netlatency
ext_xtrap ext_xrecord ext_xkb ext_xshm ext_xinerama pipeinput clients client_count pid ext_xtest ext_xtrap
ext_overlay ext_xfixes ext_xdamage ext_xrandr rootwin ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay
num_buttons button_mask mouse_x mouse_y bpp depth ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons
indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y button_mask mouse_x mouse_y bpp depth indexed_color
cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd dpy_x dpy_y wdpy_x wdpy_y off_x off_y cdpy_x cdpy_y
coff_x coff_y rfbauth passwd viewpasswd
.PP .PP
\fB-QD\fR \fIvariable\fR \fB-QD\fR \fIvariable\fR
.IP .IP

@ -904,6 +904,7 @@ static void print_settings(int try_http, int bg, char *gui_str) {
fprintf(stderr, "Settings:\n"); fprintf(stderr, "Settings:\n");
fprintf(stderr, " display: %s\n", use_dpy ? use_dpy fprintf(stderr, " display: %s\n", use_dpy ? use_dpy
: "null"); : "null");
#if SMALL_FOOTPRINT < 2
fprintf(stderr, " authfile: %s\n", auth_file ? auth_file fprintf(stderr, " authfile: %s\n", auth_file ? auth_file
: "null"); : "null");
fprintf(stderr, " subwin: 0x%lx\n", subwin); fprintf(stderr, " subwin: 0x%lx\n", subwin);
@ -940,6 +941,7 @@ static void print_settings(int try_http, int bg, char *gui_str) {
fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile
: "null"); : "null");
fprintf(stderr, " unixpw: %d\n", unixpw); fprintf(stderr, " unixpw: %d\n", unixpw);
fprintf(stderr, " unixpw_lst: %s\n", unixpw_list ? unixpw_list:"null");
fprintf(stderr, " stunnel: %d\n", use_stunnel); fprintf(stderr, " stunnel: %d\n", use_stunnel);
fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd
: "null"); : "null");
@ -1073,6 +1075,7 @@ static void print_settings(int try_http, int bg, char *gui_str) {
fprintf(stderr, " nocmds: %d\n", no_external_cmds); fprintf(stderr, " nocmds: %d\n", no_external_cmds);
fprintf(stderr, " deny_all: %d\n", deny_all); fprintf(stderr, " deny_all: %d\n", deny_all);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif
rfbLog("x11vnc version: %s\n", lastmod); rfbLog("x11vnc version: %s\n", lastmod);
} }
@ -1282,6 +1285,7 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-overlay_yescursor")) { } else if (!strcmp(arg, "-overlay_yescursor")) {
overlay = 1; overlay = 1;
overlay_cursor = 2; overlay_cursor = 2;
#if !SKIP_8TO24
} else if (!strcmp(arg, "-8to24")) { } else if (!strcmp(arg, "-8to24")) {
cmap8to24 = 1; cmap8to24 = 1;
if (i < argc-1) { if (i < argc-1) {
@ -1291,6 +1295,7 @@ int main(int argc, char* argv[]) {
i++; i++;
} }
} }
#endif
} else if (!strcmp(arg, "-visual")) { } else if (!strcmp(arg, "-visual")) {
CHECK_ARGC CHECK_ARGC
visual_str = strdup(argv[++i]); visual_str = strdup(argv[++i]);
@ -1359,14 +1364,36 @@ int main(int argc, char* argv[]) {
CHECK_ARGC CHECK_ARGC
passwdfile = strdup(argv[++i]); passwdfile = strdup(argv[++i]);
got_passwdfile = 1; got_passwdfile = 1;
} else if (!strcmp(arg, "-unixpw")) { } else if (!strcmp(arg, "-unixpw")
|| !strcmp(arg, "-unixpw_unsafe")) {
unixpw = 1; unixpw = 1;
if (i < argc-1) { if (i < argc-1) {
char *s = argv[i+1]; char *p, *q, *s = argv[i+1];
if (s[0] != '-') { if (s[0] != '-') {
unixpw_list = strdup(s); unixpw_list = strdup(s);
i++; i++;
} }
if (s[0] == '%') {
p = unixpw_list;
unixpw_list = NULL;
strcpy(p, s+1);
strcat(p, "\n"); /* just fits */
if ((q = strchr(p, ':')) == NULL) {
exit(1);
}
*q = '\0';
if (su_verify(p, q+1)) {
fprintf(stderr, "\nY\n");
} else {
fprintf(stderr, "\nN\n");
}
exit(0);
}
}
if (!strcmp(arg, "-unixpw_unsafe")) {
/* hidden option for testing. */
set_env("UNIXPW_DISABLE_STUNNEL", "1");
set_env("UNIXPW_DISABLE_LOCALHOST", "1");
} }
} else if (!strcmp(arg, "-stunnel")) { } else if (!strcmp(arg, "-stunnel")) {
use_stunnel = 1; use_stunnel = 1;
@ -2079,12 +2106,16 @@ int main(int argc, char* argv[]) {
allow_list = strdup("127.0.0.1"); allow_list = strdup("127.0.0.1");
got_localhost = 1; got_localhost = 1;
} }
if (! got_stunnel && ! getenv("UNIXPW_DISABLE_STUNNEL")) { if (! got_stunnel) {
if (! getenv("UNIXPW_DISABLE_STUNNEL") &&
! have_ssh_env()) {
if (! quiet) { if (! quiet) {
rfbLog("Setting -stunnel in -unixpw mode.\n"); rfbLog("Setting -stunnel in -unixpw "
"mode.\n");
} }
use_stunnel = 1; use_stunnel = 1;
} }
}
} else if (use_stunnel) { } else if (use_stunnel) {
if (! got_localhost && ! getenv("STUNNEL_DISABLE_LOCALHOST")) { if (! got_localhost && ! getenv("STUNNEL_DISABLE_LOCALHOST")) {

@ -116,15 +116,18 @@
#define NOGUI #define NOGUI
#endif #endif
#define SKIP_XKB 0
#define SKIP_8TO24 0
#if (SMALL_FOOTPRINT > 1) #if (SMALL_FOOTPRINT > 1)
#undef LIBVNCSERVER_HAVE_XKEYBOARD #undef SKIP_XKB
#undef SKIP_8TO24
#undef LIBVNCSERVER_HAVE_LIBXINERAMA #undef LIBVNCSERVER_HAVE_LIBXINERAMA
#undef LIBVNCSERVER_HAVE_LIBXRANDR
#undef LIBVNCSERVER_HAVE_LIBXFIXES #undef LIBVNCSERVER_HAVE_LIBXFIXES
#undef LIBVNCSERVER_HAVE_LIBXDAMAGE #undef LIBVNCSERVER_HAVE_LIBXDAMAGE
#define LIBVNCSERVER_HAVE_XKEYBOARD 0 #define SKIP_XKB 1
#define SKIP_8TO24 1
#define LIBVNCSERVER_HAVE_LIBXINERAMA 0 #define LIBVNCSERVER_HAVE_LIBXINERAMA 0
#define LIBVNCSERVER_HAVE_LIBXRANDR 0
#define LIBVNCSERVER_HAVE_LIBXFIXES 0 #define LIBVNCSERVER_HAVE_LIBXFIXES 0
#define LIBVNCSERVER_HAVE_LIBXDAMAGE 0 #define LIBVNCSERVER_HAVE_LIBXDAMAGE 0
#endif #endif

@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0; int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */ /* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.8.1 lastmod: 2006-02-24"; char lastmod[] = "0.8.1 lastmod: 2006-03-02";
/* X display info */ /* X display info */

Loading…
Cancel
Save