From a6979298fd2fee3fc7e98b4a1879fe3912983397 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Wed, 5 Sep 2018 21:58:55 -0700 Subject: [PATCH] Steps toward getting remote cp(tar) status back to client --- hkexnet/hkexnet.go | 6 +++--- hkexsh/hkexsh.go | 11 +++++------ hkexshd/hkexshd.go | 36 ++++++++++++++++++++++-------------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index 4f331ee..bb5377f 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -437,9 +437,9 @@ func (hc Conn) Read(b []byte) (n int, err error) { } else if ctrlStatOp == CSOExitStatus { if len(payloadBytes) > 0 { *hc.closeStat = uint8(payloadBytes[0]) - // If remote end is closing (255), reply we're closing ours - if payloadBytes[0] == 255 { - hc.SetStatus(255) + // If remote end is closing with an error, reply we're closing ours + if payloadBytes[0] != 0 { + hc.SetStatus(payloadBytes[0]) hc.Close() } } else { diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index 47d520f..bfc5e6c 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -8,6 +8,7 @@ package main import ( + "bytes" "flag" "fmt" "io" @@ -142,11 +143,8 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *cmdSpec) c.Dir, _ = os.Getwd() fmt.Println("[wd:", c.Dir, "]") c.Stdout = conn - // Stderr sinkholing is important. Any extraneous output to tarpipe - // messes up remote side as it's expecting pure tar data. - // (For example, if user specifies abs paths, tar outputs - // "Removing leading '/' from path names") - c.Stderr = nil + stdErrBuffer := new(bytes.Buffer) + c.Stderr = stdErrBuffer // Start the command (no pty) err = c.Start() // returns immediately @@ -165,12 +163,13 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *cmdSpec) if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() log.Printf("Exit Status: %d", exitStatus) + fmt.Print(stdErrBuffer) } } } //fmt.Println("*** client->server cp finished ***") // Signal other end transfer is complete - conn.WritePacket([]byte{byte(255)}, hkexnet.CSOExitStatus) + conn.WritePacket([]byte{byte(rec.status)}, hkexnet.CSOExitStatus) _, _ = conn.Read(nil /*ackByte*/) } } else { diff --git a/hkexshd/hkexshd.go b/hkexshd/hkexshd.go index b8f62a6..4e02c09 100755 --- a/hkexshd/hkexshd.go +++ b/hkexshd/hkexshd.go @@ -8,6 +8,7 @@ package main import ( + "bytes" "flag" "fmt" "io" @@ -157,11 +158,14 @@ func runServerToClientCopyAs(who string, conn hkexnet.Conn, srcPath string, chaf c.SysProcAttr = &syscall.SysProcAttr{} c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid} c.Stdout = conn - // Stderr sinkholing is important. Any extraneous output to tarpipe - // messes up remote side as it's expecting pure tar data. + // Stderr sinkholing (or buffering to something other than stdout) + // is important. Any extraneous output to tarpipe messes up remote + // side as it's expecting pure tar data. // (For example, if user specifies abs paths, tar outputs // "Removing leading '/' from path names") - c.Stderr = nil + stdErrBuffer := new(bytes.Buffer) + c.Stderr = stdErrBuffer + //c.Stderr = nil if chaffing { conn.EnableChaff() @@ -189,6 +193,11 @@ func runServerToClientCopyAs(who string, conn hkexnet.Conn, srcPath string, chaf if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() log.Printf("Exit Status: %d", exitStatus) + // TODO: send stdErrBuffer to client via specific packet + // type so it can inform user + if len(stdErrBuffer.Bytes()) > 0 { + fmt.Print("TODO: (stderrBuffer to client):", stdErrBuffer) + } } } } @@ -217,6 +226,7 @@ func runShellAs(who string, cmd string, interactive bool, conn hkexnet.Conn, cha // Investigate -- rlm 2018-01-26) os.Clearenv() os.Setenv("HOME", u.HomeDir) + //os.Setenv("SHELL", "/bin/bash") os.Setenv("TERM", "vt102") // TODO: server or client option? var c *exec.Cmd @@ -262,8 +272,9 @@ func runShellAs(who string, cmd string, interactive bool, conn hkexnet.Conn, cha _, e := io.Copy(ptmx, conn) if e != nil { log.Println("** stdin->pty ended **:", e.Error()) + } else { + log.Println("*** stdin->pty goroutine done ***") } - fmt.Println("*** stdin->pty goroutine done ***") }() if chaffing { @@ -284,10 +295,11 @@ func runShellAs(who string, cmd string, interactive bool, conn hkexnet.Conn, cha _, e := io.Copy(conn, ptmx) if e != nil { log.Println("** pty->stdout ended **:", e.Error()) + } else { + // The above io.Copy() will exit when the command attached + // to the pty exits + log.Println("*** pty->stdout goroutine done ***") } - // The above io.Copy() will exit when the command attached - // to the pty exits - fmt.Println("*** pty->stdout goroutine done ***") }() if err := c.Wait(); err != nil { @@ -486,8 +498,6 @@ func main() { } else if rec.op[0] == 'D' { // File copy (destination) operation - client copy to server log.Printf("[Client->Server copy]\n") - // TODO: call function with hc, rec.cmd, chaffEnabled etc. - // func hooks tar cmd right-half of pipe to hc Reader addr := hc.RemoteAddr() hname := strings.Split(addr.String(), ":")[0] log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname) @@ -499,13 +509,11 @@ func main() { log.Printf("[Error spawning cp for %s@%s]\n", rec.who, hname) } else { log.Printf("[Command completed for %s@%s, status %d]\n", rec.who, hname, cmdStatus) - hc.SetStatus(uint8(cmdStatus)) } + hc.SetStatus(uint8(cmdStatus)) } else if rec.op[0] == 'S' { // File copy (src) operation - server copy to client log.Printf("[Server->Client copy]\n") - // TODO: call function to copy rec.cmd (file list) to - // tar cmd left-half of pipeline to hc.Writer ? addr := hc.RemoteAddr() hname := strings.Split(addr.String(), ":")[0] log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname) @@ -517,10 +525,10 @@ func main() { log.Printf("[Error spawning cp for %s@%s]\n", rec.who, hname) } else { log.Printf("[Command completed for %s@%s, status %d]\n", rec.who, hname, cmdStatus) - hc.SetStatus(uint8(cmdStatus)) } + hc.SetStatus(uint8(cmdStatus)) // Signal other end transfer is complete - hc.WritePacket([]byte{byte(255)}, hkexnet.CSOExitStatus) + hc.WritePacket([]byte{byte(cmdStatus)}, hkexnet.CSOExitStatus) //fmt.Println("Waiting for EOF from other end.") //ackByte := make([]byte, 1, 1) _, _ = hc.Read(nil /*ackByte*/)