From d91518044f4163ddaa0e29731fcf6f8197aeb74a Mon Sep 17 00:00:00 2001 From: Russell Jones Date: Fri, 18 Jan 2019 21:34:03 +0000 Subject: [PATCH] Set permissions on TTY. --- lib/srv/term.go | 80 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/lib/srv/term.go b/lib/srv/term.go index ee4fa2caba380..f6b8d5d8670e9 100644 --- a/lib/srv/term.go +++ b/lib/srv/term.go @@ -20,6 +20,8 @@ import ( "io" "os" "os/exec" + "os/user" + "strconv" "sync" "syscall" @@ -118,19 +120,30 @@ type terminal struct { // NewLocalTerminal creates and returns a local PTY. func newLocalTerminal(ctx *ServerContext) (*terminal, error) { - pty, tty, err := pty.Open() - if err != nil { - log.Warnf("Could not start PTY %v", err) - return nil, err - } - return &terminal{ + var err error + + t := &terminal{ log: log.WithFields(log.Fields{ trace.Component: teleport.ComponentLocalTerm, }), ctx: ctx, - pty: pty, - tty: tty, - }, nil + } + + // Open PTY and corresponding TTY. + t.pty, t.tty, err = pty.Open() + if err != nil { + log.Warnf("Could not start PTY %v", err) + return nil, err + } + + // Set the TTY owner. Failure is not fatal, for example Teleport is running + // on a read-only filesystem, but logging is useful for diagnostic purposes. + err = t.setOwner() + if err != nil { + log.Debugf("Unable to set TTY owner: %v.\n", err) + } + + return t, nil } // AddParty adds another participant to this terminal. We will keep the @@ -294,6 +307,55 @@ func (t *terminal) SetTerminalModes(termModes ssh.TerminalModes) { return } +// setOwner sets the owner and mode of the TTY similar to OpenSSH: +// https://github.com/openssh/openssh-portable/blob/ddc0f38/sshpty.c#L164-L215 +func (t *terminal) setOwner() error { + var err error + var uid int + var gid int + var mode os.FileMode + + // Lookup the Unix login for the UID and fallback GID. + u, err := user.Lookup(t.ctx.Identity.Login) + if err != nil { + return trace.Wrap(err) + } + uid, err = strconv.Atoi(u.Uid) + if err != nil { + return trace.Wrap(err) + } + + // If the tty group exists, use that as the gid of the TTY and set mode to + // be u+rw. Otherwise use the group of the user with mode u+rw g+w. + group, err := user.LookupGroup("tty") + if err != nil { + gid, err = strconv.Atoi(u.Gid) + if err != nil { + return trace.Wrap(err) + } + mode = 0620 + } else { + gid, err = strconv.Atoi(group.Gid) + if err != nil { + return trace.Wrap(err) + } + mode = 0600 + } + + err = os.Chown(t.tty.Name(), uid, gid) + if err != nil { + return trace.Wrap(err) + } + err = os.Chmod(t.tty.Name(), mode) + if err != nil { + return trace.Wrap(err) + } + + log.Debugf("Set permissions on %v to %v:%v with mode %v.", t.tty.Name(), uid, gid, mode) + + return nil +} + type remoteTerminal struct { wg sync.WaitGroup mu sync.Mutex