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