aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-11-23 14:31:19 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2019-11-24 00:04:41 +0100
commit8d026ad24a9b48254fbc71921557c6f7aad58b7e (patch)
tree9b0b295799a53f484ff57cbaa397bddd36e54346
parentui: remove trailing … from file dialog titles (diff)
downloadwireguard-windows-8d026ad24a9b48254fbc71921557c6f7aad58b7e.tar.xz
wireguard-windows-8d026ad24a9b48254fbc71921557c6f7aad58b7e.zip
elevate: add DoAsSystem helper
-rw-r--r--elevate/doas.go100
1 files changed, 100 insertions, 0 deletions
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()
+}