]> granicus.if.org Git - sudo/commitdiff
Add group_source setting in sudo.conf to allow the admin to specify
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 27 Jan 2013 18:53:11 +0000 (13:53 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 27 Jan 2013 18:53:11 +0000 (13:53 -0500)
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).

common/sudo_conf.c
include/sudo_conf.h
src/sudo.c

index da3b4d11599dace6d530d4465295eeaad10107b9..92628cb603bafedf1600b1170dfe215e2ae845f9 100644 (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)
 {
index 22b9a43bb1f91bdc21a125bfadb396f3572e6231..974e2802065b2fd0f243f311eceb10acd1ede5fc 100644 (file)
 
 #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 */
index 1246b26f577575c4dfa13eaf7377a17f7e488795..c19244e79d609ce16cd19d3a75b473180c762671 100644 (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
-    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"));
     }