#include "collectd.h"
-#include "common.h"
#include "plugin.h"
+#include "utils/common/common.h"
-#include "utils_cmd_putnotif.h"
-#include "utils_cmd_putval.h"
+#include "utils/cmds/putnotif.h"
+#include "utils/cmds/putval.h"
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <sys/types.h>
-#include <stdlib.h>
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
#endif
return 0;
} /* int exec_config }}} */
+#if !defined(HAVE_SETENV)
+static char env_interval[64];
+// max hostname len is 255, so this should be enough
+static char env_hostname[300];
+#endif
+
static void set_environment(void) /* {{{ */
{
+#ifdef HAVE_SETENV
char buffer[1024];
-#ifdef HAVE_SETENV
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
- snprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f",
+ snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL=%.3f",
CDTIME_T_TO_DOUBLE(plugin_get_interval()));
- putenv(buffer);
+ putenv(env_interval);
- snprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
- putenv(buffer);
+ snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME=%s",
+ hostname_g);
+ putenv(env_hostname);
#endif
} /* }}} void set_environment */
+static void unset_environment(void) /* {{{ */
+{
+#ifdef HAVE_SETENV
+ unsetenv("COLLECTD_INTERVAL");
+ unsetenv("COLLECTD_HOSTNAME");
+#else
+ snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL");
+ putenv(env_interval);
+ snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME");
+ putenv(env_hostname);
+#endif
+} /* }}} void unset_environment */
+
__attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid,
int gid, int egid) /* {{{ */
{
} /* }}} 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 {
+ ERROR("exec plugin: getegr_id failed %s", STRERRNO);
+ 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
/* 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;
-
- 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) {
- goto failed;
- }
- } else {
- egid = gid;
- }
- } /* if (pl->group == NULL) */
+ egid = getegr_id(pl, gid);
+ if (egid == -2) {
+ goto failed;
+ }
+
+ set_environment();
pid = fork();
if (pid < 0) {
close(fd_pipe_err[1]);
}
- set_environment();
-
/* Unblock all signals */
reset_signal_mask();
/* does not return */
}
+ unset_environment();
+
close(fd_pipe_in[0]);
close(fd_pipe_out[1]);
close(fd_pipe_err[1]);
return pid;
failed:
+ unset_environment();
+
close_pipe(fd_pipe_in);
close_pipe(fd_pipe_out);
close_pipe(fd_pipe_err);