From 8d026ad24a9b48254fbc71921557c6f7aad58b7e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sat, 23 Nov 2019 14:31:19 +0100 Subject: elevate: add DoAsSystem helper --- elevate/doas.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 elevate/doas.go diff --git a/elevate/doas.go b/elevate/doas.go new file mode 100644 index 00000000..ede22a9a --- /dev/null +++ b/elevate/doas.go @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package elevate + +import ( + "errors" + "runtime" + "strings" + "unsafe" + + "golang.org/x/sys/windows" +) + +func DoAsSystem(f func() error) error { + runtime.LockOSThread() + defer func() { + windows.RevertToSelf() + runtime.UnlockOSThread() + }() + privileges := windows.Tokenprivileges{ + PrivilegeCount: 1, + Privileges: [1]windows.LUIDAndAttributes{ + { + Attributes: windows.SE_PRIVILEGE_ENABLED, + }, + }, + } + err := windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr("SeDebugPrivilege"), &privileges.Privileges[0].Luid) + if err != nil { + return err + } + err = windows.ImpersonateSelf(windows.SecurityImpersonation) + if err != nil { + return err + } + var threadToken windows.Token + err = windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_QUERY|windows.TOKEN_ADJUST_PRIVILEGES, false, &threadToken) + if err != nil { + return err + } + defer threadToken.Close() + tokenUser, err := threadToken.GetTokenUser() + if err == nil && tokenUser.User.Sid.IsWellKnown(windows.WinLocalSystemSid) { + return f() + } + err = windows.AdjustTokenPrivileges(threadToken, false, &privileges, uint32(unsafe.Sizeof(privileges)), nil, nil) + if err != nil { + return err + } + + processes, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) + if err != nil { + return err + } + defer windows.CloseHandle(processes) + + var winlogonToken windows.Token + processEntry := windows.ProcessEntry32{Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{}))} + for err = windows.Process32First(processes, &processEntry); err == nil; err = windows.Process32Next(processes, &processEntry) { + if strings.ToLower(windows.UTF16ToString(processEntry.ExeFile[:])) != "winlogon.exe" { + continue + } + winlogonProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, processEntry.ProcessID) + if err != nil { + continue + } + err = windows.OpenProcessToken(winlogonProcess, windows.TOKEN_QUERY|windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE, &winlogonToken) + if err != nil { + windows.CloseHandle(winlogonProcess) + continue + } + tokenUser, err := winlogonToken.GetTokenUser() + if err != nil || !tokenUser.User.Sid.IsWellKnown(windows.WinLocalSystemSid) { + windows.CloseHandle(winlogonProcess) + winlogonToken.Close() + winlogonToken = 0 + continue + } + defer windows.CloseHandle(winlogonProcess) + defer winlogonToken.Close() + break + } + if winlogonToken == 0 { + return errors.New("unable to find winlogon.exe process") + } + var duplicatedToken windows.Token + err = windows.DuplicateTokenEx(winlogonToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken) + if err != nil { + return err + } + defer duplicatedToken.Close() + err = windows.SetThreadToken(nil, duplicatedToken) + if err != nil { + return err + } + return f() +} -- cgit v1.2.3-59-g8ed1b