//go:build !windows package pty import ( "log" "github.com/gliderlabs/ssh" "github.com/u-root/u-root/pkg/termios" gossh "golang.org/x/crypto/ssh" "golang.org/x/xerrors" ) // terminalModeFlagNames maps the SSH terminal mode flags to mnemonic // names used by the termios package. var terminalModeFlagNames = map[uint8]string{ gossh.VINTR: "intr", gossh.VQUIT: "quit", gossh.VERASE: "erase", gossh.VKILL: "kill", gossh.VEOF: "eof", gossh.VEOL: "eol", gossh.VEOL2: "eol2", gossh.VSTART: "start", gossh.VSTOP: "stop", gossh.VSUSP: "susp", gossh.VDSUSP: "dsusp", gossh.VREPRINT: "rprnt", gossh.VWERASE: "werase", gossh.VLNEXT: "lnext", gossh.VFLUSH: "flush", gossh.VSWTCH: "swtch", gossh.VSTATUS: "status", gossh.VDISCARD: "discard", gossh.IGNPAR: "ignpar", gossh.PARMRK: "parmrk", gossh.INPCK: "inpck", gossh.ISTRIP: "istrip", gossh.INLCR: "inlcr", gossh.IGNCR: "igncr", gossh.ICRNL: "icrnl", gossh.IUCLC: "iuclc", gossh.IXON: "ixon", gossh.IXANY: "ixany", gossh.IXOFF: "ixoff", gossh.IMAXBEL: "imaxbel", gossh.IUTF8: "iutf8", gossh.ISIG: "isig", gossh.ICANON: "icanon", gossh.XCASE: "xcase", gossh.ECHO: "echo", gossh.ECHOE: "echoe", gossh.ECHOK: "echok", gossh.ECHONL: "echonl", gossh.NOFLSH: "noflsh", gossh.TOSTOP: "tostop", gossh.IEXTEN: "iexten", gossh.ECHOCTL: "echoctl", gossh.ECHOKE: "echoke", gossh.PENDIN: "pendin", gossh.OPOST: "opost", gossh.OLCUC: "olcuc", gossh.ONLCR: "onlcr", gossh.OCRNL: "ocrnl", gossh.ONOCR: "onocr", gossh.ONLRET: "onlret", gossh.CS7: "cs7", gossh.CS8: "cs8", gossh.PARENB: "parenb", gossh.PARODD: "parodd", gossh.TTY_OP_ISPEED: "tty_op_ispeed", gossh.TTY_OP_OSPEED: "tty_op_ospeed", } // applyTerminalModesToFd applies the terminal settings from the SSH // request to the given fd. // // This is based on code from Tailscale's tailssh package: // https://github.com/tailscale/tailscale/blob/main/ssh/tailssh/incubator.go func applyTerminalModesToFd(logger *log.Logger, fd uintptr, req ssh.Pty) error { // Get the current TTY configuration. tios, err := termios.GTTY(int(fd)) if err != nil { return xerrors.Errorf("GTTY: %w", err) } // Apply the modes from the SSH request. tios.Row = req.Window.Height tios.Col = req.Window.Width for c, v := range req.Modes { if c == gossh.TTY_OP_ISPEED { tios.Ispeed = int(v) continue } if c == gossh.TTY_OP_OSPEED { tios.Ospeed = int(v) continue } k, ok := terminalModeFlagNames[c] if !ok { if logger != nil { logger.Printf("unknown terminal mode: %d", c) } continue } if _, ok := tios.CC[k]; ok { tios.CC[k] = uint8(v) continue } if _, ok := tios.Opts[k]; ok { tios.Opts[k] = v > 0 continue } if logger != nil { logger.Printf("unsupported terminal mode: k=%s, c=%d, v=%d", k, c, v) } } // Save the new TTY configuration. if _, err := tios.STTY(int(fd)); err != nil { return xerrors.Errorf("STTY: %w", err) } return nil }