From: Todd C. Miller Date: Sun, 27 Jan 2013 18:53:11 +0000 (-0500) Subject: Add group_source setting in sudo.conf to allow the admin to specify X-Git-Tag: SUDO_1_8_7~1^2~261 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=630b47e22fe8934976aceafc82870d415864a6c0;p=sudo Add group_source setting in sudo.conf to allow the admin to specify how a user's groups are looked up. Legal values are static (just the kernel list from getgroups), dynamic (whatever the group database includes) and adaptive (only use group db if kernel group list is full). --- diff --git a/common/sudo_conf.c b/common/sudo_conf.c index da3b4d115..92628cb60 100644 --- a/common/sudo_conf.c +++ b/common/sudo_conf.c @@ -100,11 +100,13 @@ static struct sudo_conf_table sudo_conf_table[] = { static struct sudo_conf_data { bool disable_coredump; + int group_source; const char *debug_flags; struct sudo_conf_paths paths[3]; struct plugin_info_list plugins; } sudo_conf_data = { true, + GROUP_SOURCE_ADAPTIVE, NULL, { #define SUDO_CONF_ASKPASS_IDX 0 @@ -125,7 +127,6 @@ set_variable(const char *entry) { #undef DC_LEN #define DC_LEN (sizeof("disable_coredump") - 1) - /* Currently the only variable supported is "disable_coredump". */ if (strncmp(entry, "disable_coredump", DC_LEN) == 0 && isblank((unsigned char)entry[DC_LEN])) { entry += DC_LEN + 1; @@ -134,6 +135,24 @@ set_variable(const char *entry) sudo_conf_data.disable_coredump = atobool(entry); } #undef DC_LEN +#undef GS_LEN +#define GS_LEN (sizeof("group_source") - 1) + if (strncmp(entry, "group_source", GS_LEN) == 0 && + isblank((unsigned char)entry[GS_LEN])) { + entry += GS_LEN + 1; + while (isblank((unsigned char)*entry)) + entry++; + if (strcasecmp(entry, "adaptive") == 0) { + sudo_conf_data.group_source = GROUP_SOURCE_ADAPTIVE; + } else if (strcasecmp(entry, "static") == 0) { + sudo_conf_data.group_source = GROUP_SOURCE_STATIC; + } else if (strcasecmp(entry, "dynamic") == 0) { + sudo_conf_data.group_source = GROUP_SOURCE_DYNAMIC; + } else { + warningx(_("unsupported group source `%s' in %s, line %d"), entry, + _PATH_SUDO_CONF, lineno); + } + } return true; } @@ -277,6 +296,12 @@ sudo_conf_debug_flags(void) return sudo_conf_data.debug_flags; } +int +sudo_conf_group_source(void) +{ + return sudo_conf_data.group_source; +} + struct plugin_info_list * sudo_conf_plugins(void) { diff --git a/include/sudo_conf.h b/include/sudo_conf.h index 22b9a43bb..974e28020 100644 --- a/include/sudo_conf.h +++ b/include/sudo_conf.h @@ -19,6 +19,10 @@ #include "list.h" +#define GROUP_SOURCE_ADAPTIVE 0 +#define GROUP_SOURCE_STATIC 1 +#define GROUP_SOURCE_DYNAMIC 2 + struct plugin_info { struct plugin_info *prev; /* required */ struct plugin_info *next; /* required */ @@ -38,5 +42,6 @@ const char *sudo_conf_noexec_path(void); const char *sudo_conf_debug_flags(void); struct plugin_info_list *sudo_conf_plugins(void); bool sudo_conf_disable_coredump(void); +int sudo_conf_group_source(void); #endif /* _SUDO_CONF_H */ diff --git a/src/sudo.c b/src/sudo.c index 1246b26f5..c19244e79 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -336,29 +336,23 @@ fix_fds(void) /* * Allocate space for groups and fill in using getgrouplist() - * for when we cannot use getgroups(). + * for when we cannot (or don't want to) use getgroups(). */ static int -fill_group_list(struct user_details *ud) +fill_group_list(struct user_details *ud, int maxgroups) { - int maxgroups, tries, rval = -1; + int tries, rval = -1; debug_decl(fill_group_list, SUDO_DEBUG_UTIL) -#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) - maxgroups = (int)sysconf(_SC_NGROUPS_MAX); - if (maxgroups < 0) -#endif - maxgroups = NGROUPS_MAX; - /* * It is possible to belong to more groups in the group database - * than NGROUPS_MAX. We start off with NGROUPS_MAX * 2 entries + * than NGROUPS_MAX. We start off with NGROUPS_MAX * 4 entries * and double this as needed. */ ud->groups = NULL; - ud->ngroups = maxgroups; + ud->ngroups = maxgroups << 1; for (tries = 0; tries < 10 && rval == -1; tries++) { - ud->ngroups *= 2; + ud->ngroups <<= 1; efree(ud->groups); ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); @@ -371,25 +365,35 @@ get_user_groups(struct user_details *ud) { char *cp, *gid_list = NULL; size_t glsize; - int i, len; + int i, len, maxgroups, group_source; debug_decl(get_user_groups, SUDO_DEBUG_UTIL) - /* - * Systems with mbr_check_membership() support more than NGROUPS_MAX - * groups so we cannot use getgroups(). - */ +#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) + maxgroups = (int)sysconf(_SC_NGROUPS_MAX); + if (maxgroups < 0) +#endif + maxgroups = NGROUPS_MAX; + ud->groups = NULL; -#ifndef HAVE_MBR_CHECK_MEMBERSHIP - if ((ud->ngroups = getgroups(0, NULL)) > 0) { - ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); - if (getgroups(ud->ngroups, ud->groups) < 0) { - efree(ud->groups); - ud->groups = NULL; + group_source = sudo_conf_group_source(); + if (group_source != GROUP_SOURCE_DYNAMIC) { + if ((ud->ngroups = getgroups(0, NULL)) > 0) { + /* Use groups from kernel if not too many or source is static. */ + if (ud->ngroups < maxgroups || group_source == GROUP_SOURCE_STATIC) { + ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); + if (getgroups(ud->ngroups, ud->groups) < 0) { + efree(ud->groups); + ud->groups = NULL; + } + } } } -#endif /* HAVE_MBR_CHECK_MEMBERSHIP */ if (ud->groups == NULL) { - if (fill_group_list(ud) == -1) + /* + * Query group database if kernel list is too small or disabled. + * Typically, this is because NFS can only support up to 16 groups. + */ + if (fill_group_list(ud, maxgroups) == -1) error(1, _("unable to get group vector")); }