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