- safe interp for the remote, using Safe to provide policy and such - main impediment being to correctly and flexibly implement policy setting at the remote end.
- some protection against the puts stderr problem mentioned above.
- asynchronous command execution - it's not too hard, actually, it only requires a sequence number to match requests and responses, and a fileevent-driven command interpreter.
- chroot jail. TclX provides chroot, but actually setting up a chroot jail is a fairly complex process. Perhaps tclsh + chroot, working in with a Safe interp would do the trick.
proc connect {where} {
global ssh
set ssh [open "|ssh $where" "r+"] ;# start up the remote shell, should be tclsh
fconfigure $ssh -buffering line -blocking 1
# set up a command loop which processes and returns our commands
puts $ssh {
fconfigure stdout -buffering line
while {![eof stdin]} {
set cmd [gets stdin]
set code [catch $cmd result opt]
puts [string map [list \\ \\\\ \n \\n] $opt]
puts [string map [list \\ \\\\ \n \\n] $result]
}
}
# return the ssh connection
return $ssh
}I (CJL) found the code above introduces a lag between command and response, such that command-N sees the response to command-(N-1). I eventually tracked it down to the injection of a false null command by the puts $ssh ... statement. The code below removes that behaviour (the double closing brace, rather than two single braces is what makes the difference):
puts $ssh {
fconfigure stdout -buffering line
while {![eof stdin]} {
set cmd [gets stdin]
set code [catch $cmd result opt]
puts [string map [list \\ \\\\ \n \\n] $opt]
puts [string map [list \\ \\\\ \n \\n] $result]
}}remote passes the expression to the remote via ssh, and returns the result.
proc remote {arg} {
global ssh
# execute the command in the remote tclsh
#puts stderr "CMD: $arg"
puts $ssh $arg
# get the error option dict
set opt [string map [list \\n \n \\\\ \\] [gets $ssh]]
#puts "OPT: $opt"
# get the remote execution result
set result [string map [list \\n \n \\\\ \\] [gets $ssh]]
#puts "RESULT: $result"
# return the result or error from the remote
return -options [eval dict create $opt] $result
}remotes passes several commands to the remote ssh, returning the last result
proc remotes {arg} {
foreach line [split $arg \n] {
#puts "CMDL: $line"
remote $line
}
}This is just a little bitttt of test code. There's a problem with quoting, if someone can show me how to do it better, I'd be grateful.
if {[info exists argv0] && ($argv0 == [info script])} {
connect user@host
puts [remote set mumble 100]
puts [remote incr mumble]
puts [remote set mumble]
puts [remote return "Woo\\nWoo\\n"]
puts [remote set blerf] ;# expect an error here
puts [remote set mumble]
}Changes:- Changed [connect] to permit multi-line commands.
ZB 22.06.2008. BTW: there is an utility SecPanel [1], which is a SSH gui for unix like systems, written in pure TCL (last version 0.6.1 from 18.08.2010.). Wrote this here, because it's "very a'propos".
Tclssh
is a package of pure Tcl functions for executing Tcl scripts in a remote host.RFox - 2013-11-13 15:54:20Would have thought this was an ideal job for expect?

