Fall back gracefully when home dir does not exist

Former-commit-id: 07bf861179
This commit is contained in:
Owen
2026-05-31 16:24:57 -07:00
parent 8191f30e77
commit e77b1d9363
2 changed files with 50 additions and 2 deletions

View File

@@ -1,10 +1,13 @@
package nativessh
import (
"bufio"
"errors"
"fmt"
"os"
"os/exec"
"os/user"
"strings"
"sync"
"github.com/creack/pty"
@@ -31,6 +34,42 @@ func findShell() string {
return "/bin/sh"
}
// userShell returns the login shell configured for u in /etc/passwd.
// If the field is empty or the binary does not exist, it falls back to
// findShell so there is always a usable shell.
func userShell(u *user.User) string {
if shell := passwdShell(u.Username); shell != "" {
if _, err := exec.LookPath(shell); err == nil {
return shell
}
}
return findShell()
}
// passwdShell reads /etc/passwd and returns the login shell for the named user.
// Returns "" if the user is not found or the file cannot be read.
func passwdShell(username string) string {
f, err := os.Open("/etc/passwd")
if err != nil {
return ""
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if line == "" || line[0] == '#' {
continue
}
// Fields: username:password:uid:gid:gecos:home:shell
fields := strings.SplitN(line, ":", 7)
if len(fields) == 7 && fields[0] == username {
return fields[6]
}
}
_ = scanner.Err()
return ""
}
// NewPTYSession spawns the best available shell in a PTY.
func NewPTYSession() (*PTYSession, error) {
shell := findShell()

View File

@@ -4,6 +4,7 @@ package nativessh
import (
"fmt"
"os"
"os/exec"
"os/user"
"strconv"
@@ -42,7 +43,15 @@ func NewPTYSessionAs(username string) (*PTYSession, error) {
}
}
shell := findShell()
shell := userShell(u)
// Prefer the user's home directory as the working directory, but fall back
// to / if it does not exist (e.g. useradd was run without -m).
homeDir := u.HomeDir
if _, err := os.Stat(homeDir); err != nil {
homeDir = "/"
}
cmd := exec.Command(shell, "--login")
cmd.Env = []string{
"TERM=xterm-256color",
@@ -52,7 +61,7 @@ func NewPTYSessionAs(username string) (*PTYSession, error) {
"SHELL=" + shell,
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
cmd.Dir = u.HomeDir
cmd.Dir = homeDir
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uint32(uid),