From c3488b9382b08a7fde24955f6342403576847d6a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 6 May 2019 09:46:10 +0200 Subject: updater: move into manager Signed-off-by: Jason A. Donenfeld --- service/service_manager.go | 182 +++++++++++---------------------------------- 1 file changed, 45 insertions(+), 137 deletions(-) (limited to 'service/service_manager.go') diff --git a/service/service_manager.go b/service/service_manager.go index 715b4257..e8818ae4 100644 --- a/service/service_manager.go +++ b/service/service_manager.go @@ -16,82 +16,9 @@ import ( "runtime/debug" "sync" "syscall" - "unicode/utf16" "unsafe" ) -const ( - wtsSessionLogon uint32 = 5 - wtsSessionLogoff uint32 = 6 -) - -type wtsState int - -const ( - wtsActive wtsState = iota - wtsConnected - wtsConnectQuery - wtsShadow - wtsDisconnected - wtsIdle - wtsListen - wtsReset - wtsDown - wtsInit -) - -type wtsSessionNotification struct { - size uint32 - sessionID uint32 -} - -type wtsSessionInfo struct { - sessionID uint32 - windowStationName *uint16 - state wtsState -} - -//sys wtsQueryUserToken(session uint32, token *windows.Token) (err error) = wtsapi32.WTSQueryUserToken -//sys wtsEnumerateSessions(handle windows.Handle, reserved uint32, version uint32, sessions **wtsSessionInfo, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW -//sys wtsFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory - -const ( - SE_KERNEL_OBJECT = 6 - DACL_SECURITY_INFORMATION = 4 - ATTRIBUTE_SECURITY_INFORMATION = 16 -) - -//sys getSecurityInfo(handle windows.Handle, objectType uint32, si uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *uintptr, sacl *uintptr, securityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo -//sys getSecurityDescriptorLength(securityDescriptor uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength - -//sys createEnvironmentBlock(block *uintptr, token windows.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock -//sys destroyEnvironmentBlock(block uintptr) (err error) = userenv.DestroyEnvironmentBlock - -func userEnviron(token windows.Token) (env []string, err error) { - var block uintptr - err = createEnvironmentBlock(&block, token, false) - if err != nil { - return - } - offset := uintptr(0) - for { - entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(block + offset))[:] - for i, v := range entry { - if v == 0 { - entry = entry[:i] - break - } - } - if len(entry) == 0 { - break - } - env = append(env, string(utf16.Decode(entry))) - offset += 2 * (uintptr(len(entry)) + 1) - } - destroyEnvironmentBlock(block) - return -} - type managerService struct{} func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) { @@ -126,29 +53,12 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest serviceError = ErrorDetermineExecutablePath return } - - adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) - if err != nil { - serviceError = ErrorFindAdministratorsSID - return - } - - currentProcess, err := windows.GetCurrentProcess() - if err != nil { - panic(err) - } - var securityAttributes syscall.SecurityAttributes - err = getSecurityInfo(currentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, nil, nil, &securityAttributes.SecurityDescriptor) + securityAttributes, err := getCurrentSecurityAttributes() if err != nil { serviceError = ErrorCreateSecurityDescriptor return } defer windows.LocalFree(windows.Handle(securityAttributes.SecurityDescriptor)) - securityAttributes.Length = getSecurityDescriptorLength(securityAttributes.SecurityDescriptor) - if securityAttributes.Length == 0 { - serviceError = ErrorCreateSecurityDescriptor - return - } devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) if err != nil { @@ -172,49 +82,51 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest startProcess = func(session uint32) { defer runtime.UnlockOSThread() + + var userToken windows.Token + err := wtsQueryUserToken(session, &userToken) + if err != nil { + return + } + defer userToken.Close() + if !tokenIsMemberOfBuiltInAdministrator(userToken) { + return + } + user, err := userToken.GetTokenUser() + if err != nil { + log.Printf("Unable to lookup user from token: %v", err) + return + } + username, domain, accType, err := user.User.Sid.LookupAccount("") + if err != nil { + log.Printf("Unable to lookup username from sid: %v", err) + return + } + if accType != windows.SidTypeUser { + return + } + env, err := userEnviron(userToken) + if err != nil { + log.Printf("Unable to determine user environment: %v", err) + return + } + userTokenInfo := &UserTokenInfo{} + userTokenInfo.elevatedToken, err = getElevatedToken(userToken) + if err != nil { + log.Printf("Unable to elevate token: %v", err) + } + if userTokenInfo.elevatedToken != userToken { + defer userTokenInfo.elevatedToken.Close() + } + userTokenInfo.elevatedEnvironment, err = userEnviron(userTokenInfo.elevatedToken) + if err != nil { + log.Printf("Unable to determine elevated environment: %v", err) + return + } for { if stoppingManager { return } - var userToken windows.Token - err := wtsQueryUserToken(session, &userToken) - if err != nil { - return - } - - //TODO: SECURITY CRITICIAL! - //TODO: Isn't it better to use an impersonation token and userToken.IsMember instead? - gs, err := userToken.GetTokenGroups() - if err != nil { - log.Printf("Unable to lookup user groups from token: %v", err) - return - } - p := unsafe.Pointer(&gs.Groups[0]) - groups := (*[(1 << 28) - 1]windows.SIDAndAttributes)(p)[:gs.GroupCount] - isAdmin := false - for _, g := range groups { - if windows.EqualSid(g.Sid, adminSid) { - isAdmin = true - break - } - } - if !isAdmin { - return - } - - user, err := userToken.GetTokenUser() - if err != nil { - log.Printf("Unable to lookup user from token: %v", err) - return - } - username, domain, accType, err := user.User.Sid.LookupAccount("") - if err != nil { - log.Printf("Unable to lookup username from sid: %v", err) - return - } - if accType != windows.SidTypeUser { - return - } //TODO: we lock the OS thread so that these inheritable handles don't escape into other processes that // might be running in parallel Go routines. But the Go runtime is strange and who knows what's really @@ -226,7 +138,7 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest return } ourEvents, theirEvents, theirEventStr, err := inheritableEvents() - err = IPCServerListen(ourReader, ourWriter, ourEvents) + err = IPCServerListen(ourReader, ourWriter, ourEvents, userTokenInfo) if err != nil { log.Printf("Unable to listen on IPC pipes: %v", err) return @@ -237,12 +149,6 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest return } - env, err := userEnviron(userToken) - if err != nil { - log.Printf("Unable to determine user environment: %v", err) - return - } - log.Printf("Starting UI process for user: '%s@%s'", username, domain) attr := &os.ProcAttr{ Sys: &syscall.SysProcAttr{ @@ -286,6 +192,8 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest } } + go checkForUpdates() + var sessionsPointer *wtsSessionInfo var count uint32 err = wtsEnumerateSessions(0, 0, 1, &sessionsPointer, &count) -- cgit v1.2.3-59-g8ed1b