diff options
Diffstat (limited to 'src/os/user/lookup_windows.go')
-rw-r--r-- | src/os/user/lookup_windows.go | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/os/user/lookup_windows.go b/src/os/user/lookup_windows.go new file mode 100644 index 000000000..99c325ff0 --- /dev/null +++ b/src/os/user/lookup_windows.go @@ -0,0 +1,149 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package user + +import ( + "fmt" + "syscall" + "unsafe" +) + +func isDomainJoined() (bool, error) { + var domain *uint16 + var status uint32 + err := syscall.NetGetJoinInformation(nil, &domain, &status) + if err != nil { + return false, err + } + syscall.NetApiBufferFree((*byte)(unsafe.Pointer(domain))) + return status == syscall.NetSetupDomainName, nil +} + +func lookupFullNameDomain(domainAndUser string) (string, error) { + return syscall.TranslateAccountName(domainAndUser, + syscall.NameSamCompatible, syscall.NameDisplay, 50) +} + +func lookupFullNameServer(servername, username string) (string, error) { + s, e := syscall.UTF16PtrFromString(servername) + if e != nil { + return "", e + } + u, e := syscall.UTF16PtrFromString(username) + if e != nil { + return "", e + } + var p *byte + e = syscall.NetUserGetInfo(s, u, 10, &p) + if e != nil { + return "", e + } + defer syscall.NetApiBufferFree(p) + i := (*syscall.UserInfo10)(unsafe.Pointer(p)) + if i.FullName == nil { + return "", nil + } + name := syscall.UTF16ToString((*[1024]uint16)(unsafe.Pointer(i.FullName))[:]) + return name, nil +} + +func lookupFullName(domain, username, domainAndUser string) (string, error) { + joined, err := isDomainJoined() + if err == nil && joined { + name, err := lookupFullNameDomain(domainAndUser) + if err == nil { + return name, nil + } + } + name, err := lookupFullNameServer(domain, username) + if err == nil { + return name, nil + } + // domain worked neigher as a domain nor as a server + // could be domain server unavailable + // pretend username is fullname + return username, nil +} + +func newUser(usid *syscall.SID, gid, dir string) (*User, error) { + username, domain, t, e := usid.LookupAccount("") + if e != nil { + return nil, e + } + if t != syscall.SidTypeUser { + return nil, fmt.Errorf("user: should be user account type, not %d", t) + } + domainAndUser := domain + `\` + username + uid, e := usid.String() + if e != nil { + return nil, e + } + name, e := lookupFullName(domain, username, domainAndUser) + if e != nil { + return nil, e + } + u := &User{ + Uid: uid, + Gid: gid, + Username: domainAndUser, + Name: name, + HomeDir: dir, + } + return u, nil +} + +func current() (*User, error) { + t, e := syscall.OpenCurrentProcessToken() + if e != nil { + return nil, e + } + defer t.Close() + u, e := t.GetTokenUser() + if e != nil { + return nil, e + } + pg, e := t.GetTokenPrimaryGroup() + if e != nil { + return nil, e + } + gid, e := pg.PrimaryGroup.String() + if e != nil { + return nil, e + } + dir, e := t.GetUserProfileDirectory() + if e != nil { + return nil, e + } + return newUser(u.User.Sid, gid, dir) +} + +// BUG(brainman): Lookup and LookupId functions do not set +// Gid and HomeDir fields in the User struct returned on windows. + +func newUserFromSid(usid *syscall.SID) (*User, error) { + // TODO(brainman): do not know where to get gid and dir fields + gid := "unknown" + dir := "Unknown directory" + return newUser(usid, gid, dir) +} + +func lookup(username string) (*User, error) { + sid, _, t, e := syscall.LookupSID("", username) + if e != nil { + return nil, e + } + if t != syscall.SidTypeUser { + return nil, fmt.Errorf("user: should be user account type, not %d", t) + } + return newUserFromSid(sid) +} + +func lookupId(uid string) (*User, error) { + sid, e := syscall.StringToSid(uid) + if e != nil { + return nil, e + } + return newUserFromSid(sid) +} |