Fixed shell (interative & non-) exit status after cp status fixes

This commit is contained in:
Russ Magee 2018-09-06 00:16:44 -07:00
parent a6979298fd
commit db1b494d00
3 changed files with 51 additions and 40 deletions

View file

@ -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() == "<iface/addr info ...>: 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})
}
}
}
}

View file

@ -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 {

View file

@ -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 {