Updated 2013-01-24 11:24:26 by dkf
 ## ********************************************************
 ##
 ## Name: securePipe
 ##
 ## Description:
 ## Opens an ssh tunnel to the remote host.
 ## When ssh falls back to rsh under these circumstances,
 ## two bad lines will get returned at the top of the
 ## result and one bad line at the bottom.  When it doesn't
 ## fall back, one bad line will be returned at the bottom.
 ##
 ## Parameters:
 ##
 ## Usage:
 ##
 ## set fid [ securePipe $user $host ]
 ## puts $fid $command
 ## set data [ read $fid ]
 ##
 ## If the command is forced into the background, an immediate
 ## gets will return a background task i.d. and a process i.d.:
 ##
 ##   puts $fid "ps -Ao fname,user &"
 ##   gets $fid -   [ 2 ] 10359
 ##
 ## And the next command sent through after the task completes
 ## will have the status line for the last backgrounded task
 ## appended to its output:
 ##
 ##   puts $fid date
 ##   read $fid -
 ##   Fri Jan 26 13:19:11 PST 2001
 ##   [2]  + Done  ps -Ao fname,user
 ##
 ## along with the usual blank line.
 ##
 ## And this works:
 ##
 ##   puts $fid "ssh -n user@host $command"
 ##
 ## So you can use securePipe to tunnel into private networks.
 ##
 ## Comments:
 ## If the command sent down the pipe never returns, the pipe
 ## will become useless.  It will not block, but will always
 ## return a blank line.
 ##
 ## Using this to connect as another user on the local host
 ## can fail in unexpected ways.
 ##

 proc securePipe { user host } {
     if { [ catch {
        set fid [ open "|ssh ${user}@$host" a+ ]
        fconfigure $fid -blocking off
        fconfigure $fid -buffering full
        ;## let ssh settle...
        after 2000
        set junk [ read $fid ]
        ;## now make sure we got authenticated (this will throw
        ;## a "broken pipe" exception if auth failed).
        if { [ catch {
           fconfigure $fid -buffering line
           puts $fid hostname
        } err ] } {
           if { [ regexp {broken pipe} $err ] } {
              set err "ssh/rsh auth failed for ${user}@$host"
           }
           return -code error $err
        }
        after 1000
        fconfigure $fid -buffering full
        set junk [ read $fid ]
     } err ] } {
        return -code error "securePipe: $err"
     }
     return $fid
 }
 ## ********************************************************

-PSE

rdt Am I right in assuming that this only works if you have got the ssh to not ask for a password?

Lars H, 2007-06-25: [1] mentions using master connections (-M and -S options of ssh) to get around that. The idea seems to be that the asking-for-password only happens when starting the master connection; the slaves share the master's connection and authentication.

TV I'm quite sure this wonderful enough construction that I used with quite unrecent tcl versions on Unix won't have a chance working on the Windows platform....

schlenk Using Cygwin it may actually work on Windows.

TV The problem is that the whole pipe_to_a_process to my knowledge doesn't work under Windows, that is you can start a process and pipe data to it, but it will then just run until eof and wait with giving data back until it exits.

slebetman Piping to a process works correctly under Windows, but only for 32 bit executables. Which is fine in this case since Cygwin is fully 32 bits. If I'm not mistaken you can even use the command line client shipped with PuTTY. Besides, I haven't seen a 16 bit app since Windows 98 and they were supposed to be phased out for Windows 95.

[ramy] - 2013-01-24 04:09:53

For some reason I dont see the remote output just by "read $fid" but i have to flush first "flush $fid; read $fid" [Edit] I got it .. I think we should change the buffering to be by line instead of full buffer "fconfigure $fid -buffering line" before "return $fid"


See also edit