diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index c1bf61aed..9ef45d49d 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -3228,6 +3228,17 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) { } } +// operatorUserName returns the current pref's OperatorUser's name, or the +// empty string if none. +func (b *LocalBackend) operatorUserName() string { + b.mu.Lock() + defer b.mu.Unlock() + if b.prefs == nil { + return "" + } + return b.prefs.OperatorUser +} + // OperatorUserID returns the current pref's OperatorUser's ID (in // os/user.User.Uid string form), or the empty string if none. func (b *LocalBackend) OperatorUserID() string { @@ -3596,6 +3607,17 @@ func (b *LocalBackend) DoNoiseRequest(req *http.Request) (*http.Response, error) return cc.DoNoiseRequest(req) } +// tailscaleSSHEnabled reports whether Tailscale SSH is currently enabled based +// on prefs. It returns false if there are no prefs set. +func (b *LocalBackend) tailscaleSSHEnabled() bool { + b.mu.Lock() + defer b.mu.Unlock() + if b.prefs == nil { + return false + } + return b.prefs.RunSSH +} + func (b *LocalBackend) sshServerOrInit() (_ SSHServer, err error) { b.mu.Lock() defer b.mu.Unlock() diff --git a/ipn/ipnlocal/ssh.go b/ipn/ipnlocal/ssh.go index 1409cdcf4..8ea43e596 100644 --- a/ipn/ipnlocal/ssh.go +++ b/ipn/ipnlocal/ssh.go @@ -38,15 +38,16 @@ import ( // running as root. var keyTypes = []string{"rsa", "ecdsa", "ed25519"} +// getSSHUsernames discovers and returns the list of usernames that are +// potential Tailscale SSH user targets. +// +// Invariant: must not be called with b.mu held. func (b *LocalBackend) getSSHUsernames(req *tailcfg.C2NSSHUsernamesRequest) (*tailcfg.C2NSSHUsernamesResponse, error) { res := new(tailcfg.C2NSSHUsernamesResponse) - - b.mu.Lock() - defer b.mu.Unlock() - - if b.sshServer == nil { + if !b.tailscaleSSHEnabled() { return res, nil } + max := 10 if req != nil && req.Max != 0 { max = req.Max @@ -70,8 +71,8 @@ func (b *LocalBackend) getSSHUsernames(req *tailcfg.C2NSSHUsernamesRequest) (*ta res.Usernames = append(res.Usernames, u) } - if b.prefs != nil && b.prefs.OperatorUser != "" { - add(b.prefs.OperatorUser) + if opUser := b.operatorUserName(); opUser != "" { + add(opUser) } // Check popular usernames and see if they exist with a real shell. diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 7e364e91c..dcf7affc6 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -79,7 +79,8 @@ type CapabilityVersion int // - 40: 2022-08-22: added Node.KeySignature, PeersChangedPatch.KeySignature // - 41: 2022-08-30: uses 100.100.100.100 for route-less ExtraRecords if global nameservers is set // - 42: 2022-09-06: NextDNS DoH support; see https://github.com/tailscale/tailscale/pull/5556 -const CurrentCapabilityVersion CapabilityVersion = 42 +// - 43: 2022-09-21: clients can return usernames for SSH +const CurrentCapabilityVersion CapabilityVersion = 43 type StableID string