From 64e731a9da82e3cc614e274d6fca6f855d0359b7 Mon Sep 17 00:00:00 2001 From: runge Date: Sun, 18 Jun 2006 23:59:45 +0000 Subject: x11vnc: --grabkbd, -grabptr, -env, -allowedcmds, unixpw+WAIT user fred:options --- x11vnc/8to24.c | 2 +- x11vnc/ChangeLog | 5 + x11vnc/README | 113 ++++++++++++++++----- x11vnc/cleanup.c | 2 +- x11vnc/connections.c | 112 ++++++++++++++++++--- x11vnc/connections.h | 1 + x11vnc/cursor.c | 2 +- x11vnc/gui.c | 2 +- x11vnc/help.c | 98 +++++++++++++++---- x11vnc/keyboard.c | 4 +- x11vnc/options.c | 1 + x11vnc/options.h | 1 + x11vnc/pm.c | 4 +- x11vnc/pointer.c | 6 +- x11vnc/remote.c | 73 ++++++++++++-- x11vnc/scan.c | 36 +++---- x11vnc/screen.c | 12 +-- x11vnc/solid.c | 14 ++- x11vnc/sslcmds.c | 271 ++++++++++++++++++++++++++++----------------------- x11vnc/sslhelper.c | 121 ++++++++++++++++------- x11vnc/sslhelper.h | 2 + x11vnc/ssltools.h | 55 ++++++++--- x11vnc/tkx11vnc | 2 + x11vnc/tkx11vnc.h | 2 + x11vnc/unixpw.c | 52 ++++++---- x11vnc/unixpw.h | 1 + x11vnc/user.c | 148 +++++++++++++++++++++++----- x11vnc/userinput.c | 8 +- x11vnc/util.c | 53 +++++++--- x11vnc/v4l.c | 2 +- x11vnc/win_utils.c | 2 +- x11vnc/x11vnc.1 | 95 ++++++++++++++++-- x11vnc/x11vnc.c | 58 +++++++++-- x11vnc/x11vnc.h | 6 +- x11vnc/x11vnc_defs.c | 16 +-- x11vnc/xdamage.c | 2 +- x11vnc/xevents.c | 14 +-- x11vnc/xevents.h | 2 + x11vnc/xrandr.h | 4 +- x11vnc/xwrappers.c | 31 ++++++ 40 files changed, 1058 insertions(+), 377 deletions(-) (limited to 'x11vnc') diff --git a/x11vnc/8to24.c b/x11vnc/8to24.c index 5304a52..b7efdab 100644 --- a/x11vnc/8to24.c +++ b/x11vnc/8to24.c @@ -65,7 +65,7 @@ static unsigned int root_rgb[NCOLOR]; static void set_root_cmap(void) { static time_t last_set = 0; - time_t now = time(0); + time_t now = time(NULL); XWindowAttributes attr; static XColor color[NCOLOR]; int redo = 0; diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog index 4c8257c..278d4e3 100644 --- a/x11vnc/ChangeLog +++ b/x11vnc/ChangeLog @@ -1,3 +1,8 @@ +2006-06-18 Karl Runge + * x11vnc: -grabkbd, -grabptr, -env options. under -unixpw + + WAIT let user add some options after his username (e.g. runge:3/4) + -allowedcmds to fine tune vs. -nocmds. general cleanup. + 2006-06-12 Karl Runge * x11vnc: word tune SSL Java viewer; fix multi-certs bug. Add -display WAIT:cmd=FINDDISPLAY builtin script and cmd=HTTPONCE diff --git a/x11vnc/README b/x11vnc/README index d538a04..ca73da0 100644 --- a/x11vnc/README +++ b/x11vnc/README @@ -1,5 +1,5 @@ -x11vnc README file Date: Mon Jun 12 22:23:23 EDT 2006 +x11vnc README file Date: Sun Jun 18 19:37:38 EDT 2006 The following information is taken from these URLs: @@ -7192,7 +7192,7 @@ x11vnc: a VNC server for real X displays Here are all of x11vnc command line options: % x11vnc -opts (see below for -help long descriptions) -x11vnc: allow VNC connections to real X11 displays. 0.8.2 lastmod: 2006-06-12 +x11vnc: allow VNC connections to real X11 displays. 0.8.2 lastmod: 2006-06-18 x11vnc options: -display disp -auth file -id windowid @@ -7205,19 +7205,20 @@ x11vnc options: -inetd -nofilexfer -http -http_ssl -connect string -vncconnect -novncconnect -allow host1[,host2..] -localhost - -nolookup -input string -viewpasswd string - -passwdfile filename -unixpw [list] -unixpw_nis [list] - -display WAIT:... -ssl [pem] -ssldir [dir] - -sslverify [path] -sslGenCA [dir] -sslGenCert type name - -sslEncKey [pem] -sslCertInfo [pem] -sslDelCert [pem] - -stunnel [pem] -stunnel3 [pem] -https [port] - -usepw -storepasswd pass file -nopw - -accept string -afteraccept string -gone string - -users list -noshm -flipbyteorder - -onetile -solid [color] -blackout string - -xinerama -noxinerama -xtrap - -xrandr [mode] -padgeom WxH -o logfile - -flag file -rc filename -norc + -nolookup -input string -grabkbd + -grabptr -viewpasswd string -passwdfile filename + -unixpw [list] -unixpw_nis [list] -display WAIT:... + -ssl [pem] -ssldir [dir] -sslverify [path] + -sslGenCA [dir] -sslGenCert type name -sslEncKey [pem] + -sslCertInfo [pem] -sslDelCert [pem] -stunnel [pem] + -stunnel3 [pem] -https [port] -usepw + -storepasswd pass file -nopw -accept string + -afteraccept string -gone string -users list + -noshm -flipbyteorder -onetile + -solid [color] -blackout string -xinerama + -noxinerama -xtrap -xrandr [mode] + -padgeom WxH -o logfile -flag file + -rc filename -norc -env VAR=VALUE -h, -help -?, -opts -V, -version -dbg -q -bg -modtweak -nomodtweak -xkb @@ -7254,7 +7255,8 @@ x11vnc options: -remote command -query variable -QD variable -sync -noremote -yesremote -unsafe -safer -privremote - -nocmds -deny_all + -nocmds -allowedcmds list -deny_all + libvncserver options: -rfbport port TCP port for RFB protocol @@ -7288,7 +7290,7 @@ libvncserver-tight-extension options: % x11vnc -help -x11vnc: allow VNC connections to real X11 displays. 0.8.2 lastmod: 2006-06-12 +x11vnc: allow VNC connections to real X11 displays. 0.8.2 lastmod: 2006-06-18 (type "x11vnc -opts" to just list the options.) @@ -7576,6 +7578,7 @@ Options: option, otherwise the stderr goes to the viewer which will cause it to abort. Specifying both -inetd and -q and no -o will automatically close the stderr. + -nofilexfer Disable the TightVNC file transfer extension. (same as -disablefiletransfer). Note that when the -viewonly option is supplied all file transfers are disabled. @@ -7583,6 +7586,7 @@ Options: However, if the remote control mechanism is used to change the global or per-client viewonly state the filetransfer permissions will NOT change. + -http Instead of using -httpdir (see below) to specify where the Java vncviewer applet is, have x11vnc try to *guess* where the directory is by looking relative @@ -7659,6 +7663,23 @@ Options: a global -viewonly is in effect (all input is discarded in that case). +-grabkbd When VNC viewers are connected, attempt to the grab the + keyboard so someone sitting at the physical display + is not able to enter keystrokes. This method uses + XGrabKeyboard(3X11) and so it is not secure and does not + rule out the person at the physical display injecting + keystrokes by flooding the server with them, grabbing + the keyboard himself, etc. Some degree of cooperation + from the person at the display is assumed. +-grabptr As -grabkbd, but for the mouse pointer using + XGrabPointer(3X11). Unfortunately due to the way the X + server works, the mouse can still be moved around by the + user at the physical display, but he will not be able to + change window focus with it. Also some window managers + that call XGrabServer(3X11) for resizes, etc, will + act on the local user's input. Again, some degree of + cooperation from the person at the display is assumed. + -viewpasswd string Supply a 2nd password for view-only logins. The -passwd (full-access) password must also be supplied. @@ -7857,7 +7878,25 @@ Options: as the user who just authenticated via the login and password prompt. - Thus the combination of -display WAIT:cmd=... and + Also in the case of -unixpw, the user logging in can + place a colon at the end of his username and supply + a few options: scale=, scale_cursor=, solid, id=, + clear_mods, clear_keys, repeat, or speeds= separated + by commas if there is more than one. After the user + logs in successfully, these options will be applied to + the VNC screen. For example, + + login: fred:scale=3/4,repeat + Password: ... + + for convenience m/n implies scale= e.g. fred:3/4 + To disable this set the environment variable + X11VNC_NO_UNIXPW_OPTS=1. To set any other options, + the user can use the gui (x11vnc -gui connect) or the + remote control method (x11vnc -R opt:val) during his + VNC session. + + So the combination of -display WAIT:cmd=... and -unixpw allows automatic pairing of an unix authenticated VNC user with his desktop. This could be very useful on SunRays and also any system where @@ -7890,7 +7929,7 @@ Options: 5815 stream tcp nowait root /usr/sbin/tcpd .../x11vnc \ -inetd -q -http_ssl -display WAIT:cmd=HTTPONCE - Is used in the Apache SSL-portal example (see FAQ). + It is used in the Apache SSL-portal example (see FAQ). Finally, one can insert a geometry between colons, e.g. WAIT:1280x1024:... to set the size of the display @@ -8672,6 +8711,12 @@ Options: -rc filename Use "filename" instead of $HOME/.x11vncrc for rc file. -norc Do not process any .x11vncrc file for options. +-env VAR=VALUE Set the environment variable 'VAR' to value 'VALUE' + at x11vnc startup. This is a convenience utility to + avoid shell script wrappers, etc. to set the env. var. + You may specify as many of these as needed on the + command line. + -h, -help Print this help text. -?, -opts Only list the x11vnc options. -V, -version Print program version and last modification date. @@ -9974,6 +10019,10 @@ n nolookup enable -nolookup mode. lookup disable -nolookup mode. input:str set -input to "str", empty to disable. + grabkbd enable -grabkbd mode. + nograbkbd disable -grabkbd mode. + grabptr enable -grabptr mode. + nograbptr disable -grabptr mode. client_input:str set the K, M, B -input on a per-client basis. select which client as for disconnect, e.g. client_input:host:MB @@ -10230,13 +10279,14 @@ n scr_skip scr_inc scr_keys scr_term scr_keyrepeat scr_parms scrollcopyrect scr noscrollcopyrect noscr fixscreen noxrecord xrecord reset_record pointer_mode - pm input_skip input client_input speeds wmdt - debug_pointer dp nodebug_pointer nodp debug_keyboard - dk nodebug_keyboard nodk deferupdate defer wait_ui - wait_bog nowait_bog slow_fb wait readtimeout nap nonap - sb screen_blank fbpm nofbpm fs gaps grow fuzz snapfb - nosnapfb rawfb progressive rfbport http nohttp httpport - httpdir enablehttpproxy noenablehttpproxy alwaysshared + pm input_skip input grabkbd nograbkbd grabptr + nograbptr client_input speeds wmdt debug_pointer dp + nodebug_pointer nodp debug_keyboard dk nodebug_keyboard + nodk deferupdate defer wait_ui wait_bog nowait_bog + slow_fb wait readtimeout nap nonap sb screen_blank + fbpm nofbpm fs gaps grow fuzz snapfb nosnapfb rawfb + progressive rfbport http nohttp httpport httpdir + enablehttpproxy noenablehttpproxy alwaysshared noalwaysshared nevershared noalwaysshared dontdisconnect nodontdisconnect desktop debug_xevents nodebug_xevents debug_xevents debug_xdamage nodebug_xdamage @@ -10323,6 +10373,17 @@ n remote-control is disabled it cannot be turned back on. -nocmds No external commands (e.g. system(3), popen(3), exec(3)) will be run. +-allowedcmds list "list" contains a comma separated list of the only + external commands that can be run. The full list of + associated options is: + + stunnel, ssl, unixpw, WAIT, id, accept, afteraccept, + gone, pipeinput, v4l-info, rawfb-setup, dt, gui, + storepasswd, crash. + + See each option's help to learn the associated external + command. Note that the -nocmds option takes precedence + and disables all external commands. -deny_all For use with -remote nodeny: start out denying all incoming clients until "-remote nodeny" is used to diff --git a/x11vnc/cleanup.c b/x11vnc/cleanup.c index 0d5926e..bbf2d29 100644 --- a/x11vnc/cleanup.c +++ b/x11vnc/cleanup.c @@ -312,7 +312,7 @@ static void crash_shell(void) { } else if (*str == 's' && *(str+1) == '\0') { sprintf(cmd, "sh -c '(%s) &'", crash_stack_command1); /* crash */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("crash")) { fprintf(stderr, "\nno_external_cmds=%d\n", no_external_cmds); goto crash_prompt; diff --git a/x11vnc/connections.c b/x11vnc/connections.c index ec77101..37ba798 100644 --- a/x11vnc/connections.c +++ b/x11vnc/connections.c @@ -14,6 +14,7 @@ #include "sslcmds.h" #include "sslhelper.h" #include "xwrappers.h" +#include "xevents.h" /* * routines for handling incoming, outgoing, etc connections @@ -44,6 +45,7 @@ void check_gui_inputs(void); enum rfbNewClientAction new_client(rfbClientPtr client); void start_client_info_sock(char *host_port_cookie); void send_client_info(char *str); +void adjust_grabs(int grab, int quiet); void check_new_clients(void); @@ -328,6 +330,32 @@ void set_child_info(void) { } } +int cmd_ok(char *cmd) { + char *p, *str; + if (no_external_cmds) { + return 0; + } + if (! cmd || cmd[0] == '\0') { + return 0; + } + if (! allowed_external_cmds) { + /* default, allow any (overridden by -nocmds) */ + return 1; + } + + str = strdup(allowed_external_cmds); + p = strtok(str, ","); + while (p) { + if (!strcmp(p, cmd)) { + free(str); + return 1; + } + p = strtok(NULL, ","); + } + free(str); + return 0; +} + /* * utility to run a user supplied command setting some RFB_ env vars. * used by, e.g., accept_client() and client_gone() @@ -336,7 +364,7 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) { char *old_display = NULL; char *addr = client->host; char str[100]; - int rc; + int rc, ok; ClientData *cd = (ClientData *) client->clientData; if (addr == NULL || addr[0] == '\0') { @@ -414,11 +442,11 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) { if (cd) { sprintf(str, "%d", (int) cd->login_time); } else { - sprintf(str, ">%d", (int) time(0)); + sprintf(str, ">%d", (int) time(NULL)); } set_env("RFB_LOGIN_TIME", str); - sprintf(str, "%d", (int) time(0)); + sprintf(str, "%d", (int) time(NULL)); set_env("RFB_CURRENT_TIME", str); if (!cd || !cd->username || cd->username[0] == '\0') { @@ -449,7 +477,17 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) { set_env("RFB_CLIENT_COUNT", str); /* gone, accept, afteraccept */ - if (no_external_cmds) { + ok = 0; + if (!strcmp(mode, "accept") && cmd_ok("accept")) { + ok = 1; + } + if (!strcmp(mode, "afteraccept") && cmd_ok("afteraccept")) { + ok = 1; + } + if (!strcmp(mode, "gone") && cmd_ok("gone")) { + ok = 1; + } + if (no_external_cmds || !ok) { rfbLogEnable(1); rfbLog("cannot run external commands in -nocmds mode:\n"); rfbLog(" \"%s\"\n", cmd); @@ -1398,7 +1436,7 @@ static void check_connect_file(char *file) { char line[VNC_CONNECT_MAX], host[VNC_CONNECT_MAX]; static int first_warn = 1, truncate_ok = 1; static time_t last_time = 0; - time_t now = time(0); + time_t now = time(NULL); if (last_time == 0) { last_time = now; @@ -1846,7 +1884,7 @@ void check_gui_inputs(void) { enum rfbNewClientAction new_client(rfbClientPtr client) { ClientData *cd; - last_event = last_input = time(0); + last_event = last_input = time(NULL); if (inetd) { @@ -1902,7 +1940,7 @@ if (getenv("NEW_CLIENT")) fprintf(stderr, "new_client: %s %d\n", client->host, c cd->input[0] = '-'; cd->login_viewonly = -1; - cd->login_time = time(0); + cd->login_time = time(NULL); cd->ssl_helper_pid = 0; if (use_openssl && openssl_last_helper_pid) { @@ -1933,7 +1971,7 @@ if (0) fprintf(stderr, "SET ssl_helper_pid: %d\n", openssl_last_helper_pid); } client_count++; - last_keyboard_input = last_pointer_input = time(0); + last_keyboard_input = last_pointer_input = time(NULL); if (no_autorepeat && client_count == 1 && ! view_only) { /* @@ -1958,7 +1996,7 @@ if (0) fprintf(stderr, "SET ssl_helper_pid: %d\n", openssl_last_helper_pid); cd->raw_bytes_sent = 0; accepted_client = 1; - last_client = time(0); + last_client = time(NULL); if (unixpw) { unixpw_in_progress = 1; @@ -1968,7 +2006,7 @@ if (0) fprintf(stderr, "SET ssl_helper_pid: %d\n", openssl_last_helper_pid); unixpw_login_viewonly = 1; client->viewOnly = FALSE; } - unixpw_last_try_time = time(0); + unixpw_last_try_time = time(NULL); unixpw_screen(1); unixpw_keystroke(0, 0, 1); } @@ -2027,7 +2065,7 @@ void start_client_info_sock(char *host_port_cookie) { if (sock >= 0) { char *lst = list_clients(); icon_mode_socks[next] = sock; - start_time[next] = time(0); + start_time[next] = time(NULL); write(sock, "COOKIE:", strlen("COOKIE:")); write(sock, cookie, strlen(cookie)); write(sock, "\n", strlen("\n")); @@ -2105,6 +2143,40 @@ void send_client_info(char *str) { } } +void adjust_grabs(int grab, int quiet) { + RAWFB_RET_VOID + /* n.b. caller decides to X_LOCK or not. */ + if (grab) { + if (grab_kbd) { + if (! quiet) { + rfbLog("grabbing keyboard with XGrabKeyboard\n"); + } + XGrabKeyboard(dpy, window, False, GrabModeAsync, + GrabModeAsync, CurrentTime); + } + if (grab_ptr) { + if (! quiet) { + rfbLog("grabbing pointer with XGrabPointer\n"); + } + XGrabPointer(dpy, window, False, 0, GrabModeAsync, + GrabModeAsync, None, None, CurrentTime); + } + } else { + if (grab_kbd) { + if (! quiet) { + rfbLog("ungrabbing keyboard with XUngrabKeyboard\n"); + } + XUngrabKeyboard(dpy, CurrentTime); + } + if (grab_ptr) { + if (! quiet) { + rfbLog("ungrabbing pointer with XUngrabPointer\n"); + } + XUngrabPointer(dpy, CurrentTime); + } + } +} + void check_new_clients(void) { static int last_count = 0; rfbClientIteratorPtr iter; @@ -2117,12 +2189,27 @@ void check_new_clients(void) { unixpw_login_viewonly = 1; unixpw_client->viewOnly = FALSE; } - if (time(0) > unixpw_last_try_time + 25) { + if (time(NULL) > unixpw_last_try_time + 25) { rfbLog("unixpw_deny: timed out waiting for reply.\n"); unixpw_deny(); } return; } + + if (grab_kbd || grab_ptr) { + static double last_force = 0.0; + if (client_count != last_count || dnow() > last_force + 0.25) { + int q = (client_count == last_count); + last_force = dnow(); + X_LOCK; + if (client_count) { + adjust_grabs(1, q); + } else { + adjust_grabs(0, q); + } + X_UNLOCK; + } + } if (client_count == last_count) { return; @@ -2143,6 +2230,7 @@ void check_new_clients(void) { if (! screen) { return; } + if (! client_count) { send_client_info("clients:none"); return; diff --git a/x11vnc/connections.h b/x11vnc/connections.h index 6b736ed..1f70d42 100644 --- a/x11vnc/connections.h +++ b/x11vnc/connections.h @@ -28,6 +28,7 @@ extern void check_gui_inputs(void); extern enum rfbNewClientAction new_client(rfbClientPtr client); extern void start_client_info_sock(char *host_port_cookie); extern void send_client_info(char *str); +extern void adjust_grabs(int grab, int quiet); extern void check_new_clients(void); #endif /* _X11VNC_CONNECTIONS_H */ diff --git a/x11vnc/cursor.c b/x11vnc/cursor.c index e9a2d54..2c2a763 100644 --- a/x11vnc/cursor.c +++ b/x11vnc/cursor.c @@ -1262,7 +1262,7 @@ static int get_xfixes_cursor(int init) { oldest++; } oldtime = curs_times[oldest]; - now = time(0); + now = time(NULL); for (i = CURS_DYN_MIN; i <= CURS_DYN_MAX; i++) { if (screen && screen->cursor == cursors[i]->rfb) { ; diff --git a/x11vnc/gui.c b/x11vnc/gui.c index 99d35ba..d38640d 100644 --- a/x11vnc/gui.c +++ b/x11vnc/gui.c @@ -420,7 +420,7 @@ if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc } /* gui */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("gui")) { fprintf(stderr, "cannot run external commands in -nocmds " "mode:\n"); fprintf(stderr, " \"%s\"\n", "gui + wish"); diff --git a/x11vnc/help.c b/x11vnc/help.c index 87062ce..5d8eb61 100644 --- a/x11vnc/help.c +++ b/x11vnc/help.c @@ -305,6 +305,7 @@ void print_help(int mode) { " option, otherwise the stderr goes to the viewer which\n" " will cause it to abort. Specifying both -inetd and -q\n" " and no -o will automatically close the stderr.\n" +"\n" "-nofilexfer Disable the TightVNC file transfer extension. (same as\n" " -disablefiletransfer). Note that when the -viewonly\n" " option is supplied all file transfers are disabled.\n" @@ -312,6 +313,7 @@ void print_help(int mode) { " However, if the remote control mechanism is used to\n" " change the global or per-client viewonly state the\n" " filetransfer permissions will NOT change.\n" +"\n" "-http Instead of using -httpdir (see below) to specify\n" " where the Java vncviewer applet is, have x11vnc try\n" " to *guess* where the directory is by looking relative\n" @@ -388,6 +390,23 @@ void print_help(int mode) { " a global -viewonly is in effect (all input is discarded\n" " in that case).\n" "\n" +"-grabkbd When VNC viewers are connected, attempt to the grab the\n" +" keyboard so someone sitting at the physical display\n" +" is not able to enter keystrokes. This method uses\n" +" XGrabKeyboard(3X11) and so it is not secure and does not\n" +" rule out the person at the physical display injecting\n" +" keystrokes by flooding the server with them, grabbing\n" +" the keyboard himself, etc. Some degree of cooperation\n" +" from the person at the display is assumed.\n" +"-grabptr As -grabkbd, but for the mouse pointer using\n" +" XGrabPointer(3X11). Unfortunately due to the way the X\n" +" server works, the mouse can still be moved around by the\n" +" user at the physical display, but he will not be able to\n" +" change window focus with it. Also some window managers\n" +" that call XGrabServer(3X11) for resizes, etc, will\n" +" act on the local user's input. Again, some degree of\n" +" cooperation from the person at the display is assumed.\n" +"\n" "-viewpasswd string Supply a 2nd password for view-only logins. The -passwd\n" " (full-access) password must also be supplied.\n" "\n" @@ -587,7 +606,25 @@ void print_help(int mode) { " as the user who just authenticated via the login and\n" " password prompt.\n" "\n" -" Thus the combination of -display WAIT:cmd=... and\n" +" Also in the case of -unixpw, the user logging in can\n" +" place a colon at the end of his username and supply\n" +" a few options: scale=, scale_cursor=, solid, id=,\n" +" clear_mods, clear_keys, repeat, or speeds= separated\n" +" by commas if there is more than one. After the user\n" +" logs in successfully, these options will be applied to\n" +" the VNC screen. For example,\n" +"\n" +" login: fred:scale=3/4,repeat\n" +" Password: ...\n" +"\n" +" for convenience m/n implies scale= e.g. fred:3/4\n" +" To disable this set the environment variable\n" +" X11VNC_NO_UNIXPW_OPTS=1. To set any other options,\n" +" the user can use the gui (x11vnc -gui connect) or the\n" +" remote control method (x11vnc -R opt:val) during his\n" +" VNC session.\n" +"\n" +" So the combination of -display WAIT:cmd=... and\n" " -unixpw allows automatic pairing of an unix\n" " authenticated VNC user with his desktop. This could\n" " be very useful on SunRays and also any system where\n" @@ -620,7 +657,7 @@ void print_help(int mode) { " 5815 stream tcp nowait root /usr/sbin/tcpd .../x11vnc \\\n" " -inetd -q -http_ssl -display WAIT:cmd=HTTPONCE\n" "\n" -" Is used in the Apache SSL-portal example (see FAQ).\n" +" It is used in the Apache SSL-portal example (see FAQ).\n" "\n" " Finally, one can insert a geometry between colons,\n" " e.g. WAIT:1280x1024:... to set the size of the display\n" @@ -1404,6 +1441,12 @@ void print_help(int mode) { "-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc file.\n" "-norc Do not process any .x11vncrc file for options.\n" "\n" +"-env VAR=VALUE Set the environment variable 'VAR' to value 'VALUE'\n" +" at x11vnc startup. This is a convenience utility to\n" +" avoid shell script wrappers, etc. to set the env. var.\n" +" You may specify as many of these as needed on the\n" +" command line.\n" +"\n" "-h, -help Print this help text.\n" "-?, -opts Only list the x11vnc options.\n" "-V, -version Print program version and last modification date.\n" @@ -2719,6 +2762,10 @@ void print_help(int mode) { " nolookup enable -nolookup mode.\n" " lookup disable -nolookup mode.\n" " input:str set -input to \"str\", empty to disable.\n" +" grabkbd enable -grabkbd mode.\n" +" nograbkbd disable -grabkbd mode.\n" +" grabptr enable -grabptr mode.\n" +" nograbptr disable -grabptr mode.\n" " client_input:str set the K, M, B -input on a per-client\n" " basis. select which client as for\n" " disconnect, e.g. client_input:host:MB\n" @@ -2976,13 +3023,14 @@ void print_help(int mode) { " scr_skip scr_inc scr_keys scr_term scr_keyrepeat\n" " scr_parms scrollcopyrect scr noscrollcopyrect noscr\n" " fixscreen noxrecord xrecord reset_record pointer_mode\n" -" pm input_skip input client_input speeds wmdt\n" -" debug_pointer dp nodebug_pointer nodp debug_keyboard\n" -" dk nodebug_keyboard nodk deferupdate defer wait_ui\n" -" wait_bog nowait_bog slow_fb wait readtimeout nap nonap\n" -" sb screen_blank fbpm nofbpm fs gaps grow fuzz snapfb\n" -" nosnapfb rawfb progressive rfbport http nohttp httpport\n" -" httpdir enablehttpproxy noenablehttpproxy alwaysshared\n" +" pm input_skip input grabkbd nograbkbd grabptr\n" +" nograbptr client_input speeds wmdt debug_pointer dp\n" +" nodebug_pointer nodp debug_keyboard dk nodebug_keyboard\n" +" nodk deferupdate defer wait_ui wait_bog nowait_bog\n" +" slow_fb wait readtimeout nap nonap sb screen_blank\n" +" fbpm nofbpm fs gaps grow fuzz snapfb nosnapfb rawfb\n" +" progressive rfbport http nohttp httpport httpdir\n" +" enablehttpproxy noenablehttpproxy alwaysshared\n" " noalwaysshared nevershared noalwaysshared dontdisconnect\n" " nodontdisconnect desktop debug_xevents nodebug_xevents\n" " debug_xevents debug_xdamage nodebug_xdamage\n" @@ -2997,12 +3045,8 @@ void print_help(int mode) { " scale_str scaled_x scaled_y scale_numer scale_denom\n" " scale_fac scaling_blend scaling_nomult4 scaling_pad\n" " scaling_interpolate inetd privremote unsafe safer nocmds\n" -#ifndef REL81 " passwdfile unixpw unixpw_nis unixpw_list ssl ssl_pem\n" " sslverify stunnel stunnel_pem https usepw using_shm\n" -#else -" passwdfile usepw using_shm\n" -#endif " logfile o flag rc norc h help V version lastmod bg\n" " sigpipe threads readrate netrate netlatency pipeinput\n" " clients client_count pid ext_xtest ext_xtrap ext_xrecord\n" @@ -3073,6 +3117,17 @@ void print_help(int mode) { " remote-control is disabled it cannot be turned back on.\n" "-nocmds No external commands (e.g. system(3), popen(3), exec(3))\n" " will be run.\n" +"-allowedcmds list \"list\" contains a comma separated list of the only\n" +" external commands that can be run. The full list of\n" +" associated options is:\n" +"\n" +" stunnel, ssl, unixpw, WAIT, id, accept, afteraccept,\n" +" gone, pipeinput, v4l-info, rawfb-setup, dt, gui,\n" +" storepasswd, crash.\n" +"\n" +" See each option's help to learn the associated external\n" +" command. Note that the -nocmds option takes precedence\n" +" and disables all external commands.\n" "\n" "-deny_all For use with -remote nodeny: start out denying all\n" " incoming clients until \"-remote nodeny\" is used to\n" @@ -3247,7 +3302,7 @@ void nopassword_warning_msg(int gotloc) { "#@ YOU ARE RUNNING X11VNC WITHOUT A PASSWORD!! @#\n" "#@ @#\n" "#@ This means anyone with network access to this computer @#\n" -"#@ will be able to easily view and control your desktop. @#\n" +"#@ will be able to view and control your desktop. @#\n" "#@ @#\n" "#@ >>> If you did not mean to do this Press CTRL-C now!! <<< @#\n" "#@ @#\n" @@ -3257,16 +3312,18 @@ void nopassword_warning_msg(int gotloc) { "#@ @#\n" "#@ You can create an x11vnc password file by running: @#\n" "#@ @#\n" -"#@ x11vnc -storepasswd password /path/to/passfile @#\n" +"#@ x11vnc -storepasswd password /path/to/passfile @#\n" +"#@ or x11vnc -storepasswd /path/to/passfile @#\n" +"#@ or x11vnc -storepasswd @#\n" +"#@ @#\n" +"#@ (the last one will use ~/.vnc/passwd) @#\n" "#@ @#\n" "#@ and then starting x11vnc via: @#\n" "#@ @#\n" "#@ x11vnc -rfbauth /path/to/passfile @#\n" "#@ @#\n" -"#@ an existing ~/.vnc/passwd file will work too. @#\n" -"#@ @#\n" -"#@ Running \"x11vnc -storepasswd\" with no arguments @#\n" -"#@ will prompt for a passwd to store in ~/.vnc/passwd. @#\n" +"#@ an existing ~/.vnc/passwd file from another VNC @#\n" +"#@ application will work fine too. @#\n" "#@ @#\n" "#@ You can also use the -passwdfile or -passwd options. @#\n" "#@ (note -passwd is unsafe if local users are not trusted) @#\n" @@ -3277,7 +3334,8 @@ void nopassword_warning_msg(int gotloc) { "#@ Use x11vnc -usepw to automatically use your @#\n" "#@ ~/.vnc/passwd or ~/.vnc/passwdfile password files. @#\n" "#@ (and prompt you to create ~/.vnc/passwd if neither @#\n" -"#@ file exists.) @#\n" +"#@ file exists.) Under -usepw, x11vnc will exit if it @#\n" +"#@ cannot find a password to use. @#\n" "#@ @#\n" "#@ @#\n" "#@ Even with a password, the subsequent VNC traffic is @#\n" diff --git a/x11vnc/keyboard.c b/x11vnc/keyboard.c index c160726..a2ae349 100644 --- a/x11vnc/keyboard.c +++ b/x11vnc/keyboard.c @@ -324,7 +324,7 @@ void autorepeat(int restore, int bequiet) { void check_add_keysyms(void) { static time_t last_check = 0; int clear_freq = 300, quiet = 1, count; - time_t now = time(0); + time_t now = time(NULL); if (unixpw_in_progress) return; @@ -2612,7 +2612,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { KeyCode k; int idx, isbutton = 0; allowed_input_t input; - time_t now = time(0); + time_t now = time(NULL); double tnow; static int skipped_last_down; static rfbBool last_down; diff --git a/x11vnc/options.c b/x11vnc/options.c index b14967b..5e60627 100644 --- a/x11vnc/options.c +++ b/x11vnc/options.c @@ -75,6 +75,7 @@ int no_external_cmds = 0; /* -nocmds */ #else int no_external_cmds = 1; /* cannot be turned back on. */ #endif +char *allowed_external_cmds = NULL; int started_as_root = 0; int host_lookup = 1; char *users_list = NULL; /* -users */ diff --git a/x11vnc/options.h b/x11vnc/options.h index f49c70a..059db27 100644 --- a/x11vnc/options.h +++ b/x11vnc/options.h @@ -56,6 +56,7 @@ extern int safe_remote_only; extern int priv_remote; extern int more_safe; extern int no_external_cmds; +extern char *allowed_external_cmds; extern int started_as_root; extern int host_lookup; extern char *users_list; diff --git a/x11vnc/pm.c b/x11vnc/pm.c index 2ddb009..75e4e1e 100644 --- a/x11vnc/pm.c +++ b/x11vnc/pm.c @@ -51,10 +51,10 @@ static void check_fbpm(void) { if (! client_count) { return; } - if (time(0) < last_fbpm + 5) { + if (time(NULL) < last_fbpm + 5) { return; } - last_fbpm = time(0); + last_fbpm = time(NULL); if (FBPMInfo(dpy, &level, &enabled)) { if (db) fprintf(stderr, "FBPMInfo level: %d enabled: %d\n", level, enabled); diff --git a/x11vnc/pointer.c b/x11vnc/pointer.c index 1ad10e9..30268e7 100644 --- a/x11vnc/pointer.c +++ b/x11vnc/pointer.c @@ -319,7 +319,7 @@ static void update_x11_pointer_position(int x, int y) { rc = set_cursor(x, y, get_which_cursor()); cursor_changes += rc; - last_event = last_input = last_pointer_input = time(0); + last_event = last_input = last_pointer_input = time(NULL); } void do_button_mask_change(int mask, int button) { @@ -390,7 +390,7 @@ void do_button_mask_change(int mask, int button) { static void update_x11_pointer_mask(int mask) { int snapped = 0, xr_mouse = 1, i; - last_event = last_input = last_pointer_input = time(0); + last_event = last_input = last_pointer_input = time(NULL); RAWFB_RET_VOID @@ -942,7 +942,7 @@ if (0) fprintf(stderr, "initialize_pipeinput: %s -- %s\n", pipeinput_str, p); set_child_info(); /* pipeinput */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("pipeinput")) { rfbLogEnable(1); rfbLog("cannot run external commands in -nocmds mode:\n"); rfbLog(" \"%s\"\n", p); diff --git a/x11vnc/remote.c b/x11vnc/remote.c index b68e9b1..ae5361f 100644 --- a/x11vnc/remote.c +++ b/x11vnc/remote.c @@ -296,7 +296,10 @@ int check_httpdir(void) { p = strtok(path, ":"); while(p) { - free(prog); + if (prog) { + free(prog); + prog = NULL; + } len = strlen(p) + 1 + strlen(base) + 1; prog = (char *) malloc(len); snprintf(prog, len, "%s/%s", p, base); @@ -314,6 +317,7 @@ int check_httpdir(void) { * 12345678901234567 * /path/to/bin/../share/x11vnc/classes/ssl * 123456789012345678901 + * 21 */ if ((q = strrchr(prog, '/')) == NULL) { rfbLog("check_httpdir: bad program path: %s\n", prog); @@ -648,13 +652,25 @@ char *process_remote_cmd(char *cmd, int stringonly) { /* comma separated batch mode */ char *s, *q, *res; char tmp[512]; - strcpy(buf, ""); + char **pieces; + int k = 0, n = 0; + + pieces = (char **) malloc(strlen(cmd) * sizeof(char *)); s = strdup(cmd + strlen("qry=")); q = strtok(s, ","); + while (q) { strcpy(tmp, "qry="); strncat(tmp, q, 500); - res = process_remote_cmd(tmp, 1); + pieces[n] = strdup(tmp); + n++; + q = strtok(NULL, ","); + } + free(s); + + strcpy(buf, ""); + for (k=0; k= X11VNC_REMOTE_MAX - 1) { rfbLog("overflow in process_remote_cmd:" @@ -666,12 +682,14 @@ char *process_remote_cmd(char *cmd, int stringonly) { strcat(buf, res); free(res); } - q = strtok(NULL, ","); - if (q) { + if (k < n - 1) { strcat(buf, ","); } } - free(s); + for (k=0; kdata = (char *) malloc(xim->bytes_per_line * xim->height); if (xim->data == NULL) { rfbErr("XCreateImage(%s) data malloc failed.\n", name); @@ -349,7 +349,7 @@ void shm_delete(XShmSegmentInfo *shm) { void shm_clean(XShmSegmentInfo *shm, XImage *xim) { int db = 0; - if (db) fprintf(stderr, "shm_clean: called: 0x%x\n", xim); + if (db) fprintf(stderr, "shm_clean: called: %p\n", xim); X_LOCK; #if LIBVNCSERVER_HAVE_XSHM if (shm != NULL && shm->shmid != -1 && dpy) { @@ -360,11 +360,11 @@ void shm_clean(XShmSegmentInfo *shm, XImage *xim) { if (xim != NULL) { if (! raw_fb_back_to_X) { /* raw_fb hack */ if (xim->bitmap_unit != -1) { - if (db) fprintf(stderr, "shm_clean: XDestroyImage 0x%x\n", xim); + if (db) fprintf(stderr, "shm_clean: XDestroyImage %p\n", xim); XDestroyImage(xim); } else { if (xim->data) { - if (db) fprintf(stderr, "shm_clean: free xim->data 0x%x 0x%x\n", xim, xim->data); + if (db) fprintf(stderr, "shm_clean: free xim->data %p %p\n", xim, xim->data); free(xim->data); xim->data = NULL; } @@ -1228,7 +1228,7 @@ void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { * damage_delay seconds. */ int debug = 0; - if (time(0) > damage_time + damage_delay) { + if (time(NULL) > damage_time + damage_delay) { if (! quiet) { rfbLog("damaging turned off.\n"); } @@ -2153,7 +2153,7 @@ if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - st */ static void nap_set(int tile_cnt) { int nap_in = nap_ok; - time_t now = time(0); + time_t now = time(NULL); if (scan_count == 0) { /* roll up check for all NSCAN scans */ @@ -2219,7 +2219,7 @@ static void nap_check(int tile_cnt) { return; } - now = time(0); + now = time(NULL); if (screen_blank > 0) { int dt_ev, dt_fbu, ms = 2000; @@ -2254,7 +2254,7 @@ static void nap_check(int tile_cnt) { */ static void ping_clients(int tile_cnt) { static time_t last_send = 0; - time_t now = time(0); + time_t now = time(NULL); if (rfbMaxClientWait < 20000) { rfbMaxClientWait = 20000; diff --git a/x11vnc/screen.c b/x11vnc/screen.c index 117bc30..a309c5c 100644 --- a/x11vnc/screen.c +++ b/x11vnc/screen.c @@ -752,7 +752,7 @@ void check_padded_fb(void) { } if (unixpw_in_progress) return; - if (time(0) > pad_geometry_time+1 && all_clients_initialized()) { + if (time(NULL) > pad_geometry_time+1 && all_clients_initialized()) { remove_fake_fb(); } } @@ -776,7 +776,7 @@ void install_padded_fb(char *geom) { return; } install_fake_fb(w, h, bpp); - pad_geometry_time = time(0); + pad_geometry_time = time(NULL); } static void initialize_snap_fb(void) { @@ -885,7 +885,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n"); set_child_info(); q += strlen("setup:"); /* rawfb-setup */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("rawfb-setup")) { rfbLogEnable(1); rfbLog("cannot run external commands in -nocmds " "mode:\n"); @@ -1354,12 +1354,12 @@ static void initialize_clipshift(void) { static int wait_until_mapped(Window win) { int ms = 50, waittime = 30; - time_t start = time(0); + time_t start = time(NULL); XWindowAttributes attr; while (1) { if (! valid_window(win, NULL, 0)) { - if (time(0) > start + waittime) { + if (time(NULL) > start + waittime) { break; } usleep(ms * 1000); @@ -1840,7 +1840,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { fb_depth = (int) fb->depth; rfbLog("initialize_screen: fb_depth/fb_bpp/fb_Bpl %d/%d/%d\n", fb_depth, - fb_depth, fb_Bpl); + fb_bpp, fb_Bpl); main_bytes_per_line = fb->bytes_per_line; diff --git a/x11vnc/solid.c b/x11vnc/solid.c index 25d92e2..16e1628 100644 --- a/x11vnc/solid.c +++ b/x11vnc/solid.c @@ -54,7 +54,7 @@ static int dt_cmd(char *cmd) { } /* dt */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("dt")) { rfbLog("cannot run external commands in -nocmds mode:\n"); rfbLog(" \"%s\"\n", cmd); rfbLog(" dt_cmd: returning 1\n"); @@ -522,7 +522,11 @@ static void solid_gnome(char *color) { if (! orig_color) { char *q; - orig_color = strdup(cmd_output(get_color)); + if (cmd_ok("dt")) { + orig_color = strdup(cmd_output(get_color)); + } else { + orig_color = ""; + } if (*orig_color == '\0') { orig_color = strdup("#FFFFFF"); } @@ -532,7 +536,11 @@ static void solid_gnome(char *color) { } if (! orig_option) { char *q; - orig_option = strdup(cmd_output(get_option)); + if (cmd_ok("dt")) { + orig_option = strdup(cmd_output(get_option)); + } else { + orig_color = ""; + } if (*orig_option == '\0') { orig_option = strdup("stretched"); } diff --git a/x11vnc/sslcmds.c b/x11vnc/sslcmds.c index db31b5e..88254d1 100644 --- a/x11vnc/sslcmds.c +++ b/x11vnc/sslcmds.c @@ -32,7 +32,7 @@ static pid_t stunnel_pid = 0; void check_stunnel(void) { static time_t last_check = 0; - time_t now = time(0); + time_t now = time(NULL); if (last_check + 3 >= now) { return; @@ -72,13 +72,14 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { path = getenv("PATH"); if (! path) { - path = strdup(extra); + path = strdup(extra+1); } else { + char *pt = path; path = (char *) malloc(strlen(path)+strlen(extra)+1); if (! path) { return 0; } - strcpy(path, getenv("PATH")); + strcpy(path, pt); strcat(path, extra); } @@ -106,15 +107,16 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { } if (! stunnel_path) { + free(exe); return 0; } if (stunnel_path[0] == '\0') { - free(stunnel_path); + free(exe); return 0; } /* stunnel */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("stunnel")) { rfbLogEnable(1); rfbLog("start_stunnel: cannot run external commands in -nocmds mode:\n"); rfbLog(" \"%s\"\n", stunnel_path); @@ -140,7 +142,7 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { if (ssl_verify) { if (stat(ssl_verify, &verify_buf) != 0) { rfbLog("stunnel: %s does not exist.\n", ssl_verify); - return 0; + clean_up_exit(1); } } @@ -148,7 +150,7 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { if (stunnel_pid < 0) { stunnel_pid = 0; - free(stunnel_path); + free(exe); return 0; } @@ -162,7 +164,7 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { } if (use_stunnel == 3) { - char sp[20], xp[20], *a = NULL; + char sp[30], xp[30], *a = NULL; char *st = stunnel_path; char *pm = stunnel_pem; char *sv = ssl_verify; @@ -179,6 +181,7 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { } if (stunnel_pem && ssl_verify) { + /* XXX double check -v 2 */ execlp(st, st, "-f", "-d", sp, "-r", xp, "-P", "none", "-p", pm, a, sv, "-v", "2", (char *) NULL); @@ -212,6 +215,7 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { } else { fprintf(in, "CAfile = %s\n", ssl_verify); } + /* XXX double check -v 2 */ fprintf(in, "verify = 2\n"); } fprintf(in, ";debug = 7\n\n"); @@ -226,7 +230,8 @@ int start_stunnel(int stunnel_port, int x11vnc_port) { execlp(stunnel_path, stunnel_path, "-fd", fd, (char *) NULL); exit(1); } - free(stunnel_path); + + free(exe); usleep(500 * 1000); waitpid(stunnel_pid, &status, WNOHANG); @@ -263,9 +268,9 @@ void stop_stunnel(void) { void setup_stunnel(int rport, int *argc, char **argv) { int i, xport = 0; - if (! rport) { + if (! rport && argc && argv) { for (i=0; i< *argc; i++) { - if (!strcmp(argv[i], "-rfbport")) { + if (argv[i] && !strcmp(argv[i], "-rfbport")) { if (i < *argc - 1) { rport = atoi(argv[i+1]); break; @@ -281,18 +286,21 @@ void setup_stunnel(int rport, int *argc, char **argv) { goto stunnel_fail; } } + xport = find_free_port(5950, 5999); if (! xport) { goto stunnel_fail; } + if (start_stunnel(rport, xport)) { int tweaked = 0; - char tmp[20]; + char tmp[30]; sprintf(tmp, "%d", xport); - if (argv) { - for (i=0; i< *argc; i++) { - if (!strcmp(argv[i], "-rfbport")) { + if (argc && argv) { + for (i=0; i < *argc; i++) { + if (argv[i] && !strcmp(argv[i], "-rfbport")) { if (i < *argc - 1) { + /* replace orig value */ argv[i+i] = strdup(tmp); tweaked = 1; break; @@ -353,7 +361,7 @@ char *get_Cert_dir(char *cdir_in, char **tmp_in) { sprintf(cdir, "%s%s", home, cases1[1]); } - tmp = (char *) malloc(strlen(cdir) + 10); + tmp = (char *) malloc(strlen(cdir) + strlen("/tmp") + 1); for (i=0; i<3; i++) { int ret; sprintf(tmp, "%s%s", cdir, cases2[i]); @@ -380,35 +388,36 @@ char *get_Cert_dir(char *cdir_in, char **tmp_in) { return cdir; } -void sslGenCA(char *cdir) { +static char *getsslscript(char *cdir, char *name, char *script) { char *openssl = find_openssl_bin(); - char *tmp, *cmd, *scr, *cdir_use; + char *tmp, *scr, *cdir_use; FILE *out; - if (! openssl) { + if (! openssl || openssl[0] == '\0') { + exit(1); + } + + if (!name || !script) { exit(1); } cdir_use = get_Cert_dir(cdir, &tmp); - if (! cdir_use) { + if (!cdir_use || !tmp) { exit(1); } - cmd = (char *) malloc(strlen(tmp) + 100); - scr = (char *) malloc(strlen(tmp) + 100); + scr = (char *) malloc(strlen(tmp) + 1 + strlen(name) + 30); - sprintf(cmd, "%s/genca.%d.sh", tmp, getpid()); - out = fopen(cmd, "w"); + sprintf(scr, "%s/%s.%d.sh", tmp, name, getpid()); + out = fopen(scr, "w"); if (! out) { - rfbLog("could not open: %s\n", cmd); + rfbLog("could not open: %s\n", scr); rfbLogPerror("fopen"); exit(1); } - fprintf(out, "%s", genCA); + fprintf(out, "%s", script); fclose(out); - sprintf(scr, "/bin/sh %s", cmd); - rfbLog("Using openssl: %s\n", openssl); rfbLog("Using certs dir: %s\n", cdir_use); fprintf(stderr, "\n"); @@ -416,45 +425,36 @@ void sslGenCA(char *cdir) { set_env("BASE_DIR", cdir_use); set_env("OPENSSL", openssl); - system(scr); - unlink(cmd); + return scr; } -void sslGenCert(char *ty, char *nm) { - char *openssl = find_openssl_bin(); - char *tmp, *cmd, *scr, *cdir_use; - FILE *out; +void sslGenCA(char *cdir) { + char *cmd, *scr = getsslscript(cdir, "genca", genCA); - if (! openssl) { + if (! scr) { exit(1); } - cdir_use = get_Cert_dir(NULL, &tmp); - if (! cdir_use) { - exit(1); - } + cmd = (char *)malloc(strlen("/bin/sh ") + strlen(scr) + 1); + sprintf(cmd, "/bin/sh %s", scr); - cmd = (char *) malloc(strlen(tmp) + 100); - scr = (char *) malloc(strlen(tmp) + 100); + system(cmd); + unlink(scr); - sprintf(cmd, "%s/gencert.%d.sh", tmp, getpid()); - out = fopen(cmd, "w"); - if (! out) { - rfbLog("could not open: %s\n", cmd); - rfbLogPerror("fopen"); + free(cmd); + free(scr); +} + +void sslGenCert(char *ty, char *nm) { + char *cmd, *scr = getsslscript(NULL, "gencert", genCert); + + if (! scr) { exit(1); } - fprintf(out, "%s", genCert); - fclose(out); - - sprintf(scr, "/bin/sh %s", cmd); - rfbLog("Using openssl: %s\n", openssl); - rfbLog("Using certs dir: %s\n", cdir_use); - fprintf(stderr, "\n"); + cmd = (char *)malloc(strlen("/bin/sh ") + strlen(scr) + 1); + sprintf(cmd, "/bin/sh %s", scr); - set_env("BASE_DIR", cdir_use); - set_env("OPENSSL", openssl); if (! ty) { set_env("TYPE", ""); } else { @@ -474,17 +474,18 @@ void sslGenCert(char *ty, char *nm) { } } - system(scr); - unlink(cmd); + system(cmd); + unlink(scr); + + free(cmd); + free(scr); } void sslEncKey(char *path, int mode) { char *openssl = find_openssl_bin(); - char *scr, *cert = NULL, *tca; + char *scr, *cert = NULL, *tca, *cdir = NULL; char line[1024], tmp[] = "/tmp/x11vnc-tmp.XXXXXX"; - char *cdir = NULL; - int tmp_fd, incert, info_only = 0, delete_only = 0; - int listlong = 0; + int tmp_fd, incert, info_only = 0, delete_only = 0, listlong = 0; struct stat sbuf; FILE *file; static int depth = 0; @@ -493,6 +494,11 @@ void sslEncKey(char *path, int mode) { /* get_saved_pem may call us back. */ return; } + + if (! path) { + return; + } + depth++; if (mode == 1) { @@ -504,8 +510,9 @@ void sslEncKey(char *path, int mode) { if (! openssl) { exit(1); } + cdir = get_Cert_dir(NULL, &tca); - if (! cdir) { + if (! cdir || ! tca) { fprintf(stderr, "could not find Cert dir\n"); exit(1); } @@ -518,28 +525,38 @@ void sslEncKey(char *path, int mode) { if (strstr(path, "SAVE") == path) { char *p = get_saved_pem(path, 0); if (p == NULL) { - fprintf(stderr, "could not find saved pem matching: %s\n", path); + fprintf(stderr, "could not find saved pem " + "matching: %s\n", path); exit(1); } path = p; - } else if (!strcmp(path, "CA") && cdir) { - tca = (char *) malloc(strlen(cdir) + strlen("/CA/cacert.pem") + 1); + } else if (!strcmp(path, "CA")) { + tca = (char *) malloc(strlen(cdir)+strlen("/CA/cacert.pem")+1); sprintf(tca, "%s/CA/cacert.pem", cdir); path = tca; - } else if (info_only && (!strcasecmp(path, "LIST") || !strcasecmp(path, "LS") || - !strcasecmp(path, "ALL"))) { - if (! cdir || strchr(cdir, '\'')) { - fprintf(stderr, "bad certdir char: %s\n", cdir ? cdir : "null"); + } else if (info_only && (!strcasecmp(path, "LIST") || + !strcasecmp(path, "LS") || !strcasecmp(path, "ALL"))) { + + if (! program_name || strchr(program_name, ' ')) { + fprintf(stderr, "bad program name.\n"); + exit(1); + } + if (strchr(cdir, '\'')) { + fprintf(stderr, "bad certdir char: %s\n", cdir); exit(1); } - tca = (char *) malloc(2*strlen(cdir) + strlen(program_name) + 1000); - sprintf(tca, "find '%s' | egrep '/(CA|tmp|clients)$|\\.(crt|pem|key|req)$' " - "| grep -v CA/newcerts", cdir); + + tca = (char *) malloc(2*strlen(cdir)+strlen(program_name)+1000); + + sprintf(tca, "find '%s' | egrep '/(CA|tmp|clients)$|" + "\\.(crt|pem|key|req)$' | grep -v CA/newcerts", cdir); + if (!strcasecmp(path, "ALL")) { /* ugh.. */ - strcat(tca, " | egrep -v 'private/cakey.pem|(CA|tmp|clients)$' | xargs -n1 "); + strcat(tca, " | egrep -v 'private/cakey.pem|" + "(CA|tmp|clients)$' | xargs -n1 "); strcat(tca, program_name); strcat(tca, " -ssldir '"); strcat(tca, cdir); @@ -548,6 +565,8 @@ void sslEncKey(char *path, int mode) { strcat(tca, " | xargs ls -ld "); } system(tca); + free(tca); + depth--; return; @@ -562,7 +581,7 @@ void sslEncKey(char *path, int mode) { write(tmp_fd, genCert, strlen(genCert)); close(tmp_fd); - scr = (char *) malloc(strlen(tmp) + 100); + scr = (char *) malloc(strlen("/bin/sh ") + strlen(tmp) + 1); sprintf(scr, "/bin/sh %s", tmp); set_env("BASE_DIR", cdir); @@ -575,57 +594,59 @@ void sslEncKey(char *path, int mode) { } system(scr); unlink(tmp); + free(scr); + depth--; return; } + if (stat(path, &sbuf) != 0) { - if (strstr(path, "client") || strchr(path, '/') == NULL) { - int i; - tca = (char *) malloc(strlen(cdir) + strlen("/clients") - + strlen(path) + 100); - for (i = 1; i <= 15; i++) { - tca[0] = '\0'; - if ( i == 1) { - sprintf(tca, "%s/%s", cdir, path); - } else if (i == 2 && mode > 0) { - sprintf(tca, "%s/%s.crt", cdir, path); - } else if (i == 3) { - sprintf(tca, "%s/%s.pem", cdir, path); - } else if (i == 4 && mode > 1) { - sprintf(tca, "%s/%s.req", cdir, path); - } else if (i == 5 && mode > 1) { - sprintf(tca, "%s/%s.key", cdir, path); - } else if (i == 6) { - sprintf(tca, "%s/clients/%s", cdir, path); - } else if (i == 7 && mode > 0) { - sprintf(tca, "%s/clients/%s.crt", cdir, path); - } else if (i == 8) { - sprintf(tca, "%s/clients/%s.pem", cdir, path); - } else if (i == 9 && mode > 1) { - sprintf(tca, "%s/clients/%s.req", cdir, path); - } else if (i == 10 && mode > 1) { - sprintf(tca, "%s/clients/%s.key", cdir, path); - } else if (i == 11) { - sprintf(tca, "%s/server-%s", cdir, path); - } else if (i == 12 && mode > 0) { - sprintf(tca, "%s/server-%s.crt", cdir, path); - } else if (i == 13) { - sprintf(tca, "%s/server-%s.pem", cdir, path); - } else if (i == 14 && mode > 1) { - sprintf(tca, "%s/server-%s.req", cdir, path); - } else if (i == 15 && mode > 1) { - sprintf(tca, "%s/server-%s.key", cdir, path); - } - if (tca[0] == '\0') { - continue; - } - if (stat(tca, &sbuf) == 0) { - path = tca; - break; - } + if (strstr(path, "client") || strchr(path, '/') == NULL) { + int i; + tca = (char *) malloc(strlen(cdir) + strlen(path) + 100); + for (i = 1; i <= 15; i++) { + tca[0] = '\0'; + if ( i == 1) { + sprintf(tca, "%s/%s", cdir, path); + } else if (i == 2 && mode > 0) { + sprintf(tca, "%s/%s.crt", cdir, path); + } else if (i == 3) { + sprintf(tca, "%s/%s.pem", cdir, path); + } else if (i == 4 && mode > 1) { + sprintf(tca, "%s/%s.req", cdir, path); + } else if (i == 5 && mode > 1) { + sprintf(tca, "%s/%s.key", cdir, path); + } else if (i == 6) { + sprintf(tca, "%s/clients/%s", cdir, path); + } else if (i == 7 && mode > 0) { + sprintf(tca, "%s/clients/%s.crt", cdir, path); + } else if (i == 8) { + sprintf(tca, "%s/clients/%s.pem", cdir, path); + } else if (i == 9 && mode > 1) { + sprintf(tca, "%s/clients/%s.req", cdir, path); + } else if (i == 10 && mode > 1) { + sprintf(tca, "%s/clients/%s.key", cdir, path); + } else if (i == 11) { + sprintf(tca, "%s/server-%s", cdir, path); + } else if (i == 12 && mode > 0) { + sprintf(tca, "%s/server-%s.crt", cdir, path); + } else if (i == 13) { + sprintf(tca, "%s/server-%s.pem", cdir, path); + } else if (i == 14 && mode > 1) { + sprintf(tca, "%s/server-%s.req", cdir, path); + } else if (i == 15 && mode > 1) { + sprintf(tca, "%s/server-%s.key", cdir, path); + } + if (tca[0] == '\0') { + continue; + } + if (stat(tca, &sbuf) == 0) { + path = tca; + break; } } + } } if (stat(path, &sbuf) != 0) { @@ -635,7 +656,7 @@ void sslEncKey(char *path, int mode) { } if (! info_only) { - cert = (char *) malloc(2*(sbuf.st_size + 100)); + cert = (char *) malloc(2*(sbuf.st_size + 1024)); file = fopen(path, "r"); if (file == NULL) { rfbLog("sslEncKey: %s\n", path); @@ -645,15 +666,17 @@ void sslEncKey(char *path, int mode) { incert = 0; cert[0] = '\0'; while (fgets(line, 1024, file) != NULL) { - if (strstr(line, "-----BEGIN CERTIFICATE-----") == line) { + if (strstr(line, "-----BEGIN CERTIFICATE-----") + == line) { incert = 1; } if (incert) { - if (strlen(cert) + strlen(line) < 2*sbuf.st_size) { + if (strlen(cert)+strlen(line) < 2*sbuf.st_size) { strcat(cert, line); } } - if (strstr(line, "-----END CERTIFICATE-----") == line) { + if (strstr(line, "-----END CERTIFICATE-----") + == line) { incert = 0; } } @@ -668,7 +691,7 @@ void sslEncKey(char *path, int mode) { write(tmp_fd, genCert, strlen(genCert)); close(tmp_fd); - scr = (char *) malloc(strlen(tmp) + 100); + scr = (char *) malloc(strlen("/bin/sh ") + strlen(tmp) + 1); sprintf(scr, "/bin/sh %s", tmp); set_env("BASE_DIR", "/no/such/dir"); @@ -691,7 +714,7 @@ void sslEncKey(char *path, int mode) { rfbLogPerror("fopen"); exit(1); } - fprintf(file, cert); + fprintf(file, "%s", cert); fclose(file); free(cert); } diff --git a/x11vnc/sslhelper.c b/x11vnc/sslhelper.c index b98ff28..32df174 100644 --- a/x11vnc/sslhelper.c +++ b/x11vnc/sslhelper.c @@ -92,9 +92,9 @@ int openssl_present(void) {return 1;} static void sslerrexit(void) { unsigned long err = ERR_get_error(); - char str[256]; if (err) { + char str[256]; ERR_error_string(err, str); fprintf(stderr, "ssl error: %s\n", str); } @@ -106,6 +106,11 @@ char *get_saved_pem(char *save, int create) { int prompt = 0, len; struct stat sbuf; + if (! save) { + rfbLog("get_saved_pem: save string is null.\n"); + clean_up_exit(1); + } + if (strstr(save, "SAVE_PROMPT") == save) { prompt = 1; s = save + strlen("SAVE_PROMPT"); @@ -121,11 +126,13 @@ char *get_saved_pem(char *save, int create) { } cdir = get_Cert_dir(NULL, &tmp); - if (! cdir) { + if (! cdir || ! tmp) { rfbLog("get_saved_pem: could not find Cert dir.\n"); clean_up_exit(1); } + len = strlen(cdir) + strlen("/server.pem") + strlen(s) + 1; + path = (char *) malloc(len); sprintf(path, "%s/server%s.pem", cdir, s); @@ -145,6 +152,11 @@ char *get_saved_pem(char *save, int create) { static char *get_input(char *tag, char **in) { char line[1024], *str; + + if (! tag || ! in || ! *in) { + return NULL; + } + fprintf(stderr, "%s:\n [%s] ", tag, *in); if (fgets(line, 1024, stdin) == NULL) { rfbLog("could not read stdin!\n"); @@ -155,26 +167,28 @@ static char *get_input(char *tag, char **in) { *str = '\0'; } str = lblanks(line); - if (! strcmp(str, "")) { + if (!strcmp(str, "")) { return *in; } else { - free(*in); return strdup(line); } } char *find_openssl_bin(void) { - char *path, *exe, *p; + char *path, *exe, *p, *gp; struct stat sbuf; int found_openssl = 0; - char extra[] = ":/usr/bin:/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/sfw/bin"; + char extra[] = ":/usr/bin:/bin:/usr/sbin:/usr/local/bin" + ":/usr/local/sbin:/usr/sfw/bin"; - if (! getenv("PATH")) { + gp = getenv("PATH"); + if (! gp) { fprintf(stderr, "could not find openssl(1) program in PATH.\n"); return NULL; } - path = (char *) malloc(strlen(getenv("PATH")) + strlen(extra) + 1); - strcpy(path, getenv("PATH")); + + path = (char *) malloc(strlen(gp) + strlen(extra) + 1); + strcpy(path, gp); strcat(path, extra); /* find openssl binary: */ @@ -233,31 +247,36 @@ static char *create_tmp_pem(char *pathin, int prompt) { ; C = strdup("AU"); - L = strdup(UT.sysname); - snprintf(line, 1024, "%s-%f", UT.nodename, dnow()); + L = strdup(UT.sysname ? UT.sysname : "unknown-os"); + snprintf(line, 1024, "%s-%f", UT.nodename ? UT.nodename : + "unknown-node", dnow()); line[1024-1] = '\0'; + OU = strdup(line); O = strdup("x11vnc"); if (pathin) { snprintf(line, 1024, "x11vnc-SELF-SIGNED-CERT-%d", getpid()); } else { - snprintf(line, 1024, "x11vnc-SELF-SIGNED-TEMPORARY-CERT-%d", getpid()); + snprintf(line, 1024, "x11vnc-SELF-SIGNED-TEMPORARY-CERT-%d", + getpid()); } line[1024-1] = '\0'; CN = strdup(line); EM = strdup("x11vnc@server.nowhere"); /* ssl */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("ssl")) { rfbLog("create_tmp_pem: cannot run external commands.\n"); return NULL; } + rfbLog("\n"); if (pathin) { rfbLog("Creating a self-signed PEM certificate...\n"); } else { rfbLog("Creating a temporary, self-signed PEM certificate...\n"); } + rfbLog("\n"); rfbLog("This will NOT prevent man-in-the-middle attacks UNLESS you\n"); rfbLog("get the certificate information to the VNC viewers SSL\n"); @@ -274,9 +293,8 @@ static char *create_tmp_pem(char *pathin, int prompt) { rfbLog("server certificate.\n"); rfbLog("\n"); - exe = find_openssl_bin(); - if (exe == NULL) { + if (! exe) { return NULL; } @@ -401,14 +419,15 @@ static char *create_tmp_pem(char *pathin, int prompt) { rfbLogPerror("fopen"); return NULL; } + out = fopen(pathin, "w"); + chmod(pathin, 0600); if (out == NULL) { rfbLog("could not open: %s\n", pathin); rfbLogPerror("fopen"); fclose(crt); return NULL; } - chmod(pathin, 0600); in = fopen(pem, "r"); if (in == NULL) { @@ -461,6 +480,10 @@ static int pem_passwd_callback(char *buf, int size, int rwflag, void *userdata) { char *q, line[1024]; + if (! buf) { + exit(1); + } + fprintf(stderr, "\nA passphrase is needed to unlock an OpenSSL " "private key (PEM file).\n"); fprintf(stderr, "Enter passphrase> "); @@ -488,7 +511,18 @@ static int pem_passwd_callback(char *buf, int size, int rwflag, static int appendfile(FILE *out, char *infile) { char line[1024]; - FILE *in = fopen(infile, "r"); + FILE *in; + + if (! infile) { + rfbLog("appendfile: null infile.\n"); + return 0; + } + if (! out) { + rfbLog("appendfile: null out handle.\n"); + return 0; + } + + in = fopen(infile, "r"); if (in == NULL) { rfbLog("appendfile: %s\n", infile); @@ -520,11 +554,8 @@ static char *get_ssl_verify_file(char *str_in) { return str_in; } - str = strdup(str_in); - p = strtok(str, ","); - cdir = get_Cert_dir(NULL, &tmp); - if (! cdir) { + if (! cdir || ! tmp) { rfbLog("get_ssl_verify_file: invalid cert-dir.\n"); exit(1); } @@ -535,12 +566,15 @@ static char *get_ssl_verify_file(char *str_in) { sprintf(tfile, "%s/sslverify-load-%d.crts", tmp, getpid()); file = fopen(tfile, "w"); + chmod(tfile, 0600); if (file == NULL) { rfbLog("get_ssl_verify_file: %s\n", tfile); rfbLogPerror("fopen"); exit(1); } - chmod(tfile, 0600); + + str = strdup(str_in); + p = strtok(str, ","); while (p) { if (!strcmp(p, "CA")) { @@ -551,9 +585,11 @@ static char *get_ssl_verify_file(char *str_in) { } fprintf(stderr, "sslverify: loaded %s\n", tfile2); count++; + } else if (!strcmp(p, "clients")) { DIR *dir; struct dirent *dp; + sprintf(tfile2, "%s/clients", cdir); dir = opendir(tfile2); if (! dir) { @@ -565,15 +601,21 @@ static char *get_ssl_verify_file(char *str_in) { while ( (dp = readdir(dir)) != NULL) { char *n = dp->d_name; char *q = strstr(n, ".crt"); + if (! q || strlen(q) != strlen(".crt")) { continue; } + if (strlen(n) > 512) { + continue; + } + sprintf(tfile2, "%s/clients/%s", cdir, n); if (! appendfile(file, tfile2)) { unlink(tfile); exit(1); } - fprintf(stderr, "sslverify: loaded %s\n", tfile2); + fprintf(stderr, "sslverify: loaded %s\n", + tfile2); count++; } closedir(dir); @@ -599,7 +641,10 @@ static char *get_ssl_verify_file(char *str_in) { fclose(file); free(tfile2); free(str); - fprintf(stderr, "sslverify: using %d client certs in %s\n", count, tfile); + + fprintf(stderr, "sslverify: using %d client certs in %s\n", count, + tfile); + return tfile; } @@ -676,6 +721,7 @@ void openssl_init(void) { clean_up_exit(1); } tmp_pem = 1; + } else if (strstr(openssl_pem, "SAVE") == openssl_pem) { openssl_pem = get_saved_pem(openssl_pem, 1); if (! openssl_pem) { @@ -747,16 +793,19 @@ void openssl_init(void) { } unlink(openssl_pem); free(openssl_pem); + openssl_pem = NULL; } if (ssl_verify) { struct stat sbuf; char *file; int lvl; + file = get_ssl_verify_file(ssl_verify); - if (stat(file, &sbuf) != 0) { + + if (!file || stat(file, &sbuf) != 0) { rfbLog("openssl_init: -sslverify does not exists %s.\n", - file); + file ? file : "null"); rfbLogPerror("stat"); clean_up_exit(1); } @@ -773,6 +822,7 @@ void openssl_init(void) { sslerrexit(); } } + lvl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_PEER; SSL_CTX_set_verify(ctx, lvl, NULL); if (strstr(file, "tmp/sslverify-load-")) { @@ -860,7 +910,9 @@ void https_port(void) { rfbLog("https_port: could not open port %d\n", port); clean_up_exit(1); } - if (db) fprintf(stderr, "https_port: listen on port/sock %d/%d\n", port, sock); + if (db) fprintf(stderr, "https_port: listen on port/sock %d/%d\n", + port, sock); + https_sock = sock; } @@ -978,6 +1030,7 @@ if (db) fprintf(stderr, "waitpid(%d) 2\n", helpers[i]); } } +/* AUDIT */ static int is_ssl_readable(int s_in, time_t last_https, char *last_get, int mode) { int nfd, db = 0; @@ -1008,7 +1061,7 @@ static int is_ssl_readable(int s_in, time_t last_https, char *last_get, * increase the timeout if we know HTTP traffic has occurred * recently: */ - if (time(0) < last_https + 30) { + if (time(NULL) < last_https + 30) { tv.tv_sec = 8; if (strstr(last_get, "VncViewer")) { tv.tv_sec = 4; @@ -1047,7 +1100,7 @@ static int watch_for_http_traffic(char *buf_a, int *n_a) { db = atoi(getenv("ACCEPT_OPENSSL_DEBUG")); } - buf = (char *) calloc(sizeof(ABSIZE+1), 1); + buf = (char *) calloc((ABSIZE+1), 1); *n_a = 0; n = SSL_read(ssl, buf, 2); @@ -1614,7 +1667,7 @@ if (db) fprintf(stderr, "iface: %s\n", iface); int i; rfbLog("SSL: but https for helper process succeeded.\n"); if (mode != OPENSSL_HTTPS) { - last_https = time(0); + last_https = time(NULL); for (i=0; i<128; i++) { last_get[i] = '\0'; } @@ -1856,7 +1909,7 @@ static void ssl_xfer(int csock, int s_in, int s_out, int is_https) { if (db) fprintf(stderr, "ssl_xfer begin\n"); - start = time(0); + start = time(NULL); if (is_https) { tv_use = tv_https_early; } else { @@ -1967,7 +2020,7 @@ static void ssl_xfer(int csock, int s_in, int s_out, int is_https) { } } - if (tv_cutover && time(0) > start + tv_cutover) { + if (tv_cutover && time(NULL) > start + tv_cutover) { tv_cutover = 0; if (is_https) { tv_use = tv_https_later; @@ -2176,8 +2229,8 @@ void check_openssl(void) { } last_check = now; - if (time(0) > last_waitall + 150) { - last_waitall = time(0); + if (time(NULL) > last_waitall + 150) { + last_waitall = time(NULL); ssl_helper_pid(0, -2); /* waitall */ } diff --git a/x11vnc/sslhelper.h b/x11vnc/sslhelper.h index 46ed070..cdba866 100644 --- a/x11vnc/sslhelper.h +++ b/x11vnc/sslhelper.h @@ -13,6 +13,8 @@ extern int openssl_port_num; extern int https_sock; extern pid_t openssl_last_helper_pid; +extern void raw_xfer(int csock, int s_in, int s_out); + extern int openssl_present(void); extern void openssl_init(void); extern void openssl_port(void); diff --git a/x11vnc/ssltools.h b/x11vnc/ssltools.h index 98ee802..73b2686 100644 --- a/x11vnc/ssltools.h +++ b/x11vnc/ssltools.h @@ -697,9 +697,14 @@ char find_display[] = "if [ \"X$1\" = \"X-n\" ]; then\n" " showxauth=\"\"\n" " shift\n" -"elif [ \"X$1\" = \"X-f\" ]; then\n" +"fi\n" +"if [ \"X$1\" = \"X-f\" ]; then\n" " shift\n" -" showxauth=\"$1\"\n" +" if [ ! -r $1 ]; then\n" +" echo \"\"\n" +" exit 1\n" +" fi\n" +" export XAUTHORITY=\"$1\"\n" " shift\n" "fi\n" "\n" @@ -724,24 +729,46 @@ char find_display[] = "# Now try to match X DISPLAY to user:\n" "\n" "# who(1) output column 2:\n" -"display=`who | grep \"^${user}[ ][ ]*:[0-9]\" | head -1 | awk '{print $2}'`\n" +"display=`who | grep \"^${user}[ ][ ]*:[0-9]\" | head -1 \\\n" +" | awk '{print $2}'`\n" "\n" "if [ \"X$display\" = \"X\" ]; then\n" -" # who(1) output, last column:\n" -" display=`who | grep \"^${user}[ ]\" | awk '{print $NF}' | grep '(:[0-9]' | sed -e 's/[()]//g' | head -1`\n" -" if [ \"X$display\" = \"X\" ]; then\n" -" echo \"\" # failure\n" -" exit 1\n" -" fi\n" +" # who(1) output, last column:\n" +" display=`who | grep \"^${user}[ ]\" | awk '{print $NF}' \\\n" +" | grep '(:[0-9]' | sed -e 's/[()]//g' | head -1`\n" +" if [ \"X$display\" = \"X\" ]; then\n" +" if [ \"X$X11VNC_FINDDISPLAY_SKIP_XAUTH\" != \"X\" ]; then\n" +" echo \"\" # failure\n" +" exit 1\n" +" fi\n" +" # loop over xauth list items machine ^hostname/unix:N\n" +" host=`hostname | sed -e 's/\\..*$//'`\n" +" for d in `xauth list | awk '{print $1}' | grep /unix \\\n" +" | grep \"^${host}\" | sed -e 's/^.*://' | sort -n | uniq`\n" +" do\n" +" xdpyinfo -display \":$d\" >/dev/null 2>&1\n" +" if [ $? = 0 ]; then\n" +" # try again with no authority:\n" +" env XAUTHORITY=/dev/null xdpyinfo \\\n" +" -display \":$d\" >/dev/null 2>&1\n" +" # 0 means got in for free... skip it.\n" +" if [ $? != 0 ]; then\n" +" # keep it\n" +" display=\":$d\"\n" +" break\n" +" fi\n" +" fi\n" +" done\n" +" if [ \"X$display\" = \"X\" ]; then\n" +" echo \"\" # failure\n" +" exit 1\n" +" fi\n" +" fi\n" "fi\n" "\n" "echo \"DISPLAY=$display\"\n" "if [ \"X$showxauth\" != \"X\" ]; then\n" -" if [ \"X$showxauth\" = \"X1\" ]; then\n" -" xauth extract - \"$display\" 2>/dev/null\n" -" else\n" -" xauth -f \"$showxauth\" extract - \"$display\" 2>/dev/null\n" -" fi\n" +" xauth extract - \"$display\" 2>/dev/null\n" "fi\n" "\n" "exit 0\n" diff --git a/x11vnc/tkx11vnc b/x11vnc/tkx11vnc index 4eaa665..10dbb50 100755 --- a/x11vnc/tkx11vnc +++ b/x11vnc/tkx11vnc @@ -310,6 +310,8 @@ Permissions =0S dontdisconnect =SQA deny_all timeout: + grabkbd + grabptr =GAL LOFF Tuning diff --git a/x11vnc/tkx11vnc.h b/x11vnc/tkx11vnc.h index 98749ac..b4f9232 100644 --- a/x11vnc/tkx11vnc.h +++ b/x11vnc/tkx11vnc.h @@ -321,6 +321,8 @@ char gui_code[] = ""; " =0S dontdisconnect\n" " =SQA deny_all\n" " timeout:\n" +" grabkbd\n" +" grabptr\n" " =GAL LOFF\n" "\n" "Tuning\n" diff --git a/x11vnc/unixpw.c b/x11vnc/unixpw.c index c09f00e..297a8e2 100644 --- a/x11vnc/unixpw.c +++ b/x11vnc/unixpw.c @@ -70,6 +70,7 @@ rfbClientPtr unixpw_client = NULL; int keep_unixpw = 0; char *keep_unixpw_user = NULL; char *keep_unixpw_pass = NULL; +char *keep_unixpw_opts = NULL; static int in_login = 0, in_passwd = 0, tries = 0; static int char_row = 0, char_col = 0; @@ -398,7 +399,7 @@ int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size) { } } /* unixpw */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("unixpw")) { rfbLog("su_verify: cannot run external commands.\n"); clean_up_exit(1); } @@ -789,50 +790,54 @@ static void unixpw_verify(char *user, char *pass) { int x, y; char li[] = "Login incorrect"; char log[] = "login: "; + char *colon = NULL; if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "********"); rfbLog("unixpw_verify: %s\n", user); + colon = strchr(user, ':'); + if (colon) { + *colon = '\0'; + rfbLog("unixpw_verify: colon: %s\n", user); + } + + if (unixpw_nis) { if (crypt_verify(user, pass)) { unixpw_accept(user); if (keep_unixpw) { keep_unixpw_user = strdup(user); keep_unixpw_pass = strdup(pass); + if (colon) { + keep_unixpw_opts = strdup(colon+1); + } else { + keep_unixpw_opts = strdup(""); + } } + if (colon) *colon = ':'; return; } else { rfbLog("unixpw_verify: crypt_verify login for %s failed.\n", user); usleep(3000*1000); } - } else if (0) { - char buf[8192]; - int n = 8000; - int res = su_verify(user, pass, "/home/runge/wallycom yegg 33", buf, &n); - - fprintf(stderr, "su_verify ret: n=%d ", n); - write(2, buf, n); - - if (res) { - unixpw_accept(user); - if (keep_unixpw) { - keep_unixpw_user = strdup(user); - keep_unixpw_pass = strdup(pass); - } - return; - } - rfbLog("unixpw_verify: su_verify login for %s failed.\n", user); } else { if (su_verify(user, pass, NULL, NULL, NULL)) { unixpw_accept(user); if (keep_unixpw) { keep_unixpw_user = strdup(user); keep_unixpw_pass = strdup(pass); + if (colon) { + keep_unixpw_opts = strdup(colon+1); + } else { + keep_unixpw_opts = strdup(""); + } } + if (colon) *colon = ':'; return; } rfbLog("unixpw_verify: su_verify login for %s failed.\n", user); } + if (colon) *colon = ':'; if (tries < 2) { char_row++; @@ -856,7 +861,7 @@ if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "*** mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); } - unixpw_last_try_time = time(0); + unixpw_last_try_time = time(NULL); unixpw_keystroke(0, 0, 2); tries++; } else { @@ -902,6 +907,10 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) { free(keep_unixpw_pass); keep_unixpw_pass = NULL; } + if (keep_unixpw_opts) { + free(keep_unixpw_opts); + keep_unixpw_opts = NULL; + } return; } @@ -988,7 +997,12 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) { return; } +#if 0 user[u_cnt++] = keystr[0]; +#else + user[u_cnt++] = (char) keysym; + keystr[0] = (char) keysym; +#endif x = text_x(); y = text_y(); diff --git a/x11vnc/unixpw.h b/x11vnc/unixpw.h index aa443d4..a0d8245 100644 --- a/x11vnc/unixpw.h +++ b/x11vnc/unixpw.h @@ -18,5 +18,6 @@ extern rfbClientPtr unixpw_client; extern int keep_unixpw; extern char *keep_unixpw_user; extern char *keep_unixpw_pass; +extern char *keep_unixpw_opts; #endif /* _X11VNC_UNIXPW_H */ diff --git a/x11vnc/user.c b/x11vnc/user.c index 7dfb5d1..0b78f99 100644 --- a/x11vnc/user.c +++ b/x11vnc/user.c @@ -46,7 +46,7 @@ void check_switched_user(void) { static int did_solid = 0; static int did_dummy = 0; int delay = 15; - time_t now = time(0); + time_t now = time(NULL); if (unixpw_in_progress) return; @@ -675,7 +675,7 @@ static int switch_user_env(uid_t uid, char *name, char *home, int fb_mode) { static void try_to_switch_users(void) { static time_t last_try = 0; - time_t now = time(0); + time_t now = time(NULL); char *users, *p; if (getuid() && geteuid()) { @@ -934,7 +934,7 @@ void check_new_passwds(void) { } if (unixpw_in_progress) return; - now = time(0); + now = time(NULL); if (now > last_check + 1) { if (read_passwds(passwdfile)) { install_passwds(); @@ -1029,16 +1029,106 @@ static void handle_one_http_request(void) { } } +void user_supplied_opts(char *opts) { + char *p, *str; + char *allow[] = { + "skip-display", "skip-auth", "skip-shared", + "scale", "scale_cursor", "solid", "id", "clear_mods", + "clear_keys", "repeat", "speeds", + NULL + }; + + if (getenv("X11VNC_NO_UNIXPW_OPTS")) { + return; + } + + str = strdup(opts); + + p = strtok(str, ","); + while (p) { + char *q; + int i, n, m, ok = 0; + + i = 0; + while (allow[i] != NULL) { + if (strstr(allow[i], "skip-")) { + i++; + continue; + } + if (strstr(p, allow[i]) == p) { + ok = 1; + break; + } + i++; + } + + if (! ok && sscanf(p, "%d/%d", &n, &m) == 2) { + if (scale_str) free(scale_str); + scale_str = strdup(p); + } else if (ok) { + if (strstr(p, "display=") == p) { + if (use_dpy) free(use_dpy); + use_dpy = strdup(p + strlen("display=")); + } else if (strstr(p, "auth=") == p) { + if (auth_file) free(auth_file); + auth_file = strdup(p + strlen("auth=")); + } else if (strstr(p, "scale=") == p) { + if (scale_str) free(scale_str); + scale_str = strdup(p + strlen("scale=")); + } else if (strstr(p, "scale_cursor=") == p) { + if (scale_cursor_str) free(scale_cursor_str); + scale_cursor_str = strdup(p + + strlen("scale_cursor=")); + } else if (!strcmp(p, "shared")) { + shared = 1; + } else if (!strcmp(p, "solid")) { + use_solid_bg = 1; + if (!solid_str) { + solid_str = strdup(solid_default); + } + } else if (strstr(p, "solid=") == p) { + use_solid_bg = 1; + if (solid_str) free(solid_str); + solid_str = strdup(p + strlen("solid=")); + } else if (strstr(p, "id=") == p) { + unsigned long win; + q = p + strlen("id="); + if (strcmp(q, "pick")) { + if (scan_hexdec(q, &win)) { + subwin = win; + } + } + } else if (!strcmp(p, "clear_mods")) { + clear_mods = 1; + } else if (!strcmp(p, "clear_keys")) { + clear_mods = 2; + } else if (!strcmp(p, "repeat")) { + no_autorepeat = 0; + } else if (strstr(p, "speeds=") == p) { + if (speeds_str) free(speeds_str); + speeds_str = strdup(p + strlen("speeds=")); + q = speeds_str; + while (*q != '\0') { + if (*q == '-') { + *q = ','; + } + q++; + } + } + } + p = strtok(NULL, ","); + } + free(str); +} + extern char find_display[]; +static XImage ximage_struct; int wait_for_client(int *argc, char** argv, int http) { - static XImage ximage_struct; XImage* fb_image; int w = 640, h = 480, b = 32; - int w0, h0, i; - int chg_raw_fb = 0; - char *str, *q, *p; - char *cmd = NULL; + int w0, h0, i, chg_raw_fb = 0; + char *str, *q, *p, *cmd = NULL; int db = 0; char tmp[] = "/tmp/x11vnc-find_display.XXXXXX"; int tmp_fd = -1, dt = 0; @@ -1047,11 +1137,11 @@ int wait_for_client(int *argc, char** argv, int http) { return 0; } - for (i=0; i< *argc; i++) { + for (i=0; i < *argc; i++) { if (!strcmp(argv[i], "-desktop")) { dt = 1; } - if (0) fprintf(stderr, "args %d %s\n", i, argv[i]); + if (1) fprintf(stderr, "args %d %s\n", i, argv[i]); } str = strdup(use_dpy); @@ -1085,7 +1175,7 @@ int wait_for_client(int *argc, char** argv, int http) { if (db) fprintf(stderr, "str: %s\n", str); if (strstr(str, "cmd=") == str) { - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("WAIT")) { rfbLog("wait_for_client external cmds not allowed:" " %s\n", use_dpy); clean_up_exit(1); @@ -1127,7 +1217,7 @@ int wait_for_client(int *argc, char** argv, int http) { if (! dt) { char *s; argv[*argc] = strdup("-desktop"); - (*argc)++; + *argc = (*argc) + 1; if (cmd) { char *q; @@ -1141,18 +1231,27 @@ int wait_for_client(int *argc, char** argv, int http) { } rfb_desktop_name = strdup(s); argv[*argc] = s; - (*argc)++; + *argc = (*argc) + 1; } initialize_allowed_input(); + if (! multiple_cursors_mode) { + multiple_cursors_mode = strdup("default"); + } initialize_cursors_mode(); initialize_screen(argc, argv, fb_image); initialize_signals(); - if (!strcmp(cmd, "HTTPONCE")) { + 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); } @@ -1161,12 +1260,6 @@ int wait_for_client(int *argc, char** argv, int http) { http_connections(1); } - if (! raw_fb) { - chg_raw_fb = 1; - /* kludge to get RAWFB_RET with dpy == NULL guards */ - raw_fb = "null"; - } - if (cmd && unixpw) { keep_unixpw = 1; } @@ -1176,12 +1269,15 @@ int wait_for_client(int *argc, char** argv, int http) { } while (1) { - if (! use_threads) { - rfbPE(-1); + if (shut_down) { + clean_up_exit(0); } if (use_openssl) { check_openssl(); } + if (! use_threads) { + rfbPE(-1); + } if (! screen || ! screen->clientHead) { usleep(100 * 1000); continue; @@ -1196,6 +1292,9 @@ int wait_for_client(int *argc, char** argv, int http) { clean_up_exit(1); } while (1) { + if (shut_down) { + clean_up_exit(0); + } if (! use_threads) { rfbPE(-1); } @@ -1238,7 +1337,6 @@ int wait_for_client(int *argc, char** argv, int http) { char line[18000]; memset(line, 0, 18000); - if (0) unixpw_msg("Looking up DISPLAY", 0); if (keep_unixpw_user && keep_unixpw_pass) { n = 18000; @@ -1329,7 +1427,6 @@ if (db) write(2, line, n); write(2, "\n", 1); if (*q == '\n' || *q == '\r') *q = '\0'; q++; } -if (db) fprintf(stderr, "use_dpy: %s n: %d\n", use_dpy, n); if (line2[0] != '\0') { if (strstr(line2, "XAUTHORITY=") == line2) { q = line2; @@ -1360,6 +1457,9 @@ if (db) fprintf(stderr, "xauth_raw_len: %d\n", n); if (chg_raw_fb) { raw_fb = NULL; } + if (unixpw && keep_unixpw_opts && keep_unixpw_opts[0] != '\0') { + user_supplied_opts(keep_unixpw_opts); + } return 1; } diff --git a/x11vnc/userinput.c b/x11vnc/userinput.c index 10e56d6..1395c71 100644 --- a/x11vnc/userinput.c +++ b/x11vnc/userinput.c @@ -2807,7 +2807,7 @@ static int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy * it for now by CopyRect-ing the *whole* on-screen * rectangle (whether obscured or not!) */ - if (time(0) > dt_bad_check + 5) { + if (time(NULL) > dt_bad_check + 5) { char *dt = guess_desktop(); if (!strcmp(dt, "kde")) { dt_bad = 1; @@ -2816,7 +2816,7 @@ static int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy } else { dt_bad = 0; } - dt_bad_check = time(0); + dt_bad_check = time(NULL); } if (clipshift) { @@ -3746,7 +3746,7 @@ if (db) fprintf(stderr, "send_copyrect: %d\n", sent_copyrect); * save the stack list, perhaps the user has * paused with button down. */ - last_save_stacklist = time(0); + last_save_stacklist = time(NULL); } else { stack_list_num = 0; } @@ -4126,7 +4126,7 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) { sscanf(p, "%lf,%lf,%lf,%lf", &dt_cut, &Tfac_r, &Tfac_v, &Tfac_n); } first = 0; - ssec = time(0); + ssec = time(NULL); if (dtr) {} /* unused vars warning: */ } diff --git a/x11vnc/util.c b/x11vnc/util.c index 1995164..fa28853 100644 --- a/x11vnc/util.c +++ b/x11vnc/util.c @@ -51,7 +51,7 @@ char *choose_title(char *display); /* - * routine to keep 0 <= i < n, should use in more places... + * routine to keep 0 <= i < n */ int nfix(int i, int n) { if (i < 0) { @@ -120,7 +120,7 @@ void uppercase(char *str) { char *lblanks(char *str) { char *p = str; - while (*p) { + while (*p != '\0') { if (! isspace(*p)) { break; } @@ -150,6 +150,9 @@ int scan_hexdec(char *str, unsigned long *num) { int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H) { int w, h, x, y; + if (! str) { + return 0; + } /* handle +/-x and +/-y */ if (sscanf(str, "%dx%d+%d+%d", &w, &h, &x, &y) == 4) { ; @@ -176,10 +179,13 @@ int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H) { void set_env(char *name, char *value) { char *str; - if (!value) { + if (! name) { + return; + } + if (! value) { value = ""; } - str = (char *) malloc(strlen(name)+strlen(value)+2); + str = (char *) malloc(strlen(name) + 1 + strlen(value) + 1); sprintf(str, "%s=%s", name, value); putenv(str); } @@ -277,6 +283,7 @@ char *this_host(void) { char host[MAXN]; #if LIBVNCSERVER_HAVE_GETHOSTNAME if (gethostname(host, MAXN) == 0) { + host[MAXN-1] = '\0'; return strdup(host); } #endif @@ -286,8 +293,8 @@ char *this_host(void) { int match_str_list(char *str, char **list) { int i = 0, matched = 0; - if (! list) { - return matched; + if (! str || ! list) { + return 0; } while (list[i] != NULL) { if (!strcmp(list[i], "*")) { @@ -304,9 +311,14 @@ int match_str_list(char *str, char **list) { char **create_str_list(char *cslist) { int i, n; - char *p, *str = strdup(cslist); + char *p, *str; char **list = NULL; + + if (! cslist) { + return NULL; + } + str = strdup(cslist); n = 1; p = str; while (*p != '\0') { @@ -316,7 +328,8 @@ char **create_str_list(char *cslist) { p++; } - list = (char **) malloc((n+1)*sizeof(char *)); + /* the extra last one holds NULL */ + list = (char **) malloc( (n+1)*sizeof(char *) ); for(i=0; i < n+1; i++) { list[i] = NULL; } @@ -427,6 +440,10 @@ double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1, a = nabs((x2 - x1) * (y2 - y1)); A = nabs((X2 - X1) * (Y2 - Y1)); + if (a == 0 || A == 0) { + return 0.0; + } + r = sraRgnCreateRect(x1, y1, x2, y2); R = sraRgnCreateRect(X1, Y1, X2, Y2); @@ -455,6 +472,8 @@ double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1, */ char *choose_title(char *display) { static char title[(MAXN+10)]; + + memset(title, 0, MAXN+10); strcpy(title, "x11vnc"); if (display == NULL) { @@ -465,16 +484,20 @@ char *choose_title(char *display) { } title[0] = '\0'; if (display[0] == ':') { - if (this_host() != NULL) { - strncpy(title, this_host(), MAXN - strlen(title)); + char *th = this_host(); + if (th != NULL) { + strncpy(title, th, MAXN - strlen(title)); } } strncat(title, display, MAXN - strlen(title)); - if (subwin && valid_window(subwin, NULL, 0)) { - char *name; - if (dpy && XFetchName(dpy, subwin, &name)) { - strncat(title, " ", MAXN - strlen(title)); - strncat(title, name, MAXN - strlen(title)); + if (subwin && dpy && valid_window(subwin, NULL, 0)) { + char *name = NULL; + if (XFetchName(dpy, subwin, &name)) { + if (name) { + strncat(title, " ", MAXN - strlen(title)); + strncat(title, name, MAXN - strlen(title)); + free(name); + } } } return title; diff --git a/x11vnc/v4l.c b/x11vnc/v4l.c index 7799354..22b4d00 100644 --- a/x11vnc/v4l.c +++ b/x11vnc/v4l.c @@ -1090,7 +1090,7 @@ static char *guess_via_v4l_info(char *dev, int *fd) { if (*fd) {} /* v4l-info */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("v4l-info")) { rfbLog("guess_via_v4l_info: cannot run external " "command: v4l-info\n"); return NULL; diff --git a/x11vnc/win_utils.c b/x11vnc/win_utils.c index 88c3987..f923262 100644 --- a/x11vnc/win_utils.c +++ b/x11vnc/win_utils.c @@ -305,7 +305,7 @@ int pick_windowid(unsigned long *num) { set_env("DISPLAY", use_dpy); } /* id */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("id")) { rfbLogEnable(1); rfbLog("cannot run external commands in -nocmds mode:\n"); rfbLog(" \"%s\"\n", "xwininfo"); diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1 index 0f0285d..3bb336e 100644 --- a/x11vnc/x11vnc.1 +++ b/x11vnc/x11vnc.1 @@ -2,7 +2,7 @@ .TH X11VNC "1" "June 2006" "x11vnc " "User Commands" .SH NAME x11vnc - allow VNC connections to real X11 displays - version: 0.8.2, lastmod: 2006-06-12 + version: 0.8.2, lastmod: 2006-06-18 .SH SYNOPSIS .B x11vnc [OPTION]... @@ -474,6 +474,32 @@ users to move the mouse. This option is ignored when a global \fB-viewonly\fR is in effect (all input is discarded in that case). .PP +\fB-grabkbd\fR +.IP +When VNC viewers are connected, attempt to the grab the +keyboard so someone sitting at the physical display +is not able to enter keystrokes. This method uses +.IR XGrabKeyboard (3X11) +and so it is not secure and does not +rule out the person at the physical display injecting +keystrokes by flooding the server with them, grabbing +the keyboard himself, etc. Some degree of cooperation +from the person at the display is assumed. +.PP +\fB-grabptr\fR +.IP +As \fB-grabkbd,\fR but for the mouse pointer using +.IR XGrabPointer (3X11). +Unfortunately due to the way the X +server works, the mouse can still be moved around by the +user at the physical display, but he will not be able to +change window focus with it. Also some window managers +that call +.IR XGrabServer (3X11) +for resizes, etc, will +act on the local user's input. Again, some degree of +cooperation from the person at the display is assumed. +.PP \fB-viewpasswd\fR \fIstring\fR .IP Supply a 2nd password for view-only logins. The \fB-passwd\fR @@ -704,7 +730,25 @@ In the case of \fB-unixpw,\fR then the above command is run as the user who just authenticated via the login and password prompt. .IP -Thus the combination of \fB-display\fR WAIT:cmd=... and +Also in the case of \fB-unixpw,\fR the user logging in can +place a colon at the end of his username and supply +a few options: scale=, scale_cursor=, solid, id=, +clear_mods, clear_keys, repeat, or speeds= separated +by commas if there is more than one. After the user +logs in successfully, these options will be applied to +the VNC screen. For example, +.IP +login: fred:scale=3/4,repeat +Password: ... +.IP +for convenience m/n implies scale= e.g. fred:3/4 +To disable this set the environment variable +X11VNC_NO_UNIXPW_OPTS=1. To set any other options, +the user can use the gui (x11vnc \fB-gui\fR connect) or the +remote control method (x11vnc \fB-R\fR opt:val) during his +VNC session. +.IP +So the combination of \fB-display\fR WAIT:cmd=... and \fB-unixpw\fR allows automatic pairing of an unix authenticated VNC user with his desktop. This could be very useful on SunRays and also any system where @@ -738,7 +782,7 @@ by client web browsers. For example: 5815 stream tcp nowait root /usr/sbin/tcpd .../x11vnc \\ \fB-inetd\fR \fB-q\fR \fB-http_ssl\fR \fB-display\fR WAIT:cmd=HTTPONCE .IP -Is used in the Apache SSL-portal example (see FAQ). +It is used in the Apache SSL-portal example (see FAQ). .IP Finally, one can insert a geometry between colons, e.g. WAIT:1280x1024:... to set the size of the display @@ -1629,6 +1673,14 @@ Use \fIfilename\fR instead of $HOME/.x11vncrc for rc file. .IP Do not process any .x11vncrc file for options. .PP +\fB-env\fR \fIVAR=VALUE\fR +.IP +Set the environment variable 'VAR' to value 'VALUE' +at x11vnc startup. This is a convenience utility to +avoid shell script wrappers, etc. to set the env. var. +You may specify as many of these as needed on the +command line. +.PP \fB-h,\fR \fB-help\fR .IP Print this help text. @@ -3222,6 +3274,14 @@ lookup disable \fB-nolookup\fR mode. .IP input:str set \fB-input\fR to "str", empty to disable. .IP +grabkbd enable \fB-grabkbd\fR mode. +.IP +nograbkbd disable \fB-grabkbd\fR mode. +.IP +grabptr enable \fB-grabptr\fR mode. +.IP +nograbptr disable \fB-grabptr\fR mode. +.IP client_input:str set the K, M, B \fB-input\fR on a per-client basis. select which client as for disconnect, e.g. client_input:host:MB @@ -3653,13 +3713,14 @@ nowf wirecopyrect wcr nowirecopyrect nowcr scr_area scr_skip scr_inc scr_keys scr_term scr_keyrepeat scr_parms scrollcopyrect scr noscrollcopyrect noscr fixscreen noxrecord xrecord reset_record pointer_mode -pm input_skip input client_input speeds wmdt -debug_pointer dp nodebug_pointer nodp debug_keyboard -dk nodebug_keyboard nodk deferupdate defer wait_ui -wait_bog nowait_bog slow_fb wait readtimeout nap nonap -sb screen_blank fbpm nofbpm fs gaps grow fuzz snapfb -nosnapfb rawfb progressive rfbport http nohttp httpport -httpdir enablehttpproxy noenablehttpproxy alwaysshared +pm input_skip input grabkbd nograbkbd grabptr +nograbptr client_input speeds wmdt debug_pointer dp +nodebug_pointer nodp debug_keyboard dk nodebug_keyboard +nodk deferupdate defer wait_ui wait_bog nowait_bog +slow_fb wait readtimeout nap nonap sb screen_blank +fbpm nofbpm fs gaps grow fuzz snapfb nosnapfb rawfb +progressive rfbport http nohttp httpport httpdir +enablehttpproxy noenablehttpproxy alwaysshared noalwaysshared nevershared noalwaysshared dontdisconnect nodontdisconnect desktop debug_xevents nodebug_xevents debug_xevents debug_xdamage nodebug_xdamage @@ -3770,6 +3831,20 @@ No external commands (e.g. ) will be run. .PP +\fB-allowedcmds\fR \fIlist\fR +.IP +\fIlist\fR contains a comma separated list of the only +external commands that can be run. The full list of +associated options is: +.IP +stunnel, ssl, unixpw, WAIT, id, accept, afteraccept, +gone, pipeinput, v4l-info, rawfb-setup, dt, gui, +storepasswd, crash. +.IP +See each option's help to learn the associated external +command. Note that the \fB-nocmds\fR option takes precedence +and disables all external commands. +.PP \fB-deny_all\fR .IP For use with \fB-remote\fR nodeny: start out denying all diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index ab4451a..6d418a0 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -211,7 +211,7 @@ static void check_cursor_changes(void) { static void record_last_fb_update(void) { static int rbs0 = -1; static time_t last_call = 0; - time_t now = time(0); + time_t now = time(NULL); int rbs = -1; rfbClientIteratorPtr iter; rfbClientPtr cl; @@ -399,7 +399,7 @@ if (0 && dt > 0.0) fprintf(stderr, "dt: %.5f %.4f\n", dt, dnow() - x11vnc_start) static void watch_loop(void) { int cnt = 0, tile_diffs = 0, skip_pe = 0; double tm, dtr, dt = 0.0; - time_t start = time(0); + time_t start = time(NULL); if (use_threads) { rfbRunEventLoop(screen, -1, TRUE); @@ -489,7 +489,7 @@ if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret); } if (first_conn_timeout < 0) { - start = time(0); + start = time(NULL); first_conn_timeout = -first_conn_timeout; } } @@ -497,7 +497,7 @@ if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret); if (! screen || ! screen->clientHead) { /* waiting for a client */ if (first_conn_timeout) { - if (time(0) - start > first_conn_timeout) { + if (time(NULL) - start > first_conn_timeout) { rfbLog("No client after %d secs.\n", first_conn_timeout); shut_down = 1; @@ -1252,7 +1252,7 @@ static void store_homedir_passwd(char *file) { str2[0] = '\0'; /* storepasswd */ - if (no_external_cmds) { + if (no_external_cmds || !cmd_ok("storepasswd")) { fprintf(stderr, "-nocmds cannot be used with -storepasswd\n"); exit(1); } @@ -1376,6 +1376,10 @@ int main(int argc, char* argv[]) { immediate_switch_user(argc, argv); } + for (i=0; i < 2048; i++) { + argv_vnc[i] = NULL; + } + argv_vnc[0] = strdup(argv[0]); program_name = strdup(argv[0]); program_pid = (int) getpid(); @@ -1431,6 +1435,30 @@ int main(int argc, char* argv[]) { } } + /* + * do a quick check for -env parameters + */ + for (i=1; i < argc; i++) { + char *p, *q; + arg = argv[i]; + if (strstr(arg, "--") == arg) { + arg++; + } + if (!strcmp(arg, "-env")) { + CHECK_ARGC + p = strdup(argv[++i]); + q = strchr(p, '='); + if (! q) { + fprintf(stderr, "no -env '=' found: %s\n", p); + exit(1); + } else { + *q = '\0'; + } + set_env(p, q+1); + free(p); + } + } + for (i=1; i < argc; i++) { /* quick-n-dirty --option handling. */ arg = argv[i]; @@ -1569,6 +1597,10 @@ int main(int argc, char* argv[]) { } else if (!strcmp(arg, "-input")) { CHECK_ARGC allowed_input_str = strdup(argv[++i]); + } else if (!strcmp(arg, "-grabkbd")) { + grab_kbd = 1; + } else if (!strcmp(arg, "-grabptr")) { + grab_ptr = 1; } else if (!strcmp(arg, "-viewpasswd")) { vpw_loc = i; CHECK_ARGC @@ -1781,6 +1813,8 @@ int main(int argc, char* argv[]) { i++; /* done above */ } else if (!strcmp(arg, "-norc")) { ; /* done above */ + } else if (!strcmp(arg, "-env")) { + i++; /* done above */ } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) { print_help(0); } else if (!strcmp(arg, "-?") || !strcmp(arg, "-opts")) { @@ -2181,6 +2215,9 @@ int main(int argc, char* argv[]) { more_safe = 1; } else if (!strcmp(arg, "-nocmds")) { no_external_cmds = 1; + } else if (!strcmp(arg, "-allowedcmds")) { + CHECK_ARGC + allowed_external_cmds = strdup(argv[++i]); } else if (!strcmp(arg, "-deny_all")) { deny_all = 1; } else if (!strcmp(arg, "-httpdir")) { @@ -3157,9 +3194,14 @@ int main(int argc, char* argv[]) { initialize_screen(&argc_vnc, argv_vnc, fb0); - if (waited_for_client && fake_fb) { - free(fake_fb); - fake_fb = NULL; + if (waited_for_client) { + if (fake_fb) { + free(fake_fb); + fake_fb = NULL; + } + if (use_solid_bg && client_count) { + solid_bg(0); + } } if (! waited_for_client) { diff --git a/x11vnc/x11vnc.h b/x11vnc/x11vnc.h index 643c103..c8431f7 100644 --- a/x11vnc/x11vnc.h +++ b/x11vnc/x11vnc.h @@ -366,9 +366,9 @@ extern char *http_dir; extern char vnc_desktop_name[]; extern char *main_fb; /* our copy of the X11 fb */ extern char *rfb_fb; /* same as main_fb unless transformation */ -extern char *fake_fb; /* used under -padgeom */ -extern char *snap_fb; /* used under -snapfb */ -extern char *cmap8to24_fb; /* used under -8to24 */ +extern char *fake_fb; /* used under -padgeom */ +extern char *snap_fb; /* used under -snapfb */ +extern char *cmap8to24_fb; /* used under -8to24 */ extern char *raw_fb; extern char *raw_fb_addr; extern int raw_fb_offset; diff --git a/x11vnc/x11vnc_defs.c b/x11vnc/x11vnc_defs.c index b2cce67..c432d32 100644 --- a/x11vnc/x11vnc_defs.c +++ b/x11vnc/x11vnc_defs.c @@ -15,7 +15,7 @@ int xtrap_base_event_type = 0; int xdamage_base_event_type = 0; /* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.8.2 lastmod: 2006-06-12"; +char lastmod[] = "0.8.2 lastmod: 2006-06-18"; /* X display info */ @@ -68,11 +68,11 @@ int raw_fb_seek = 0; int raw_fb_fd = -1; int raw_fb_back_to_X = 0; /* kludge for testing rawfb -> X */ -int rfb_bytes_per_line; -int main_bytes_per_line; -unsigned long main_red_mask, main_green_mask, main_blue_mask; -unsigned short main_red_max, main_green_max, main_blue_max; -unsigned short main_red_shift, main_green_shift, main_blue_shift; +int rfb_bytes_per_line = 0; +int main_bytes_per_line = 0; +unsigned long main_red_mask = 0, main_green_mask = 0, main_blue_mask = 0; +unsigned short main_red_max = 0, main_green_max = 0, main_blue_max = 0; +unsigned short main_red_shift = 0, main_green_shift = 0, main_blue_shift = 0; /* scaling parameters */ char *scale_str = NULL; @@ -123,8 +123,8 @@ int client_count = 0; int clients_served = 0; /* more transient kludge variables: */ -int cursor_x, cursor_y; /* x and y from the viewer(s) */ -int button_change_x, button_change_y; +int cursor_x = 0, cursor_y = 0; /* x and y from the viewer(s) */ +int button_change_x = 0, button_change_y = 0; int got_user_input = 0; int got_pointer_input = 0; int got_pointer_calls = 0; diff --git a/x11vnc/xdamage.c b/x11vnc/xdamage.c index 4c9319a..655b496 100644 --- a/x11vnc/xdamage.c +++ b/x11vnc/xdamage.c @@ -369,7 +369,7 @@ if (0) XEventsQueued(dpy, QueuedAfterFlush); "/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount, dcount, ccount, xdamage_direct_count); } - now = time(0); + now = time(NULL); if (! last_rpt) { last_rpt = now; } diff --git a/x11vnc/xevents.c b/x11vnc/xevents.c index ab49f0b..f027731 100644 --- a/x11vnc/xevents.c +++ b/x11vnc/xevents.c @@ -16,6 +16,8 @@ /* XXX CHECK BEFORE RELEASE */ int grab_buster = 0; +int grab_kbd = 0; +int grab_ptr = 0; int sync_tod_delay = 3; void initialize_vnc_connect_prop(void); @@ -187,7 +189,7 @@ static void get_prop(char *str, int len, Atom prop) { static void bust_grab(int reset) { static int bust_count = 0; static time_t last_bust = 0; - time_t now = time(0); + time_t now = time(NULL); KeyCode key; int button, x, y, nb; @@ -272,7 +274,7 @@ static void bust_grab(int reset) { XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime); } XFlush_wr(dpy); - last_bust = time(0); + last_bust = time(NULL); } typedef struct _grabwatch { @@ -294,7 +296,7 @@ static int process_watch(char *str, int parent, int db) { unsigned long xtime; static grabwatch_t watches[GRABWATCH]; static int first = 1; - time_t now = time(0); + time_t now = time(NULL); static time_t last_bust = 0; int too_long, problems = 0; @@ -604,7 +606,7 @@ void sync_tod_with_servertime(void) { void check_keycode_state(void) { static time_t last_check = 0; int delay = 10, noinput = 3; - time_t now = time(0); + time_t now = time(NULL); if (! client_count) { return; @@ -629,7 +631,7 @@ void check_keycode_state(void) { void check_autorepeat(void) { static time_t last_check = 0; - time_t now = time(0); + time_t now = time(NULL); int autorepeat_is_on, autorepeat_initially_on, idle_timeout = 300; static int idle_reset = 0; @@ -710,7 +712,7 @@ void check_xevents(int reset) { static time_t last_init_check = 0; static time_t last_sync = 0; static time_t last_time_sync = 0; - time_t now = time(0); + time_t now = time(NULL); static double last_request = 0.0; XErrorHandler old_handler; diff --git a/x11vnc/xevents.h b/x11vnc/xevents.h index 0e501b0..3200063 100644 --- a/x11vnc/xevents.h +++ b/x11vnc/xevents.h @@ -4,6 +4,8 @@ /* -- xevents.h -- */ extern int grab_buster; +extern int grab_kbd; +extern int grab_ptr; extern int sync_tod_delay; extern void initialize_vnc_connect_prop(void); diff --git a/x11vnc/xrandr.h b/x11vnc/xrandr.h index baab196..5e3a7d6 100644 --- a/x11vnc/xrandr.h +++ b/x11vnc/xrandr.h @@ -34,11 +34,11 @@ extern int known_xrandr_mode(char *s); if (subwin) { \ static int last = 0; \ subwin_trap_count++; \ - if (time(0) > last_subwin_trap + 60) { \ + if (time(NULL) > last_subwin_trap + 60) { \ rfbLog("trapped GetImage xerror" \ " in SUBWIN mode. [%d]\n", \ subwin_trap_count); \ - last_subwin_trap = time(0); \ + last_subwin_trap = time(NULL); \ last = subwin_trap_count; \ } \ if (subwin_trap_count - last > 30) { \ diff --git a/x11vnc/xwrappers.c b/x11vnc/xwrappers.c index 88413b6..d58e914 100644 --- a/x11vnc/xwrappers.c +++ b/x11vnc/xwrappers.c @@ -3,6 +3,7 @@ #include "x11vnc.h" #include "xrecord.h" #include "keyboard.h" +#include "xevents.h" int xshm_present = 0; int xtest_present = 0; @@ -601,8 +602,15 @@ void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, last_keyboard_keycode = key; } + if (grab_kbd) { + XUngrabKeyboard(dpy, CurrentTime); + } + if (xtrap_input) { XTRAP_FakeKeyEvent_wr(dpy, key, down, delay); + if (grab_kbd) { + adjust_grabs(1, 1); + } return; } @@ -616,6 +624,9 @@ void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, } #if LIBVNCSERVER_HAVE_XTEST XTestFakeKeyEvent(dpy, key, down, delay); + if (grab_kbd) { + adjust_grabs(1, 1); + } if (debug_keyboard) { upup_downdown_warning(key, down); } @@ -648,8 +659,15 @@ void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, RAWFB_RET_VOID + if (grab_ptr) { + XUngrabPointer(dpy, CurrentTime); + } + if (xtrap_input) { XTRAP_FakeButtonEvent_wr(dpy, button, is_press, delay); + if (grab_ptr) { + adjust_grabs(1, 1); + } return; } @@ -664,6 +682,9 @@ void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, #if LIBVNCSERVER_HAVE_XTEST XTestFakeButtonEvent(dpy, button, is_press, delay); #endif + if (grab_ptr) { + adjust_grabs(1, 1); + } } void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y, @@ -690,8 +711,15 @@ void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, RAWFB_RET_VOID + if (grab_ptr) { + XUngrabPointer(dpy, CurrentTime); + } + if (xtrap_input) { XTRAP_FakeMotionEvent_wr(dpy, screen, x, y, delay); + if (grab_ptr) { + adjust_grabs(1, 1); + } return; } @@ -702,6 +730,9 @@ void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, #if LIBVNCSERVER_HAVE_XTEST XTestFakeMotionEvent(dpy, screen, x, y, delay); #endif + if (grab_ptr) { + adjust_grabs(1, 1); + } } Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) { -- cgit v1.1