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).
This commit is contained in:
Todd C. Miller
2013-01-27 13:53:11 -05:00
parent 8ab7cf61bd
commit 630b47e22f
3 changed files with 60 additions and 26 deletions

View File

@@ -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)
{

View File

@@ -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 */

View File

@@ -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
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"));
}