liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
 
package syscall
 
import (
   "unsafe"
)
 
const (
   STANDARD_RIGHTS_REQUIRED = 0xf0000
   STANDARD_RIGHTS_READ     = 0x20000
   STANDARD_RIGHTS_WRITE    = 0x20000
   STANDARD_RIGHTS_EXECUTE  = 0x20000
   STANDARD_RIGHTS_ALL      = 0x1F0000
)
 
const (
   NameUnknown          = 0
   NameFullyQualifiedDN = 1
   NameSamCompatible    = 2
   NameDisplay          = 3
   NameUniqueId         = 6
   NameCanonical        = 7
   NameUserPrincipal    = 8
   NameCanonicalEx      = 9
   NameServicePrincipal = 10
   NameDnsDomain        = 12
)
 
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
// https://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
//sys    TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
//sys    GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
 
// TranslateAccountName converts a directory service
// object name from one format to another.
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
   u, e := UTF16PtrFromString(username)
   if e != nil {
       return "", e
   }
   n := uint32(50)
   for {
       b := make([]uint16, n)
       e = TranslateName(u, from, to, &b[0], &n)
       if e == nil {
           return UTF16ToString(b[:n]), nil
       }
       if e != ERROR_INSUFFICIENT_BUFFER {
           return "", e
       }
       if n <= uint32(len(b)) {
           return "", e
       }
   }
}
 
const (
   // do not reorder
   NetSetupUnknownStatus = iota
   NetSetupUnjoined
   NetSetupWorkgroupName
   NetSetupDomainName
)
 
type UserInfo10 struct {
   Name       *uint16
   Comment    *uint16
   UsrComment *uint16
   FullName   *uint16
}
 
//sys    NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
//sys    NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
//sys    NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
 
const (
   // do not reorder
   SidTypeUser = 1 + iota
   SidTypeGroup
   SidTypeDomain
   SidTypeAlias
   SidTypeWellKnownGroup
   SidTypeDeletedAccount
   SidTypeInvalid
   SidTypeUnknown
   SidTypeComputer
   SidTypeLabel
)
 
//sys    LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
//sys    LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
//sys    ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys    ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
//sys    GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
//sys    CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
 
// The security identifier (SID) structure is a variable-length
// structure used to uniquely identify users or groups.
type SID struct{}
 
// StringToSid converts a string-format security identifier
// sid into a valid, functional sid.
func StringToSid(s string) (*SID, error) {
   var sid *SID
   p, e := UTF16PtrFromString(s)
   if e != nil {
       return nil, e
   }
   e = ConvertStringSidToSid(p, &sid)
   if e != nil {
       return nil, e
   }
   defer LocalFree((Handle)(unsafe.Pointer(sid)))
   return sid.Copy()
}
 
// LookupSID retrieves a security identifier sid for the account
// and the name of the domain on which the account was found.
// System specify target computer to search.
func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
   if len(account) == 0 {
       return nil, "", 0, EINVAL
   }
   acc, e := UTF16PtrFromString(account)
   if e != nil {
       return nil, "", 0, e
   }
   var sys *uint16
   if len(system) > 0 {
       sys, e = UTF16PtrFromString(system)
       if e != nil {
           return nil, "", 0, e
       }
   }
   n := uint32(50)
   dn := uint32(50)
   for {
       b := make([]byte, n)
       db := make([]uint16, dn)
       sid = (*SID)(unsafe.Pointer(&b[0]))
       e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
       if e == nil {
           return sid, UTF16ToString(db), accType, nil
       }
       if e != ERROR_INSUFFICIENT_BUFFER {
           return nil, "", 0, e
       }
       if n <= uint32(len(b)) {
           return nil, "", 0, e
       }
   }
}
 
// String converts sid to a string format
// suitable for display, storage, or transmission.
func (sid *SID) String() (string, error) {
   var s *uint16
   e := ConvertSidToStringSid(sid, &s)
   if e != nil {
       return "", e
   }
   defer LocalFree((Handle)(unsafe.Pointer(s)))
   return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
}
 
// Len returns the length, in bytes, of a valid security identifier sid.
func (sid *SID) Len() int {
   return int(GetLengthSid(sid))
}
 
// Copy creates a duplicate of security identifier sid.
func (sid *SID) Copy() (*SID, error) {
   b := make([]byte, sid.Len())
   sid2 := (*SID)(unsafe.Pointer(&b[0]))
   e := CopySid(uint32(len(b)), sid2, sid)
   if e != nil {
       return nil, e
   }
   return sid2, nil
}
 
// LookupAccount retrieves the name of the account for this sid
// and the name of the first domain on which this sid is found.
// System specify target computer to search for.
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
   var sys *uint16
   if len(system) > 0 {
       sys, err = UTF16PtrFromString(system)
       if err != nil {
           return "", "", 0, err
       }
   }
   n := uint32(50)
   dn := uint32(50)
   for {
       b := make([]uint16, n)
       db := make([]uint16, dn)
       e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
       if e == nil {
           return UTF16ToString(b), UTF16ToString(db), accType, nil
       }
       if e != ERROR_INSUFFICIENT_BUFFER {
           return "", "", 0, e
       }
       if n <= uint32(len(b)) {
           return "", "", 0, e
       }
   }
}
 
