summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrunge <runge>2005-02-11 04:14:20 +0000
committerrunge <runge>2005-02-11 04:14:20 +0000
commit86ccf267b18b30a3c0d4f5b96b6738f3c2b17e2b (patch)
tree519106dc628376f40e8cf065742cda1396fe8084
parent5b18d40136b20695b4048a69fcfbd0631ad7bb81 (diff)
downloadlibtdevnc-86ccf267.tar.gz
libtdevnc-86ccf267.zip
x11vnc -input to fine tune allow user input. per-client settings -R
-rw-r--r--ChangeLog4
-rw-r--r--x11vnc/ChangeLog5
-rw-r--r--x11vnc/README4
-rwxr-xr-xx11vnc/tkx11vnc369
-rw-r--r--x11vnc/tkx11vnc.h369
-rw-r--r--x11vnc/x11vnc.154
-rw-r--r--x11vnc/x11vnc.c614
7 files changed, 1243 insertions, 176 deletions
diff --git a/ChangeLog b/ChangeLog
index 9f91328..7d48f27 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+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.
+
2005-02-09 Karl Runge <runge@karlrunge.com>
* x11vnc: -users, fix -solid on gnome and kde.
* configure.ac: add pwd.h, wait.h, and utmpx.h checks.
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index cc93296..a08556d 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,8 @@
+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.
+ * fix bug in get_remote_port, add ip2host for client info.
+
2005-02-09 Karl Runge <runge@karlrunge.com>
* Add -users switch user mechanism and related utilities.
* fix -solid for gnome and kde.
diff --git a/x11vnc/README b/x11vnc/README
index 392af22..41f1db0 100644
--- a/x11vnc/README
+++ b/x11vnc/README
@@ -1,5 +1,5 @@
-x11vnc README file Date: Wed Feb 9 00:21:28 EST 2005
+x11vnc README file Date: Thu Feb 10 23:33:03 EST 2005
The following information is taken from these URLs:
@@ -594,6 +594,8 @@ ls -l ./x11vnc/x11vnc
Please feel free to [45]contact me if you have any questions,
problems, or comments about x11vnc, etc.
+
+ [PayPal]
_________________________________________________________________
x11vnc FAQ:
diff --git a/x11vnc/tkx11vnc b/x11vnc/tkx11vnc
index 875ddd2..3ef212f 100755
--- a/x11vnc/tkx11vnc
+++ b/x11vnc/tkx11vnc
@@ -196,6 +196,8 @@ Permissions
forever
timeout:
--
+ input:
+ --
=SA alwaysshared
=SA nevershared
=SA dontdisconnect
@@ -279,6 +281,11 @@ Check if x11vnc still responds to \"ping\" remote command.
set helptext(update-all) "
Query the x11vnc server for the current values of all variables.
Populate the values into the gui's database.
+
+Normally the gui will refresh this info every time it interacts
+with the x11vnc server, so one doesn't need to use this action
+very often (unless something else is changing the state of the
+x11vnc server, or new clients have connected, etc).
"
set helptext(clear-all) "
@@ -321,10 +328,29 @@ Terminate the tkx11vnc gui. Any x11vnc servers will be left running.
set helptext(current) "
Shows a menu of currently connected VNC clients on the x11vnc server.
-Allows you to find more information about them or disconnect them.
+Allows you to find more information about them, change their input
+permissions, or disconnect them.
+
You will be prompted to confirm any disconnections.
"
+ set helptext(client) "
+After selecting a VNC client from the \"Clients -> current\" menu,
+you will be presented with a dialog that shows the information
+about the VNC client.
+
+You can chose to disconnect the client by clicking on the
+\"Disconnect\" checkbox and pressing \"OK\". There will be a
+confirmation dialog to doublecheck.
+
+Alternatively, you can fine tune the VNC client's input permissions
+by selecting any of the Keystrokes, Mouse Motion, or Button Clicks
+checkboxes and pressing \"OK\". This is like the \"-input\" option
+but on a per-client basis.
+
+To not change any aspects of the VNC client press \"Skip\".
+"
+
set helptext(solid_color) "
Set the -solid color value.
"
@@ -470,12 +496,18 @@ proc textheight {text} {
return $count
}
+proc set_name {name} {
+ wm title . "$name"
+ wm iconname . "$name"
+}
+
proc make_toplevel {w {title ""}} {
catch {destroy $w}
toplevel $w;
bind $w <Escape> "destroy $w"
if {$title != ""} {
- wm title $w $title
+ wm title $w $title
+ wm iconname $w $title
}
}
@@ -1054,6 +1086,195 @@ proc push_new_value {item name new {query 1}} {
}
}
+proc set_kmb_str {} {
+ global vl_bk vl_bm vl_bb vr_bk vr_bm vr_bb
+
+ set str ""
+ if {$vl_bk} {
+ append str "K"
+ }
+ if {$vl_bm} {
+ append str "M"
+ }
+ if {$vl_bb} {
+ append str "B"
+ }
+ if {$vr_bk || $vr_bm || $vr_bb} {
+ append str ","
+ }
+ if {$vr_bk} {
+ append str "K"
+ }
+ if {$vr_bm} {
+ append str "M"
+ }
+ if {$vr_bb} {
+ append str "B"
+ }
+ entry_insert $str
+}
+
+proc insert_input_window {} {
+ global text_area cleanup_window
+ global ffont menu_var
+ 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"
+ set w "$text_area.wk_f"
+ catch {destroy $w}
+ frame $w -bd 1 -relief ridge -cursor {top_left_arrow}
+ set fl $w.fl
+ frame $fl
+ set fr $w.fr
+ frame $fr
+ label $fl.l -font $ffont -text "Normal clients: "
+ checkbutton $fl.bk -pady 1 -font $ffont -anchor w -variable vl_bk \
+ -pady 1 -command set_kmb_str -text "Keystrokes"
+ checkbutton $fl.bm -font $ffont -anchor w -variable vl_bm \
+ -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:"
+ 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 \
+ -pady 1 -command set_kmb_str -text "Mouse Motion"
+ checkbutton $fr.bb -font $ffont -anchor w -variable vr_bb \
+ -pady 1 -command set_kmb_str -text "Button Clicks"
+
+ if {[info exists menu_var(input)]} {
+ set input_str $menu_var(input)
+ } else {
+ set input_str ""
+ }
+
+ if {[regexp {(.*),(.*)} $input_str match normal viewonly]} {
+ ;
+ } else {
+ set normal $input_str
+ set viewonly ""
+ }
+ set vl_bk 0
+ set vl_bm 0
+ set vl_bb 0
+ set vr_bk 0
+ set vr_bm 0
+ set vr_bb 0
+
+ if {[regexp -nocase {K} $normal]} {
+ set vl_bk 1
+ }
+ if {[regexp -nocase {M} $normal]} {
+ set vl_bm 1
+ }
+ if {[regexp -nocase {B} $normal]} {
+ set vl_bb 1
+ }
+ if {[regexp -nocase {K} $viewonly]} {
+ set vr_bk 1
+ }
+ if {[regexp -nocase {M} $viewonly]} {
+ set vr_bm 1
+ }
+ if {[regexp -nocase {B} $viewonly]} {
+ set vr_bb 1
+ }
+
+ pack $fl.l $fl.bk $fl.bm $fl.bb -side top -fill x
+ pack $fr.l $fr.bk $fr.bm $fr.bb -side top -fill x
+ pack $fl $fr -side left
+ update
+ update idletasks
+ $text_area window create end -window $w
+ $text_area see end
+ $text_area insert end "\n"
+# $text_area insert end "\n\n\n\n\n\n\n\n\n"
+
+ set cleanup_window $w
+}
+
+proc set_ca_str {w} {
+ global ca_bk ca_bm ca_bb ca_bk ca_di
+
+ if {$ca_di} {
+ entry_insert "disconnect"
+ $w.bk configure -state disabled
+ $w.bm configure -state disabled
+ $w.bb configure -state disabled
+ return
+ }
+
+ $w.bk configure -state normal
+ $w.bm configure -state normal
+ $w.bb configure -state normal
+
+ set str ""
+ if {$ca_bk} {
+ append str "K"
+ }
+ if {$ca_bm} {
+ append str "M"
+ }
+ if {$ca_bb} {
+ append str "B"
+ }
+ entry_insert $str
+}
+
+proc insert_client_action_window {input} {
+ global text_area cleanup_window
+ global ffont menu_var
+ global ca_bk ca_bm ca_bb ca_bk ca_di
+
+ append_text "\nUse these checkboxes to set the input permissions "
+ append_text "for this client\n-or- whether to disconnect it instead. "
+ append_text "Then press \"OK\" or \"Skip\".\n\n"
+ set w "$text_area.ca_f"
+ catch {destroy $w}
+ frame $w -bd 1 -relief ridge -cursor {top_left_arrow}
+ checkbutton $w.di -pady 1 -font $ffont -anchor w -variable ca_di \
+ -pady 1 -command "set_ca_str $w" -text "Disconnect "
+ checkbutton $w.bk -font $ffont -anchor w -variable ca_bk \
+ -pady 1 -command "set_ca_str $w" -text "Keystrokes"
+ checkbutton $w.bm -font $ffont -anchor w -variable ca_bm \
+ -pady 1 -command "set_ca_str $w" -text "Mouse Motion"
+ checkbutton $w.bb -font $ffont -anchor w -variable ca_bb \
+ -pady 1 -command "set_ca_str $w" -text "Button Clicks"
+
+ set ca_di 0
+ set ca_bk 0
+ set ca_bm 0
+ set ca_bb 0
+
+ if {[regexp -nocase {K} $input]} {
+ set ca_bk 1
+ }
+ if {[regexp -nocase {M} $input]} {
+ set ca_bm 1
+ }
+ if {[regexp -nocase {B} $input]} {
+ set ca_bb 1
+ }
+
+ pack $w.di $w.bk $w.bm $w.bb -side left
+ update
+ update idletasks
+ $text_area window create end -window $w
+ $text_area see end
+ $text_area insert end "\n"
+
+ set cleanup_window $w
+}
+
+proc cleanup_text_window {} {
+ global cleanup_window
+ if {[info exists cleanup_window]} {
+ catch {destroy $cleanup_window}
+ }
+}
+
# For updating a string variable. Also used for simple OK/Skip dialogs
# with entry = 0.
proc entry_dialog {item {entry 1}} {
@@ -1084,6 +1305,13 @@ proc entry_dialog {item {entry 1}} {
entry_disable box
}
+ set clean_text_window 0;
+
+ if {$item == "input"} {
+ insert_input_window
+ set clean_text_window 1
+ }
+
update
# wait for user reply:
@@ -1101,6 +1329,11 @@ proc entry_dialog {item {entry 1}} {
entry_delete
entry_disable
menus_enable
+
+ if {$clean_text_window} {
+ cleanup_text_window;
+ }
+
update
if {! $entry} {
@@ -1205,7 +1438,8 @@ proc see_if_ok {query item expected} {
} elseif {[regexp {:[0-9]\.[0-9]} $expected]} {
append_text "\t($msg)\n"
return 1
- } elseif {$item == "connect" || $item == "disconnect"} {
+ } elseif {$item == "connect" || $item == "disconnect"
+ || $item == "client" || $item == "client_input"} {
append_text "\t($msg)\n"
return 1
} else {
@@ -1259,7 +1493,7 @@ proc clear_all {} {
continue
}
if {[info exists menu_var($item)]} {
- if [is_action $item] {
+ if {[is_action $item]} {
set menu_var($item) ""
} elseif {[value_is_bool $item]} {
set menu_var($item) 0
@@ -1494,7 +1728,7 @@ proc do_action {item} {
push_new_value $item $name $new 0
set_connected no
- } elseif [opt_match Q $item] {
+ } elseif {[opt_match Q $item]} {
push_new_value $item $name $new 1
} else {
push_new_value $item $name $new 0
@@ -1660,7 +1894,7 @@ proc split_query {query} {
proc set_x11_display {name} {
global x11_display
set x11_display "x11vnc X display: $name"
- wm title . "tkx11vnc - $name"
+ set_name "tkx11vnc - $name"
}
proc set_vnc_display {name} {
global vnc_display
@@ -1672,7 +1906,7 @@ proc set_vnc_url {name} {
}
proc no_x11_display {} {
set_x11_display "(*none*)"
- wm title . "tkx11vnc"
+ set_name "tkx11vnc"
}
proc no_vnc_display {} {
set_vnc_display "(*none*)"
@@ -1713,20 +1947,99 @@ proc fetch_displays {} {
}
}
+proc client_dialog {client} {
+ set cid ""
+ set host ""
+ set ip ""
+ global menu_var text_area cleanup_window item_bool
+
+ append_text "\nClient info string: $client\n\n"
+ if {[regexp {^(.*):(.*):(.*):(.*):(.*):(.*)$} \
+ $client m0 m1 m2 m3 m4 m5 m6]} {
+ # id:ip:port:hostname:input:loginvo
+ set cid $m1
+ set ip $m2
+ set port $m3
+ set host $m4
+ regsub {\..*$} $host "" host
+ set input $m5
+ set logvo $m6
+ append_text "Host: $host, Port: $port, IP: $ip, Id: $cid\n"
+ 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: "
+ set sk 0
+ set sm 0
+ set sb 0
+ if {[regexp -nocase {K} $input]} {
+ append_text "Keystroke"
+ set sk 1
+ }
+ if {[regexp -nocase {M} $input]} {
+ if {$sk} {
+ append_text ", "
+ }
+ append_text "Mouse-Motion"
+ set sm 1
+ }
+ if {[regexp -nocase {B} $input]} {
+ if {$sk || $sm} {
+ append_text ", "
+ }
+ append_text "Button-Click"
+ set sb 1
+ }
+ if {! $sk && ! $sm && ! $sb} {
+ append_text "None"
+ }
+ append_text "\n"
+ }
+ if {$cid == ""} {
+ append_text "Invalid client info string: $client\n"
+ return
+ }
+
+ regsub -all {_} $input "" input
+ set menu_var(client) "$input"
+ set item_bool(client) 0
+
+ insert_client_action_window $input
+ set rc [entry_dialog client 1]
+
+ cleanup_text_window
+
+ set val $menu_var(client)
+ #puts "rc: $rc val: $val"
+
+ if {! $rc} {
+ return;
+ } elseif {[regexp -nocase {(disconnect|close)} $val]} {
+ disconnect_dialog $client
+ } else {
+ regsub -all -nocase {[^KMB]} $val ""
+ set item_bool(client_input) 0
+ push_new_value "client_input" "client_input" "$cid:$val" 0
+ }
+}
+
proc disconnect_dialog {client} {
set cid ""
set host ""
set msg "\n"
append msg "*** Client info string: $client\n"
- if {[regexp {^(.*):(.*)/(.*)-(.*)$} $client m0 m1 m2 m3 m4]} {
- if {$m4 == "ro"} {
- set view "(viewonly)"
- } else {
- set view "(interactive)"
- }
- set host $m1
- set cid $m3
- append msg "*** Host: $m1, Port: $m2 Id: $m3 $view\n"
+ if {[regexp {^(.*):(.*):(.*):(.*):(.*):(.*)$} $client m0 m1 m2 m3 m4 m5 m6]} {
+ set cid $m1
+ set ip $m2
+ set port $m3
+ set host $m4
+ regsub {\..*$} $host "" host
+ set input $m5
+ set logvo $m6
+ append_text "Host: $host, Port: $port, IP: $ip, Id: $cid\n"
}
if {$cid == ""} {
append_text "Invalid client info string: $client\n"
@@ -1734,7 +2047,7 @@ proc disconnect_dialog {client} {
}
append msg "*** To *DISCONNECT* this client press \"OK\", otherwise press \"Skip\"\n"
bell
- if [warning_dialog $msg "current"] {
+ if {[warning_dialog $msg "current"]} {
push_new_value "disconnect" "disconnect" $cid 1
} else {
append_text "disconnect cancelled.\n"
@@ -1756,7 +2069,7 @@ proc update_clients_and_repost {} {
continue
}
set name [$casc entrycget $i -label]
- if {[regexp {^#} $name]} {
+ if {[regexp {^num-clients} $name]} {
continue
}
if {[regexp {^refresh-list} $name]} {
@@ -1783,12 +2096,20 @@ proc update_clients_menu {list} {
$subm add separator
set count 0
foreach client [split $list ","] {
- regsub {:[0-9][0-9]*/} $client {/} lab
- $subm add command -label "$client" \
- -command "disconnect_dialog $client"
+ if {[regexp {^(.*):(.*):(.*):(.*):(.*):(.*)$} \
+ $client m0 m1 m2 m3 m4 m5 m6]} {
+ # id:ip:port:hostname:input:loginvo
+ set host $m4
+ regsub {\..*$} $host "" host
+ set clabel "$host $m1"
+ } else {
+ regsub {:.*$} $client "" clabel
+ }
+ $subm add command -label "$clabel" \
+ -command "client_dialog $client"
incr count
}
- $subm entryconfigure 0 -label "#clients: $count"
+ $subm entryconfigure 0 -label "num-clients: $count"
}
proc set_widgets {} {
@@ -2076,7 +2397,7 @@ proc make_widgets {} {
pack $df -side top -fill x
# text area
- text .text -height 11 -relief ridge -font $ffont
+ text .text -height 12 -relief ridge -font $ffont
set text_area .text
pack .text -side top -fill both -expand 1
@@ -2622,7 +2943,7 @@ tweak_both screen_blank sb
set_template
-wm title . "tkx11vnc"
+set_name "tkx11vnc"
make_widgets;
menu_bindings;
diff --git a/x11vnc/tkx11vnc.h b/x11vnc/tkx11vnc.h
index cc60b8b..1604b31 100644
--- a/x11vnc/tkx11vnc.h
+++ b/x11vnc/tkx11vnc.h
@@ -202,6 +202,8 @@
" forever\n"
" timeout:\n"
" --\n"
+" input:\n"
+" --\n"
" =SA alwaysshared\n"
" =SA nevershared\n"
" =SA dontdisconnect\n"
@@ -285,6 +287,11 @@
" set helptext(update-all) \"\n"
"Query the x11vnc server for the current values of all variables.\n"
"Populate the values into the gui's database.\n"
+"\n"
+"Normally the gui will refresh this info every time it interacts\n"
+"with the x11vnc server, so one doesn't need to use this action\n"
+"very often (unless something else is changing the state of the\n"
+"x11vnc server, or new clients have connected, etc).\n"
"\"\n"
"\n"
" set helptext(clear-all) \"\n"
@@ -327,10 +334,29 @@
" set helptext(current) \"\n"
"Shows a menu of currently connected VNC clients on the x11vnc server.\n"
"\n"
-"Allows you to find more information about them or disconnect them.\n"
+"Allows you to find more information about them, change their input\n"
+"permissions, or disconnect them.\n"
+"\n"
"You will be prompted to confirm any disconnections.\n"
"\"\n"
"\n"
+" set helptext(client) \"\n"
+"After selecting a VNC client from the \\\"Clients -> current\\\" menu,\n"
+"you will be presented with a dialog that shows the information\n"
+"about the VNC client.\n"
+"\n"
+"You can chose to disconnect the client by clicking on the \n"
+"\\\"Disconnect\\\" checkbox and pressing \\\"OK\\\". There will be a\n"
+"confirmation dialog to doublecheck.\n"
+"\n"
+"Alternatively, you can fine tune the VNC client's input permissions\n"
+"by selecting any of the Keystrokes, Mouse Motion, or Button Clicks\n"
+"checkboxes and pressing \\\"OK\\\". This is like the \\\"-input\\\" option\n"
+"but on a per-client basis.\n"
+"\n"
+"To not change any aspects of the VNC client press \\\"Skip\\\".\n"
+"\"\n"
+"\n"
" set helptext(solid_color) \"\n"
"Set the -solid color value.\n"
"\"\n"
@@ -476,12 +502,18 @@
" return $count\n"
"}\n"
"\n"
+"proc set_name {name} {\n"
+" wm title . \"$name\"\n"
+" wm iconname . \"$name\"\n"
+"}\n"
+"\n"
"proc make_toplevel {w {title \"\"}} {\n"
" catch {destroy $w}\n"
" toplevel $w;\n"
" bind $w <Escape> \"destroy $w\"\n"
" if {$title != \"\"} {\n"
-" wm title $w $title\n"
+" wm title $w $title\n"
+" wm iconname $w $title\n"
" }\n"
"}\n"
"\n"
@@ -1060,6 +1092,195 @@
" }\n"
"}\n"
"\n"
+"proc set_kmb_str {} {\n"
+" global vl_bk vl_bm vl_bb vr_bk vr_bm vr_bb \n"
+"\n"
+" set str \"\"\n"
+" if {$vl_bk} {\n"
+" append str \"K\"\n"
+" }\n"
+" if {$vl_bm} {\n"
+" append str \"M\"\n"
+" }\n"
+" if {$vl_bb} {\n"
+" append str \"B\"\n"
+" }\n"
+" if {$vr_bk || $vr_bm || $vr_bb} {\n"
+" append str \",\"\n"
+" }\n"
+" if {$vr_bk} {\n"
+" append str \"K\"\n"
+" }\n"
+" if {$vr_bm} {\n"
+" append str \"M\"\n"
+" }\n"
+" if {$vr_bb} {\n"
+" append str \"B\"\n"
+" }\n"
+" entry_insert $str\n"
+"}\n"
+"\n"
+"proc insert_input_window {} {\n"
+" global text_area cleanup_window\n"
+" global ffont menu_var\n"
+" 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"
+" set w \"$text_area.wk_f\"\n"
+" catch {destroy $w}\n"
+" frame $w -bd 1 -relief ridge -cursor {top_left_arrow}\n"
+" set fl $w.fl\n"
+" frame $fl\n"
+" set fr $w.fr\n"
+" frame $fr\n"
+" label $fl.l -font $ffont -text \"Normal clients: \"\n"
+" checkbutton $fl.bk -pady 1 -font $ffont -anchor w -variable vl_bk \\\n"
+" -pady 1 -command set_kmb_str -text \"Keystrokes\" \n"
+" checkbutton $fl.bm -font $ffont -anchor w -variable vl_bm \\\n"
+" -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"
+" 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"
+" -pady 1 -command set_kmb_str -text \"Mouse Motion\" \n"
+" checkbutton $fr.bb -font $ffont -anchor w -variable vr_bb \\\n"
+" -pady 1 -command set_kmb_str -text \"Button Clicks\"\n"
+"\n"
+" if {[info exists menu_var(input)]} {\n"
+" set input_str $menu_var(input)\n"
+" } else {\n"
+" set input_str \"\"\n"
+" }\n"
+"\n"
+" if {[regexp {(.*),(.*)} $input_str match normal viewonly]} {\n"
+" ;\n"
+" } else {\n"
+" set normal $input_str\n"
+" set viewonly \"\"\n"
+" }\n"
+" set vl_bk 0\n"
+" set vl_bm 0\n"
+" set vl_bb 0\n"
+" set vr_bk 0\n"
+" set vr_bm 0\n"
+" set vr_bb 0\n"
+"\n"
+" if {[regexp -nocase {K} $normal]} {\n"
+" set vl_bk 1\n"
+" }\n"
+" if {[regexp -nocase {M} $normal]} {\n"
+" set vl_bm 1\n"
+" }\n"
+" if {[regexp -nocase {B} $normal]} {\n"
+" set vl_bb 1\n"
+" }\n"
+" if {[regexp -nocase {K} $viewonly]} {\n"
+" set vr_bk 1\n"
+" }\n"
+" if {[regexp -nocase {M} $viewonly]} {\n"
+" set vr_bm 1\n"
+" }\n"
+" if {[regexp -nocase {B} $viewonly]} {\n"
+" set vr_bb 1\n"
+" }\n"
+"\n"
+" pack $fl.l $fl.bk $fl.bm $fl.bb -side top -fill x\n"
+" pack $fr.l $fr.bk $fr.bm $fr.bb -side top -fill x\n"
+" pack $fl $fr -side left\n"
+" update\n"
+" update idletasks\n"
+" $text_area window create end -window $w\n"
+" $text_area see end\n"
+" $text_area insert end \"\\n\"\n"
+"# $text_area insert end \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\"\n"
+"\n"
+" set cleanup_window $w\n"
+"}\n"
+"\n"
+"proc set_ca_str {w} {\n"
+" global ca_bk ca_bm ca_bb ca_bk ca_di\n"
+"\n"
+" if {$ca_di} {\n"
+" entry_insert \"disconnect\"\n"
+" $w.bk configure -state disabled\n"
+" $w.bm configure -state disabled\n"
+" $w.bb configure -state disabled\n"
+" return\n"
+" }\n"
+"\n"
+" $w.bk configure -state normal\n"
+" $w.bm configure -state normal\n"
+" $w.bb configure -state normal\n"
+"\n"
+" set str \"\"\n"
+" if {$ca_bk} {\n"
+" append str \"K\"\n"
+" }\n"
+" if {$ca_bm} {\n"
+" append str \"M\"\n"
+" }\n"
+" if {$ca_bb} {\n"
+" append str \"B\"\n"
+" }\n"
+" entry_insert $str\n"
+"}\n"
+"\n"
+"proc insert_client_action_window {input} {\n"
+" global text_area cleanup_window\n"
+" global ffont menu_var\n"
+" global ca_bk ca_bm ca_bb ca_bk ca_di\n"
+"\n"
+" append_text \"\\nUse these checkboxes to set the input permissions \"\n"
+" append_text \"for this client\\n-or- whether to disconnect it instead. \"\n"
+" append_text \"Then press \\\"OK\\\" or \\\"Skip\\\".\\n\\n\"\n"
+" set w \"$text_area.ca_f\"\n"
+" catch {destroy $w}\n"
+" frame $w -bd 1 -relief ridge -cursor {top_left_arrow}\n"
+" checkbutton $w.di -pady 1 -font $ffont -anchor w -variable ca_di \\\n"
+" -pady 1 -command \"set_ca_str $w\" -text \"Disconnect \" \n"
+" checkbutton $w.bk -font $ffont -anchor w -variable ca_bk \\\n"
+" -pady 1 -command \"set_ca_str $w\" -text \"Keystrokes\" \n"
+" checkbutton $w.bm -font $ffont -anchor w -variable ca_bm \\\n"
+" -pady 1 -command \"set_ca_str $w\" -text \"Mouse Motion\" \n"
+" checkbutton $w.bb -font $ffont -anchor w -variable ca_bb \\\n"
+" -pady 1 -command \"set_ca_str $w\" -text \"Button Clicks\"\n"
+"\n"
+" set ca_di 0\n"
+" set ca_bk 0\n"
+" set ca_bm 0\n"
+" set ca_bb 0\n"
+"\n"
+" if {[regexp -nocase {K} $input]} {\n"
+" set ca_bk 1\n"
+" }\n"
+" if {[regexp -nocase {M} $input]} {\n"
+" set ca_bm 1\n"
+" }\n"
+" if {[regexp -nocase {B} $input]} {\n"
+" set ca_bb 1\n"
+" }\n"
+"\n"
+" pack $w.di $w.bk $w.bm $w.bb -side left\n"
+" update\n"
+" update idletasks\n"
+" $text_area window create end -window $w\n"
+" $text_area see end\n"
+" $text_area insert end \"\\n\"\n"
+"\n"
+" set cleanup_window $w\n"
+"}\n"
+"\n"
+"proc cleanup_text_window {} {\n"
+" global cleanup_window\n"
+" if {[info exists cleanup_window]} {\n"
+" catch {destroy $cleanup_window}\n"
+" }\n"
+"}\n"
+"\n"
"# For updating a string variable. Also used for simple OK/Skip dialogs\n"
"# with entry = 0.\n"
"proc entry_dialog {item {entry 1}} {\n"
@@ -1090,6 +1311,13 @@
" entry_disable box\n"
" }\n"
"\n"
+" set clean_text_window 0;\n"
+"\n"
+" if {$item == \"input\"} {\n"
+" insert_input_window\n"
+" set clean_text_window 1\n"
+" }\n"
+"\n"
" update\n"
"\n"
" # wait for user reply:\n"
@@ -1107,6 +1335,11 @@
" entry_delete\n"
" entry_disable\n"
" menus_enable\n"
+"\n"
+" if {$clean_text_window} {\n"
+" cleanup_text_window;\n"
+" }\n"
+"\n"
" update\n"
"\n"
" if {! $entry} {\n"
@@ -1211,7 +1444,8 @@
" } elseif {[regexp {:[0-9]\\.[0-9]} $expected]} {\n"
" append_text \"\\t($msg)\\n\"\n"
" return 1\n"
-" } elseif {$item == \"connect\" || $item == \"disconnect\"} {\n"
+" } elseif {$item == \"connect\" || $item == \"disconnect\"\n"
+" || $item == \"client\" || $item == \"client_input\"} {\n"
" append_text \"\\t($msg)\\n\"\n"
" return 1\n"
" } else {\n"
@@ -1265,7 +1499,7 @@
" continue\n"
" }\n"
" if {[info exists menu_var($item)]} {\n"
-" if [is_action $item] {\n"
+" if {[is_action $item]} {\n"
" set menu_var($item) \"\"\n"
" } elseif {[value_is_bool $item]} {\n"
" set menu_var($item) 0\n"
@@ -1500,7 +1734,7 @@
" push_new_value $item $name $new 0\n"
" set_connected no\n"
" \n"
-" } elseif [opt_match Q $item] {\n"
+" } elseif {[opt_match Q $item]} {\n"
" push_new_value $item $name $new 1\n"
" } else {\n"
" push_new_value $item $name $new 0\n"
@@ -1666,7 +1900,7 @@
"proc set_x11_display {name} {\n"
" global x11_display\n"
" set x11_display \"x11vnc X display: $name\"\n"
-" wm title . \"tkx11vnc - $name\"\n"
+" set_name \"tkx11vnc - $name\"\n"
"}\n"
"proc set_vnc_display {name} {\n"
" global vnc_display\n"
@@ -1678,7 +1912,7 @@
"}\n"
"proc no_x11_display {} {\n"
" set_x11_display \"(*none*)\"\n"
-" wm title . \"tkx11vnc\"\n"
+" set_name \"tkx11vnc\"\n"
"}\n"
"proc no_vnc_display {} {\n"
" set_vnc_display \"(*none*)\"\n"
@@ -1719,20 +1953,99 @@
" }\n"
"}\n"
"\n"
+"proc client_dialog {client} {\n"
+" set cid \"\"\n"
+" set host \"\"\n"
+" set ip \"\"\n"
+" global menu_var text_area cleanup_window item_bool\n"
+"\n"
+" append_text \"\\nClient info string: $client\\n\\n\"\n"
+" if {[regexp {^(.*):(.*):(.*):(.*):(.*):(.*)$} \\\n"
+" $client m0 m1 m2 m3 m4 m5 m6]} {\n"
+" # id:ip:port:hostname:input:loginvo\n"
+" set cid $m1\n"
+" set ip $m2\n"
+" set port $m3\n"
+" set host $m4\n"
+" regsub {\\..*$} $host \"\" host\n"
+" 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"
+" 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"
+" set sk 0\n"
+" set sm 0\n"
+" set sb 0\n"
+" if {[regexp -nocase {K} $input]} {\n"
+" append_text \"Keystroke\"\n"
+" set sk 1\n"
+" }\n"
+" if {[regexp -nocase {M} $input]} {\n"
+" if {$sk} {\n"
+" append_text \", \"\n"
+" }\n"
+" append_text \"Mouse-Motion\"\n"
+" set sm 1\n"
+" }\n"
+" if {[regexp -nocase {B} $input]} {\n"
+" if {$sk || $sm} {\n"
+" append_text \", \"\n"
+" }\n"
+" append_text \"Button-Click\"\n"
+" set sb 1\n"
+" }\n"
+" if {! $sk && ! $sm && ! $sb} {\n"
+" append_text \"None\"\n"
+" }\n"
+" append_text \"\\n\"\n"
+" }\n"
+" if {$cid == \"\"} {\n"
+" append_text \"Invalid client info string: $client\\n\"\n"
+" return\n"
+" }\n"
+"\n"
+" regsub -all {_} $input \"\" input\n"
+" set menu_var(client) \"$input\"\n"
+" set item_bool(client) 0\n"
+"\n"
+" insert_client_action_window $input\n"
+" set rc [entry_dialog client 1]\n"
+"\n"
+" cleanup_text_window\n"
+"\n"
+" set val $menu_var(client)\n"
+" #puts \"rc: $rc val: $val\"\n"
+"\n"
+" if {! $rc} {\n"
+" return;\n"
+" } elseif {[regexp -nocase {(disconnect|close)} $val]} {\n"
+" disconnect_dialog $client\n"
+" } else {\n"
+" regsub -all -nocase {[^KMB]} $val \"\" \n"
+" set item_bool(client_input) 0\n"
+" push_new_value \"client_input\" \"client_input\" \"$cid:$val\" 0\n"
+" }\n"
+"}\n"
+"\n"
"proc disconnect_dialog {client} {\n"
" set cid \"\"\n"
" set host \"\"\n"
" set msg \"\\n\"\n"
" append msg \"*** Client info string: $client\\n\"\n"
-" if {[regexp {^(.*):(.*)/(.*)-(.*)$} $client m0 m1 m2 m3 m4]} {\n"
-" if {$m4 == \"ro\"} {\n"
-" set view \"(viewonly)\"\n"
-" } else {\n"
-" set view \"(interactive)\"\n"
-" }\n"
-" set host $m1\n"
-" set cid $m3\n"
-" append msg \"*** Host: $m1, Port: $m2 Id: $m3 $view\\n\"\n"
+" if {[regexp {^(.*):(.*):(.*):(.*):(.*):(.*)$} $client m0 m1 m2 m3 m4 m5 m6]} {\n"
+" set cid $m1\n"
+" set ip $m2\n"
+" set port $m3\n"
+" set host $m4\n"
+" regsub {\\..*$} $host \"\" host\n"
+" set input $m5\n"
+" set logvo $m6\n"
+" append_text \"Host: $host, Port: $port, IP: $ip, Id: $cid\\n\"\n"
" }\n"
" if {$cid == \"\"} {\n"
" append_text \"Invalid client info string: $client\\n\"\n"
@@ -1740,7 +2053,7 @@
" }\n"
" append msg \"*** To *DISCONNECT* this client press \\\"OK\\\", otherwise press \\\"Skip\\\"\\n\"\n"
" bell\n"
-" if [warning_dialog $msg \"current\"] {\n"
+" if {[warning_dialog $msg \"current\"]} {\n"
" push_new_value \"disconnect\" \"disconnect\" $cid 1\n"
" } else {\n"
" append_text \"disconnect cancelled.\\n\"\n"
@@ -1762,7 +2075,7 @@
" continue\n"
" }\n"
" set name [$casc entrycget $i -label]\n"
-" if {[regexp {^#} $name]} {\n"
+" if {[regexp {^num-clients} $name]} {\n"
" continue\n"
" }\n"
" if {[regexp {^refresh-list} $name]} {\n"
@@ -1789,12 +2102,20 @@
" $subm add separator\n"
" set count 0\n"
" foreach client [split $list \",\"] {\n"
-" regsub {:[0-9][0-9]*/} $client {/} lab\n"
-" $subm add command -label \"$client\" \\\n"
-" -command \"disconnect_dialog $client\"\n"
+" if {[regexp {^(.*):(.*):(.*):(.*):(.*):(.*)$} \\\n"
+" $client m0 m1 m2 m3 m4 m5 m6]} {\n"
+" # id:ip:port:hostname:input:loginvo\n"
+" set host $m4\n"
+" regsub {\\..*$} $host \"\" host\n"
+" set clabel \"$host $m1\"\n"
+" } else {\n"
+" regsub {:.*$} $client \"\" clabel\n"
+" }\n"
+" $subm add command -label \"$clabel\" \\\n"
+" -command \"client_dialog $client\"\n"
" incr count\n"
" }\n"
-" $subm entryconfigure 0 -label \"#clients: $count\"\n"
+" $subm entryconfigure 0 -label \"num-clients: $count\"\n"
"}\n"
"\n"
"proc set_widgets {} {\n"
@@ -2082,7 +2403,7 @@
" pack $df -side top -fill x\n"
"\n"
" # text area\n"
-" text .text -height 11 -relief ridge -font $ffont\n"
+" text .text -height 12 -relief ridge -font $ffont\n"
" set text_area .text\n"
" pack .text -side top -fill both -expand 1\n"
"\n"
@@ -2628,7 +2949,7 @@
"\n"
"set_template\n"
"\n"
-"wm title . \"tkx11vnc\"\n"
+"set_name \"tkx11vnc\"\n"
"make_widgets;\n"
"\n"
"menu_bindings;\n"
diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1
index 66bb57d..fcafe51 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-08
+ version: 0.7.1pre, lastmod: 2005-02-10
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@@ -250,6 +250,21 @@ out with the "#" character in the usual way.
.IP
Same as \fB-allow\fR 127.0.0.1
.PP
+\fB-input\fR \fIstring\fR
+.IP
+Fine tuning of allowed user input. If \fIstring\fR 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. "\fB-input\fR \fIM\fR" means normal users can only move
+the mouse and "\fB-input\fR \fIKMB,M\fR" lets normal users do
+anything and enables view-only users to move the mouse.
+This option is ignored when a global \fB-viewonly\fR is in
+effect (all input is discarded).
+.PP
\fB-viewpasswd\fR \fIstring\fR
.IP
Supply a 2nd password for view-only logins. The \fB-passwd\fR
@@ -394,7 +409,8 @@ 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 +
character. E.g. "\fB-users\fR \fI+bob\fR" or "\fB-users\fR \fI+nobody\fR".
-The latter is probably the only use of this option
+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".
@@ -402,7 +418,7 @@ use the "=" character: "\fB-users\fR \fI=username\fR".
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,fred\fR". Be especially careful
+use: "\fB-users\fR \fIguess=bob,betty\fR". Be especially careful
using this mode.
.PP
\fB-noshm\fR
@@ -1143,6 +1159,13 @@ localhost enable \fB-localhost\fR mode
.IP
nolocalhost disable \fB-localhost\fR mode
.IP
+input:str set \fB-input\fR to "str", empty to disable.
+.IP
+client_input:str set the K, M, B \fB-input\fR on a per-client
+ basis. select which client as for
+ disconnect, e.g. client_input:host:MB
+ or client_input:0x2:K
+.IP
accept:cmd set \fB-accept\fR "cmd" (empty to disable).
.IP
gone:cmd set \fB-gone\fR "cmd" (empty to disable).
@@ -1424,13 +1447,13 @@ nosolid blackout xinerama noxinerama xrandr noxrandr
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
@@ -1482,10 +1505,13 @@ x11vnc. Normally access to the X display is protected.
Note that if they can modify VNC_CONNECT, they could
also run their own x11vnc and have complete control
of the desktop. If the "\fB-connect\fR \fI/path/to/file\fR"
-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.
+.IP
+To disable the VNC_CONNECT property channel completely
+use \fB-novncconnect.\fR
.PP
\fB-unsafe\fR
.IP
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index af15260..89bef9d 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-08";
+char lastmod[] = "0.7.1pre lastmod: 2005-02-10";
/* X display info */
@@ -346,13 +346,19 @@ unsigned short main_red_shift, main_green_shift, main_blue_shift;
/* we now have a struct with client specific data: */
#define RATE_SAMPLES 5
+#define CILEN 10
typedef struct _ClientData {
- int had_cursor_shape_updates;
- int had_cursor_pos_updates;
int uid;
+ char *hostname;
int client_port;
int server_port;
char *server_ip;
+ char input[CILEN];
+ int login_viewonly;
+
+ int had_cursor_shape_updates;
+ int had_cursor_pos_updates;
+
double timer;
double send_cmp_rate;
double send_raw_rate;
@@ -445,6 +451,7 @@ double dtime(double *);
void initialize_blackouts(char *);
void initialize_blackouts_and_xinerama(void);
void initialize_keyboard_and_pointer(void);
+void initialize_allowed_input(void);
void initialize_modtweak(void);
void initialize_pointer_map(char *);
void initialize_cursors_mode(void);
@@ -519,6 +526,8 @@ void check_xevents(void);
char *this_host(void);
void set_vnc_desktop_name(void);
+char *short_kmb(char *);
+
int get_cmp_rate(void);
int get_raw_rate(void);
int get_read_rate(void);
@@ -574,6 +583,9 @@ char *allow_once = NULL; /* one time -allow */
char *accept_cmd = NULL; /* for -accept */
char *gone_cmd = NULL; /* for -gone */
int view_only = 0; /* clients can only watch. */
+char *allowed_input_view_only = NULL;
+char *allowed_input_normal = NULL;
+char *allowed_input_str = NULL;
char *viewonly_passwd = NULL; /* view only passwd. */
int inetd = 0; /* spawned from inetd(1) */
int connect_once = 1; /* disconnect after first connection session. */
@@ -776,6 +788,18 @@ void lowercase(char *str) {
}
}
+void uppercase(char *str) {
+ char *p;
+ if (str == NULL) {
+ return;
+ }
+ p = str;
+ while (*p != '\0') {
+ *p = toupper(*p);
+ p++;
+ }
+}
+
char *lblanks(char *str) {
char *p = str;
while (*p) {
@@ -1325,6 +1349,31 @@ char *host2ip(char *host) {
return str;
}
+char *ip2host(char *ip) {
+ char *str;
+#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
+ struct hostent *hp;
+#ifndef in_addr_t
+typedef unsigned int in_addr_t;
+#endif
+ in_addr_t iaddr;
+
+ iaddr = inet_addr(ip);
+ if (iaddr == INADDR_NONE) {
+ return strdup("unknown");
+ }
+
+ hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET);
+ if (!hp) {
+ return strdup("unknown");
+ }
+ str = strdup(hp->h_name);
+#else
+ str = strdup("unknown");
+#endif
+ return str;
+}
+
int dotted_ip(char *host) {
char *p = host;
while (*p != '\0') {
@@ -1337,20 +1386,34 @@ int dotted_ip(char *host) {
return 1;
}
-int get_remote_port(int sock) {
+int get_port(int sock, int remote) {
struct sockaddr_in saddr;
int saddr_len, saddr_port;
saddr_len = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
saddr_port = -1;
- if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
- saddr_port = ntohs(saddr.sin_port);
+ if (remote) {
+ if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+ saddr_port = ntohs(saddr.sin_port);
+ }
+ } else {
+ if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+ saddr_port = ntohs(saddr.sin_port);
+ }
}
return saddr_port;
}
-char *get_remote_host(int sock) {
+int get_remote_port(int sock) {
+ return get_port(sock, 1);
+}
+
+int get_local_port(int sock) {
+ return get_port(sock, 0);
+}
+
+char *get_host(int sock, int remote) {
struct sockaddr_in saddr;
int saddr_len, saddr_port;
char *saddr_ip_str = NULL;
@@ -1358,47 +1421,29 @@ char *get_remote_host(int sock) {
saddr_len = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
saddr_port = -1;
- if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
#if LIBVNCSERVER_HAVE_NETINET_IN_H
- saddr_ip_str = inet_ntoa(saddr.sin_addr);
-#endif
+ if (remote) {
+ if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+ saddr_ip_str = inet_ntoa(saddr.sin_addr);
+ }
+ } else {
+ if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+ saddr_ip_str = inet_ntoa(saddr.sin_addr);
+ }
}
+#endif
if (! saddr_ip_str) {
- saddr_ip_str = strdup("unknown");
+ saddr_ip_str = "unknown";
}
- return saddr_ip_str;
+ return strdup(saddr_ip_str);
}
-int get_local_port(int sock) {
- struct sockaddr_in saddr;
- int saddr_len, saddr_port;
-
- saddr_len = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
- saddr_port = -1;
- if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
- saddr_port = ntohs(saddr.sin_port);
- }
- return saddr_port;
+char *get_remote_host(int sock) {
+ return get_host(sock, 1);
}
char *get_local_host(int sock) {
- struct sockaddr_in saddr;
- int saddr_len, saddr_port;
- char *saddr_ip_str = NULL;
-
- saddr_len = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
- saddr_port = -1;
- if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
-#if LIBVNCSERVER_HAVE_NETINET_IN_H
- saddr_ip_str = inet_ntoa(saddr.sin_addr);
-#endif
- }
- if (! saddr_ip_str) {
- saddr_ip_str = strdup("unknown");
- }
- return saddr_ip_str;
+ return get_host(sock, 0);
}
/*
@@ -2072,10 +2117,13 @@ char *list_clients(void) {
rfbReleaseClientIterator(iter);
/*
- * each client: 123.123.123.123:60000/0x11111111-rw, = 36 bytes
- * so count+1 * 100 must cover it.
+ * each client:
+ * <id>:<ip>:<port>:<hostname>:<input>:<loginview>,
+ * 8+1+16+1+5+1+256+1+5+1+1+1
+ * 123.123.123.123:60000/0x11111111-rw, = 297 bytes
+ * so count+1 * 400 must cover it.
*/
- list = (char *) malloc((count+1)*100);
+ list = (char *) malloc((count+1)*400);
list[0] = '\0';
@@ -2085,14 +2133,18 @@ char *list_clients(void) {
if (*list != '\0') {
strcat(list, ",");
}
+ sprintf(tmp, "0x%x:", cd->uid);
+ strcat(list, tmp);
strcat(list, cl->host);
- sprintf(tmp, ":%d/0x%x", get_remote_port(cl->sock), cd->uid);
+ strcat(list, ":");
+ sprintf(tmp, "%d:", cd->client_port);
+ strcat(list, tmp);
+ strcat(list, cd->hostname);
+ strcat(list, ":");
+ strcat(list, cd->input);
+ strcat(list, ":");
+ sprintf(tmp, "%d", cd->login_viewonly);
strcat(list, tmp);
- if (cl->viewOnly) {
- strcat(list, "-ro");
- } else {
- strcat(list, "-rw");
- }
}
rfbReleaseClientIterator(iter);
return list;
@@ -2114,23 +2166,18 @@ void close_all_clients(void) {
rfbReleaseClientIterator(iter);
}
-void close_clients(char *str) {
+rfbClientPtr *client_match(char *str) {
rfbClientIteratorPtr iter;
- rfbClientPtr cl;
- int host_warn = 0, hex_warn = 0;
-
- if (!strcmp(str, "all") || !strcmp(str, "*")) {
- close_all_clients();
- return;
- }
-
- if (! screen) {
- return;
- }
+ rfbClientPtr cl, *cl_list;
+ int i, n, host_warn = 0, hex_warn = 0;
+ n = client_count + 10;
+ cl_list = (rfbClientPtr *) malloc(n * sizeof(rfbClientPtr));
+
+ i = 0;
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
- if (strstr(str, "0x")) {
+ if (strstr(str, "0x") == str) {
int id;
ClientData *cd = (ClientData *) cl->clientData;
if (sscanf(str, "0x%x", &id) != 1) {
@@ -2141,8 +2188,7 @@ void close_clients(char *str) {
continue;
}
if ( cd->uid == id) {
- rfbCloseClient(cl);
- rfbClientConnectionGone(cl);
+ cl_list[i++] = cl;
}
} else {
char *rstr = str;
@@ -2159,15 +2205,77 @@ void close_clients(char *str) {
rfbLog("lookup: %s -> %s\n", str, rstr);
}
if (!strcmp(rstr, cl->host)) {
- rfbCloseClient(cl);
- rfbClientConnectionGone(cl);
+ cl_list[i++] = cl;
}
if (rstr != str) {
free(rstr);
}
}
+ if (i >= n - 1) {
+ break;
+ }
}
rfbReleaseClientIterator(iter);
+
+ cl_list[i] = NULL;
+
+ return cl_list;
+}
+
+void close_clients(char *str) {
+ rfbClientPtr *cl_list, *cp;
+
+ if (!strcmp(str, "all") || !strcmp(str, "*")) {
+ close_all_clients();
+ return;
+ }
+
+ if (! screen) {
+ return;
+ }
+
+ cl_list = client_match(str);
+
+ cp = cl_list;
+ while (*cp) {
+ rfbCloseClient(*cp);
+ rfbClientConnectionGone(*cp);
+ cp++;
+ }
+ free(cl_list);
+}
+
+void set_client_input(char *str) {
+ rfbClientPtr *cl_list, *cp;
+ char *p, *val;
+
+ /* str is "match:value" */
+
+ if (! screen) {
+ return;
+ }
+
+ p = strchr(str, ':');
+ if (! p) {
+ return;
+ }
+ *p = '\0';
+ p++;
+ val = short_kmb(p);
+
+ cl_list = client_match(str);
+
+ cp = cl_list;
+ while (*cp) {
+ ClientData *cd = (ClientData *) (*cp)->clientData;
+ cd->input[0] = '\0';
+ strcat(cd->input, "_");
+ strcat(cd->input, val);
+ cp++;
+ }
+
+ free(val);
+ free(cl_list);
}
/*
@@ -2221,7 +2329,9 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) {
if (cd && cd->server_ip) {
set_env("RFB_SERVER_IP", cd->server_ip);
} else {
- set_env("RFB_SERVER_IP", get_local_host(client->sock));
+ char *sip = get_local_host(client->sock);
+ set_env("RFB_SERVER_IP", sip);
+ free(sip);
}
if (cd && cd->server_port > 0) {
@@ -2287,8 +2397,13 @@ static void client_gone(rfbClientPtr client) {
if (client->clientData) {
ClientData *cd = (ClientData *) client->clientData;
- if (cd && cd->server_ip) {
- free(cd->server_ip);
+ if (cd) {
+ if (cd->server_ip) {
+ free(cd->server_ip);
+ }
+ if (cd->hostname) {
+ free(cd->hostname);
+ }
}
free(client->clientData);
}
@@ -3288,9 +3403,6 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
return(RFB_CLIENT_REFUSE);
}
- if (view_only) {
- client->viewOnly = TRUE;
- }
client->clientData = (void *) calloc(sizeof(ClientData), 1);
cd = (ClientData *) client->clientData;
@@ -3298,7 +3410,11 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
cd->client_port = get_remote_port(client->sock);
cd->server_port = get_local_port(client->sock);
- cd->server_ip = strdup(get_remote_host(client->sock));
+ cd->server_ip = get_local_host(client->sock);
+ cd->hostname = ip2host(client->host);
+
+ cd->input[0] = '-';
+ cd->login_viewonly = -1;
client->clientGoneHook = client_gone;
client_count++;
@@ -3327,6 +3443,54 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
return(RFB_CLIENT_ACCEPT);
}
+void check_new_clients(void) {
+ static int last_count = 0;
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ if (client_count == last_count) {
+ return;
+ }
+
+ if (! all_clients_initialized()) {
+ return;
+ }
+
+ last_count = client_count;
+ if (! client_count) {
+ return;
+ }
+ if (! screen) {
+ return;
+ }
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ ClientData *cd = (ClientData *) cl->clientData;
+
+ if (cd->login_viewonly < 0) {
+ /* this is a general trigger to initialize things */
+ if (cl->viewOnly) {
+ cd->login_viewonly = 1;
+ if (allowed_input_view_only) {
+ cl->viewOnly = FALSE;
+ cd->input[0] = '\0';
+ strncpy(cd->input,
+ allowed_input_view_only, CILEN);
+ }
+ } else {
+ cd->login_viewonly = 0;
+ if (allowed_input_normal) {
+ cd->input[0] = '\0';
+ strncpy(cd->input,
+ allowed_input_normal, CILEN);
+ }
+ }
+ }
+ }
+ rfbReleaseClientIterator(iter);
+}
+
/* -- keyboard.c -- */
/*
* Routine to retreive current state keyboard. 1 means down, 0 up.
@@ -4494,6 +4658,99 @@ if (sym >> 8 == 0) { \
}
#endif
+char *short_kmb(char *str) {
+ int i, saw_k = 0, saw_m = 0, saw_b = 0, n = 10;
+ char *p, tmp[10];
+
+ for (i=0; i<n; i++) {
+ tmp[i] = '\0';
+ }
+
+ p = str;
+ i = 0;
+ while (*p) {
+ if ((*p == 'K' || *p == 'k') && !saw_k) {
+ tmp[i++] = 'K';
+ saw_k = 1;
+ } else if ((*p == 'M' || *p == 'm') && !saw_m) {
+ tmp[i++] = 'M';
+ saw_m = 1;
+ } else if ((*p == 'B' || *p == 'b') && !saw_b) {
+ tmp[i++] = 'B';
+ saw_b = 1;
+ }
+ p++;
+ }
+ return(strdup(tmp));
+}
+
+void initialize_allowed_input(void) {
+ char *str;
+
+ if (allowed_input_normal) {
+ free(allowed_input_normal);
+ }
+ if (allowed_input_view_only) {
+ free(allowed_input_view_only);
+ }
+
+ if (! allowed_input_str) {
+ allowed_input_normal = strdup("KMB");
+ allowed_input_view_only = strdup("");
+ } else {
+ char *p, *str = strdup(allowed_input_str);
+ p = strchr(str, ',');
+ if (p) {
+ allowed_input_view_only = strdup(p+1);
+ *p = '\0';
+ allowed_input_normal = strdup(str);
+ } else {
+ allowed_input_normal = strdup(str);
+ allowed_input_view_only = strdup("");
+ }
+ free(str);
+ }
+
+ /* shorten them */
+ str = short_kmb(allowed_input_normal);
+ free(allowed_input_normal);
+ allowed_input_normal = str;
+
+ str = short_kmb(allowed_input_view_only);
+ free(allowed_input_view_only);
+ allowed_input_view_only = str;
+
+ if (screen) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ ClientData *cd = (ClientData *) cl->clientData;
+
+ if (cd->input[0] == '=') {
+ ; /* custom setting */
+ } else if (cd->login_viewonly) {
+ if (*allowed_input_view_only != '\0') {
+ cl->viewOnly = FALSE;
+ cd->input[0] = '\0';
+ strncpy(cd->input,
+ allowed_input_view_only, CILEN);
+ } else {
+ cl->viewOnly = TRUE;
+ }
+ } else {
+ if (allowed_input_normal) {
+ cd->input[0] = '\0';
+ strncpy(cd->input,
+ allowed_input_normal, CILEN);
+ }
+ }
+ }
+ rfbReleaseClientIterator(iter);
+ }
+}
+
void initialize_keyboard_and_pointer(void) {
if (use_modifier_tweak) {
initialize_modtweak();
@@ -4664,13 +4921,6 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
down ? "down" : "up", (int) keysym);
}
- if (view_only) {
- return;
- }
- if (client && client->viewOnly) {
- return;
- }
-
#define ADJUSTMOD(sym, state) \
if (keysym == sym) { \
if (down) { \
@@ -4715,6 +4965,54 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
}
}
+typedef struct allowed_input {
+ int keystroke;
+ int motion;
+ int button;
+} allowed_input_t;
+
+void get_allowed_input(rfbClientPtr client, allowed_input_t *input) {
+ ClientData *cd;
+ char *str;
+
+ input->keystroke = 0;
+ input->motion = 0;
+ input->button = 0;
+
+ if (! client) {
+ return;
+ }
+
+ cd = (ClientData *) client->clientData;
+
+ if (cd->input[0] != '-') {
+ str = cd->input;
+ } else if (client->viewOnly) {
+ if (allowed_input_view_only) {
+ str = allowed_input_view_only;
+ } else {
+ str = "";
+ }
+ } else {
+ if (allowed_input_normal) {
+ str = allowed_input_normal;
+ } else {
+ str = "KMB";
+ }
+ }
+
+ while (*str) {
+ if (*str == 'K') {
+ input->keystroke = 1;
+ } else if (*str == 'M') {
+ input->motion = 1;
+ } else if (*str == 'B') {
+ input->button = 1;
+ }
+ str++;
+ }
+}
+
/*
* key event handler. See the above functions for contortions for
* running under -modtweak.
@@ -4724,6 +5022,7 @@ static rfbClientPtr last_keyboard_client = NULL;
void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
KeyCode k;
int isbutton = 0;
+ allowed_input_t input;
if (debug_keyboard) {
char *str;
@@ -4737,7 +5036,8 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
if (view_only) {
return;
}
- if (client && client->viewOnly) {
+ get_allowed_input(client, &input);
+ if (! input.keystroke) {
return;
}
@@ -5074,10 +5374,9 @@ void initialize_pointer_map(char *pointer_remap) {
}
/*
- * Send a pointer event to the X server.
+ * Send a pointer position event to the X server.
*/
-static void update_x11_pointer(int mask, int x, int y) {
- int i, mb;
+static void update_x11_pointer_position(int x, int y) {
X_LOCK;
if (use_xwarppointer) {
@@ -5100,6 +5399,25 @@ static void update_x11_pointer(int mask, int x, int y) {
last_event = last_input = time(0);
+ if (nofb) {
+ /*
+ * nofb is for, e.g. Win2VNC, where fastest pointer
+ * updates are desired.
+ */
+ X_LOCK;
+ XFlush(dpy);
+ X_UNLOCK;
+ }
+}
+
+/*
+ * Send a pointer position event to the X server.
+ */
+static void update_x11_pointer_mask(int mask) {
+ int i, mb;
+
+ last_event = last_input = time(0);
+
X_LOCK;
/* look for buttons that have be clicked or released: */
for (i=0; i < MAX_BUTTONS; i++) {
@@ -5165,14 +5483,6 @@ static void update_x11_pointer(int mask, int x, int y) {
}
}
- if (nofb) {
- /*
- * nofb is for, e.g. Win2VNC, where fastest pointer
- * updates are desired.
- */
- XFlush(dpy);
- }
-
X_UNLOCK;
/*
@@ -5185,9 +5495,10 @@ static void update_x11_pointer(int mask, int x, int y) {
/*
* Actual callback from libvncserver when it gets a pointer event.
* This may queue pointer events rather than sending them immediately
- * to the X server. (see update_x11_pointer())
+ * to the X server. (see update_x11_pointer*())
*/
void pointer(int mask, int x, int y, rfbClientPtr client) {
+ allowed_input_t input;
if (debug_pointer && mask >= 0) {
static int show_motion = -1;
@@ -5207,7 +5518,8 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
if (view_only) {
return;
}
- if (client && client->viewOnly) {
+ get_allowed_input(client, &input);
+ if (! input.motion && ! input.button) {
return;
}
if (scaling) {
@@ -5277,6 +5589,13 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
ev[i][0] = mask;
ev[i][1] = x;
ev[i][2] = y;
+ if (! input.button) {
+ ev[i][0] = -1;
+ }
+ if (! input.motion) {
+ ev[i][1] = -1;
+ ev[i][2] = -1;
+ }
UNLOCK(pointerMutex);
if (debug_pointer) {
rfbLog("pointer(): deferring event "
@@ -5291,7 +5610,12 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
if (debug_pointer) {
rfbLog("pointer(): sending event %d\n", i+1);
}
- update_x11_pointer(ev[i][0], ev[i][1], ev[i][2]);
+ if (ev[i][1] >= 0) {
+ update_x11_pointer_position(ev[i][1], ev[i][2]);
+ }
+ if (ev[i][0] >= 0) {
+ update_x11_pointer_mask(ev[i][0]);
+ }
}
if (nevents && dt > maxwait) {
X_LOCK;
@@ -5313,7 +5637,12 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
}
/* update the X display with the event: */
- update_x11_pointer(mask, x, y);
+ if (input.motion) {
+ update_x11_pointer_position(x, y);
+ }
+ if (input.button) {
+ update_x11_pointer_mask(mask);
+ }
}
/* -- xkb_bell.c -- */
@@ -6098,16 +6427,22 @@ void check_xevents(void) {
* hook called when a VNC client sends us some "XCut" text (rfbClientCutText).
*/
void xcut_receive(char *text, int len, rfbClientPtr cl) {
+ allowed_input_t input;
if (!watch_selection) {
return;
}
- if (cl && cl->viewOnly) {
+ if (view_only) {
return;
}
if (text == NULL || len == 0) {
return;
}
+ get_allowed_input(cl, &input);
+ if (!input.keystroke && !input.motion && !input.button) {
+ /* maybe someday KMBC for cut text... */
+ return;
+ }
X_LOCK;
@@ -8013,6 +8348,34 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("process_remote_cmd: setting input_skip %d\n", is);
ui_skip = is;
+ } else if (strstr(p, "input") == p) {
+ int doit = 1;
+ COLON_CHECK("input:")
+ if (query) {
+ snprintf(buf, bufn, "ans=%s%s%s", p, co,
+ NONUL(allowed_input_str));
+ goto qry;
+ }
+ p += strlen("input:");
+ if (allowed_input_str && !strcmp(p, allowed_input_str)) {
+ doit = 0;
+ }
+ rfbLog("process_remote_cmd: setting input %s\n", p);
+ if (allowed_input_str) free(allowed_input_str);
+ if (*p == '\0') {
+ allowed_input_str = NULL;
+ } else {
+ allowed_input_str = strdup(p);
+ }
+ if (doit) {
+ initialize_allowed_input();
+ }
+ } else if (strstr(p, "client_input") == p) {
+ NOTAPP
+ COLON_CHECK("client_input:")
+ p += strlen("client_input:");
+ set_client_input(p);
+
} else if (strstr(p, "speeds") == p) {
COLON_CHECK("speeds:")
if (query) {
@@ -15328,6 +15691,7 @@ static void watch_loop(void) {
copy_screen();
}
+ check_new_clients();
check_xevents();
check_connect_inputs();
check_padded_fb();
@@ -15366,10 +15730,7 @@ static void watch_loop(void) {
}
if (watch_bell) {
- /*
- * check for any bell events.
- * n.b. assumes -nofb folks do not want bell...
- */
+ /* n.b. assumes -nofb folks do not want bell... */
check_bell_event();
}
@@ -15579,6 +15940,19 @@ static void print_help(int mode) {
" each time a new client connects. Lines can be commented\n"
" out with the \"#\" character in the usual way.\n"
"-localhost Same as -allow 127.0.0.1\n"
+"\n"
+"-input string Fine tuning of allowed user input. If \"string\" does\n"
+" not contain a comma \",\" the tuning applies only to\n"
+" normal clients. Otherwise the part before \",\" is\n"
+" for normal clients and the part after for view-only\n"
+" clients. \"K\" is for Keystroke input, \"M\" for\n"
+" Mouse-motion input, and \"B\" for Button-click input.\n"
+" Their presence in the string enables that type of input.\n"
+" E.g. \"-input M\" means normal users can only move\n"
+" the mouse and \"-input KMB,M\" lets normal users do\n"
+" anything and enables view-only users to move the mouse.\n"
+" This option is ignored when a global -viewonly is in\n"
+" effect (all input is discarded).\n"
"-viewpasswd string Supply a 2nd password for view-only logins. The -passwd\n"
" (full-access) password must also be supplied.\n"
"-passwdfile filename Specify libvncserver -passwd via the first line of\n"
@@ -15692,7 +16066,8 @@ static void print_help(int mode) {
" it switch immediately regardless if the display can\n"
" be reopened or not prefix the username with the +\n"
" character. E.g. \"-users +bob\" or \"-users +nobody\".\n"
-" The latter is probably the only use of this option\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"
@@ -15700,7 +16075,7 @@ static void print_help(int mode) {
" 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,fred\". Be especially careful\n"
+" use: \"-users guess=bob,betty\". Be especially careful\n"
" using this mode.\n"
" \n"
"-noshm Do not use the MIT-SHM extension for the polling.\n"
@@ -16258,6 +16633,11 @@ static void print_help(int mode) {
" use \"-host\" to delete a single host\n"
" localhost enable -localhost mode\n"
" nolocalhost disable -localhost mode\n"
+" input:str set -input to \"str\", empty to disable.\n"
+" client_input:str set the K, M, B -input on a per-client\n"
+" basis. select which client as for\n"
+" disconnect, e.g. client_input:host:MB\n"
+" or client_input:0x2:K\n"
/* ext. cmd. */
" accept:cmd set -accept \"cmd\" (empty to disable).\n"
" gone:cmd set -gone \"cmd\" (empty to disable).\n"
@@ -16429,13 +16809,13 @@ static void print_help(int mode) {
" xrandr_mode padgeom quiet q noquiet modtweak nomodtweak\n"
" xkb noxkb skip_keycodes add_keysyms noadd_keysyms\n"
" clear_mods noclear_mods clear_keys noclear_keys\n"
-" remap repeat norepeat fb nofb bell nobell sel nosel\n"
-" primary noprimary cursorshape nocursorshape cursorpos\n"
-" nocursorpos cursor show_cursor noshow_cursor\n"
-" nocursor xfixes noxfixes alphacut alphafrac\n"
-" alpharemove noalpharemove alphablend noalphablend\n"
-" xwarp xwarppointer noxwarp noxwarppointer buttonmap\n"
-" dragging nodragging pointer_mode pm input_skip speeds\n"
+" remap repeat norepeat fb nofb bell nobell sel\n"
+" nosel primary noprimary cursorshape nocursorshape\n"
+" cursorpos nocursorpos cursor show_cursor noshow_cursor\n"
+" nocursor xfixes noxfixes alphacut alphafrac alpharemove\n"
+" noalpharemove alphablend noalphablend xwarp xwarppointer\n"
+" noxwarp noxwarppointer buttonmap dragging nodragging\n"
+" pointer_mode pm input_skip input client_input speeds\n"
" debug_pointer dp nodebug_pointer nodp debug_keyboard dk\n"
" nodebug_keyboard nodk deferupdate defer wait rfbwait\n"
" nap nonap sb screen_blank fs gaps grow fuzz snapfb\n"
@@ -16483,10 +16863,13 @@ static void print_help(int mode) {
" Note that if they can modify VNC_CONNECT, they could\n"
" also run their own x11vnc and have complete control\n"
" of the desktop. If the \"-connect /path/to/file\"\n"
-" channel is being used, obviously anyone who can write\n"
-" to /path/to/file can remotely control x11vnc. So be\n"
-" sure to protect the X display and that file's write\n"
-" permissions.\n"
+" channel is being used, obviously anyone who can\n"
+" write to /path/to/file can remotely control x11vnc.\n"
+" So be sure to protect the X display and that file's\n"
+" write permissions.\n"
+"\n"
+" To disable the VNC_CONNECT property channel completely\n"
+" use -novncconnect.\n"
"\n"
"-unsafe If x11vnc is running as root (e.g. inetd or Xsetup for\n"
" a display manager) a few remote commands are disabled\n"
@@ -17044,6 +17427,9 @@ int main(int argc, char* argv[]) {
allow_list = strdup(argv[++i]);
} else if (!strcmp(arg, "-localhost")) {
allow_list = strdup("127.0.0.1");
+ } else if (!strcmp(arg, "-input")) {
+ CHECK_ARGC
+ allowed_input_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-viewpasswd")) {
vpw_loc = i;
CHECK_ARGC
@@ -17987,6 +18373,8 @@ int main(int argc, char* argv[]) {
initialize_keyboard_and_pointer();
+ initialize_allowed_input();
+
if (! inetd) {
if (! screen->port || screen->listenSock < 0) {
rfbLog("Error: could not obtain listening port.\n");