Commit abbdf92a authored by runge's avatar runge

x11vnc: add UltraVNC repeater proxy support. fix to setp gui

        mode. -threads is now strongly discouraged.  Read PORT= in url.
        User can set nolisten for Xvfb in -create mode.  clean up
        wait_for_client() to some degree.
parent d8812f8c
2008-05-07 Karl Runge <runge@karlrunge.com>
* x11vnc: add UltraVNC repeater proxy support. fix to setp gui
mode. -threads is now strongly discouraged. Read PORT= in url.
User can set nolisten for Xvfb in -create mode. clean up
wait_for_client() to some degree.
2008-01-31 Karl Runge <runge@karlrunge.com>
* x11vnc: during speeds estimate, guard against client
disconnecting. ssvnc sync.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2149,15 +2149,95 @@ static int proxy_connect(char *host, int port) {
return psock;
}
char *get_repeater_string(char *str, int *len) {
int pren, which = 0;
int prestring_len = 0;
char *prestring = NULL, *ptmp = NULL;
char *equals = strchr(str, '=');
char *plus = strrchr(str, '+');
*len = 0;
if (!plus || !equals) {
return NULL;
}
*plus = '\0';
if (strstr(str, "repeater=") == str) {
/* ultravnc repeater http://www.uvnc.com/addons/repeater.html */
prestring_len = 250;
ptmp = (char *) calloc(prestring_len+1, 1);
snprintf(ptmp, 250, "%s", str + strlen("repeater="));
which = 1;
} else if (strstr(str, "pre=") == str) {
prestring_len = strlen(str + strlen("pre="));
ptmp = (char *) calloc(prestring_len+1, 1);
snprintf(ptmp, prestring_len+1, "%s", str + strlen("pre="));
which = 2;
} else if (sscanf(str, "pre%d=", &pren) == 1) {
if (pren > 0 && pren <= 16384) {
prestring_len = pren;
ptmp = (char *) calloc(prestring_len+1, 1);
snprintf(prestring, prestring_len, "%s", equals+1);
which = 3;
}
}
if (ptmp != NULL) {
int i, k = 0;
char *p = ptmp;
prestring = (char *)calloc(prestring_len+1, 1);
/* translate \n to newline, etc. */
for (i=0; i < prestring_len; i++) {
if (i < prestring_len-1 && *(p+i) == '\\') {
if (*(p+i+1) == 'r') {
prestring[k++] = '\r'; i++;
} else if (*(p+i+1) == 'n') {
prestring[k++] = '\n'; i++;
} else if (*(p+i+1) == 't') {
prestring[k++] = '\t'; i++;
} else if (*(p+i+1) == 'a') {
prestring[k++] = '\a'; i++;
} else if (*(p+i+1) == 'b') {
prestring[k++] = '\b'; i++;
} else if (*(p+i+1) == 'v') {
prestring[k++] = '\v'; i++;
} else if (*(p+i+1) == 'f') {
prestring[k++] = '\f'; i++;
} else if (*(p+i+1) == '\\') {
prestring[k++] = '\\'; i++;
} else if (*(p+i+1) == 'c') {
prestring[k++] = ','; i++;
} else {
prestring[k++] = *(p+i);
}
} else {
prestring[k++] = *(p+i);
}
}
if (which == 2) {
prestring_len = k;
}
if (!quiet) {
rfbLog("-connect prestring: '%s'\n", prestring);
}
free(ptmp);
}
*plus = '+';
*len = prestring_len;
return prestring;
}
/*
* Do a reverse connect for a single "host" or "host:port"
*/
extern int ssl_client_mode;
static int do_reverse_connect(char *str) {
static int do_reverse_connect(char *str_in) {
rfbClientPtr cl;
char *host, *p;
char *host, *p, *str = str_in, *s = NULL;
char *prestring = NULL;
int prestring_len = 0;
int rport = 5500, len = strlen(str);
if (len < 1) {
......@@ -2173,6 +2253,24 @@ static int do_reverse_connect(char *str) {
}
if (unixpw_in_progress) return 0;
/* look for repeater pre-string */
if (strchr(str, '=') && strrchr(str, '+')
&& (strstr(str, "pre") == str || strstr(str, "repeater=") == str)) {
prestring = get_repeater_string(str, &prestring_len);
str = strrchr(str, '+') + 1;
} else if (strrchr(str, '+') && strstr(str, "repeater://") == str) {
/* repeater://host:port+string */
/* repeater=string+host:port */
char *plus = strrchr(str, '+');
str = (char *) malloc(strlen(str_in)+1);
s = str;
*plus = '\0';
sprintf(str, "repeater=%s+%s", plus+1, str_in + strlen("repeater://"));
prestring = get_repeater_string(str, &prestring_len);
str = strrchr(str, '+') + 1;
*plus = '+';
}
/* copy in to host */
host = (char *) malloc(len+1);
if (! host) {
......@@ -2204,10 +2302,15 @@ static int do_reverse_connect(char *str) {
rfbLog("reverse_connect: failed to connect to: %s\n", str);
return 0;
}
if (prestring != NULL) {
write(vncsock, prestring, prestring_len);
free(prestring);
}
#define OPENSSL_REVERSE 4
openssl_init(1);
accept_openssl(OPENSSL_REVERSE, vncsock);
openssl_init(0);
free(host);
return 1;
}
if (use_stunnel) {
......@@ -2220,17 +2323,17 @@ static int do_reverse_connect(char *str) {
}
if (unixpw) {
int is_localhost = 0, user_disabled = 0;
int is_localhost = 0, user_disabled_it = 0;
if(!strcmp(host, "localhost") || !strcmp(host, "127.0.0.1")) {
is_localhost = 1;
}
if (getenv("UNIXPW_DISABLE_LOCALHOST")) {
user_disabled = 1;
user_disabled_it = 1;
}
if (! is_localhost) {
if (user_disabled ) {
if (user_disabled_it) {
rfbLog("reverse_connect: warning disabling localhost constraint in -unixpw\n");
} else {
rfbLog("reverse_connect: error not localhost in -unixpw\n");
......@@ -2242,6 +2345,19 @@ static int do_reverse_connect(char *str) {
if (connect_proxy != NULL) {
int sock = proxy_connect(host, rport);
if (sock >= 0) {
if (prestring != NULL) {
write(sock, prestring, prestring_len);
free(prestring);
}
cl = rfbNewClient(screen, sock);
} else {
return 0;
}
} else if (prestring != NULL) {
int sock = rfbConnectToTcpAddr(host, rport);
if (sock >= 0) {
write(sock, prestring, prestring_len);
free(prestring);
cl = rfbNewClient(screen, sock);
} else {
return 0;
......
......@@ -558,8 +558,11 @@ void do_gui(char *opts, int sleep) {
if ((q = strchr(p, '=')) != NULL) {
icon_mode_font = strdup(q+1);
}
} else if (!strcmp(p, "full")) {
;
} else if (strstr(p, "full") == p) {
if (strstr(p, "setp") && 0) {
set_env("X11VNC_ICON_MODE", "2");
set_env("X11VNC_ICON_SETPASS", "2");
}
} else if (strstr(p, "tray") == p || strstr(p, "icon") == p) {
char *q;
icon_mode = 1;
......
......@@ -429,6 +429,46 @@ void print_help(int mode) {
" Be careful about the location of this file if x11vnc\n"
" is running as root (e.g. via gdm(1), etc).\n"
"\n"
"\n"
" Repeater mode: Some services provide an intermediate\n"
" \"vnc repeater\": http://www.uvnc.com/addons/repeater.html\n"
" (and also http://koti.mbnet.fi/jtko/ for linux port)\n"
" that acts as a proxy / gateway. Modes like these require\n"
" an initial string to be sent for the reverse connection\n"
" before the VNC protocol is started. Here are the ways\n"
" to do this:\n"
"\n"
" -connect pre=some_string+host:port\n"
" -connect pre128=some_string+host:port\n"
" -connect repeater=ID:1234+host:port\n"
" -connect repeater=23.45.67.89::5501+host:port\n"
"\n"
" SSVNC notation is also supported:\n"
"\n"
" -connect repeater://host:port+ID:1234\n"
"\n"
" As with normal -connect usage, if the repeater port is\n"
" not supplied 5500 is assumed.\n"
"\n"
" The basic idea is between the special tag, e.g. \"pre=\"\n"
" and \"+\" is the pre-string to be sent. Note that in\n"
" this case host:port is the repeater server, NOT the\n"
" vnc viewer. Somehow the pre-string tells the repeater\n"
" server how to find the vnc viewer and connect you to it.\n"
"\n"
" In the case pre=some_string+host:port, \"some_string\"\n"
" is simply sent. In the case preNNN=some_string+host:port\n"
" \"some_string\" is sent in a null padded buffer of\n"
" length NNN. repeater= is the same as pre250=, this is\n"
" the ultravnc repeater buffer size.\n"
"\n"
" Strings like \"\\n\" and \"\\r\", etc. are expanded to\n"
" newline and carriage return. \"\\c\" is expanded to\n"
" \",\" since the connect string is comma separated.\n"
"\n"
" See also the -proxy option below for additional ways\n"
" to plumb reverse connections.\n"
"\n"
"-connect_or_exit str As with -connect, except if none of the reverse\n"
" connections succeed, then x11vnc shutdowns immediately.\n"
"\n"
......@@ -896,6 +936,10 @@ void print_help(int mode) {
" and so \"-ssl SAVE -redirect host:port\" can act as a\n"
" replacement for stunnel(1).\n"
"\n"
" This mode only allows one redirected connection.\n"
" The -forever option does not apply. Use -inetd or\n"
" -loop for persistant service.\n"
"\n"
"-display WAIT:... A special usage mode for the normal -display option.\n"
" Useful with -unixpw, but can be used independently\n"
" of it. If the display string begins with WAIT: then\n"
......@@ -3075,8 +3119,8 @@ void print_help(int mode) {
"-forcedpms If the system supports the DPMS (Display Power\n"
" Management Signaling) extension, then try to keep the\n"
" monitor in a powered off state. This is to prevent\n"
" nosey people at the physical display from viewing\n"
" what is on the screen. Be sure lock the screen before\n"
" nosey people at the physical display from viewing what\n"
" is on the screen. Be sure to lock the screen before\n"
" disconnecting.\n"
"\n"
" This method is far from bullet proof, e.g. suppose\n"
......@@ -3151,7 +3195,11 @@ void print_help(int mode) {
"\n"
"-threads Whether or not to use the threaded libvncserver\n"
"-nothreads algorithm [rfbRunEventLoop] if libpthread is available\n"
" Default: %s\n"
" Default: %s. NOTE: The -threads mode is now\n"
" disabled due to its unstable behavior. Not recommended,\n"
" but you can recompile with -DX11VNC_THREADED in\n"
" CPPFLAGS if you need to use it. You can also set the\n"
" env. variable X11VNC_THREADED=1\n"
"\n"
"-fs f If the fraction of changed tiles in a poll is greater\n"
" than f, the whole screen is updated. Default: %.2f\n"
......
......@@ -414,7 +414,7 @@ int verbose = 0;
/* threaded vs. non-threaded (default) */
#if LIBVNCSERVER_HAVE_LIBPTHREAD && defined(X11VNC_THREADED)
int use_threads = 1;
int use_threads = 0; /* not 1. now X11VNC_THREADED means enable it at all. */
#else
int use_threads = 0;
#endif
......
......@@ -881,7 +881,10 @@ void scale_rect(double factor, int blend, int interpolate, int Bpp,
j1 = nfix(j1, ny);
j2 = nfix(j2, ny) + 1;
/* special case integer magnification with no blending */
/*
* special case integer magnification with no blending.
* vision impaired magnification usage is interested in this case.
*/
if (mark && ! blend && mag_int && Bpp != 3) {
int jmin, jmax, imin, imax;
......@@ -1122,14 +1125,10 @@ void scale_rect(double factor, int blend, int interpolate, int Bpp,
*/
if (Bpp == 4) {
/* unroll the loops, can give 20% */
pixave[0] += w *
((unsigned char) *(src ));
pixave[1] += w *
((unsigned char) *(src+1));
pixave[2] += w *
((unsigned char) *(src+2));
pixave[3] += w *
((unsigned char) *(src+3));
pixave[0] += w * ((unsigned char) *(src ));
pixave[1] += w * ((unsigned char) *(src+1));
pixave[2] += w * ((unsigned char) *(src+2));
pixave[3] += w * ((unsigned char) *(src+3));
} else if (Bpp == 2) {
/*
* 16bpp: trickier with green
......
......@@ -1567,6 +1567,9 @@ void accept_openssl(int mode, int presock) {
if (screen->httpListenSock >= 0 && screen->httpPort > 0) {
have_httpd = 1;
}
if (screen->httpListenSock == -2) {
have_httpd = 1;
}
if (mode == OPENSSL_HTTPS && ! have_httpd) {
rfbLog("SSL: accept_openssl[%d]: no httpd socket for "
"-https mode\n", getpid());
......@@ -1695,10 +1698,11 @@ void accept_openssl(int mode, int presock) {
/* send the failure tag: */
strcpy(tbuf, uniq);
if (https_port_redir < 0) {
if (https_port_redir < 0 || (strstr(buf, "PORT=") || strstr(buf, "port="))) {
char *q = strstr(buf, "Host:");
int fport = 443;
int fport = 443, match = 0;
char num[16];
if (q && strstr(q, "\n")) {
q += strlen("Host:") + 1;
while (*q != '\n') {
......@@ -1706,12 +1710,25 @@ void accept_openssl(int mode, int presock) {
if (*q == ':' && sscanf(q, ":%d", &p) == 1) {
if (p > 0 && p < 65536) {
fport = p;
match = 1;
break;
}
}
q++;
}
}
if (!match || !https_port_redir) {
int p;
if (sscanf(buf, "PORT=%d,", &p) == 1) {
if (p > 0 && p < 65536) {
fport = p;
}
} else if (sscanf(buf, "port=%d,", &p) == 1) {
if (p > 0 && p < 65536) {
fport = p;
}
}
}
sprintf(num, "HP=%d,", fport);
strcat(tbuf, num);
}
......
......@@ -1400,32 +1400,32 @@ char create_display[] =
" else\n"
" sxcmd=$have_xinit\n"
" fi\n"
" echo \"$sxcmd $sess -- $* -nolisten tcp -auth $authfile $FD_OPTS\" 1>&2\n"
" echo \"$sxcmd $sess -- $* $nolisten -auth $authfile $FD_OPTS\" 1>&2\n"
" if [ \"X$have_root\" != \"X\" ]; then\n"
" $sxcmd $sess -- $* -nolisten tcp -auth $authfile $FD_OPTS 1>&2 &\n"
" $sxcmd $sess -- $* $nolisten -auth $authfile $FD_OPTS 1>&2 &\n"
" else\n"
" if [ \"X$ns\" = \"X0\" ]; then\n"
" $have_nohup sh -c \"$sxcmd $sess -- $* -nolisten tcp -auth $authfile $FD_OPTS\" 1>&2 &\n"
" $have_nohup sh -c \"$sxcmd $sess -- $* $nolisten -auth $authfile $FD_OPTS\" 1>&2 &\n"
" else\n"
" # Why did we ever sleep before starting the server??\n"
" $have_nohup sh -c \"(sleep $ns; $sxcmd $sess -- $* -nolisten tcp -auth $authfile $FD_OPTS)\" 1>&2 &\n"
" $have_nohup sh -c \"(sleep $ns; $sxcmd $sess -- $* $nolisten -auth $authfile $FD_OPTS)\" 1>&2 &\n"
" #result=1\n"
" fi\n"
" fi\n"
" pid=$!\n"
" else\n"
" # need to emulate startx/xinit ourselves...\n"
" echo \"$* -nolisten tcp -auth $authfile $FD_OPTS\" 1>&2\n"
" echo \"$* $nolisten -auth $authfile $FD_OPTS\" 1>&2\n"
" if [ \"X$have_root\" != \"X\" ]; then\n"
" $have_nohup $* -nolisten tcp -auth $authfile $FD_OPTS 1>&2 &\n"
" $have_nohup $* $nolisten -auth $authfile $FD_OPTS 1>&2 &\n"
" pid=$!\n"
" sleep 3\n"
" $have_nohup $sess 1>&2 &\n"
" else\n"
" if [ \"X$ns\" = \"X0\" ]; then\n"
" $have_nohup sh -c \"$* -nolisten tcp -auth $authfile $FD_OPTS\" 1>&2 &\n"
" $have_nohup sh -c \"$* $nolisten -auth $authfile $FD_OPTS\" 1>&2 &\n"
" else\n"
" $have_nohup sh -c \"(sleep $ns; $* -nolisten tcp -auth $authfile $FD_OPTS)\" 1>&2 &\n"
" $have_nohup sh -c \"(sleep $ns; $* $nolisten -auth $authfile $FD_OPTS)\" 1>&2 &\n"
" #result=1\n"
" fi\n"
" pid=$!\n"
......@@ -1719,6 +1719,8 @@ char create_display[] =
"depth=${depth:-16}\n"
"geom=${geom:-1280x1024}\n"
"\n"
"nolisten=${FD_NOLISTEN:-\"-nolisten tcp\"}\n"
"\n"
"if [ \"X$X11VNC_CREATE_GEOM\" != \"X\" -a \"X$FD_GEOM\" = \"X\" ]; then\n"
" FD_GEOM=$X11VNC_CREATE_GEOM\n"
"fi\n"
......
......@@ -671,7 +671,7 @@ of actions:
Properties - Brings up the Properties dialog to set some basic
parameters. The full tkx11vnc GUI may be accessed
via the \"Advanced ...\" button. Press \"Help ...\"
via the \"Advanced ...\" button. Press \"Help\"
in the Properties dialog for more info.
Help - Displays this help text.
......@@ -781,7 +781,7 @@ Password\" empty as well and removes the need for any password to log in.
If you set \"ViewOnly Password\" to the empty string that just removes
the ViewOnly log in aspect: \"Password\" is still required to log in.
- The \"Help ...\" button shows this help text.
- The \"Help\" button shows this help text.
- The \"Advanced ...\" button replaces the Properties dialog with the full
tkx11vnc GUI. All dynamic settings can be modified in the full GUI.
......@@ -4272,7 +4272,7 @@ proc do_props {{msg ""}} {
bind $w <KeyPress-Escape> "destroy $w"
pack $b1.apply $b1.cancel $b1.ok -side right -expand 1
pack $b1.ok $b1.cancel $b1.apply -side left -expand 0
lappend props_buttons $b1.apply $b1.cancel $b1.ok
set b2 "$w.buttons2"
......@@ -4282,12 +4282,12 @@ proc do_props {{msg ""}} {
-command "destroy $w; props_advanced" -font $bfont
if {! $icon_noadvanced} {
lappend props_buttons $b2.advanced
pack $b2.advanced -side right -expand 1
pack $b2.advanced -side left -expand 0
}
button $b2.help -text "Help ..." -command "menu_help Properties" -font $bfont
button $b2.help -text "Help" -command "menu_help Properties" -font $bfont
lappend props_buttons $b2.help
pack $b2.help -side right -expand 1
pack $b2.help -side left -expand 0
set vp "$w.viewpw"
if {$have_labelframes} {
......@@ -6626,14 +6626,8 @@ get_default_vars
dtime D
if {$icon_mode} {
if {$tray_embed} {
make_gui "tray"
} else {
make_gui "icon"
}
dtime G
old_balloon
proc check_setpasswd {} {
global icon_setpasswd
if {$icon_setpasswd} {
set m "You must specify a Session Password\n"
set m "${m}before VNC clients can connect.\n"
......@@ -6643,9 +6637,33 @@ if {$icon_mode} {
do_props $m
#push_new_value "unlock" "unlock" 1 0
}
}
if {0} {
if {[info exists env(X11VNC_ICON_SETPASS)]} {
if {$env(X11VNC_ICON_SETPASS) == "2"} {
global icon_mode_at_startup icon_mode
set icon_mode_at_startup 1
set icon_mode 2
}
}
}
if {$icon_mode} {
if {$icon_mode == 2} {
make_gui "full"
} elseif {$tray_embed} {
make_gui "tray"
} else {
make_gui "icon"
}
dtime G
old_balloon
check_setpasswd
} else {
make_gui "full"
dtime G
check_setpasswd
}
......
......@@ -682,7 +682,7 @@ char gui_code[] = "";
"\n"
" Properties - Brings up the Properties dialog to set some basic\n"
" parameters. The full tkx11vnc GUI may be accessed\n"
" via the \\\"Advanced ...\\\" button. Press \\\"Help ...\\\"\n"
" via the \\\"Advanced ...\\\" button. Press \\\"Help\\\"\n"
" in the Properties dialog for more info.\n"
" \n"
" Help - Displays this help text.\n"
......@@ -792,7 +792,7 @@ char gui_code[] = "";
"If you set \\\"ViewOnly Password\\\" to the empty string that just removes\n"
"the ViewOnly log in aspect: \\\"Password\\\" is still required to log in.\n"
"\n"
" - The \\\"Help ...\\\" button shows this help text.\n"
" - The \\\"Help\\\" button shows this help text.\n"
" \n"
" - The \\\"Advanced ...\\\" button replaces the Properties dialog with the full\n"
" tkx11vnc GUI. All dynamic settings can be modified in the full GUI.\n"
......@@ -4283,7 +4283,7 @@ char gui_code[] = "";
"\n"
" bind $w <KeyPress-Escape> \"destroy $w\"\n"
"\n"
" pack $b1.apply $b1.cancel $b1.ok -side right -expand 1\n"
" pack $b1.ok $b1.cancel $b1.apply -side left -expand 0\n"
" lappend props_buttons $b1.apply $b1.cancel $b1.ok\n"
"\n"
" set b2 \"$w.buttons2\"\n"
......@@ -4293,12 +4293,12 @@ char gui_code[] = "";
" -command \"destroy $w; props_advanced\" -font $bfont\n"
" if {! $icon_noadvanced} {\n"
" lappend props_buttons $b2.advanced\n"
" pack $b2.advanced -side right -expand 1\n"
" pack $b2.advanced -side left -expand 0\n"
" }\n"
"\n"
" button $b2.help -text \"Help ...\" -command \"menu_help Properties\" -font $bfont\n"
" button $b2.help -text \"Help\" -command \"menu_help Properties\" -font $bfont\n"
" lappend props_buttons $b2.help\n"
" pack $b2.help -side right -expand 1\n"
" pack $b2.help -side left -expand 0\n"
"\n"
" set vp \"$w.viewpw\"\n"
" if {$have_labelframes} {\n"
......@@ -6637,14 +6637,8 @@ char gui_code[] = "";
"\n"
"dtime D\n"
"\n"
"if {$icon_mode} {\n"
" if {$tray_embed} {\n"
" make_gui \"tray\"\n"
" } else {\n"
" make_gui \"icon\"\n"
" }\n"
" dtime G\n"
" old_balloon\n"
"proc check_setpasswd {} {\n"
" global icon_setpasswd\n"
" if {$icon_setpasswd} {\n"
" set m \"You must specify a Session Password\\n\" \n"
" set m \"${m}before VNC clients can connect.\\n\" \n"
......@@ -6654,9 +6648,33 @@ char gui_code[] = "";
" do_props $m\n"
" #push_new_value \"unlock\" \"unlock\" 1 0\n"
" }\n"
"}\n"
"\n"
"if {0} {\n"
" if {[info exists env(X11VNC_ICON_SETPASS)]} {\n"
" if {$env(X11VNC_ICON_SETPASS) == \"2\"} {\n"
" global icon_mode_at_startup icon_mode\n"
" set icon_mode_at_startup 1\n"
" set icon_mode 2\n"
" }\n"
" }\n"
"}\n"
"\n"
"if {$icon_mode} {\n"
" if {$icon_mode == 2} {\n"
" make_gui \"full\"\n"
" } elseif {$tray_embed} {\n"
" make_gui \"tray\"\n"
" } else {\n"
" make_gui \"icon\"\n"
" }\n"
" dtime G\n"
" old_balloon\n"
" check_setpasswd\n"
"} else {\n"
" make_gui \"full\"\n"
" dtime G\n"
" check_setpasswd\n"
"}\n"
"\n"
"\n"
......
......@@ -1094,7 +1094,6 @@ rfbBool custom_passwd_check(rfbClientPtr cl, const char *response, int len) {
}
static void handle_one_http_request(void) {
rfbLog("handle_one_http_request: begin.\n");
if (inetd || screen->httpPort == 0) {
int port = find_free_port(5800, 5860);
......@@ -1111,7 +1110,7 @@ static void handle_one_http_request(void) {
http_connections(1);
rfbInitServer(screen);
if (! inetd) {
if (!inetd) {
int conn = 0;
while (1) {
if (0) fprintf(stderr, "%d %d %d %d\n", conn, screen->listenSock, screen->httpSock, screen->httpListenSock);
......@@ -1136,6 +1135,7 @@ static void handle_one_http_request(void) {
rfbLog("handle_one_http_request: finished.\n");
return;
} else {
/* inetd case: */
#if LIBVNCSERVER_HAVE_FORK
pid_t pid;
int s_in = screen->inetdSock;
......@@ -1147,7 +1147,6 @@ static void handle_one_http_request(void) {
if (pid < 0) {
rfbLog("handle_one_http_request: could not fork.\n");
clean_up_exit(1);
} else if (pid > 0) {
int status;
pid_t pidw;
......@@ -1162,7 +1161,6 @@ static void handle_one_http_request(void) {
}
rfbLog("handle_one_http_request: finished.\n");
return;
} else {
int sock = rfbConnectToTcpAddr("127.0.0.1",
screen->httpPort);
......@@ -1322,149 +1320,20 @@ static void vnc_redirect_timeout (int sig) {
exit(0);
}
extern char find_display[];
extern char create_display[];
static XImage ximage_struct;
int wait_for_client(int *argc, char** argv, int http) {
XImage* fb_image;
int w = 640, h = 480, b = 32;
int w0, h0, i, chg_raw_fb = 0;
char *str, *q, *cmd = NULL;
int db = 0;
char tmp[] = "/tmp/x11vnc-find_display.XXXXXX";
int tmp_fd = -1, dt = 0;
char *create_cmd = NULL;
char *users_list_save = NULL;
int created_disp = 0;
int ncache_save;
int did_client_connect = 0;
int loop = 0;
time_t start;
char *vnc_redirect_host = "localhost";
int vnc_redirect_port = -1;
int vnc_redirect_cnt = 0;
char vnc_redirect_test[10];
vnc_redirect = 0;
if (! use_dpy || strstr(use_dpy, "WAIT:") != use_dpy) {
return 0;
}
if (getenv("WAIT_FOR_CLIENT_DB")) {
db = 1;
}
for (i=0; i < *argc; i++) {
if (!strcmp(argv[i], "-desktop")) {
dt = 1;
}
if (db) fprintf(stderr, "args %d %s\n", i, argv[i]);
}
if (!quiet && !strstr(use_dpy, "FINDDISPLAY-run")) {
rfbLog("wait_for_client: %s\n", use_dpy);
}
str = strdup(use_dpy);
str += strlen("WAIT");
xdmcp_insert = NULL;
/* get any leading geometry: */
q = strchr(str+1, ':');
if (q) {
*q = '\0';
if (sscanf(str+1, "%dx%d", &w0, &h0) == 2) {
w = w0;
h = h0;
rfbLog("wait_for_client set: w=%d h=%d\n", w, h);
}
*q = ':';
str = q;
}
/* str currently begins with a ':' */
if (strstr(str, ":cmd=") == str) {
/* cmd=/path/to/mycommand */
str++;
} else if (strpbrk(str, "0123456789") == str+1) {
/* :0.0 */
;
} else {
/* hostname:0.0 */
str++;
}
if (db) fprintf(stderr, "str: %s\n", str);
if (strstr(str, "cmd=") == str) {
if (no_external_cmds || !cmd_ok("WAIT")) {
rfbLog("wait_for_client external cmds not allowed:"
" %s\n", use_dpy);
clean_up_exit(1);
}
static void do_chvt(int vt) {
char chvt[100];
sprintf(chvt, "chvt %d >/dev/null 2>/dev/null &", vt);
rfbLog("running: %s\n", chvt);
system(chvt);
sleep(2);
}
cmd = str + strlen("cmd=");
if (!strcmp(cmd, "FINDDISPLAY-print")) {
fprintf(stdout, "%s", find_display);
clean_up_exit(0);
}
if (!strcmp(cmd, "FINDDISPLAY-run")) {
char tmp[] = "/tmp/fd.XXXXXX";
char com[100];
int fd = mkstemp(tmp);
if (fd >= 0) {
write(fd, find_display, strlen(find_display));
close(fd);
set_env("FINDDISPLAY_run", "1");
sprintf(com, "/bin/sh %s -n; rm -f %s", tmp, tmp);
system(com);
}
unlink(tmp);
exit(0);
}
if (!strcmp(str, "FINDCREATEDISPLAY-print")) {
fprintf(stdout, "%s", create_display);
clean_up_exit(0);
}
if (db) fprintf(stderr, "cmd: %s\n", cmd);
if (strstr(str, "FINDCREATEDISPLAY") || strstr(str, "FINDDISPLAY")) {
if (strstr(str, "Xvnc.redirect") || strstr(str, "X.redirect")) {
vnc_redirect = 1;
}
}
if (strstr(cmd, "FINDDISPLAY-vnc_redirect") == cmd) {
int p;
char h[256];
if (strlen(cmd) >= 256) {
rfbLog("wait_for_client string too long: %s\n", str);
clean_up_exit(1);
}
h[0] = '\0';
if (sscanf(cmd, "FINDDISPLAY-vnc_redirect=%d", &p) == 1) {
;
} else if (sscanf(cmd, "FINDDISPLAY-vnc_redirect=%s %d", h, &p) == 2) {
;
} else {
rfbLog("wait_for_client bad string: %s\n", cmd);
clean_up_exit(1);
}
vnc_redirect_port = p;
if (strcmp(h, "")) {
vnc_redirect_host = strdup(h);
}
vnc_redirect = 2;
rfbLog("wait_for_client: vnc_redirect: %s:%d\n", vnc_redirect_host, vnc_redirect_port);
}
}
static void setup_fake_fb(XImage* fb_image, int w, int h, int b) {
if (fake_fb) {
free(fake_fb);
}
fake_fb = (char *) calloc(w*h*b/8, 1);
fb_image = &ximage_struct;
fb_image->data = fake_fb;
fb_image->format = ZPixmap;
fb_image->width = w;
......@@ -1483,64 +1352,9 @@ int wait_for_client(int *argc, char** argv, int http) {
dpy_y = wdpy_y = h;
off_x = 0;
off_y = 0;
}
if (! dt) {
char *s;
argv[*argc] = strdup("-desktop");
*argc = (*argc) + 1;
if (cmd) {
char *q;
s = choose_title(":0");
q = strstr(s, ":0");
if (q) {
*q = '\0';
}
} else {
s = choose_title(str);
}
rfb_desktop_name = strdup(s);
argv[*argc] = s;
*argc = (*argc) + 1;
}
ncache_save = ncache;
ncache = 0;
initialize_allowed_input();
if (! multiple_cursors_mode) {
multiple_cursors_mode = strdup("default");
}
initialize_cursors_mode();
initialize_screen(argc, argv, fb_image);
initialize_signals();
if (ssh_str != NULL) {
ssh_remote_tunnel(ssh_str, screen->port);
}
if (! raw_fb) {
chg_raw_fb = 1;
/* kludge to get RAWFB_RET with dpy == NULL guards */
raw_fb = (char *) 0x1;
}
if (cmd && !strcmp(cmd, "HTTPONCE")) {
handle_one_http_request();
clean_up_exit(0);
}
if (http && check_httpdir()) {
http_connections(1);
}
if (cmd && unixpw) {
keep_unixpw = 1;
}
static void setup_service(void) {
if (!inetd) {
if (!use_openssl) {
announce(screen->port, use_openssl, NULL);
......@@ -1562,7 +1376,9 @@ int wait_for_client(int *argc, char** argv, int http) {
avahi_initialise();
avahi_advertise(name, this_host(), screen->port);
}
}
static void check_waitbg(void) {
if (getenv("WAITBG")) {
#if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SETSID
int p, n;
......@@ -1594,91 +1410,9 @@ int wait_for_client(int *argc, char** argv, int http) {
clean_up_exit(1);
#endif
}
}
if (vnc_redirect) {
if (unixpw) {
rfbLog("wait_for_client: -unixpw and Xvnc.redirect not allowed\n");
clean_up_exit(1);
}
if (client_connect) {
rfbLog("wait_for_client: -connect and Xvnc.redirect not allowed\n");
clean_up_exit(1);
}
if (inetd) {
if (use_openssl) {
accept_openssl(OPENSSL_INETD, -1);
}
} else {
if (first_conn_timeout) {
if (first_conn_timeout < 0) {
first_conn_timeout = -first_conn_timeout;
}
signal(SIGALRM, vnc_redirect_timeout);
alarm(first_conn_timeout);
}
if (use_openssl) {
accept_openssl(OPENSSL_VNC, -1);
} else {
struct sockaddr_in addr;
#ifdef __hpux
int addrlen = sizeof(addr);
#else
socklen_t addrlen = sizeof(addr);
#endif
if (screen->listenSock < 0) {
rfbLog("wait_for_client: Xvnc.redirect not listening... sock=%d port=%d\n", screen->listenSock, screen->port);
clean_up_exit(1);
}
vnc_redirect_sock = accept(screen->listenSock, (struct sockaddr *)&addr, &addrlen);
}
if (first_conn_timeout) {
alarm(0);
}
}
if (vnc_redirect_sock < 0) {
rfbLog("wait_for_client: vnc_redirect failed.\n");
clean_up_exit(1);
}
if (!inetd && use_openssl) {
/* check for Fetch Cert closing */
fd_set rfds;
struct timeval tv;
int nfds;
usleep(300*1000);
FD_ZERO(&rfds);
FD_SET(vnc_redirect_sock, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 200000;
nfds = select(vnc_redirect_sock+1, &rfds, NULL, NULL, &tv);
rfbLog("wait_for_client: vnc_redirect nfds: %d\n", nfds);
if (nfds > 0) {
int n;
n = read(vnc_redirect_sock, vnc_redirect_test, 1);
if (n <= 0) {
close(vnc_redirect_sock);
vnc_redirect_sock = -1;
rfbLog("wait_for_client: waiting for 2nd connection (Fetch Cert?)\n");
accept_openssl(OPENSSL_VNC, -1);
if (vnc_redirect_sock < 0) {
rfbLog("wait_for_client: vnc_redirect failed.\n");
clean_up_exit(1);
}
} else {
vnc_redirect_cnt = n;
}
}
}
goto vnc_redirect_place;
}
if (inetd && use_openssl) {
accept_openssl(OPENSSL_INETD, -1);
}
static void setup_client_connect(int *did_client_connect) {
if (client_connect != NULL) {
char *remainder = NULL;
if (inetd) {
......@@ -1701,7 +1435,7 @@ int wait_for_client(int *argc, char** argv, int http) {
rfbLog("wait_for_client: reverse_connect(%s)\n",
client_connect);
reverse_connect(client_connect);
did_client_connect = 1;
*did_client_connect = 1;
}
free(client_connect);
if (remainder != NULL) {
......@@ -1711,11 +1445,14 @@ int wait_for_client(int *argc, char** argv, int http) {
client_connect = NULL;
}
}
}
static void loop_for_connect(int did_client_connect) {
int loop = 0;
time_t start = time(NULL);
if (first_conn_timeout < 0) {
first_conn_timeout = -first_conn_timeout;
}
start = time(NULL);
while (1) {
loop++;
......@@ -1789,16 +1526,19 @@ int wait_for_client(int *argc, char** argv, int http) {
if (! use_threads) {
rfbPE(-1);
}
screen_check:
if (! screen || ! screen->clientHead) {
usleep(100 * 1000);
continue;
}
rfbLog("wait_for_client: got client\n");
break;
}
}
static void do_unixpw_loop(void) {
if (unixpw) {
if (! unixpw_in_progress) {
rfbLog("unixpw but no unixpw_in_progress\n");
......@@ -1808,12 +1548,6 @@ int wait_for_client(int *argc, char** argv, int http) {
rfbLog("taking unixpw_client off hold.\n");
unixpw_client->onHold = FALSE;
}
if (cmd && strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
if (users_list && strstr(users_list, "unixpw=") == users_list) {
users_list_save = users_list;
users_list = NULL;
}
}
while (1) {
if (shut_down) {
clean_up_exit(0);
......@@ -1831,482 +1565,803 @@ int wait_for_client(int *argc, char** argv, int http) {
break;
}
}
}
if (0) db = 1;
vnc_redirect_place:
if (vnc_redirect == 2) {
;
} else if (cmd) {
char line1[1024];
char line2[16384];
char *q;
int n;
int nodisp = 0;
int saw_xdmcp = 0;
char *usslpeer = NULL;
memset(line1, 0, 1024);
memset(line2, 0, 16384);
if (users_list && strstr(users_list, "sslpeer=") == users_list) {
int ok = 0;
char *u = NULL, *upeer = NULL;
if (certret_str) {
char *q, *p, *str = strdup(certret_str);
q = strstr(str, "Subject: ");
if (! q) return 0;
p = strstr(q, "\n");
if (p) *p = '\0';
q = strstr(q, "CN=");
if (! q) return 0;
if (! getenv("X11VNC_SSLPEER_CN")) {
p = q;
q = strstr(q, "/emailAddress=");
if (! q) q = strstr(p, "/Email=");
if (! q) return 0;
}
q = strstr(q, "=");
if (! q) return 0;
q++;
p = strstr(q, " ");
if (p) *p = '\0';
p = strstr(q, "@");
if (p) *p = '\0';
p = strstr(q, "/");
if (p) *p = '\0';
upeer = strdup(q);
if (strcmp(upeer, "")) {
p = upeer;
while (*p != '\0') {
char c = *p;
if (!isalnum((int) c)) {
*p = '\0';
break;
}
p++;
}
if (strcmp(upeer, "")) {
ok = 1;
}
static void vnc_redirect_loop(char *vnc_redirect_test, int *vnc_redirect_cnt) {
if (unixpw) {
rfbLog("wait_for_client: -unixpw and Xvnc.redirect not allowed\n");
clean_up_exit(1);
}
if (client_connect) {
rfbLog("wait_for_client: -connect and Xvnc.redirect not allowed\n");
clean_up_exit(1);
}
if (inetd) {
if (use_openssl) {
accept_openssl(OPENSSL_INETD, -1);
}
} else {
pid_t pid = 0;
if (screen->httpListenSock >= 0) {
#if LIBVNCSERVER_HAVE_FORK
if ((pid = fork()) > 0) {
close(screen->httpListenSock);
screen->httpListenSock = -2;
usleep(500 * 1000);
} else {
close(screen->listenSock);
screen->listenSock = -1;
while (1) {
usleep(10 * 1000);
rfbHttpCheckFds(screen);
}
exit(1);
}
if (! ok || !upeer) {
return 0;
#else
clean_up_exit(1);
#endif
}
if (first_conn_timeout) {
if (first_conn_timeout < 0) {
first_conn_timeout = -first_conn_timeout;
}
rfbLog("sslpeer unix username extracted from x509 cert: %s\n", upeer);
u = (char *) malloc(strlen(upeer+2));
u[0] = '\0';
if (!strcmp(users_list, "sslpeer=")) {
sprintf(u, "+%s", upeer);
signal(SIGALRM, vnc_redirect_timeout);
alarm(first_conn_timeout);
}
if (use_openssl) {
int i;
if (pid == 0) {
accept_openssl(OPENSSL_VNC, -1);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("sslpeer="), ",");
while (p) {
if (!strcmp(p, upeer)) {
sprintf(u, "+%s", upeer);
for (i=0; i < 16; i++) {
accept_openssl(OPENSSL_VNC, -1);
rfbLog("iter %d: vnc_redirect_sock: %d\n", i, vnc_redirect_sock);
if (vnc_redirect_sock >= 0) {
break;
}
p = strtok(NULL, ",");
}
free(str);
}
if (u[0] == '\0') {
rfbLog("sslpeer cannot determine user: %s\n", upeer);
free(u);
return 0;
} else {
struct sockaddr_in addr;
#ifdef __hpux
int addrlen = sizeof(addr);
#else
socklen_t addrlen = sizeof(addr);
#endif
if (screen->listenSock < 0) {
rfbLog("wait_for_client: Xvnc.redirect not listening... sock=%d port=%d\n", screen->listenSock, screen->port);
clean_up_exit(1);
}
free(u);
usslpeer = upeer;
vnc_redirect_sock = accept(screen->listenSock, (struct sockaddr *)&addr, &addrlen);
}
/* only sets environment variables: */
run_user_command("", latest_client, "env", NULL, 0, NULL);
if (program_name) {
set_env("X11VNC_PROG", program_name);
} else {
set_env("X11VNC_PROG", "x11vnc");
if (first_conn_timeout) {
alarm(0);
}
if (!strcmp(cmd, "FINDDISPLAY") ||
strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
char *nd = "";
tmp_fd = mkstemp(tmp);
if (tmp_fd < 0) {
rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("mkstemp");
clean_up_exit(1);
if (pid > 0) {
#if LIBVNCSERVER_HAVE_FORK
int rc;
pid_t pidw;
rfbLog("wait_for_client: kill TERM: %d\n", (int) pid);
kill(pid, SIGTERM);
usleep(1000 * 1000); /* 1.0 sec */
pidw = waitpid(pid, &rc, WNOHANG);
if (pidw <= 0) {
usleep(1000 * 1000); /* 1.0 sec */
pidw = waitpid(pid, &rc, WNOHANG);
}
chmod(tmp, 0644);
if (getenv("X11VNC_FINDDISPLAY_ALWAYS_FAILS")) {
char *s = "#!/bin/sh\necho _FAIL_\nexit 1\n";
write(tmp_fd, s, strlen(s));
#else
clean_up_exit(1);
#endif
}
}
if (vnc_redirect_sock < 0) {
rfbLog("wait_for_client: vnc_redirect failed.\n");
clean_up_exit(1);
}
if (!inetd && use_openssl) {
/* check for Fetch Cert closing */
fd_set rfds;
struct timeval tv;
int nfds;
usleep(300*1000);
FD_ZERO(&rfds);
FD_SET(vnc_redirect_sock, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 200000;
nfds = select(vnc_redirect_sock+1, &rfds, NULL, NULL, &tv);
rfbLog("wait_for_client: vnc_redirect nfds: %d\n", nfds);
if (nfds > 0) {
int n;
n = read(vnc_redirect_sock, vnc_redirect_test, 1);
if (n <= 0) {
close(vnc_redirect_sock);
vnc_redirect_sock = -1;
rfbLog("wait_for_client: waiting for 2nd connection (Fetch Cert?)\n");
accept_openssl(OPENSSL_VNC, -1);
if (vnc_redirect_sock < 0) {
rfbLog("wait_for_client: vnc_redirect failed.\n");
clean_up_exit(1);
}
} else {
write(tmp_fd, find_display, strlen(find_display));
}
close(tmp_fd);
nodisp = 1;
if (strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
char *opts = strchr(cmd, '-');
char st[] = "";
char fdgeom[128], fdsess[128], fdopts[128], fdprog[128];
char fdxsrv[128], fdxdum[128], fdcups[128], fdesd[128];
char fdnas[128], fdsmb[128], fdtag[128];
if (opts) {
opts++;
if (strstr(opts, "xdmcp")) {
saw_xdmcp = 1;
}
} else {
opts = st;
}
sprintf(fdgeom, "NONE");
fdsess[0] = '\0';
fdgeom[0] = '\0';
fdopts[0] = '\0';
fdprog[0] = '\0';
fdxsrv[0] = '\0';
fdxdum[0] = '\0';
fdcups[0] = '\0';
fdesd[0] = '\0';
fdnas[0] = '\0';
fdsmb[0] = '\0';
fdtag[0] = '\0';
if (unixpw && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') {
char *q, *p, *t = strdup(keep_unixpw_opts);
if (strstr(t, "gnome")) {
sprintf(fdsess, "gnome");
} else if (strstr(t, "kde")) {
sprintf(fdsess, "kde");
} else if (strstr(t, "twm")) {
sprintf(fdsess, "twm");
} else if (strstr(t, "fvwm")) {
sprintf(fdsess, "fvwm");
} else if (strstr(t, "mwm")) {
sprintf(fdsess, "mwm");
} else if (strstr(t, "cde")) {
sprintf(fdsess, "cde");
} else if (strstr(t, "dtwm")) {
sprintf(fdsess, "dtwm");
} else if (strstr(t, "xterm")) {
sprintf(fdsess, "xterm");
} else if (strstr(t, "wmaker")) {
sprintf(fdsess, "wmaker");
} else if (strstr(t, "xfce")) {
sprintf(fdsess, "xfce");
} else if (strstr(t, "enlightenment")) {
sprintf(fdsess, "enlightenment");
} else if (strstr(t, "Xsession")) {
sprintf(fdsess, "Xsession");
} else if (strstr(t, "failsafe")) {
sprintf(fdsess, "failsafe");
}
*vnc_redirect_cnt = n;
}
}
}
}
q = strstr(t, "ge=");
if (! q) q = strstr(t, "geom=");
if (! q) q = strstr(t, "geometry=");
if (q) {
int ok = 1;
q = strstr(q, "=");
q++;
p = strstr(q, ",");
if (p) *p = '\0';
p = q;
while (*p) {
if (*p == 'x') {
;
} else if (isdigit((int) *p)) {
;
} else {
ok = 0;
break;
}
p++;
}
if (ok && strlen(q) < 32) {
sprintf(fdgeom, q);
if (!quiet) {
rfbLog("set create display geom: %s\n", fdgeom);
}
}
}
q = strstr(t, "cups=");
if (q) {
int p;
if (sscanf(q, "cups=%d", &p) == 1) {
sprintf(fdcups, "%d", p);
}
}
q = strstr(t, "esd=");
if (q) {
int p;
if (sscanf(q, "esd=%d", &p) == 1) {
sprintf(fdesd, "%d", p);
}
}
free(t);
}
if (fdgeom[0] == '\0' && getenv("FD_GEOM")) {
snprintf(fdgeom, 120, "%s", getenv("FD_GEOM"));
}
if (fdsess[0] == '\0' && getenv("FD_SESS")) {
snprintf(fdsess, 120, "%s", getenv("FD_SESS"));
}
if (fdopts[0] == '\0' && getenv("FD_OPTS")) {
snprintf(fdopts, 120, "%s", getenv("FD_OPTS"));
}
if (fdprog[0] == '\0' && getenv("FD_PROG")) {
snprintf(fdprog, 120, "%s", getenv("FD_PROG"));
}
if (fdxsrv[0] == '\0' && getenv("FD_XSRV")) {
snprintf(fdxsrv, 120, "%s", getenv("FD_XSRV"));
}
if (fdcups[0] == '\0' && getenv("FD_CUPS")) {
snprintf(fdcups, 120, "%s", getenv("FD_CUPS"));
}
if (fdesd[0] == '\0' && getenv("FD_ESD")) {
snprintf(fdesd, 120, "%s", getenv("FD_ESD"));
}
if (fdnas[0] == '\0' && getenv("FD_NAS")) {
snprintf(fdnas, 120, "%s", getenv("FD_NAS"));
}
if (fdsmb[0] == '\0' && getenv("FD_SMB")) {
snprintf(fdsmb, 120, "%s", getenv("FD_SMB"));
}
if (fdtag[0] == '\0' && getenv("FD_TAG")) {
snprintf(fdtag, 120, "%s", getenv("FD_TAG"));
}
if (fdxdum[0] == '\0' && getenv("FD_XDUMMY_NOROOT")) {
snprintf(fdxdum, 120, "%s", getenv("FD_XDUMMY_NOROOT"));
}
static void do_vnc_redirect(int created_disp, char *vnc_redirect_host, int vnc_redirect_port,
int vnc_redirect_cnt, char *vnc_redirect_test) {
char *q = strchr(use_dpy, ':');
int vdpy = -1, sock = -1;
int s_in, s_out, i;
if (vnc_redirect == 2) {
char num[32];
sprintf(num, ":%d", vnc_redirect_port);
q = num;
}
if (!q) {
rfbLog("wait_for_client: can't find number in X display: %s\n", use_dpy);
clean_up_exit(1);
}
if (sscanf(q+1, "%d", &vdpy) != 1) {
rfbLog("wait_for_client: can't find number in X display: %s\n", q);
clean_up_exit(1);
}
if (vdpy == -1 && vnc_redirect != 2) {
rfbLog("wait_for_client: can't find number in X display: %s\n", q);
clean_up_exit(1);
}
if (vnc_redirect == 2) {
if (vdpy < 0) {
vdpy = -vdpy;
} else if (vdpy < 200) {
vdpy += 5900;
}
} else {
vdpy += 5900;
}
if (created_disp) {
usleep(1000*1000);
}
for (i=0; i < 20; i++) {
sock = rfbConnectToTcpAddr(vnc_redirect_host, vdpy);
if (sock >= 0) {
break;
}
rfbLog("wait_for_client: ...\n");
usleep(500*1000);
}
if (sock < 0) {
rfbLog("wait_for_client: could not connect to a VNC Server at %s:%d\n", vnc_redirect_host, vdpy);
clean_up_exit(1);
}
if (inetd) {
s_in = fileno(stdin);
s_out = fileno(stdout);
} else {
s_in = s_out = vnc_redirect_sock;
}
if (vnc_redirect_cnt > 0) {
write(vnc_redirect_sock, vnc_redirect_test, vnc_redirect_cnt);
}
rfbLog("wait_for_client: switching control to VNC Server at %s:%d\n", vnc_redirect_host, vdpy);
raw_xfer(sock, s_in, s_out);
}
set_env("FD_GEOM", fdgeom);
set_env("FD_OPTS", fdopts);
set_env("FD_PROG", fdprog);
set_env("FD_XSRV", fdxsrv);
set_env("FD_CUPS", fdcups);
set_env("FD_ESD", fdesd);
set_env("FD_NAS", fdnas);
set_env("FD_SMB", fdsmb);
set_env("FD_TAG", fdtag);
set_env("FD_XDUMMY_NOROOT", fdxdum);
set_env("FD_SESS", fdsess);
if (usslpeer || (unixpw && keep_unixpw_user)) {
char *uu = usslpeer;
if (!uu) {
uu = keep_unixpw_user;
}
create_cmd = (char *) malloc(strlen(tmp)+1
+ strlen("env USER='' ")
+ strlen("FD_GEOM='' ")
+ strlen("FD_OPTS='' ")
+ strlen("FD_PROG='' ")
+ strlen("FD_XSRV='' ")
+ strlen("FD_CUPS='' ")
+ strlen("FD_ESD='' ")
+ strlen("FD_NAS='' ")
+ strlen("FD_SMB='' ")
+ strlen("FD_TAG='' ")
+ strlen("FD_XDUMMY_NOROOT='' ")
+ strlen("FD_SESS='' /bin/sh ")
+ strlen(uu) + 1
+ strlen(fdgeom) + 1
+ strlen(fdopts) + 1
+ strlen(fdprog) + 1
+ strlen(fdxsrv) + 1
+ strlen(fdcups) + 1
+ strlen(fdesd) + 1
+ strlen(fdnas) + 1
+ strlen(fdsmb) + 1
+ strlen(fdtag) + 1
+ strlen(fdxdum) + 1
+ strlen(fdsess) + 1
+ strlen(opts) + 1);
sprintf(create_cmd, "env USER='%s' FD_GEOM='%s' FD_SESS='%s' "
"FD_OPTS='%s' FD_PROG='%s' FD_XSRV='%s' FD_CUPS='%s' "
"FD_ESD='%s' FD_NAS='%s' FD_SMB='%s' FD_TAG='%s' "
"FD_XDUMMY_NOROOT='%s' /bin/sh %s %s",
uu, fdgeom, fdsess, fdopts, fdprog, fdxsrv,
fdcups, fdesd, fdnas, fdsmb, fdtag, fdxdum, tmp, opts);
extern char find_display[];
extern char create_display[];
char *setup_cmd(char *str, int *vnc_redirect, char **vnc_redirect_host, int *vnc_redirect_port, int db) {
char *cmd = NULL;
if (no_external_cmds || !cmd_ok("WAIT")) {
rfbLog("wait_for_client external cmds not allowed:"
" %s\n", use_dpy);
clean_up_exit(1);
}
cmd = str + strlen("cmd=");
if (!strcmp(cmd, "FINDDISPLAY-print")) {
fprintf(stdout, "%s", find_display);
clean_up_exit(0);
}
if (!strcmp(cmd, "FINDDISPLAY-run")) {
char tmp[] = "/tmp/fd.XXXXXX";
char com[100];
int fd = mkstemp(tmp);
if (fd >= 0) {
write(fd, find_display, strlen(find_display));
close(fd);
set_env("FINDDISPLAY_run", "1");
sprintf(com, "/bin/sh %s -n; rm -f %s", tmp, tmp);
system(com);
}
unlink(tmp);
exit(0);
}
if (!strcmp(str, "FINDCREATEDISPLAY-print")) {
fprintf(stdout, "%s", create_display);
clean_up_exit(0);
}
if (db) fprintf(stderr, "cmd: %s\n", cmd);
if (strstr(str, "FINDCREATEDISPLAY") || strstr(str, "FINDDISPLAY")) {
if (strstr(str, "Xvnc.redirect") || strstr(str, "X.redirect")) {
*vnc_redirect = 1;
}
}
if (strstr(cmd, "FINDDISPLAY-vnc_redirect") == cmd) {
int p;
char h[256];
if (strlen(cmd) >= 256) {
rfbLog("wait_for_client string too long: %s\n", str);
clean_up_exit(1);
}
h[0] = '\0';
if (sscanf(cmd, "FINDDISPLAY-vnc_redirect=%d", &p) == 1) {
;
} else if (sscanf(cmd, "FINDDISPLAY-vnc_redirect=%s %d", h, &p) == 2) {
;
} else {
rfbLog("wait_for_client bad string: %s\n", cmd);
clean_up_exit(1);
}
*vnc_redirect_port = p;
if (strcmp(h, "")) {
*vnc_redirect_host = strdup(h);
}
*vnc_redirect = 2;
rfbLog("wait_for_client: vnc_redirect: %s:%d\n", *vnc_redirect_host, *vnc_redirect_port);
}
return cmd;
}
static char *build_create_cmd(char *cmd, int *saw_xdmcp, char *usslpeer, char *tmp) {
char *create_cmd = NULL;
char *opts = strchr(cmd, '-');
char st[] = "";
char fdgeom[128], fdsess[128], fdopts[128], fdprog[128];
char fdxsrv[128], fdxdum[128], fdcups[128], fdesd[128];
char fdnas[128], fdsmb[128], fdtag[128];
if (opts) {
opts++;
if (strstr(opts, "xdmcp")) {
*saw_xdmcp = 1;
}
} else {
opts = st;
}
sprintf(fdgeom, "NONE");
fdsess[0] = '\0';
fdgeom[0] = '\0';
fdopts[0] = '\0';
fdprog[0] = '\0';
fdxsrv[0] = '\0';
fdxdum[0] = '\0';
fdcups[0] = '\0';
fdesd[0] = '\0';
fdnas[0] = '\0';
fdsmb[0] = '\0';
fdtag[0] = '\0';
if (unixpw && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') {
char *q, *p, *t = strdup(keep_unixpw_opts);
if (strstr(t, "gnome")) {
sprintf(fdsess, "gnome");
} else if (strstr(t, "kde")) {
sprintf(fdsess, "kde");
} else if (strstr(t, "twm")) {
sprintf(fdsess, "twm");
} else if (strstr(t, "fvwm")) {
sprintf(fdsess, "fvwm");
} else if (strstr(t, "mwm")) {
sprintf(fdsess, "mwm");
} else if (strstr(t, "cde")) {
sprintf(fdsess, "cde");
} else if (strstr(t, "dtwm")) {
sprintf(fdsess, "dtwm");
} else if (strstr(t, "xterm")) {
sprintf(fdsess, "xterm");
} else if (strstr(t, "wmaker")) {
sprintf(fdsess, "wmaker");
} else if (strstr(t, "xfce")) {
sprintf(fdsess, "xfce");
} else if (strstr(t, "enlightenment")) {
sprintf(fdsess, "enlightenment");
} else if (strstr(t, "Xsession")) {
sprintf(fdsess, "Xsession");
} else if (strstr(t, "failsafe")) {
sprintf(fdsess, "failsafe");
}
q = strstr(t, "ge=");
if (! q) q = strstr(t, "geom=");
if (! q) q = strstr(t, "geometry=");
if (q) {
int ok = 1;
q = strstr(q, "=");
q++;
p = strstr(q, ",");
if (p) *p = '\0';
p = q;
while (*p) {
if (*p == 'x') {
;
} else if (isdigit((int) *p)) {
;
} else {
create_cmd = (char *) malloc(strlen(tmp)
+ strlen("/bin/sh ") + 1 + strlen(opts) + 1);
sprintf(create_cmd, "/bin/sh %s %s", tmp, opts);
ok = 0;
break;
}
if (db) fprintf(stderr, "create_cmd: %s\n", create_cmd);
}
if (getenv("X11VNC_SKIP_DISPLAY")) {
nd = strdup(getenv("X11VNC_SKIP_DISPLAY"));
}
if (unixpw && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') {
char *q, *t = keep_unixpw_opts;
q = strstr(t, "nd=");
if (! q) q = strstr(t, "nodisplay=");
if (q) {
char *t2;
q = strchr(q, '=') + 1;
t = strdup(q);
q = t;
t2 = strchr(t, ',');
if (t2) *t2 = '\0';
while (*t != '\0') {
if (*t == '-') {
*t = ',';
}
t++;
}
if (!strchr(q, '\'')) {
if (! quiet) rfbLog("set X11VNC_SKIP_DISPLAY: %s\n", q);
nd = q;
}
p++;
}
if (ok && strlen(q) < 32) {
sprintf(fdgeom, q);
if (!quiet) {
rfbLog("set create display geom: %s\n", fdgeom);
}
}
}
q = strstr(t, "cups=");
if (q) {
int p;
if (sscanf(q, "cups=%d", &p) == 1) {
sprintf(fdcups, "%d", p);
}
}
q = strstr(t, "esd=");
if (q) {
int p;
if (sscanf(q, "esd=%d", &p) == 1) {
sprintf(fdesd, "%d", p);
}
}
free(t);
}
if (fdgeom[0] == '\0' && getenv("FD_GEOM")) {
snprintf(fdgeom, 120, "%s", getenv("FD_GEOM"));
}
if (fdsess[0] == '\0' && getenv("FD_SESS")) {
snprintf(fdsess, 120, "%s", getenv("FD_SESS"));
}
if (fdopts[0] == '\0' && getenv("FD_OPTS")) {
snprintf(fdopts, 120, "%s", getenv("FD_OPTS"));
}
if (fdprog[0] == '\0' && getenv("FD_PROG")) {
snprintf(fdprog, 120, "%s", getenv("FD_PROG"));
}
if (fdxsrv[0] == '\0' && getenv("FD_XSRV")) {
snprintf(fdxsrv, 120, "%s", getenv("FD_XSRV"));
}
if (fdcups[0] == '\0' && getenv("FD_CUPS")) {
snprintf(fdcups, 120, "%s", getenv("FD_CUPS"));
}
if (fdesd[0] == '\0' && getenv("FD_ESD")) {
snprintf(fdesd, 120, "%s", getenv("FD_ESD"));
}
if (fdnas[0] == '\0' && getenv("FD_NAS")) {
snprintf(fdnas, 120, "%s", getenv("FD_NAS"));
}
if (fdsmb[0] == '\0' && getenv("FD_SMB")) {
snprintf(fdsmb, 120, "%s", getenv("FD_SMB"));
}
if (fdtag[0] == '\0' && getenv("FD_TAG")) {
snprintf(fdtag, 120, "%s", getenv("FD_TAG"));
}
if (fdxdum[0] == '\0' && getenv("FD_XDUMMY_NOROOT")) {
snprintf(fdxdum, 120, "%s", getenv("FD_XDUMMY_NOROOT"));
}
set_env("FD_GEOM", fdgeom);
set_env("FD_OPTS", fdopts);
set_env("FD_PROG", fdprog);
set_env("FD_XSRV", fdxsrv);
set_env("FD_CUPS", fdcups);
set_env("FD_ESD", fdesd);
set_env("FD_NAS", fdnas);
set_env("FD_SMB", fdsmb);
set_env("FD_TAG", fdtag);
set_env("FD_XDUMMY_NOROOT", fdxdum);
set_env("FD_SESS", fdsess);
if (usslpeer || (unixpw && keep_unixpw_user)) {
char *uu = usslpeer;
if (!uu) {
uu = keep_unixpw_user;
}
create_cmd = (char *) malloc(strlen(tmp)+1
+ strlen("env USER='' ")
+ strlen("FD_GEOM='' ")
+ strlen("FD_OPTS='' ")
+ strlen("FD_PROG='' ")
+ strlen("FD_XSRV='' ")
+ strlen("FD_CUPS='' ")
+ strlen("FD_ESD='' ")
+ strlen("FD_NAS='' ")
+ strlen("FD_SMB='' ")
+ strlen("FD_TAG='' ")
+ strlen("FD_XDUMMY_NOROOT='' ")
+ strlen("FD_SESS='' /bin/sh ")
+ strlen(uu) + 1
+ strlen(fdgeom) + 1
+ strlen(fdopts) + 1
+ strlen(fdprog) + 1
+ strlen(fdxsrv) + 1
+ strlen(fdcups) + 1
+ strlen(fdesd) + 1
+ strlen(fdnas) + 1
+ strlen(fdsmb) + 1
+ strlen(fdtag) + 1
+ strlen(fdxdum) + 1
+ strlen(fdsess) + 1
+ strlen(opts) + 1);
sprintf(create_cmd, "env USER='%s' FD_GEOM='%s' FD_SESS='%s' "
"FD_OPTS='%s' FD_PROG='%s' FD_XSRV='%s' FD_CUPS='%s' "
"FD_ESD='%s' FD_NAS='%s' FD_SMB='%s' FD_TAG='%s' "
"FD_XDUMMY_NOROOT='%s' /bin/sh %s %s",
uu, fdgeom, fdsess, fdopts, fdprog, fdxsrv,
fdcups, fdesd, fdnas, fdsmb, fdtag, fdxdum, tmp, opts);
} else {
create_cmd = (char *) malloc(strlen(tmp)
+ strlen("/bin/sh ") + 1 + strlen(opts) + 1);
sprintf(create_cmd, "/bin/sh %s %s", tmp, opts);
}
return create_cmd;
}
static char *certret_extract() {
char *q, *p, *str = strdup(certret_str);
char *upeer = NULL;
int ok = 0;
q = strstr(str, "Subject: ");
if (! q) return NULL;
p = strstr(q, "\n");
if (p) *p = '\0';
cmd = (char *) malloc(strlen("env X11VNC_SKIP_DISPLAY='' ")
+ strlen(nd) + strlen(tmp) + strlen("/bin/sh ") + 1);
sprintf(cmd, "env X11VNC_SKIP_DISPLAY='%s' /bin/sh %s", nd, tmp);
q = strstr(q, "CN=");
if (! q) return NULL;
if (! getenv("X11VNC_SSLPEER_CN")) {
p = q;
q = strstr(q, "/emailAddress=");
if (! q) q = strstr(p, "/Email=");
if (! q) return NULL;
}
q = strstr(q, "=");
if (! q) return NULL;
q++;
p = strstr(q, " ");
if (p) *p = '\0';
p = strstr(q, "@");
if (p) *p = '\0';
p = strstr(q, "/");
if (p) *p = '\0';
upeer = strdup(q);
if (strcmp(upeer, "")) {
p = upeer;
while (*p != '\0') {
char c = *p;
if (!isalnum((int) c)) {
*p = '\0';
break;
}
p++;
}
if (strcmp(upeer, "")) {
ok = 1;
}
}
if (! ok) {
upeer = NULL;
}
return upeer;
}
rfbLog("wait_for_client: running: %s\n", cmd);
static void check_nodisplay(char **nd) {
if (unixpw && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') {
char *q, *t = keep_unixpw_opts;
q = strstr(t, "nd=");
if (! q) q = strstr(t, "nodisplay=");
if (q) {
char *t2;
q = strchr(q, '=') + 1;
t = strdup(q);
q = t;
t2 = strchr(t, ',');
if (t2) *t2 = '\0';
while (*t != '\0') {
if (*t == '-') {
*t = ',';
}
t++;
}
if (!strchr(q, '\'')) {
if (! quiet) rfbLog("set X11VNC_SKIP_DISPLAY: %s\n", q);
*nd = q;
}
}
}
}
if (unixpw) {
int res = 0, k, j, i;
char line[18000];
static char *get_usslpeer() {
char *u = NULL, *upeer = NULL;
memset(line, 0, 18000);
if (certret_str) {
upeer = certret_extract();
}
if (!upeer) {
return NULL;
}
rfbLog("sslpeer unix username extracted from x509 cert: %s\n", upeer);
if (keep_unixpw_user && keep_unixpw_pass) {
n = 18000;
res = su_verify(keep_unixpw_user,
keep_unixpw_pass, cmd, line, &n, nodisp);
u = (char *) malloc(strlen(upeer+2));
u[0] = '\0';
if (!strcmp(users_list, "sslpeer=")) {
sprintf(u, "+%s", upeer);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("sslpeer="), ",");
while (p) {
if (!strcmp(p, upeer)) {
sprintf(u, "+%s", upeer);
break;
}
p = strtok(NULL, ",");
}
free(str);
}
if (u[0] == '\0') {
rfbLog("sslpeer cannot determine user: %s\n", upeer);
free(u);
return NULL;
}
free(u);
return upeer;
}
static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int created_disp, int db) {
char tmp[] = "/tmp/x11vnc-find_display.XXXXXX";
char line1[1024], line2[16384];
char *q, *usslpeer = NULL;
int n, nodisp = 0, saw_xdmcp = 0;
int tmp_fd = -1;
memset(line1, 0, 1024);
memset(line2, 0, 16384);
if (users_list && strstr(users_list, "sslpeer=") == users_list) {
usslpeer = get_usslpeer();
if (! usslpeer) {
return 0;
}
}
/* only sets environment variables: */
run_user_command("", latest_client, "env", NULL, 0, NULL);
if (program_name) {
set_env("X11VNC_PROG", program_name);
} else {
set_env("X11VNC_PROG", "x11vnc");
}
if (!strcmp(cmd, "FINDDISPLAY") ||
strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
char *nd = "";
tmp_fd = mkstemp(tmp);
if (tmp_fd < 0) {
rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("mkstemp");
clean_up_exit(1);
}
chmod(tmp, 0644);
if (getenv("X11VNC_FINDDISPLAY_ALWAYS_FAILS")) {
char *s = "#!/bin/sh\necho _FAIL_\nexit 1\n";
write(tmp_fd, s, strlen(s));
} else {
write(tmp_fd, find_display, strlen(find_display));
}
close(tmp_fd);
nodisp = 1;
if (strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
create_cmd = build_create_cmd(cmd, &saw_xdmcp, usslpeer, tmp);
if (db) fprintf(stderr, "create_cmd: %s\n", create_cmd);
}
if (getenv("X11VNC_SKIP_DISPLAY")) {
nd = strdup(getenv("X11VNC_SKIP_DISPLAY"));
}
check_nodisplay(&nd);
cmd = (char *) malloc(strlen("env X11VNC_SKIP_DISPLAY='' ")
+ strlen(nd) + strlen(tmp) + strlen("/bin/sh ") + 1);
sprintf(cmd, "env X11VNC_SKIP_DISPLAY='%s' /bin/sh %s", nd, tmp);
}
rfbLog("wait_for_client: running: %s\n", cmd);
if (unixpw) {
int res = 0, k, j, i;
char line[18000];
memset(line, 0, 18000);
if (keep_unixpw_user && keep_unixpw_pass) {
n = 18000;
res = su_verify(keep_unixpw_user,
keep_unixpw_pass, cmd, line, &n, nodisp);
}
if (db) {fprintf(stderr, "line: "); write(2, line, n); write(2, "\n", 1); fprintf(stderr, "res=%d n=%d\n", res, n);}
if (! res) {
rfbLog("wait_for_client: find display cmd failed\n");
}
if (! res) {
rfbLog("wait_for_client: find display cmd failed\n");
}
if (! res && create_cmd) {
FILE *mt = fopen(tmp, "w");
if (! mt) {
rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("fopen");
clean_up_exit(1);
}
fprintf(mt, "%s", create_display);
fclose(mt);
if (! res && create_cmd) {
FILE *mt = fopen(tmp, "w");
if (! mt) {
rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("fopen");
clean_up_exit(1);
}
fprintf(mt, "%s", create_display);
fclose(mt);
findcreatedisplay = 1;
findcreatedisplay = 1;
if (getuid() != 0) {
/* if not root, run as the other user... */
n = 18000;
close_exec_fds();
res = su_verify(keep_unixpw_user,
keep_unixpw_pass, create_cmd, line, &n, nodisp);
if (getuid() != 0) {
/* if not root, run as the other user... */
n = 18000;
close_exec_fds();
res = su_verify(keep_unixpw_user,
keep_unixpw_pass, create_cmd, line, &n, nodisp);
if (db) fprintf(stderr, "c-res=%d n=%d line: '%s'\n", res, n, line);
} else {
FILE *p;
close_exec_fds();
rfbLog("wait_for_client: running: %s\n", create_cmd);
p = popen(create_cmd, "r");
if (! p) {
rfbLog("wait_for_client: popen failed: %s\n", create_cmd);
res = 0;
} else if (fgets(line1, 1024, p) == NULL) {
rfbLog("wait_for_client: read failed: %s\n", create_cmd);
res = 0;
} else {
FILE *p;
close_exec_fds();
rfbLog("wait_for_client: running: %s\n", create_cmd);
p = popen(create_cmd, "r");
if (! p) {
rfbLog("wait_for_client: popen failed: %s\n", create_cmd);
res = 0;
} else if (fgets(line1, 1024, p) == NULL) {
rfbLog("wait_for_client: read failed: %s\n", create_cmd);
n = fread(line2, 1, 16384, p);
if (pclose(p) != 0) {
res = 0;
} else {
n = fread(line2, 1, 16384, p);
if (pclose(p) != 0) {
res = 0;
} else {
strncpy(line, line1, 100);
memcpy(line + strlen(line1), line2, n);
strncpy(line, line1, 100);
memcpy(line + strlen(line1), line2, n);
if (db) fprintf(stderr, "line1: '%s'\n", line1);
n += strlen(line1);
created_disp = 1;
res = 1;
}
n += strlen(line1);
created_disp = 1;
res = 1;
}
}
if (res && saw_xdmcp) {
xdmcp_insert = strdup(keep_unixpw_user);
}
}
if (tmp_fd >= 0) {
unlink(tmp);
if (res && saw_xdmcp) {
xdmcp_insert = strdup(keep_unixpw_user);
}
}
if (! res) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd);
unixpw_msg("No DISPLAY found.", 3);
clean_up_exit(1);
}
if (tmp_fd >= 0) {
unlink(tmp);
}
/*
* we need to hunt for DISPLAY= since there may be
* a login banner or something at the beginning.
*/
q = strstr(line, "DISPLAY=");
if (! q) {
q = line;
}
n -= (q - line);
if (! res) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd);
unixpw_msg("No DISPLAY found.", 3);
clean_up_exit(1);
}
for (k = 0; k < 1024; k++) {
line1[k] = q[k];
if (q[k] == '\n') {
k++;
break;
}
/*
* we need to hunt for DISPLAY= since there may be
* a login banner or something at the beginning.
*/
q = strstr(line, "DISPLAY=");
if (! q) {
q = line;
}
n -= (q - line);
for (k = 0; k < 1024; k++) {
line1[k] = q[k];
if (q[k] == '\n') {
k++;
break;
}
n -= k;
i = 0;
for (j = 0; j < 16384; j++) {
if (j < 16384 - 1) {
/* xauth data, assume pty added CR */
if (q[k+j] == '\r' && q[k+j+1] == '\n') {
continue;
}
}
n -= k;
i = 0;
for (j = 0; j < 16384; j++) {
if (j < 16384 - 1) {
/* xauth data, assume pty added CR */
if (q[k+j] == '\r' && q[k+j+1] == '\n') {
continue;
}
line2[i] = q[k+j];
i++;
}
line2[i] = q[k+j];
i++;
}
if (db) write(2, line, 100);
if (db) fprintf(stderr, "\n");
} else {
FILE *p;
int rc;
close_exec_fds();
if (usslpeer) {
char *c;
if (getuid() == 0) {
c = (char *) malloc(strlen("su - '' -c \"")
+ strlen(usslpeer) + strlen(cmd) + 1 + 1);
sprintf(c, "su - '%s' -c \"%s\"", usslpeer, cmd);
} else {
c = strdup(cmd);
}
p = popen(c, "r");
free(c);
} else {
FILE *p;
int rc;
close_exec_fds();
if (usslpeer) {
char *c;
if (getuid() == 0) {
c = (char *) malloc(strlen("su - '' -c \"")
+ strlen(usslpeer) + strlen(cmd) + 1 + 1);
sprintf(c, "su - '%s' -c \"%s\"", usslpeer, cmd);
} else {
c = strdup(cmd);
p = popen(cmd, "r");
}
if (! p) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd);
rfbLogPerror("popen");
if (tmp_fd >= 0) {
unlink(tmp);
}
clean_up_exit(1);
}
if (fgets(line1, 1024, p) == NULL) {
rfbLog("wait_for_client: read failed: %s\n", cmd);
rfbLogPerror("fgets");
if (tmp_fd >= 0) {
unlink(tmp);
}
clean_up_exit(1);
}
n = fread(line2, 1, 16384, p);
rc = pclose(p);
if (rc != 0) {
rfbLog("wait_for_client: find display cmd failed\n");
}
if (create_cmd && rc != 0) {
FILE *mt = fopen(tmp, "w");
if (! mt) {
rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("fopen");
if (tmp_fd >= 0) {
unlink(tmp);
}
p = popen(c, "r");
free(c);
} else {
p = popen(cmd, "r");
clean_up_exit(1);
}
fprintf(mt, "%s", create_display);
fclose(mt);
findcreatedisplay = 1;
rfbLog("wait_for_client: FINDCREATEDISPLAY cmd: %s\n", create_cmd);
p = popen(create_cmd, "r");
if (! p) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd);
rfbLog("wait_for_client: cmd failed: %s\n", create_cmd);
rfbLogPerror("popen");
if (tmp_fd >= 0) {
unlink(tmp);
......@@ -2314,7 +2369,7 @@ if (db) fprintf(stderr, "\n");
clean_up_exit(1);
}
if (fgets(line1, 1024, p) == NULL) {
rfbLog("wait_for_client: read failed: %s\n", cmd);
rfbLog("wait_for_client: read failed: %s\n", create_cmd);
rfbLogPerror("fgets");
if (tmp_fd >= 0) {
unlink(tmp);
......@@ -2322,198 +2377,317 @@ if (db) fprintf(stderr, "\n");
clean_up_exit(1);
}
n = fread(line2, 1, 16384, p);
rc = pclose(p);
if (rc != 0) {
rfbLog("wait_for_client: find display cmd failed\n");
}
if (create_cmd && rc != 0) {
FILE *mt = fopen(tmp, "w");
if (! mt) {
rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("fopen");
if (tmp_fd >= 0) {
unlink(tmp);
}
clean_up_exit(1);
}
fprintf(mt, "%s", create_display);
fclose(mt);
findcreatedisplay = 1;
rfbLog("wait_for_client: FINDCREATEDISPLAY cmd: %s\n", create_cmd);
p = popen(create_cmd, "r");
if (! p) {
rfbLog("wait_for_client: cmd failed: %s\n", create_cmd);
rfbLogPerror("popen");
if (tmp_fd >= 0) {
unlink(tmp);
}
clean_up_exit(1);
}
if (fgets(line1, 1024, p) == NULL) {
rfbLog("wait_for_client: read failed: %s\n", create_cmd);
rfbLogPerror("fgets");
if (tmp_fd >= 0) {
unlink(tmp);
}
clean_up_exit(1);
}
n = fread(line2, 1, 16384, p);
}
if (tmp_fd >= 0) {
unlink(tmp);
}
}
if (tmp_fd >= 0) {
unlink(tmp);
}
}
if (db) fprintf(stderr, "line1=%s\n", line1);
if (strstr(line1, "DISPLAY=") != line1) {
rfbLog("wait_for_client: bad reply '%s'\n", line1);
if (unixpw) {
unixpw_msg("No DISPLAY found.", 3);
}
clean_up_exit(1);
if (strstr(line1, "DISPLAY=") != line1) {
rfbLog("wait_for_client: bad reply '%s'\n", line1);
if (unixpw) {
unixpw_msg("No DISPLAY found.", 3);
}
clean_up_exit(1);
}
if (strstr(line1, ",VT=")) {
int vt;
char *t = strstr(line1, ",VT=");
vt = atoi(t + strlen(",VT="));
*t = '\0';
if (7 <= vt && vt <= 15) {
char chvt[100];
sprintf(chvt, "chvt %d >/dev/null 2>/dev/null &", vt);
rfbLog("running: %s\n", chvt);
system(chvt);
sleep(2);
}
} else if (strstr(line1, ",XPID=")) {
int i, pvt, vt = -1;
char *t = strstr(line1, ",XPID=");
pvt = atoi(t + strlen(",XPID="));
*t = '\0';
if (pvt > 0) {
for (i=3; i <= 10; i++) {
int k;
char proc[100];
char buf[100];
sprintf(proc, "/proc/%d/fd/%d", pvt, i);
if (strstr(line1, ",VT=")) {
int vt;
char *t = strstr(line1, ",VT=");
vt = atoi(t + strlen(",VT="));
*t = '\0';
if (7 <= vt && vt <= 15) {
do_chvt(vt);
}
} else if (strstr(line1, ",XPID=")) {
int i, pvt, vt = -1;
char *t = strstr(line1, ",XPID=");
pvt = atoi(t + strlen(",XPID="));
*t = '\0';
if (pvt > 0) {
for (i=3; i <= 10; i++) {
int k;
char proc[100];
char buf[100];
sprintf(proc, "/proc/%d/fd/%d", pvt, i);
if (db) fprintf(stderr, "%d -- %s\n", i, proc);
for (k=0; k < 100; k++) {
buf[k] = '\0';
}
if (readlink(proc, buf, 100) != -1) {
buf[100-1] = '\0';
for (k=0; k < 100; k++) {
buf[k] = '\0';
}
if (readlink(proc, buf, 100) != -1) {
buf[100-1] = '\0';
if (db) fprintf(stderr, "%d -- %s -- %s\n", i, proc, buf);
if (strstr(buf, "/dev/tty") == buf) {
vt = atoi(buf + strlen("/dev/tty"));
if (vt > 0) {
break;
}
if (strstr(buf, "/dev/tty") == buf) {
vt = atoi(buf + strlen("/dev/tty"));
if (vt > 0) {
break;
}
}
}
}
if (7 <= vt && vt <= 12) {
char chvt[100];
sprintf(chvt, "chvt %d >/dev/null 2>/dev/null &", vt);
rfbLog("running: %s\n", chvt);
system(chvt);
sleep(2);
}
}
use_dpy = strdup(line1 + strlen("DISPLAY="));
q = use_dpy;
while (*q != '\0') {
if (*q == '\n' || *q == '\r') *q = '\0';
q++;
if (7 <= vt && vt <= 12) {
do_chvt(vt);
}
if (line2[0] != '\0') {
if (strstr(line2, "XAUTHORITY=") == line2) {
q = line2;
while (*q != '\0') {
if (*q == '\n' || *q == '\r') *q = '\0';
q++;
}
if (auth_file) {
free(auth_file);
}
auth_file = strdup(line2 + strlen("XAUTHORITY="));
}
} else {
xauth_raw_data = (char *)malloc(n);
xauth_raw_len = n;
memcpy(xauth_raw_data, line2, n);
use_dpy = strdup(line1 + strlen("DISPLAY="));
q = use_dpy;
while (*q != '\0') {
if (*q == '\n' || *q == '\r') *q = '\0';
q++;
}
if (line2[0] != '\0') {
if (strstr(line2, "XAUTHORITY=") == line2) {
q = line2;
while (*q != '\0') {
if (*q == '\n' || *q == '\r') *q = '\0';
q++;
}
if (auth_file) {
free(auth_file);
}
auth_file = strdup(line2 + strlen("XAUTHORITY="));
} else {
xauth_raw_data = (char *)malloc(n);
xauth_raw_len = n;
memcpy(xauth_raw_data, line2, n);
if (db) {fprintf(stderr, "xauth_raw_len: %d\n", n);
write(2, xauth_raw_data, n);
fprintf(stderr, "\n");}
}
}
}
if (usslpeer) {
char *u = (char *) malloc(strlen(usslpeer+2));
sprintf(u, "+%s", usslpeer);
if (switch_user(u, 0)) {
rfbLog("sslpeer switched to user: %s\n", usslpeer);
} else {
rfbLog("sslpeer failed to switch to user: %s\n", usslpeer);
}
free(u);
} else if (users_list_save && keep_unixpw_user) {
char *user = keep_unixpw_user;
char *u = (char *)malloc(strlen(user)+1);
if (usslpeer) {
char *u = (char *) malloc(strlen(usslpeer+2));
sprintf(u, "+%s", usslpeer);
if (switch_user(u, 0)) {
rfbLog("sslpeer switched to user: %s\n", usslpeer);
} else {
rfbLog("sslpeer failed to switch to user: %s\n", usslpeer);
}
free(u);
} else if (users_list_save && keep_unixpw_user) {
char *user = keep_unixpw_user;
char *u = (char *)malloc(strlen(user)+1);
users_list = users_list_save;
users_list = users_list_save;
u[0] = '\0';
if (!strcmp(users_list, "unixpw=")) {
sprintf(u, "+%s", user);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("unixpw="), ",");
while (p) {
if (!strcmp(p, user)) {
sprintf(u, "+%s", user);
break;
}
p = strtok(NULL, ",");
u[0] = '\0';
if (!strcmp(users_list, "unixpw=")) {
sprintf(u, "+%s", user);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("unixpw="), ",");
while (p) {
if (!strcmp(p, user)) {
sprintf(u, "+%s", user);
break;
}
free(str);
}
if (u[0] == '\0') {
rfbLog("unixpw_accept skipping switch to user: %s\n", user);
} else if (switch_user(u, 0)) {
rfbLog("unixpw_accept switched to user: %s\n", user);
} else {
rfbLog("unixpw_accept failed to switch to user: %s\n", user);
p = strtok(NULL, ",");
}
free(u);
free(str);
}
if (u[0] == '\0') {
rfbLog("unixpw_accept skipping switch to user: %s\n", user);
} else if (switch_user(u, 0)) {
rfbLog("unixpw_accept switched to user: %s\n", user);
} else {
rfbLog("unixpw_accept failed to switch to user: %s\n", user);
}
free(u);
}
if (unixpw) {
char str[32];
if (keep_unixpw_user && keep_unixpw_pass) {
strzero(keep_unixpw_user);
strzero(keep_unixpw_pass);
keep_unixpw = 0;
}
if (unixpw) {
char str[32];
if (created_disp) {
snprintf(str, 30, "Created DISPLAY %s", use_dpy);
} else {
snprintf(str, 30, "Using DISPLAY %s", use_dpy);
}
unixpw_msg(str, 2);
}
return 1;
}
static XImage ximage_struct;
int wait_for_client(int *argc, char** argv, int http) {
/* ugh, here we go... */
XImage* fb_image;
int w = 640, h = 480, b = 32;
int w0, h0, i, chg_raw_fb = 0;
char *str, *q, *cmd = NULL;
int db = 0, dt = 0;
char *create_cmd = NULL;
char *users_list_save = NULL;
int created_disp = 0, ncache_save;
int did_client_connect = 0;
char *vnc_redirect_host = "localhost";
int vnc_redirect_port = -1, vnc_redirect_cnt = 0;
char vnc_redirect_test[10];
if (getenv("WAIT_FOR_CLIENT_DB")) {
db = 1;
}
vnc_redirect = 0;
if (! use_dpy || strstr(use_dpy, "WAIT:") != use_dpy) {
return 0;
}
for (i=0; i < *argc; i++) {
if (!strcmp(argv[i], "-desktop")) {
dt = 1;
}
if (db) fprintf(stderr, "args %d %s\n", i, argv[i]);
}
if (!quiet && !strstr(use_dpy, "FINDDISPLAY-run")) {
rfbLog("wait_for_client: %s\n", use_dpy);
}
str = strdup(use_dpy);
str += strlen("WAIT");
xdmcp_insert = NULL;
/* get any leading geometry: */
q = strchr(str+1, ':');
if (q) {
*q = '\0';
if (sscanf(str+1, "%dx%d", &w0, &h0) == 2) {
w = w0;
h = h0;
rfbLog("wait_for_client set: w=%d h=%d\n", w, h);
}
*q = ':';
str = q;
}
if (keep_unixpw_user && keep_unixpw_pass) {
strzero(keep_unixpw_user);
strzero(keep_unixpw_pass);
keep_unixpw = 0;
/* str currently begins with a ':' */
if (strstr(str, ":cmd=") == str) {
/* cmd=/path/to/mycommand */
str++;
} else if (strpbrk(str, "0123456789") == str+1) {
/* :0.0 */
;
} else {
/* hostname:0.0 */
str++;
}
if (db) fprintf(stderr, "str: %s\n", str);
if (strstr(str, "cmd=") == str) {
cmd = setup_cmd(str, &vnc_redirect, &vnc_redirect_host, &vnc_redirect_port, db);
}
fb_image = &ximage_struct;
setup_fake_fb(fb_image, w, h, b);
if (! dt) {
char *s;
argv[*argc] = strdup("-desktop");
*argc = (*argc) + 1;
if (cmd) {
char *q;
s = choose_title(":0");
q = strstr(s, ":0");
if (q) {
*q = '\0';
}
} else {
s = choose_title(str);
}
rfb_desktop_name = strdup(s);
argv[*argc] = s;
*argc = (*argc) + 1;
}
if (created_disp) {
snprintf(str, 30, "Created DISPLAY %s", use_dpy);
} else {
snprintf(str, 30, "Using DISPLAY %s", use_dpy);
ncache_save = ncache;
ncache = 0;
initialize_allowed_input();
if (! multiple_cursors_mode) {
multiple_cursors_mode = strdup("default");
}
initialize_cursors_mode();
initialize_screen(argc, argv, fb_image);
initialize_signals();
if (ssh_str != NULL) {
ssh_remote_tunnel(ssh_str, screen->port);
}
if (! raw_fb) {
chg_raw_fb = 1;
/* kludge to get RAWFB_RET with dpy == NULL guards */
raw_fb = (char *) 0x1;
}
if (cmd && !strcmp(cmd, "HTTPONCE")) {
handle_one_http_request();
clean_up_exit(0);
}
if (http && check_httpdir()) {
http_connections(1);
}
if (cmd && unixpw) {
keep_unixpw = 1;
}
setup_service();
check_waitbg();
if (vnc_redirect) {
vnc_redirect_loop(vnc_redirect_test, &vnc_redirect_cnt);
} else {
if (inetd && use_openssl) {
accept_openssl(OPENSSL_INETD, -1);
}
setup_client_connect(&did_client_connect);
loop_for_connect(did_client_connect);
if (unixpw) {
if (cmd && strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
if (users_list && strstr(users_list, "unixpw=") == users_list) {
users_list_save = users_list;
users_list = NULL;
}
}
unixpw_msg(str, 2);
do_unixpw_loop();
}
}
if (vnc_redirect == 2) {
;
} else if (cmd) {
if (!do_run_cmd(cmd, create_cmd, users_list_save, created_disp, db)) {
return 0;
}
} else {
use_dpy = strdup(str);
......@@ -2532,61 +2706,8 @@ fprintf(stderr, "\n");}
}
if (vnc_redirect) {
char *q = strchr(use_dpy, ':');
int vdpy = -1, sock = -1;
int s_in, s_out, i;
if (vnc_redirect == 2) {
char num[32];
sprintf(num, ":%d", vnc_redirect_port);
q = num;
}
if (!q) {
rfbLog("wait_for_client: can't find number in X display: %s\n", use_dpy);
clean_up_exit(1);
}
if (sscanf(q+1, "%d", &vdpy) != 1) {
rfbLog("wait_for_client: can't find number in X display: %s\n", q);
clean_up_exit(1);
}
if (vdpy == -1 && vnc_redirect != 2) {
rfbLog("wait_for_client: can't find number in X display: %s\n", q);
clean_up_exit(1);
}
if (vnc_redirect == 2) {
if (vdpy < 0) {
vdpy = -vdpy;
} else if (vdpy < 200) {
vdpy += 5900;
}
} else {
vdpy += 5900;
}
if (created_disp) {
usleep(1000*1000);
}
for (i=0; i < 20; i++) {
sock = rfbConnectToTcpAddr(vnc_redirect_host, vdpy);
if (sock >= 0) {
break;
}
rfbLog("wait_for_client: ...\n");
usleep(500*1000);
}
if (sock < 0) {
rfbLog("wait_for_client: could not connect to a VNC Server at %s:%d\n", vnc_redirect_host, vdpy);
clean_up_exit(1);
}
if (inetd) {
s_in = fileno(stdin);
s_out = fileno(stdout);
} else {
s_in = s_out = vnc_redirect_sock;
}
if (vnc_redirect_cnt > 0) {
write(vnc_redirect_sock, vnc_redirect_test, vnc_redirect_cnt);
}
rfbLog("wait_for_client: switching control to VNC Server at %s:%d\n", vnc_redirect_host, vdpy);
raw_xfer(sock, s_in, s_out);
do_vnc_redirect(created_disp, vnc_redirect_host, vnc_redirect_port,
vnc_redirect_cnt, vnc_redirect_test);
clean_up_exit(0);
}
......
.\" This file was automatically generated from x11vnc -help output.
.TH X11VNC "1" "February 2008" "x11vnc " "User Commands"
.TH X11VNC "1" "May 2008" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.9.4, lastmod: 2008-02-17
version: 0.9.4, lastmod: 2008-05-07
.SH SYNOPSIS
.B x11vnc
[OPTION]...
......@@ -507,6 +507,45 @@ Be careful about the location of this file if x11vnc
is running as root (e.g. via
.IR gdm (1)
, etc).
.IP
Repeater mode: Some services provide an intermediate
"vnc repeater": http://www.uvnc.com/addons/repeater.html
(and also http://koti.mbnet.fi/jtko/ for linux port)
that acts as a proxy / gateway. Modes like these require
an initial string to be sent for the reverse connection
before the VNC protocol is started. Here are the ways
to do this:
.IP
\fB-connect\fR pre=some_string+host:port
\fB-connect\fR pre128=some_string+host:port
\fB-connect\fR repeater=ID:1234+host:port
\fB-connect\fR repeater=23.45.67.89::5501+host:port
.IP
SSVNC notation is also supported:
.IP
\fB-connect\fR repeater://host:port+ID:1234
.IP
As with normal \fB-connect\fR usage, if the repeater port is
not supplied 5500 is assumed.
.IP
The basic idea is between the special tag, e.g. "pre="
and "+" is the pre-string to be sent. Note that in
this case host:port is the repeater server, NOT the
vnc viewer. Somehow the pre-string tells the repeater
server how to find the vnc viewer and connect you to it.
.IP
In the case pre=some_string+host:port, "some_string"
is simply sent. In the case preNNN=some_string+host:port
"some_string" is sent in a null padded buffer of
length NNN. repeater= is the same as pre250=, this is
the ultravnc repeater buffer size.
.IP
Strings like "\\n" and "\\r", etc. are expanded to
newline and carriage return. "\\c" is expanded to
"," since the connect string is comma separated.
.IP
See also the \fB-proxy\fR option below for additional ways
to plumb reverse connections.
.PP
\fB-connect_or_exit\fR \fIstr\fR
.IP
......@@ -1068,6 +1107,10 @@ In fact, the protocol does not even need to be VNC,
and so "\fB-ssl\fR \fISAVE \fB-redirect\fR host:port\fR" can act as a
replacement for
.IR stunnel (1).
.IP
This mode only allows one redirected connection.
The \fB-forever\fR option does not apply. Use \fB-inetd\fR or
\fB-loop\fR for persistant service.
.PP
\fB-display\fR \fIWAIT:...\fR
.IP
......@@ -3620,8 +3663,8 @@ for details. \fB-nodpms\fR is basically the same as running
If the system supports the DPMS (Display Power
Management Signaling) extension, then try to keep the
monitor in a powered off state. This is to prevent
nosey people at the physical display from viewing
what is on the screen. Be sure lock the screen before
nosey people at the physical display from viewing what
is on the screen. Be sure to lock the screen before
disconnecting.
.IP
This method is far from bullet proof, e.g. suppose
......@@ -3713,7 +3756,11 @@ for this option if you don't like the 'pipe'. Example:
.IP
Whether or not to use the threaded libvncserver
algorithm [rfbRunEventLoop] if libpthread is available
Default: \fB-nothreads\fR
Default: \fB-nothreads.\fR NOTE: The \fB-threads\fR mode is now
disabled due to its unstable behavior. Not recommended,
but you can recompile with \fB-DX11VNC_THREADED\fR in
CPPFLAGS if you need to use it. You can also set the
env. variable X11VNC_THREADED=1
.PP
\fB-fs\fR \fIf\fR
.IP
......
......@@ -2589,7 +2589,7 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-connect") ||
!strcmp(arg, "-connect_or_exit")) {
CHECK_ARGC
if (strchr(argv[++i], '/')) {
if (strchr(argv[++i], '/' && !strstr(argv[i], "repeater://"))) {
client_connect_file = strdup(argv[i]);
} else {
client_connect = strdup(argv[i]);
......@@ -3280,7 +3280,22 @@ int main(int argc, char* argv[]) {
}
#if LIBVNCSERVER_HAVE_LIBPTHREAD
} else if (!strcmp(arg, "-threads")) {
#if defined(X11VNC_THREADED)
use_threads = 1;
#else
if (getenv("X11VNC_THREADED")) {
use_threads = 1;
} else {
rfbLog("\n");
rfbLog("The -threads mode is unstable and not tested or maintained.\n");
rfbLog("It is disabled in the source code. If you really need\n");
rfbLog("the feature you can reenable it at build time by setting\n");
rfbLog("-DX11VNC_THREADED in CPPFLAGS. Or set X11VNC_THREADED=1\n");
rfbLog("in your runtime environment.\n");
rfbLog("\n");
usleep(500*1000);
}
#endif
} else if (!strcmp(arg, "-nothreads")) {
use_threads = 0;
#endif
......
......@@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.4 lastmod: 2008-02-17";
char lastmod[] = "0.9.4 lastmod: 2008-05-07";
/* X display info */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment