x11vnc: -display WAIT:..., -users unixpw=, su_verify dpy command.

pull/1/head
runge 17 years ago
parent a60ee2ee9f
commit 1776a3a55f

@ -1,10 +1,13 @@
2006-06-08 Karl Runge <runge@karlrunge.com>
* prepare_x11vnc_dist.sh: to 0.8.2
2006-05-29 Steven Carr <scarr@jsa-usa.com>
* Identified and removed some memory leaks associated
with the Encodings RRE, CoRRE, ZLIB, and Ultra.
* KeyboardLedState now has portable masks defined.
* rfb >= 3.7 Security Type Handler list would grow 1
entry for each new client connection.
2006-05-16 Steven Carr <scarr@jsa-usa.com>
* Statistics output now fits in 80-column output
* Corrected Cursor Statistics reporting as messages

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

@ -1,3 +1,8 @@
2006-06-08 Karl Runge <runge@karlrunge.com>
* x11vnc: XOpenDisplay wrapper for raw xauth data, -unixpw
su_verify() to run any cmd, -users unixpw= mode. -display WAIT:...
modes for delayed X display opening and dynamic choosing.
2006-06-03 Karl Runge <runge@karlrunge.com>
* x11vnc: -capslock and -skip_lockkeys options. map some Alt keys
to Latin under linuxfb. switch to new stats API. Handle more

File diff suppressed because it is too large Load Diff

