mirror of https://gogs.blitter.com/RLabs/xs
.hkexsh_id file supports multiple authtokens (multi remote hosts, aliases for same remote host)
This commit is contained in:
parent
d9b34fa631
commit
e02764bf4b
7
TODO.txt
7
TODO.txt
|
@ -20,9 +20,10 @@ Features
|
|||
- (IN PROGRESS) auth tokens to allow scripted hkexsh/hkexcp use
|
||||
* ~/.hkexsh_id file with multiple (host:token) entries
|
||||
(Currently only one supported - need to support multiple lines for
|
||||
multiple dest servers; also consider client sending host/ip used
|
||||
to connect to server, so it can ensure the auth token matches that
|
||||
used as servers can potentially be reached by multiple hostnames/IPs)
|
||||
multiple dest servers; client sends host/ip used to connect to server,
|
||||
so multihomed servers can still be specified, with separate entries
|
||||
stored in both server/client ~/.hkexsh_id files. Use connhost here to
|
||||
match against proper entry.)
|
||||
- hktun - tunnelling - multiple tunnel sessions co-existing w/shell sessions
|
||||
|
||||
Alternate transports for hkexsh.Conn - HTTP-mimicking traffic, ICMP, ... ?
|
||||
|
|
23
hkexauth.go
23
hkexauth.go
|
@ -17,6 +17,7 @@ import (
|
|||
"log"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/jameskeane/bcrypt"
|
||||
)
|
||||
|
@ -69,6 +70,7 @@ func AuthUserByPasswd(username string, auth string, fname string) (valid bool, a
|
|||
}
|
||||
|
||||
func AuthUserByToken(username string, connhostname string, auth string) (valid bool) {
|
||||
auth = strings.TrimSpace(auth)
|
||||
u, ue := user.Lookup(username)
|
||||
if ue != nil {
|
||||
return false
|
||||
|
@ -80,8 +82,25 @@ func AuthUserByToken(username string, connhostname string, auth string) (valid b
|
|||
return false
|
||||
}
|
||||
|
||||
if string(b) == auth {
|
||||
return true
|
||||
r := csv.NewReader(bytes.NewReader(b))
|
||||
|
||||
r.Comma = ':'
|
||||
r.Comment = '#'
|
||||
r.FieldsPerRecord = 2 // connhost:authtoken
|
||||
for {
|
||||
record, err := r.Read()
|
||||
if err == io.EOF {
|
||||
return false
|
||||
}
|
||||
record[0] = strings.TrimSpace(record[0])
|
||||
record[1] = strings.TrimSpace(record[1])
|
||||
fmt.Println("auth:", auth, "record:",
|
||||
strings.Join([]string{record[0], record[1]}, ":"))
|
||||
|
||||
if (connhostname == record[0]) &&
|
||||
(auth == strings.Join([]string{record[0], record[1]}, ":")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -320,7 +320,8 @@ func rejectUserMsg() string {
|
|||
func main() {
|
||||
version := "0.2pre (NO WARRANTY)"
|
||||
var vopt bool
|
||||
var aopt bool
|
||||
var aopt bool //login using authToken
|
||||
var gopt bool //login via password, asking server to generate authToken
|
||||
var dbg bool
|
||||
var shellMode bool // if true act as shell, else file copier
|
||||
var cAlg string
|
||||
|
@ -358,7 +359,8 @@ func main() {
|
|||
// hkexsh accepts a command (-x) but not
|
||||
// a srcpath (-r) or dstpath (-t)
|
||||
flag.StringVar(&cmdStr, "x", "", "`command` to run (if not specified run interactive shell)")
|
||||
flag.BoolVar(&aopt, "a", false, "return autologin token from server")
|
||||
flag.BoolVar(&aopt, "a", false, "login using auth token")
|
||||
flag.BoolVar(&gopt, "g", false, "ask server to generate authtoken")
|
||||
shellMode = true
|
||||
flag.Usage = UsageShell
|
||||
} else {
|
||||
|
@ -445,20 +447,44 @@ func main() {
|
|||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
// See if we can log in via an auth token
|
||||
u, _ := user.Current()
|
||||
ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.hkexsh_id", u.HomeDir))
|
||||
if aerr == nil {
|
||||
authCookie = string(ab)
|
||||
// Security scrub
|
||||
ab = nil
|
||||
runtime.GC()
|
||||
if aopt && gopt {
|
||||
fmt.Fprintln(os.Stderr,
|
||||
"Error: use -g first to generate an authtoken,",
|
||||
" then -a to login using it.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !gopt {
|
||||
// See if we can log in via an auth token
|
||||
u, _ := user.Current()
|
||||
ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.hkexsh_id", u.HomeDir))
|
||||
if aerr == nil {
|
||||
//authCookie = string(ab)
|
||||
idx := strings.Index(string(ab), remoteHost)
|
||||
if idx >= 0 {
|
||||
ab = ab[idx:]
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, "ERROR: no matching authtoken")
|
||||
os.Exit(1)
|
||||
}
|
||||
entries := strings.SplitN(string(ab), "\n", -1)
|
||||
//if len(entries) > 0 {
|
||||
fmt.Println("entries[0]:", entries[0])
|
||||
authCookie = strings.TrimSpace(entries[0])
|
||||
//} else {
|
||||
// fmt.Fprintln(os.Stderr, "ERROR: no matching authtoken")
|
||||
// os.Exit(1)
|
||||
//}
|
||||
// Security scrub
|
||||
ab = nil
|
||||
runtime.GC()
|
||||
}
|
||||
}
|
||||
|
||||
if shellMode {
|
||||
// We must make the decision about interactivity before Dial()
|
||||
// as it affects chaffing behaviour. 20180805
|
||||
if aopt {
|
||||
if gopt {
|
||||
op = []byte{'A'}
|
||||
chaffFreqMin = 2
|
||||
chaffFreqMax = 10
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -106,7 +107,8 @@ func runClientToServerCopyAs(who, ttype string, conn hkexnet.Conn, fpath string,
|
|||
// an ExitStatus() method with the same signature.
|
||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
exitStatus = uint32(status.ExitStatus())
|
||||
log.Printf("Exit Status: %d", exitStatus)
|
||||
err = errors.New("cmd returned nonzero status")
|
||||
fmt.Printf("Exit Status: %d\n", exitStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,7 +497,7 @@ func main() {
|
|||
hname := strings.Split(addr.String(), ":")[0]
|
||||
log.Printf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)
|
||||
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
|
||||
tokenCmd := fmt.Sprintf("echo \"%s\" | tee ~/.hkexsh_id", token)
|
||||
tokenCmd := fmt.Sprintf("echo \"%s\" | tee -a ~/.hkexsh_id", token)
|
||||
runErr, cmdStatus := runShellAs(string(rec.Who()), string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
||||
// Returned hopefully via an EOF or exit/logout;
|
||||
// Clear current op so user can enter next, or EOF
|
||||
|
@ -554,10 +556,11 @@ func main() {
|
|||
// Clear current op so user can enter next, or EOF
|
||||
rec.SetOp([]byte{0})
|
||||
if runErr != nil {
|
||||
log.Printf("[Error spawning cp for %s@%s]\n", rec.Who(), hname)
|
||||
log.Printf("[Error running cp for %s@%s]\n", rec.Who(), hname)
|
||||
} else {
|
||||
log.Printf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
|
||||
}
|
||||
fmt.Println("cmdStatus:", cmdStatus)
|
||||
hc.SetStatus(cmdStatus)
|
||||
} else if rec.Op()[0] == 'S' {
|
||||
// File copy (src) operation - server copy to client
|
||||
|
|
Loading…
Reference in New Issue