ssh/tailssh: exec into `login` when launching a shell
This has the added benefit of displaying the MOTD and reducing our
dependency on the DBus interface.
Fixes
Updates
@@ -65,6 +65,7 @@ func (ss *sshSession) newIncubatorCommand() *exec.Cmd {
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.
