diff options
author | runge <runge> | 2005-02-14 20:42:46 +0000 |
---|---|---|
committer | runge <runge> | 2005-02-14 20:42:46 +0000 |
commit | 5c13bd0cd45c4e5d600e94225fa962ee6be80821 (patch) | |
tree | 5433a079790ef3128f48c9fec04dca1e3820f774 | |
parent | 86ccf267b18b30a3c0d4f5b96b6738f3c2b17e2b (diff) | |
download | libtdevnc-5c13bd0cd45c4e5d600e94225fa962ee6be80821.tar.gz libtdevnc-5c13bd0cd45c4e5d600e94225fa962ee6be80821.zip |
x11vnc: -users lurk=, -solid for cde, -gui ez,.. beginner mode.
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | x11vnc/ChangeLog | 5 | ||||
-rw-r--r-- | x11vnc/README | 213 | ||||
-rwxr-xr-x | x11vnc/tkx11vnc | 461 | ||||
-rw-r--r-- | x11vnc/tkx11vnc.h | 461 | ||||
-rw-r--r-- | x11vnc/x11vnc.1 | 130 | ||||
-rw-r--r-- | x11vnc/x11vnc.c | 1225 |
7 files changed, 1826 insertions, 672 deletions
@@ -1,3 +1,6 @@ +2005-02-14 Karl Runge <runge@karlrunge.com> + * x11vnc: -users lurk=, -solid for cde, -gui ez,.. beginner mode. + 2005-02-10 Karl Runge <runge@karlrunge.com> * x11vnc: -input option to fine tune allowed client input, additions to remote control and gui for this. diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog index a08556d..c5b8107 100644 --- a/x11vnc/ChangeLog +++ b/x11vnc/ChangeLog @@ -1,3 +1,8 @@ +2005-02-14 Karl Runge <runge@karlrunge.com> + * cleanup -users stuff, add "lurk=" mode + * support cde in -solid + * simple gui mode for beginners, -gui ez,... + 2005-02-10 Karl Runge <runge@karlrunge.com> * Add -input to fine tune client input (keystroke, mouse motion, and button presses). Allow per-client setting via remote cntl. diff --git a/x11vnc/README b/x11vnc/README index 41f1db0..29c3df7 100644 --- a/x11vnc/README +++ b/x11vnc/README @@ -1,5 +1,5 @@ -x11vnc README file Date: Thu Feb 10 23:33:03 EST 2005 +x11vnc README file Date: Mon Feb 14 14:23:56 EST 2005 The following information is taken from these URLs: @@ -889,7 +889,9 @@ ls -l ./x11vnc/x11vnc the person sitting at the X session types "xhost +localhost" then one should be able to attach x11vnc to the session (from the same machine). The person could then type "xhost -localhost" after x11vnc - has connected to go back to the default permissions. + has connected to go back to the default permissions. Also, for some + situations the -users lurk= option may be of use (please read the + documentation on the -users option). Some Linux distributions or display managers may set XAUTHORITY to a random local filename. You need to dig out where they have hidden the @@ -2246,9 +2248,9 @@ ied) has been added to allow exact extraction of the mouse cursor shape. The only issue is the handling of alpha channel transparency in cursors (they must be approximated). XFIXES is available on recent - Linux Xorg based distros and Solaris 10 express (on Solaris you will - need to add "-L /usr/openwin/sfw/lib -R /usr/openwin/sfw/lib" to - LDFLAGS for configure to enable it). + Linux Xorg based distros and Solaris 10 (on Solaris you will need to + add "-L /usr/openwin/sfw/lib -R /usr/openwin/sfw/lib" to LDFLAGS for + configure to enable it). Q-43: When using XFIXES cursorshape mode, some of the cursors look really bad with extra black borders around the cursor and other cruft. @@ -3088,8 +3090,8 @@ 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.7.1pre lastmod: 2005-02-0 -5 +x11vnc: allow VNC connections to real X11 displays. 0.7.1pre lastmod: 2005-02-1 +4 x11vnc options: -display disp -auth file @@ -3102,9 +3104,10 @@ x11vnc options: -timeout n -inetd -connect string -vncconnect -novncconnect -allow host1[,host2..] - -localhost -viewpasswd string - -passwdfile filename -storepasswd pass file - -accept string -gone string + -localhost -input string + -viewpasswd string -passwdfile filename + -storepasswd pass file -accept string + -gone string -users list -noshm -flipbyteorder -onetile -solid [color] -blackout string -xinerama @@ -3163,8 +3166,8 @@ libvncserver options: % x11vnc -help -x11vnc: allow VNC connections to real X11 displays. 0.7.1pre lastmod: 2005-02-0 -5 +x11vnc: allow VNC connections to real X11 displays. 0.7.1pre lastmod: 2005-02-1 +4 Typical usage is: @@ -3210,7 +3213,8 @@ Options: environment variable to "disp". -auth file Set the X authority file to be "file", equivalent to setting the XAUTHORITY environment variable to "file" - before startup. See Xsecurity(7), xauth(1) man pages. + before startup. Same as -xauth file. See Xsecurity(7), + xauth(1) man pages for more info. -id windowid Show the window corresponding to "windowid" not the entire display. New windows like popup menus, @@ -3307,10 +3311,13 @@ Options: -connect string For use with "vncviewer -listen" reverse connections. If "string" has the form "host" or "host:port" the connection is made once at startup. Use commas - for a list of host's and host:port's. If "string" - contains "/" it is instead interpreted as a file to - periodically check for new hosts. The first line is - read and then the file is truncated. + for a list of host's and host:port's. + + If "string" contains "/" it is instead interpreted + as a file to periodically check for new hosts. + The first line is read and then the file is truncated. + Be careful for this usage mode if x11vnc is running as + root (e.g. via inetd(1) or gdm(1)). -vncconnect Monitor the VNC_CONNECT X property set by the standard -novncconnect VNC program vncconnect(1). When the property is set to "host" or "host:port" establish a reverse @@ -3327,14 +3334,30 @@ Options: each time a new client connects. Lines can be commented out with the "#" character in the usual way. -localhost Same as -allow 127.0.0.1 + +-input string Fine tuning of allowed user input. If "string" does + not contain a comma "," the tuning applies only to + normal clients. Otherwise the part before "," is + for normal clients and the part after for view-only + clients. "K" is for Keystroke input, "M" for + Mouse-motion input, and "B" for Button-click input. + Their presence in the string enables that type of input. + E.g. "-input M" means normal users can only move + the mouse and "-input KMB,M" lets normal users do + anything and enables view-only users to move the mouse. + This option is ignored when a global -viewonly is in + effect (all input is discarded). -viewpasswd string Supply a 2nd password for view-only logins. The -passwd (full-access) password must also be supplied. -passwdfile filename Specify libvncserver -passwd via the first line of the file "filename" instead of via command line. - If a second non blank line exists in the file it is - taken as a view-only password (i.e. -viewpasswd) Note: - this is a simple plaintext passwd, see also -rfbauth - and -storepasswd below for obfuscated passwords. + If a second non blank line exists in the file it + is taken as a view-only password (i.e. -viewpasswd) + To supply an empty password for either field use the + string "__EMPTY__". Note: -passwdfile is a simple + plaintext passwd, see also -rfbauth and -storepasswd + below for obfuscated passwords. Neither should be + readable by others. -storepasswd pass file Store password "pass" as the VNC password in the file "file". Once the password is stored the program exits. Use the password via "-rfbauth file" @@ -3348,6 +3371,11 @@ Options: otherwise the client is rejected. See below for an extension to accept a client view-only. + If x11vnc is running as root (say from inetd(1) or from + display managers xdm(1), gdm(1), etc), think about the + security implications carefully before supplying this + option (likewise for the -gone option). + Environment: The RFB_CLIENT_IP environment variable will be set to the incoming client IP number and the port in RFB_CLIENT_PORT (or -1 if unavailable). Similarly, @@ -3399,6 +3427,74 @@ Options: in -accept. Unlike -accept, the command return code is not interpreted by x11vnc. Example: -gone 'xlock &' +-users list If x11vnc is started as root (say from inetd(1) or + from display managers xdm(1), gdm(1), etc), then as + soon as possible after connections to the display are + established try to switch to one of the users in the + comma separated "list". If x11vnc is not running as + root this option is ignored. + + Why use this option? In general it is not needed + since x11vnc is already connected to the display and + can perform its primary functions. The option was + added to make some of the *external* utility commands + x11vnc occasionally runs work properly. In particular + under GNOME and KDE to implement the "-solid color" + feature external commands (gconftool-2 and dcop) must be + run as the user owning the desktop session. Since this + option switches userid it also affects the userid used + to run the processes for the -accept and -gone options. + It also affects the ability to read files for options + such as -connect, -allow, and -remap. Note that the + -connect file is also sometimes written to. + + So be careful with this option since in many situations + its use can decrease security. + + The switch to a user will only take place if the + display can still be successfully opened as that user + (this is primarily to try to guess the actual owner + of the session). Example: "-users fred,wilma,betty". + Note that a malicious user "barney" by quickly using + "xhost +" when logging in may get x11vnc to switch + to user "fred". What happens next? + + Under display managers it may be a long time before + the switch succeeds (i.e. a user logs in). To make + it switch immediately regardless if the display + can be reopened prefix the username with the + + character. E.g. "-users +bob" or "-users +nobody". + The latter (i.e. switching immediately to user + "nobody") is probably the only use of this option + that increases security. + + To immediately switch to a user *before* connections to + the display are made or any files opened use the "=" + character: "-users =bob". That user needs to be able + to open the display of course. + + The special user "guess=" means to examine the utmpx + database (see who(1)) looking for a user attached to + the display number (from DISPLAY or -display option) + and try him/her. To limit the list of guesses, use: + "-users guess=bob,betty". + + Even more sinister is the special user "lurk=" that + means to try to guess the DISPLAY from the utmpx login + database as well. So it "lurks" waiting for anyone + to log into an X session and then connects to it. + Specify a list of users after the = to limit which + users will be tried. If the first user in the list + is something like ":0" or ":0-2" that indicates a + range of DISPLAY numbers that will be tried (regardless + of whether they are in the utmpx database) for all + users that are logged in. Examples: "-users lurk=" + and "-users lurk=:0-1,bob,mary" + + Be especially careful using the "guess=" and "lurk=" + modes. They are not recommended for use on machines + with untrustworthy local users. + -noshm Do not use the MIT-SHM extension for the polling. Remote displays can be polled this way: be careful this can use large amounts of network bandwidth. This is @@ -3414,15 +3510,18 @@ Options: try to change the desktop background to a solid color. The [color] is optional: the default color is "cyan4". For a different one specify the X color (rgb.txt name, - e.g. "darkblue" or numerical "#RRGGBB"). Currently - this option only works on GNOME, KDE, and classic X - (i.e. with the background image on the root window). - The "gconftool-2" and "dcop" external commands are - run for GNOME and KDE respectively. Other desktops - won't work, e.g. XFCE (send us the corresponding - commands if you find them). If x11vnc guesses your - desktop incorrectly, you can force it by prefixing - color with "gnome:", "kde:", or "root:". + e.g. "darkblue" or numerical "#RRGGBB"). + + Currently this option only works on GNOME, KDE, CDE, + and classic X (i.e. with the background image on the + root window). The "gconftool-2" and "dcop" external + commands are run for GNOME and KDE respectively. + Other desktops won't work, e.g. XFCE (send us the + corresponding commands if you find them). If x11vnc is + running as root (inetd(1) or gdm(1)), the -users option + may be needed for GNOME and KDE. If x11vnc guesses + your desktop incorrectly, you can force it by prefixing + color with "gnome:", "kde:", "cde:" or "root:". -blackout string Black out rectangles on the screen. "string" is a comma separated list of WxH+X+Y type geometries for each rectangle. @@ -3818,9 +3917,11 @@ Options: up on the X display in the environment variable DISPLAY. "gui-opts" can be a comma separated list of items. - Currently there are only two types of items: 1) a gui - mode and 2) the X display the gui should display on. - The gui mode can be "start", "conn", or "wait" + Currently there are these types of items: 1) a gui mode, + a 2) gui "simplicity", and 3) the X display the gui + should display on. + + 1) The gui mode can be "start", "conn", or "wait" "start" is the default mode above and is not required. "conn" means do not automatically start up x11vnc, but instead just try to connect to an existing x11vnc @@ -3828,16 +3929,22 @@ Options: else (you will later instruct the gui to start x11vnc or connect to an existing one.) - Note the possible confusion regarding the potentially + 2) The gui simplicity is off by default (a power-user + gui with all options is presented) To start with + something less daunting supply the string "simple" + ("ez" is an alias for this). Once the gui is + started you can toggle between the two with "Misc -> + simple_gui". + + 3) Note the possible confusion regarding the potentially two different X displays: x11vnc polls one, but you may want the gui to appear on another. For example, if you ssh in and x11vnc is not running yet you may want the gui to come back to you via your ssh redirected X display (e.g. localhost:10). - Examples: "x11vnc -gui", "x11vnc -gui localhost:10", - "x11vnc -gui :10", "x11vnc -gui wait,:10", - "x11vnc -gui <x11vnc-opts...>" + Examples: "x11vnc -gui", "x11vnc -gui ez" + "x11vnc -gui localhost:10", "x11vnc -gui conn,host:0" If you do not specify a gui X display in "gui-opts" then the DISPLAY environment variable and -display @@ -3935,6 +4042,11 @@ Options: use "-host" to delete a single host localhost enable -localhost mode nolocalhost disable -localhost mode + input:str set -input to "str", empty to disable. + 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 + or client_input:0x2:K accept:cmd set -accept "cmd" (empty to disable). gone:cmd set -gone "cmd" (empty to disable). noshm enable -noshm mode. @@ -4103,13 +4215,13 @@ Options: xrandr_mode padgeom quiet q noquiet modtweak nomodtweak xkb noxkb skip_keycodes add_keysyms noadd_keysyms clear_mods noclear_mods clear_keys noclear_keys - remap repeat norepeat fb nofb bell nobell sel nosel - primary noprimary cursorshape nocursorshape cursorpos - nocursorpos cursor show_cursor noshow_cursor - nocursor xfixes noxfixes alphacut alphafrac - alpharemove noalpharemove alphablend noalphablend - xwarp xwarppointer noxwarp noxwarppointer buttonmap - dragging nodragging pointer_mode pm input_skip speeds + remap repeat norepeat fb nofb bell nobell sel + nosel primary noprimary cursorshape nocursorshape + cursorpos nocursorpos cursor show_cursor noshow_cursor + nocursor xfixes noxfixes alphacut alphafrac alpharemove + noalpharemove alphablend noalphablend xwarp xwarppointer + noxwarp noxwarppointer buttonmap dragging nodragging + pointer_mode pm input_skip input client_input speeds debug_pointer dp nodebug_pointer nodp debug_keyboard dk nodebug_keyboard nodk deferupdate defer wait rfbwait nap nonap sb screen_blank fs gaps grow fuzz snapfb @@ -4119,7 +4231,7 @@ Options: nodontdisconnect desktop noremote aro= display vncdisplay desktopname http_url auth - rootshift scale_str scaled_x scaled_y scale_numer + users rootshift scale_str scaled_x scaled_y scale_numer scale_denom scale_fac scaling_noblend scaling_nomult4 scaling_pad scaling_interpolate inetd safer unsafe passwdfile using_shm logfile o rc norc h help V version @@ -4157,10 +4269,13 @@ Options: Note that if they can modify VNC_CONNECT, they could also run their own x11vnc and have complete control of the desktop. If the "-connect /path/to/file" - channel is being used, obviously anyone who can write - to /path/to/file can remotely control x11vnc. So be - sure to protect the X display and that file's write - permissions. + channel is being used, obviously anyone who can + write to /path/to/file can remotely control x11vnc. + So be sure to protect the X display and that file's + write permissions. + + To disable the VNC_CONNECT property channel completely + use -novncconnect. -unsafe If x11vnc is running as root (e.g. inetd or Xsetup for a display manager) a few remote commands are disabled diff --git a/x11vnc/tkx11vnc b/x11vnc/tkx11vnc index 3ef212f..4a34f17 100755 --- a/x11vnc/tkx11vnc +++ b/x11vnc/tkx11vnc @@ -3,7 +3,7 @@ exec wish "$0" "$@" catch {rename send {}} # -# Copyright (c) 2004 Karl J. Runge <runge@karlrunge.com> +# Copyright (c) 2004-2005 Karl J. Runge <runge@karlrunge.com> # All rights reserved. # # This is free software; you can redistribute it and/or modify @@ -45,9 +45,6 @@ catch {rename send {}} # R means it is an action only valid in remote mode. # S means it is an action only valid in startup mode. # Q means it is an action worth querying after running. -# D means it is a good idea to delay a little before querying -# (i.e. perhaps it causes x11vnc to do a lot of work, new fb) -# No longer used, -sync is used instead. # P means the string can be +/- appended/deleted (string may not # be the same after the remote command) # G means gui internal item @@ -66,61 +63,61 @@ Row: Displays Screen Tuning Debugging Misc Actions =SA start =RA stop - =GA attach - =RA detach + =DGA attach + =DRA detach -- =RA ping =RA update-all =GA clear-all - -- - =RA stop+quit - =GA Quit + -- D + =DRA stop+quit + =DGA Quit Help - =GA gui + =DGA gui =GA all Clients - =RQA current: - =F connect: - =RQA disconnect: + =DRQA current: + =DF connect: + =DRQA disconnect: -- accept: gone: vncconnect - -- - http + -- D + =D http =F httpdir: httpport: enablehttpproxy Displays - display: + =D display: =F auth: - desktop: - rfbport: + =D desktop: + =D rfbport: =0 gui: Screen =DRA refresh - =DRA reset + =RA reset =DRA blacken - -- - =D id: - =D sid: + -- D + id: + sid: =D scale: -- - =D overlay + overlay overlay_nocursor -- - =D visual: + visual: flashcmap notruecolor -- - =DP blackout: - =D xinerama + =P blackout: + xinerama -- - solid + =D solid solid_color: -- = xrandr @@ -128,8 +125,8 @@ Screen padgeom: Keyboard - norepeat - add_keysyms + =D norepeat + =D add_keysyms skip_keycodes: modtweak xkb @@ -140,25 +137,27 @@ Keyboard clear_keys Pointer - =-C:none,arrow,X,some,most cursor: + =D-C:none,arrow,X,some,most cursor: noxfixes noalphablend -- cursorpos - nocursorshape + =D nocursorshape -- buttonmap: -- xwarppointer Misc + =GD simple-gui + -- D =F rc: norc -- nofb -- - nobell - nosel + =D nobell + =D nosel noprimary -- bg @@ -178,29 +177,29 @@ Debugging quiet -- =GA show-start-cmd - =G debug_gui + =DG debug_gui Permissions - =RQA lock - =RQA unlock + =DRQA lock + =DRQA unlock =SQA deny_all -- - =FP allow: + =DFP allow: localhost =RA allowonce: - -- + -- D =RA noremote -- - viewonly - shared - forever + =D viewonly + =D shared + =D forever timeout: -- input: -- - =SA alwaysshared - =SA nevershared - =SA dontdisconnect + =S alwaysshared + =S nevershared + =S dontdisconnect -- viewpasswd: =F passwdfile: @@ -212,22 +211,22 @@ Permissions unsafe Tuning - =-C:0,1,2,3,4 pointer_mode: + =D-C:0,1,2,3,4 pointer_mode: input_skip: - nodragging + =D nodragging -- - =D noshm + noshm flipbyteorder onetile -- alphacut: alphafrac: alpharemove - -- + -- D speeds: - wait: + =D wait: defer: - nap + =D nap screen_blank: -- fs: @@ -359,6 +358,12 @@ Set the -solid color value. Set the -xrandr mode value. " + set helptext(simple-gui) " +Toggle between menu items corresponding the most basic ones +and all possible settings. I.e. toggle between a simple gui +and one for power users. +" + set helptext(all) $helpall set helptext(gui) " @@ -366,7 +371,7 @@ tkx11vnc is a simple frontend to x11vnc. Nothing fancy, it merely provides an interface to each of the many x11vnc command line options and remote control commands. See \"Help -> all\" for much info about x11vnc. -Most menu items have a (?) button one can click on to get more information +All menu items have a (?) button one can click on to get more information about the option or command. There are two states tkx11vnc can be in: @@ -466,6 +471,57 @@ and -forever which are hopefully enough for most usage. They may be specified for x11vnc startup if desired. " + +global beginner_mode +if {$beginner_mode} { + set helptext(gui) " +tkx11vnc is a simple frontend to x11vnc. It is currently running in +\"ez\" or \"simple\" mode. For many more options run it in normal +mode buy toggling \"Misc -> simple_gui\". + +All menu items have a (?) button one can click on to get more information +about the option or command. + +GUI components: +--- ---------- + +1) At the top of the gui is a info text label where information will +be posted, e.g. when traversing menu items text indicating how to get +help on the item and its current value will be displayed. + +2) Below the info label is the area where the menu buttons, Actions, +Clients, etc., are presented. If a menu item has a checkbox, +it corresponds to a boolean on/off variable. Otherwise it is +either a string variable, or an action not associated with a +variable (for the most part). + +3) Below the menu button area is a text label indicating the current x11vnc +X display being polled and the corresponding VNC display name. Both +will be \"(*none*)\" when there is no connection established. + +4) Below the x11 and vnc displays text label is a text area there scrolling +information about actions being taken and commands being run is displayed. +To scroll click in the area and use PageUp/PageDown or the arrow keys. + +5) At the bottom is an entry area. When one selects a menu item that +requires supplying a string value, the label will be set to the +parameter name and one types in the new value. Then one presses the +\"OK\" button or presses \"Enter\" to set the value. Or you can press +\"Skip\" or \"Escape\" to avoid changing the variable. Some variables +are boolean toggles (for example, \"Permissions -> viewonly\") or Radio +button selections. Selecting these menu items will not activate the +entry area but rather toggle the variable directly. + + +Cascades Bug: There is a bug not yet worked around for the cascade menus +where the (?) help button gets in the way. To get the mouse over to +the cascade menu click and release mouse to activate the cascade, then +you can click on its items. Dragging with a mouse button held down will +not work (sorry!). + +" +} + } proc center_win {w} { @@ -555,6 +611,10 @@ proc active_when_connected {item} { if {[opt_match G $item]} { return 1 + } elseif {[opt_match R $item]} { + return 1 + } elseif {[opt_match S $item]} { + return 0 } elseif {[is_action $item]} { if {[opt_match R $item]} { return 1 @@ -569,10 +629,27 @@ proc active_when_connected {item} { } proc active_when_starting {item} { - global helpremote helptext + global helpremote helptext beginner_mode + + if {$beginner_mode} { + if {[opt_match G $item]} { + return 1 + } + if {$item == "display"} { + return 1 + } + if {$item == "debug_gui"} { + return 1 + } + return 0 + } if {[opt_match G $item]} { return 1 + } elseif {[opt_match S $item]} { + return 1 + } elseif {[opt_match R $item]} { + return 0 } elseif {[is_action $item]} { if {[opt_match S $item]} { return 1 @@ -1120,8 +1197,10 @@ proc insert_input_window {} { global vl_bk vl_bm vl_bb vr_bk vr_bm vr_bb append_text "\nUse these checkboxes to set the input permissions, " - append_text "or type in the \"KMB...\"\n-input string manually. " - append_text "Then press \"OK\" or \"Skip\".\n\n" + append_text "or type in the \"KMB...\"\n" + append_text "-input string manually. Then press \"OK\" or \"Skip\".\n" + append_text "(note: an empty setting means use the default behavior, " + append_text "see viewonly)\n\n" set w "$text_area.wk_f" catch {destroy $w} frame $w -bd 1 -relief ridge -cursor {top_left_arrow} @@ -1136,7 +1215,7 @@ proc insert_input_window {} { -pady 1 -command set_kmb_str -text "Mouse Motion" checkbutton $fl.bb -font $ffont -anchor w -variable vl_bb \ -pady 1 -command set_kmb_str -text "Button Clicks" - label $fr.l -pady 1 -font $ffont -text "View-only clients:" + label $fr.l -pady 1 -font $ffont -text "View-Only clients:" checkbutton $fr.bk -font $ffont -anchor w -variable vr_bk \ -pady 1 -command set_kmb_str -text "Keystrokes" checkbutton $fr.bm -font $ffont -anchor w -variable vr_bm \ @@ -1623,7 +1702,7 @@ proc tail_logfile {} { set xterm_cmd "xterm -sb -fn $ffont -geometry 80x45 -title x11vnc-logfile -e" set cmd [split $xterm_cmd] lappend cmd "tail" - lappend cmd "+1f" + lappend cmd "-3000f" lappend cmd $logfile lappend cmd "&" catch {[eval exec $cmd]} @@ -1665,14 +1744,18 @@ proc detach_from_display {} { # Menu item is an action: proc do_action {item} { - global menu_var connected_to_x11vnc + global menu_var connected_to_x11vnc beginner_mode if {[in_debug_mode]} { append_text "action: \"$item\"\n" } if {$item == "ping"} { - try_connect + if {$beginner_mode} { + try_connect_and_query_all + } else { + try_connect + } return } elseif {$item == "start"} { start_x11vnc @@ -1965,18 +2048,18 @@ proc client_dialog {client} { set input $m5 set logvo $m6 append_text "Host: $host, Port: $port, IP: $ip, Id: $cid\n" - append_text " - originally logged in as: " + append_text " - originally logged in as: " if {$logvo == "1" } { append_text "View-Only Client\n" } else { append_text "Normal Client\n" } - append_text " - currently allowed input: " + append_text " - currently allowed input: " set sk 0 set sm 0 set sb 0 if {[regexp -nocase {K} $input]} { - append_text "Keystroke" + append_text "Keystrokes" set sk 1 } if {[regexp -nocase {M} $input]} { @@ -1990,7 +2073,7 @@ proc client_dialog {client} { if {$sk || $sm} { append_text ", " } - append_text "Button-Click" + append_text "Button-Clicks" set sb 1 } if {! $sk && ! $sm && ! $sb} { @@ -2020,7 +2103,7 @@ proc client_dialog {client} { } elseif {[regexp -nocase {(disconnect|close)} $val]} { disconnect_dialog $client } else { - regsub -all -nocase {[^KMB]} $val "" + regsub -all -nocase {[^KMB]} $val "" val set item_bool(client_input) 0 push_new_value "client_input" "client_input" "$cid:$val" 0 } @@ -2119,6 +2202,10 @@ proc set_widgets {} { set case $item_case($item) set menu $menu_m($case) set entry $item_entry($item) + if {$entry < 0} { + # skip case under beginner_mode + continue + } set type [$menu type $entry] if {$type == "separator" || $type == "tearoff"} { continue @@ -2126,102 +2213,52 @@ proc set_widgets {} { if {$connected_to_x11vnc} { if {[active_when_connected $item]} { $menu entryconfigure $entry -state normal +#puts "n-1 $case / $item / $entry" } else { $menu entryconfigure $entry -state disabled +#puts "I-1 $case / $item / $entry" } } else { if {[active_when_starting $item]} { $menu entryconfigure $entry -state normal +#puts "n-2 $case / $item / $entry" } else { $menu entryconfigure $entry -state disabled +#puts "I-2 $case / $item / $entry" } } } } -proc make_widgets {} { - global template - global menu_b menu_m - global item_opts item_bool item_case item_entry menu_var unset_str - global item_cascade - global info_label info_str x11_display vnc_display - global text_area - global entry_box entry_str entry_set entry_label entry_ok entry_browse - global entry_help entry_skip - global bfont ffont - global helptext helpremote helplabel - - set label_width 80 - - set info_label .info - label $info_label -textvariable info_str -bd 2 -relief groove \ - -anchor w -width $label_width -font $ffont - pack $info_label -side top -fill x -expand 0 - - # Extract the Rows: - set row 0; - set colmax 0; - foreach line [split $template "\n"] { - if {[regexp {^Row: (.*)} $line rest]} { - set col 0 - foreach case [split $rest] { - if {$case == "" || $case == "Row:"} { - continue - } - set menu_row($case) $row - set menu_col($case) $col - set menu_count($case) 0 +proc toggle_simple_gui {} { + global beginner_mode simple_gui_created + global connected_to_x11vnc - lappend cases($col) $case; - set len [string length $case] - if {[info exists max_len($col)]} { - if {$len > $max_len($col)} { - set max_len($col) $len - } - } else { - set max_len($col) $len - } - incr col - if {$col > $colmax} { - set colmax $col - } - } - incr row; - } + if {$beginner_mode} { + append_text "\nSwitching to simple-gui mode.\n" + } else { + append_text "\nSwitching to power-user gui mode.\n" } - # Make frames for the rows and make the menu buttons. - set f ".menuframe" - frame $f - for {set c 0} {$c < $colmax} {incr c} { - set colf "$f.menuframe$c" - frame $colf - pack $colf -side left -fill y - set fbg [$colf cget -background] - foreach case $cases($c) { - set menub "$colf.menu$case"; - set menu "$colf.menu$case.menu"; - set menu_b($case) $menub - set menu_m($case) $menu - set ul 0 - foreach char [split $case ""] { - set char [string tolower $char] - if {![info exists underlined($char)]} { - set underlined($char) 1 - break - } - incr ul - } - menubutton $menub -text "$case" -underline $ul \ - -anchor w -menu $menu -background $fbg \ - -font $bfont - pack $menub -side top -fill x - menu $menu -tearoff 0 - } + set simple_gui_created 1 + make_menu_items + set_widgets + set_internal_help + if {$connected_to_x11vnc} { + query_all } - pack $f -side top -fill x + append_text "\n" +} + +proc make_menu_items {} { + global template + global menu_b menu_m menu_count + global item_opts item_bool item_case item_entry menu_var unset_str + global item_cascade + global bfont ffont beginner_mode simple_gui_created + global helptext helpremote helplabel - # Now extract the menu items: + # Extract the menu items: set case ""; foreach line [split $template "\n"] { if {[regexp {^Row:} $line]} { @@ -2229,8 +2266,19 @@ proc make_widgets {} { } if {[regexp {^[A-z]} $line]} { set case [string trim $line] + + if {$simple_gui_created} { + set i0 0 + if {$case == "Misc"} { + # kludge for simple_gui + set i0 1 + } + catch {$menu_m($case) delete $i0 end} + } + set menu_count($case) 0 continue; } + set item [string trim $line] regsub -all { *} $item " " item if {$item == ""} { @@ -2252,17 +2300,29 @@ proc make_widgets {} { } regsub {:$} $item {} item + if {$item == "-- D"} { + set beginner_sep 1 + set item "--" + } else { + set beginner_sep 0 + } + set item_opts($item) $opts set item_case($item) $case set item_bool($item) $bool set item_cascade($item) "" set item_entry($item) $menu_count($case) - if {0} { puts "ITEM: $item - $opts - $case - $bool - $menu_count($case)" } - set mvar 0 set m $menu_m($case) + if {$beginner_mode && ! $beginner_sep && ![opt_match D $item]} { + set item_entry($item) "-1" + continue; + } + + if {0} { puts "ITEM: $item\t- $opts\t- $case\t- $bool\t- $menu_count($case)" } + # Create the menu items, its variables, etc., etc. if {$item == "--"} { @@ -2282,7 +2342,8 @@ proc make_widgets {} { } elseif {$item == "current"} { # Current clients cascade - set subm $m.cascade$menu_count($case) + set subm $m.current_cascade + catch {destroy $subm} set item_cascade($item) $subm update_clients_menu "" $m add cascade -label "$item" \ @@ -2300,7 +2361,8 @@ proc make_widgets {} { # String if {[regexp -- {-C:(.*)} $item_opts($item) m0 m1]} { # Radiobutton select - set subm $m.cascade$menu_count($case) + set subm $m.radio_cascade$menu_count($case) + catch {destroy $subm} menu $subm -tearoff 0 -font $ffont foreach val [split $m1 ","] { $subm add radiobutton -label "$val" \ @@ -2321,6 +2383,13 @@ proc make_widgets {} { } set mvar 1 + } elseif {$item == "simple-gui"} { + if {! $simple_gui_created} { + $m add checkbutton -label "$item" \ + -command "toggle_simple_gui" \ + -font $ffont \ + -variable beginner_mode + } } else { # Boolean $m add checkbutton -label "$item" \ @@ -2331,12 +2400,13 @@ proc make_widgets {} { } incr menu_count($case) + if {$mvar} { set menu_var($item) $unset_str } } - # Now make the litte "(?)" help buttons + # Now make the little "(?)" help buttons foreach case [array names menu_m] { if {$case == "Help"} { continue; @@ -2376,6 +2446,90 @@ proc make_widgets {} { } } } +} + +proc make_widgets {} { + global template + global menu_b menu_m menu_count + global item_opts item_bool item_case item_entry menu_var unset_str + global item_cascade + global info_label info_str x11_display vnc_display + global text_area + global entry_box entry_str entry_set entry_label entry_ok entry_browse + global entry_help entry_skip + global bfont ffont beginner_mode + global helptext helpremote helplabel + + # Make the top label + set label_width 80 + set info_label .info + label $info_label -textvariable info_str -bd 2 -relief groove \ + -anchor w -width $label_width -font $ffont + pack $info_label -side top -fill x -expand 0 + + # Extract the Rows: + set row 0; + set colmax 0; + foreach line [split $template "\n"] { + if {[regexp {^Row: (.*)} $line rest]} { + set col 0 + foreach case [split $rest] { + if {$case == "" || $case == "Row:"} { + continue + } + set menu_row($case) $row + set menu_col($case) $col + + lappend cases($col) $case; + set len [string length $case] + if {[info exists max_len($col)]} { + if {$len > $max_len($col)} { + set max_len($col) $len + } + } else { + set max_len($col) $len + } + incr col + if {$col > $colmax} { + set colmax $col + } + } + incr row; + } + } + + # Make frames for the rows and make the menu buttons. + set f ".menuframe" + frame $f + for {set c 0} {$c < $colmax} {incr c} { + set colf "$f.menuframe$c" + frame $colf + pack $colf -side left -fill y + set fbg [$colf cget -background] + foreach case $cases($c) { + set menub "$colf.menu$case"; + set menu "$colf.menu$case.menu"; + set menu_b($case) $menub + set menu_m($case) $menu + set ul 0 + foreach char [split $case ""] { + set char [string tolower $char] + if {![info exists underlined($char)]} { + set underlined($char) 1 + break + } + incr ul + } + menubutton $menub -text "$case" -underline $ul \ + -anchor w -menu $menu -background $fbg \ + -font $bfont + pack $menub -side top -fill x + menu $menu -tearoff 0 + } + } + pack $f -side top -fill x + + make_menu_items # Make the x11 and vnc display label bar: set df .displayframe @@ -2552,9 +2706,9 @@ proc stop_watch {onoff} { proc double_check_noremote {} { set msg "\n\n" - append msg "WARNING: setting \"noremote\" will disable ALL remote control commands\n" - append msg "WARNING: (i.e. this gui will be locked out) Do you really want to do this?\n" - append msg "WARNING: If so, press \"OK\", otherwise press \"Skip\"\n" + append msg "*** WARNING: setting \"noremote\" will disable ALL remote control commands (i.e.\n" + append msg "*** WARNING: *this* gui will be locked out). Do you really want to do this?\n" + append msg "*** WARNING: If so, press \"OK\", otherwise press \"Skip\"\n" append msg "\n" bell return [warning_dialog $msg "noremote"] @@ -2829,7 +2983,7 @@ proc try_connect {} { # main: global env x11vnc_prog x11vnc_cmdline x11vnc_xdisplay x11vnc_connect; -global x11vnc_auth_file +global x11vnc_auth_file beginner_mode simple_gui_created global helpall helptext helpremote helplabel hostname; global all_settings reply_xdisplay always_update global max_text_height max_text_width @@ -2920,6 +3074,13 @@ if {[info exists env(X11VNC_AUTH_FILE)]} { set x11vnc_auth_file "" } +set simple_gui_created 0 +if {[info exists env(X11VNC_SIMPLE_GUI)]} { + set beginner_mode 1 +} else { + set beginner_mode 0 +} + set hostname [exec uname -n] #puts [exec env] diff --git a/x11vnc/tkx11vnc.h b/x11vnc/tkx11vnc.h index 1604b31..c9a2486 100644 --- a/x11vnc/tkx11vnc.h +++ b/x11vnc/tkx11vnc.h @@ -9,7 +9,7 @@ "exec wish \"$0\" \"$@\"\n" "catch {rename send {}}\n" "#\n" -"# Copyright (c) 2004 Karl J. Runge <runge@karlrunge.com>\n" +"# Copyright (c) 2004-2005 Karl J. Runge <runge@karlrunge.com>\n" "# All rights reserved.\n" "#\n" "# This is free software; you can redistribute it and/or modify\n" @@ -51,9 +51,6 @@ "# R means it is an action only valid in remote mode.\n" "# S means it is an action only valid in startup mode.\n" "# Q means it is an action worth querying after running.\n" -"# D means it is a good idea to delay a little before querying \n" -"# (i.e. perhaps it causes x11vnc to do a lot of work, new fb)\n" -"# No longer used, -sync is used instead.\n" "# P means the string can be +/- appended/deleted (string may not\n" "# be the same after the remote command)\n" "# G means gui internal item\n" @@ -72,61 +69,61 @@ "Actions\n" " =SA start\n" " =RA stop\n" -" =GA attach\n" -" =RA detach\n" +" =DGA attach\n" +" =DRA detach\n" " --\n" " =RA ping\n" " =RA update-all\n" " =GA clear-all\n" -" --\n" -" =RA stop+quit \n" -" =GA Quit \n" +" -- D\n" +" =DRA stop+quit \n" +" =DGA Quit \n" "\n" "Help\n" -" =GA gui\n" +" =DGA gui\n" " =GA all\n" "\n" "Clients\n" -" =RQA current:\n" -" =F connect:\n" -" =RQA disconnect:\n" +" =DRQA current:\n" +" =DF connect:\n" +" =DRQA disconnect:\n" " --\n" " accept:\n" " gone:\n" " vncconnect\n" -" --\n" -" http\n" +" -- D\n" +" =D http\n" " =F httpdir:\n" " httpport:\n" " enablehttpproxy\n" "\n" "Displays\n" -" display:\n" +" =D display:\n" " =F auth:\n" -" desktop:\n" -" rfbport:\n" +" =D desktop:\n" +" =D rfbport:\n" " =0 gui:\n" "\n" "Screen\n" " =DRA refresh\n" -" =DRA reset\n" +" =RA reset\n" " =DRA blacken\n" -" --\n" -" =D id:\n" -" =D sid:\n" +" -- D\n" +" id:\n" +" sid:\n" " =D scale:\n" " --\n" -" =D overlay\n" +" overlay\n" " overlay_nocursor\n" " --\n" -" =D visual:\n" +" visual:\n" " flashcmap\n" " notruecolor\n" " --\n" -" =DP blackout:\n" -" =D xinerama\n" +" =P blackout:\n" +" xinerama\n" " --\n" -" solid\n" +" =D solid\n" " solid_color:\n" " --\n" " = xrandr\n" @@ -134,8 +131,8 @@ " padgeom:\n" "\n" "Keyboard\n" -" norepeat\n" -" add_keysyms\n" +" =D norepeat\n" +" =D add_keysyms\n" " skip_keycodes:\n" " modtweak\n" " xkb\n" @@ -146,25 +143,27 @@ " clear_keys\n" "\n" "Pointer\n" -" =-C:none,arrow,X,some,most cursor:\n" +" =D-C:none,arrow,X,some,most cursor:\n" " noxfixes\n" " noalphablend\n" " --\n" " cursorpos\n" -" nocursorshape\n" +" =D nocursorshape\n" " --\n" " buttonmap:\n" " --\n" " xwarppointer\n" "\n" "Misc\n" +" =GD simple-gui\n" +" -- D\n" " =F rc:\n" " norc\n" " --\n" " nofb\n" " --\n" -" nobell\n" -" nosel\n" +" =D nobell\n" +" =D nosel\n" " noprimary\n" " --\n" " bg\n" @@ -184,29 +183,29 @@ " quiet\n" " --\n" " =GA show-start-cmd\n" -" =G debug_gui\n" +" =DG debug_gui\n" "\n" "Permissions\n" -" =RQA lock\n" -" =RQA unlock\n" +" =DRQA lock\n" +" =DRQA unlock\n" " =SQA deny_all\n" " --\n" -" =FP allow:\n" +" =DFP allow:\n" " localhost\n" " =RA allowonce:\n" -" --\n" +" -- D\n" " =RA noremote\n" " --\n" -" viewonly\n" -" shared\n" -" forever\n" +" =D viewonly\n" +" =D shared\n" +" =D forever\n" " timeout:\n" " --\n" " input:\n" " --\n" -" =SA alwaysshared\n" -" =SA nevershared\n" -" =SA dontdisconnect\n" +" =S alwaysshared\n" +" =S nevershared\n" +" =S dontdisconnect\n" " --\n" " viewpasswd:\n" " =F passwdfile:\n" @@ -218,22 +217,22 @@ " unsafe\n" "\n" "Tuning\n" -" =-C:0,1,2,3,4 pointer_mode:\n" +" =D-C:0,1,2,3,4 pointer_mode:\n" " input_skip:\n" -" nodragging\n" +" =D nodragging\n" " --\n" -" =D noshm\n" +" noshm\n" " flipbyteorder\n" " onetile\n" " --\n" " alphacut:\n" " alphafrac:\n" " alpharemove\n" -" --\n" +" -- D\n" " speeds:\n" -" wait:\n" +" =D wait:\n" " defer:\n" -" nap\n" +" =D nap\n" " screen_blank:\n" " --\n" " fs:\n" @@ -365,6 +364,12 @@ "Set the -xrandr mode value.\n" "\"\n" "\n" +" set helptext(simple-gui) \"\n" +"Toggle between menu items corresponding the most basic ones\n" +"and all possible settings. I.e. toggle between a simple gui\n" +"and one for power users.\n" +"\"\n" +"\n" " set helptext(all) $helpall\n" "\n" " set helptext(gui) \"\n" @@ -372,7 +377,7 @@ "provides an interface to each of the many x11vnc command line options and\n" "remote control commands. See \\\"Help -> all\\\" for much info about x11vnc.\n" "\n" -"Most menu items have a (?) button one can click on to get more information\n" +"All menu items have a (?) button one can click on to get more information\n" "about the option or command.\n" "\n" "There are two states tkx11vnc can be in:\n" @@ -472,6 +477,57 @@ "specified for x11vnc startup if desired.\n" "\n" "\"\n" +"\n" +"global beginner_mode\n" +"if {$beginner_mode} {\n" +" set helptext(gui) \"\n" +"tkx11vnc is a simple frontend to x11vnc. It is currently running in\n" +"\\\"ez\\\" or \\\"simple\\\" mode. For many more options run it in normal\n" +"mode buy toggling \\\"Misc -> simple_gui\\\".\n" +"\n" +"All menu items have a (?) button one can click on to get more information\n" +"about the option or command.\n" +"\n" +"GUI components: \n" +"--- ----------\n" +"\n" +"1) At the top of the gui is a info text label where information will\n" +"be posted, e.g. when traversing menu items text indicating how to get\n" +"help on the item and its current value will be displayed.\n" +"\n" +"2) Below the info label is the area where the menu buttons, Actions,\n" +"Clients, etc., are presented. If a menu item has a checkbox,\n" +"it corresponds to a boolean on/off variable. Otherwise it is\n" +"either a string variable, or an action not associated with a\n" +"variable (for the most part).\n" +"\n" +"3) Below the menu button area is a text label indicating the current x11vnc\n" +"X display being polled and the corresponding VNC display name. Both\n" +"will be \\\"(*none*)\\\" when there is no connection established.\n" +"\n" +"4) Below the x11 and vnc displays text label is a text area there scrolling\n" +"information about actions being taken and commands being run is displayed.\n" +"To scroll click in the area and use PageUp/PageDown or the arrow keys.\n" +"\n" +"5) At the bottom is an entry area. When one selects a menu item that\n" +"requires supplying a string value, the label will be set to the\n" +"parameter name and one types in the new value. Then one presses the\n" +"\\\"OK\\\" button or presses \\\"Enter\\\" to set the value. Or you can press\n" +"\\\"Skip\\\" or \\\"Escape\\\" to avoid changing the variable. Some variables\n" +"are boolean toggles (for example, \\\"Permissions -> viewonly\\\") or Radio\n" +"button selections. Selecting these menu items will not activate the\n" +"entry area but rather toggle the variable directly.\n" +"\n" +"\n" +"Cascades Bug: There is a bug not yet worked around for the cascade menus\n" +"where the (?) help button gets in the way. To get the mouse over to\n" +"the cascade menu click and release mouse to activate the cascade, then\n" +"you can click on its items. Dragging with a mouse button held down will\n" +"not work (sorry!).\n" +"\n" +"\"\n" +"}\n" +"\n" "}\n" "\n" "proc center_win {w} {\n" @@ -561,6 +617,10 @@ "\n" " if {[opt_match G $item]} {\n" " return 1\n" +" } elseif {[opt_match R $item]} {\n" +" return 1\n" +" } elseif {[opt_match S $item]} {\n" +" return 0\n" " } elseif {[is_action $item]} {\n" " if {[opt_match R $item]} {\n" " return 1\n" @@ -575,10 +635,27 @@ "}\n" "\n" "proc active_when_starting {item} {\n" -" global helpremote helptext\n" +" global helpremote helptext beginner_mode\n" +"\n" +" if {$beginner_mode} {\n" +" if {[opt_match G $item]} {\n" +" return 1\n" +" }\n" +" if {$item == \"display\"} {\n" +" return 1\n" +" }\n" +" if {$item == \"debug_gui\"} {\n" +" return 1\n" +" }\n" +" return 0\n" +" }\n" "\n" " if {[opt_match G $item]} {\n" " return 1\n" +" } elseif {[opt_match S $item]} {\n" +" return 1\n" +" } elseif {[opt_match R $item]} {\n" +" return 0\n" " } elseif {[is_action $item]} {\n" " if {[opt_match S $item]} {\n" " return 1\n" @@ -1126,8 +1203,10 @@ " global vl_bk vl_bm vl_bb vr_bk vr_bm vr_bb \n" "\n" " append_text \"\\nUse these checkboxes to set the input permissions, \"\n" -" append_text \"or type in the \\\"KMB...\\\"\\n-input string manually. \"\n" -" append_text \"Then press \\\"OK\\\" or \\\"Skip\\\".\\n\\n\"\n" +" append_text \"or type in the \\\"KMB...\\\"\\n\"\n" +" append_text \"-input string manually. Then press \\\"OK\\\" or \\\"Skip\\\".\\n\"\n" +" append_text \"(note: an empty setting means use the default behavior, \"\n" +" append_text \"see viewonly)\\n\\n\"\n" " set w \"$text_area.wk_f\"\n" " catch {destroy $w}\n" " frame $w -bd 1 -relief ridge -cursor {top_left_arrow}\n" @@ -1142,7 +1221,7 @@ " -pady 1 -command set_kmb_str -text \"Mouse Motion\" \n" " checkbutton $fl.bb -font $ffont -anchor w -variable vl_bb \\\n" " -pady 1 -command set_kmb_str -text \"Button Clicks\"\n" -" label $fr.l -pady 1 -font $ffont -text \"View-only clients:\"\n" +" label $fr.l -pady 1 -font $ffont -text \"View-Only clients:\"\n" " checkbutton $fr.bk -font $ffont -anchor w -variable vr_bk \\\n" " -pady 1 -command set_kmb_str -text \"Keystrokes\" \n" " checkbutton $fr.bm -font $ffont -anchor w -variable vr_bm \\\n" @@ -1629,7 +1708,7 @@ " set xterm_cmd \"xterm -sb -fn $ffont -geometry 80x45 -title x11vnc-logfile -e\"\n" " set cmd [split $xterm_cmd]\n" " lappend cmd \"tail\"\n" -" lappend cmd \"+1f\"\n" +" lappend cmd \"-3000f\"\n" " lappend cmd $logfile\n" " lappend cmd \"&\"\n" " catch {[eval exec $cmd]}\n" @@ -1671,14 +1750,18 @@ "\n" "# Menu item is an action:\n" "proc do_action {item} {\n" -" global menu_var connected_to_x11vnc\n" +" global menu_var connected_to_x11vnc beginner_mode\n" "\n" " if {[in_debug_mode]} {\n" " append_text \"action: \\\"$item\\\"\\n\"\n" " }\n" "\n" " if {$item == \"ping\"} {\n" -" try_connect\n" +" if {$beginner_mode} {\n" +" try_connect_and_query_all\n" +" } else {\n" +" try_connect\n" +" }\n" " return\n" " } elseif {$item == \"start\"} {\n" " start_x11vnc\n" @@ -1971,18 +2054,18 @@ " set input $m5\n" " set logvo $m6\n" " append_text \"Host: $host, Port: $port, IP: $ip, Id: $cid\\n\"\n" -" append_text \" - originally logged in as: \"\n" +" append_text \" - originally logged in as: \"\n" " if {$logvo == \"1\" } {\n" " append_text \"View-Only Client\\n\"\n" " } else {\n" " append_text \"Normal Client\\n\"\n" " }\n" -" append_text \" - currently allowed input: \"\n" +" append_text \" - currently allowed input: \"\n" " set sk 0\n" " set sm 0\n" " set sb 0\n" " if {[regexp -nocase {K} $input]} {\n" -" append_text \"Keystroke\"\n" +" append_text \"Keystrokes\"\n" " set sk 1\n" " }\n" " if {[regexp -nocase {M} $input]} {\n" @@ -1996,7 +2079,7 @@ " if {$sk || $sm} {\n" " append_text \", \"\n" " }\n" -" append_text \"Button-Click\"\n" +" append_text \"Button-Clicks\"\n" " set sb 1\n" " }\n" " if {! $sk && ! $sm && ! $sb} {\n" @@ -2026,7 +2109,7 @@ " } elseif {[regexp -nocase {(disconnect|close)} $val]} {\n" " disconnect_dialog $client\n" " } else {\n" -" regsub -all -nocase {[^KMB]} $val \"\" \n" +" regsub -all -nocase {[^KMB]} $val \"\" val\n" " set item_bool(client_input) 0\n" " push_new_value \"client_input\" \"client_input\" \"$cid:$val\" 0\n" " }\n" @@ -2125,6 +2208,10 @@ " set case $item_case($item)\n" " set menu $menu_m($case)\n" " set entry $item_entry($item)\n" +" if {$entry < 0} {\n" +" # skip case under beginner_mode \n" +" continue\n" +" }\n" " set type [$menu type $entry]\n" " if {$type == \"separator\" || $type == \"tearoff\"} {\n" " continue\n" @@ -2132,102 +2219,52 @@ " if {$connected_to_x11vnc} {\n" " if {[active_when_connected $item]} {\n" " $menu entryconfigure $entry -state normal\n" +"#puts \"n-1 $case / $item / $entry\"\n" " } else {\n" " $menu entryconfigure $entry -state disabled\n" +"#puts \"I-1 $case / $item / $entry\"\n" " }\n" " } else {\n" " if {[active_when_starting $item]} {\n" " $menu entryconfigure $entry -state normal\n" +"#puts \"n-2 $case / $item / $entry\"\n" " } else {\n" " $menu entryconfigure $entry -state disabled\n" +"#puts \"I-2 $case / $item / $entry\"\n" " }\n" " }\n" " }\n" "}\n" "\n" -"proc make_widgets {} {\n" -" global template \n" -" global menu_b menu_m\n" -" global item_opts item_bool item_case item_entry menu_var unset_str\n" -" global item_cascade\n" -" global info_label info_str x11_display vnc_display\n" -" global text_area\n" -" global entry_box entry_str entry_set entry_label entry_ok entry_browse\n" -" global entry_help entry_skip\n" -" global bfont ffont\n" -" global helptext helpremote helplabel\n" -"\n" -" set label_width 80\n" -"\n" -" set info_label .info\n" -" label $info_label -textvariable info_str -bd 2 -relief groove \\\n" -" -anchor w -width $label_width -font $ffont\n" -" pack $info_label -side top -fill x -expand 0\n" -"\n" -" # Extract the Rows:\n" -" set row 0;\n" -" set colmax 0;\n" -" foreach line [split $template \"\\n\"] {\n" -" if {[regexp {^Row: (.*)} $line rest]} {\n" -" set col 0\n" -" foreach case [split $rest] {\n" -" if {$case == \"\" || $case == \"Row:\"} {\n" -" continue\n" -" }\n" -" set menu_row($case) $row\n" -" set menu_col($case) $col\n" -" set menu_count($case) 0\n" +"proc toggle_simple_gui {} {\n" +" global beginner_mode simple_gui_created\n" +" global connected_to_x11vnc\n" "\n" -" lappend cases($col) $case;\n" -" set len [string length $case]\n" -" if {[info exists max_len($col)]} {\n" -" if {$len > $max_len($col)} {\n" -" set max_len($col) $len\n" -" }\n" -" } else {\n" -" set max_len($col) $len\n" -" }\n" -" incr col\n" -" if {$col > $colmax} {\n" -" set colmax $col\n" -" }\n" -" }\n" -" incr row;\n" -" }\n" +" if {$beginner_mode} {\n" +" append_text \"\\nSwitching to simple-gui mode.\\n\"\n" +" } else {\n" +" append_text \"\\nSwitching to power-user gui mode.\\n\"\n" " }\n" "\n" -" # Make frames for the rows and make the menu buttons.\n" -" set f \".menuframe\"\n" -" frame $f\n" -" for {set c 0} {$c < $colmax} {incr c} {\n" -" set colf \"$f.menuframe$c\"\n" -" frame $colf\n" -" pack $colf -side left -fill y\n" -" set fbg [$colf cget -background]\n" -" foreach case $cases($c) {\n" -" set menub \"$colf.menu$case\";\n" -" set menu \"$colf.menu$case.menu\";\n" -" set menu_b($case) $menub\n" -" set menu_m($case) $menu\n" -" set ul 0\n" -" foreach char [split $case \"\"] {\n" -" set char [string tolower $char]\n" -" if {![info exists underlined($char)]} {\n" -" set underlined($char) 1\n" -" break\n" -" }\n" -" incr ul\n" -" }\n" -" menubutton $menub -text \"$case\" -underline $ul \\\n" -" -anchor w -menu $menu -background $fbg \\\n" -" -font $bfont\n" -" pack $menub -side top -fill x\n" -" menu $menu -tearoff 0\n" -" }\n" +" set simple_gui_created 1\n" +" make_menu_items\n" +" set_widgets\n" +" set_internal_help\n" +" if {$connected_to_x11vnc} {\n" +" query_all\n" " }\n" -" pack $f -side top -fill x\n" +" append_text \"\\n\"\n" +"}\n" +"\n" +"proc make_menu_items {} {\n" +" global template \n" +" global menu_b menu_m menu_count\n" +" global item_opts item_bool item_case item_entry menu_var unset_str\n" +" global item_cascade\n" +" global bfont ffont beginner_mode simple_gui_created\n" +" global helptext helpremote helplabel\n" "\n" -" # Now extract the menu items:\n" +" # Extract the menu items:\n" " set case \"\";\n" " foreach line [split $template \"\\n\"] {\n" " if {[regexp {^Row:} $line]} {\n" @@ -2235,8 +2272,19 @@ " }\n" " if {[regexp {^[A-z]} $line]} {\n" " set case [string trim $line]\n" +"\n" +" if {$simple_gui_created} {\n" +" set i0 0\n" +" if {$case == \"Misc\"} {\n" +" # kludge for simple_gui\n" +" set i0 1\n" +" }\n" +" catch {$menu_m($case) delete $i0 end}\n" +" }\n" +" set menu_count($case) 0\n" " continue;\n" " }\n" +"\n" " set item [string trim $line]\n" " regsub -all { *} $item \" \" item\n" " if {$item == \"\"} {\n" @@ -2258,17 +2306,29 @@ " }\n" " regsub {:$} $item {} item\n" "\n" +" if {$item == \"-- D\"} {\n" +" set beginner_sep 1\n" +" set item \"--\"\n" +" } else {\n" +" set beginner_sep 0\n" +" }\n" +"\n" " set item_opts($item) $opts\n" " set item_case($item) $case\n" " set item_bool($item) $bool\n" " set item_cascade($item) \"\"\n" " set item_entry($item) $menu_count($case)\n" "\n" -" if {0} { puts \"ITEM: $item - $opts - $case - $bool - $menu_count($case)\" }\n" -"\n" " set mvar 0 \n" " set m $menu_m($case)\n" "\n" +" if {$beginner_mode && ! $beginner_sep && ![opt_match D $item]} {\n" +" set item_entry($item) \"-1\"\n" +" continue;\n" +" }\n" +"\n" +" if {0} { puts \"ITEM: $item\\t- $opts\\t- $case\\t- $bool\\t- $menu_count($case)\" }\n" +"\n" " # Create the menu items, its variables, etc., etc.\n" "\n" " if {$item == \"--\"} {\n" @@ -2288,7 +2348,8 @@ "\n" " } elseif {$item == \"current\"} {\n" " # Current clients cascade\n" -" set subm $m.cascade$menu_count($case)\n" +" set subm $m.current_cascade\n" +" catch {destroy $subm}\n" " set item_cascade($item) $subm\n" " update_clients_menu \"\"\n" " $m add cascade -label \"$item\" \\\n" @@ -2306,7 +2367,8 @@ " # String\n" " if {[regexp -- {-C:(.*)} $item_opts($item) m0 m1]} {\n" " # Radiobutton select\n" -" set subm $m.cascade$menu_count($case)\n" +" set subm $m.radio_cascade$menu_count($case)\n" +" catch {destroy $subm}\n" " menu $subm -tearoff 0 -font $ffont\n" " foreach val [split $m1 \",\"] {\n" " $subm add radiobutton -label \"$val\" \\\n" @@ -2327,6 +2389,13 @@ " }\n" " set mvar 1\n" "\n" +" } elseif {$item == \"simple-gui\"} {\n" +" if {! $simple_gui_created} {\n" +" $m add checkbutton -label \"$item\" \\\n" +" -command \"toggle_simple_gui\" \\\n" +" -font $ffont \\\n" +" -variable beginner_mode\n" +" }\n" " } else {\n" " # Boolean\n" " $m add checkbutton -label \"$item\" \\\n" @@ -2337,12 +2406,13 @@ " }\n" "\n" " incr menu_count($case)\n" +"\n" " if {$mvar} {\n" " set menu_var($item) $unset_str\n" " }\n" " }\n" "\n" -" # Now make the litte \"(?)\" help buttons\n" +" # Now make the little \"(?)\" help buttons\n" " foreach case [array names menu_m] {\n" " if {$case == \"Help\"} {\n" " continue;\n" @@ -2382,6 +2452,90 @@ " }\n" " }\n" " }\n" +"}\n" +"\n" +"proc make_widgets {} {\n" +" global template \n" +" global menu_b menu_m menu_count\n" +" global item_opts item_bool item_case item_entry menu_var unset_str\n" +" global item_cascade\n" +" global info_label info_str x11_display vnc_display\n" +" global text_area\n" +" global entry_box entry_str entry_set entry_label entry_ok entry_browse\n" +" global entry_help entry_skip\n" +" global bfont ffont beginner_mode\n" +" global helptext helpremote helplabel\n" +"\n" +" # Make the top label\n" +" set label_width 80\n" +" set info_label .info\n" +" label $info_label -textvariable info_str -bd 2 -relief groove \\\n" +" -anchor w -width $label_width -font $ffont\n" +" pack $info_label -side top -fill x -expand 0\n" +"\n" +" # Extract the Rows:\n" +" set row 0;\n" +" set colmax 0;\n" +" foreach line [split $template \"\\n\"] {\n" +" if {[regexp {^Row: (.*)} $line rest]} {\n" +" set col 0\n" +" foreach case [split $rest] {\n" +" if {$case == \"\" || $case == \"Row:\"} {\n" +" continue\n" +" }\n" +" set menu_row($case) $row\n" +" set menu_col($case) $col\n" +"\n" +" lappend cases($col) $case;\n" +" set len [string length $case]\n" +" if {[info exists max_len($col)]} {\n" +" if {$len > $max_len($col)} {\n" +" set max_len($col) $len\n" +" }\n" +" } else {\n" +" set max_len($col) $len\n" +" }\n" +" incr col\n" +" if {$col > $colmax} {\n" +" set colmax $col\n" +" }\n" +" }\n" +" incr row;\n" +" }\n" +" }\n" +"\n" +" # Make frames for the rows and make the menu buttons.\n" +" set f \".menuframe\"\n" +" frame $f\n" +" for {set c 0} {$c < $colmax} {incr c} {\n" +" set colf \"$f.menuframe$c\"\n" +" frame $colf\n" +" pack $colf -side left -fill y\n" +" set fbg [$colf cget -background]\n" +" foreach case $cases($c) {\n" +" set menub \"$colf.menu$case\";\n" +" set menu \"$colf.menu$case.menu\";\n" +" set menu_b($case) $menub\n" +" set menu_m($case) $menu\n" +" set ul 0\n" +" foreach char [split $case \"\"] {\n" +" set char [string tolower $char]\n" +" if {![info exists underlined($char)]} {\n" +" set underlined($char) 1\n" +" break\n" +" }\n" +" incr ul\n" +" }\n" +" menubutton $menub -text \"$case\" -underline $ul \\\n" +" -anchor w -menu $menu -background $fbg \\\n" +" -font $bfont\n" +" pack $menub -side top -fill x\n" +" menu $menu -tearoff 0\n" +" }\n" +" }\n" +" pack $f -side top -fill x\n" +"\n" +" make_menu_items\n" "\n" " # Make the x11 and vnc display label bar:\n" " set df .displayframe\n" @@ -2558,9 +2712,9 @@ "\n" "proc double_check_noremote {} {\n" " set msg \"\\n\\n\"\n" -" append msg \"WARNING: setting \\\"noremote\\\" will disable ALL remote control commands\\n\"\n" -" append msg \"WARNING: (i.e. this gui will be locked out) Do you really want to do this?\\n\"\n" -" append msg \"WARNING: If so, press \\\"OK\\\", otherwise press \\\"Skip\\\"\\n\"\n" +" append msg \"*** WARNING: setting \\\"noremote\\\" will disable ALL remote control commands (i.e.\\n\"\n" +" append msg \"*** WARNING: *this* gui will be locked out). Do you really want to do this?\\n\"\n" +" append msg \"*** WARNING: If so, press \\\"OK\\\", otherwise press \\\"Skip\\\"\\n\"\n" " append msg \"\\n\"\n" " bell\n" " return [warning_dialog $msg \"noremote\"]\n" @@ -2835,7 +2989,7 @@ "# main:\n" "\n" "global env x11vnc_prog x11vnc_cmdline x11vnc_xdisplay x11vnc_connect;\n" -"global x11vnc_auth_file\n" +"global x11vnc_auth_file beginner_mode simple_gui_created\n" "global helpall helptext helpremote helplabel hostname;\n" "global all_settings reply_xdisplay always_update\n" "global max_text_height max_text_width\n" @@ -2926,6 +3080,13 @@ " set x11vnc_auth_file \"\"\n" "}\n" "\n" +"set simple_gui_created 0\n" +"if {[info exists env(X11VNC_SIMPLE_GUI)]} {\n" +" set beginner_mode 1\n" +"} else {\n" +" set beginner_mode 0\n" +"}\n" +"\n" "\n" "set hostname [exec uname -n]\n" "#puts [exec env]\n" diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1 index fcafe51..85169be 100644 --- a/x11vnc/x11vnc.1 +++ b/x11vnc/x11vnc.1 @@ -2,7 +2,7 @@ .TH X11VNC "1" "February 2005" "x11vnc " "User Commands" .SH NAME x11vnc - allow VNC connections to real X11 displays - version: 0.7.1pre, lastmod: 2005-02-10 + version: 0.7.1pre, lastmod: 2005-02-14 .SH SYNOPSIS .B x11vnc [OPTION]... @@ -274,10 +274,13 @@ Supply a 2nd password for view-only logins. The \fB-passwd\fR .IP Specify libvncserver \fB-passwd\fR via the first line of the file \fIfilename\fR instead of via command line. -If a second non blank line exists in the file it is -taken as a view-only password (i.e. \fB-viewpasswd)\fR Note: -this is a simple plaintext passwd, see also \fB-rfbauth\fR -and \fB-storepasswd\fR below for obfuscated passwords. +If a second non blank line exists in the file it +is taken as a view-only password (i.e. \fB-viewpasswd)\fR +To supply an empty password for either field use the +string "__EMPTY__". Note: \fB-passwdfile\fR is a simple +plaintext passwd, see also \fB-rfbauth\fR and \fB-storepasswd\fR +below for obfuscated passwords. Neither should be +readable by others. .PP \fB-storepasswd\fR \fIpass\fR \fIfile\fR .IP @@ -382,44 +385,66 @@ root this option is ignored. .IP Why use this option? In general it is not needed since x11vnc is already connected to the display and -can perform its primary functions. It was added to -make some of the *external* utility commands x11vnc -occasionally runs work properly. In particular under -GNOME and KDE to implement the "\fB-solid\fR \fIcolor\fR" feature -external commands (gconftool-2 and dcop) must be run as -the user owning the desktop session. This option also -affects the userid used to run the processes for the -\fB-accept\fR and \fB-gone\fR options. It also affects the ability -to read files for options such as \fB-connect,\fR \fB-allow,\fR and -\fB-remap.\fR Note that the \fB-connect\fR file is also written to. +can perform its primary functions. The option was +added to make some of the *external* utility commands +x11vnc occasionally runs work properly. In particular +under GNOME and KDE to implement the "\fB-solid\fR \fIcolor\fR" +feature external commands (gconftool-2 and dcop) must be +run as the user owning the desktop session. Since this +option switches userid it also affects the userid used +to run the processes for the \fB-accept\fR and \fB-gone\fR options. +It also affects the ability to read files for options +such as \fB-connect,\fR \fB-allow,\fR and \fB-remap.\fR Note that the +\fB-connect\fR file is also sometimes written to. .IP So be careful with this option since in many situations its use can decrease security. .IP -The switch to a user will only take place if the display -can still be opened as that user (this is primarily to -try to guess the actual owner of the session). Example: -"\fB-users\fR \fIfred,wilma,betty\fR". Note that a malicious -user "barney" by quickly using "xhost +" when -logging in can get x11vnc to switch to user "fred". -What happens next? +The switch to a user will only take place if the +display can still be successfully opened as that user +(this is primarily to try to guess the actual owner +of the session). Example: "\fB-users\fR \fIfred,wilma,betty\fR". +Note that a malicious user "barney" by quickly using +"xhost +" when logging in may get x11vnc to switch +to user "fred". What happens next? .IP Under display managers it may be a long time before the switch succeeds (i.e. a user logs in). To make -it switch immediately regardless if the display can -be reopened or not prefix the username with the + +it switch immediately regardless if the display +can be reopened prefix the username with the + character. E.g. "\fB-users\fR \fI+bob\fR" or "\fB-users\fR \fI+nobody\fR". The latter (i.e. switching immediately to user "nobody") is probably the only use of this option -that increases security. To switch to a user *before* -connections to the display are made or any files opened -use the "=" character: "\fB-users\fR \fI=username\fR". -.IP -The special user "guess" means to examine the utmpx -database looking for a user attached to the display -number and try him/her. To limit the list of guesses, -use: "\fB-users\fR \fIguess=bob,betty\fR". Be especially careful -using this mode. +that increases security. +.IP +To immediately switch to a user *before* connections to +the display are made or any files opened use the "=" +character: "\fB-users\fR \fI=bob\fR". That user needs to be able +to open the display of course. +.IP +The special user "guess=" means to examine the utmpx +database (see +.IR who (1) +) looking for a user attached to +the display number (from DISPLAY or \fB-display\fR option) +and try him/her. To limit the list of guesses, use: +"\fB-users\fR \fIguess=bob,betty\fR". +.IP +Even more sinister is the special user "lurk=" that +means to try to guess the DISPLAY from the utmpx login +database as well. So it "lurks" waiting for anyone +to log into an X session and then connects to it. +Specify a list of users after the = to limit which +users will be tried. If the first user in the list +is something like ":0" or ":0-2" that indicates a +range of DISPLAY numbers that will be tried (regardless +of whether they are in the utmpx database) for all +users that are logged in. Examples: "\fB-users\fR \fIlurk=\fR" +and "\fB-users\fR \fIlurk=:0-1,bob,mary\fR" +.IP +Be especially careful using the "guess=" and "lurk=" +modes. They are not recommended for use on machines +with untrustworthy local users. .PP \fB-noshm\fR .IP @@ -448,20 +473,20 @@ The [color] is optional: the default color is "cyan4". For a different one specify the X color (rgb.txt name, e.g. "darkblue" or numerical "#RRGGBB"). .IP -Currently this option only works on GNOME, KDE, and -classic X (i.e. with the background image on the root -window). The "gconftool-2" and "dcop" external +Currently this option only works on GNOME, KDE, CDE, +and classic X (i.e. with the background image on the +root window). The "gconftool-2" and "dcop" external commands are run for GNOME and KDE respectively. Other desktops won't work, e.g. XFCE (send us the -corresponding commands if you find them). If x11vnc -is running as root ( +corresponding commands if you find them). If x11vnc is +running as root ( .IR inetd (1) or .IR gdm (1) -), the \fB-users\fR -option may be needed for GNOME and KDE. If x11vnc -guesses your desktop incorrectly, you can force it by -prefixing color with "gnome:", "kde:", or "root:". +), the \fB-users\fR option +may be needed for GNOME and KDE. If x11vnc guesses +your desktop incorrectly, you can force it by prefixing +color with "gnome:", "kde:", "cde:" or "root:". .PP \fB-blackout\fR \fIstring\fR .IP @@ -1008,9 +1033,11 @@ to start up both the gui and x11vnc with the gui showing up on the X display in the environment variable DISPLAY. .IP "gui-opts" can be a comma separated list of items. -Currently there are only two types of items: 1) a gui -mode and 2) the X display the gui should display on. -The gui mode can be "start", "conn", or "wait" +Currently there are these types of items: 1) a gui mode, +a 2) gui "simplicity", and 3) the X display the gui +should display on. +.IP +1) The gui mode can be "start", "conn", or "wait" "start" is the default mode above and is not required. "conn" means do not automatically start up x11vnc, but instead just try to connect to an existing x11vnc @@ -1018,15 +1045,22 @@ process. "wait" means just start the gui and nothing else (you will later instruct the gui to start x11vnc or connect to an existing one.) .IP -Note the possible confusion regarding the potentially +2) The gui simplicity is off by default (a power-user +gui with all options is presented) To start with +something less daunting supply the string "simple" +("ez" is an alias for this). Once the gui is +started you can toggle between the two with "Misc -> +simple_gui". +.IP +3) Note the possible confusion regarding the potentially two different X displays: x11vnc polls one, but you may want the gui to appear on another. For example, if you ssh in and x11vnc is not running yet you may want the gui to come back to you via your ssh redirected X display (e.g. localhost:10). .IP -Examples: "x11vnc \fB-gui",\fR "x11vnc \fB-gui\fR localhost:10", -"x11vnc \fB-gui\fR :10", "x11vnc \fB-gui\fR conn,host:10", +Examples: "x11vnc \fB-gui",\fR "x11vnc \fB-gui\fR ez" +"x11vnc \fB-gui\fR localhost:10", "x11vnc \fB-gui\fR conn,host:0" .IP If you do not specify a gui X display in "gui-opts" then the DISPLAY environment variable and \fB-display\fR diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index 89bef9d..e28e0a5 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -290,7 +290,7 @@ static int xdamage_base_event_type; #endif /* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.7.1pre lastmod: 2005-02-10"; +char lastmod[] = "0.7.1pre lastmod: 2005-02-14"; /* X display info */ @@ -977,14 +977,18 @@ char *get_shell(void) { } } -int switch_user(char *); +/* -- user.c -- */ + +int switch_user(char *, int); +int switch_user_env(uid_t, char*, char *, int); void try_to_switch_users(void); char *guess_desktop(void); -void switch_user_dummy(void) { +/* tasks for after we switch */ +void switch_user_task_dummy(void) { ; /* dummy does nothing */ } -void switch_user_solid_bg(void) { +void switch_user_task_solid_bg(void) { /* we have switched users, some things to do. */ if (use_solid_bg && client_count) { solid_bg(0); @@ -1017,7 +1021,7 @@ void check_switched_user (void) { } if (! did_dummy) { - switch_user_dummy(); + switch_user_task_dummy(); did_dummy = 1; } if (! did_solid) { @@ -1034,7 +1038,7 @@ void check_switched_user (void) { doit = 1; } if (doit) { - switch_user_solid_bg(); + switch_user_task_solid_bg(); did_solid = 1; } } @@ -1044,250 +1048,576 @@ void check_switched_user (void) { } } -int guess_user_and_switch(char *str) { +/* utilities for switching users */ +char *get_login_list(int with_display) { + char *out; #if LIBVNCSERVER_HAVE_UTMPX_H - char *q, *dstr, *d = DisplayString(dpy); - char *allowed = NULL; - int i, ret = 0, max = 300; + int i, cnt, max = 200, ut_namesize = 32; + int dpymax = 1000, sawdpy[1000]; + struct utmpx *utx; - if (strstr(str, "guess=") == str) { - char *allowed = strchr(str, '='); - allowed++; - } + /* size based on "username:999," * max */ + out = (char *) malloc(max * (ut_namesize+1+3+1) + 1); + out[0] = '\0'; - /* pick out ":N" */ - dstr = strchr(d, ':'); - if (! dstr) { - return 0; - } - q = strchr(dstr, '.'); - if (q) { - *q = '\0'; + for (i=0; i<dpymax; i++) { + sawdpy[i] = 0; } - /* look over the utmpx entries looking for this display */ setutxent(); - for (i=0; i<max; i++) { - char *str; - struct utmpx *utx = getutxent(); - + cnt = 0; + while (1) { + char *user, *line, *host, *id; + char tmp[10]; + int d = -1; + utx = getutxent(); if (! utx) { break; } - - str = lblanks(utx->ut_user); - if (*str == '\0') { - continue; /* blank user */ + if (utx->ut_type != USER_PROCESS) { + continue; } - if (allowed) { - char *p, *t = strdup(allowed); - int ok = 0; - p = strtok(t, ","); - while (p) { - if (!strcmp(p, utx->ut_user)) { - ok = 1; - } - p = strtok(NULL, ","); - } - free(t); - if (! ok) { - continue; - } + user = lblanks(utx->ut_user); + if (*user == '\0') { + continue; } - if (!strcmp(utx->ut_user, "guess")) { - continue; /* never... */ + if (strchr(user, ',')) { + continue; /* unlikely, but comma is our sep. */ } - /* try the line for leading :N */ - str = lblanks(utx->ut_line); - if (strstr(str, dstr) == str) { - int n = strlen(dstr); - if (isdigit(*(str+n))) { - continue; /* :1 vs. :10 */ - } else if (switch_user(utx->ut_user)) { - rfbLog("switched to guessed user: %s\n", - utx->ut_user); - ret = 1; - break; - } else { + line = lblanks(utx->ut_line); + host = lblanks(utx->ut_host); + id = lblanks(utx->ut_id); + + if (with_display) { + if (0 && line[0] != ':' && strcmp(line, "dtlocal")) { + /* XXX useful? */ continue; } - } - /* try the host for leading :N */ - str = lblanks(utx->ut_host); - if (strstr(str, dstr) == str) { - int n = strlen(dstr); - if (isdigit(*(str+n))) { - continue; /* :1 vs. :10 */ - } else if (switch_user(utx->ut_user)) { - rfbLog("switched to guessed user: %s\n", - utx->ut_user); - ret = 1; - break; - } else { + if (line[0] == ':') { + if (sscanf(line, ":%d", &d) != 1) { + d = -1; + } + } + if (d < 0 && host[0] == ':') { + if (sscanf(host, ":%d", &d) != 1) { + d = -1; + } + } + if (d < 0 && id[0] == ':') { + if (sscanf(id, ":%d", &d) != 1) { + d = -1; + } + } + + if (d < 0 || d >= dpymax || sawdpy[d]) { continue; } + sawdpy[d] = 1; + sprintf(tmp, ":%d", d); + } else { + /* try to eliminate repeats */ + int repeat = 0; + char *q; + + q = out; + while ((q = strstr(q, user)) != NULL) { + char *p = q + strlen(user) + strlen(":DPY"); + if (q == out || *(q-1) == ',') { + /* bounded on left. */ + if (*p == ',' || *p == '\0') { + /* bounded on right. */ + repeat = 1; + break; + } + } + q = p; + } + if (repeat) { + continue; + } + sprintf(tmp, ":DPY"); + } + + if (*out) { + strcat(out, ","); + } + strcat(out, user); + strcat(out, tmp); + + cnt++; + if (cnt >= max) { + break; } } endutxent(); - - return ret; #else - return 0; + out = strdup(""); #endif + return out; } -int switch_user(char *user) { - int force = 0, numerical = 1; - uid_t uid = 0; - char *q, *name, *home; - - if (*user == '+') { - force = 1; - user++; +char **user_list(char *user_str) { + int n, i; + char *p, **list; + + p = user_str; + n = 1; + while (*p++) { + if (*p == ',') { + n++; + } } + list = (char **) malloc((n+1)*(sizeof(char *))); - if (!strcmp(user, "guess") || strstr(user, "guess=") == user) { - return guess_user_and_switch(user); + p = strtok(user_str, ","); + i = 0; + while (p) { + list[i++] = p; + p = strtok(NULL, ","); } + list[i] = NULL; + return list; +} + +void user2uid(char *user, uid_t *uid, char **name, char **home) { + int numerical = 1; + char *q; + + *uid = (uid_t) -1; + *name = NULL; + *home = NULL; q = user; while (*q) { - if (! isdigit(*q)) { + if (! isdigit(*q++)) { numerical = 0; break; } - q++; } -#if LIBVNCSERVER_HAVE_PWD_H if (numerical) { int u = atoi(user); - struct passwd *pw; - if (u > 0) { - uid = (uid_t) u; - } else { - return 0; + if (u < 0) { + return; } - pw = getpwuid(uid); - if (pw) { - name = pw->pw_name; - home = pw->pw_dir; + *uid = (uid_t) u; + } + +#if LIBVNCSERVER_HAVE_PWD_H + if (1) { + struct passwd *pw; + if (numerical) { + pw = getpwuid(*uid); } else { - return 0; + pw = getpwnam(user); } - } else { - struct passwd *pw = getpwnam(user); if (pw) { - uid = pw->pw_uid; - name = pw->pw_name; - home = pw->pw_dir; - } else { - return 0; + *uid = pw->pw_uid; + *name = pw->pw_name; /* n.b. use immediately */ + *home = pw->pw_dir; } } -#else - return 0; #endif - if (! uid) { - return 0; - } +} - if (! force) { -#if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SYS_WAIT_H - pid_t pid, pidw; - int st; - - /* - * We fork here and try to open the display again as the - * new user. Unreadable XAUTHORITY could be a problem... - * This is not really needed since we have DISPLAY open - * but: 1) is a good indicator this user owns the session - * and 2) some activities do spawn new X apps, e.g. - * xmessage(1), etc. - */ - if ((pid = fork()) > 0) { - ; - } else if (pid == -1) { - fprintf(stderr, "could not fork\n"); - rfbLogPerror("fork"); - return 0; - } else { - Display *dpy2 = 0; - char *xauth = getenv("XAUTHORITY"); -#if LIBVNCSERVER_HAVE_SETUID - if (setuid(uid) != 0) { - exit(1); /* fail */ +int try_user_and_display(uid_t, char*); + +int lurk(char **users) { + uid_t uid; + int success = 0, dmin = -1, dmax = -1; + char *p, *logins, **u; + + if ((u = users) != NULL && *u != NULL && *(*u) == ':') { + int len; + char *tmp; + + /* extract min and max display numbers */ + tmp = *u; + if (strchr(tmp, '-')) { + if (sscanf(tmp, ":%d-%d", &dmin, &dmax) != 2) { + dmin = -1; + dmax = -1; } -#else - exit(1); -#endif - if (xauth && access(xauth, R_OK) != 0) { - *(xauth-2) = '_'; /* yow */ - } - set_env("USER", name); - set_env("LOGNAME", name); - set_env("HOME", home); - fclose(stderr); - dpy2 = XOpenDisplay(DisplayString(dpy)); - if (dpy2) { - XCloseDisplay(dpy2); - exit(0); /* success */ + } + if (dmin < 0) { + if (sscanf(tmp, ":%d", &dmin) != 1) { + dmin = -1; + dmax = -1; } else { - exit(2); /* fail */ + dmax = dmin; } } - - /* see what the child says: */ - pidw = waitpid(pid, &st, 0); - if (pidw == pid && WIFEXITED(st) && WEXITSTATUS(st) == 0) { - force = 1; + if ((dmin < 0 || dmax < 0) || dmin > dmax || dmax > 10000) { + dmin = -1; + dmax = -1; } -#else - force = 1; -#endif - } - if (force) { - char *xauth = getenv("XAUTHORITY"); + /* get user logins regardless of having a display: */ + logins = get_login_list(0); /* - * OK tricky here, we need to free the shm... otherwise - * we won't be able to delete it as the other user... + * now we append the list in users (might as well try + * them) this will probably allow weird ways of starting + * xservers to work. */ -#if !LIBVNCSERVER_HAVE_SETUID + len = strlen(logins); + u++; + while (*u != NULL) { + len += strlen(*u) + strlen(":DPY,"); + u++; + } + tmp = (char *) malloc(len+1); + strcpy(tmp, logins); + + /* now concatenate them: */ + u = users+1; + while (*u != NULL) { + char *q, chk[100]; + snprintf(chk, 100, "%s:DPY", *u); + q = strstr(tmp, chk); + if (q) { + char *p = q + strlen(chk); + + if (q == tmp || *(q-1) == ',') { + /* bounded on left. */ + if (*p == ',' || *p == '\0') { + /* bounded on right. */ + u++; + continue; + } + } + } + + if (*tmp) { + strcat(tmp, ","); + } + strcat(tmp, *u); + strcat(tmp, ":DPY"); + u++; + } + free(logins); + logins = tmp; + + } else { + logins = get_login_list(1); + } + + p = strtok(logins, ","); + while (p) { + char *user, *name, *home, dpystr[10]; + char *q, *t; + int ok = 1, dn; + + t = strdup(p); /* bob:0 */ + q = strchr(t, ':'); + if (! q) { + free(t); + break; + } + *q = '\0'; + user = t; + snprintf(dpystr, 10, ":%s", q+1); + + if (users) { + u = users; + ok = 0; + while (*u != NULL) { + if (*(*u) == ':') { + u++; + continue; + } + if (!strcmp(user, *u++)) { + ok = 1; + break; + } + } + } + + user2uid(user, &uid, &name, &home); + free(t); + + if (! uid) { + ok = 0; + } + + if (! ok) { + p = strtok(NULL, ","); + continue; + } + + for (dn = dmin; dn <= dmax; dn++) { + if (dn >= 0) { + sprintf(dpystr, ":%d", dn); + } + if (try_user_and_display(uid, dpystr)) { + if (switch_user_env(uid, name, home, 0)) { + rfbLog("lurk: now user: %s @ %s\n", + name, dpystr); + started_as_root = 2; + success = 1; + } + set_env("DISPLAY", dpystr); + break; + } + } + if (success) { + break; + } + + p = strtok(NULL, ","); + } + free(logins); + return success; +} + +void lurk_loop(char *str) { + char *tstr = NULL, **users = NULL; + + if (strstr(str, "lurk=") != str) { + exit(1); + } + rfbLog("lurking for logins using: '%s'\n", str); + if (strlen(str) > strlen("lurk=")) { + char *q = strchr(str, '='); + tstr = strdup(q+1); + users = user_list(tstr); + } + + while (1) { + if (lurk(users)) { + break; + } + sleep(3); + } + if (tstr) { + free(tstr); + } + if (users) { + free(users); + } +} + +int guess_user_and_switch(char *str, int fb_mode) { + char *dstr, *d = DisplayString(dpy); + char *p, *tstr = NULL, *allowed = NULL, *logins, **users = NULL; + int dpy1, ret = 0; + + /* pick out ":N" */ + dstr = strchr(d, ':'); + if (! dstr) { return 0; -#else - if (using_shm) { - clean_shm(0); - free_tiles(); + } + if (sscanf(dstr, ":%d", &dpy1) != 1) { + return 0; + } + if (dpy1 < 0) { + return 0; + } + + if (strstr(str, "guess=") == str && strlen(str) > strlen("guess=")) { + allowed = strchr(str, '='); + allowed++; + + tstr = strdup(allowed); + users = user_list(tstr); + } + + /* loop over the utmpx entries looking for this display */ + logins = get_login_list(1); + p = strtok(logins, ","); + while (p) { + char *user, *q, *t; + int dpy2, ok = 1; + + t = strdup(p); + q = strchr(t, ':'); + if (! q) { + free(t); + break; } - if (setuid(uid) != 0) { - if (using_shm) { - /* 2 means we did clean_shm and free_tiles */ - do_new_fb(2); + *q = '\0'; + user = t; + dpy2 = atoi(q+1); + + if (users) { + char **u = users; + ok = 0; + while (*u != NULL) { + if (!strcmp(user, *u++)) { + ok = 1; + break; + } } - return 0; } -#endif - if (using_shm) { - do_new_fb(2); + if (dpy1 != dpy2) { + ok = 0; + } + + if (! ok) { + free(t); + p = strtok(NULL, ","); + continue; + } + if (switch_user(user, fb_mode)) { + rfbLog("switched to guessed user: %s\n", user); + free(t); + ret = 1; + break; + } + + p = strtok(NULL, ","); + } + if (tstr) { + free(tstr); + } + if (users) { + free(users); + } + if (logins) { + free(logins); + } + return ret; +} + +int try_user_and_display(uid_t uid, char *dpystr) { + /* NO strtoks */ +#if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_PWD_H + pid_t pid, pidw; + char *home, *name; + int st; + struct passwd *pw; + + pw = getpwuid(uid); + if (pw) { + name = pw->pw_name; + home = pw->pw_dir; + } else { + return 0; + } + + /* + * We fork here and try to open the display again as the + * new user. Unreadable XAUTHORITY could be a problem... + * This is not really needed since we have DISPLAY open but: + * 1) is a good indicator this user owns the session and 2) + * some activities do spawn new X apps, e.g. xmessage(1), etc. + */ + if ((pid = fork()) > 0) { + ; + } else if (pid == -1) { + fprintf(stderr, "could not fork\n"); + rfbLogPerror("fork"); + return 0; + } else { + /* child */ + Display *dpy2 = 0; + int rc; + + rc = switch_user_env(uid, name, home, 0); + if (! rc) { + exit(1); } - if (xauth && access(xauth, R_OK) != 0) { - *(xauth-2) = '_'; /* yow */ + fclose(stderr); + dpy2 = XOpenDisplay(dpystr); + if (dpy2) { + XCloseDisplay(dpy2); + exit(0); /* success */ + } else { + exit(2); /* fail */ } - set_env("USER", name); - set_env("LOGNAME", name); - set_env("HOME", home); + } + + /* see what the child says: */ + pidw = waitpid(pid, &st, 0); + if (pidw == pid && WIFEXITED(st) && WEXITSTATUS(st) == 0) { return 1; + } +#endif /* LIBVNCSERVER_HAVE_FORK ... */ + return 0; +} + +int switch_user(char *user, int fb_mode) { + /* NO strtoks */ + int doit = 0; + uid_t uid = 0; + char *name, *home; + + if (*user == '+') { + doit = 1; + user++; + } + + if (strstr(user, "guess=") == user) { + return guess_user_and_switch(user, fb_mode); + } + + user2uid(user, &uid, &name, &home); + + if (uid == -1 || uid == 0) { + return 0; + } + + if (! doit && dpy) { + /* see if this display works: */ + char *dstr = DisplayString(dpy); + doit = try_user_and_display(uid, dstr); + } + + if (doit) { + int rc = switch_user_env(uid, name, home, fb_mode); + if (rc) { + started_as_root = 2; + } + return rc; } else { return 0; } } +int switch_user_env(uid_t uid, char *name, char *home, int fb_mode) { + /* NO strtoks */ + char *xauth; + int reset_fb = 0; + +#if !LIBVNCSERVER_HAVE_SETUID + return 0; +#else + /* + * OK tricky here, we need to free the shm... otherwise + * we won't be able to delete it as the other user... + */ + if (fb_mode == 1 && using_shm) { + reset_fb = 1; + clean_shm(0); + free_tiles(); + } + if (setuid(uid) != 0) { + if (reset_fb) { + /* 2 means we did clean_shm and free_tiles */ + do_new_fb(2); + } + return 0; + } +#endif + if (reset_fb) { + do_new_fb(2); + } + + xauth = getenv("XAUTHORITY"); + if (xauth && access(xauth, R_OK) != 0) { + *(xauth-2) = '_'; /* yow */ + } + + set_env("USER", name); + set_env("LOGNAME", name); + set_env("HOME", home); + return 1; +} + void try_to_switch_users(void) { static time_t last_try = 0; time_t now = time(0); @@ -1309,9 +1639,8 @@ void try_to_switch_users(void) { users = strdup(users_list); if (strstr(users, "guess=") == users) { - if (switch_user(users)) { + if (switch_user(users, 1)) { started_as_root = 2; - rfbLog("try_to_switch_users: now %s\n", p); } free(users); return; @@ -1319,7 +1648,7 @@ void try_to_switch_users(void) { p = strtok(users, ","); while (p) { - if (switch_user(p)) { + if (switch_user(p, 1)) { started_as_root = 2; rfbLog("try_to_switch_users: now %s\n", p); break; @@ -6316,6 +6645,17 @@ void check_xevents(void) { } sent_some_sel = 1; } + if (! have_clients) { + /* + * If we don't have clients we can miss the X server + * going away until a client connects. + */ + static time_t last_X_ping = 0; + if (now > last_X_ping + 5) { + last_X_ping = now; + XGetSelectionOwner(dpy, XA_PRIMARY); + } + } if (XCheckTypedEvent(dpy, MappingNotify, &xev)) { XRefreshKeyboardMapping((XMappingEvent *) &xev); @@ -11566,7 +11906,7 @@ void solid_root(char *color) { Colormap cmap; if (subwin || window != rootwin) { - rfbLog("cannot set subwin to solid color, must be root\n"); + rfbLog("cannot set subwin to solid color, must be rootwin\n"); return; } @@ -11625,7 +11965,6 @@ void solid_root(char *color) { iswa.override_redirect = True; iswa.backing_store = NotUseful; iswa.save_under = False; - iswa.background_pixmap = None; iswa.background_pixmap = ParentRelative; iwin = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth, @@ -11660,6 +11999,263 @@ void solid_root(char *color) { XDestroyWindow(dpy, expose); } +void solid_cde(char *color) { + int wsmax = 16; + static XImage *image[16]; + static Window ws_wins[16]; + static int nws = -1; + + Window expose; + Pixmap pixmap; + XGCValues gcv; + GC gc; + XSetWindowAttributes swa; + Visual visual; + unsigned long mask, pixel; + XColor cdef; + Colormap cmap; + int n; + + if (subwin || window != rootwin) { + rfbLog("cannot set subwin to solid color, must be rootwin\n"); + return; + } + + /* create the "clear" window just for generating exposures */ + swa.override_redirect = True; + swa.backing_store = NotUseful; + swa.save_under = False; + swa.background_pixmap = None; + visual.visualid = CopyFromParent; + mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap); + expose = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth, + InputOutput, &visual, mask, &swa); + + if (! color) { + /* restore the backdrop windows from the XImage snapshots */ + + for (n=0; n < nws; n++) { + Window twin; + + if (! image[n]) { + continue; + } + + twin = ws_wins[n]; + if (! twin) { + twin = rootwin; + } + if (! valid_window(twin)) { + continue; + } + + pixmap = XCreatePixmap(dpy, twin, dpy_x, dpy_y, depth); + + /* draw the image to a pixmap: */ + gcv.function = GXcopy; + gcv.plane_mask = AllPlanes; + gc = XCreateGC(dpy, twin, GCFunction|GCPlaneMask, &gcv); + + XPutImage(dpy, pixmap, gc, image[n], 0, 0, 0, 0, + dpy_x, dpy_y); + + gcv.foreground = gcv.background = BlackPixel(dpy, scr); + gc = XCreateGC(dpy, twin, GCForeground|GCBackground, + &gcv); + + rfbLog("restoring CDE ws%d snapshot to 0x%lx\n", + n, twin); + /* set the pixmap as the bg: */ + XSetWindowBackgroundPixmap(dpy, twin, pixmap); + XFreePixmap(dpy, pixmap); + XClearWindow(dpy, twin); + XFlush(dpy); + } + + /* generate exposures */ + XMapWindow(dpy, expose); + XSync(dpy, False); + XDestroyWindow(dpy, expose); + return; + } + + if (nws < 0) { + /* need to retrieve snapshots of the ws backgrounds: */ + Window iwin, wm_win; + XSetWindowAttributes iswa; + Atom dt_list, wm_info, type; + int format; + unsigned long length, after; + unsigned char *data; + unsigned int * dp; + + nws = 0; + + /* extract the hidden wm properties about backdrops: */ + + wm_info = XInternAtom(dpy, "_MOTIF_WM_INFO", True); + if (wm_info == None) { + return; + } + + XGetWindowProperty(dpy, rootwin, wm_info, 0L, 10L, False, + AnyPropertyType, &type, &format, &length, &after, &data); + + /* + * xprop -notype -root _MOTIF_WM_INFO + * _MOTIF_WM_INFO = 0x2, 0x580028 + */ + + if (length < 2 || format != 32 || after != 0) { + return; + } + + dp = (unsigned int *) data; + wm_win = (Window) *(dp+1); /* 2nd item. */ + + + dt_list = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True); + if (dt_list == None) { + return; + } + + XGetWindowProperty(dpy, wm_win, dt_list, 0L, 10L, False, + AnyPropertyType, &type, &format, &length, &after, &data); + + nws = length; + + if (nws > wsmax) { + nws = wsmax; + } + if (nws < 0) { + nws = 0; + } + + rfbLog("special CDE win: 0x%lx, %d workspaces\n", wm_win, nws); + if (nws == 0) { + return; + } + + for (n=0; n<nws; n++) { + Atom ws_atom; + char tmp[32]; + Window twin; + XWindowAttributes attr; + int i, cnt; + + image[n] = NULL; + ws_wins[n] = 0x0; + + sprintf(tmp, "_DT_WORKSPACE_INFO_ws%d", n); + ws_atom = XInternAtom(dpy, tmp, False); + if (ws_atom == None) { + continue; + } + XGetWindowProperty(dpy, wm_win, ws_atom, 0L, 100L, + False, AnyPropertyType, &type, &format, &length, + &after, &data); + + if (format != 8 || after != 0) { + continue; + } + /* + * xprop -notype -id wm_win + * _DT_WORKSPACE_INFO_ws0 = "One", "3", "0x2f2f4a", + * "0x63639c", "0x103", "1", "0x58044e" + */ + + cnt = 0; + twin = 0x0; + for (i=0; i<length; i++) { + if (*(data+i) != '\0') { + continue; + } + cnt++; /* count nulls to indicate field */ + if (cnt == 6) { + /* one past the null: */ + char *q = (char *) (data+i+1); + unsigned long in; + if (sscanf(q, "0x%lx", &in) == 1) { + twin = (Window) in; + break; + } + } + } + ws_wins[n] = twin; + + if (! twin) { + twin = rootwin; + } + + XGetWindowAttributes(dpy, twin, &attr); + if (twin != rootwin) { + if (attr.map_state != IsViewable) { + XMapWindow(dpy, twin); + } + XRaiseWindow(dpy, twin); + } + XSync(dpy, False); + + /* create image window: */ + iswa.override_redirect = True; + iswa.backing_store = NotUseful; + iswa.save_under = False; + iswa.background_pixmap = ParentRelative; + visual.visualid = CopyFromParent; + + iwin = XCreateWindow(dpy, twin, 0, 0, dpy_x, dpy_y, + 0, depth, InputOutput, &visual, mask, &iswa); + + rfbLog("snapshotting CDE backdrop ws%d 0x%lx -> " + "0x%lx ...\n", n, twin, iwin); + XMapWindow(dpy, iwin); + XSync(dpy, False); + + image[n] = XGetImage(dpy, iwin, 0, 0, dpy_x, dpy_y, + AllPlanes, ZPixmap); + XSync(dpy, False); + XDestroyWindow(dpy, iwin); + if (twin != rootwin) { + XLowerWindow(dpy, twin); + if (attr.map_state != IsViewable) { + XUnmapWindow(dpy, twin); + } + } + } + } + if (nws == 0) { + return; + } + + /* use black for low colors or failure */ + pixel = BlackPixel(dpy, scr); + if (depth > 8 || strcmp(color, solid_default)) { + cmap = DefaultColormap (dpy, scr); + if (XParseColor(dpy, cmap, color, &cdef) && + XAllocColor(dpy, cmap, &cdef)) { + pixel = cdef.pixel; + } else { + rfbLog("error parsing/allocing color: %s\n", color); + } + } + + rfbLog("setting solid backgrounds...\n"); + + for (n=0; n < nws; n++) { + Window twin = ws_wins[n]; + if (image[n] == NULL) { + continue; + } + if (! twin) { + twin = rootwin; + } + XSetWindowBackground(dpy, twin, pixel); + } + XMapWindow(dpy, expose); + XSync(dpy, False); + XDestroyWindow(dpy, expose); +} + void solid_gnome(char *color) { char get_color[] = "gconftool-2 --get " "/desktop/gnome/background/primary_color"; @@ -11793,6 +12389,13 @@ char *guess_desktop() { if (prop != None) { return "gnome"; } + prop = XInternAtom(dpy, "_MOTIF_WM_INFO", True); + if (prop != None) { + prop = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True); + if (prop != None) { + return "cde"; + } + } return "root"; } @@ -11817,6 +12420,8 @@ void solid_bg(int restore) { solid_gnome(NULL); } else if (desktop == 2) { solid_kde(NULL); + } else if (desktop == 3) { + solid_cde(NULL); } solid_on = 0; return; @@ -11836,6 +12441,8 @@ void solid_bg(int restore) { dtname = "gnome"; } else if (strstr(solid_str, "kde:") == solid_str) { dtname = "kde"; + } else if (strstr(solid_str, "cde:") == solid_str) { + dtname = "cde"; } else { dtname = "root"; } @@ -11856,6 +12463,9 @@ void solid_bg(int restore) { } else if (!strcmp(dtname, "kde")) { desktop = 2; solid_kde(color); + } else if (!strcmp(dtname, "cde")) { + desktop = 3; + solid_cde(color); } else { desktop = 0; solid_root(color); @@ -14559,7 +15169,8 @@ char gui_code[] = ""; #include "tkx11vnc.h" #endif -void run_gui(char *gui_xdisplay, int connect_to_x11vnc, pid_t parent) { +void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui, + pid_t parent) { char *x11vnc_xdisplay = NULL; char extra_path[] = ":/usr/local/bin:/usr/bin/X11:/usr/sfw/bin" ":/usr/X11R6/bin:/usr/openwin/bin:/usr/dt/bin"; @@ -14682,8 +15293,10 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, pid_t parent) { set_env("DISPLAY", gui_xdisplay); set_env("X11VNC_PROG", program_name); set_env("X11VNC_CMDLINE", program_cmdline); + if (simple_gui) { + set_env("X11VNC_SIMPLE_GUI", "1"); + } if (auth_file) { - set_env("X11VNC_AUTH_FILE", auth_file); } sprintf(cmd, "%s -", wish); @@ -14722,6 +15335,7 @@ void do_gui(char *opts) { char *gui_xdisplay = NULL; int start_x11vnc = 1; int connect_to_x11vnc = 0; + int simple_gui = 0; Display *test_dpy; if (opts) { @@ -14754,6 +15368,8 @@ void do_gui(char *opts) { } else if (!strcmp(p, "conn") || !strcmp(p, "connect")) { start_x11vnc = 0; connect_to_x11vnc = 1; + } else if (!strcmp(p, "ez") || !strcmp(p, "simple")) { + simple_gui = 1; } else { fprintf(stderr, "unrecognized gui opt: %s\n", p); } @@ -14804,7 +15420,8 @@ void do_gui(char *opts) { perror("fork"); clean_up_exit(1); } else { - run_gui(gui_xdisplay, connect_to_x11vnc, parent); + run_gui(gui_xdisplay, connect_to_x11vnc, simple_gui, + parent); exit(1); } #else @@ -14814,7 +15431,7 @@ void do_gui(char *opts) { #endif } if (!start_x11vnc) { - run_gui(gui_xdisplay, connect_to_x11vnc, 0); + run_gui(gui_xdisplay, connect_to_x11vnc, simple_gui, 0); exit(1); } if (old_xauth) { @@ -15957,10 +16574,13 @@ static void print_help(int mode) { " (full-access) password must also be supplied.\n" "-passwdfile filename Specify libvncserver -passwd via the first line of\n" " the file \"filename\" instead of via command line.\n" -" If a second non blank line exists in the file it is\n" -" taken as a view-only password (i.e. -viewpasswd) Note:\n" -" this is a simple plaintext passwd, see also -rfbauth\n" -" and -storepasswd below for obfuscated passwords.\n" +" If a second non blank line exists in the file it\n" +" is taken as a view-only password (i.e. -viewpasswd)\n" +" To supply an empty password for either field use the\n" +" string \"__EMPTY__\". Note: -passwdfile is a simple\n" +" plaintext passwd, see also -rfbauth and -storepasswd\n" +" below for obfuscated passwords. Neither should be\n" +" readable by others.\n" "-storepasswd pass file Store password \"pass\" as the VNC password in the\n" " file \"file\". Once the password is stored the\n" " program exits. Use the password via \"-rfbauth file\"\n" @@ -16039,44 +16659,64 @@ static void print_help(int mode) { " \n" " Why use this option? In general it is not needed\n" " since x11vnc is already connected to the display and\n" -" can perform its primary functions. It was added to\n" -" 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 as\n" -" the user owning the desktop session. This option also\n" -" affects the userid used to run the processes for the\n" -" -accept and -gone options. It also affects the ability\n" -" to read files for options such as -connect, -allow, and\n" -" -remap. Note that the -connect file is also written to.\n" +" can perform its primary functions. The option was\n" +" added to make some of the *external* utility commands\n" +" x11vnc occasionally runs work properly. In particular\n" +" under GNOME and KDE to implement the \"-solid color\"\n" +" feature external commands (gconftool-2 and dcop) must be\n" +" run 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" " its use can decrease security.\n" " \n" -" The switch to a user will only take place if the display\n" -" can still be opened as that user (this is primarily to\n" -" try to guess the actual owner of the session). Example:\n" -" \"-users fred,wilma,betty\". Note that a malicious\n" -" user \"barney\" by quickly using \"xhost +\" when\n" -" logging in can get x11vnc to switch to user \"fred\".\n" -" What happens next?\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" +" 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" " 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 can\n" -" be reopened or not prefix the username with the +\n" +" 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" " The latter (i.e. switching immediately to user\n" " \"nobody\") is probably the only use of this option\n" -" that increases security. To switch to a user *before*\n" -" connections to the display are made or any files opened\n" -" use the \"=\" character: \"-users =username\".\n" +" that increases security.\n" " \n" -" The special user \"guess\" means to examine the utmpx\n" -" database looking for a user attached to the display\n" -" number and try him/her. To limit the list of guesses,\n" -" use: \"-users guess=bob,betty\". Be especially careful\n" -" using this mode.\n" +" To immediately switch to a user *before* connections to\n" +" the display are made or any files opened use the \"=\"\n" +" character: \"-users =bob\". That user needs to be able\n" +" to open the display 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. If the first user in the list\n" +" is something like \":0\" or \":0-2\" that indicates a\n" +" range of DISPLAY numbers that will be tried (regardless\n" +" of whether they are in the utmpx database) for all\n" +" users that are logged in. Examples: \"-users lurk=\"\n" +" and \"-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" "-noshm Do not use the MIT-SHM extension for the polling.\n" " Remote displays can be polled this way: be careful this\n" @@ -16095,16 +16735,16 @@ static void print_help(int mode) { " For a different one specify the X color (rgb.txt name,\n" " e.g. \"darkblue\" or numerical \"#RRGGBB\").\n" "\n" -" Currently this option only works on GNOME, KDE, and\n" -" classic X (i.e. with the background image on the root\n" -" window). The \"gconftool-2\" and \"dcop\" external\n" +" Currently this option only works on GNOME, KDE, CDE,\n" +" and classic X (i.e. with the background image on the\n" +" root window). The \"gconftool-2\" and \"dcop\" external\n" " 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\n" -" is running as root (inetd(1) or gdm(1)), the -users\n" -" option may be needed for GNOME and KDE. If x11vnc\n" -" guesses your desktop incorrectly, you can force it by\n" -" prefixing color with \"gnome:\", \"kde:\", or \"root:\".\n" +" corresponding commands if you find them). If x11vnc is\n" +" running as root (inetd(1) 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" "-blackout string Black out rectangles on the screen. \"string\" is a\n" " comma separated list of WxH+X+Y type geometries for\n" " each rectangle.\n" @@ -16512,9 +17152,11 @@ static void print_help(int mode) { " up on the X display in the environment variable DISPLAY.\n" "\n" " \"gui-opts\" can be a comma separated list of items.\n" -" Currently there are only two types of items: 1) a gui\n" -" mode and 2) the X display the gui should display on.\n" -" The gui mode can be \"start\", \"conn\", or \"wait\"\n" +" Currently there are these types of items: 1) a gui mode,\n" +" a 2) gui \"simplicity\", and 3) the X display the gui\n" +" should display on.\n" +"\n" +" 1) The gui mode can be \"start\", \"conn\", or \"wait\"\n" " \"start\" is the default mode above and is not required.\n" " \"conn\" means do not automatically start up x11vnc,\n" " but instead just try to connect to an existing x11vnc\n" @@ -16522,15 +17164,22 @@ static void print_help(int mode) { " else (you will later instruct the gui to start x11vnc\n" " or connect to an existing one.)\n" "\n" -" Note the possible confusion regarding the potentially\n" +" 2) The gui simplicity is off by default (a power-user\n" +" gui with all options is presented) To start with\n" +" something less daunting supply the string \"simple\"\n" +" (\"ez\" is an alias for this). Once the gui is\n" +" started you can toggle between the two with \"Misc ->\n" +" simple_gui\".\n" +"\n" +" 3) Note the possible confusion regarding the potentially\n" " two different X displays: x11vnc polls one, but you\n" " may want the gui to appear on another. For example, if\n" " you ssh in and x11vnc is not running yet you may want\n" " the gui to come back to you via your ssh redirected X\n" " display (e.g. localhost:10).\n" "\n" -" Examples: \"x11vnc -gui\", \"x11vnc -gui localhost:10\",\n" -" \"x11vnc -gui :10\", \"x11vnc -gui conn,host:10\",\n" +" Examples: \"x11vnc -gui\", \"x11vnc -gui ez\"\n" +" \"x11vnc -gui localhost:10\", \"x11vnc -gui conn,host:0\"\n" "\n" " If you do not specify a gui X display in \"gui-opts\"\n" " then the DISPLAY environment variable and -display\n" @@ -17244,6 +17893,41 @@ static void check_rcfile(int argc, char **argv) { } } +void immediate_switch_user(int argc, char* argv[]) { + int i; + for (i=1; i < argc; i++) { + char *u; + + if (strcmp(argv[i], "-users")) { + continue; + } + if (i == argc - 1) { + fprintf(stderr, "not enough arguments for: -users\n"); + exit(1); + } + if (*(argv[i+1]) != '=') { + break; + } + + /* wants an immediate switch: =bob */ + u = strdup(argv[i+1]); + *u = '+'; + if (strstr(u, "+guess") == u) { + fprintf(stderr, "invalid user: %s\n", u+1); + exit(1); + } + if (!switch_user(u, 0)) { + fprintf(stderr, "Could not switch to user: %s\n", u+1); + exit(1); + } else { + fprintf(stderr, "Switched to user: %s\n", u+1); + started_as_root = 2; + } + free(u); + break; + } +} + int main(int argc, char* argv[]) { int i, len; @@ -17261,48 +17945,13 @@ int main(int argc, char* argv[]) { /* used to pass args we do not know about to rfbGetScreen(): */ int argc_vnc = 1; char *argv_vnc[128]; - /* if we are root limit some remote commands: */ + /* if we are root limit some remote commands, etc: */ if (!getuid() || !geteuid()) { safe_remote_only = 1; started_as_root = 1; - /* check for '-users =fred' */ - for (i=1; i < argc; i++) { - char *u; - int saved; - - if (strcmp(argv[i], "-users")) { - continue; - } - if (i == argc - 1) { - fprintf(stderr, "not enough arguments for: " - "-users\n"); - exit(1); - } - if (*(argv[i+1]) != '=') { - break; - } - u = strdup(argv[i+1]); - *u = '+'; - if (strstr(u, "+guess") == u) { - fprintf(stderr, "invalid user: %s\n", u); - exit(1); - } - /* kludge... */ - saved = using_shm; - using_shm = 0; - if (!switch_user(u)) { - fprintf(stderr, "Could not switch to user: " - "%s\n", u+1); - exit(1); - } else { - fprintf(stderr, "Switched to user: %s\n", u+1); - started_as_root = 2; - } - using_shm = saved; - free(u); - break; - } + /* check for '-users =bob' */ + immediate_switch_user(argc, argv); } argv_vnc[0] = strdup(argv[0]); @@ -17797,12 +18446,20 @@ int main(int argc, char* argv[]) { exit(1); } if (fgets(line, 1024, in) != NULL) { + char *q; int len = strlen(line); if (len > 0 && line[len-1] == '\n') { line[len-1] = '\0'; } argv_vnc[argc_vnc++] = strdup("-passwd"); - argv_vnc[argc_vnc++] = strdup(line); + if (!strcmp(line, "__EMPTY__")) { + argv_vnc[argc_vnc++] = strdup(""); + } else if ((q = strstr(line, "__ENDPASSWD__")) !=NULL) { + *q = '\0'; + argv_vnc[argc_vnc++] = strdup(line); + } else { + argv_vnc[argc_vnc++] = strdup(line); + } pw_loc = 100; /* just for pw_loc check below */ if (fgets(line, 1024, in) != NULL) { /* try to read viewonly passwd from file */ @@ -17822,7 +18479,15 @@ int main(int argc, char* argv[]) { } } if (ok) { - viewonly_passwd = strdup(line); + if (!strcmp(line, "__EMPTY__")) { + viewonly_passwd = strdup(""); + } else if ((q = strstr(line, + "__ENDPASSWD__")) != NULL) { + *q = '\0'; + viewonly_passwd = strdup(line); + } else { + viewonly_passwd = strdup(line); + } } else { rfbLog("*** not setting" " viewonly password to the 2nd" @@ -17972,6 +18637,8 @@ int main(int argc, char* argv[]) { fprintf(stderr, " vnc_conn: %d\n", vnc_connect); fprintf(stderr, " allow: %s\n", allow_list ? allow_list : "null"); + fprintf(stderr, " input: %s\n", allowed_input_str + ? allowed_input_str : "null"); fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile : "null"); fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd @@ -18093,6 +18760,14 @@ int main(int argc, char* argv[]) { use_xkb_modtweak = 0; #endif + if (users_list && strstr(users_list, "lurk=")) { + if (use_dpy) { + rfbLog("warning: -display does not make sense in " + "\"lurk=\" mode...\n"); + } + lurk_loop(users_list); + } + if (use_dpy) { dpy = XOpenDisplay(use_dpy); } else if ( (use_dpy = getenv("DISPLAY")) ) { |