summaryrefslogtreecommitdiffstats
path: root/worker/helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'worker/helpers.c')
-rw-r--r--worker/helpers.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/worker/helpers.c b/worker/helpers.c
new file mode 100644
index 0000000..e4b503d
--- /dev/null
+++ b/worker/helpers.c
@@ -0,0 +1,182 @@
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+
+#include <selinux/selinux.h>
+
+#include "util.h"
+
+/**
+ * \brief Open a temporary file in a safe way
+ *
+ * Use this function to create a temporary file in a safe way with the help of
+ * mkstemp and set file properties.
+ *
+ * \param name name of the temporary file in the format mkstemp expects, i.e.
+ * ending with XXXXXX; mkstemp will modify name to contain the name of the
+ * temporary file
+ * \param permission string wit hthe octal repesentation of the file access
+ * permissions
+ * \param user name of the file owner
+ * \param group name of the owning group
+ * \param selinux_context_string string containing the SELinux file context
+ *
+ * \return file descriptor or -1 in case of an error
+ *
+ */
+int open_temporary_file(char *name, const char *permission, const char *user, const char *group, const char *selinux_context_string) {
+ int fd;
+ int ret;
+ struct passwd *pwd_info;
+ struct group *grp_info;
+
+ pwd_info=getpwnam(user);
+ CHECK(pwd_info, NULL, ("Cannot find user %s.\n", user), return -1);
+ grp_info=getgrnam(group);
+ CHECK(grp_info, NULL, ("Cannot find group %s.\n", group), return -1);
+
+
+ fd=mkstemp(name);
+ if (fd==-1) {
+ DEBUG(0,("mkstemp failed with template %s: %s\n",name, strerror(errno)));
+ return -1;
+ }
+
+ ret=fchmod(fd, (mode_t) strtol(permission, NULL, 8));
+ CHECK(ret, -1, ("Cannot chmod temporary file to %s: %s\n", permission, strerror(errno)), return -1);
+
+ ret=fchown(fd, pwd_info->pw_uid, grp_info->gr_gid);
+ CHECK(ret, -1, ("Cannot chown temporary file to %s:%s: %s\n", user, group, strerror(errno)), return -1);
+
+ if (selinux_context_string != NULL ) {
+
+ ret=fsetfilecon(fd, (security_context_t ) selinux_context_string);
+ CHECK(ret, -1, ("fsetfilecon failed: %s\n",strerror(errno)), return -1);
+
+ }
+
+ return fd;
+}
+
+
+/**
+ * \brief run an external command
+ *
+ * This is a helper function to run an external command in a different user
+ * context.
+ *
+ * \param command command to run
+ * \param user name of the user to run the command
+ * \param group name of the group to run the command
+ * \param arguments space separated list of arguments, may be NULL
+ * \param extra_args another space separated list of arguments, useful if you
+ * have some static and some generated/extracted arguments, may be NULL
+ *
+ * \return return code of the external command or -1 in an error occurred
+ *
+ */
+int exec_command(const char *command, const char *user, const char *group, char *arguments, char *extra_args) {
+ char *argv[10]; /* FIXME */
+ int c=0;
+ int i;
+ char *cur;
+ char *next_arg;
+ pid_t pid;
+ int ret;
+ int status;
+ int stdout_pipe[2];
+ int stderr_pipe[2];
+ char buffer[255];
+ struct passwd *pwd_info;
+ struct group *grp_info;
+
+ pwd_info=getpwnam(user);
+ CHECK(pwd_info, NULL, ("Cannot find user %s.\n", user), return -1);
+ grp_info=getgrnam(group);
+ CHECK(grp_info, NULL, ("Cannot find group %s.\n", group), return -1);
+
+ argv[c++]=strdup(command);
+ if (arguments!=NULL) {
+ cur=arguments;
+ while( (next_arg=strchr(cur, ' '))!=NULL) {
+ argv[c++]=strndup(cur, next_arg-cur);
+ cur=next_arg+1;
+ }
+ argv[c++]=strdup(cur);
+ }
+ if (extra_args!=NULL) {
+ cur=extra_args;
+ while( (next_arg=strchr(cur, ' '))!=NULL) {
+ argv[c++]=strndup(cur, next_arg-cur);
+ cur=next_arg+1;
+ }
+ argv[c++]=strdup(cur);
+ }
+ argv[c++]=NULL;
+
+ for(i=0;i<c;i++){
+ DEBUG(3,("argument array element %d: |%s|\n",i, argv[i]));
+ }
+
+ ret=pipe(stdout_pipe);
+ CHECK(ret, -1, ("pipe failed: %s\n",strerror(errno)), return -1);
+ ret=pipe(stderr_pipe);
+ CHECK(ret, -1, ("pipe failed: %s\n",strerror(errno)), return -1);
+
+ pid=fork();
+ CHECK(pid, -1, ("fork failed: %s",strerror(errno)), return -1);
+ if (!pid) { /* FIXME: missing error checking */
+
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
+
+ ret=dup2(stdout_pipe[1], STDOUT_FILENO);
+ CHECK(ret, -1, ("dup2 failed: %s\n",strerror(errno)), exit(1));
+ ret=dup2(stderr_pipe[1], STDERR_FILENO);
+ CHECK(ret, -1, ("dup2 failed: %s\n",strerror(errno)), exit(1));
+ close(STDIN_FILENO);
+
+ ret=chdir("/");
+ CHECK(ret, -1, ("chdir to / failed: %s\n",strerror(errno)), exit(1));
+ ret=setgid(grp_info->gr_gid);
+ CHECK(ret, -1, ("setgid failed: %s\n",strerror(errno)), exit(1));
+ ret=setuid(pwd_info->pw_uid);
+ CHECK(ret, -1, ("setuid failed: %s\n",strerror(errno)), exit(1));
+
+ execv(command, argv);
+ }
+
+ close(stdout_pipe[1]);
+ close(stderr_pipe[1]);
+
+ *buffer='\0';
+ ret=read(stdout_pipe[0], &buffer, 255);
+ buffer[ret]='\0';
+ DEBUG(3,("stdout from child: >>%s<<\n",buffer));
+ *buffer='\0';
+ ret=read(stderr_pipe[0], &buffer, 255);
+ buffer[ret]='\0';
+ DEBUG(3,("stderr from child: >>%s<<\n",buffer));
+
+ ret = waitpid(pid, & status, 0);
+ if (WIFEXITED(status)) {
+ DEBUG(3,("Child terminated normally with exit status %d\n",WEXITSTATUS(status)));
+ } else {
+ DEBUG(1,("Child terminated not normally.\n"));
+ }
+
+
+ for(i=0;i<c;i++){
+ free(argv[i]);
+ }
+ return WEXITSTATUS(status);
+}