ipn/ipnserver: move more connection acceptance logic to LocalBackend

Follow-up to #6467 and #6506.

LocalBackend knows the server-mode state, so move more auth checking
there, removing some bookkeeping from ipnserver.Server.

Updates #6417
Updates tailscale/corp#8051

Change-Id: Ic5d14a077bf0dccc92a3621bd2646bab2cc5b837
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/6510/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 5ea7c7d603
commit 0a842f353c

@ -200,7 +200,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
tailscale.com/hostinfo from tailscale.com/control/controlclient+
tailscale.com/ipn from tailscale.com/ipn/ipnlocal+
tailscale.com/ipn/ipnauth from tailscale.com/ipn/ipnserver
tailscale.com/ipn/ipnauth from tailscale.com/ipn/ipnserver+
tailscale.com/ipn/ipnlocal from tailscale.com/ssh/tailssh+
tailscale.com/ipn/ipnserver from tailscale.com/cmd/tailscaled
tailscale.com/ipn/ipnstate from tailscale.com/control/controlclient+

@ -44,7 +44,16 @@ type ConnIdentity struct {
user *user.User
}
func (ci *ConnIdentity) UserID() string { return ci.userID }
// UserID returns the local machine's userid of the connection.
//
// It's suitable for passing to LookupUserFromID (os/user.LookupId) on any
// operating system.
//
// TODO(bradfitz): it currently returns an empty string on everything
// but Windows. We should make it return the actual uid also on all supported
// peercred platforms from the creds if non-nil.
func (ci *ConnIdentity) UserID() string { return ci.userID }
func (ci *ConnIdentity) User() *user.User { return ci.user }
func (ci *ConnIdentity) Pid() int { return ci.pid }
func (ci *ConnIdentity) IsUnixSock() bool { return ci.isUnixSock }

@ -38,6 +38,7 @@ import (
"tailscale.com/health/healthmsg"
"tailscale.com/hostinfo"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnauth"
"tailscale.com/ipn/ipnstate"
"tailscale.com/ipn/policy"
"tailscale.com/net/dns"
@ -2029,6 +2030,34 @@ func (b *LocalBackend) InServerMode() bool {
return b.inServerMode
}
// CheckIPNConnectionAllowed returns an error if the identity in ci should not
// be allowed to connect or make requests to the LocalAPI currently.
//
// Currently (as of 2022-11-23), this is only used on Windows to check if
// we started in server mode and ci is from an identity other than the one
// that started the server.
func (b *LocalBackend) CheckIPNConnectionAllowed(ci *ipnauth.ConnIdentity) error {
b.mu.Lock()
defer b.mu.Unlock()
serverModeUid := b.pm.CurrentUser()
if serverModeUid == "" {
// Either this platform isn't a "multi-user" platform or we're not yet
// running as one.
return nil
}
if !b.inServerMode {
return nil
}
uid := ci.UserID()
if uid == "" {
return errors.New("empty user uid in connection identity")
}
if uid != serverModeUid {
return fmt.Errorf("Tailscale running in server mode (uid=%v); connection from %q not allowed", serverModeUid, uid)
}
return nil
}
// Login implements Backend.
// As of 2022-11-15, this is only exists for Android.
func (b *LocalBackend) Login(token *tailcfg.Oauth2Token) {
@ -4383,11 +4412,3 @@ func (b *LocalBackend) ListProfiles() []ipn.LoginProfile {
defer b.mu.Unlock()
return b.pm.Profiles()
}
// CurrentUser returns the current server mode user ID. It is only non-empty on
// Windows where we have a multi-user system.
func (b *LocalBackend) CurrentUser() string {
b.mu.Lock()
defer b.mu.Unlock()
return b.pm.CurrentUser()
}

@ -304,8 +304,8 @@ func (s *Server) checkConnIdentityLocked(ci *ipnauth.ConnIdentity) error {
return inUseOtherUserError{fmt.Errorf("Tailscale already in use by %s, pid %d", active.User().Username, active.Pid())}
}
}
if cu := s.b.CurrentUser(); cu != "" && cu != ci.UserID() {
return inUseOtherUserError{fmt.Errorf("Tailscale already in use by %s", s.b.CurrentUser())}
if err := s.b.CheckIPNConnectionAllowed(ci); err != nil {
return inUseOtherUserError{err}
}
return nil
}

Loading…
Cancel
Save