@ -155,7 +155,7 @@ void clean_up_exit (int ret) {
}
#endif
/* XXX rdpy_ctrl, etc. cannot close w/o blocking */
XCloseDisplay(dpy);
XCloseDisplay_wr(dpy);
X_UNLOCK;
fflush(stderr);
@ -311,6 +311,7 @@ static void crash_shell(void) {
crash_shell_help();
} else if (*str == 's' && *(str+1) == '\0') {
sprintf(cmd, "sh -c '(%s) &'", crash_stack_command1);
/* crash */
if (no_external_cmds) {
fprintf(stderr, "\nno_external_cmds=%d\n",
no_external_cmds);

@ -448,6 +448,7 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) {
sprintf(str, "%d", client_count);
set_env("RFB_CLIENT_COUNT", str);
/* gone, accept, afteraccept */
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds mode:\n");

@ -5,6 +5,7 @@
#include "win_utils.h"
#include "remote.h"
#include "cleanup.h"
#include "xwrappers.h"
#include "tkx11vnc.h"
@ -229,15 +230,15 @@ if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc
} else {
old_xauth = strdup("");
}
dpy = XOpenDisplay(x11vnc_xdisplay);
dpy = XOpenDisplay_wr(x11vnc_xdisplay);
if (! dpy && auth_file) {
set_env("XAUTHORITY", auth_file);
dpy = XOpenDisplay(x11vnc_xdisplay);
dpy = XOpenDisplay_wr(x11vnc_xdisplay);
}
if (! dpy && ! x11vnc_xdisplay) {
/* worstest case */
x11vnc_xdisplay = strdup(":0");
dpy = XOpenDisplay(x11vnc_xdisplay);
dpy = XOpenDisplay_wr(x11vnc_xdisplay);
}
if (! dpy) {
rfbLog("gui: could not open x11vnc "
@ -310,7 +311,7 @@ if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc
set_env("X11VNC_CONNECT_FILE", client_connect_file);
}
if (dpy) {
XCloseDisplay(dpy);
XCloseDisplay_wr(dpy);
dpy = NULL;
}
if (old_xauth) {
@ -418,6 +419,7 @@ if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc
set_env("X11VNC_ICON_FONT", icon_mode_font);
}
/* gui */
if (no_external_cmds) {
fprintf(stderr, "cannot run external commands in -nocmds "
"mode:\n");
@ -576,20 +578,20 @@ void do_gui(char *opts, int sleep) {
fprintf(stderr, "starting gui, trying display: %s\n",
gui_xdisplay);
}
test_dpy = XOpenDisplay(gui_xdisplay);
test_dpy = XOpenDisplay_wr(gui_xdisplay);
if (! test_dpy && auth_file) {
if (getenv("XAUTHORITY") != NULL) {
old_xauth = strdup(getenv("XAUTHORITY"));
}
set_env("XAUTHORITY", auth_file);
test_dpy = XOpenDisplay(gui_xdisplay);
test_dpy = XOpenDisplay_wr(gui_xdisplay);
}
if (! test_dpy) {
if (! old_xauth && getenv("XAUTHORITY") != NULL) {
old_xauth = strdup(getenv("XAUTHORITY"));
}
set_env("XAUTHORITY", "");
test_dpy = XOpenDisplay(gui_xdisplay);
test_dpy = XOpenDisplay_wr(gui_xdisplay);
}
if (! test_dpy) {
fprintf(stderr, "error: cannot connect to gui X DISPLAY: %s\n",
@ -603,7 +605,7 @@ void do_gui(char *opts, int sleep) {
tray_manager_ok = 0;
}
}
XCloseDisplay(test_dpy);
XCloseDisplay_wr(test_dpy);
if (start_x11vnc) {

@ -69,7 +69,8 @@ void print_help(int mode) {
"-display disp X11 server display to connect to, usually :0. The X\n"
" server process must be running on same machine and\n"
" support MIT-SHM. Equivalent to setting the DISPLAY\n"
" environment variable to \"disp\".\n"
" environment variable to \"disp\". See the description\n"
" below of the \"-display WAIT:...\" extensions.\n"
"-auth file Set the X authority file to be \"file\", equivalent to\n"
" setting the XAUTHORITY environment variable to \"file\"\n"
" before startup. Same as -xauth file. See Xsecurity(7),\n"
@ -298,7 +299,7 @@ void print_help(int mode) {
" and only loop 5 times.\n"
"-timeout n Exit unless a client connects within the first n seconds\n"
" after startup.\n"
"-inetd Launched by inetd(1): stdio instead of listening socket.\n"
"-inetd Launched by inetd(8): stdio instead of listening socket.\n"
" Note: if you are not redirecting stderr to a log file\n"
" (via shell 2> or -o option) you MUST also specify the -q\n"
" option, otherwise the stderr goes to the viewer which\n"
@ -554,6 +555,62 @@ void print_help(int mode) {
" for any other modern environment. All of the -unixpw\n"
" options and contraints apply.\n"
"\n"
"-display WAIT:... A special usage mode for the normal -display option.\n"
" Useful with -unixpw, but can be used independently\n"
" of it. If the display string begins with WAIT: then\n"
" x11vnc waits until a VNC client connects before opening\n"
" the X display (or -rawfb device).\n"
"\n"
" This could be useful for delaying opening the display\n"
" for certain usage modes (say if x11vnc is started at\n"
" boot time and no X server is running or users logged\n"
" in yet).\n"
"\n"
" If the string is, e.g. WAIT:0.0 or WAIT:1, i.e. \"WAIT\"\n"
" in front of a normal X display, then that indicated\n"
" display is used. A more interesting case is like this:\n"
"\n"
" WAIT:cmd=/usr/local/bin/find_display\n"
"\n"
" in which case the command after \"cmd=\" is run to\n"
" dynamically work out the DISPLAY and optionally the\n"
" XAUTHORITY data. The first line of the command output\n"
" must be of the form DISPLAY=<xdisplay>. Any remaining\n"
" output is taken as XAUTHORITY data. It can be either\n"
" of the form XAUTHORITY=<file> or raw xauthority data for\n"
" the display (e.g. \"xauth extract - $DISPLAY\" output).\n"
"\n"
" In the case of -unixpw, then the above command is run\n"
" as the user who just authenticated via the login and\n"
" password prompt.\n"
"\n"
" Thus 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"
" multiple users share a given machine. The user does\n"
" not need to remember special ports or passwords set up\n"
" for his desktop and VNC.\n"
"\n"
" A nice way to use WAIT:cmd=... is out of inetd(8)\n"
" (it automatically forks a new x11vnc for each user).\n"
" You can have the x11vnc inetd spawned process run as,\n"
" say, root or nobody. When run as root (for either\n"
" inetd or display manager), you can also supply the\n"
" option \"-users unixpw=\" to have the x11vnc process\n"
" switch to the user as well. Note: there will be a 2nd\n"
" SSL helper process that will not switch, but it is only\n"
" encoding and decoding the stream at that point.\n"
"\n"
" As a special case, WAIT:cmd=FINDDISPLAY will run a\n"
" script that works on most Unixes to determine a user's\n"
" DISPLAY variable and xauthority data. this is TBD.\n"
"\n"
" Finally, one can insert a geometry between colons,\n"
" e.g. WAIT:1280x1024:... to set the size of the display\n"
" the VNC client first attaches to since some VNC viewers\n"
" will not automatically adjust to a new framebuffer size.\n"
"\n"
"-ssl [pem] Use the openssl library (www.openssl.org) to provide a\n"
" built-in encrypted SSL tunnel between VNC viewers and\n"
" x11vnc. This requires libssl support to be compiled\n"
@ -689,24 +746,24 @@ void print_help(int mode) {
" is attempted to be loaded. As a kludge, use a token\n"
" like ../server-foo to load a server cert if you find\n"
" that necessary.\n"
" \n"
"\n"
" Use -ssldir to use a directory different from the\n"
" ~/.vnc/certs default.\n"
" \n"
"\n"
" Note that if the \"CA\" cert is loaded you do not need\n"
" to load any of the certs that have been signed by it.\n"
" You will need to load any additional self-signed certs\n"
" however.\n"
" \n"
"\n"
" Examples:\n"
" x11vnc -ssl -sslverify CA\n"
" x11vnc -ssl -sslverify self:fred,self:jim\n"
" x11vnc -ssl -sslverify CA,clients\n"
" \n"
"\n"
" Usually \"-sslverify CA\" is the most effective.\n"
" See the -sslGenCA and -sslGenCert options below for\n"
" how to set up and manage the CA framework.\n"
" \n"
"\n"
"\n"
"\n"
" NOTE: the following utilities, -sslGenCA, -sslGenCert,\n"
@ -1092,7 +1149,7 @@ void print_help(int mode) {
" otherwise the client is rejected. See below for an\n"
" extension to accept a client view-only.\n"
"\n"
" If x11vnc is running as root (say from inetd(1) or from\n"
" If x11vnc is running as root (say from inetd(8) or from\n"
" display managers xdm(1), gdm(1), etc), think about the\n"
" security implications carefully before supplying this\n"
" option (likewise for the -gone option).\n"
@ -1163,75 +1220,84 @@ void print_help(int mode) {
" Unlike -accept, the command return code is not\n"
" interpreted by x11vnc. Example: -gone 'xlock &'\n"
"\n"
"-users list If x11vnc is started as root (say from inetd(1) or from\n"
"-users list If x11vnc is started as root (say from inetd(8) or from\n"
" display managers xdm(1), gdm(1), etc), then as soon\n"
" as possible after connections to the X display are\n"
" established try to switch to one of the users in the\n"
" comma separated \"list\". If x11vnc is not running as\n"
" root this option is ignored.\n"
" \n"
"\n"
" Why use this option? In general it is not needed since\n"
" x11vnc is already connected to the X display and can\n"
" perform its primary functions. The option was added\n"
" to make some of the *external* utility commands x11vnc\n"
" occasionally runs work properly. In particular under\n"
" GNOME and KDE to implement the \"-solid color\" feature\n"
" external commands (gconftool-2 and dcop) must be run\n"
" as the user owning the desktop session. Since this\n"
" option switches userid it also affects the userid used\n"
" to run the processes for the -accept and -gone options.\n"
" It also affects the ability to read files for options\n"
" such as -connect, -allow, and -remap. Note that the\n"
" -connect file is also sometimes written to.\n"
" \n"
" So be careful with this option since in many situations\n"
" external commands (gconftool-2 and dcop) unfortunately\n"
" must be run as the user owning the desktop session.\n"
" Since this option switches userid it also affects the\n"
" userid used to run the processes for the -accept and\n"
" -gone options. It also affects the ability to read\n"
" files for options such as -connect, -allow, and -remap.\n"
" Note that the -connect file is also sometimes written\n"
" to.\n"
"\n"
" So be careful with this option since in some situations\n"
" its use can decrease security.\n"
" \n"
" The switch to a user will only take place if the\n"
" display can still be successfully opened as that user\n"
" (this is primarily to try to guess the actual owner\n"
"\n"
" In general the switch to a user will only take place\n"
" if the display can still be successfully opened as that\n"
" user (this is primarily to try to guess the actual owner\n"
" of the session). Example: \"-users fred,wilma,betty\".\n"
" Note that a malicious user \"barney\" by quickly using\n"
" \"xhost +\" when logging in may get x11vnc to switch\n"
" to user \"fred\". What happens next?\n"
" \n"
" \"xhost +\" when logging in may possibly get the x11vnc\n"
" process to switch to user \"fred\". What happens next?\n"
"\n"
" Under display managers it may be a long time before\n"
" the switch succeeds (i.e. a user logs in). To make\n"
" it switch immediately regardless if the display\n"
" the switch succeeds (i.e. a user logs in). To instead\n"
" make it switch immediately regardless if the display\n"
" can be reopened prefix the username with the \"+\"\n"
" character. E.g. \"-users +bob\" or \"-users +nobody\".\n"
"\n"
" The latter (i.e. switching immediately to user\n"
" \"nobody\") is probably the only use of this option\n"
" that increases security.\n"
" \n"
"\n"
" In -unixpw mode, if \"-users unixpw=\" is supplied\n"
" then after a user authenticates himself via the\n"
" -unixpw mechanism, x11vnc will try to switch to that\n"
" user as though \"-users +username\" had been supplied.\n"
" If you want to limit which users this will be done for,\n"
" provide them as a comma separated list after \"unixpw=\"\n"
"\n"
" To immediately switch to a user *before* connections\n"
" to the X display are made or any files opened use the\n"
" \"=\" character: \"-users =bob\". That user needs to\n"
" be able to open the X display of course.\n"
" \n"
" be able to open the X display and any files of course.\n"
"\n"
" The special user \"guess=\" means to examine the utmpx\n"
" database (see who(1)) looking for a user attached to\n"
" the display number (from DISPLAY or -display option)\n"
" and try him/her. To limit the list of guesses, use:\n"
" \"-users guess=bob,betty\".\n"
" \n"
" Even more sinister is the special user \"lurk=\" that\n"
" means to try to guess the DISPLAY from the utmpx login\n"
" database as well. So it \"lurks\" waiting for anyone\n"
" to log into an X session and then connects to it.\n"
" Specify a list of users after the = to limit which\n"
" users will be tried. To enable a different searching\n"
" mode, if the first user in the list is something like\n"
" \":0\" or \":0-2\" that indicates a range of DISPLAY\n"
" numbers that will be tried (regardless of whether\n"
" they are in the utmpx database) for all users that\n"
" are logged in. Examples: \"-users lurk=\" and also\n"
" \"-users lurk=:0-1,bob,mary\"\n"
" \n"
"\n"
" Even more sinister is the special user \"lurk=\"\n"
" that means to try to guess the DISPLAY from the utmpx\n"
" login database as well. So it \"lurks\" waiting for\n"
" anyone to log into an X session and then connects to it.\n"
" Specify a list of users after the = to limit which users\n"
" will be tried. To enable a different searching mode, if\n"
" the first user in the list is something like \":0\" or\n"
" \":0-2\" that indicates a range of DISPLAY numbers that\n"
" will be tried (regardless of whether they are in the\n"
" utmpx database) for all users that are logged in. Also\n"
" see the \"-display WAIT:...\" functionality. Examples:\n"
" \"-users lurk=\" and also \"-users lurk=:0-1,bob,mary\"\n"
"\n"
" Be especially careful using the \"guess=\" and \"lurk=\"\n"
" modes. They are not recommended for use on machines\n"
" with untrustworthy local users.\n"
" \n"
"\n"
"-noshm Do not use the MIT-SHM extension for the polling.\n"
" Remote displays can be polled this way: be careful this\n"
" can use large amounts of network bandwidth. This is\n"
@ -1255,7 +1321,7 @@ void print_help(int mode) {
" commands are run for GNOME and KDE respectively.\n"
" Other desktops won't work, e.g. Xfce (send us the\n"
" corresponding commands if you find them). If x11vnc is\n"
" running as root (inetd(1) or gdm(1)), the -users option\n"
" running as root (inetd(8) or gdm(1)), the -users option\n"
" may be needed for GNOME and KDE. If x11vnc guesses\n"
" your desktop incorrectly, you can force it by prefixing\n"
" color with \"gnome:\", \"kde:\", \"cde:\" or \"root:\".\n"
@ -1554,7 +1620,7 @@ void print_help(int mode) {
" default (see -noxfixes below). This can be disabled\n"
" with -nocursor, and also some values of the \"mode\"\n"
" option below.\n"
" \n"
"\n"
" Note that under XFIXES cursors with transparency (alpha\n"
" channel) will usually not be exactly represented and one\n"
" may find Overlay preferable. See also the -alphacut\n"
@ -1606,7 +1672,7 @@ void print_help(int mode) {
" pixel with alpha value less than n becomes completely\n"
" transparent. Otherwise the pixel is completely opaque.\n"
" Default %d\n"
" \n"
"\n"
"-alphafrac fraction With the threshold in -alphacut some cursors will become\n"
" almost completely transparent because their alpha values\n"
" are not high enough. For those cursors adjust the\n"
@ -1872,7 +1938,7 @@ void print_help(int mode) {
" So for a short time there are two (or more) block\n"
" cursors on the screen. There are similar scenarios,\n"
" (e.g. an output line is duplicated).\n"
" \n"
"\n"
" These transients are induced by the approximation of\n"
" scroll detection (e.g. it detects the scroll, but not\n"
" the fact that the block cursor was cleared just before\n"
@ -2279,7 +2345,7 @@ void print_help(int mode) {
" mode if the bpp is 24.\n"
"\n"
" video4linux: on Linux some attempt is made to handle\n"
" video devices (webcams or tv tuners) automatically.\n"
" video devices (webcams or TV tuners) automatically.\n"
" The idea is the WxHxB will be extracted from the\n"
" device itself. So if you do not supply \"@WxHxB...\n"
" parameters x11vnc will try to determine them. It first\n"
@ -2326,7 +2392,7 @@ void print_help(int mode) {
" 24, and 32 respectively). See http://www.linuxtv.org\n"
" for more info (V4L api).\n"
"\n"
" For tv/rf tuner cards one can set the tuning mode\n"
" For TV/rf tuner cards one can set the tuning mode\n"
" via tun=XXX where XXX can be one of PAL, NTSC, SECAM,\n"
" or AUTO.\n"
"\n"

@ -93,7 +93,7 @@ char *allowed_input_str = NULL;
char *viewonly_passwd = NULL; /* view only passwd. */
char **passwd_list = NULL; /* for -passwdfile */
int begin_viewonly = -1;
int inetd = 0; /* spawned from inetd(1) */
int inetd = 0; /* spawned from inetd(8) */
#ifndef FILEXFER
#define FILEXFER 1
#endif

@ -941,6 +941,7 @@ if (0) fprintf(stderr, "initialize_pipeinput: %s -- %s\n", pipeinput_str, p);
}
set_child_info();
/* pipeinput */
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds mode:\n");

@ -585,7 +585,7 @@ int remote_control_access_ok(void) {
"XAUTHORITY\n", dpy_str);
fprintf(stderr, " -- (ignore any Xlib: errors that"
" follow) --\n");
dpy2 = XOpenDisplay(dpy_str);
dpy2 = XOpenDisplay_wr(dpy_str);
fflush(stderr);
fprintf(stderr, " -- (done checking) --\n\n");
@ -601,7 +601,7 @@ int remote_control_access_ok(void) {
if (dpy2) {
rfbLog("XAUTHORITY is not required on display.\n");
rfbLog(" %s\n", DisplayString(dpy));
XCloseDisplay(dpy2);
XCloseDisplay_wr(dpy2);
dpy2 = NULL;
return 0;
}

@ -541,7 +541,7 @@ void set_raw_fb_params(int restore) {
multiple_cursors_mode = mc0;
if (! dpy && raw_fb_orig_dpy) {
dpy = XOpenDisplay(raw_fb_orig_dpy);
dpy = XOpenDisplay_wr(raw_fb_orig_dpy);
if (dpy) {
if (! quiet) rfbLog("reopened DISPLAY: %s\n",
raw_fb_orig_dpy);
@ -881,6 +881,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
set_child_info();
q += strlen("setup:");
/* rawfb-setup */
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds "
@ -988,7 +989,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
if (dpy) {
rfbLog("closing X DISPLAY: %s in rawfb mode.\n",
DisplayString(dpy));
XCloseDisplay(dpy); /* yow! */
XCloseDisplay_wr(dpy); /* yow! */
}
dpy = NULL;
}
@ -1974,7 +1975,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
have_masks = 0;
}
if (cmap8to24 && depth == 8) {
if (cmap8to24 && depth == 8 && dpy) {
XVisualInfo vinfo;
/* more cooking up... */
have_masks = 2;
@ -2042,6 +2043,8 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
rfbLog("Raw fb at addr %p is %dbpp depth=%d "
"true color\n", raw_fb_addr,
fb_bpp, fb_depth);
} else if (! dpy) {
;
} else if (have_masks == 2) {
rfbLog("\n");
rfbLog("X display %s is %dbpp depth=%d indexed "
@ -2206,6 +2209,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
fprintf(stderr, " 8to24_fb: %p\n", cmap8to24_fb);
fprintf(stderr, " snap_fb: %p\n", snap_fb);
fprintf(stderr, " raw_fb: %p\n", raw_fb);
fprintf(stderr, " fake_fb: %p\n", fake_fb);
fprintf(stderr, "\n");
}

@ -53,6 +53,7 @@ static int dt_cmd(char *cmd) {
return 0;
}
/* dt */
if (no_external_cmds) {
rfbLog("cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", cmd);

@ -113,6 +113,7 @@ int start_stunnel(int stunnel_port, int x11vnc_port) {
return 0;
}
/* stunnel */
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("start_stunnel: cannot run external commands in -nocmds mode:\n");

@ -246,6 +246,7 @@ static char *create_tmp_pem(char *pathin, int prompt) {
CN = strdup(line);
EM = strdup("x11vnc@server.nowhere");
/* ssl */
if (no_external_cmds) {
rfbLog("create_tmp_pem: cannot run external commands.\n");
return NULL;
@ -818,7 +819,7 @@ void openssl_port(void) {
rfbLog("openssl_port: could not reopen port %d\n", port);
clean_up_exit(1);
}
if (db) fprintf(stderr, "listen on port/sock %d/%d\n", port, sock);
rfbLog("openssl_port: listen on port/sock %d/%d\n", port, sock);
openssl_sock = sock;
openssl_port_num = port;

@ -316,6 +316,12 @@ Tuning
=D-C:0,1,2,3,4 pointer_mode:
input_skip:
=D nodragging
-- D
speeds:
=D wait:
defer:
=D nap
screen_blank:
--
=GAL WireFrame::
wireframe
@ -337,12 +343,6 @@ Tuning
xd_area:
xd_mem:
=GAL LOFF
-- D
speeds:
=D wait:
defer:
=D nap
screen_blank:
--
=GAL SharedMemory::
noshm

@ -327,6 +327,12 @@ char gui_code[] = "";
" =D-C:0,1,2,3,4 pointer_mode:\n"
" input_skip:\n"
" =D nodragging\n"
" -- D\n"
" speeds:\n"
" =D wait:\n"
" defer:\n"
" =D nap\n"
" screen_blank:\n"
" --\n"
" =GAL WireFrame::\n"
" wireframe\n"
@ -348,12 +354,6 @@ char gui_code[] = "";
" xd_area:\n"
" xd_mem:\n"
" =GAL LOFF\n"
" -- D\n"
" speeds:\n"
" =D wait:\n"
" defer:\n"
" =D nap\n"
" screen_blank:\n"
" --\n"
" =GAL SharedMemory::\n"
" noshm\n"

@ -49,7 +49,7 @@ void unixpw_screen(int init);
void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init);
void unixpw_accept(char *user);
void unixpw_deny(void);
int su_verify(char *user, char *pass);
int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size);
int crypt_verify(char *user, char *pass);
static int white(void);
@ -63,6 +63,10 @@ int unixpw_login_viewonly = 0;
time_t unixpw_last_try_time = 0;
rfbClientPtr unixpw_client = NULL;
int keep_unixpw = 0;
char *keep_unixpw_user = NULL;
char *keep_unixpw_pass = NULL;
static int in_login = 0, in_passwd = 0, tries = 0;
static int char_row = 0, char_col = 0;
static int char_x = 0, char_y = 0, char_w = 8, char_h = 16;
@ -352,11 +356,11 @@ int crypt_verify(char *user, char *pass) {
#endif /* UNIXPW_CRYPT */
}
int su_verify(char *user, char *pass) {
int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size) {
#ifndef UNIXPW_SU
return 0;
#else
int i, j, status, fd = -1, sfd, tfd;
int i, j, status, fd = -1, sfd, tfd, drain_size = 4096, rsize;
int slow_pw = 1;
char *slave, *bin_true = NULL, *bin_su = NULL;
pid_t pid, pidw;
@ -389,6 +393,7 @@ int su_verify(char *user, char *pass) {
return 0;
}
}
/* unixpw */
if (no_external_cmds) {
rfbLog("su_verify: cannot run external commands.\n");
clean_up_exit(1);
@ -417,6 +422,10 @@ int su_verify(char *user, char *pass) {
} if (stat("/usr/bin/true", &sbuf) == 0) {
bin_true = "/usr/bin/true";
}
if (cmd != NULL && cmd[0] != '\0') {
/* this is for ext. cmd su -c "my cmd" */
bin_true = cmd;
}
if (bin_true == NULL) {
rfbLogPerror("existence /bin/true");
return 0;
@ -617,13 +626,13 @@ if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
if (db) fprintf(stderr, "%s", buf);
if (db > 3 && n == 1 && buf[0] == ':') {
char cmd[32];
char cmd0[32];
usleep( 100 * 1000 );
fprintf(stderr, "\n\n");
sprintf(cmd, "ps wu %d", pid);
system(cmd);
sprintf(cmd, "stty -a < %s", slave);
system(cmd);
sprintf(cmd0, "ps wu %d", pid);
system(cmd0);
sprintf(cmd0, "stty -a < %s", slave);
system(cmd0);
fprintf(stderr, "\n\n");
}
@ -675,7 +684,12 @@ if (db) {
* if we don't drain we may block at waitpid. If we close(fd), the
* make cause child to die by signal.
*/
for (i = 0; i<4096; i++) {
if (rbuf && *rbuf_size > 0) {
/* asked to return output of command */
drain_size = *rbuf_size;
rsize = 0;
}
for (i = 0; i< drain_size; i++) {
int n;
buf[0] = '\0';
@ -691,6 +705,48 @@ if (db) fprintf(stderr, "%s", buf);
if (n <= 0) {
break;
}
if (rbuf) {
rbuf[i] = buf[0];
rsize++;
}
}
if (rbuf) {
char *s = rbuf;
char *p = strdup(pass);
int n, o = 0;
n = strlen(p);
if (p[n-1] == '\n') {
p[n-1] = '\0';
}
/*
* usually is: Password: mypassword\r\n\r\n<output-of-command>
* and output will have \n -> \r\n
*/
if (rbuf[0] == ' ') {
s++;
o++;
}
if (strstr(s, p) == s) {
s += strlen(p);
o += strlen(p);
for (n = 0; n < 4; n++) {
if (s[0] == '\r' || s[0] == '\n') {
s++;
o++;
}
}
}
if (o > 0) {
int i = 0;
rsize -= o;
while (o < drain_size) {
rbuf[i++] = rbuf[o++];
}
}
*rbuf_size = rsize;
strzero(p);
}
if (db) fprintf(stderr, "\n");
@ -730,14 +786,39 @@ if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "***
if (unixpw_nis) {
if (crypt_verify(user, pass)) {
unixpw_accept(user);
if (keep_unixpw) {
keep_unixpw_user = strdup(user);
keep_unixpw_pass = strdup(pass);
}
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)) {
if (su_verify(user, pass, NULL, NULL, NULL)) {
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);
@ -803,6 +884,14 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) {
user[i] = '\0';
pass[i] = '\0';
}
if (keep_unixpw_user) {
free(keep_unixpw_user);
keep_unixpw_user = NULL;
}
if (keep_unixpw_pass) {
free(keep_unixpw_pass);
keep_unixpw_pass = NULL;
}
return;
}
@ -1027,6 +1116,41 @@ static void apply_opts (char *user) {
void unixpw_accept(char *user) {
apply_opts(user);
if (started_as_root == 1 && users_list
&& strstr(users_list, "unixpw=") == users_list) {
if (getuid() && geteuid()) {
rfbLog("unixpw_accept: unixpw= but not root\n");
started_as_root = 2;
} else {
char *u = (char *)malloc(strlen(user)+1);
u[0] = '\0';
if (!strcmp(users_list, "unixpw=")) {
sprintf(u, "+%s", user);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("unixpw="), ",");
while (p) {
if (!strcmp(p, user)) {
sprintf(u, "+%s", user);
break;
}
p = strtok(NULL, ",");
}
free(str);
}
if (u[0] == '\0') {
rfbLog("unixpw_accept skipping switch to user: %s\n", user);
} else if (switch_user(u, 0)) {
rfbLog("unixpw_accept switched to user: %s\n", user);
} else {
rfbLog("unixpw_accept failed to switched to user: %s\n", user);
}
free(u);
}
}
if (unixpw_login_viewonly) {
unixpw_client->viewOnly = TRUE;
}

@ -7,12 +7,15 @@ extern void unixpw_screen(int init);
extern void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init);
extern void unixpw_accept(char *user);
extern void unixpw_deny(void);
extern int su_verify(char *user, char *pass);
extern int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size);
extern int crypt_verify(char *user, char *pass);
extern int unixpw_in_progress;
extern int unixpw_login_viewonly;
extern time_t unixpw_last_try_time;
extern rfbClientPtr unixpw_client;
extern int keep_unixpw;
extern char *keep_unixpw_user;
extern char *keep_unixpw_pass;
#endif /* _X11VNC_UNIXPW_H */

@ -6,6 +6,8 @@
#include "scan.h"
#include "screen.h"
#include "unixpw.h"
#include "sslhelper.h"
#include "xwrappers.h"
void check_switched_user(void);
void lurk_loop(char *str);
@ -13,6 +15,7 @@ int switch_user(char *user, int fb_mode);
int read_passwds(char *passfile);
void install_passwds(void);
void check_new_passwds(void);
int wait_for_client(int *argc, char** argv, int http);
static void switch_user_task_dummy(void);
@ -574,9 +577,9 @@ static int try_user_and_display(uid_t uid, char *dpystr) {
}
fclose(stderr);
dpy2 = XOpenDisplay(dpystr);
dpy2 = XOpenDisplay_wr(dpystr);
if (dpy2) {
XCloseDisplay(dpy2);
XCloseDisplay_wr(dpy2);
exit(0); /* success */
} else {
exit(2); /* fail */
@ -940,4 +943,234 @@ void check_new_passwds(void) {
}
}
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 db = 0;
if (! use_dpy || strstr(use_dpy, "WAIT:") != use_dpy) {
return 0;
}
rfbLog("into wait_for_client.\n");
str = strdup(use_dpy);
str += strlen("WAIT:");
q = strchr(str, ':');
/* get any leading geometry: */
if (q) *q = '\0';
if (sscanf(str, "%dx%d", &w0, &h0) == 2) {
w = w0;
h = h0;
}
if (q) *q = ':';
q = strchr(str, ':');
if (! q) {
if (strstr(str, "cmd=") != str) {
str = strdup(":0");
}
} else {
str = q;
}
if (db) fprintf(stderr, "str: %s\n", str);
if (strstr(str, "cmd=") == str) {
cmd = str + strlen("cmd=");
if (db) fprintf(stderr, "cmd: %s\n", cmd);
/* WAIT */
if (no_external_cmds) {
rfbLog("wait_for_client external cmds not allowed:"
" %s\n", use_dpy);
clean_up_exit(1);
}
}
if (fake_fb) {
free(fake_fb);
}
fake_fb = (char *) calloc(w*h*b/4, 1);
fb_image = &ximage_struct;
fb_image->data = fake_fb;
fb_image->format = ZPixmap;
fb_image->width = w;
fb_image->height = h;
fb_image->bits_per_pixel = b;
fb_image->bytes_per_line = w*b/8;
fb_image->bitmap_unit = -1;
fb_image->depth = 24;
fb_image->red_mask = 0xff0000;
fb_image->green_mask = 0x00ff00;
fb_image->blue_mask = 0x0000ff;
depth = fb_image->depth;
dpy_x = wdpy_x = w;
dpy_y = wdpy_y = h;
off_x = 0;
off_y = 0;
initialize_allowed_input();
initialize_screen(argc, argv, fb_image);
if (http && check_httpdir()) {
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;
}
if (inetd && use_openssl) {
accept_openssl(OPENSSL_INETD);
}
while (1) {
if (! use_threads) {
rfbPE(-1);
}
if (use_openssl) {
check_openssl();
}
if (! screen || ! screen->clientHead) {
usleep(100 * 1000);
continue;
}
rfbLog("wait_for_client: got client\n");
break;
}
if (unixpw) {
if (! unixpw_in_progress) {
rfbLog("unixpw but no unixpw_in_progress\n");
clean_up_exit(1);
}
while (1) {
if (! use_threads) {
rfbPE(-1);
}
if (unixpw_in_progress) {
usleep(20 * 1000);
continue;
}
rfbLog("wait_for_client: unixpw finished.\n");
break;
}
}
if (cmd) {
char line1[1024];
char line2[16384];
char *q;
int n;
memset(line1, 0, 1024);
memset(line2, 0, 16384);
if (unixpw) {
int res = 0, k, j;
char line[18000];
memset(line, 0, 18000);
if (keep_unixpw_user && keep_unixpw_pass) {
n = 18000;
res = su_verify(keep_unixpw_user, keep_unixpw_pass,
cmd, line, &n);
strzero(keep_unixpw_user);
strzero(keep_unixpw_pass);
}
keep_unixpw = 0;
if (! res) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd);
clean_up_exit(1);
}
for (k = 0; k < 1024; k++) {
line1[k] = line[k];
if (line[k] == '\n') {
k++;
break;
}
}
n -= k;
while (j < 16384) {
line2[j] = line[k+j];
j++;
}
} else {
FILE *p = popen(cmd, "r");
if (! p) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd);
rfbLogPerror("popen");
clean_up_exit(1);
}
if (fgets(line1, 1024, p) == NULL) {
rfbLog("wait_for_client: read failed: %s\n", cmd);
rfbLogPerror("fgets");
clean_up_exit(1);
}
n = fread(line2, 1, 16384, p);
pclose(p);
}
if (strstr(line1, "DISPLAY=") != line1) {
rfbLog("wait_for_client: bad reply %s\n", line1);
clean_up_exit(1);
}
use_dpy = strdup(line1 + strlen("DISPLAY="));
q = use_dpy;
while (*q != '\0') {
if (*q == '\n' || *q == '\r') *q = '\0';
q++;
}
if (db) fprintf(stderr, "use_dpy: %s n: %d\n", use_dpy, n);
if (0) write(2, line2, n);
if (line2[0] != '\0') {
if (strstr(line2, "XAUTHORITY=") == line2) {
q = line2;
while (*q != '\0') {
if (*q == '\n' || *q == '\r') *q = '\0';
q++;
}
if (auth_file) {
free(auth_file);
}
auth_file = strdup(line2 + strlen("XAUTHORITY="));
} else {
xauth_raw_data = (char *)malloc(n);
xauth_raw_len = n;
memcpy(xauth_raw_data, line2, n);
if (db) fprintf(stderr, "xauth_raw_len: %d\n", n);
if (0) {
write(2, xauth_raw_data, xauth_raw_len);
fprintf(stderr, "\n");
}
}
}
} else {
use_dpy = strdup(str);
}
if (chg_raw_fb) {
raw_fb = NULL;
}
return 1;
}

@ -9,5 +9,6 @@ extern int switch_user(char *, int);
extern int read_passwds(char *passfile);
extern void install_passwds(void);
extern void check_new_passwds(void);
extern int wait_for_client(int *argc, char** argv, int http);
#endif /* _X11VNC_USER_H */

@ -1089,6 +1089,7 @@ static char *guess_via_v4l_info(char *dev, int *fd) {
if (*fd) {}
/* v4l-info */
if (no_external_cmds) {
rfbLog("guess_via_v4l_info: cannot run external "
"command: v4l-info\n");

@ -304,6 +304,7 @@ int pick_windowid(unsigned long *num) {
if (use_dpy) {
set_env("DISPLAY", use_dpy);
}
/* id */
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds mode:\n");

@ -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.1, lastmod: 2006-06-03
version: 0.8.2, lastmod: 2006-06-08
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@ -60,7 +60,8 @@ becomes a space character).
X11 server display to connect to, usually :0. The X
server process must be running on same machine and
support MIT-SHM. Equivalent to setting the DISPLAY
environment variable to \fIdisp\fR.
environment variable to \fIdisp\fR. See the description
below of the "\fB-display\fR \fIWAIT:...\fR" extensions.
.PP
\fB-auth\fR \fIfile\fR
.IP
@ -355,7 +356,7 @@ after startup.
\fB-inetd\fR
.IP
Launched by
.IR inetd (1):
.IR inetd (8):
stdio instead of listening socket.
Note: if you are not redirecting stderr to a log file
(via shell 2> or \fB-o\fR option) you MUST also specify the \fB-q\fR
@ -515,6 +516,755 @@ used to have viewonly passwords. (tip: make the 3rd
and last line be "__BEGIN_VIEWONLY__" to have 2
full-access passwords)
.PP
\fB-unixpw\fR \fI[list]\fR
.IP
Use Unix username and password authentication. x11vnc
uses the
.IR su (1)
program to verify the user's password.
[list] is an optional comma separated list of allowed
Unix usernames. See below for per-user options that
can be applied.
.IP
A familiar "login:" and "Password:" dialog is
presented to the user on a black screen inside the
vncviewer. The connection is dropped if the user fails
to supply the correct password in 3 tries or does not
send one before a 25 second timeout. Existing clients
are view-only during this period.
.IP
Since the detailed behavior of
.IR su (1)
can vary from
OS to OS and for local configurations, test the mode
carefully on your systems before using it in production.
Test different combinations of valid/invalid usernames
and valid/invalid passwords to see if it behaves as
expected. x11vnc will attempt to be conservative and
reject a login if anything abnormal occurs.
.IP
On FreeBSD and the other BSD's by default it is
impossible for the user running x11vnc to validate
his *own* password via
.IR su (1)
(evidently commenting out
the pam_self.so entry in /etc/pam.d/su eliminates this
problem). So the x11vnc login will always *fail* for
this case (even when the correct password is supplied).
.IP
A possible workaround for this would be to start
x11vnc as root with the "\fB-users\fR \fI+nobody\fR" option to
immediately switch to user nobody. Another source of
problems are PAM modules that prompt for extra info,
e.g. password aging modules. These logins will fail
as well even when the correct password is supplied.
.IP
**IMPORTANT**: to prevent the Unix password being sent
in *clear text* over the network, one of two schemes
will be enforced: 1) the \fB-ssl\fR builtin SSL mode, or 2)
require both \fB-localhost\fR and \fB-stunnel\fR be enabled.
.IP
Method 1) ensures the traffic is encrypted between
viewer and server. A PEM file will be required, see the
discussion under \fB-ssl\fR below (under some circumstances
a temporary one can be automatically generated).
.IP
Method 2) requires the viewer connection to appear
to come from the same machine x11vnc is running on
(e.g. from a ssh \fB-L\fR port redirection). And that the
\fB-stunnel\fR SSL mode be used for encryption over the
network.(see the description of \fB-stunnel\fR below).
.IP
Note: as a convenience, if you
.IR ssh (1)
in and start
x11vnc it will check if the environment variable
SSH_CONNECTION is set and appears reasonable. If it
does, then the \fB-ssl\fR or \fB-stunnel\fR requirement will be
dropped since it is assumed you are using ssh for the
encrypted tunnelling. \fB-localhost\fR is still enforced.
Use \fB-ssl