mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-24 02:01:01 +00:00
ssh/tailssh: refactor incubator flags
Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
741ae9956e
commit
a253057fc3
@ -51,7 +51,7 @@ var ptyName = func(f *os.File) (string, error) {
|
||||
// On success, it may return a non-nil close func which must be closed to
|
||||
// release the session.
|
||||
// See maybeStartLoginSessionLinux.
|
||||
var maybeStartLoginSession = func(logf logger.Logf, uid uint32, localUser, remoteUser, remoteHost, tty string) (close func() error, err error) {
|
||||
var maybeStartLoginSession = func(logf logger.Logf, ia incubatorArgs) (close func() error, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -133,6 +133,38 @@ func (stdRWC) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type incubatorArgs struct {
|
||||
uid uint64
|
||||
gid int
|
||||
groups string
|
||||
localUser string
|
||||
remoteUser string
|
||||
remoteIP string
|
||||
ttyName string
|
||||
hasTTY bool
|
||||
cmdName string
|
||||
isSFTP bool
|
||||
loginCmdPath string
|
||||
cmdArgs []string
|
||||
}
|
||||
|
||||
func parseIncubatorArgs(args []string) (a incubatorArgs) {
|
||||
flags := flag.NewFlagSet("", flag.ExitOnError)
|
||||
flags.Uint64Var(&a.uid, "uid", 0, "the uid of local-user")
|
||||
flags.IntVar(&a.gid, "gid", 0, "the gid of local-user")
|
||||
flags.StringVar(&a.groups, "groups", "", "comma-separated list of gids of local-user")
|
||||
flags.StringVar(&a.localUser, "local-user", "", "the user to run as")
|
||||
flags.StringVar(&a.remoteUser, "remote-user", "", "the remote user/tags")
|
||||
flags.StringVar(&a.remoteIP, "remote-ip", "", "the remote Tailscale IP")
|
||||
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.isSFTP, "sftp", false, "run sftp server (cmd is ignored)")
|
||||
flags.Parse(args)
|
||||
a.cmdArgs = flags.Args()
|
||||
return a
|
||||
}
|
||||
|
||||
// beIncubator is the entrypoint to the `tailscaled be-child ssh` subcommand.
|
||||
// It is responsible for informing the system of a new login session for the user.
|
||||
// This is sometimes necessary for mounting home directories and decrypting file
|
||||
@ -143,23 +175,7 @@ func (stdRWC) Close() error {
|
||||
// OS, sets its UID and groups to the specified `--uid`, `--gid` and
|
||||
// `--groups` and then launches the requested `--cmd`.
|
||||
func beIncubator(args []string) error {
|
||||
var (
|
||||
flags = flag.NewFlagSet("", flag.ExitOnError)
|
||||
uid = flags.Uint64("uid", 0, "the uid of local-user")
|
||||
gid = flags.Int("gid", 0, "the gid of local-user")
|
||||
groups = flags.String("groups", "", "comma-separated list of gids of local-user")
|
||||
localUser = flags.String("local-user", "", "the user to run as")
|
||||
remoteUser = flags.String("remote-user", "", "the remote user/tags")
|
||||
remoteIP = flags.String("remote-ip", "", "the remote Tailscale IP")
|
||||
ttyName = flags.String("tty-name", "", "the tty name (pts/3)")
|
||||
hasTTY = flags.Bool("has-tty", false, "is the output attached to a tty")
|
||||
cmdName = flags.String("cmd", "", "the cmd to launch (ignored in sftp mode)")
|
||||
sftpMode = flags.Bool("sftp", false, "run sftp server (cmd is ignored)")
|
||||
)
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
cmdArgs := flags.Args()
|
||||
ia := parseIncubatorArgs(args)
|
||||
|
||||
logf := logger.Discard
|
||||
if debugIncubator {
|
||||
@ -170,16 +186,17 @@ func beIncubator(args []string) error {
|
||||
}
|
||||
|
||||
euid := uint64(os.Geteuid())
|
||||
|
||||
// Inform the system that we are about to log someone in.
|
||||
// We can only do this if we are running as root.
|
||||
// This is best effort to still allow running on machines where
|
||||
// we don't support starting sessions, e.g. darwin.
|
||||
sessionCloser, err := maybeStartLoginSession(logf, uint32(*uid), *localUser, *remoteUser, *remoteIP, *ttyName)
|
||||
sessionCloser, err := maybeStartLoginSession(logf, ia)
|
||||
if err == nil && sessionCloser != nil {
|
||||
defer sessionCloser()
|
||||
}
|
||||
var groupIDs []int
|
||||
for _, g := range strings.Split(*groups, ",") {
|
||||
for _, g := range strings.Split(ia.groups, ",") {
|
||||
gid, err := strconv.ParseInt(g, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -189,20 +206,20 @@ func beIncubator(args []string) error {
|
||||
if err := syscall.Setgroups(groupIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
if egid := os.Getegid(); egid != *gid {
|
||||
if err := syscall.Setgid(int(*gid)); err != nil {
|
||||
if egid := os.Getegid(); egid != ia.gid {
|
||||
if err := syscall.Setgid(int(ia.gid)); err != nil {
|
||||
logf(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if euid != *uid {
|
||||
if euid != ia.uid {
|
||||
// Switch users if required before starting the desired process.
|
||||
if err := syscall.Setuid(int(*uid)); err != nil {
|
||||
if err := syscall.Setuid(int(ia.uid)); err != nil {
|
||||
logf(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if *sftpMode {
|
||||
if ia.isSFTP {
|
||||
logf("handling sftp")
|
||||
|
||||
server, err := sftp.NewServer(stdRWC{})
|
||||
@ -212,13 +229,13 @@ func beIncubator(args []string) error {
|
||||
return server.Serve()
|
||||
}
|
||||
|
||||
cmd := exec.Command(*cmdName, cmdArgs...)
|
||||
cmd := exec.Command(ia.cmdName, ia.cmdArgs...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
if *hasTTY {
|
||||
if ia.hasTTY {
|
||||
// If we were launched with a tty then we should
|
||||
// mark that as the ctty of the child. However,
|
||||
// as the ctty is being passed from the parent
|
||||
@ -266,7 +283,6 @@ func (ss *sshSession) launchProcess() error {
|
||||
return ss.startWithStdPipes()
|
||||
}
|
||||
ss.ptyReq = &ptyReq
|
||||
ss.logf("starting pty command: %+v", cmd.Args)
|
||||
pty, err := ss.startWithPTY()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -443,6 +459,7 @@ func (ss *sshSession) startWithPTY() (ptyFile *os.File, err error) {
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
|
||||
ss.logf("starting pty command: %+v", cmd.Args)
|
||||
if err = cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -148,21 +148,21 @@ func releaseSession(sessionID string) error {
|
||||
}
|
||||
|
||||
// maybeStartLoginSessionLinux is the linux implementation of maybeStartLoginSession.
|
||||
func maybeStartLoginSessionLinux(logf logger.Logf, uid uint32, localUser, remoteUser, remoteHost, tty string) (func() error, error) {
|
||||
func maybeStartLoginSessionLinux(logf logger.Logf, ia incubatorArgs) (func() error, error) {
|
||||
if os.Geteuid() != 0 {
|
||||
return nil, nil
|
||||
}
|
||||
logf("starting session for user %d", uid)
|
||||
logf("starting session for user %d", ia.uid)
|
||||
// The only way we can actually start a new session is if we are
|
||||
// running outside one and are root, which is typically the case
|
||||
// for systemd managed tailscaled.
|
||||
resp, err := createSession(uint32(uid), remoteUser, remoteHost, tty)
|
||||
resp, err := createSession(uint32(ia.uid), ia.remoteUser, ia.remoteIP, ia.ttyName)
|
||||
if err != nil {
|
||||
// TODO(maisem): figure out if we are running in a session.
|
||||
// We can look at the DBus GetSessionByPID API.
|
||||
// https://www.freedesktop.org/software/systemd/man/org.freedesktop.login1.html
|
||||
// For now best effort is fine.
|
||||
logf("ssh: failed to CreateSession for user %q (%d) %v", localUser, uid, err)
|
||||
logf("ssh: failed to CreateSession for user %q (%d) %v", ia.localUser, ia.uid, err)
|
||||
return nil, nil
|
||||
}
|
||||
os.Setenv("DBUS_SESSION_BUS_ADDRESS", fmt.Sprintf("unix:path=%v/bus", resp.runtimePath))
|
||||
|
Loading…
x
Reference in New Issue
Block a user