mirror of https://gogs.blitter.com/RLabs/xs
Added -u (user), -x (exec cmd) options, -d (dbg) for logging; detection of "-x -" for
stdin/pipeline commands.
This commit is contained in:
parent
39a0890346
commit
6fd8ac1519
|
@ -7,6 +7,8 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
hkex "blitter.com/herradurakex"
|
hkex "blitter.com/herradurakex"
|
||||||
|
@ -37,18 +39,27 @@ type cmdSpec struct {
|
||||||
func main() {
|
func main() {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
var dbg bool
|
||||||
var cAlg string
|
var cAlg string
|
||||||
var hAlg string
|
var hAlg string
|
||||||
var server string
|
var server string
|
||||||
|
var cmdStr string
|
||||||
|
var altUser string
|
||||||
isInteractive := false
|
isInteractive := false
|
||||||
|
|
||||||
flag.StringVar(&cAlg, "c", "C_AES_256", "cipher [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]")
|
flag.StringVar(&cAlg, "c", "C_AES_256", "cipher [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]")
|
||||||
flag.StringVar(&hAlg, "h", "H_SHA256", "hmac [\"H_SHA256\"]")
|
flag.StringVar(&hAlg, "h", "H_SHA256", "hmac [\"H_SHA256\"]")
|
||||||
flag.StringVar(&server, "s", "localhost:2000", "server hostname/address[:port]")
|
flag.StringVar(&server, "s", "localhost:2000", "server hostname/address[:port]")
|
||||||
|
flag.StringVar(&cmdStr, "x", "", "command to run (default empty - interactive shell)")
|
||||||
|
flag.StringVar(&altUser, "u", "", "specify alternate user")
|
||||||
|
flag.BoolVar(&dbg, "d", false, "debug logging")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
//log.SetOutput(os.Stdout)
|
if dbg {
|
||||||
log.SetOutput(ioutil.Discard)
|
log.SetOutput(os.Stdout)
|
||||||
|
} else {
|
||||||
|
log.SetOutput(ioutil.Discard)
|
||||||
|
}
|
||||||
|
|
||||||
conn, err := hkex.Dial("tcp", server, cAlg, hAlg)
|
conn, err := hkex.Dial("tcp", server, cAlg, hAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,8 +69,9 @@ func main() {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
// Set stdin in raw mode if it's an interactive session
|
// Set stdin in raw mode if it's an interactive session
|
||||||
|
// TODO: send flag to server side indicating this
|
||||||
|
// affects shell command used
|
||||||
if isatty.IsTerminal(os.Stdin.Fd()) {
|
if isatty.IsTerminal(os.Stdin.Fd()) {
|
||||||
isInteractive = true
|
|
||||||
oldState, err := MakeRaw(int(os.Stdin.Fd()))
|
oldState, err := MakeRaw(int(os.Stdin.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -69,9 +81,33 @@ func main() {
|
||||||
fmt.Println("NOT A TTY")
|
fmt.Println("NOT A TTY")
|
||||||
}
|
}
|
||||||
|
|
||||||
rec := &cmdSpec{op: []byte{'s'},
|
var uname string
|
||||||
who: []byte("ABCD"),
|
if len(altUser) == 0 {
|
||||||
cmd: []byte("EFGH"),
|
u, _ := user.Current()
|
||||||
|
uname = u.Username
|
||||||
|
} else {
|
||||||
|
uname = altUser
|
||||||
|
}
|
||||||
|
|
||||||
|
var op []byte
|
||||||
|
if len(cmdStr) == 0 {
|
||||||
|
op = []byte{'s'}
|
||||||
|
isInteractive = true
|
||||||
|
} else if cmdStr == "-" {
|
||||||
|
op = []byte{'c'}
|
||||||
|
cmdStdin, err := ioutil.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
cmdStr = strings.Trim(string(cmdStdin), "\r\n")
|
||||||
|
} else {
|
||||||
|
op = []byte{'c'}
|
||||||
|
}
|
||||||
|
|
||||||
|
rec := &cmdSpec{
|
||||||
|
op: op,
|
||||||
|
who: []byte(uname),
|
||||||
|
cmd: []byte(cmdStr),
|
||||||
authCookie: []byte("99"),
|
authCookie: []byte("99"),
|
||||||
status: 0}
|
status: 0}
|
||||||
|
|
||||||
|
@ -109,23 +145,25 @@ func main() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// client writer (to server) goroutine
|
if isInteractive {
|
||||||
wg.Add(1)
|
// client writer (to server) goroutine
|
||||||
go func() {
|
wg.Add(1)
|
||||||
defer wg.Done()
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
// io.Copy() expects EOF so this will
|
// io.Copy() expects EOF so this will
|
||||||
// exit with outerr == nil
|
// exit with outerr == nil
|
||||||
_, outerr := io.Copy(conn, os.Stdin)
|
_, outerr := io.Copy(conn, os.Stdin)
|
||||||
if outerr != nil {
|
if outerr != nil {
|
||||||
if outerr.Error() != "EOF" {
|
if outerr.Error() != "EOF" {
|
||||||
fmt.Println(outerr)
|
fmt.Println(outerr)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
log.Println("[Sent EOF]")
|
||||||
log.Println("[Sent EOF]")
|
wg.Done() // client hung up, close WaitGroup to exit client
|
||||||
wg.Done() // client hung up, close WaitGroup to exit client
|
}()
|
||||||
}()
|
}
|
||||||
|
|
||||||
// Wait until both stdin and stdout goroutines finish
|
// Wait until both stdin and stdout goroutines finish
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -15,24 +16,6 @@ import (
|
||||||
"github.com/kr/pty"
|
"github.com/kr/pty"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unused, probably obsolete. Once interactive session
|
|
||||||
// and piped I/O one-shot commands are working reconsider
|
|
||||||
// how Op might be used
|
|
||||||
const (
|
|
||||||
OpR = 'r' // read(file) (binary mode)
|
|
||||||
OpW = 'w' // (over)write
|
|
||||||
OpA = 'a' // append
|
|
||||||
OpRm = 'd' // rm
|
|
||||||
OpRmD = 'D' // rmdir (rm -rf)
|
|
||||||
OpM = 'm' // mkdir (-p)
|
|
||||||
OpN = 'n' // re(n)ame (mv)
|
|
||||||
OpCm = 'c' // chmod
|
|
||||||
OpCo = 'C' // chown
|
|
||||||
OpX = 'x' // exec
|
|
||||||
)
|
|
||||||
|
|
||||||
//type Op uint8
|
|
||||||
|
|
||||||
type cmdSpec struct {
|
type cmdSpec struct {
|
||||||
op []byte
|
op []byte
|
||||||
who []byte
|
who []byte
|
||||||
|
@ -89,12 +72,18 @@ func runCmdAs(who string, cmd string, conn hkex.Conn) (err error) {
|
||||||
// Listener and Conns. The KEx and encrypt/decrypt is done within the type.
|
// Listener and Conns. The KEx and encrypt/decrypt is done within the type.
|
||||||
// Compare to 'serverp.go' in this directory to see the equivalence.
|
// Compare to 'serverp.go' in this directory to see the equivalence.
|
||||||
func main() {
|
func main() {
|
||||||
|
var dbg bool
|
||||||
var laddr string
|
var laddr string
|
||||||
|
|
||||||
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen")
|
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen")
|
||||||
|
flag.BoolVar(&dbg, "d", false, "debug logging")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
log.SetOutput(os.Stdout /*ioutil.Discard*/)
|
if dbg {
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
|
} else {
|
||||||
|
log.SetOutput(ioutil.Discard)
|
||||||
|
}
|
||||||
|
|
||||||
// Listen on TCP port 2000 on all available unicast and
|
// Listen on TCP port 2000 on all available unicast and
|
||||||
// anycast IP addresses of the local system.
|
// anycast IP addresses of the local system.
|
||||||
|
@ -163,9 +152,17 @@ func main() {
|
||||||
fmt.Printf("[cmdSpec: op:%c who:%s cmd:%s auth:%s]\n",
|
fmt.Printf("[cmdSpec: op:%c who:%s cmd:%s auth:%s]\n",
|
||||||
rec.op[0], string(rec.who), string(rec.cmd), string(rec.authCookie))
|
rec.op[0], string(rec.who), string(rec.cmd), string(rec.authCookie))
|
||||||
|
|
||||||
if rec.op[0] == 's' {
|
if rec.op[0] == 'c' {
|
||||||
|
// Non-interactive command
|
||||||
|
fmt.Println("[Running command]")
|
||||||
|
runCmdAs(string(rec.who), string(rec.cmd), conn)
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
// Clear current op so user can enter next, or EOF
|
||||||
|
rec.op[0] = 0
|
||||||
|
fmt.Println("[Command complete]")
|
||||||
|
} else if rec.op[0] == 's' {
|
||||||
fmt.Println("[Running shell]")
|
fmt.Println("[Running shell]")
|
||||||
runCmdAs("larissa", "bash -l -i", conn)
|
runCmdAs(string(rec.who), "bash -l -i", conn)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
rec.op[0] = 0
|
rec.op[0] = 0
|
||||||
|
|
Loading…
Reference in New Issue