Source file
src/os/user/lookup_windows.go
1
2
3
4
5 package user
6
7 import (
8 "fmt"
9 "internal/syscall/windows"
10 "internal/syscall/windows/registry"
11 "syscall"
12 "unsafe"
13 )
14
15 func isDomainJoined() (bool, error) {
16 var domain *uint16
17 var status uint32
18 err := syscall.NetGetJoinInformation(nil, &domain, &status)
19 if err != nil {
20 return false, err
21 }
22 syscall.NetApiBufferFree((*byte)(unsafe.Pointer(domain)))
23 return status == syscall.NetSetupDomainName, nil
24 }
25
26 func lookupFullNameDomain(domainAndUser string) (string, error) {
27 return syscall.TranslateAccountName(domainAndUser,
28 syscall.NameSamCompatible, syscall.NameDisplay, 50)
29 }
30
31 func lookupFullNameServer(servername, username string) (string, error) {
32 s, e := syscall.UTF16PtrFromString(servername)
33 if e != nil {
34 return "", e
35 }
36 u, e := syscall.UTF16PtrFromString(username)
37 if e != nil {
38 return "", e
39 }
40 var p *byte
41 e = syscall.NetUserGetInfo(s, u, 10, &p)
42 if e != nil {
43 return "", e
44 }
45 defer syscall.NetApiBufferFree(p)
46 i := (*syscall.UserInfo10)(unsafe.Pointer(p))
47 return windows.UTF16PtrToString(i.FullName), nil
48 }
49
50 func lookupFullName(domain, username, domainAndUser string) (string, error) {
51 joined, err := isDomainJoined()
52 if err == nil && joined {
53 name, err := lookupFullNameDomain(domainAndUser)
54 if err == nil {
55 return name, nil
56 }
57 }
58 name, err := lookupFullNameServer(domain, username)
59 if err == nil {
60 return name, nil
61 }
62
63
64
65 return username, nil
66 }
67
68
69
70 func getProfilesDirectory() (string, error) {
71 n := uint32(100)
72 for {
73 b := make([]uint16, n)
74 e := windows.GetProfilesDirectory(&b[0], &n)
75 if e == nil {
76 return syscall.UTF16ToString(b), nil
77 }
78 if e != syscall.ERROR_INSUFFICIENT_BUFFER {
79 return "", e
80 }
81 if n <= uint32(len(b)) {
82 return "", e
83 }
84 }
85 }
86
87
88 func lookupUsernameAndDomain(usid *syscall.SID) (username, domain string, e error) {
89 username, domain, t, e := usid.LookupAccount("")
90 if e != nil {
91 return "", "", e
92 }
93 if t != syscall.SidTypeUser {
94 return "", "", fmt.Errorf("user: should be user account type, not %d", t)
95 }
96 return username, domain, nil
97 }
98
99
100 func findHomeDirInRegistry(uid string) (dir string, e error) {
101 k, e := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\`+uid, registry.QUERY_VALUE)
102 if e != nil {
103 return "", e
104 }
105 defer k.Close()
106 dir, _, e = k.GetStringValue("ProfileImagePath")
107 if e != nil {
108 return "", e
109 }
110 return dir, nil
111 }
112
113
114 func lookupGroupName(groupname string) (string, error) {
115 sid, _, t, e := syscall.LookupSID("", groupname)
116 if e != nil {
117 return "", e
118 }
119
120
121
122
123
124
125 if t != syscall.SidTypeGroup && t != syscall.SidTypeWellKnownGroup && t != syscall.SidTypeAlias {
126 return "", fmt.Errorf("lookupGroupName: should be group account type, not %d", t)
127 }
128 return sid.String()
129 }
130
131
132
133 func listGroupsForUsernameAndDomain(username, domain string) ([]string, error) {
134
135 var query string
136 joined, err := isDomainJoined()
137 if err == nil && joined && len(domain) != 0 {
138 query = domain + `\` + username
139 } else {
140 query = username
141 }
142 q, err := syscall.UTF16PtrFromString(query)
143 if err != nil {
144 return nil, err
145 }
146 var p0 *byte
147 var entriesRead, totalEntries uint32
148
149
150
151
152
153
154
155
156 err = windows.NetUserGetLocalGroups(nil, q, 0, windows.LG_INCLUDE_INDIRECT, &p0, windows.MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries)
157 if err != nil {
158 return nil, err
159 }
160 defer syscall.NetApiBufferFree(p0)
161 if entriesRead == 0 {
162 return nil, fmt.Errorf("listGroupsForUsernameAndDomain: NetUserGetLocalGroups() returned an empty list for domain: %s, username: %s", domain, username)
163 }
164 entries := (*[1024]windows.LocalGroupUserInfo0)(unsafe.Pointer(p0))[:entriesRead:entriesRead]
165 var sids []string
166 for _, entry := range entries {
167 if entry.Name == nil {
168 continue
169 }
170 sid, err := lookupGroupName(windows.UTF16PtrToString(entry.Name))
171 if err != nil {
172 return nil, err
173 }
174 sids = append(sids, sid)
175 }
176 return sids, nil
177 }
178
179 func newUser(uid, gid, dir, username, domain string) (*User, error) {
180 domainAndUser := domain + `\` + username
181 name, e := lookupFullName(domain, username, domainAndUser)
182 if e != nil {
183 return nil, e
184 }
185 u := &User{
186 Uid: uid,
187 Gid: gid,
188 Username: domainAndUser,
189 Name: name,
190 HomeDir: dir,
191 }
192 return u, nil
193 }
194
195 var (
196
197
198 userBuffer = 0
199 groupBuffer = 0
200 )
201
202 func current() (*User, error) {
203 t, e := syscall.OpenCurrentProcessToken()
204 if e != nil {
205 return nil, e
206 }
207 defer t.Close()
208 u, e := t.GetTokenUser()
209 if e != nil {
210 return nil, e
211 }
212 pg, e := t.GetTokenPrimaryGroup()
213 if e != nil {
214 return nil, e
215 }
216 uid, e := u.User.Sid.String()
217 if e != nil {
218 return nil, e
219 }
220 gid, e := pg.PrimaryGroup.String()
221 if e != nil {
222 return nil, e
223 }
224 dir, e := t.GetUserProfileDirectory()
225 if e != nil {
226 return nil, e
227 }
228 username, domain, e := lookupUsernameAndDomain(u.User.Sid)
229 if e != nil {
230 return nil, e
231 }
232 return newUser(uid, gid, dir, username, domain)
233 }
234
235
236
237
238 func lookupUserPrimaryGroup(username, domain string) (string, error) {
239
240 sid, _, t, e := syscall.LookupSID("", domain)
241 if e != nil {
242 return "", e
243 }
244 if t != syscall.SidTypeDomain {
245 return "", fmt.Errorf("lookupUserPrimaryGroup: should be domain account type, not %d", t)
246 }
247 domainRID, e := sid.String()
248 if e != nil {
249 return "", e
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264 joined, err := isDomainJoined()
265 if err == nil && joined {
266 return domainRID + "-513", nil
267 }
268
269
270
271
272
273
274 u, e := syscall.UTF16PtrFromString(username)
275 if e != nil {
276 return "", e
277 }
278 d, e := syscall.UTF16PtrFromString(domain)
279 if e != nil {
280 return "", e
281 }
282 var p *byte
283 e = syscall.NetUserGetInfo(d, u, 4, &p)
284 if e != nil {
285 return "", e
286 }
287 defer syscall.NetApiBufferFree(p)
288 i := (*windows.UserInfo4)(unsafe.Pointer(p))
289 return fmt.Sprintf("%s-%d", domainRID, i.PrimaryGroupID), nil
290 }
291
292 func newUserFromSid(usid *syscall.SID) (*User, error) {
293 username, domain, e := lookupUsernameAndDomain(usid)
294 if e != nil {
295 return nil, e
296 }
297 gid, e := lookupUserPrimaryGroup(username, domain)
298 if e != nil {
299 return nil, e
300 }
301 uid, e := usid.String()
302 if e != nil {
303 return nil, e
304 }
305
306
307
308
309
310
311
312
313
314 dir, e := findHomeDirInRegistry(uid)
315 if e != nil {
316
317
318
319
320 dir, e = getProfilesDirectory()
321 if e != nil {
322 return nil, e
323 }
324 dir += `\` + username
325 }
326 return newUser(uid, gid, dir, username, domain)
327 }
328
329 func lookupUser(username string) (*User, error) {
330 sid, _, t, e := syscall.LookupSID("", username)
331 if e != nil {
332 return nil, e
333 }
334 if t != syscall.SidTypeUser {
335 return nil, fmt.Errorf("user: should be user account type, not %d", t)
336 }
337 return newUserFromSid(sid)
338 }
339
340 func lookupUserId(uid string) (*User, error) {
341 sid, e := syscall.StringToSid(uid)
342 if e != nil {
343 return nil, e
344 }
345 return newUserFromSid(sid)
346 }
347
348 func lookupGroup(groupname string) (*Group, error) {
349 sid, err := lookupGroupName(groupname)
350 if err != nil {
351 return nil, err
352 }
353 return &Group{Name: groupname, Gid: sid}, nil
354 }
355
356 func lookupGroupId(gid string) (*Group, error) {
357 sid, err := syscall.StringToSid(gid)
358 if err != nil {
359 return nil, err
360 }
361 groupname, _, t, err := sid.LookupAccount("")
362 if err != nil {
363 return nil, err
364 }
365 if t != syscall.SidTypeGroup && t != syscall.SidTypeWellKnownGroup && t != syscall.SidTypeAlias {
366 return nil, fmt.Errorf("lookupGroupId: should be group account type, not %d", t)
367 }
368 return &Group{Name: groupname, Gid: gid}, nil
369 }
370
371 func listGroups(user *User) ([]string, error) {
372 sid, err := syscall.StringToSid(user.Uid)
373 if err != nil {
374 return nil, err
375 }
376 username, domain, err := lookupUsernameAndDomain(sid)
377 if err != nil {
378 return nil, err
379 }
380 sids, err := listGroupsForUsernameAndDomain(username, domain)
381 if err != nil {
382 return nil, err
383 }
384
385
386 for _, sid := range sids {
387 if sid == user.Gid {
388 return sids, nil
389 }
390 }
391 return append(sids, user.Gid), nil
392 }
393
View as plain text