ssh/tailssh: get login shell when running as non-root
And also reject attempts to use other users. Updates #3802 Change-Id: Iddc85f6ea2dba17d12be66a50408d24c1f92833e Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>pull/3509/merge
parent
e1e20f6d39
commit
03caa95bf2
|
@ -16,6 +16,9 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
@ -100,9 +103,9 @@ func (srv *server) handleSSH(s ssh.Session) {
|
|||
lb := srv.lb
|
||||
logf := srv.logf
|
||||
|
||||
user := s.User()
|
||||
sshUser := s.User()
|
||||
addr := s.RemoteAddr()
|
||||
logf("Handling SSH from %v for user %v", addr, user)
|
||||
logf("Handling SSH from %v for user %v", addr, sshUser)
|
||||
ta, ok := addr.(*net.TCPAddr)
|
||||
if !ok {
|
||||
logf("tsshd: rejecting non-TCP addr %T %v", addr, addr)
|
||||
|
@ -140,7 +143,7 @@ func (srv *server) handleSSH(s ssh.Session) {
|
|||
srcIP := srcIPP.IP()
|
||||
sctx := &sshContext{
|
||||
now: time.Now(),
|
||||
sshUser: s.User(),
|
||||
sshUser: sshUser,
|
||||
srcIP: srcIP,
|
||||
node: node,
|
||||
uprof: &uprof,
|
||||
|
@ -165,8 +168,19 @@ func (srv *server) handleSSH(s ssh.Session) {
|
|||
return
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if os.Getuid() != 0 || localUser == "root" {
|
||||
cmd = exec.Command("/bin/bash")
|
||||
if os.Getuid() != 0 {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
logf("failed to get current user: %v", err)
|
||||
s.Exit(1)
|
||||
return
|
||||
}
|
||||
if u.Username != localUser {
|
||||
fmt.Fprintf(s, "can't switch user\n")
|
||||
s.Exit(1)
|
||||
return
|
||||
}
|
||||
cmd = exec.Command(loginShell(u.Uid))
|
||||
} else {
|
||||
cmd = exec.Command("/usr/bin/env", "su", "-", localUser)
|
||||
}
|
||||
|
@ -297,3 +311,19 @@ func matchesPrincipal(ps []*tailcfg.SSHPrincipal, sctx *sshContext) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func loginShell(uid string) string {
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
out, _ := exec.Command("getent", "passwd", uid).Output()
|
||||
// out is "root:x:0:0:root:/root:/bin/bash"
|
||||
f := strings.SplitN(string(out), ":", 10)
|
||||
if len(f) > 6 {
|
||||
return f[6] // shell
|
||||
}
|
||||
}
|
||||
if e := os.Getenv("SHELL"); e != "" {
|
||||
return e
|
||||
}
|
||||
return "/bin/bash"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue