From: Ross Light Date: Tue, 8 Mar 2016 00:21:30 +0000 (-0800) Subject: os/user: make OS-specific getgrouplist calls X-Git-Tag: go1.7beta1~1472 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f128b5421e4ec7a00d9ff93288ea3f4b38654243;p=gostls13.git os/user: make OS-specific getgrouplist calls 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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/os/user/getgrouplist_darwin.c b/src/os/user/getgrouplist_darwin.c new file mode 100644 index 0000000000..6ad5614898 --- /dev/null +++ b/src/os/user/getgrouplist_darwin.c @@ -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 +#include +#include + +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 index 0000000000..eb14f9ab8a --- /dev/null +++ b/src/os/user/getgrouplist_unix.c @@ -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 +#include +#include + +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 index 0000000000..28a8a78dbb --- /dev/null +++ b/src/os/user/listgroups_solaris.go @@ -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 index 0000000000..f78baaac1e --- /dev/null +++ b/src/os/user/listgroups_unix.go @@ -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 +#include +#include + +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 +} diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go index 52d57c3884..579e0d5cb4 100644 --- a/src/os/user/lookup_unix.go +++ b/src/os/user/lookup_unix.go @@ -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)), diff --git a/src/os/user/user_test.go b/src/os/user/user_test.go index 222b339544..361c48a7bd 100644 --- a/src/os/user/user_test.go +++ b/src/os/user/user_test.go @@ -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)