From 3d40975cf5249bdd75078a59d64ba31048fff645 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 5 Oct 2018 09:35:40 +0100 Subject: [PATCH] Don't use sysconf(_SC_NGROUPS_MAX) on macOS for getgroups() On MacOS sysconf(_SC_NGROUPS_MAX) always returns 16. However, this is not the value used by getgroups(2). MacOS uses nested groups but getgroups(2) will return the flattened list which can easily exceed 16 groups. In my testing getgroups() already returns 16 groups on a freshly installed system. And on a 10.14 system the root user is in more than 16 groups by default which makes it impossible to run smbd without this change. Setting _DARWIN_UNLIMITED_GETGROUPS allows getgroups() to return more than 16 groups. This also changes set_unix_security_ctx() to only set up to 16 groups since that is the limit for initgroups() according to the manpage. BUG: https://bugzilla.samba.org/show_bug.cgi?id=8773 Signed-off-by: Alex Richardson Reviewed-by: Andrew Bartlett Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Sep 9 17:43:19 UTC 2021 on sn-devel-184 (cherry picked from commit 2c18a982537ea1a62e4d802c9ae0ef06b36158dc) --- buildtools/wafsamba/wscript | 5 ++++- source3/include/proto.h | 3 ++- source3/lib/system.c | 24 +++++++++++++++++++++--- source3/lib/system_smbd.c | 2 +- source3/smbd/sec_ctx.c | 2 +- testsuite/smbd/sec_ctx_utils.c | 2 +- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript index 1aadb9570e1..def13f71c93 100644 --- a/buildtools/wafsamba/wscript +++ b/buildtools/wafsamba/wscript @@ -542,7 +542,10 @@ struct foo bar = { .y = 'X', .x = 1 }; conf.CHECK_HEADERS('strings.h inttypes.h stdint.h unistd.h minix/config.h', add_headers=True) conf.CHECK_HEADERS('ctype.h', add_headers=True) - if sys.platform != 'darwin': + if sys.platform == 'darwin': + conf.DEFINE('_DARWIN_C_SOURCE', 1, add_to_cflags=True) + conf.DEFINE('_DARWIN_UNLIMITED_GETGROUPS', 1, add_to_cflags=True) + else: conf.CHECK_HEADERS('standards.h', add_headers=True) conf.CHECK_HEADERS('stdbool.h stdint.h stdarg.h vararg.h', add_headers=True) diff --git a/source3/include/proto.h b/source3/include/proto.h index 938a71e8083..eb45179aebb 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -230,7 +230,8 @@ void set_effective_capability(enum smbd_capability capability); void drop_effective_capability(enum smbd_capability capability); long sys_random(void); void sys_srandom(unsigned int seed); -int groups_max(void); +int getgroups_max(void); +int setgroups_max(void); int sys_getgroups(int setlen, gid_t *gidset); int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset); uint32_t unix_dev_major(SMB_DEV_T dev); diff --git a/source3/lib/system.c b/source3/lib/system.c index 5d57ffadda1..a14fc51ca63 100644 --- a/source3/lib/system.c +++ b/source3/lib/system.c @@ -756,7 +756,7 @@ void sys_srandom(unsigned int seed) Returns equivalent to NGROUPS_MAX - using sysconf if needed. ****************************************************************************/ -int groups_max(void) +int setgroups_max(void) { #if defined(SYSCONF_SC_NGROUPS_MAX) int ret = sysconf(_SC_NGROUPS_MAX); @@ -766,6 +766,24 @@ int groups_max(void) #endif } +int getgroups_max(void) +{ +#if defined(DARWINOS) + /* + * On MacOS sysconf(_SC_NGROUPS_MAX) returns 16 due to MacOS's group + * nesting. However, The initgroups() manpage states the following: + * "Note that OS X supports group membership in an unlimited number + * of groups. The OS X kernel uses the group list stored in the process + * credentials only as an initial cache. Additional group memberships + * are determined by communication between the operating system and the + * opendirectoryd daemon." + */ + return INT_MAX; +#else + return setgroups_max(); +#endif +} + /************************************************************************** Wrap setgroups and getgroups for systems that declare getgroups() as returning an array of gid_t, but actuall return an array of int. @@ -831,7 +849,7 @@ static int sys_broken_setgroups(int setlen, gid_t *gidset) if (setlen == 0) return 0 ; - if (setlen < 0 || setlen > groups_max()) { + if (setlen < 0 || setlen > setgroups_max()) { errno = EINVAL; return -1; } @@ -882,7 +900,7 @@ static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset) int ret; /* setgroups(2) will fail with EINVAL if we pass too many groups. */ - max = groups_max(); + max = setgroups_max(); /* No group list, just make sure we are setting the efective GID. */ if (setlen == 0) { diff --git a/source3/lib/system_smbd.c b/source3/lib/system_smbd.c index 3b1ac9c1c2a..73bffe05f7a 100644 --- a/source3/lib/system_smbd.c +++ b/source3/lib/system_smbd.c @@ -205,7 +205,7 @@ bool getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user, gid_t primary_gid, gid_t **ret_groups, uint32_t *p_ngroups) { - int max_grp = MIN(128, groups_max()); + int max_grp = MIN(128, getgroups_max()); gid_t stack_groups[max_grp]; uint32_t ngrp; gid_t *temp_groups = stack_groups; diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c index 5e0710e0ecb..d6fd11cd4a3 100644 --- a/source3/smbd/sec_ctx.c +++ b/source3/smbd/sec_ctx.c @@ -282,7 +282,7 @@ static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *grou static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups) { - int max = groups_max(); + int max = NGROUPS_MAX; /* Start context switch */ gain_root(); diff --git a/testsuite/smbd/sec_ctx_utils.c b/testsuite/smbd/sec_ctx_utils.c index e72292b9864..3834cfd4a16 100644 --- a/testsuite/smbd/sec_ctx_utils.c +++ b/testsuite/smbd/sec_ctx_utils.c @@ -30,7 +30,7 @@ void get_random_grouplist(int *ngroups, gid_t **groups) { int i; - *ngroups = random() % groups_max(); + *ngroups = random() % setgroups_max(); *groups = malloc(*ngroups * sizeof(gid_t)); if (!groups) { -- 2.25.1