- 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?