]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/nspawn/nspawn-setuid.c
tree-wide: port various places over to use new rearrange_stdio()
[thirdparty/systemd.git] / src / nspawn / nspawn-setuid.c
index 2a1dfd83a9bd568ea74cdefd631489fa94811e5c..2dee5f8ec8224f27608a75696f4d21481f872dfe 100644 (file)
@@ -1,5 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
+#include "def.h"
+#include "errno.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "mkdir.h"
 #include "nspawn-setuid.h"
 #include "process-util.h"
 #include "signal-util.h"
 #include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
 #include "util.h"
 
 static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
-        int pipe_fds[2];
+        int pipe_fds[2], r;
         pid_t pid;
 
         assert(database);
@@ -42,36 +47,19 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
         if (pipe2(pipe_fds, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to allocate pipe: %m");
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork getent child: %m");
-        else if (pid == 0) {
-                int nullfd;
+        r = safe_fork("(getent)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
+        if (r < 0) {
+                safe_close_pair(pipe_fds);
+                return r;
+        }
+        if (r == 0) {
                 char *empty_env = NULL;
 
-                if (dup3(pipe_fds[1], STDOUT_FILENO, 0) < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (pipe_fds[0] > 2)
-                        safe_close(pipe_fds[0]);
-                if (pipe_fds[1] > 2)
-                        safe_close(pipe_fds[1]);
+                safe_close(pipe_fds[0]);
 
-                nullfd = open("/dev/null", O_RDWR);
-                if (nullfd < 0)
+                if (rearrange_stdio(-1, pipe_fds[1], -1) < 0)
                         _exit(EXIT_FAILURE);
 
-                if (dup3(nullfd, STDIN_FILENO, 0) < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (dup3(nullfd, STDERR_FILENO, 0) < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (nullfd > 2)
-                        safe_close(nullfd);
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
                 close_all_fds(NULL, 0);
 
                 execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
@@ -87,10 +75,10 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
 }
 
 int change_uid_gid(const char *user, char **_home) {
-        char line[LINE_MAX], *x, *u, *g, *h;
+        char *x, *u, *g, *h;
         const char *word, *state;
         _cleanup_free_ uid_t *uids = NULL;
-        _cleanup_free_ char *home = NULL;
+        _cleanup_free_ char *home = NULL, *line = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_close_ int fd = -1;
         unsigned n_uids = 0;
@@ -102,7 +90,7 @@ int change_uid_gid(const char *user, char **_home) {
 
         assert(_home);
 
-        if (!user || streq(user, "root") || streq(user, "0")) {
+        if (!user || STR_IN_SET(user, "root", "0")) {
                 /* Reset everything fully to 0, just in case */
 
                 r = reset_uid_gid();
@@ -118,25 +106,20 @@ int change_uid_gid(const char *user, char **_home) {
         if (fd < 0)
                 return fd;
 
-        f = fdopen(fd, "r");
+        f = fdopen(fd, "re");
         if (!f)
                 return log_oom();
         fd = -1;
 
-        if (!fgets(line, sizeof(line), f)) {
-
-                if (!ferror(f)) {
-                        log_error("Failed to resolve user %s.", user);
-                        return -ESRCH;
-                }
-
-                log_error_errno(errno, "Failed to read from getent: %m");
-                return -errno;
+        r = read_line(f, LONG_LINE_MAX, &line);
+        if (r == 0) {
+                log_error("Failed to resolve user %s.", user);
+                return -ESRCH;
         }
+        if (r < 0)
+                return log_error_errno(r, "Failed to read from getent: %m");
 
-        truncate_nl(line);
-
-        wait_for_terminate_and_warn("getent passwd", pid, true);
+        (void) wait_for_terminate_and_check("getent passwd", pid, WAIT_LOG);
 
         x = strchr(line, ':');
         if (!x) {
@@ -197,30 +180,28 @@ int change_uid_gid(const char *user, char **_home) {
         if (!home)
                 return log_oom();
 
+        f = safe_fclose(f);
+        line = mfree(line);
+
         /* Second, get group memberships */
         fd = spawn_getent("initgroups", user, &pid);
         if (fd < 0)
                 return fd;
 
-        fclose(f);
-        f = fdopen(fd, "r");
+        f = fdopen(fd, "re");
         if (!f)
                 return log_oom();
         fd = -1;
 
-        if (!fgets(line, sizeof(line), f)) {
-                if (!ferror(f)) {
-                        log_error("Failed to resolve user %s.", user);
-                        return -ESRCH;
-                }
-
-                log_error_errno(errno, "Failed to read from getent: %m");
-                return -errno;
+        r = read_line(f, LONG_LINE_MAX, &line);
+        if (r == 0) {
+                log_error("Failed to resolve user %s.", user);
+                return -ESRCH;
         }
+        if (r < 0)
+                return log_error_errno(r, "Failed to read from getent: %m");
 
-        truncate_nl(line);
-
-        wait_for_terminate_and_warn("getent initgroups", pid, true);
+        (void) wait_for_terminate_and_check("getent initgroups", pid, WAIT_LOG);
 
         /* Skip over the username and subsequent separator whitespace */
         x = line;
@@ -237,17 +218,15 @@ int change_uid_gid(const char *user, char **_home) {
                         return log_oom();
 
                 r = parse_uid(c, &uids[n_uids++]);
-                if (r < 0) {
-                        log_error("Failed to parse group data from getent.");
-                        return -EIO;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse group data from getent: %m");
         }
 
         r = mkdir_parents(home, 0775);
         if (r < 0)
                 return log_error_errno(r, "Failed to make home root directory: %m");
 
-        r = mkdir_safe(home, 0755, uid, gid);
+        r = mkdir_safe(home, 0755, uid, gid, false);
         if (r < 0 && r != -EEXIST)
                 return log_error_errno(r, "Failed to make home directory: %m");
 
@@ -259,10 +238,10 @@ int change_uid_gid(const char *user, char **_home) {
                 return log_error_errno(errno, "Failed to set auxiliary groups: %m");
 
         if (setresgid(gid, gid, gid) < 0)
-                return log_error_errno(errno, "setregid() failed: %m");
+                return log_error_errno(errno, "setresgid() failed: %m");
 
         if (setresuid(uid, uid, uid) < 0)
-                return log_error_errno(errno, "setreuid() failed: %m");
+                return log_error_errno(errno, "setresuid() failed: %m");
 
         if (_home) {
                 *_home = home;