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>
This commit is contained in:
@@ -109,37 +109,39 @@ func (e *desktopSessionsExt) updateDesktopSessionState(session *desktop.Session)
|
||||
|
||||
// getBackgroundProfile is a [profileResolver] that works as follows:
|
||||
//
|
||||
// If Always-On mode is disabled, it returns no profile ("","",false).
|
||||
// If Always-On mode is disabled, it returns no profile.
|
||||
//
|
||||
// If AlwaysOn mode is enabled, it returns the current profile unless:
|
||||
// - The current user has signed out.
|
||||
// - The current profile's owner has signed out.
|
||||
// - Another user has a foreground (i.e. active/unlocked) session.
|
||||
//
|
||||
// If the current user's session runs in the background and no other user
|
||||
// If the current profile owner's session runs in the background and no other user
|
||||
// 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.
|
||||
//
|
||||
// In all other cases, it returns no profile ("","",false).
|
||||
// In all other cases, it returns no profile.
|
||||
//
|
||||
// It is called with [LocalBackend.mu] locked.
|
||||
func (e *desktopSessionsExt) getBackgroundProfile() (_ ipn.WindowsUserID, _ ipn.ProfileID, ok bool) {
|
||||
func (e *desktopSessionsExt) getBackgroundProfile() ipn.LoginProfileView {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if alwaysOn, _ := syspolicy.GetBoolean(syspolicy.AlwaysOn, false); !alwaysOn {
|
||||
return "", "", false
|
||||
// If the Always-On mode is disabled, there's no background profile
|
||||
// as far as the desktop session extension is concerned.
|
||||
return ipn.LoginProfileView{}
|
||||
}
|
||||
|
||||
isCurrentUserSingedIn := false
|
||||
isCurrentProfileOwnerSignedIn := false
|
||||
var foregroundUIDs []ipn.WindowsUserID
|
||||
for _, s := range e.id2sess {
|
||||
switch uid := s.User.UserID(); uid {
|
||||
case e.pm.CurrentUserID():
|
||||
isCurrentUserSingedIn = true
|
||||
case e.pm.CurrentProfile().LocalUserID():
|
||||
isCurrentProfileOwnerSignedIn = true
|
||||
if s.Status == desktop.ForegroundSession {
|
||||
// Keep the current profile if the user has a foreground session.
|
||||
return e.pm.CurrentUserID(), e.pm.CurrentProfile().ID(), true
|
||||
return e.pm.CurrentProfile()
|
||||
}
|
||||
default:
|
||||
if s.Status == desktop.ForegroundSession {
|
||||
@@ -148,23 +150,24 @@ func (e *desktopSessionsExt) getBackgroundProfile() (_ ipn.WindowsUserID, _ ipn.
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no current user (e.g., tailscaled just started), or if the current
|
||||
// user has no foreground session, switch to the default profile of the first user
|
||||
// with a foreground session, if any.
|
||||
// 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.
|
||||
for _, uid := range foregroundUIDs {
|
||||
if profileID := e.pm.DefaultUserProfileID(uid); profileID != "" {
|
||||
return uid, profileID, true
|
||||
if profile := e.pm.DefaultUserProfile(uid); profile.ID() != "" {
|
||||
return profile
|
||||
}
|
||||
}
|
||||
|
||||
// If no user has a foreground session but the current user is still signed in,
|
||||
// If no user has a foreground session but the current profile's owner is still signed in,
|
||||
// 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.
|
||||
if len(foregroundUIDs) == 0 && isCurrentUserSingedIn {
|
||||
return e.pm.CurrentUserID(), e.pm.CurrentProfile().ID(), true
|
||||
if len(foregroundUIDs) == 0 && isCurrentProfileOwnerSignedIn {
|
||||
return e.pm.CurrentProfile()
|
||||
}
|
||||
|
||||
return "", "", false
|
||||
// Otherwise, there's no background profile.
|
||||
return ipn.LoginProfileView{}
|
||||
}
|
||||
|
||||
// Shutdown implements [localBackendExtension].
|
||||
|
||||
Reference in New Issue
Block a user