summaryrefslogtreecommitdiff
path: root/src/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/proc.c')
-rw-r--r--src/proc.c186
1 files changed, 150 insertions, 36 deletions
diff --git a/src/proc.c b/src/proc.c
index a7b47aa..1151fff 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -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;
+}