]> Cypherpunks repositories - gostls13.git/commitdiff
os/user: make OS-specific getgrouplist calls
authorRoss Light <light@google.com>
Tue, 8 Mar 2016 00:21:30 +0000 (16:21 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 8 Mar 2016 20:58:00 +0000 (20:58 +0000)
getgrouplist is non-standard and has slightly different semantics on
each platform.  Darwin defines the function in terms of ints instead of
gid_ts.  Solaris only recently supported the call, so stubbing out for
now.

Fixes #14696
Fixes #14709

Change-Id: I5a44538d41594909efb6f3f9610c55d638c36757
Reviewed-on: https://go-review.googlesource.com/20348
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/os/user/getgrouplist_darwin.c [new file with mode: 0644]
src/os/user/getgrouplist_unix.c [new file with mode: 0644]
src/os/user/listgroups_solaris.go [new file with mode: 0644]
src/os/user/listgroups_unix.go [new file with mode: 0644]
src/os/user/lookup_unix.go
src/os/user/user_test.go

diff --git a/src/os/user/getgrouplist_darwin.c b/src/os/user/getgrouplist_darwin.c
new file mode 100644 (file)
index 0000000..6ad5614
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+// +build cgo
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+       int* buf = malloc(*ngroups * sizeof(int));
+       int rv = getgrouplist(user, (int) group, buf, ngroups);
+       int i;
+       if (rv == 0) {
+               for (i = 0; i < *ngroups; i++) {
+                       groups[i] = (gid_t) buf[i];
+               }
+       }
+       free(buf);
+       return rv;
+}
diff --git a/src/os/user/getgrouplist_unix.c b/src/os/user/getgrouplist_unix.c
new file mode 100644 (file)
index 0000000..eb14f9a
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+// +build cgo
+// +build dragonfly freebsd !android,linux netbsd openbsd
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <grp.h>
+
+int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+       return getgrouplist(user, group, groups, ngroups);
+}
diff --git a/src/os/user/listgroups_solaris.go b/src/os/user/listgroups_solaris.go
new file mode 100644 (file)
index 0000000..28a8a78
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 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.
+
+// +build cgo
+
+// Even though this file requires no C, it is used to provide a
+// listGroup stub because all the other Solaris calls work.  Otherwise,
+// this stub will conflict with the lookup_stubs.go fallback.
+
+package user
+
+import "fmt"
+
+func listGroups(u *User) ([]string, error) {
+       return nil, fmt.Errorf("user: list groups for %s: not supported on Solaris", u.Username)
+}
diff --git a/src/os/user/listgroups_unix.go b/src/os/user/listgroups_unix.go
new file mode 100644 (file)
index 0000000..f78baaa
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2016 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.
+
+// +build dragonfly darwin freebsd !android,linux netbsd openbsd
+
+package user
+
+import (
+       "fmt"
+       "strconv"
+       "unsafe"
+)
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+extern int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups);
+*/
+import "C"
+
+func listGroups(u *User) ([]string, error) {
+       ug, err := strconv.Atoi(u.Gid)
+       if err != nil {
+               return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
+       }
+       userGID := C.gid_t(ug)
+       nameC := C.CString(u.Username)
+       defer C.free(unsafe.Pointer(nameC))
+
+       n := C.int(256)
+       gidsC := make([]C.gid_t, n)
+       rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n)
+       if rv == -1 {
+               // More than initial buffer, but now n contains the correct size.
+               const maxGroups = 2048
+               if n > maxGroups {
+                       return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups)
+               }
+               gidsC = make([]C.gid_t, n)
+               rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n)
+               if rv == -1 {
+                       return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
+               }
+       }
+       gidsC = gidsC[:n]
+       gids := make([]string, 0, n)
+       for _, g := range gidsC[:n] {
+               gids = append(gids, strconv.Itoa(int(g)))
+       }
+       return gids, nil
+}
index 52d57c3884dbb53d960afa8c68897b3a7121e7d7..579e0d5cb40d40b13112c159eabc7865efaab5b1 100644 (file)
@@ -37,11 +37,6 @@ static int mygetgrgid_r(int gid, struct group *grp,
        char *buf, size_t buflen, struct group **result) {
  return getgrgid_r(gid, grp, buf, buflen, result);
 }
-
-static int mygetgrouplist(const char *user, gid_t group, gid_t *groups,
-       int *ngroups) {
- return getgrouplist(user, group, groups, ngroups);
-}
 */
 import "C"
 
@@ -112,38 +107,6 @@ func lookupUnixUid(uid int) (*User, error) {
        return buildUser(&pwd), nil
 }
 
-func listGroups(u *User) ([]string, error) {
-       ug, err := strconv.Atoi(u.Gid)
-       if err != nil {
-               return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
-       }
-       userGID := C.gid_t(ug)
-       nameC := C.CString(u.Username)
-       defer C.free(unsafe.Pointer(nameC))
-
-       n := C.int(256)
-       gidsC := make([]C.gid_t, n)
-       rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n)
-       if rv == -1 {
-               // More than initial buffer, but now n contains the correct size.
-               const maxGroups = 2048
-               if n > maxGroups {
-                       return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups)
-               }
-               gidsC = make([]C.gid_t, n)
-               rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n)
-               if rv == -1 {
-                       return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
-               }
-       }
-       gidsC = gidsC[:n]
-       gids := make([]string, 0, n)
-       for _, g := range gidsC[:n] {
-               gids = append(gids, strconv.Itoa(int(g)))
-       }
-       return gids, nil
-}
-
 func buildUser(pwd *C.struct_passwd) *User {
        u := &User{
                Uid:      strconv.Itoa(int(pwd.pw_uid)),
index 222b33954465ef2b5dfd55c39cd1abe8440e9d8f..361c48a7bddb07c8b6ffd35754dbb4949535a7dd 100644 (file)
@@ -121,6 +121,9 @@ func TestLookupGroup(t *testing.T) {
 
 func TestGroupIds(t *testing.T) {
        checkGroup(t)
+       if runtime.GOOS == "solaris" {
+               t.Skip("skipping GroupIds, see golang.org/issue/14709")
+       }
        user, err := Current()
        if err != nil {
                t.Fatalf("Current(): %v", err)