Browse Source

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 #4627
Updates #3802

Signed-off-by: Maisem Ali <[email protected]>
Maisem Ali 3 years ago
parent
commit
5cd56fe8d5
1 changed files with 23 additions and 3 deletions
  1. 23 3
      ssh/tailssh/incubator.go

+ 23 - 3
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.