mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
ipn/ipnauth: improve the Windows token administrator check
(*Token).IsAdministrator is supposed to return true even when the user is running with a UAC limited token. The idea is that, for the purposes of this check, we don't care whether the user is *currently* running with full Admin rights, we just want to know whether the user can *potentially* do so. We accomplish this by querying for the token's "linked token," which should be the fully-elevated variant, and checking its group memberships. We also switch ipn/ipnserver/(*Server).connIsLocalAdmin to use the elevation check to preserve those semantics for tailscale serve; I want the IsAdministrator check to be used for less sensitive things like toggling auto-update on and off. Fixes #10036 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
This commit is contained in:
parent
e5dcf7bdde
commit
fbc18410ad
@ -13,6 +13,7 @@
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/safesocket"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/winutil"
|
||||
)
|
||||
|
||||
// GetConnIdentity extracts the identity information from the connection
|
||||
@ -64,7 +65,28 @@ func (t *token) IsAdministrator() (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return t.t.IsMember(baSID)
|
||||
isMember, err := t.t.IsMember(baSID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if isMember {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
isLimited, err := winutil.IsTokenLimited(t.t)
|
||||
if err != nil || !isLimited {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Try to obtain a linked token, and if present, check it.
|
||||
// (This should be the elevated token associated with limited UAC accounts.)
|
||||
linkedToken, err := t.t.GetLinkedToken()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer linkedToken.Close()
|
||||
|
||||
return linkedToken.IsMember(baSID)
|
||||
}
|
||||
|
||||
func (t *token) IsElevated() bool {
|
||||
|
@ -367,8 +367,7 @@ func (s *Server) connCanFetchCerts(ci *ipnauth.ConnIdentity) bool {
|
||||
// connIsLocalAdmin reports whether ci has administrative access to the local
|
||||
// machine, for whatever that means with respect to the current OS.
|
||||
//
|
||||
// This returns true only on Windows machines when the client user is a
|
||||
// member of the built-in Administrators group (but not necessarily elevated).
|
||||
// This returns true only on Windows machines when the client user is elevated.
|
||||
// This is useful because, on Windows, tailscaled itself always runs with
|
||||
// elevated rights: we want to avoid privilege escalation for certain mutative operations.
|
||||
func (s *Server) connIsLocalAdmin(ci *ipnauth.ConnIdentity) bool {
|
||||
@ -381,12 +380,7 @@ func (s *Server) connIsLocalAdmin(ci *ipnauth.ConnIdentity) bool {
|
||||
}
|
||||
defer tok.Close()
|
||||
|
||||
isAdmin, err := tok.IsAdministrator()
|
||||
if err != nil {
|
||||
s.logf("ipnauth.WindowsToken.IsAdministrator() error: %v", err)
|
||||
return false
|
||||
}
|
||||
return isAdmin
|
||||
return tok.IsElevated()
|
||||
}
|
||||
|
||||
// addActiveHTTPRequest adds c to the server's list of active HTTP requests.
|
||||
|
@ -367,6 +367,30 @@ func getTokenPrimaryGroupInfo(token windows.Token) (*windows.Tokenprimarygroup,
|
||||
return (*windows.Tokenprimarygroup)(unsafe.Pointer(&buf[0])), nil
|
||||
}
|
||||
|
||||
type tokenElevationType int32
|
||||
|
||||
const (
|
||||
tokenElevationTypeDefault tokenElevationType = 1
|
||||
tokenElevationTypeFull tokenElevationType = 2
|
||||
tokenElevationTypeLimited tokenElevationType = 3
|
||||
)
|
||||
|
||||
func getTokenElevationType(token windows.Token) (result tokenElevationType, err error) {
|
||||
var actualLen uint32
|
||||
p := (*byte)(unsafe.Pointer(&result))
|
||||
err = windows.GetTokenInformation(token, windows.TokenElevationType, p, uint32(unsafe.Sizeof(result)), &actualLen)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// IsTokenLimited returns whether token is a limited UAC token.
|
||||
func IsTokenLimited(token windows.Token) (bool, error) {
|
||||
elevationType, err := getTokenElevationType(token)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return elevationType == tokenElevationTypeLimited, nil
|
||||
}
|
||||
|
||||
// UserSIDs contains the SIDs for a Windows NT token object's associated user
|
||||
// as well as its primary group.
|
||||
type UserSIDs struct {
|
||||
|
Loading…
Reference in New Issue
Block a user