Merge branch 'collectd-5.7' into collectd-5.8
authorFlorian Forster <octo@collectd.org>
Mon, 8 Oct 2018 09:48:54 +0000 (11:48 +0200)
committerFlorian Forster <octo@collectd.org>
Mon, 8 Oct 2018 09:48:54 +0000 (11:48 +0200)
1  2 
src/exec.c

diff --combined src/exec.c
@@@ -78,6 -78,11 +78,11 @@@ typedef struct program_list_and_notific
  } program_list_and_notification_t;
  
  /*
+  * constants
+  */
+ const long int MAX_GRBUF_SIZE = 65536;
+ /*
   * Private variables
   */
  static program_list_t *pl_head = NULL;
@@@ -108,26 -113,26 +113,26 @@@ static int exec_config_exec(oconfig_ite
  
    if (ci->children_num != 0) {
      WARNING("exec plugin: The config option `%s' may not be a block.", ci->key);
 -    return (-1);
 +    return -1;
    }
    if (ci->values_num < 2) {
      WARNING("exec plugin: The config option `%s' needs at least two "
              "arguments.",
              ci->key);
 -    return (-1);
 +    return -1;
    }
    if ((ci->values[0].type != OCONFIG_TYPE_STRING) ||
        (ci->values[1].type != OCONFIG_TYPE_STRING)) {
      WARNING("exec plugin: The first two arguments to the `%s' option must "
              "be string arguments.",
              ci->key);
 -    return (-1);
 +    return -1;
    }
  
    pl = calloc(1, sizeof(*pl));
    if (pl == NULL) {
      ERROR("exec plugin: calloc failed.");
 -    return (-1);
 +    return -1;
    }
  
    if (strcasecmp("NotificationExec", ci->key) == 0)
    if (pl->user == NULL) {
      ERROR("exec plugin: strdup failed.");
      sfree(pl);
 -    return (-1);
 +    return -1;
    }
  
    pl->group = strchr(pl->user, ':');
      ERROR("exec plugin: strdup failed.");
      sfree(pl->user);
      sfree(pl);
 -    return (-1);
 +    return -1;
    }
  
    pl->argv = calloc(ci->values_num, sizeof(*pl->argv));
      sfree(pl->exec);
      sfree(pl->user);
      sfree(pl);
 -    return (-1);
 +    return -1;
    }
  
    {
      sfree(pl->exec);
      sfree(pl->user);
      sfree(pl);
 -    return (-1);
 +    return -1;
    }
  
    for (i = 1; i < (ci->values_num - 1); i++) {
        pl->argv[i] = strdup(ci->values[i + 1].value.string);
      } else {
        if (ci->values[i + 1].type == OCONFIG_TYPE_NUMBER) {
 -        ssnprintf(buffer, sizeof(buffer), "%lf",
 -                  ci->values[i + 1].value.number);
 +        snprintf(buffer, sizeof(buffer), "%lf", ci->values[i + 1].value.number);
        } else {
          if (ci->values[i + 1].value.boolean)
            sstrncpy(buffer, "true", sizeof(buffer));
      sfree(pl->exec);
      sfree(pl->user);
      sfree(pl);
 -    return (-1);
 +    return -1;
    }
  
    for (i = 0; pl->argv[i] != NULL; i++) {
    pl->next = pl_head;
    pl_head = pl;
  
 -  return (0);
 +  return 0;
  } /* int exec_config_exec }}} */
  
  static int exec_config(oconfig_item_t *ci) /* {{{ */
      }
    } /* for (i) */
  
 -  return (0);
 +  return 0;
  } /* int exec_config }}} */
  
  static void set_environment(void) /* {{{ */
    char buffer[1024];
  
  #ifdef HAVE_SETENV
 -  ssnprintf(buffer, sizeof(buffer), "%.3f",
 -            CDTIME_T_TO_DOUBLE(plugin_get_interval()));
 +  snprintf(buffer, sizeof(buffer), "%.3f",
 +           CDTIME_T_TO_DOUBLE(plugin_get_interval()));
    setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
  
    sstrncpy(buffer, hostname_g, sizeof(buffer));
    setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
  #else
 -  ssnprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f",
 -            CDTIME_T_TO_DOUBLE(plugin_get_interval()));
 +  snprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f",
 +           CDTIME_T_TO_DOUBLE(plugin_get_interval()));
    putenv(buffer);
  
 -  ssnprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
 +  snprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
    putenv(buffer);
  #endif
  } /* }}} void set_environment */
@@@ -331,7 -337,7 +336,7 @@@ static int create_pipe(int fd_pipe[2]) 
    if (status != 0) {
      ERROR("exec plugin: pipe failed: %s",
            sstrerror(errno, errbuf, sizeof(errbuf)));
 -    return (-1);
 +    return -1;
    }
  
    return 0;