const (
   // do not reorder
   TOKEN_ASSIGN_PRIMARY = 1 << iota
   TOKEN_DUPLICATE
   TOKEN_IMPERSONATE
   TOKEN_QUERY
   TOKEN_QUERY_SOURCE
   TOKEN_ADJUST_PRIVILEGES
   TOKEN_ADJUST_GROUPS
   TOKEN_ADJUST_DEFAULT
   TOKEN_ADJUST_SESSIONID
 
   TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
       TOKEN_ASSIGN_PRIMARY |
       TOKEN_DUPLICATE |
       TOKEN_IMPERSONATE |
       TOKEN_QUERY |
       TOKEN_QUERY_SOURCE |
       TOKEN_ADJUST_PRIVILEGES |
       TOKEN_ADJUST_GROUPS |
       TOKEN_ADJUST_DEFAULT |
       TOKEN_ADJUST_SESSIONID
   TOKEN_READ  = STANDARD_RIGHTS_READ | TOKEN_QUERY
   TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
       TOKEN_ADJUST_PRIVILEGES |
       TOKEN_ADJUST_GROUPS |
       TOKEN_ADJUST_DEFAULT
   TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
)
 
const (
   // do not reorder
   TokenUser = 1 + iota
   TokenGroups
   TokenPrivileges
   TokenOwner
   TokenPrimaryGroup
   TokenDefaultDacl
   TokenSource
   TokenType
   TokenImpersonationLevel
   TokenStatistics
   TokenRestrictedSids
   TokenSessionId
   TokenGroupsAndPrivileges
   TokenSessionReference
   TokenSandBoxInert
   TokenAuditPolicy
   TokenOrigin
   TokenElevationType
   TokenLinkedToken
   TokenElevation
   TokenHasRestrictions
   TokenAccessInformation
   TokenVirtualizationAllowed
   TokenVirtualizationEnabled
   TokenIntegrityLevel
   TokenUIAccess
   TokenMandatoryPolicy
   TokenLogonSid
   MaxTokenInfoClass
)
 
type SIDAndAttributes struct {
   Sid        *SID
   Attributes uint32
}
 
type Tokenuser struct {
   User SIDAndAttributes
}
 
type Tokenprimarygroup struct {
   PrimaryGroup *SID
}
 
//sys    OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
//sys    GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
//sys    GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
 
// An access token contains the security information for a logon session.
// The system creates an access token when a user logs on, and every
// process executed on behalf of the user has a copy of the token.
// The token identifies the user, the user's groups, and the user's
// privileges. The system uses the token to control access to securable
// objects and to control the ability of the user to perform various
// system-related operations on the local computer.
type Token Handle
 
// OpenCurrentProcessToken opens the access token
// associated with current process.
func OpenCurrentProcessToken() (Token, error) {
   p, e := GetCurrentProcess()
   if e != nil {
       return 0, e
   }
   var t Token
   e = OpenProcessToken(p, TOKEN_QUERY, &t)
   if e != nil {
       return 0, e
   }
   return t, nil
}
 
// Close releases access to access token.
func (t Token) Close() error {
   return CloseHandle(Handle(t))
}
 
// getInfo retrieves a specified type of information about an access token.
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
   n := uint32(initSize)
   for {
       b := make([]byte, n)
       e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
       if e == nil {
           return unsafe.Pointer(&b[0]), nil
       }
       if e != ERROR_INSUFFICIENT_BUFFER {
           return nil, e
       }
       if n <= uint32(len(b)) {
           return nil, e
       }
   }
}
 
// GetTokenUser retrieves access token t user account information.
func (t Token) GetTokenUser() (*Tokenuser, error) {
   i, e := t.getInfo(TokenUser, 50)
   if e != nil {
       return nil, e
   }
   return (*Tokenuser)(i), nil
}
 
// GetTokenPrimaryGroup retrieves access token t primary group information.
// A pointer to a SID structure representing a group that will become
// the primary group of any objects created by a process using this access token.
func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
   i, e := t.getInfo(TokenPrimaryGroup, 50)
   if e != nil {
       return nil, e
   }
   return (*Tokenprimarygroup)(i), nil
}
 
// GetUserProfileDirectory retrieves path to the
// root directory of the access token t user's profile.
func (t Token) GetUserProfileDirectory() (string, error) {
   n := uint32(100)
   for {
       b := make([]uint16, n)
       e := GetUserProfileDirectory(t, &b[0], &n)
       if e == nil {
           return UTF16ToString(b), nil
       }
       if e != ERROR_INSUFFICIENT_BUFFER {
           return "", e
       }
       if n <= uint32(len(b)) {
           return "", e
       }
   }
}