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