Commit 86ccf267 authored by runge's avatar runge

x11vnc -input to fine tune allow user input. per-client settings -R

parent 5b18d401
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.
......
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.
......
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:
......
......@@ -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,8 +328,27 @@ 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) "
......@@ -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;
......
......@@ -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"
......
......@@ -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
......
......@@ -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");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment