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
5package windows
6
7import (
8	"syscall"
9	"unsafe"
10)
11
12const (
13	STANDARD_RIGHTS_REQUIRED = 0xf0000
14	STANDARD_RIGHTS_READ     = 0x20000
15	STANDARD_RIGHTS_WRITE    = 0x20000
16	STANDARD_RIGHTS_EXECUTE  = 0x20000
17	STANDARD_RIGHTS_ALL      = 0x1F0000
18)
19
20const (
21	NameUnknown          = 0
22	NameFullyQualifiedDN = 1
23	NameSamCompatible    = 2
24	NameDisplay          = 3
25	NameUniqueId         = 6
26	NameCanonical        = 7
27	NameUserPrincipal    = 8
28	NameCanonicalEx      = 9
29	NameServicePrincipal = 10
30	NameDnsDomain        = 12
31)
32
33// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
34// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
35//sys	TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
36//sys	GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
37
38// TranslateAccountName converts a directory service
39// object name from one format to another.
40func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
41	u, e := UTF16PtrFromString(username)
42	if e != nil {
43		return "", e
44	}
45	n := uint32(50)
46	for {
47		b := make([]uint16, n)
48		e = TranslateName(u, from, to, &b[0], &n)
49		if e == nil {
50			return UTF16ToString(b[:n]), nil
51		}
52		if e != ERROR_INSUFFICIENT_BUFFER {
53			return "", e
54		}
55		if n <= uint32(len(b)) {
56			return "", e
57		}
58	}
59}
60
61const (
62	// do not reorder
63	NetSetupUnknownStatus = iota
64	NetSetupUnjoined
65	NetSetupWorkgroupName
66	NetSetupDomainName
67)
68
69type UserInfo10 struct {
70	Name       *uint16
71	Comment    *uint16
72	UsrComment *uint16
73	FullName   *uint16
74}
75
76//sys	NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
77//sys	NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
78//sys	NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
79
80const (
81	// do not reorder
82	SidTypeUser = 1 + iota
83	SidTypeGroup
84	SidTypeDomain
85	SidTypeAlias
86	SidTypeWellKnownGroup
87	SidTypeDeletedAccount
88	SidTypeInvalid
89	SidTypeUnknown
90	SidTypeComputer
91	SidTypeLabel
92)
93
94type SidIdentifierAuthority struct {
95	Value [6]byte
96}
97
98var (
99	SECURITY_NULL_SID_AUTHORITY        = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}}
100	SECURITY_WORLD_SID_AUTHORITY       = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}}
101	SECURITY_LOCAL_SID_AUTHORITY       = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}}
102	SECURITY_CREATOR_SID_AUTHORITY     = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}}
103	SECURITY_NON_UNIQUE_AUTHORITY      = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}}
104	SECURITY_NT_AUTHORITY              = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}}
105	SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}}
106)
107
108const (
109	SECURITY_NULL_RID                   = 0
110	SECURITY_WORLD_RID                  = 0
111	SECURITY_LOCAL_RID                  = 0
112	SECURITY_CREATOR_OWNER_RID          = 0
113	SECURITY_CREATOR_GROUP_RID          = 1
114	SECURITY_DIALUP_RID                 = 1
115	SECURITY_NETWORK_RID                = 2
116	SECURITY_BATCH_RID                  = 3
117	SECURITY_INTERACTIVE_RID            = 4
118	SECURITY_LOGON_IDS_RID              = 5
119	SECURITY_SERVICE_RID                = 6
120	SECURITY_LOCAL_SYSTEM_RID           = 18
121	SECURITY_BUILTIN_DOMAIN_RID         = 32
122	SECURITY_PRINCIPAL_SELF_RID         = 10
123	SECURITY_CREATOR_OWNER_SERVER_RID   = 0x2
124	SECURITY_CREATOR_GROUP_SERVER_RID   = 0x3
125	SECURITY_LOGON_IDS_RID_COUNT        = 0x3
126	SECURITY_ANONYMOUS_LOGON_RID        = 0x7
127	SECURITY_PROXY_RID                  = 0x8
128	SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
129	SECURITY_SERVER_LOGON_RID           = SECURITY_ENTERPRISE_CONTROLLERS_RID
130	SECURITY_AUTHENTICATED_USER_RID     = 0xb
131	SECURITY_RESTRICTED_CODE_RID        = 0xc
132	SECURITY_NT_NON_UNIQUE_RID          = 0x15
133)
134
135// Predefined domain-relative RIDs for local groups.
136// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379649(v=vs.85).aspx
137const (
138	DOMAIN_ALIAS_RID_ADMINS                         = 0x220
139	DOMAIN_ALIAS_RID_USERS                          = 0x221
140	DOMAIN_ALIAS_RID_GUESTS                         = 0x222
141	DOMAIN_ALIAS_RID_POWER_USERS                    = 0x223
142	DOMAIN_ALIAS_RID_ACCOUNT_OPS                    = 0x224
143	DOMAIN_ALIAS_RID_SYSTEM_OPS                     = 0x225
144	DOMAIN_ALIAS_RID_PRINT_OPS                      = 0x226
145	DOMAIN_ALIAS_RID_BACKUP_OPS                     = 0x227
146	DOMAIN_ALIAS_RID_REPLICATOR                     = 0x228
147	DOMAIN_ALIAS_RID_RAS_SERVERS                    = 0x229
148	DOMAIN_ALIAS_RID_PREW2KCOMPACCESS               = 0x22a
149	DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS           = 0x22b
150	DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS      = 0x22c
151	DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS = 0x22d
152	DOMAIN_ALIAS_RID_MONITORING_USERS               = 0X22e
153	DOMAIN_ALIAS_RID_LOGGING_USERS                  = 0x22f
154	DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS            = 0x230
155	DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS             = 0x231
156	DOMAIN_ALIAS_RID_DCOM_USERS                     = 0x232
157	DOMAIN_ALIAS_RID_IUSERS                         = 0x238
158	DOMAIN_ALIAS_RID_CRYPTO_OPERATORS               = 0x239
159	DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP     = 0x23b
160	DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP = 0x23c
161	DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP        = 0x23d
162	DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP      = 0x23e
163)
164
165//sys	LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
166//sys	LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
167//sys	ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
168//sys	ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
169//sys	GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
170//sys	CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
171//sys	AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid
172//sys	FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
173//sys	EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
174
175// The security identifier (SID) structure is a variable-length
176// structure used to uniquely identify users or groups.
177type SID struct{}
178
179// StringToSid converts a string-format security identifier
180// sid into a valid, functional sid.
181func StringToSid(s string) (*SID, error) {
182	var sid *SID
183	p, e := UTF16PtrFromString(s)
184	if e != nil {
185		return nil, e
186	}
187	e = ConvertStringSidToSid(p, &sid)
188	if e != nil {
189		return nil, e
190	}
191	defer LocalFree((Handle)(unsafe.Pointer(sid)))
192	return sid.Copy()
193}
194
195// LookupSID retrieves a security identifier sid for the account
196// and the name of the domain on which the account was found.
197// System specify target computer to search.
198func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
199	if len(account) == 0 {
200		return nil, "", 0, syscall.EINVAL
201	}
202	acc, e := UTF16PtrFromString(account)
203	if e != nil {
204		return nil, "", 0, e
205	}
206	var sys *uint16
207	if len(system) > 0 {
208		sys, e = UTF16PtrFromString(system)
209		if e != nil {
210			return nil, "", 0, e
211		}
212	}
213	n := uint32(50)
214	dn := uint32(50)
215	for {
216		b := make([]byte, n)
217		db := make([]uint16, dn)
218		sid = (*SID)(unsafe.Pointer(&b[0]))
219		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
220		if e == nil {
221			return sid, UTF16ToString(db), accType, nil
222		}
223		if e != ERROR_INSUFFICIENT_BUFFER {
224			return nil, "", 0, e
225		}
226		if n <= uint32(len(b)) {
227			return nil, "", 0, e
228		}
229	}
230}
231
232// String converts sid to a string format
233// suitable for display, storage, or transmission.
234func (sid *SID) String() (string, error) {
235	var s *uint16
236	e := ConvertSidToStringSid(sid, &s)
237	if e != nil {
238		return "", e
239	}
240	defer LocalFree((Handle)(unsafe.Pointer(s)))
241	return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
242}
243
244// Len returns the length, in bytes, of a valid security identifier sid.
245func (sid *SID) Len() int {
246	return int(GetLengthSid(sid))
247}
248
249// Copy creates a duplicate of security identifier sid.
250func (sid *SID) Copy() (*SID, error) {
251	b := make([]byte, sid.Len())
252	sid2 := (*SID)(unsafe.Pointer(&b[0]))
253	e := CopySid(uint32(len(b)), sid2, sid)
254	if e != nil {
255		return nil, e
256	}
257	return sid2, nil
258}
259
260// LookupAccount retrieves the name of the account for this sid
261// and the name of the first domain on which this sid is found.
262// System specify target computer to search for.
263func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
264	var sys *uint16
265	if len(system) > 0 {
266		sys, err = UTF16PtrFromString(system)
267		if err != nil {
268			return "", "", 0, err
269		}
270	}
271	n := uint32(50)
272	dn := uint32(50)
273	for {
274		b := make([]uint16, n)
275		db := make([]uint16, dn)
276		e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
277		if e == nil {
278			return UTF16ToString(b), UTF16ToString(db), accType, nil
279		}
280		if e != ERROR_INSUFFICIENT_BUFFER {
281			return "", "", 0, e
282		}
283		if n <= uint32(len(b)) {
284			return "", "", 0, e
285		}
286	}
287}
288
289const (
290	// do not reorder
291	TOKEN_ASSIGN_PRIMARY = 1 << iota
292	TOKEN_DUPLICATE
293	TOKEN_IMPERSONATE
294	TOKEN_QUERY
295	TOKEN_QUERY_SOURCE
296	TOKEN_ADJUST_PRIVILEGES
297	TOKEN_ADJUST_GROUPS
298	TOKEN_ADJUST_DEFAULT
299	TOKEN_ADJUST_SESSIONID
300
301	TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
302		TOKEN_ASSIGN_PRIMARY |
303		TOKEN_DUPLICATE |
304		TOKEN_IMPERSONATE |
305		TOKEN_QUERY |
306		TOKEN_QUERY_SOURCE |
307		TOKEN_ADJUST_PRIVILEGES |
308		TOKEN_ADJUST_GROUPS |
309		TOKEN_ADJUST_DEFAULT |
310		TOKEN_ADJUST_SESSIONID
311	TOKEN_READ  = STANDARD_RIGHTS_READ | TOKEN_QUERY
312	TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
313		TOKEN_ADJUST_PRIVILEGES |
314		TOKEN_ADJUST_GROUPS |
315		TOKEN_ADJUST_DEFAULT
316	TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
317)
318
319const (
320	// do not reorder
321	TokenUser = 1 + iota
322	TokenGroups
323	TokenPrivileges
324	TokenOwner
325	TokenPrimaryGroup
326	TokenDefaultDacl
327	TokenSource
328	TokenType
329	TokenImpersonationLevel
330	TokenStatistics
331	TokenRestrictedSids
332	TokenSessionId
333	TokenGroupsAndPrivileges
334	TokenSessionReference
335	TokenSandBoxInert
336	TokenAuditPolicy
337	TokenOrigin
338	TokenElevationType
339	TokenLinkedToken
340	TokenElevation
341	TokenHasRestrictions
342	TokenAccessInformation
343	TokenVirtualizationAllowed
344	TokenVirtualizationEnabled
345	TokenIntegrityLevel
346	TokenUIAccess
347	TokenMandatoryPolicy
348	TokenLogonSid
349	MaxTokenInfoClass
350)
351
352type SIDAndAttributes struct {
353	Sid        *SID
354	Attributes uint32
355}
356
357type Tokenuser struct {
358	User SIDAndAttributes
359}
360
361type Tokenprimarygroup struct {
362	PrimaryGroup *SID
363}
364
365type Tokengroups struct {
366	GroupCount uint32
367	Groups     [1]SIDAndAttributes
368}
369
370// Authorization Functions
371//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership
372//sys	OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
373//sys	GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
374//sys	GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
375
376// An access token contains the security information for a logon session.
377// The system creates an access token when a user logs on, and every
378// process executed on behalf of the user has a copy of the token.
379// The token identifies the user, the user's groups, and the user's
380// privileges. The system uses the token to control access to securable
381// objects and to control the ability of the user to perform various
382// system-related operations on the local computer.
383type Token Handle
384
385// OpenCurrentProcessToken opens the access token
386// associated with current process.
387func OpenCurrentProcessToken() (Token, error) {
388	p, e := GetCurrentProcess()
389	if e != nil {
390		return 0, e
391	}
392	var t Token
393	e = OpenProcessToken(p, TOKEN_QUERY, &t)
394	if e != nil {
395		return 0, e
396	}
397	return t, nil
398}
399
400// Close releases access to access token.
401func (t Token) Close() error {
402	return CloseHandle(Handle(t))
403}
404
405// getInfo retrieves a specified type of information about an access token.
406func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
407	n := uint32(initSize)
408	for {
409		b := make([]byte, n)
410		e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
411		if e == nil {
412			return unsafe.Pointer(&b[0]), nil
413		}
414		if e != ERROR_INSUFFICIENT_BUFFER {
415			return nil, e
416		}
417		if n <= uint32(len(b)) {
418			return nil, e
419		}
420	}
421}
422
423// GetTokenUser retrieves access token t user account information.
424func (t Token) GetTokenUser() (*Tokenuser, error) {
425	i, e := t.getInfo(TokenUser, 50)
426	if e != nil {
427		return nil, e
428	}
429	return (*Tokenuser)(i), nil
430}
431
432// GetTokenGroups retrieves group accounts associated with access token t.
433func (t Token) GetTokenGroups() (*Tokengroups, error) {
434	i, e := t.getInfo(TokenGroups, 50)
435	if e != nil {
436		return nil, e
437	}
438	return (*Tokengroups)(i), nil
439}
440
441// GetTokenPrimaryGroup retrieves access token t primary group information.
442// A pointer to a SID structure representing a group that will become
443// the primary group of any objects created by a process using this access token.
444func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
445	i, e := t.getInfo(TokenPrimaryGroup, 50)
446	if e != nil {
447		return nil, e
448	}
449	return (*Tokenprimarygroup)(i), nil
450}
451
452// GetUserProfileDirectory retrieves path to the
453// root directory of the access token t user's profile.
454func (t Token) GetUserProfileDirectory() (string, error) {
455	n := uint32(100)
456	for {
457		b := make([]uint16, n)
458		e := GetUserProfileDirectory(t, &b[0], &n)
459		if e == nil {
460			return UTF16ToString(b), nil
461		}
462		if e != ERROR_INSUFFICIENT_BUFFER {
463			return "", e
464		}
465		if n <= uint32(len(b)) {
466			return "", e
467		}
468	}
469}
470
471// IsMember reports whether the access token t is a member of the provided SID.
472func (t Token) IsMember(sid *SID) (bool, error) {
473	var b int32
474	if e := checkTokenMembership(t, sid, &b); e != nil {
475		return false, e
476	}
477	return b != 0, nil
478}
479