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//sys	LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
136//sys	LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
137//sys	ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
138//sys	ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
139//sys	GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
140//sys	CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
141//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
142//sys	FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
143//sys	EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
144
145// The security identifier (SID) structure is a variable-length
146// structure used to uniquely identify users or groups.
147type SID struct{}
148
149// StringToSid converts a string-format security identifier
150// sid into a valid, functional sid.
151func StringToSid(s string) (*SID, error) {
152	var sid *SID
153	p, e := UTF16PtrFromString(s)
154	if e != nil {
155		return nil, e
156	}
157	e = ConvertStringSidToSid(p, &sid)
158	if e != nil {
159		return nil, e
160	}
161	defer LocalFree((Handle)(unsafe.Pointer(sid)))
162	return sid.Copy()
163}
164
165// LookupSID retrieves a security identifier sid for the account
166// and the name of the domain on which the account was found.
167// System specify target computer to search.
168func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
169	if len(account) == 0 {
170		return nil, "", 0, syscall.EINVAL
171	}
172	acc, e := UTF16PtrFromString(account)
173	if e != nil {
174		return nil, "", 0, e
175	}
176	var sys *uint16
177	if len(system) > 0 {
178		sys, e = UTF16PtrFromString(system)
179		if e != nil {
180			return nil, "", 0, e
181		}
182	}
183	n := uint32(50)
184	dn := uint32(50)
185	for {
186		b := make([]byte, n)
187		db := make([]uint16, dn)
188		sid = (*SID)(unsafe.Pointer(&b[0]))
189		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
190		if e == nil {
191			return sid, UTF16ToString(db), accType, nil
192		}
193		if e != ERROR_INSUFFICIENT_BUFFER {
194			return nil, "", 0, e
195		}
196		if n <= uint32(len(b)) {
197			return nil, "", 0, e
198		}
199	}
200}
201
202// String converts sid to a string format
203// suitable for display, storage, or transmission.
204func (sid *SID) String() (string, error) {
205	var s *uint16
206	e := ConvertSidToStringSid(sid, &s)
207	if e != nil {
208		return "", e
209	}
210	defer LocalFree((Handle)(unsafe.Pointer(s)))
211	return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
212}
213
214// Len returns the length, in bytes, of a valid security identifier sid.
215func (sid *SID) Len() int {
216	return int(GetLengthSid(sid))
217}
218
219// Copy creates a duplicate of security identifier sid.
220func (sid *SID) Copy() (*SID, error) {
221	b := make([]byte, sid.Len())
222	sid2 := (*SID)(unsafe.Pointer(&b[0]))
223	e := CopySid(uint32(len(b)), sid2, sid)
224	if e != nil {
225		return nil, e
226	}
227	return sid2, nil
228}
229
230// LookupAccount retrieves the name of the account for this sid
231// and the name of the first domain on which this sid is found.
232// System specify target computer to search for.
233func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
234	var sys *uint16
235	if len(system) > 0 {
236		sys, err = UTF16PtrFromString(system)
237		if err != nil {
238			return "", "", 0, err
239		}
240	}
241	n := uint32(50)
242	dn := uint32(50)
243	for {
244		b := make([]uint16, n)
245		db := make([]uint16, dn)
246		e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
247		if e == nil {
248			return UTF16ToString(b), UTF16ToString(db), accType, nil
249		}
250		if e != ERROR_INSUFFICIENT_BUFFER {
251			return "", "", 0, e
252		}
253		if n <= uint32(len(b)) {
254			return "", "", 0, e
255		}
256	}
257}
258
259const (
260	// do not reorder
261	TOKEN_ASSIGN_PRIMARY = 1 << iota
262	TOKEN_DUPLICATE
263	TOKEN_IMPERSONATE
264	TOKEN_QUERY
265	TOKEN_QUERY_SOURCE
266	TOKEN_ADJUST_PRIVILEGES
267	TOKEN_ADJUST_GROUPS
268	TOKEN_ADJUST_DEFAULT
269
270	TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
271		TOKEN_ASSIGN_PRIMARY |
272		TOKEN_DUPLICATE |
273		TOKEN_IMPERSONATE |
274		TOKEN_QUERY |
275		TOKEN_QUERY_SOURCE |
276		TOKEN_ADJUST_PRIVILEGES |
277		TOKEN_ADJUST_GROUPS |
278		TOKEN_ADJUST_DEFAULT
279	TOKEN_READ  = STANDARD_RIGHTS_READ | TOKEN_QUERY
280	TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
281		TOKEN_ADJUST_PRIVILEGES |
282		TOKEN_ADJUST_GROUPS |
283		TOKEN_ADJUST_DEFAULT
284	TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
285)
286
287const (
288	// do not reorder
289	TokenUser = 1 + iota
290	TokenGroups
291	TokenPrivileges
292	TokenOwner
293	TokenPrimaryGroup
294	TokenDefaultDacl
295	TokenSource
296	TokenType
297	TokenImpersonationLevel
298	TokenStatistics
299	TokenRestrictedSids
300	TokenSessionId
301	TokenGroupsAndPrivileges
302	TokenSessionReference
303	TokenSandBoxInert
304	TokenAuditPolicy
305	TokenOrigin
306	TokenElevationType
307	TokenLinkedToken
308	TokenElevation
309	TokenHasRestrictions
310	TokenAccessInformation
311	TokenVirtualizationAllowed
312	TokenVirtualizationEnabled
313	TokenIntegrityLevel
314	TokenUIAccess
315	TokenMandatoryPolicy
316	TokenLogonSid
317	MaxTokenInfoClass
318)
319
320type SIDAndAttributes struct {
321	Sid        *SID
322	Attributes uint32
323}
324
325type Tokenuser struct {
326	User SIDAndAttributes
327}
328
329type Tokenprimarygroup struct {
330	PrimaryGroup *SID
331}
332
333type Tokengroups struct {
334	GroupCount uint32
335	Groups     [1]SIDAndAttributes
336}
337
338//sys	OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
339//sys	GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
340//sys	GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
341
342// An access token contains the security information for a logon session.
343// The system creates an access token when a user logs on, and every
344// process executed on behalf of the user has a copy of the token.
345// The token identifies the user, the user's groups, and the user's
346// privileges. The system uses the token to control access to securable
347// objects and to control the ability of the user to perform various
348// system-related operations on the local computer.
349type Token Handle
350
351// OpenCurrentProcessToken opens the access token
352// associated with current process.
353func OpenCurrentProcessToken() (Token, error) {
354	p, e := GetCurrentProcess()
355	if e != nil {
356		return 0, e
357	}
358	var t Token
359	e = OpenProcessToken(p, TOKEN_QUERY, &t)
360	if e != nil {
361		return 0, e
362	}
363	return t, nil
364}
365
366// Close releases access to access token.
367func (t Token) Close() error {
368	return CloseHandle(Handle(t))
369}
370
371// getInfo retrieves a specified type of information about an access token.
372func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
373	n := uint32(initSize)
374	for {
375		b := make([]byte, n)
376		e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
377		if e == nil {
378			return unsafe.Pointer(&b[0]), nil
379		}
380		if e != ERROR_INSUFFICIENT_BUFFER {
381			return nil, e
382		}
383		if n <= uint32(len(b)) {
384			return nil, e
385		}
386	}
387}
388
389// GetTokenUser retrieves access token t user account information.
390func (t Token) GetTokenUser() (*Tokenuser, error) {
391	i, e := t.getInfo(TokenUser, 50)
392	if e != nil {
393		return nil, e
394	}
395	return (*Tokenuser)(i), nil
396}
397
398// GetTokenGroups retrieves group accounts associated with access token t.
399func (t Token) GetTokenGroups() (*Tokengroups, error) {
400	i, e := t.getInfo(TokenGroups, 50)
401	if e != nil {
402		return nil, e
403	}
404	return (*Tokengroups)(i), nil
405}
406
407// GetTokenPrimaryGroup retrieves access token t primary group information.
408// A pointer to a SID structure representing a group that will become
409// the primary group of any objects created by a process using this access token.
410func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
411	i, e := t.getInfo(TokenPrimaryGroup, 50)
412	if e != nil {
413		return nil, e
414	}
415	return (*Tokenprimarygroup)(i), nil
416}
417
418// GetUserProfileDirectory retrieves path to the
419// root directory of the access token t user's profile.
420func (t Token) GetUserProfileDirectory() (string, error) {
421	n := uint32(100)
422	for {
423		b := make([]uint16, n)
424		e := GetUserProfileDirectory(t, &b[0], &n)
425		if e == nil {
426			return UTF16ToString(b), nil
427		}
428		if e != ERROR_INSUFFICIENT_BUFFER {
429			return "", e
430		}
431		if n <= uint32(len(b)) {
432			return "", e
433		}
434	}
435}
436