X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fexec.c;h=e5c5df9f3eef09dc6102bfdd475302cf08d05d04;hb=2b95935417aa46534bf986c06a8723e0af32d63f;hp=36f2d4da19021eae2a63d9684058422881a9d888;hpb=849f5394cce97a76da080f6cd9e5194b7f4ee0f0;p=collectd.git diff --git a/src/exec.c b/src/exec.c index 36f2d4da..e5c5df9f 100644 --- a/src/exec.c +++ b/src/exec.c @@ -39,6 +39,7 @@ #include #include +#include #ifdef HAVE_SYS_CAPABILITY_H #include #endif @@ -78,9 +79,14 @@ 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 = NULL; +static program_list_t *pl_head; static pthread_mutex_t pl_lock = PTHREAD_MUTEX_INITIALIZER; /* @@ -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) {