.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / sys@v0.0.0-20210124154548-22da62e12c0c / windows / svc / security.go
1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build windows
6
7 package svc
8
9 import (
10         "errors"
11         "syscall"
12         "unsafe"
13
14         "golang.org/x/sys/windows"
15 )
16
17 func allocSid(subAuth0 uint32) (*windows.SID, error) {
18         var sid *windows.SID
19         err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
20                 1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
21         if err != nil {
22                 return nil, err
23         }
24         return sid, nil
25 }
26
27 // IsAnInteractiveSession determines if calling process is running interactively.
28 // It queries the process token for membership in the Interactive group.
29 // http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
30 //
31 // Deprecated: Use IsWindowsService instead.
32 func IsAnInteractiveSession() (bool, error) {
33         interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
34         if err != nil {
35                 return false, err
36         }
37         defer windows.FreeSid(interSid)
38
39         serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
40         if err != nil {
41                 return false, err
42         }
43         defer windows.FreeSid(serviceSid)
44
45         t, err := windows.OpenCurrentProcessToken()
46         if err != nil {
47                 return false, err
48         }
49         defer t.Close()
50
51         gs, err := t.GetTokenGroups()
52         if err != nil {
53                 return false, err
54         }
55
56         for _, g := range gs.AllGroups() {
57                 if windows.EqualSid(g.Sid, interSid) {
58                         return true, nil
59                 }
60                 if windows.EqualSid(g.Sid, serviceSid) {
61                         return false, nil
62                 }
63         }
64         return false, nil
65 }
66
67 var (
68         ntdll                      = windows.NewLazySystemDLL("ntdll.dll")
69         _NtQueryInformationProcess = ntdll.NewProc("NtQueryInformationProcess")
70
71         kernel32                    = windows.NewLazySystemDLL("kernel32.dll")
72         _QueryFullProcessImageNameA = kernel32.NewProc("QueryFullProcessImageNameA")
73 )
74
75 // IsWindowsService reports whether the process is currently executing
76 // as a Windows service.
77 func IsWindowsService() (bool, error) {
78         // This code was copied from runtime.isWindowsService function.
79
80         // The below technique looks a bit hairy, but it's actually
81         // exactly what the .NET framework does for the similarly named function:
82         // https://github.com/dotnet/extensions/blob/f4066026ca06984b07e90e61a6390ac38152ba93/src/Hosting/WindowsServices/src/WindowsServiceHelpers.cs#L26-L31
83         // Specifically, it looks up whether the parent process has session ID zero
84         // and is called "services".
85         const _CURRENT_PROCESS = ^uintptr(0)
86         // pbi is a PROCESS_BASIC_INFORMATION struct, where we just care about
87         // the 6th pointer inside of it, which contains the pid of the process
88         // parent:
89         // https://github.com/wine-mirror/wine/blob/42cb7d2ad1caba08de235e6319b9967296b5d554/include/winternl.h#L1294
90         var pbi [6]uintptr
91         var pbiLen uint32
92         r0, _, _ := syscall.Syscall6(_NtQueryInformationProcess.Addr(), 5, _CURRENT_PROCESS, 0, uintptr(unsafe.Pointer(&pbi[0])), uintptr(unsafe.Sizeof(pbi)), uintptr(unsafe.Pointer(&pbiLen)), 0)
93         if r0 != 0 {
94                 return false, errors.New("NtQueryInformationProcess failed: error=" + itoa(int(r0)))
95         }
96         var psid uint32
97         err := windows.ProcessIdToSessionId(uint32(pbi[5]), &psid)
98         if err != nil {
99                 return false, err
100         }
101         if psid != 0 {
102                 // parent session id should be 0 for service process
103                 return false, nil
104         }
105
106         pproc, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pbi[5]))
107         if err != nil {
108                 return false, err
109         }
110         defer windows.CloseHandle(pproc)
111
112         // exeName gets the path to the executable image of the parent process
113         var exeName [261]byte
114         exeNameLen := uint32(len(exeName) - 1)
115         r0, _, e0 := syscall.Syscall6(_QueryFullProcessImageNameA.Addr(), 4, uintptr(pproc), 0, uintptr(unsafe.Pointer(&exeName[0])), uintptr(unsafe.Pointer(&exeNameLen)), 0, 0)
116         if r0 == 0 {
117                 if e0 != 0 {
118                         return false, e0
119                 } else {
120                         return false, syscall.EINVAL
121                 }
122         }
123         const (
124                 servicesLower = "services.exe"
125                 servicesUpper = "SERVICES.EXE"
126         )
127         i := int(exeNameLen) - 1
128         j := len(servicesLower) - 1
129         if i < j {
130                 return false, nil
131         }
132         for {
133                 if j == -1 {
134                         return i == -1 || exeName[i] == '\\', nil
135                 }
136                 if exeName[i] != servicesLower[j] && exeName[i] != servicesUpper[j] {
137                         return false, nil
138                 }
139                 i--
140                 j--
141         }
142 }
143
144 func itoa(val int) string { // do it here rather than with fmt to avoid dependency
145         if val < 0 {
146                 return "-" + itoa(-val)
147         }
148         var buf [32]byte // big enough for int64
149         i := len(buf) - 1
150         for val >= 10 {
151                 buf[i] = byte(val%10 + '0')
152                 i--
153                 val /= 10
154         }
155         buf[i] = byte(val + '0')
156         return string(buf[i:])
157 }