diff options
Diffstat (limited to 'src/proc.c')
-rw-r--r-- | src/proc.c | 186 |
1 files changed, 150 insertions, 36 deletions
@@ -7,42 +7,118 @@ * General Public License as published by the Free Software Foundation; * either version 2.1 or (at your option) any later version. */ -#include "config.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "internal.h" - -#if !defined(HAVE_FORK) || !defined(HAVE_PIPE) || !defined(HAVE_EXECV) || \ - !defined(HAVE_EXECVP) #include <errno.h> +#include <limits.h> +#include <unistd.h> +#ifdef HAVE_SYS_RESOURCE_H +# include <sys/resource.h> +#endif #include <libHX/proc.h> +#ifdef _WIN32 +# include <winsock2.h> +#endif -struct HXproc; +#if defined(HAVE_INITGROUPS) && defined(HAVE_SETGID) +#include <grp.h> +#include <pwd.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> -EXPORT_SYMBOL int HXproc_run_async(const char *const *argv, struct HXproc *p) +static int HXproc_switch_gid(const struct passwd *pw, gid_t gr_gid) { - return -ENOSYS; + bool do_setgid = getgid() != gr_gid || getegid() != gr_gid; + if (do_setgid && setgid(gr_gid) != 0) { + if (errno == 0) + errno = -EINVAL; + return HXPROC_SETGID_FAILED; + } + if (pw == NULL) + return do_setgid ? HXPROC_SU_SUCCESS : HXPROC_SU_NOOP; + + /* pw!=NULL: user switch requested, do initgroups now. */ + + if (geteuid() == pw->pw_uid) { + /* + * Target identity (usually unprivileged) already reached. + * initgroups is unlikely to succeed. + */ + if (initgroups(pw->pw_name, gr_gid) < 0) + /* ignore */; + return do_setgid ? HXPROC_SU_SUCCESS : HXPROC_SU_NOOP; + } + if (initgroups(pw->pw_name, gr_gid) != 0) + return HXPROC_INITGROUPS_FAILED; + return do_setgid ? HXPROC_SU_SUCCESS : HXPROC_SU_NOOP; } -EXPORT_SYMBOL int HXproc_run_sync(const char *const *argv, unsigned int flags) +static int HXproc_switch_group(const struct passwd *pw, const char *group) { - /* Might use system() here... */ - return -ENOSYS; + char *end; + unsigned long gid = strtoul(group, &end, 10); + const struct group *gr = *end == '\0' ? getgrgid(gid) : getgrnam(group); + if (gr == NULL) { + if (errno == 0) + errno = ENOENT; + return HXPROC_GROUP_NOT_FOUND; + } + return HXproc_switch_gid(pw, gr->gr_gid); } -EXPORT_SYMBOL int HXproc_wait(struct HXproc *p) +EXPORT_SYMBOL int HXproc_switch_user(const char *user, const char *group) +{ + const struct passwd *pw = NULL; + if (user != NULL && *user != '\0') { + char *end; + unsigned long uid = strtoul(user, &end, 10); + pw = *end == '\0' ? getpwuid(uid) : getpwnam(user); + if (pw == NULL) { + if (errno == 0) + errno = ENOENT; + return HXPROC_USER_NOT_FOUND; + } + } + int ret = HXPROC_SU_NOOP; + if (group != NULL && *group != '\0') { + ret = HXproc_switch_group(pw, group); + if (ret < 0) + return ret; + } else if (group == NULL && pw != NULL) { + ret = HXproc_switch_gid(pw, pw->pw_gid); + if (ret < 0) + return ret; + } + bool do_setuid = pw != NULL && (getuid() != pw->pw_uid || geteuid() != pw->pw_uid); + if (do_setuid && setuid(pw->pw_uid) != 0) { + if (errno == 0) + errno = -EINVAL; + return HXPROC_SETUID_FAILED; + } + return do_setuid ? HXPROC_SU_SUCCESS : ret; +} + +#else + +EXPORT_SYMBOL int HXproc_switch_user(const char *user, const char *group) { return -ENOSYS; } -#else /* HAVE_FORK, HAVE_PIPE, HAVE_EXECVE */ +#endif /* HAVE_lots */ +#if defined(HAVE_FORK) && defined(HAVE_PIPE) && defined(HAVE_EXECV) && \ + defined(HAVE_EXECVP) #include <sys/wait.h> #include <fcntl.h> -#include <errno.h> +#include <stdbool.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <libHX/defs.h> -#include <libHX/proc.h> #include "internal.h" #ifdef _WIN32 @@ -88,18 +164,20 @@ HXproc_build_pipes(const struct HXproc *proc, int (*p)[2]) */ static void HXproc_close_pipes(int (*p)[2]) { +#define xc(fd) do { close(fd); (fd) = -1; } while (false) if (p[0][0] >= 0) - close(p[0][0]); + xc(p[0][0]); if (p[0][1] >= 0) - close(p[0][1]); + xc(p[0][1]); if (p[1][0] >= 0) - close(p[1][0]); + xc(p[1][0]); if (p[1][1] >= 0) - close(p[1][1]); + xc(p[1][1]); if (p[2][0] >= 0) - close(p[2][0]); + xc(p[2][0]); if (p[2][1] >= 0) - close(p[2][1]); + xc(p[2][1]); +#undef xc } /** @@ -113,29 +191,27 @@ EXPORT_SYMBOL int HXproc_run_async(const char *const *argv, struct HXproc *proc) { int pipes[3][2], nullfd = -1, ret, saved_errno; - unsigned int t; if (argv == NULL || *argv == NULL) return -EFAULT; - - proc->p_stdin = proc->p_stdout = proc->p_stderr = -1; - - t = (proc->p_flags & (HXPROC_STDIN | HXPROC_NULL_STDIN)) == - (HXPROC_STDIN | HXPROC_NULL_STDIN); - t |= (proc->p_flags & (HXPROC_STDOUT | HXPROC_NULL_STDOUT)) == - (HXPROC_STDOUT | HXPROC_NULL_STDOUT); - t |= (proc->p_flags & (HXPROC_STDERR | HXPROC_NULL_STDERR)) == - (HXPROC_STDERR | HXPROC_NULL_STDERR); - if (t > 0) + if ((proc->p_flags & (HXPROC_STDIN | HXPROC_NULL_STDIN)) == + (HXPROC_STDIN | HXPROC_NULL_STDIN)) + return -EINVAL; + if ((proc->p_flags & (HXPROC_STDOUT | HXPROC_NULL_STDOUT)) == + (HXPROC_STDOUT | HXPROC_NULL_STDOUT)) + return -EINVAL; + if ((proc->p_flags & (HXPROC_STDERR | HXPROC_NULL_STDERR)) == + (HXPROC_STDERR | HXPROC_NULL_STDERR)) return -EINVAL; - if (proc->p_flags & (HXPROC_NULL_STDIN | HXPROC_NULL_STDOUT | HXPROC_NULL_STDERR)) { if ((nullfd = open(NULL_DEVICE, O_RDWR)) < 0) return -errno; } + proc->p_stdin = proc->p_stdout = proc->p_stderr = -1; if ((ret = HXproc_build_pipes(proc, pipes)) <= 0) { saved_errno = errno; + HXproc_close_pipes(pipes); if (nullfd >= 0) close(nullfd); errno = saved_errno; @@ -183,17 +259,17 @@ HXproc_run_async(const char *const *argv, struct HXproc *proc) */ HXproc_close_pipes(pipes); if ((proc->p_flags & (HXPROC_STDIN | HXPROC_NULL_STDIN)) && - proc->p_stdin != STDIN_FILENO) { + proc->p_stdin >= 0 && proc->p_stdin != STDIN_FILENO) { dup2(proc->p_stdin, STDIN_FILENO); close(proc->p_stdin); } if ((proc->p_flags & (HXPROC_STDOUT | HXPROC_NULL_STDOUT)) && - proc->p_stdout != STDOUT_FILENO) { + proc->p_stdout >= 0 && proc->p_stdout != STDOUT_FILENO) { dup2(proc->p_stdout, STDOUT_FILENO); close(proc->p_stdout); } if ((proc->p_flags & (HXPROC_STDERR | HXPROC_NULL_STDERR)) && - proc->p_stderr != STDERR_FILENO) { + proc->p_stderr >= 0 && proc->p_stderr != STDERR_FILENO) { dup2(proc->p_stderr, STDERR_FILENO); close(proc->p_stderr); } @@ -223,7 +299,8 @@ HXproc_run_async(const char *const *argv, struct HXproc *proc) close(pipes[2][1]); proc->p_stderr = pipes[2][0]; } - + if (nullfd >= 0) + close(nullfd); return 1; } @@ -266,4 +343,41 @@ EXPORT_SYMBOL int HXproc_wait(struct HXproc *proc) return static_cast(unsigned char, proc->p_status); } +#else + +EXPORT_SYMBOL int HXproc_run_async(const char *const *argv, struct HXproc *p) +{ + return -ENOSYS; +} + +EXPORT_SYMBOL int HXproc_run_sync(const char *const *argv, unsigned int flags) +{ + /* Might use system() here... */ + return -ENOSYS; +} + +EXPORT_SYMBOL int HXproc_wait(struct HXproc *p) +{ + return -ENOSYS; +} + #endif /* HAVE_lots */ + +EXPORT_SYMBOL int HXproc_top_fd(void) +{ +#ifndef _WIN32 + struct rlimit r; + if (getrlimit(RLIMIT_NOFILE, &r) == 0) { + if (r.rlim_max > INT_MAX) + r.rlim_max = INT_MAX; + return r.rlim_max; + } + long v = sysconf(_SC_OPEN_MAX); + if (v >= 0) { + if (v > INT_MAX) + v = INT_MAX; + return v; + } +#endif + return FD_SETSIZE; +} |