summaryrefslogtreecommitdiff
path: root/src/nspawn/nspawn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nspawn/nspawn.c')
-rw-r--r--src/nspawn/nspawn.c244
1 files changed, 2 insertions, 242 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index fcabe24601..cdb699eaaa 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -103,6 +103,7 @@
#include "nspawn-expose-ports.h"
#include "nspawn-cgroup.h"
#include "nspawn-register.h"
+#include "nspawn-setuid.h"
typedef enum ContainerStatus {
CONTAINER_TERMINATED,
@@ -2246,247 +2247,6 @@ static void loop_remove(int nr, int *image_fd) {
log_debug_errno(errno, "Failed to remove loop %d: %m", nr);
}
-static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
- int pipe_fds[2];
- pid_t pid;
-
- assert(database);
- assert(key);
- assert(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;
- 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]);
-
- nullfd = open("/dev/null", O_RDWR);
- if (nullfd < 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);
- execle("/bin/getent", "getent", database, key, NULL, &empty_env);
- _exit(EXIT_FAILURE);
- }
-
- pipe_fds[1] = safe_close(pipe_fds[1]);
-
- *rpid = pid;
-
- return pipe_fds[0];
-}
-
-static int change_uid_gid(char **_home) {
- char line[LINE_MAX], *x, *u, *g, *h;
- const char *word, *state;
- _cleanup_free_ uid_t *uids = NULL;
- _cleanup_free_ char *home = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_close_ int fd = -1;
- unsigned n_uids = 0;
- size_t sz = 0, l;
- uid_t uid;
- gid_t gid;
- pid_t pid;
- int r;
-
- assert(_home);
-
- if (!arg_user || streq(arg_user, "root") || streq(arg_user, "0")) {
- /* Reset everything fully to 0, just in case */
-
- r = reset_uid_gid();
- if (r < 0)
- return log_error_errno(r, "Failed to become root: %m");
-
- *_home = NULL;
- return 0;
- }
-
- /* First, get user credentials */
- fd = spawn_getent("passwd", arg_user, &pid);
- if (fd < 0)
- return fd;
-
- f = fdopen(fd, "r");
- if (!f)
- return log_oom();
- fd = -1;
-
- if (!fgets(line, sizeof(line), f)) {
-
- if (!ferror(f)) {
- log_error("Failed to resolve user %s.", arg_user);
- return -ESRCH;
- }
-
- log_error_errno(errno, "Failed to read from getent: %m");
- return -errno;
- }
-
- truncate_nl(line);
-
- wait_for_terminate_and_warn("getent passwd", pid, true);
-
- x = strchr(line, ':');
- if (!x) {
- log_error("/etc/passwd entry has invalid user field.");
- return -EIO;
- }
-
- u = strchr(x+1, ':');
- if (!u) {
- log_error("/etc/passwd entry has invalid password field.");
- return -EIO;
- }
-
- u++;
- g = strchr(u, ':');
- if (!g) {
- log_error("/etc/passwd entry has invalid UID field.");
- return -EIO;
- }
-
- *g = 0;
- g++;
- x = strchr(g, ':');
- if (!x) {
- log_error("/etc/passwd entry has invalid GID field.");
- return -EIO;
- }
-
- *x = 0;
- h = strchr(x+1, ':');
- if (!h) {
- log_error("/etc/passwd entry has invalid GECOS field.");
- return -EIO;
- }
-
- h++;
- x = strchr(h, ':');
- if (!x) {
- log_error("/etc/passwd entry has invalid home directory field.");
- return -EIO;
- }
-
- *x = 0;
-
- r = parse_uid(u, &uid);
- if (r < 0) {
- log_error("Failed to parse UID of user.");
- return -EIO;
- }
-
- r = parse_gid(g, &gid);
- if (r < 0) {
- log_error("Failed to parse GID of user.");
- return -EIO;
- }
-
- home = strdup(h);
- if (!home)
- return log_oom();
-
- /* Second, get group memberships */
- fd = spawn_getent("initgroups", arg_user, &pid);
- if (fd < 0)
- return fd;
-
- fclose(f);
- f = fdopen(fd, "r");
- if (!f)
- return log_oom();
- fd = -1;
-
- if (!fgets(line, sizeof(line), f)) {
- if (!ferror(f)) {
- log_error("Failed to resolve user %s.", arg_user);
- return -ESRCH;
- }
-
- log_error_errno(errno, "Failed to read from getent: %m");
- return -errno;
- }
-
- truncate_nl(line);
-
- wait_for_terminate_and_warn("getent initgroups", pid, true);
-
- /* Skip over the username and subsequent separator whitespace */
- x = line;
- x += strcspn(x, WHITESPACE);
- x += strspn(x, WHITESPACE);
-
- FOREACH_WORD(word, l, x, state) {
- char c[l+1];
-
- memcpy(c, word, l);
- c[l] = 0;
-
- if (!GREEDY_REALLOC(uids, sz, n_uids+1))
- return log_oom();
-
- r = parse_uid(c, &uids[n_uids++]);
- if (r < 0) {
- log_error("Failed to parse group data from getent.");
- return -EIO;
- }
- }
-
- 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);
- if (r < 0 && r != -EEXIST)
- return log_error_errno(r, "Failed to make home directory: %m");
-
- (void) fchown(STDIN_FILENO, uid, gid);
- (void) fchown(STDOUT_FILENO, uid, gid);
- (void) fchown(STDERR_FILENO, uid, gid);
-
- if (setgroups(n_uids, uids) < 0)
- 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");
-
- if (setresuid(uid, uid, uid) < 0)
- return log_error_errno(errno, "setreuid() failed: %m");
-
- if (_home) {
- *_home = home;
- home = NULL;
- }
-
- return 0;
-}
-
/*
* Return values:
* < 0 : wait_for_terminate() failed to get the state of the
@@ -2787,7 +2547,7 @@ static int inner_child(
return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
#endif
- r = change_uid_gid(&home);
+ r = change_uid_gid(arg_user, &home);
if (r < 0)
return r;