ipn: don't Logout when Windows GUI disconnects

Logout used to be a no-op, so the ipnserver previously synthensized a Logout
on disconnect. Now that Logout actually invalidates the node key that was
forcing all GUI closes to log people out.

Instead, add a method to LocalBackend to specifically mean "the
Windows GUI closed, please forget all the state".

Fixes tailscale/corp#1591 (ignoring the notification issues, tracked elsewhere)

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/1749/head
Brad Fitzpatrick 4 years ago committed by Brad Fitzpatrick
parent 158328ba24
commit f99e63bb17

@ -298,7 +298,7 @@ func run() error {
Port: 41112, Port: 41112,
StatePath: args.statepath, StatePath: args.statepath,
AutostartStateKey: globalStateKey, AutostartStateKey: globalStateKey,
SurviveDisconnects: true, SurviveDisconnects: runtime.GOOS != "windows",
DebugMux: debugMux, DebugMux: debugMux,
} }
err = ipnserver.Run(ctx, logf, pol.PublicID.String(), ipnserver.FixedEngine(e), opts) err = ipnserver.Run(ctx, logf, pol.PublicID.String(), ipnserver.FixedEngine(e), opts)

@ -2082,6 +2082,30 @@ func (b *LocalBackend) requestEngineStatusAndWait() {
b.statusLock.Unlock() b.statusLock.Unlock()
} }
// ResetForClientDisconnect resets the backend for GUI clients running
// in interactive (non-headless) mode. This is currently used only by
// Windows. This causes all state to be cleared, lest an unrelated user
// connect to tailscaled next. But it does not trigger a logout; we
// don't want to the user to have to reauthenticate in the future
// when they restart the GUI.
func (b *LocalBackend) ResetForClientDisconnect() {
defer b.enterState(ipn.Stopped)
b.mu.Lock()
defer b.mu.Unlock()
b.logf("LocalBackend.ResetForClientDisconnect")
if b.cc != nil {
go b.cc.Shutdown()
b.cc = nil
}
b.stateKey = ""
b.userID = ""
b.setNetMapLocked(nil)
b.prefs = new(ipn.Prefs)
b.authURL = ""
b.activeLogin = ""
}
// Logout tells the controlclient that we want to log out, and // Logout tells the controlclient that we want to log out, and
// transitions the local engine to the logged-out state without // transitions the local engine to the logged-out state without
// waiting for controlclient to be in that state. // waiting for controlclient to be in that state.
@ -2105,7 +2129,7 @@ func (b *LocalBackend) logout(ctx context.Context, sync bool) error {
b.EditPrefs(&ipn.MaskedPrefs{ b.EditPrefs(&ipn.MaskedPrefs{
WantRunningSet: true, WantRunningSet: true,
Prefs: ipn.Prefs{WantRunning: true}, Prefs: ipn.Prefs{WantRunning: false},
}) })
if cc == nil { if cc == nil {

@ -476,9 +476,7 @@ func (s *server) addConn(c net.Conn, isHTTP bool) (ci connIdentity, err error) {
defer func() { defer func() {
if doReset { if doReset {
s.logf("identity changed; resetting server") s.logf("identity changed; resetting server")
s.bsMu.Lock() s.b.ResetForClientDisconnect()
s.bs.Reset(context.TODO())
s.bsMu.Unlock()
} }
}() }()
@ -528,9 +526,7 @@ func (s *server) removeAndCloseConn(c net.Conn) {
s.logf("client disconnected; staying alive in server mode") s.logf("client disconnected; staying alive in server mode")
} else { } else {
s.logf("client disconnected; stopping server") s.logf("client disconnected; stopping server")
s.bsMu.Lock() s.b.ResetForClientDisconnect()
s.bs.Reset(context.TODO())
s.bsMu.Unlock()
} }
} }
c.Close() c.Close()

@ -143,11 +143,6 @@ func (bs *BackendServer) GotCommandMsg(ctx context.Context, b []byte) error {
return bs.GotCommand(ctx, cmd) return bs.GotCommand(ctx, cmd)
} }
func (bs *BackendServer) GotFakeCommand(ctx context.Context, cmd *Command) error {
cmd.Version = version.Long
return bs.GotCommand(ctx, cmd)
}
// ErrMsgPermissionDenied is the Notify.ErrMessage value used an // ErrMsgPermissionDenied is the Notify.ErrMessage value used an
// operation was done from a user/context that didn't have permission. // operation was done from a user/context that didn't have permission.
const ErrMsgPermissionDenied = "permission denied" const ErrMsgPermissionDenied = "permission denied"
@ -211,12 +206,6 @@ func (bs *BackendServer) GotCommand(ctx context.Context, cmd *Command) error {
return fmt.Errorf("BackendServer.Do: no command specified") return fmt.Errorf("BackendServer.Do: no command specified")
} }
func (bs *BackendServer) Reset(ctx context.Context) error {
// Tell the backend we got a Logout command, which will cause it
// to forget all its authentication information.
return bs.GotFakeCommand(ctx, &Command{Logout: &NoArgs{}})
}
type BackendClient struct { type BackendClient struct {
logf logger.Logf logf logger.Logf
sendCommandMsg func(jsonb []byte) sendCommandMsg func(jsonb []byte)

Loading…
Cancel
Save