Browse Source

Fixes for file ownership creating ~/.xs_id
Added username field to authToken to allow token-based login to other users

Signed-off-by: Russ Magee <rmagee@gmail.com>

Russ Magee 8 months ago
parent
commit
83cd38c651
9 changed files with 676 additions and 473 deletions
  1. 1 1
      Makefile
  2. 14 7
      auth.go
  3. 2 2
      auth_test.go
  4. BIN
      xs/xs-vis-fixedup.png
  5. 282 253
      xs/xs-vis.gv
  6. 15 9
      xs/xs.go
  7. BIN
      xsd/xsd-vis-fixedup.png
  8. 339 182
      xsd/xsd-vis.gv
  9. 23 19
      xsd/xsd.go

+ 1 - 1
Makefile

@@ -1,4 +1,4 @@
-VERSION := 0.9.2
+VERSION := 0.9.3-pre
 .PHONY: lint vis clean common client server passwd subpkgs install uninstall reinstall
 
 ## Tag version of binaries with build info wrt.

+ 14 - 7
auth.go

@@ -182,19 +182,27 @@ func AuthUserByToken(ctx *AuthCtx, username string, connhostname string, auth st
 
 	r.Comma = ':'
 	r.Comment = '#'
-	r.FieldsPerRecord = 2 // connhost:authtoken
+	r.FieldsPerRecord = 3 // connhost:username:authtoken
 	for {
 		record, err := r.Read()
 		if err == io.EOF {
 			return false
 		}
+		if len(record) < 3 ||
+			len(record[0]) < 1 ||
+			len(record[1]) < 1 ||
+			len(record[2]) < 1 {
+			return false
+		}
 		record[0] = strings.TrimSpace(record[0])
 		record[1] = strings.TrimSpace(record[1])
+		record[2] = strings.TrimSpace(record[2])
 		//fmt.Println("auth:", auth, "record:",
-		//	strings.Join([]string{record[0], record[1]}, ":"))
+		//	strings.Join([]string{record[0], record[1], record[2]}, ":"))
 
 		if (connhostname == record[0]) &&
-			(auth == strings.Join([]string{record[0], record[1]}, ":")) {
+			username == record[1] &&
+			(auth == strings.Join([]string{record[0], record[1], record[2]}, ":")) {
 			valid = true
 			break
 		}
@@ -207,21 +215,20 @@ func AuthUserByToken(ctx *AuthCtx, username string, connhostname string, auth st
 }
 
 func GetTool(tool string) (ret string) {
-	ret = "/bin/"+tool
+	ret = "/bin/" + tool
 	_, err := os.Stat(ret)
 	if err == nil {
 		return ret
 	}
-	ret = "/usr/bin/"+tool
+	ret = "/usr/bin/" + tool
 	_, err = os.Stat(ret)
 	if err == nil {
 		return ret
 	}
-	ret = "/usr/local/bin/"+tool
+	ret = "/usr/local/bin/" + tool
 	_, err = os.Stat(ret)
 	if err == nil {
 		return ret
 	}
 	return ""
 }
-

+ 2 - 2
auth_test.go

@@ -19,7 +19,7 @@ var (
 joebloggs:$6$F.0IXOrb0w0VJHG1$3O4PYyng7F3hlh42mbroEdQZvslybY5etPPiLMQJ1xosjABY.Q4xqAfyIfe03Du61ZjGQIt3nL0j12P9k1fsK/:18310:0:99999:7:::
 disableduser:!:18310::::::`
 
-	dummyAuthTokenFile = "hostA:abcdefg\nhostB:wxyz\n"
+	dummyAuthTokenFile = "hostA:johndoe:abcdefg\nhostB:imposter:wxyz\n"
 
 	dummyXsPasswdFile = `#username:salt:authCookie
 bobdobbs:$2a$12$9vqGkFqikspe/2dTARqu1O:$2a$12$9vqGkFqikspe/2dTARqu1OuDKCQ/RYWsnaFjmi.HtmECRkxcZ.kBK
@@ -155,7 +155,7 @@ func TestAuthUserByTokenSucceedsWithMatchedUserAndToken(t *testing.T) {
 	ctx := newMockAuthCtx(_mock_ioutil_ReadFile, _mock_user_Lookup)
 	userlookup_arg_u = "johndoe"
 	readfile_arg_f = "/.xs_id"
-	stat := AuthUserByToken(ctx, userlookup_arg_u, "hostA", "hostA:abcdefg")
+	stat := AuthUserByToken(ctx, userlookup_arg_u, "hostA", "hostA:johndoe:abcdefg")
 	if !stat {
 		t.Fatal("failed with valid user and token")
 	}

BIN
xs/xs-vis-fixedup.png


File diff suppressed because it is too large
+ 282 - 253
xs/xs-vis.gv


+ 15 - 9
xs/xs.go

@@ -855,21 +855,27 @@ func main() {
 		u, _ := user.Current() // nolint: gosec
 		ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir))
 		if aerr == nil {
-			idx := strings.Index(string(ab), remoteHost)
-			if idx >= 0 {
-				ab = ab[idx:]
-				entries := strings.SplitN(string(ab), "\n", -1)
-				authCookie = strings.TrimSpace(entries[0])
-				// Security scrub
-				ab = nil
-				runtime.GC()
-			} else {
+			for _, line := range strings.Split(string(ab), "\n") {
+				line = line + "\n"
+				idx := strings.Index(string(line), remoteHost+":"+uname)
+				if idx >= 0 {
+					line = line[idx:]
+					entries := strings.SplitN(string(line), "\n", -1)
+					authCookie = strings.TrimSpace(entries[0])
+					// Security scrub
+					line = ""
+					break
+				}
+			}
+			if authCookie == "" {
 				_, _ = fmt.Fprintln(os.Stderr, "[no authtoken, use -g to request one from server]")
 			}
+
 		} else {
 			log.Printf("[cannot read %s/.xs_id]\n", u.HomeDir)
 		}
 	}
+	runtime.GC()
 
 	//=== Enforce some sane min/max vals on chaff flags
 	if chaffFreqMin < 2 {

BIN
xsd/xsd-vis-fixedup.png


File diff suppressed because it is too large
+ 339 - 182
xsd/xsd-vis.gv


+ 23 - 19
xsd/xsd.go

@@ -82,7 +82,7 @@ func runClientToServerCopyAs(who, ttype string, conn *xsnet.Conn, fpath string,
 	os.Clearenv()
 	os.Setenv("HOME", u.HomeDir) // nolint: gosec,errcheck
 	os.Setenv("TERM", ttype)     // nolint: gosec,errcheck
-	os.Setenv("XS_SESSION", "1")     // nolint: gosec,errcheck
+	os.Setenv("XS_SESSION", "1") // nolint: gosec,errcheck
 
 	var c *exec.Cmd
 	cmdName := xs.GetTool("tar")
@@ -187,7 +187,7 @@ func runServerToClientCopyAs(who, ttype string, conn *xsnet.Conn, srcPath string
 	os.Clearenv()
 	_ = os.Setenv("HOME", u.HomeDir) // nolint: gosec
 	_ = os.Setenv("TERM", ttype)     // nolint: gosec
-	_ = os.Setenv("XS_SESSION", "1")     // nolint: gosec
+	_ = os.Setenv("XS_SESSION", "1") // nolint: gosec
 
 	var c *exec.Cmd
 	cmdName := xs.GetTool("tar")
@@ -278,13 +278,17 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, conn *xsnet.Con
 	os.Clearenv()
 	_ = os.Setenv("HOME", u.HomeDir) // nolint: gosec
 	_ = os.Setenv("TERM", ttype)     // nolint: gosec
-	_ = os.Setenv("XS_SESSION", "1")     // nolint: gosec
+	_ = os.Setenv("XS_SESSION", "1") // nolint: gosec
 
 	var c *exec.Cmd
+
 	if interactive {
 		if useSysLogin {
-			// Use the server's login binary (post-auth
-			// which is still done via our own bcrypt file)
+			// Use the server's login binary (post-auth, which
+			// is still done via our own bcrypt file)
+			//
+			// Note login will drop privs to the intended user for us
+			//
 			// Things UNIX login does, like print the 'motd',
 			// and use the shell specified by /etc/passwd, will be done
 			// automagically, at the cost of another external tool
@@ -292,23 +296,23 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, conn *xsnet.Con
 			//
 			c = exec.Command(xs.GetTool("login"), "-f", "-p", who) // nolint: gosec
 		} else {
+			// Using our separate login via local passwd file
+			//
+			// Note we must drop privs ourselves for the user shell
+			//
 			c = exec.Command(xs.GetTool("bash"), "-i", "-l") // nolint: gosec
+			c.SysProcAttr = &syscall.SysProcAttr{}
+			c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
 		}
 	} else {
 		c = exec.Command(xs.GetTool("bash"), "-c", cmd) // nolint: gosec
+		c.SysProcAttr = &syscall.SysProcAttr{}
+		c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
 	}
 	//If os.Clearenv() isn't called by server above these will be seen in the
 	//client's session env.
 	//c.Env = []string{"HOME=" + u.HomeDir, "SUDO_GID=", "SUDO_UID=", "SUDO_USER=", "SUDO_COMMAND=", "MAIL=", "LOGNAME="+who}
 	c.Dir = u.HomeDir
-	c.SysProcAttr = &syscall.SysProcAttr{}
-	if useSysLogin {
-		// If using server's login binary, drop to user creds
-		// is taken care of by it.
-		c.SysProcAttr.Credential = &syscall.Credential{}
-	} else {
-		c.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
-	}
 
 	// Start the command with a pty.
 	ptmx, err := pty.Start(c) // returns immediately with ptmx file
@@ -418,15 +422,15 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, conn *xsnet.Con
 // GenAuthToken generates a pseudorandom auth token for a specific
 // user from a specific host to allow non-interactive logins.
 func GenAuthToken(who string, connhost string) string {
-	//tokenA, e := os.Hostname()
+	//hname, e := os.Hostname()
 	//if e != nil {
-	//	tokenA = "badhost"
+	//	hname = "#badhost#"
 	//}
-	tokenA := connhost
+	hname := connhost
 
-	tokenB := make([]byte, 64)
-	_, _ = rand.Read(tokenB) // nolint: gosec
-	return fmt.Sprintf("%s:%s", tokenA, hex.EncodeToString(tokenB))
+	token := make([]byte, 64)
+	_, _ = rand.Read(token) // nolint: gosec
+	return fmt.Sprintf("%s:%s:%s", hname, who, hex.EncodeToString(token))
 }
 
 var (