#include <signal.h>
#include <sys/types.h>
+#include <stdlib.h>
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
#endif
} 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;
/*
int gid, int egid) /* {{{ */
{
int status;
- char errbuf[1024];
#if HAVE_SETGROUPS
if (getuid() == 0) {
status = setgid(gid);
if (status != 0) {
- ERROR("exec plugin: setgid (%i) failed: %s", gid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: setgid (%i) failed: %s", gid, STRERRNO);
exit(-1);
}
if (egid != -1) {
status = setegid(egid);
if (status != 0) {
- ERROR("exec plugin: setegid (%i) failed: %s", egid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: setegid (%i) failed: %s", egid, STRERRNO);
exit(-1);
}
}
status = setuid(uid);
if (status != 0) {
- ERROR("exec plugin: setuid (%i) failed: %s", uid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: setuid (%i) failed: %s", uid, STRERRNO);
exit(-1);
}
execvp(pl->exec, pl->argv);
- ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec, STRERRNO);
exit(-1);
} /* void exec_child }}} */
static int create_pipe(int fd_pipe[2]) /* {{{ */
{
- char errbuf[1024];
int status;
status = pipe(fd_pipe);
if (status != 0) {
- ERROR("exec plugin: pipe failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: pipe failed: %s", STRERRNO);
return -1;
}
} /* }}} 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
int fd_pipe_in[2] = {-1, -1};
int fd_pipe_out[2] = {-1, -1};
int fd_pipe_err[2] = {-1, -1};
- char errbuf[1024];
int status;
int pid;
struct passwd *sp_ptr;
struct passwd sp;
- char nambuf[4096];
if (pl->pid != 0)
return -1;
+ long int nambuf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (nambuf_size <= 0)
+ nambuf_size = sysconf(_SC_PAGESIZE);
+ if (nambuf_size <= 0)
+ nambuf_size = 4096;
+ char nambuf[nambuf_size];
+
if ((create_pipe(fd_pipe_in) == -1) || (create_pipe(fd_pipe_out) == -1) ||
(create_pipe(fd_pipe_err) == -1))
goto failed;
status = getpwnam_r(pl->user, &sp, nambuf, sizeof(nambuf), &sp_ptr);
if (status != 0) {
ERROR("exec plugin: Failed to get user information for user ``%s'': %s",
- pl->user, sstrerror(status, errbuf, sizeof(errbuf)));
+ pl->user, STRERROR(status));
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;
-
- status = getgrnam_r(pl->group, &gr, nambuf, sizeof(nambuf), &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) {
+ ERROR("exec plugin: getegr_id failed: %s", STRERRNO);
+ goto failed;
+ }
pid = fork();
if (pid < 0) {
- ERROR("exec plugin: fork failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: fork failed: %s", STRERRNO);
goto failed;
} else if (pid == 0) {
int fd_num;
fh = fdopen(fd, "w");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("exec plugin: fdopen (%i) failed: %s", fd,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: fdopen (%i) failed: %s", fd, STRERRNO);
kill(pid, SIGTERM);
close(fd);
sfree(arg);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- plugin_thread_create(&t, &attr, exec_read_one, (void *)pl, "exec read");
+ int status =
+ plugin_thread_create(&t, &attr, exec_read_one, (void *)pl, "exec read");
+ if (status != 0) {
+ ERROR("exec plugin: plugin_thread_create failed.");
+ }
pthread_attr_destroy(&attr);
} /* for (pl) */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- plugin_thread_create(&t, &attr, exec_notification_one, (void *)pln,
- "exec notify");
+ int status = plugin_thread_create(&t, &attr, exec_notification_one,
+ (void *)pln, "exec notify");
+ if (status != 0) {
+ ERROR("exec plugin: plugin_thread_create failed.");
+ }
pthread_attr_destroy(&attr);
} /* for (pl) */