}
*/
import "C"
+import (
+ "fmt"
+ "unsafe"
+)
func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
return C.mygetgrouplist(name, userGID, gids, n)
}
+
+// groupRetry retries getGroupList with an increasingly large size for n. The
+// result is stored in gids.
+func groupRetry(username string, name []byte, userGID C.gid_t, gids *[]C.gid_t, n *C.int) error {
+ *n = C.int(256 * 2)
+ for {
+ *gids = make([]C.gid_t, *n)
+ rv := getGroupList((*C.char)(unsafe.Pointer(&name[0])), userGID, &(*gids)[0], n)
+ if rv >= 0 {
+ // n is set correctly
+ break
+ }
+ if *n > maxGroups {
+ return fmt.Errorf("user: %q is a member of more than %d groups", username, maxGroups)
+ }
+ *n = *n * C.int(2)
+ }
+ return nil
+}
}
*/
import "C"
+import (
+ "fmt"
+ "unsafe"
+)
func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
return C.mygetgrouplist(name, userGID, gids, n)
}
+
+// groupRetry retries getGroupList with much larger size for n. The result is
+// stored in gids.
+func groupRetry(username string, name []byte, userGID C.gid_t, gids *[]C.gid_t, n *C.int) error {
+ // More than initial buffer, but now n contains the correct size.
+ if *n > maxGroups {
+ return fmt.Errorf("user: %q is a member of more than %d groups", username, maxGroups)
+ }
+ *gids = make([]C.gid_t, *n)
+ rv := getGroupList((*C.char)(unsafe.Pointer(&name[0])), userGID, &(*gids)[0], n)
+ if rv == -1 {
+ return fmt.Errorf("user: list groups for %s failed", username)
+ }
+ return nil
+}
*/
import "C"
+const maxGroups = 2048
+
func listGroups(u *User) ([]string, error) {
ug, err := strconv.Atoi(u.Gid)
if err != nil {
gidsC := make([]C.gid_t, n)
rv := getGroupList((*C.char)(unsafe.Pointer(&nameC[0])), 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 := getGroupList((*C.char)(unsafe.Pointer(&nameC[0])), userGID, &gidsC[0], &n)
- if rv == -1 {
- return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
+ // Mac is the only Unix that does not set n properly when rv == -1, so
+ // we need to use different logic for Mac vs. the other OS's.
+ if err := groupRetry(u.Username, nameC, userGID, &gidsC, &n); err != nil {
+ return nil, err
}
}
gidsC = gidsC[:n]