diff --git a/isolate/util.c b/isolate/util.c new file mode 100644 --- /dev/null +++ b/isolate/util.c @@ -0,0 +1,182 @@ +/* + * Process Isolator -- Utility Functions + * + * (c) 2012-2017 Martin Mares + * (c) 2012-2014 Bernard Blackham + */ + +#include "isolate.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void * +xmalloc(size_t size) +{ + void *p = malloc(size); + if (!p) + die("Out of memory"); + return p; +} + +char * +xstrdup(char *str) +{ + char *p = strdup(str); + if (!p) + die("Out of memory"); + return p; +} + +int +dir_exists(char *path) +{ + struct stat st; + return (stat(path, &st) >= 0 && S_ISDIR(st.st_mode)); +} + +void +make_dir(char *path) +{ + char *sep = (path[0] == '/' ? path+1 : path); + + for (;;) + { + sep = strchr(sep, '/'); + if (sep) + *sep = 0; + + if (mkdir(path, 0777) < 0 && errno != EEXIST) + die("Cannot create directory %s: %m", path); + + if (!sep) + break; + *sep++ = '/'; + } + + // mkdir() above may have returned EEXIST even if the path was not + // a directory. Ensure that it is. + struct stat st; + if (stat(path, &st) < 0) + die("Cannot stat %s: %m", path); + if (!S_ISDIR(st.st_mode)) + die("Cannot create %s: already exists, but not a directory", path); +} + + +static int +rmtree_helper(const char *fpath, const struct stat *sb, int typeflag UNUSED, struct FTW *ftwbuf UNUSED) +{ + if (S_ISDIR(sb->st_mode)) + { + if (rmdir(fpath) < 0) + die("Cannot rmdir %s: %m", fpath); + } + else + { + if (unlink(fpath) < 0) + die("Cannot unlink %s: %m", fpath); + } + return 0; +} + +void +rmtree(char *path) +{ + nftw(path, rmtree_helper, 32, FTW_MOUNT | FTW_PHYS | FTW_DEPTH); +} + +static uid_t chown_uid; +static gid_t chown_gid; + +static int +chowntree_helper(const char *fpath, const struct stat *sb UNUSED, int typeflag UNUSED, struct FTW *ftwbuf UNUSED) +{ + if (lchown(fpath, chown_uid, chown_gid) < 0) + die("Cannot chown %s: %m", fpath); + else + return 0; +} + +void +chowntree(char *path, uid_t uid, gid_t gid) +{ + chown_uid = uid; + chown_gid = gid; + nftw(path, chowntree_helper, 32, FTW_MOUNT | FTW_PHYS); +} + +static int fd_to_keep = -1; + +void +close_all_fds(void) +{ + /* Close all file descriptors except 0, 1, 2 */ + + DIR *dir = opendir("/proc/self/fd"); + if (!dir) + die("Cannot open /proc/self/fd: %m"); + int dir_fd = dirfd(dir); + + struct dirent *e; + while (e = readdir(dir)) + { + char *end; + long int fd = strtol(e->d_name, &end, 10); + if (*end) + continue; + if (fd >= 0 && fd <= 2 || fd == dir_fd || fd == fd_to_keep) + continue; + close(fd); + } + + closedir(dir); +} + +/*** Meta-files ***/ + +static FILE *metafile; + +void +meta_open(const char *name) +{ + if (!strcmp(name, "-")) + { + metafile = stdout; + return; + } + if (setfsuid(getuid()) < 0) + die("Failed to switch FS UID: %m"); + metafile = fopen(name, "w"); + if (setfsuid(geteuid()) < 0) + die("Failed to switch FS UID back: %m"); + if (!metafile) + die("Failed to open metafile '%s'",name); + fd_to_keep = fileno(metafile); +} + +void +meta_close(void) +{ + if (metafile && metafile != stdout) + fclose(metafile); +} + +void +meta_printf(const char *fmt, ...) +{ + if (!metafile) + return; + + va_list args; + va_start(args, fmt); + vfprintf(metafile, fmt, args); + va_end(args); +}