@@@ -347,6 -353,67 +352,67 @@@ static void close_pipe(int fd_pipe[2]) 
  } /* }}} void close_pipe */
  
  /*
+  * Get effective group ID from group name.
+  * Input arguments:
+  *       pl  :program list struct with group name
+  *       gid :group id to fallback in case egid cannot be determined.
+  * Returns:
+  *       egid effective group id if successfull,
+  *            -1 if group is not defined/not found.
+  *            -2 for any buffer allocation error.
+  */
+ static int getegr_id(program_list_t *pl, int gid) /* {{{ */
+ {
+   if (pl->group == NULL) {
+     return -1;
+   }
+   if (strcmp(pl->group, "") == 0) {
+     return gid;
+   }
+   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 *temp = NULL;
+   char *grbuf = NULL;
+   do {
+     temp = realloc(grbuf, grbuf_size);
+     if (temp == NULL) {
+       ERROR("exec plugin: getegr_id for %s: realloc buffer[%ld] failed ",
+             pl->group, grbuf_size);
+       sfree(grbuf);
+       return -2;
+     }
+     grbuf = temp;
+     if (getgrnam_r(pl->group, &gr, grbuf, grbuf_size, &gr_ptr) == 0) {
+       sfree(grbuf);
+       if (gr_ptr == NULL) {
+         ERROR("exec plugin: No such group: `%s'", pl->group);
+         return -1;
+       }
+       return gr.gr_gid;
+     } else if (errno == ERANGE) {
+       grbuf_size += grbuf_size; // increment buffer size and try again
+     } else {
+       char errbuf[1024];
+       ERROR("exec plugin: getegr_id failed %s",
+             sstrerror(errno, errbuf, sizeof(errbuf)));
+       sfree(grbuf);
+       return -2;
+     }
+   } while (grbuf_size <= MAX_GRBUF_SIZE);
+   ERROR("exec plugin: getegr_id Max grbuf size reached  for %s", pl->group);
+   sfree(grbuf);
+   return -2;
+ } /* }}} */
+ /*
   * 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
@@@ -370,7 -437,7 +436,7 @@@ static int fork_child(program_list_t *p
    struct passwd sp;
  
    if (pl->pid != 0)
 -    return (-1);
 +    return -1;
  
    long int nambuf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
    if (nambuf_size <= 0)
      goto failed;
    }
  
-   /* 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, sstrerror(status, errbuf, sizeof(errbuf)));
-         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) {
+     goto failed;
+   }
  
    pid = fork();
    if (pid < 0) {
    else
      close(fd_pipe_err[0]);
  
 -  return (pid);
 +  return pid;
  
  failed:
    close_pipe(fd_pipe_in);
    close_pipe(fd_pipe_out);
    close_pipe(fd_pipe_err);
  
 -  return (-1);
 +  return -1;
  } /* int fork_child }}} */
  
  static int parse_line(char *buffer) /* {{{ */
  {
    if (strncasecmp("PUTVAL", buffer, strlen("PUTVAL")) == 0)
 -    return (cmd_handle_putval(stdout, buffer));
 +    return cmd_handle_putval(stdout, buffer);
    else if (strncasecmp("PUTNOTIF", buffer, strlen("PUTNOTIF")) == 0)
 -    return (handle_putnotif(stdout, buffer));
 +    return handle_putnotif(stdout, buffer);
    else {
      ERROR("exec plugin: Unable to parse command, ignoring line: \"%s\"",
            buffer);
 -    return (-1);
 +    return -1;
    }
  } /* int parse_line }}} */
  
@@@ -667,7 -706,7 +705,7 @@@ static void *exec_read_one(void *arg) /
      close(fd_err);
  
    pthread_exit((void *)0);
 -  return (NULL);
 +  return NULL;
  } /* void *exec_read_one }}} */
  
  static void *exec_notification_one(void *arg) /* {{{ */
    n->meta = NULL;
    sfree(arg);
    pthread_exit((void *)0);
 -  return (NULL);
 +  return NULL;
  } /* void *exec_notification_one }}} */
  
  static int exec_init(void) /* {{{ */
    }
  #endif
  
 -  return (0);
 +  return 0;
  } /* int exec_init }}} */
  
  static int exec_read(void) /* {{{ */
      pthread_attr_destroy(&attr);
    } /* for (pl) */
  
 -  return (0);
 +  return 0;
  } /* int exec_read }}} */
  
  static int exec_notification(const notification_t *n, /* {{{ */
      pthread_attr_destroy(&attr);
    } /* for (pl) */
  
 -  return (0);
 +  return 0;
  } /* }}} int exec_notification */
  
  static int exec_shutdown(void) /* {{{ */
    } /* while (pl) */
    pl_head = NULL;
  
 -  return (0);
 +  return 0;
  } /* int exec_shutdown }}} */
  
  void module_register(void) {
                                 /* user_data = */ NULL);
    plugin_register_shutdown("exec", exec_shutdown);
  } /* void module_register */
 -
 -/*
 - * vim:shiftwidth=2:softtabstop=2:tabstop=8:fdm=marker
 - */