exec plugin: Use `setgroups' to set the list of supplementary group IDs.
[collectd.git] / src / exec.c
index 21ac7c7..b8b538b 100644 (file)
@@ -118,6 +118,7 @@ static void exec_child (program_list_t *pl)
   int status;
   int uid;
   int gid;
+  int egid;
   char *arg0;
 
   struct passwd *sp_ptr;
@@ -140,20 +141,16 @@ static void exec_child (program_list_t *pl)
   }
 
   uid = sp.pw_uid;
+  gid = sp.pw_gid;
   if (uid == 0)
   {
     ERROR ("exec plugin: Cowardly refusing to exec program as root.");
     exit (-1);
   }
 
-  status = setuid (uid);
-  if (status != 0)
-  {
-    ERROR ("exec plugin: setuid failed: %s",
-       sstrerror (errno, errbuf, sizeof (errbuf)));
-    exit (-1);
-  }
-
+  /* The group configured in the configfile is set as effective group, because
+   * this way the forked process can (re-)gain the user's primary group. */
+  egid = -1;
   if (NULL != pl->group)
   {
     if ('\0' != *pl->group) {
@@ -173,22 +170,60 @@ static void exec_child (program_list_t *pl)
        exit (-1);
       }
 
-      gid = gr.gr_gid;
+      egid = gr.gr_gid;
     }
     else
     {
-      gid = sp.pw_gid;
+      egid = gid;
     }
+  } /* if (pl->group == NULL) */
+
+#if HAVE_SETGROUPS
+  if (getuid () == 0)
+  {
+    gid_t  glist[2];
+    size_t glist_len;
+
+    glist[0] = gid;
+    glist_len = 1;
+
+    if (gid != egid)
+    {
+      glist[1] = egid;
+      glist_len = 2;
+    }
+
+    setgroups (glist_len, glist);
+  }
+#endif /* HAVE_SETGROUPS */
 
-    status = setgid (gid);
-    if (0 != status)
+  status = setgid (gid);
+  if (status != 0)
+  {
+    ERROR ("exec plugin: setgid (%i) failed: %s",
+       gid, sstrerror (errno, errbuf, sizeof (errbuf)));
+    exit (-1);
+  }
+
+  if (egid != -1)
+  {
+    status = setegid (egid);
+    if (status != 0)
     {
-      ERROR ("exec plugin: setgid failed: %s",
-         sstrerror (errno, errbuf, sizeof (errbuf)));
+      ERROR ("exec plugin: setegid (%i) failed: %s",
+         egid, sstrerror (errno, errbuf, sizeof (errbuf)));
       exit (-1);
     }
   }
 
+  status = setuid (uid);
+  if (status != 0)
+  {
+    ERROR ("exec plugin: setuid (%i) failed: %s",
+       uid, sstrerror (errno, errbuf, sizeof (errbuf)));
+    exit (-1);
+  }
+
   arg0 = strrchr (pl->exec, '/');
   if (arg0 != NULL)
     arg0++;
@@ -256,6 +291,7 @@ static int parse_line (char *buffer)
   fields_num = strsplit (buffer, &fields[1], STATIC_ARRAY_SIZE(fields) - 1);
 
   handle_putval (stdout, fields, fields_num + 1);
+  return (0);
 } /* int parse_line */
 
 static void *exec_read_one (void *arg)
@@ -278,6 +314,7 @@ static void *exec_read_one (void *arg)
     ERROR ("exec plugin: fdopen (%i) failed: %s", fd,
        sstrerror (errno, errbuf, sizeof (errbuf)));
     kill (pl->pid, SIGTERM);
+    pl->pid = 0;
     close (fd);
     pthread_exit ((void *) 1);
   }