#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_cmd_putval.h"
#include <sys/types.h>
#include <pwd.h>
+#include <grp.h>
#include <signal.h>
#include <pthread.h>
struct program_list_s
{
char *user;
+ char *group;
char *exec;
int pid;
program_list_t *next;
pl->next = pl_head;
pl_head = pl;
+
+ pl->group = strchr (pl->user, ':');
+ if (NULL != pl->group) {
+ *pl->group = '\0';
+ pl->group++;
+ }
}
else
{
{
int status;
int uid;
+ int gid;
+ int egid;
char *arg0;
struct passwd *sp_ptr;
struct passwd sp;
- char pwnambuf[2048];
+ char nambuf[2048];
char errbuf[1024];
sp_ptr = NULL;
- status = getpwnam_r (pl->user, &sp, pwnambuf, sizeof (pwnambuf), &sp_ptr);
+ status = getpwnam_r (pl->user, &sp, nambuf, sizeof (nambuf), &sp_ptr);
if (status != 0)
{
ERROR ("exec plugin: getpwnam_r failed: %s",
}
uid = sp.pw_uid;
+ gid = sp.pw_gid;
if (uid == 0)
{
ERROR ("exec plugin: Cowardly refusing to exec program as root.");
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) {
+ struct group *gr_ptr = NULL;
+ struct group gr;
+
+ status = getgrnam_r (pl->group, &gr, nambuf, sizeof (nambuf), &gr_ptr);
+ if (0 != status)
+ {
+ ERROR ("exec plugin: getgrnam_r failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ exit (-1);
+ }
+ if (NULL == gr_ptr)
+ {
+ ERROR ("exec plugin: No such group: `%s'", pl->group);
+ exit (-1);
+ }
+
+ egid = gr.gr_gid;
+ }
+ else
+ {
+ 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) && (egid != -1))
+ {
+ glist[1] = egid;
+ glist_len = 2;
+ }
+
+ setgroups (glist_len, glist);
+ }
+#endif /* HAVE_SETGROUPS */
+
+ 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: setegid (%i) failed: %s",
+ egid, sstrerror (errno, errbuf, sizeof (errbuf)));
+ exit (-1);
+ }
+ }
+
status = setuid (uid);
if (status != 0)
{
- ERROR ("exec plugin: setuid failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
+ ERROR ("exec plugin: setuid (%i) failed: %s",
+ uid, sstrerror (errno, errbuf, sizeof (errbuf)));
exit (-1);
}
}
else if (pl->pid == 0)
{
- close (fd_pipe[0]);
+ int fd_num;
+ int fd;
+
+ /* Close all file descriptors but the pipe end we need. */
+ fd_num = getdtablesize ();
+ for (fd = 0; fd < fd_num; fd++)
+ {
+ if (fd == fd_pipe[1])
+ continue;
+ close (fd);
+ }
/* Connect the pipe to STDOUT and STDERR */
if (fd_pipe[1] != STDOUT_FILENO)
static int parse_line (char *buffer)
{
- char *fields[4];
+ char *fields[256];
int fields_num;
- char *hostname;
- char *plugin;
- char *plugin_instance;
- char *type;
- char *type_instance;
-
- const data_set_t *ds;
- value_list_t vl = VALUE_LIST_INIT;
-
- int status;
-
- fields_num = strsplit (buffer, fields, 4);
- if (fields_num != 2)
- {
- WARNING ("exec plugin: Number of fields is not 2.");
- return (-1);
- }
-
- status = parse_identifier (fields[0], &hostname,
- &plugin, &plugin_instance,
- &type, &type_instance);
- if (status != 0)
- {
- WARNING ("exec plugin: Cannot parse `%s'", fields[0]);
- return (-1);
- }
-
- if ((strlen (hostname) >= sizeof (vl.host))
- || (strlen (plugin) >= sizeof (vl.plugin))
- || ((plugin_instance != NULL)
- && (strlen (plugin_instance) >= sizeof (vl.plugin_instance)))
- || ((type_instance != NULL)
- && (strlen (type_instance) >= sizeof (vl.type_instance))))
- {
- WARNING ("exec plugin: An identifier is too long.");
- return (-1);
- }
-
- strcpy (vl.host, hostname);
- strcpy (vl.plugin, plugin);
- if (plugin_instance != NULL)
- strcpy (vl.plugin_instance, plugin_instance);
- if (type_instance != NULL)
- strcpy (vl.type_instance, type_instance);
-
- ds = plugin_get_ds (type);
- if (ds == NULL)
- {
- WARNING ("exec plugin: No such type: `%s'", type);
- return (-1);
- }
-
- vl.values_len = ds->ds_num;
- vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
- if (vl.values == NULL)
- return (-1);
-
- /* Sets vl.values and vl.time */
- status = parse_values (fields[1], &vl, ds);
- if (status != 0)
- {
- WARNING ("exec plugin: Cannot parse `%s'", fields[1]);
- sfree (vl.values);
- return (-1);
- }
-
- plugin_dispatch_values (type, &vl);
+ fields[0] = "PUTVAL";
+ fields_num = strsplit (buffer, &fields[1], STATIC_ARRAY_SIZE(fields) - 1);
- sfree (vl.values);
-
+ handle_putval (stdout, fields, fields_num + 1);
return (0);
} /* int parse_line */
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);
}