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 func current() (*User, error) {
196 t, e := syscall.OpenCurrentProcessToken()
197 if e != nil {
198 return nil, e
199 }
200 defer t.Close()
201 u, e := t.GetTokenUser()
202 if e != nil {
203 return nil, e
204 }
205 pg, e := t.GetTokenPrimaryGroup()
206 if e != nil {
207 return nil, e
208 }
209 uid, e := u.User.Sid.String()
210 if e != nil {
211 return nil, e
212 }
213 gid, e := pg.PrimaryGroup.String()
214 if e != nil {
215 return nil, e
216 }
217 dir, e := t.GetUserProfileDirectory()
218 if e != nil {
219 return nil, e
220 }
221 username, domain, e := lookupUsernameAndDomain(u.User.Sid)
222 if e != nil {
223 return nil, e
224 }
225 return newUser(uid, gid, dir, username, domain)
226 }
227
228
229
230
231 func lookupUserPrimaryGroup(username, domain string) (string, error) {
232
233 sid, _, t, e := syscall.LookupSID("", domain)
234 if e != nil {
235 return "", e
236 }
237 if t != syscall.SidTypeDomain {
238 return "", fmt.Errorf("lookupUserPrimaryGroup: should be domain account type, not %d", t)
239 }
240 domainRID, e := sid.String()
241 if e != nil {
242 return "", e
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256
257 joined, err := isDomainJoined()
258 if err == nil && joined {
259 return domainRID + "-513", nil
260 }
261
262
263
264
265
266
267 u, e := syscall.UTF16PtrFromString(username)
268 if e != nil {
269 return "", e
270 }
271 d, e := syscall.UTF16PtrFromString(domain)
272 if e != nil {
273 return "", e
274 }
275 var p *byte
276 e = syscall.NetUserGetInfo(d, u, 4, &p)
277 if e != nil {
278 return "", e
279 }
280 defer syscall.NetApiBufferFree(p)
281 i := (*windows.UserInfo4)(unsafe.Pointer(p))
282 return fmt.Sprintf("%s-%d", domainRID, i.PrimaryGroupID), nil
283 }
284
285 func newUserFromSid(usid *syscall.SID) (*User, error) {
286 username, domain, e := lookupUsernameAndDomain(usid)
287 if e != nil {
288 return nil, e
289 }
290 gid, e := lookupUserPrimaryGroup(username, domain)
291 if e != nil {
292 return nil, e
293 }
294 uid, e := usid.String()
295 if e != nil {
296 return nil, e
297 }
298
299
300
301
302
303
304
305
306
307 dir, e := findHomeDirInRegistry(uid)
308 if e != nil {
309
310
311
312
313 dir, e = getProfilesDirectory()
314 if e != nil {
315 return nil, e
316 }
317 dir += `\` + username
318 }
319 return newUser(uid, gid, dir, username, domain)
320 }
321
322 func lookupUser(username string) (*User, error) {
323 sid, _, t, e := syscall.LookupSID("", username)
324 if e != nil {
325 return nil, e
326 }
327 if t != syscall.SidTypeUser {
328 return nil, fmt.Errorf("user: should be user account type, not %d", t)
329 }
330 return newUserFromSid(sid)
331 }
332
333 func lookupUserId(uid string) (*User, error) {
334 sid, e := syscall.StringToSid(uid)
335 if e != nil {
336 return nil, e
337 }
338 return newUserFromSid(sid)
339 }
340
341 func lookupGroup(groupname string) (*Group, error) {
342 sid, err := lookupGroupName(groupname)
343 if err != nil {
344 return nil, err
345 }
346 return &Group{Name: groupname, Gid: sid}, nil
347 }
348
349 func lookupGroupId(gid string) (*Group, error) {
350 sid, err := syscall.StringToSid(gid)
351 if err != nil {
352 return nil, err
353 }
354 groupname, _, t, err := sid.LookupAccount("")
355 if err != nil {
356 return nil, err
357 }
358 if t != syscall.SidTypeGroup && t != syscall.SidTypeWellKnownGroup && t != syscall.SidTypeAlias {
359 return nil, fmt.Errorf("lookupGroupId: should be group account type, not %d", t)
360 }
361 return &Group{Name: groupname, Gid: gid}, nil
362 }
363
364 func listGroups(user *User) ([]string, error) {
365 sid, err := syscall.StringToSid(user.Uid)
366 if err != nil {
367 return nil, err
368 }
369 username, domain, err := lookupUsernameAndDomain(sid)
370 if err != nil {
371 return nil, err
372 }
373 sids, err := listGroupsForUsernameAndDomain(username, domain)
374 if err != nil {
375 return nil, err
376 }
377
378
379 for _, sid := range sids {
380 if sid == user.Gid {
381 return sids, nil
382 }
383 }
384 return append(sids, user.Gid), nil
385 }
386
View as plain text