2025-02-13 16:46:24 -06:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
// Both the desktop session manager and multi-user support
|
|
|
|
// are currently available only on Windows.
|
|
|
|
// This file does not need to be built for other platforms.
|
|
|
|
|
|
|
|
//go:build windows && !ts_omit_desktop_sessions
|
|
|
|
|
|
|
|
package ipnlocal
|
|
|
|
|
|
|
|
import (
|
|
|
|
"cmp"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"tailscale.com/feature"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn/desktop"
|
|
|
|
"tailscale.com/tsd"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
"tailscale.com/util/syspolicy"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
feature.Register("desktop-sessions")
|
|
|
|
RegisterExtension("desktop-sessions", newDesktopSessionsExt)
|
|
|
|
}
|
|
|
|
|
2025-03-24 15:40:12 -05:00
|
|
|
// desktopSessionsExt implements [Extension].
|
|
|
|
var _ Extension = (*desktopSessionsExt)(nil)
|
2025-02-13 16:46:24 -06:00
|
|
|
|
|
|
|
// desktopSessionsExt extends [LocalBackend] with desktop session management.
|
|
|
|
// It keeps Tailscale running in the background if Always-On mode is enabled,
|
|
|
|
// and switches to an appropriate profile when a user signs in or out,
|
|
|
|
// locks their screen, or disconnects a remote session.
|
|
|
|
type desktopSessionsExt struct {
|
|
|
|
logf logger.Logf
|
|
|
|
sm desktop.SessionManager
|
|
|
|
|
|
|
|
*LocalBackend // or nil, until Init is called
|
|
|
|
cleanup []func() // cleanup functions to call on shutdown
|
|
|
|
|
|
|
|
// mu protects all following fields.
|
|
|
|
// When both mu and [LocalBackend.mu] need to be taken,
|
|
|
|
// [LocalBackend.mu] must be taken before mu.
|
|
|
|
mu sync.Mutex
|
|
|
|
id2sess map[desktop.SessionID]*desktop.Session
|
|
|
|
}
|
|
|
|
|
|
|
|
// newDesktopSessionsExt returns a new [desktopSessionsExt],
|
|
|
|
// or an error if [desktop.SessionManager] is not available.
|
2025-03-24 15:40:12 -05:00
|
|
|
func newDesktopSessionsExt(logf logger.Logf, sys *tsd.System) (Extension, error) {
|
2025-02-13 16:46:24 -06:00
|
|
|
sm, ok := sys.SessionManager.GetOK()
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("session manager is not available")
|
|
|
|
}
|
|
|
|
return &desktopSessionsExt{logf: logf, sm: sm, id2sess: make(map[desktop.SessionID]*desktop.Session)}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init implements [localBackendExtension].
|
|
|
|
func (e *desktopSessionsExt) Init(lb *LocalBackend) (err error) {
|
|
|
|
e.LocalBackend = lb
|
|
|
|
unregisterResolver := lb.RegisterBackgroundProfileResolver(e.getBackgroundProfile)
|
|
|
|
unregisterSessionCb, err := e.sm.RegisterStateCallback(e.updateDesktopSessionState)
|
|
|
|
if err != nil {
|
|
|
|
unregisterResolver()
|
|
|
|
return fmt.Errorf("session callback registration failed: %w", err)
|
|
|
|
}
|
|
|
|
e.cleanup = []func(){unregisterResolver, unregisterSessionCb}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// updateDesktopSessionState is a [desktop.SessionStateCallback]
|
|
|
|
// invoked by [desktop.SessionManager] once for each existing session
|
|
|
|
// and whenever the session state changes. It updates the session map
|
|
|
|
// and switches to the best profile if necessary.
|
|
|
|
func (e *desktopSessionsExt) updateDesktopSessionState(session *desktop.Session) {
|
|
|
|
e.mu.Lock()
|
|
|
|
if session.Status != desktop.ClosedSession {
|
|
|
|
e.id2sess[session.ID] = session
|
|
|
|
} else {
|
|
|
|
delete(e.id2sess, session.ID)
|
|
|
|
}
|
|
|
|
e.mu.Unlock()
|
|
|
|
|
|
|
|
var action string
|
|
|
|
switch session.Status {
|
|
|
|
case desktop.ForegroundSession:
|
|
|
|
// The user has either signed in or unlocked their session.
|
|
|
|
// For remote sessions, this may also mean the user has connected.
|
|
|
|
// The distinction isn't important for our purposes,
|
|
|
|
// so let's always say "signed in".
|
|
|
|
action = "signed in to"
|
|
|
|
case desktop.BackgroundSession:
|
|
|
|
action = "locked"
|
|
|
|
case desktop.ClosedSession:
|
|
|
|
action = "signed out from"
|
|
|
|
default:
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
maybeUsername, _ := session.User.Username()
|
|
|
|
userIdentifier := cmp.Or(maybeUsername, string(session.User.UserID()), "user")
|
|
|
|
reason := fmt.Sprintf("%s %s session %v", userIdentifier, action, session.ID)
|
|
|
|
|
|
|
|
e.SwitchToBestProfile(reason)
|
|
|
|
}
|
|
|
|
|
|
|
|
// getBackgroundProfile is a [profileResolver] that works as follows:
|
|
|
|
//
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// If Always-On mode is disabled, it returns no profile.
|
2025-02-13 16:46:24 -06:00
|
|
|
//
|
|
|
|
// If AlwaysOn mode is enabled, it returns the current profile unless:
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// - The current profile's owner has signed out.
|
2025-02-13 16:46:24 -06:00
|
|
|
// - Another user has a foreground (i.e. active/unlocked) session.
|
|
|
|
//
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// If the current profile owner's session runs in the background and no other user
|
2025-02-13 16:46:24 -06:00
|
|
|
// has a foreground session, it returns the current profile. This applies
|
|
|
|
// when a locally signed-in user locks their screen or when a remote user
|
|
|
|
// disconnects without signing out.
|
|
|
|
//
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// In all other cases, it returns no profile.
|
2025-02-13 16:46:24 -06:00
|
|
|
//
|
|
|
|
// It is called with [LocalBackend.mu] locked.
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
func (e *desktopSessionsExt) getBackgroundProfile() ipn.LoginProfileView {
|
2025-02-13 16:46:24 -06:00
|
|
|
e.mu.Lock()
|
|
|
|
defer e.mu.Unlock()
|
|
|
|
|
|
|
|
if alwaysOn, _ := syspolicy.GetBoolean(syspolicy.AlwaysOn, false); !alwaysOn {
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// If the Always-On mode is disabled, there's no background profile
|
|
|
|
// as far as the desktop session extension is concerned.
|
|
|
|
return ipn.LoginProfileView{}
|
2025-02-13 16:46:24 -06:00
|
|
|
}
|
|
|
|
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
isCurrentProfileOwnerSignedIn := false
|
2025-02-13 16:46:24 -06:00
|
|
|
var foregroundUIDs []ipn.WindowsUserID
|
|
|
|
for _, s := range e.id2sess {
|
|
|
|
switch uid := s.User.UserID(); uid {
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
case e.pm.CurrentProfile().LocalUserID():
|
|
|
|
isCurrentProfileOwnerSignedIn = true
|
2025-02-13 16:46:24 -06:00
|
|
|
if s.Status == desktop.ForegroundSession {
|
|
|
|
// Keep the current profile if the user has a foreground session.
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
return e.pm.CurrentProfile()
|
2025-02-13 16:46:24 -06:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
if s.Status == desktop.ForegroundSession {
|
|
|
|
foregroundUIDs = append(foregroundUIDs, uid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// If the current profile is empty and not owned by anyone (e.g., tailscaled just started),
|
|
|
|
// or if the current profile's owner has no foreground session, switch to the default profile
|
|
|
|
// of the first user with a foreground session, if any.
|
2025-02-13 16:46:24 -06:00
|
|
|
for _, uid := range foregroundUIDs {
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
if profile := e.pm.DefaultUserProfile(uid); profile.ID() != "" {
|
|
|
|
return profile
|
2025-02-13 16:46:24 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// If no user has a foreground session but the current profile's owner is still signed in,
|
2025-02-13 16:46:24 -06:00
|
|
|
// keep the current profile even if the session is not in the foreground,
|
|
|
|
// such as when the screen is locked or a remote session is disconnected.
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
if len(foregroundUIDs) == 0 && isCurrentProfileOwnerSignedIn {
|
|
|
|
return e.pm.CurrentProfile()
|
2025-02-13 16:46:24 -06:00
|
|
|
}
|
|
|
|
|
ipn, ipn/ipnlocal: reduce coupling between LocalBackend/profileManager and the Windows-specific "current user" model
Ultimately, we'd like to get rid of the concept of the "current user". It is only used on Windows,
but even then it doesn't work well in multi-user and enterprise/managed Windows environments.
In this PR, we update LocalBackend and profileManager to decouple them a bit more from this obsolete concept.
This is done in a preparation for extracting ipnlocal.Extension-related interfaces and types, and using them
to implement optional features like tailscale/corp#27645, instead of continuing growing the core ipnlocal logic.
Notably, we rename (*profileManager).SetCurrentUserAndProfile() to SwitchToProfile() and change its signature
to accept an ipn.LoginProfileView instead of an ipn.ProfileID and ipn.WindowsUserID. Since we're not removing
the "current user" completely just yet, the method sets the current user to the owner of the target profile.
We also update the profileResolver callback type, which is typically implemented by LocalBackend extensions,
to return an ipn.LoginProfileView instead of ipn.ProfileID and ipn.WindowsUserID.
Updates tailscale/corp#27645
Updates tailscale/corp#18342
Signed-off-by: Nick Khyl <nickk@tailscale.com>
2025-04-05 22:15:26 -05:00
|
|
|
// Otherwise, there's no background profile.
|
|
|
|
return ipn.LoginProfileView{}
|
2025-02-13 16:46:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown implements [localBackendExtension].
|
|
|
|
func (e *desktopSessionsExt) Shutdown() error {
|
|
|
|
for _, f := range e.cleanup {
|
|
|
|
f()
|
|
|
|
}
|
|
|
|
e.cleanup = nil
|
|
|
|
e.LocalBackend = nil
|
|
|
|
return nil
|
|
|
|
}
|