security_windows.mx raw
1 // Copyright 2016 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 package windows
6
7 import (
8 "runtime"
9 "syscall"
10 "unsafe"
11 )
12
13 const (
14 SecurityAnonymous = 0
15 SecurityIdentification = 1
16 SecurityImpersonation = 2
17 SecurityDelegation = 3
18 )
19
20 //sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
21 //sys RevertToSelf() (err error) = advapi32.RevertToSelf
22 //sys ImpersonateLoggedOnUser(token syscall.Token) (err error) = advapi32.ImpersonateLoggedOnUser
23 //sys LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *syscall.Token) (err error) = advapi32.LogonUserW
24
25 const (
26 TOKEN_ADJUST_PRIVILEGES = 0x0020
27 SE_PRIVILEGE_ENABLED = 0x00000002
28 )
29
30 type LUID struct {
31 LowPart uint32
32 HighPart int32
33 }
34
35 type LUID_AND_ATTRIBUTES struct {
36 Luid LUID
37 Attributes uint32
38 }
39
40 type TOKEN_PRIVILEGES struct {
41 PrivilegeCount uint32
42 Privileges [1]LUID_AND_ATTRIBUTES
43 }
44
45 //sys OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken
46 //sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
47 //sys adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges
48
49 func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error {
50 ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen)
51 if ret == 0 {
52 // AdjustTokenPrivileges call failed
53 return err
54 }
55 // AdjustTokenPrivileges call succeeded
56 if err == syscall.EINVAL {
57 // GetLastError returned ERROR_SUCCESS
58 return nil
59 }
60 return err
61 }
62
63 //sys DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) = advapi32.DuplicateTokenEx
64 //sys SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation unsafe.Pointer, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation
65
66 type SID_AND_ATTRIBUTES struct {
67 Sid *syscall.SID
68 Attributes uint32
69 }
70
71 type TOKEN_MANDATORY_LABEL struct {
72 Label SID_AND_ATTRIBUTES
73 }
74
75 func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 {
76 return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid)
77 }
78
79 const SE_GROUP_INTEGRITY = 0x00000020
80
81 type TokenType uint32
82
83 const (
84 TokenPrimary TokenType = 1
85 TokenImpersonation TokenType = 2
86 )
87
88 //sys GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) = userenv.GetProfilesDirectoryW
89
90 const (
91 LG_INCLUDE_INDIRECT = 0x1
92 MAX_PREFERRED_LENGTH = 0xFFFFFFFF
93 )
94
95 type LocalGroupUserInfo0 struct {
96 Name *uint16
97 }
98
99 const (
100 NERR_UserNotFound syscall.Errno = 2221
101 NERR_UserExists syscall.Errno = 2224
102 )
103
104 const (
105 USER_PRIV_USER = 1
106 )
107
108 type UserInfo1 struct {
109 Name *uint16
110 Password *uint16
111 PasswordAge uint32
112 Priv uint32
113 HomeDir *uint16
114 Comment *uint16
115 Flags uint32
116 ScriptPath *uint16
117 }
118
119 type UserInfo4 struct {
120 Name *uint16
121 Password *uint16
122 PasswordAge uint32
123 Priv uint32
124 HomeDir *uint16
125 Comment *uint16
126 Flags uint32
127 ScriptPath *uint16
128 AuthFlags uint32
129 FullName *uint16
130 UsrComment *uint16
131 Parms *uint16
132 Workstations *uint16
133 LastLogon uint32
134 LastLogoff uint32
135 AcctExpires uint32
136 MaxStorage uint32
137 UnitsPerWeek uint32
138 LogonHours *byte
139 BadPwCount uint32
140 NumLogons uint32
141 LogonServer *uint16
142 CountryCode uint32
143 CodePage uint32
144 UserSid *syscall.SID
145 PrimaryGroupID uint32
146 Profile *uint16
147 HomeDirDrive *uint16
148 PasswordExpired uint32
149 }
150
151 //sys NetUserAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint32) (neterr error) = netapi32.NetUserAdd
152 //sys NetUserDel(serverName *uint16, userName *uint16) (neterr error) = netapi32.NetUserDel
153 //sys NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) = netapi32.NetUserGetLocalGroups
154
155 // GetSystemDirectory retrieves the path to current location of the system
156 // directory, which is typically, though not always, `C:\Windows\System32`.
157 //
158 //go:linkname GetSystemDirectory
159 func GetSystemDirectory() string // Implemented in runtime package.
160
161 // GetUserName retrieves the user name of the current thread
162 // in the specified format.
163 func GetUserName(format uint32) (string, error) {
164 n := uint32(50)
165 for {
166 b := make([]uint16, n)
167 e := syscall.GetUserNameEx(format, &b[0], &n)
168 if e == nil {
169 return syscall.UTF16ToString(b[:n]), nil
170 }
171 if e != syscall.ERROR_MORE_DATA {
172 return "", e
173 }
174 if n <= uint32(len(b)) {
175 return "", e
176 }
177 }
178 }
179
180 // getTokenInfo retrieves a specified type of information about an access token.
181 func getTokenInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) {
182 n := uint32(initSize)
183 for {
184 b := make([]byte, n)
185 e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
186 if e == nil {
187 return unsafe.Pointer(&b[0]), nil
188 }
189 if e != syscall.ERROR_INSUFFICIENT_BUFFER {
190 return nil, e
191 }
192 if n <= uint32(len(b)) {
193 return nil, e
194 }
195 }
196 }
197
198 type TOKEN_GROUPS struct {
199 GroupCount uint32
200 Groups [1]SID_AND_ATTRIBUTES
201 }
202
203 func (g *TOKEN_GROUPS) AllGroups() []SID_AND_ATTRIBUTES {
204 return (*[(1 << 28) - 1]SID_AND_ATTRIBUTES)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
205 }
206
207 func GetTokenGroups(t syscall.Token) (*TOKEN_GROUPS, error) {
208 i, e := getTokenInfo(t, syscall.TokenGroups, 50)
209 if e != nil {
210 return nil, e
211 }
212 return (*TOKEN_GROUPS)(i), nil
213 }
214
215 // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority
216 type SID_IDENTIFIER_AUTHORITY struct {
217 Value [6]byte
218 }
219
220 const (
221 SID_REVISION = 1
222 // https://learn.microsoft.com/en-us/windows/win32/services/localsystem-account
223 SECURITY_LOCAL_SYSTEM_RID = 18
224 // https://learn.microsoft.com/en-us/windows/win32/services/localservice-account
225 SECURITY_LOCAL_SERVICE_RID = 19
226 // https://learn.microsoft.com/en-us/windows/win32/services/networkservice-account
227 SECURITY_NETWORK_SERVICE_RID = 20
228 )
229
230 var SECURITY_NT_AUTHORITY = SID_IDENTIFIER_AUTHORITY{
231 Value: [6]byte{0, 0, 0, 0, 0, 5},
232 }
233
234 //sys IsValidSid(sid *syscall.SID) (valid bool) = advapi32.IsValidSid
235 //sys getSidIdentifierAuthority(sid *syscall.SID) (idauth uintptr) = advapi32.GetSidIdentifierAuthority
236 //sys getSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) (subAuth uintptr) = advapi32.GetSidSubAuthority
237 //sys getSidSubAuthorityCount(sid *syscall.SID) (count uintptr) = advapi32.GetSidSubAuthorityCount
238
239 // The following GetSid* functions are marked as //go:nocheckptr because checkptr
240 // instrumentation can't see that the pointer returned by the syscall is pointing
241 // into the sid's memory, which is normally allocated on the Go heap. Therefore,
242 // the checkptr instrumentation would incorrectly flag the pointer dereference
243 // as pointing to an invalid allocation.
244 // Also, use runtime.KeepAlive to ensure that the sid is not garbage collected
245 // before the GetSid* functions return, as the Go GC is not aware that the
246 // pointers returned by the syscall are pointing into the sid's memory.
247
248 //go:nocheckptr
249 func GetSidIdentifierAuthority(sid *syscall.SID) SID_IDENTIFIER_AUTHORITY {
250 defer runtime.KeepAlive(sid)
251 return *(*SID_IDENTIFIER_AUTHORITY)(unsafe.Pointer(getSidIdentifierAuthority(sid)))
252 }
253
254 //go:nocheckptr
255 func GetSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) uint32 {
256 defer runtime.KeepAlive(sid)
257 return *(*uint32)(unsafe.Pointer(getSidSubAuthority(sid, subAuthorityIdx)))
258 }
259
260 //go:nocheckptr
261 func GetSidSubAuthorityCount(sid *syscall.SID) uint8 {
262 defer runtime.KeepAlive(sid)
263 return *(*uint8)(unsafe.Pointer(getSidSubAuthorityCount(sid)))
264 }
265