mirror of
https://gogs.blitter.com/RLabs/xs
synced 2024-08-14 10:26:42 +00:00
WIP: server->client copy primitively functional; TODO client->server copy
This commit is contained in:
parent
0b9b8b8320
commit
7867f84b87
2 changed files with 124 additions and 30 deletions
101
hkexsh/hkexsh.go
101
hkexsh/hkexsh.go
|
@ -19,6 +19,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
hkexsh "blitter.com/go/hkexsh"
|
hkexsh "blitter.com/go/hkexsh"
|
||||||
"blitter.com/go/hkexsh/hkexnet"
|
"blitter.com/go/hkexsh/hkexnet"
|
||||||
|
@ -101,17 +102,101 @@ func parseNonSwitchArgs(a []string, dp string) (user, host, port, path string, i
|
||||||
}
|
}
|
||||||
|
|
||||||
// doCopyMode begins a secure hkexsh local<->remote file copy operation.
|
// doCopyMode begins a secure hkexsh local<->remote file copy operation.
|
||||||
func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, recurs bool, rec *cmdSpec) {
|
func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, recurs bool, rec *cmdSpec) (err error, exitStatus int) {
|
||||||
// TODO: Bring in runShellAs(), stripped down, from hkexshd
|
|
||||||
// and build either side of tar pipeline: names?
|
|
||||||
// runTarSrc(), runTarSink() ?
|
|
||||||
if remoteDest {
|
if remoteDest {
|
||||||
fmt.Println("local files:", files, "remote filepath:", string(rec.cmd))
|
fmt.Println("local files:", files, "remote filepath:", string(rec.cmd))
|
||||||
fmt.Fprintf(conn, "copyMode remoteDest TODO\n")
|
fmt.Fprintf(conn, "copyMode remoteDest ...\n")
|
||||||
|
|
||||||
|
var c *exec.Cmd
|
||||||
|
|
||||||
|
//os.Clearenv()
|
||||||
|
//os.Setenv("HOME", u.HomeDir)
|
||||||
|
//os.Setenv("TERM", "vt102") // TODO: server or client option?
|
||||||
|
|
||||||
|
cmdName := "/bin/tar"
|
||||||
|
cmdArgs := []string{"-cz", "-f", "/dev/stdout", files}
|
||||||
|
fmt.Printf("[%v %v]\n", cmdName, cmdArgs)
|
||||||
|
// NOTE the lack of quotes around --xform option's sed expression.
|
||||||
|
// When args are passed in exec() format, no quoting is required
|
||||||
|
// (as this isn't input from a shell) (right? -rlm 20180823)
|
||||||
|
//cmdArgs := []string{"-xvz", "-C", files, `--xform=s#.*/\(.*\)#\1#`}
|
||||||
|
c = exec.Command(cmdName, cmdArgs...)
|
||||||
|
c.Stdout = conn
|
||||||
|
|
||||||
|
// Start the command (no pty)
|
||||||
|
err = c.Start() // returns immediately
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
//log.Fatal(err)
|
||||||
|
} else {
|
||||||
|
if err = c.Wait(); err != nil {
|
||||||
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||||
|
// The program has exited with an exit code != 0
|
||||||
|
|
||||||
|
// This works on both Unix and Windows. Although package
|
||||||
|
// syscall is generally platform dependent, WaitStatus is
|
||||||
|
// defined for both Unix and Windows and in both cases has
|
||||||
|
// an ExitStatus() method with the same signature.
|
||||||
|
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||||
|
exitStatus = status.ExitStatus()
|
||||||
|
log.Printf("Exit Status: %d", exitStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("*** client->server cp finished ***")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("remote filepath:", string(rec.cmd), "local files:", files)
|
fmt.Println("remote filepath:", string(rec.cmd), "local files:", files)
|
||||||
fmt.Fprintf(conn, "copyMode localDest TODO\n")
|
fmt.Fprintf(conn, "copyMode localDest ...\n")
|
||||||
|
var c *exec.Cmd
|
||||||
|
|
||||||
|
//os.Clearenv()
|
||||||
|
//os.Setenv("HOME", u.HomeDir)
|
||||||
|
//os.Setenv("TERM", "vt102") // TODO: server or client option?
|
||||||
|
|
||||||
|
cmdName := "/bin/tar"
|
||||||
|
destPath := files
|
||||||
|
//if path.IsAbs(files) {
|
||||||
|
// destPath := files
|
||||||
|
//} else {
|
||||||
|
// destPath := strings.Join({os.Getenv("PWD"),files}, os.PathSeparator)
|
||||||
|
//}
|
||||||
|
|
||||||
|
cmdArgs := []string{"-xvz", "-C", destPath}
|
||||||
|
fmt.Printf("[%v %v]\n", cmdName, cmdArgs)
|
||||||
|
// NOTE the lack of quotes around --xform option's sed expression.
|
||||||
|
// When args are passed in exec() format, no quoting is required
|
||||||
|
// (as this isn't input from a shell) (right? -rlm 20180823)
|
||||||
|
//cmdArgs := []string{"-xvz", "-C", destPath, `--xform=s#.*/\(.*\)#\1#`}
|
||||||
|
c = exec.Command(cmdName, cmdArgs...)
|
||||||
|
c.Stdin = conn
|
||||||
|
c.Stdout = os.Stdout
|
||||||
|
c.Stderr = os.Stderr
|
||||||
|
|
||||||
|
// Start the command (no pty)
|
||||||
|
err = c.Start() // returns immediately
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
//log.Fatal(err)
|
||||||
|
} else {
|
||||||
|
if err = c.Wait(); err != nil {
|
||||||
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||||
|
// The program has exited with an exit code != 0
|
||||||
|
|
||||||
|
// This works on both Unix and Windows. Although package
|
||||||
|
// syscall is generally platform dependent, WaitStatus is
|
||||||
|
// defined for both Unix and Windows and in both cases has
|
||||||
|
// an ExitStatus() method with the same signature.
|
||||||
|
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||||
|
exitStatus = status.ExitStatus()
|
||||||
|
log.Printf("Exit Status: %d", exitStatus)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("*** server->client cp finished ***")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// doShellMode begins an hkexsh shell session (one-shot command or interactive).
|
// doShellMode begins an hkexsh shell session (one-shot command or interactive).
|
||||||
|
@ -256,7 +341,7 @@ func main() {
|
||||||
// -else flatten otherArgs into space-delim list => copySrc
|
// -else flatten otherArgs into space-delim list => copySrc
|
||||||
if pathIsDest {
|
if pathIsDest {
|
||||||
if len(otherArgs) == 0 {
|
if len(otherArgs) == 0 {
|
||||||
log.Fatal("ERROR: Must specify at least one src path for copy")
|
log.Fatal("ERROR: Must specify at least one dest path for copy")
|
||||||
} else {
|
} else {
|
||||||
for _, v := range otherArgs {
|
for _, v := range otherArgs {
|
||||||
copySrc = append(copySrc, ' ')
|
copySrc = append(copySrc, ' ')
|
||||||
|
@ -267,7 +352,7 @@ func main() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(otherArgs) == 0 {
|
if len(otherArgs) == 0 {
|
||||||
log.Fatal("ERROR: Must specify dest path for copy")
|
log.Fatal("ERROR: Must specify src path for copy")
|
||||||
} else if len(otherArgs) == 1 {
|
} else if len(otherArgs) == 1 {
|
||||||
copyDst = otherArgs[0]
|
copyDst = otherArgs[0]
|
||||||
if strings.Contains(copyDst, "*") || strings.Contains(copyDst, "?") {
|
if strings.Contains(copyDst, "*") || strings.Contains(copyDst, "?") {
|
||||||
|
|
|
@ -61,7 +61,8 @@ func runClientToServerCopyAs(who string, conn hkexnet.Conn, destPath string, cha
|
||||||
// NOTE the lack of quotes around --xform option's sed expression.
|
// NOTE the lack of quotes around --xform option's sed expression.
|
||||||
// When args are passed in exec() format, no quoting is required
|
// When args are passed in exec() format, no quoting is required
|
||||||
// (as this isn't input from a shell) (right? -rlm 20180823)
|
// (as this isn't input from a shell) (right? -rlm 20180823)
|
||||||
cmdArgs := []string{"-xzv", "-C", destPath, `--xform=s#.*/\(.*\)#\1#`}
|
cmdArgs := []string{"-xvz", "-C", destPath}
|
||||||
|
//cmdArgs := []string{"-xvz", "-C", destPath, `--xform=s#.*/\(.*\)#\1#`}
|
||||||
c = exec.Command(cmdName, cmdArgs...)
|
c = exec.Command(cmdName, cmdArgs...)
|
||||||
|
|
||||||
//If os.Clearenv() isn't called by server above these will be seen in the
|
//If os.Clearenv() isn't called by server above these will be seen in the
|
||||||
|
@ -71,8 +72,14 @@ func runClientToServerCopyAs(who string, conn hkexnet.Conn, destPath string, cha
|
||||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
||||||
c.Stdin = conn
|
c.Stdin = conn
|
||||||
c.Stdout = conn
|
//c.Stdout = conn
|
||||||
c.Stderr = conn
|
//c.Stderr = conn
|
||||||
|
|
||||||
|
if chaffing {
|
||||||
|
conn.EnableChaff()
|
||||||
|
}
|
||||||
|
defer conn.DisableChaff()
|
||||||
|
defer conn.ShutdownChaff()
|
||||||
|
|
||||||
// Start the command (no pty)
|
// Start the command (no pty)
|
||||||
log.Printf("[%v %v]\n", cmdName, cmdArgs)
|
log.Printf("[%v %v]\n", cmdName, cmdArgs)
|
||||||
|
@ -81,12 +88,6 @@ func runClientToServerCopyAs(who string, conn hkexnet.Conn, destPath string, cha
|
||||||
log.Printf("Command finished with error: %v", err)
|
log.Printf("Command finished with error: %v", err)
|
||||||
return err, 253 // !?
|
return err, 253 // !?
|
||||||
} else {
|
} else {
|
||||||
if chaffing {
|
|
||||||
conn.EnableChaff()
|
|
||||||
}
|
|
||||||
defer conn.DisableChaff()
|
|
||||||
defer conn.ShutdownChaff()
|
|
||||||
|
|
||||||
if err := c.Wait(); err != nil {
|
if err := c.Wait(); err != nil {
|
||||||
fmt.Println("*** c.Wait() done ***")
|
fmt.Println("*** c.Wait() done ***")
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||||
|
@ -102,8 +103,9 @@ func runClientToServerCopyAs(who string, conn hkexnet.Conn, destPath string, cha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
fmt.Println("*** client->server cp finished ***")
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a server->client copy
|
// Perform a server->client copy
|
||||||
|
@ -136,10 +138,16 @@ func runServerToClientCopyAs(who string, conn hkexnet.Conn, srcPath string, chaf
|
||||||
c.Dir = u.HomeDir
|
c.Dir = u.HomeDir
|
||||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
|
||||||
c.Stdin = conn
|
|
||||||
c.Stdout = conn
|
c.Stdout = conn
|
||||||
c.Stderr = conn
|
c.Stderr = conn
|
||||||
|
|
||||||
|
if chaffing {
|
||||||
|
conn.EnableChaff()
|
||||||
|
}
|
||||||
|
//defer conn.Close()
|
||||||
|
defer conn.DisableChaff()
|
||||||
|
defer conn.ShutdownChaff()
|
||||||
|
|
||||||
// Start the command (no pty)
|
// Start the command (no pty)
|
||||||
log.Printf("[%v %v]\n", cmdName, cmdArgs)
|
log.Printf("[%v %v]\n", cmdName, cmdArgs)
|
||||||
err = c.Start() // returns immediately
|
err = c.Start() // returns immediately
|
||||||
|
@ -147,12 +155,6 @@ func runServerToClientCopyAs(who string, conn hkexnet.Conn, srcPath string, chaf
|
||||||
log.Printf("Command finished with error: %v", err)
|
log.Printf("Command finished with error: %v", err)
|
||||||
return err, 253 // !?
|
return err, 253 // !?
|
||||||
} else {
|
} else {
|
||||||
if chaffing {
|
|
||||||
conn.EnableChaff()
|
|
||||||
}
|
|
||||||
defer conn.DisableChaff()
|
|
||||||
defer conn.ShutdownChaff()
|
|
||||||
|
|
||||||
if err := c.Wait(); err != nil {
|
if err := c.Wait(); err != nil {
|
||||||
fmt.Println("*** c.Wait() done ***")
|
fmt.Println("*** c.Wait() done ***")
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||||
|
@ -168,8 +170,9 @@ func runServerToClientCopyAs(who string, conn hkexnet.Conn, srcPath string, chaf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
fmt.Println("*** server->client cp finished ***")
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a command (via default shell) as a specific user
|
// Run a command (via default shell) as a specific user
|
||||||
|
@ -467,10 +470,13 @@ func main() {
|
||||||
hname := strings.Split(addr.String(), ":")[0]
|
hname := strings.Split(addr.String(), ":")[0]
|
||||||
log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname)
|
log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname)
|
||||||
runErr, cmdStatus := runClientToServerCopyAs(string(rec.who), hc, string(rec.cmd), chaffEnabled)
|
runErr, cmdStatus := runClientToServerCopyAs(string(rec.who), hc, string(rec.cmd), chaffEnabled)
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
// Clear current op so user can enter next, or EOF
|
||||||
|
rec.op[0] = 0
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
log.Printf("[Error spawning shell for %s@%s]\n", rec.who, hname)
|
log.Printf("[Error spawning cp for %s@%s]\n", rec.who, hname)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[Shell completed for %s@%s, status %d]\n", rec.who, hname, cmdStatus)
|
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' {
|
} else if rec.op[0] == 'S' {
|
||||||
|
@ -482,10 +488,13 @@ func main() {
|
||||||
hname := strings.Split(addr.String(), ":")[0]
|
hname := strings.Split(addr.String(), ":")[0]
|
||||||
log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname)
|
log.Printf("[Running copy for [%s@%s]]\n", rec.who, hname)
|
||||||
runErr, cmdStatus := runServerToClientCopyAs(string(rec.who), hc, string(rec.cmd), chaffEnabled)
|
runErr, cmdStatus := runServerToClientCopyAs(string(rec.who), hc, string(rec.cmd), chaffEnabled)
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
// Clear current op so user can enter next, or EOF
|
||||||
|
rec.op[0] = 0
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
log.Printf("[Error spawning shell for %s@%s]\n", rec.who, hname)
|
log.Printf("[Error spawning cp for %s@%s]\n", rec.who, hname)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[Shell completed for %s@%s, status %d]\n", rec.who, hname, cmdStatus)
|
log.Printf("[Command completed for %s@%s, status %d]\n", rec.who, hname, cmdStatus)
|
||||||
hc.SetStatus(uint8(cmdStatus))
|
hc.SetStatus(uint8(cmdStatus))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue