coder/pty/ssh_other.go

128 lines
3.3 KiB
Go

//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
}