sing-box/protocol/tailscale/tailssh/server_helper_unix.go
2026-06-25 17:38:51 +08:00

100 lines
2.5 KiB
Go

//go:build with_gvisor && !windows
package tailssh
import (
"os"
"path/filepath"
"strconv"
"syscall"
gliderssh "github.com/sagernet/gliderssh"
"github.com/sagernet/sing-box/adapter"
)
func isPrivilegedUser() bool {
return os.Getuid() == 0
}
func requestedUserMatchesProcess(localUser *adapter.PlatformUser) (bool, error) {
return localUser.Uid == os.Getuid() && localUser.Gid == os.Getgid(), nil
}
// verifyShellIdentity is a no-op on Unix: spawned shells and sftp-server drop to the
// requested user via setCredential, so the child already runs as that user.
func verifyShellIdentity(_ *adapter.PlatformUser) error {
return nil
}
func systemHostKeyPath() string {
return "/etc/ssh/ssh_host_ed25519_key"
}
func defaultPathEnv() string {
return "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
}
func userSocketDirectories(localUser *adapter.PlatformUser) []string {
return gliderssh.UserSocketDirectories(localUser.HomeDir, strconv.Itoa(localUser.Uid))
}
// prepareAgentSocket hands the agent-forwarding socket to the target user so
// SSH_AUTH_SOCK stays reachable after the shell drops privileges. No-op when the
// shell runs as the server identity.
func prepareAgentSocket(socketPath string, uid, gid int) error {
if uid < 0 || uid == os.Getuid() {
return nil
}
err := os.Chown(socketPath, uid, gid)
if err != nil {
return err
}
err = os.Chmod(socketPath, 0o600)
if err != nil {
return err
}
// Make the MkdirTemp parent traversable so the dropped-privilege child can
// reach the socket.
return os.Chmod(filepath.Dir(socketPath), 0o755)
}
func platformEnvironment(_ *adapter.PlatformUser) []string {
return nil
}
func sftpCommand(sftpPath string) string {
return sftpPath + " 2>/dev/null"
}
func sshSignalToSyscall(sig gliderssh.Signal) int {
switch sig {
case gliderssh.SIGABRT:
return int(syscall.SIGABRT)
case gliderssh.SIGALRM:
return int(syscall.SIGALRM)
case gliderssh.SIGFPE:
return int(syscall.SIGFPE)
case gliderssh.SIGHUP:
return int(syscall.SIGHUP)
case gliderssh.SIGILL:
return int(syscall.SIGILL)
case gliderssh.SIGINT:
return int(syscall.SIGINT)
case gliderssh.SIGKILL:
return int(syscall.SIGKILL)
case gliderssh.SIGPIPE:
return int(syscall.SIGPIPE)
case gliderssh.SIGQUIT:
return int(syscall.SIGQUIT)
case gliderssh.SIGSEGV:
return int(syscall.SIGSEGV)
case gliderssh.SIGTERM:
return int(syscall.SIGTERM)
case gliderssh.SIGUSR1:
return int(syscall.SIGUSR1)
case gliderssh.SIGUSR2:
return int(syscall.SIGUSR2)
default:
return 0
}
}