From db1b494d00428c05d2a6a6c4a8824832fe8407e4 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Thu, 6 Sep 2018 00:16:44 -0700 Subject: [PATCH] Fixed shell (interative & non-) exit status after cp status fixes --- hkexnet/hkexnet.go | 69 ++++++++++++++++++++++++---------------------- hkexsh/hkexsh.go | 15 +++++++--- hkexshd/hkexshd.go | 7 +++-- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index bb5377f..c5c7269 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -77,7 +77,7 @@ type ( chaff ChaffConfig - closeStat *uint8 // close status (shell exit status: UNIX uint8) + closeStat *uint8 // close status r cipher.Stream //read cipherStream rm hash.Hash w cipher.Stream //write cipherStream @@ -213,7 +213,6 @@ func Dial(protocol string, ipport string, extensions ...string) (hc *Conn, err e func (hc *Conn) Close() (err error) { hc.DisableChaff() hc.WritePacket([]byte{byte(*hc.closeStat)}, CSOExitStatus) - *hc.closeStat = 0 err = hc.c.Close() log.Println("[Conn Closing]") return @@ -379,8 +378,10 @@ func (hc Conn) Read(b []byte) (n int, err error) { // (on server side) err.Error() == ": use of closed network connection" if err != nil { if !strings.HasSuffix(err.Error(), "use of closed network connection") { + //fmt.Println("[1]unexpected Read() err:", err) log.Println("[1]unexpected Read() err:", err) } else { + //fmt.Println("[Client hung up]") log.Println("[Client hung up]") } return 0, err @@ -424,45 +425,47 @@ func (hc Conn) Read(b []byte) (n int, err error) { decryptN, err := rs.Read(payloadBytes) log.Printf(" <-ptext:\r\n%s\r\n", hex.Dump(payloadBytes[:n])) if err != nil { - panic(err) - } + //fmt.Print(err) + //panic(err) + } else { - // Throw away pkt if it's chaff (ie., caller to Read() won't see this data) - if ctrlStatOp == CSOChaff { - log.Printf("[Chaff pkt, discarded (len %d)]\n", decryptN) - } else if ctrlStatOp == CSOTermSize { - fmt.Sscanf(string(payloadBytes), "%d %d", &hc.Rows, &hc.Cols) - log.Printf("[TermSize pkt: rows %v cols %v]\n", hc.Rows, hc.Cols) - hc.WinCh <- WinSize{hc.Rows, hc.Cols} - } else if ctrlStatOp == CSOExitStatus { - if len(payloadBytes) > 0 { - *hc.closeStat = uint8(payloadBytes[0]) - // If remote end is closing with an error, reply we're closing ours - if payloadBytes[0] != 0 { + // Throw away pkt if it's chaff (ie., caller to Read() won't see this data) + if ctrlStatOp == CSOChaff { + log.Printf("[Chaff pkt, discarded (len %d)]\n", decryptN) + } else if ctrlStatOp == CSOTermSize { + fmt.Sscanf(string(payloadBytes), "%d %d", &hc.Rows, &hc.Cols) + log.Printf("[TermSize pkt: rows %v cols %v]\n", hc.Rows, hc.Cols) + hc.WinCh <- WinSize{hc.Rows, hc.Cols} + } else if ctrlStatOp == CSOExitStatus { + if len(payloadBytes) > 0 { hc.SetStatus(payloadBytes[0]) + //!// If remote end is closing with an error, reply we're closing ours + //!if hc.GetStatus() != 0 { + //! log.Print("CSOExitStatus:", hc.GetStatus()) hc.Close() + //!} + } else { + log.Println("[truncated payload, cannot determine CSOExitStatus]") + *hc.closeStat = 98 } } else { - log.Println("[truncated payload, cannot determine CSOExitStatus]") - *hc.closeStat = 98 + hc.dBuf.Write(payloadBytes) + //log.Printf("hc.dBuf: %s\n", hex.Dump(hc.dBuf.Bytes())) } - } else { - hc.dBuf.Write(payloadBytes) - //log.Printf("hc.dBuf: %s\n", hex.Dump(hc.dBuf.Bytes())) - } - // Re-calculate hmac, compare with received value - hc.rm.Write(payloadBytes) - hTmp := hc.rm.Sum(nil)[0:4] - log.Printf("<%04x) HMAC:(i)%s (c)%02x\r\n", decryptN, hex.EncodeToString([]byte(hmacIn[0:])), hTmp) + // Re-calculate hmac, compare with received value + hc.rm.Write(payloadBytes) + hTmp := hc.rm.Sum(nil)[0:4] + log.Printf("<%04x) HMAC:(i)%s (c)%02x\r\n", decryptN, hex.EncodeToString([]byte(hmacIn[0:])), hTmp) - if *hc.closeStat > 90 { - log.Println("[cannot verify HMAC]") - } else { - // Log alert if hmac didn't match, corrupted channel - if !bytes.Equal(hTmp, []byte(hmacIn[0:])) /*|| hmacIn[0] > 0xf8*/ { - fmt.Println("** ALERT - detected HMAC mismatch, possible channel tampering **") - _, _ = hc.c.Write([]byte{CSOHmacInvalid}) + if *hc.closeStat > 90 { + log.Println("[cannot verify HMAC]") + } else { + // Log alert if hmac didn't match, corrupted channel + if !bytes.Equal(hTmp, []byte(hmacIn[0:])) /*|| hmacIn[0] > 0xf8*/ { + fmt.Println("** ALERT - detected HMAC mismatch, possible channel tampering **") + _, _ = hc.c.Write([]byte{CSOHmacInvalid}) + } } } } diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index bfc5e6c..15d2124 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -169,7 +169,7 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *cmdSpec) } //fmt.Println("*** client->server cp finished ***") // Signal other end transfer is complete - conn.WritePacket([]byte{byte(rec.status)}, hkexnet.CSOExitStatus) + conn.WritePacket([]byte{byte( /*255*/ rec.status)}, hkexnet.CSOExitStatus) _, _ = conn.Read(nil /*ackByte*/) } } else { @@ -214,6 +214,11 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *cmdSpec) } } } + // return local status, if nonzero; + // otherwise, return remote status if nonzero + if exitStatus == 0 { + exitStatus = int(conn.GetStatus()) + } //fmt.Println("*** server->client cp finished ***") } } @@ -235,9 +240,11 @@ func doShellMode(isInteractive bool, conn *hkexnet.Conn, oldState *hkexsh.State, // exit with inerr == nil _, inerr := io.Copy(os.Stdout, conn) if inerr != nil { - fmt.Println(inerr) _ = hkexsh.Restore(int(os.Stdin.Fd()), oldState) // Best effort. - os.Exit(1) + if !strings.HasSuffix(inerr.Error(), "use of closed network connection") { + log.Println(inerr) + os.Exit(1) + } } rec.status = int(conn.GetStatus()) @@ -531,7 +538,7 @@ func main() { if shellMode { doShellMode(isInteractive, conn, oldState, rec) } else { - doCopyMode(conn, pathIsDest, fileArgs, rec) + _, rec.status = doCopyMode(conn, pathIsDest, fileArgs, rec) } if oldState != nil { diff --git a/hkexshd/hkexshd.go b/hkexshd/hkexshd.go index 4e02c09..8d12527 100755 --- a/hkexshd/hkexshd.go +++ b/hkexshd/hkexshd.go @@ -315,7 +315,8 @@ func runShellAs(who string, cmd string, interactive bool, conn hkexnet.Conn, cha exitStatus = status.ExitStatus() log.Printf("Exit Status: %d", exitStatus) } - } + } + conn.SetStatus(uint8(exitStatus)) } wg.Wait() // Wait on pty->stdout completion to client } @@ -518,6 +519,7 @@ func main() { hname := strings.Split(addr.String(), ":")[0] log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname) runErr, cmdStatus := runServerToClientCopyAs(string(rec.who), hc, string(rec.cmd), chaffEnabled) + //fmt.Print("ServerToClient cmdStatus:", cmdStatus) // Returned hopefully via an EOF or exit/logout; // Clear current op so user can enter next, or EOF rec.op[0] = 0 @@ -528,9 +530,8 @@ func main() { } hc.SetStatus(uint8(cmdStatus)) // Signal other end transfer is complete - hc.WritePacket([]byte{byte(cmdStatus)}, hkexnet.CSOExitStatus) + hc.WritePacket([]byte{byte(/*255*/cmdStatus)}, hkexnet.CSOExitStatus) //fmt.Println("Waiting for EOF from other end.") - //ackByte := make([]byte, 1, 1) _, _ = hc.Read(nil /*ackByte*/) //fmt.Println("Got remote end ack.") } else {