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