}
}
}
+
+// getTokenInfo retrieves a specified type of information about an access token.
+func getTokenInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) {
+ n := uint32(initSize)
+ for {
+ b := make([]byte, n)
+ e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+ if e == nil {
+ return unsafe.Pointer(&b[0]), nil
+ }
+ if e != syscall.ERROR_INSUFFICIENT_BUFFER {
+ return nil, e
+ }
+ if n <= uint32(len(b)) {
+ return nil, e
+ }
+ }
+}
+
+type TOKEN_GROUPS struct {
+ GroupCount uint32
+ Groups [1]SID_AND_ATTRIBUTES
+}
+
+func (g *TOKEN_GROUPS) AllGroups() []SID_AND_ATTRIBUTES {
+ return (*[(1 << 28) - 1]SID_AND_ATTRIBUTES)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
+}
+
+func GetTokenGroups(t syscall.Token) (*TOKEN_GROUPS, error) {
+ i, e := getTokenInfo(t, syscall.TokenGroups, 50)
+ if e != nil {
+ return nil, e
+ }
+ return (*TOKEN_GROUPS)(i), nil
+}
}
func listGroups(user *User) ([]string, error) {
- sid, err := syscall.StringToSid(user.Uid)
- if err != nil {
- return nil, err
- }
- username, domain, err := lookupUsernameAndDomain(sid)
- if err != nil {
- return nil, err
- }
- sids, err := listGroupsForUsernameAndDomain(username, domain)
- if err != nil {
- return nil, err
+ var sids []string
+ if u, err := Current(); err == nil && u.Uid == user.Uid {
+ // It is faster and more reliable to get the groups
+ // of the current user from the current process token.
+ err := runAsProcessOwner(func() error {
+ t, err := syscall.OpenCurrentProcessToken()
+ if err != nil {
+ return err
+ }
+ defer t.Close()
+ groups, err := windows.GetTokenGroups(t)
+ if err != nil {
+ return err
+ }
+ for _, g := range groups.AllGroups() {
+ sid, err := g.Sid.String()
+ if err != nil {
+ return err
+ }
+ sids = append(sids, sid)
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ sid, err := syscall.StringToSid(user.Uid)
+ if err != nil {
+ return nil, err
+ }
+ username, domain, err := lookupUsernameAndDomain(sid)
+ if err != nil {
+ return nil, err
+ }
+ sids, err = listGroupsForUsernameAndDomain(username, domain)
+ if err != nil {
+ return nil, err
+ }
}
// Add the primary group of the user to the list if it is not already there.
// This is done only to comply with the POSIX concept of a primary group.