2012-02-09 09:19:58 +01:00
|
|
|
// 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 (
|
2016-07-22 20:15:38 +02:00
|
|
|
"errors"
|
2012-02-09 09:19:58 +01:00
|
|
|
"fmt"
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2016-07-22 20:15:38 +02:00
|
|
|
func init() {
|
|
|
|
groupImplemented = false
|
|
|
|
}
|
|
|
|
|
2013-11-06 20:49:01 +01:00
|
|
|
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,
|
2012-02-09 09:19:58 +01:00
|
|
|
syscall.NameSamCompatible, syscall.NameDisplay, 50)
|
2013-11-06 20:49:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func lookupFullNameServer(servername, username string) (string, error) {
|
|
|
|
s, e := syscall.UTF16PtrFromString(servername)
|
2012-02-09 09:19:58 +01:00
|
|
|
if e != nil {
|
2013-11-06 20:49:01 +01:00
|
|
|
return "", e
|
2012-02-09 09:19:58 +01:00
|
|
|
}
|
2013-11-06 20:49:01 +01:00
|
|
|
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))[:])
|
2012-02-09 09:19:58 +01:00
|
|
|
return name, nil
|
|
|
|
}
|
|
|
|
|
2013-11-06 20:49:01 +01:00
|
|
|
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
|
|
|
|
}
|
2016-07-22 20:15:38 +02:00
|
|
|
// domain worked neither as a domain nor as a server
|
2013-11-06 20:49:01 +01:00
|
|
|
// could be domain server unavailable
|
|
|
|
// pretend username is fullname
|
|
|
|
return username, nil
|
|
|
|
}
|
|
|
|
|
2012-02-09 09:19:58 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2012-12-13 00:13:29 +01:00
|
|
|
func current() (*User, error) {
|
2012-02-09 09:19:58 +01:00
|
|
|
t, e := syscall.OpenCurrentProcessToken()
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2013-11-06 20:49:01 +01:00
|
|
|
defer t.Close()
|
2012-02-09 09:19:58 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2016-07-22 20:15:38 +02:00
|
|
|
func lookupUser(username string) (*User, error) {
|
2012-02-09 09:19:58 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2016-07-22 20:15:38 +02:00
|
|
|
func lookupUserId(uid string) (*User, error) {
|
2012-02-09 09:19:58 +01:00
|
|
|
sid, e := syscall.StringToSid(uid)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return newUserFromSid(sid)
|
|
|
|
}
|
2016-07-22 20:15:38 +02:00
|
|
|
|
|
|
|
func lookupGroup(groupname string) (*Group, error) {
|
|
|
|
return nil, errors.New("user: LookupGroup not implemented on windows")
|
|
|
|
}
|
|
|
|
|
|
|
|
func lookupGroupId(string) (*Group, error) {
|
|
|
|
return nil, errors.New("user: LookupGroupId not implemented on windows")
|
|
|
|
}
|
|
|
|
|
|
|
|
func listGroups(*User) ([]string, error) {
|
|
|
|
return nil, errors.New("user: GroupIds not implemented on windows")
|
|
|
|
}
|