more plan9 ssh work

Change-Id: I7049b5b4f6c0f9902693e00ab6d12ac00bc554bc
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2025-03-09 20:23:08 -07:00
parent dd3d4e3fe9
commit 6a3f589f53
4 changed files with 27 additions and 38 deletions

View File

@ -182,6 +182,10 @@ func main() {
return
}
if runtime.GOOS == "plan9" && os.Getenv("_NETSHELL_CHILD_") != "" {
os.Args = []string{"tailscaled", "be-child", "plan9-netshell"}
}
if len(os.Args) > 1 {
sub := os.Args[1]
if fp, ok := subCommands[sub]; ok {

1
go.mod
View File

@ -3,6 +3,7 @@ module tailscale.com
go 1.24.0
require (
9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f
filippo.io/mkcert v1.4.4
fyne.io/systray v1.11.0
github.com/akutz/memconn v0.1.0

2
go.sum
View File

@ -2,6 +2,8 @@
4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs=
4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc=
4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f h1:1C7nZuxUMNz7eiQALRfiqNOm04+m3edWlRff/BYHf0Q=
9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f/go.mod h1:hHyrZRryGqVdqrknjq5OWDLGCTJ2NeEvtrpR96mjraM=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=

View File

@ -22,28 +22,18 @@ import (
"strconv"
"strings"
"sync/atomic"
"syscall"
"github.com/pkg/sftp"
"tailscale.com/cmd/tailscaled/childproc"
"tailscale.com/tailcfg"
"tailscale.com/tempfork/netshell"
"tailscale.com/types/logger"
)
func init() {
childproc.Add("ssh", beIncubator)
childproc.Add("sftp", beSFTP)
}
// maybeStartLoginSession informs the system that we are about to log someone
// in. On success, it may return a non-nil close func which must be closed to
// release the session.
// We can only do this if we are running as root.
// This is best effort to still allow running on machines where
// we don't support starting sessions, e.g. darwin.
// See maybeStartLoginSessionLinux.
var maybeStartLoginSession = func(dlogf logger.Logf, ia incubatorArgs) (close func() error) {
return nil
childproc.Add("plan9-netshell", beNetshell)
}
// newIncubatorCommand returns a new exec.Cmd configured with
@ -85,7 +75,6 @@ func (ss *sshSession) newIncubatorCommand(logf logger.Logf) (cmd *exec.Cmd, err
lu := ss.conn.localUser
ci := ss.conn.info
groups := strings.Join(ss.conn.userGroupIDs, ",")
remoteUser := ci.uprof.LoginName
if ci.node.IsTagged() {
remoteUser = strings.Join(ci.node.Tags().AsSlice(), ",")
@ -94,10 +83,9 @@ func (ss *sshSession) newIncubatorCommand(logf logger.Logf) (cmd *exec.Cmd, err
incubatorArgs := []string{
"be-child",
"ssh",
"--login-shell=" + lu.LoginShell(),
"--uid=" + lu.Uid,
"--gid=" + lu.Gid,
"--groups=" + groups,
// "--login-shell=" + lu.LoginShell(),
// "--uid=" + lu.Uid,
// "--gid=" + lu.Gid,
"--local-user=" + lu.Username,
"--home-dir=" + lu.HomeDir,
"--remote-user=" + remoteUser,
@ -212,6 +200,9 @@ func parseIncubatorArgs(args []string) (incubatorArgs, error) {
flags.Parse(args)
for _, g := range strings.Split(groups, ",") {
if g == "" {
continue
}
gid, err := strconv.Atoi(g)
if err != nil {
return ia, fmt.Errorf("unable to parse group id %q: %w", g, err)
@ -250,6 +241,11 @@ func (ia incubatorArgs) forwadedEnviron() ([]string, string, error) {
return environ, allowListKeys, nil
}
func beNetshell(args []string) error {
netshell.Main()
return nil
}
// beIncubator is the entrypoint to the `tailscaled be-child ssh` subcommand.
// It is responsible for informing the system of a new login session for the
// user. This is sometimes necessary for mounting home directories and
@ -275,6 +271,11 @@ func beIncubator(args []string) error {
return fmt.Errorf("--sftp and --shell are mutually exclusive")
}
if ia.isShell {
netshell.Main()
return nil
}
dlogf := logger.Discard
if ia.debugTest {
// In testing, we don't always have syslog, so log to a temp file.
@ -301,11 +302,6 @@ func handleInProcess(dlogf logger.Logf, ia incubatorArgs) error {
func handleSFTPInProcess(dlogf logger.Logf, ia incubatorArgs) error {
dlogf("handling sftp")
sessionCloser := maybeStartLoginSession(dlogf, ia)
if sessionCloser != nil {
defer sessionCloser()
}
return serveSFTP()
}
@ -332,10 +328,6 @@ func serveSFTP() error {
// specified values, and then launches the requested `--cmd` in the user's
// login shell.
func handleSSHInProcess(dlogf logger.Logf, ia incubatorArgs) error {
sessionCloser := maybeStartLoginSession(dlogf, ia)
if sessionCloser != nil {
defer sessionCloser()
}
environ, _, err := ia.forwadedEnviron()
if err != nil {
@ -344,7 +336,7 @@ func handleSSHInProcess(dlogf logger.Logf, ia incubatorArgs) error {
args := shellArgs(ia.isShell, ia.cmd)
dlogf("running %s %q", ia.loginShell, args)
cmd := newCommand(ia.hasTTY, ia.loginShell, environ, args)
cmd := newCommand(ia.loginShell, environ, args)
err = cmd.Run()
if ee, ok := err.(*exec.ExitError); ok {
ps := ee.ProcessState
@ -361,23 +353,13 @@ func handleSSHInProcess(dlogf logger.Logf, ia incubatorArgs) error {
return err
}
func newCommand(hasTTY bool, cmdPath string, cmdEnviron []string, cmdArgs []string) *exec.Cmd {
func newCommand(cmdPath string, cmdEnviron []string, cmdArgs []string) *exec.Cmd {
cmd := exec.Command(cmdPath, cmdArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = cmdEnviron
if hasTTY {
// If we were launched with a tty then we should mark that as the ctty
// of the child. However, as the ctty is being passed from the parent
// we set the child to foreground instead which also passes the ctty.
// However, we can not do this if never had a tty to begin with.
cmd.SysProcAttr = &syscall.SysProcAttr{
// XXX TODO
}
}
return cmd
}