diff --git a/ssh/tailssh/incubator.go b/ssh/tailssh/incubator.go index f02be5726..b95e37660 100644 --- a/ssh/tailssh/incubator.go +++ b/ssh/tailssh/incubator.go @@ -62,9 +62,10 @@ var maybeStartLoginSession = func(logf logger.Logf, ia incubatorArgs) (close fun // exec.CommandContext. func (ss *sshSession) newIncubatorCommand() *exec.Cmd { var ( - name string - args []string - isSFTP bool + name string + args []string + isSFTP bool + isShell bool ) switch ss.Subsystem() { case "sftp": @@ -74,6 +75,7 @@ func (ss *sshSession) newIncubatorCommand() *exec.Cmd { if rawCmd := ss.RawCommand(); rawCmd != "" { args = append(args, "-c", rawCmd) } else { + isShell = true args = append(args, "-l") // login shell } default: @@ -107,6 +109,13 @@ func (ss *sshSession) newIncubatorCommand() *exec.Cmd { if isSFTP { incubatorArgs = append(incubatorArgs, "--sftp") } else { + if isShell { + incubatorArgs = append(incubatorArgs, "--shell") + // Currently (2022-05-09) `login` is only used for shells + if lp, err := exec.LookPath("login"); err == nil { + incubatorArgs = append(incubatorArgs, "--login-cmd="+lp) + } + } incubatorArgs = append(incubatorArgs, "--cmd="+name) if len(args) > 0 { incubatorArgs = append(incubatorArgs, "--") @@ -144,6 +153,7 @@ type incubatorArgs struct { hasTTY bool cmdName string isSFTP bool + isShell bool loginCmdPath string cmdArgs []string } @@ -159,7 +169,9 @@ func parseIncubatorArgs(args []string) (a incubatorArgs) { flags.StringVar(&a.ttyName, "tty-name", "", "the tty name (pts/3)") flags.BoolVar(&a.hasTTY, "has-tty", false, "is the output attached to a tty") flags.StringVar(&a.cmdName, "cmd", "", "the cmd to launch (ignored in sftp mode)") + flags.BoolVar(&a.isShell, "shell", false, "is launching a shell (with no cmds)") flags.BoolVar(&a.isSFTP, "sftp", false, "run sftp server (cmd is ignored)") + flags.StringVar(&a.loginCmdPath, "login-cmd", "", "the path to `login` cmd") flags.Parse(args) a.cmdArgs = flags.Args() return a @@ -176,6 +188,9 @@ func parseIncubatorArgs(args []string) (a incubatorArgs) { // `--groups` and then launches the requested `--cmd`. func beIncubator(args []string) error { ia := parseIncubatorArgs(args) + if ia.isSFTP && ia.isShell { + return fmt.Errorf("--sftp and --shell are mutually exclusive") + } logf := logger.Discard if debugIncubator { @@ -186,6 +201,11 @@ func beIncubator(args []string) error { } euid := uint64(os.Geteuid()) + runningAsRoot := euid == 0 + if runningAsRoot && ia.isShell && ia.loginCmdPath != "" { + // If we are trying to launch a login shell, just exec into login instead. + return unix.Exec(ia.loginCmdPath, []string{ia.loginCmdPath, "-f", ia.localUser, "-h", ia.remoteIP, "-p"}, os.Environ()) + } // Inform the system that we are about to log someone in. // We can only do this if we are running as root.