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