diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-12-06 13:47:00 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-12-11 12:06:25 +0100 |
commit | b0b375d89566b4cfaa506c3bb22b25e816b15508 (patch) | |
tree | 3a7c5281129aa4702c85c490bf06d575af25d9db /elevate/doas.go | |
parent | firewall: fix urls (diff) | |
download | wireguard-windows-b0b375d89566b4cfaa506c3bb22b25e816b15508.tar.xz wireguard-windows-b0b375d89566b4cfaa506c3bb22b25e816b15508.zip |
elevate: add service impersonation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to '')
-rw-r--r-- | elevate/doas.go | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/elevate/doas.go b/elevate/doas.go index ede22a9a..ceedb78b 100644 --- a/elevate/doas.go +++ b/elevate/doas.go @@ -12,6 +12,7 @@ import ( "unsafe" "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc/mgr" ) func DoAsSystem(f func() error) error { @@ -41,12 +42,13 @@ func DoAsSystem(f func() error) error { if err != nil { return err } - defer threadToken.Close() tokenUser, err := threadToken.GetTokenUser() if err == nil && tokenUser.User.Sid.IsWellKnown(windows.WinLocalSystemSid) { + threadToken.Close() return f() } err = windows.AdjustTokenPrivileges(threadToken, false, &privileges, uint32(unsafe.Sizeof(privileges)), nil, nil) + threadToken.Close() if err != nil { return err } @@ -55,9 +57,6 @@ func DoAsSystem(f func() error) error { 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" { @@ -67,34 +66,76 @@ func DoAsSystem(f func() error) error { if err != nil { continue } + var winlogonToken windows.Token err = windows.OpenProcessToken(winlogonProcess, windows.TOKEN_QUERY|windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE, &winlogonToken) + windows.CloseHandle(winlogonProcess) 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 + windows.CloseHandle(processes) + + var duplicatedToken windows.Token + err = windows.DuplicateTokenEx(winlogonToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken) + windows.CloseHandle(winlogonProcess) + if err != nil { + return err + } + err = windows.SetThreadToken(nil, duplicatedToken) + duplicatedToken.Close() + if err != nil { + return err + } + return f() } - if winlogonToken == 0 { - return errors.New("unable to find winlogon.exe process") + windows.CloseHandle(processes) + return errors.New("unable to find winlogon.exe process") +} + +func DoAsService(serviceName string, f func() error) error { + scm, err := mgr.Connect() + if err != nil { + return err } - var duplicatedToken windows.Token - err = windows.DuplicateTokenEx(winlogonToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken) + service, err := scm.OpenService(serviceName) + scm.Disconnect() if err != nil { return err } - defer duplicatedToken.Close() - err = windows.SetThreadToken(nil, duplicatedToken) + status, err := service.Query() + service.Close() if err != nil { return err } - return f() + if status.ProcessId == 0 { + return errors.New("service is not running") + } + return DoAsSystem(func() error { + serviceProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, status.ProcessId) + if err != nil { + return err + } + var serviceToken windows.Token + err = windows.OpenProcessToken(serviceProcess, windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE, &serviceToken) + windows.CloseHandle(serviceProcess) + if err != nil { + return err + } + var duplicatedToken windows.Token + err = windows.DuplicateTokenEx(serviceToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken) + serviceToken.Close() + if err != nil { + return err + } + err = windows.SetThreadToken(nil, duplicatedToken) + duplicatedToken.Close() + if err != nil { + return err + } + return f() + }) } |