fixed build issues
[collectd.git] / src / exec.c
index b145e81..e5c5df9 100644 (file)
@@ -39,6 +39,7 @@
 #include <signal.h>
 #include <sys/types.h>
 
+#include <stdlib.h>
 #ifdef HAVE_SYS_CAPABILITY_H
 #include <sys/capability.h>
 #endif
@@ -78,6 +79,11 @@ typedef struct program_list_and_notification_s {
 } program_list_and_notification_t;
 
 /*
+ * constants
+ */
+const long int MAX_GRBUF_SIZE = 65536;
+
+/*
  * Private variables
  */
 static program_list_t *pl_head;
@@ -340,6 +346,88 @@ static void close_pipe(int fd_pipe[2]) /* {{{ */
 } /* }}} void close_pipe */
 
 /*
+ * Get effective group ID from group name.
+ */
+static int getegr_id(program_list_t *pl, int gid) /* {{{ */
+{
+  int egid = -1;
+  if (pl->group != NULL) {
+    if (*pl->group != '\0') {
+      struct group *gr_ptr = NULL;
+      struct group gr;
+
+      long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+      if (grbuf_size <= 0)
+        grbuf_size = sysconf(_SC_PAGESIZE);
+      if (grbuf_size <= 0)
+        grbuf_size = 4096;
+
+      long int size;
+      size = grbuf_size;
+      char *temp = NULL;
+      char *grbuf = NULL;
+      int getgr_failed = 0;
+      grbuf = malloc(size);
+      if (grbuf == NULL) {
+        ERROR("exec plugin: get group information for '%s' failed: buffer "
+              "malloc() failed",
+              pl->group);
+        getgr_failed = 1;
+        goto gr_finally;
+      }
+      int status;
+      while ((status = getgrnam_r(pl->group, &gr, grbuf, size, &gr_ptr)) != 0) {
+        switch (errno) {
+        case ERANGE:
+          if ((size + grbuf_size) < size ||
+              (size + grbuf_size) > MAX_GRBUF_SIZE) {
+            ERROR("exec plugin: get group information for '%s' max buffer "
+                  "limit (%ld) reached \n",
+                  pl->group, MAX_GRBUF_SIZE);
+            getgr_failed = 1;
+            goto gr_finally;
+          }
+          /* grow the buffer by 'grbuf_size' each time getgrnamr fails */
+          size += grbuf_size;
+          temp = realloc(grbuf, size);
+          if (temp == NULL) {
+            ERROR("exec plugin: get group information for '%s' realloc() "
+                  "buffer to (%ld) failed ",
+                  pl->group, size);
+            getgr_failed = 1;
+            goto gr_finally;
+          }
+          grbuf = temp;
+          break;
+        default:
+          ERROR("exec plugin: default errno: get group information for '%s' "
+                "failed : %s",
+                pl->group, STRERRNO);
+          getgr_failed = 1;
+          goto gr_finally;
+        }
+      }
+      if (gr_ptr == NULL) {
+        ERROR("exec plugin: No such group: `%s'", pl->group);
+        getgr_failed = 1;
+        goto gr_finally;
+      }
+      egid = gr.gr_gid;
+    gr_finally:
+      free(grbuf);
+      DEBUG("exec plugin: release grbuf memory ");
+      grbuf = NULL;
+      if (getgr_failed > 0) {
+        egid = -2; // arbitrary value to indicate fail
+      }
+    } else {
+      egid = gid;
+    }
+  } /* if (pl->group == NULL) */
+  return egid;
+}
+
+/*
  * Creates three pipes (one for reading, one for writing and one for errors),
  * forks a child, sets up the pipes so that fd_in is connected to STDIN of
  * the child and fd_out is connected to STDOUT and fd_err is connected to STDERR
@@ -397,36 +485,11 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out,
 
   /* 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 (pl->group != NULL) {
-    if (*pl->group != '\0') {
-      struct group *gr_ptr = NULL;
-      struct group gr;
-
-      long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
-      if (grbuf_size <= 0)
-        grbuf_size = sysconf(_SC_PAGESIZE);
-      if (grbuf_size <= 0)
-        grbuf_size = 4096;
-      char grbuf[grbuf_size];
-
-      status = getgrnam_r(pl->group, &gr, grbuf, sizeof(grbuf), &gr_ptr);
-      if (status != 0) {
-        ERROR("exec plugin: Failed to get group information "
-              "for group ``%s'': %s",
-              pl->group, STRERROR(status));
-        goto failed;
-      }
-      if (gr_ptr == NULL) {
-        ERROR("exec plugin: No such group: `%s'", pl->group);
-        goto failed;
-      }
-
-      egid = gr.gr_gid;
-    } else {
-      egid = gid;
-    }
-  } /* if (pl->group == NULL) */
+  egid = getegr_id(pl, gid);
+  if (egid <= -2) {
+    ERROR("exec plugin: getegr_id failed: %s", STRERRNO);
+    goto failed;
+  }
 
   pid = fork();
   if (pid < 0) {