[systemd-commits] 4 commits - man/systemd-nspawn.xml src/execute.c src/nspawn.c src/service.c src/util.c src/util.h TODO

Lennart Poettering lennart at kemper.freedesktop.org
Fri Jul 1 14:54:23 PDT 2011


 TODO                   |    2 +
 man/systemd-nspawn.xml |   13 +++++++++
 src/execute.c          |   46 --------------------------------
 src/nspawn.c           |   70 ++++++++++++++++++++++++++++++++++++++++++++-----
 src/service.c          |    3 ++
 src/util.c             |   46 ++++++++++++++++++++++++++++++++
 src/util.h             |    2 +
 7 files changed, 130 insertions(+), 52 deletions(-)

New commits:
commit b1bc08e599ae7760c7bcb29923ef5e1f92be2af7
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jul 1 23:53:44 2011 +0200

    manager: don't even think of enumerating sysv services in user instances

diff --git a/src/service.c b/src/service.c
index 4ee7900..165655e 100644
--- a/src/service.c
+++ b/src/service.c
@@ -2977,6 +2977,9 @@ static int service_enumerate(Manager *m) {
 
         assert(m);
 
+        if (m->running_as != MANAGER_SYSTEM)
+                return 0;
+
         zero(runlevel_services);
 
         STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path)

commit 5c94603d4c011d35026251994d77a0bf2e56c593
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jul 1 23:53:14 2011 +0200

    nspawn: better use setresuid() instead of setreuid()

diff --git a/TODO b/TODO
index 5901a90..92c90ee 100644
--- a/TODO
+++ b/TODO
@@ -77,6 +77,8 @@ Features:
   controllers together in order to guarantee atomic creation/addition
   of cgroups
 
+* don't enter "exited" mode for sysv services with pid file
+
 * avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services
 
 * cgroup_notify_empty(): recursively check groups up the tree, too
diff --git a/src/nspawn.c b/src/nspawn.c
index bead9ee..50d7c2e 100644
--- a/src/nspawn.c
+++ b/src/nspawn.c
@@ -797,12 +797,12 @@ int main(int argc, char *argv[]) {
                                 goto child_fail;
                         }
 
-                        if (setregid(gid, gid) < 0) {
+                        if (setresgid(gid, gid, gid) < 0) {
                                 log_error("setregid() failed: %m");
                                 goto child_fail;
                         }
 
-                        if (setreuid(uid, uid) < 0) {
+                        if (setresuid(uid, uid, uid) < 0) {
                                 log_error("setreuid() failed: %m");
                                 goto child_fail;
                         }
@@ -811,7 +811,7 @@ int main(int argc, char *argv[]) {
                 if ((asprintf((char**)(envp + 2), "HOME=%s", home? home: "/root") < 0) ||
                     (asprintf((char**)(envp + 3), "USER=%s", arg_user? arg_user : "root") < 0) ||
                     (asprintf((char**)(envp + 4), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) {
-                    log_error("environment setup failed: %m");
+                    log_error("Out of memory");
                     goto child_fail;
                 }
 
@@ -821,7 +821,7 @@ int main(int argc, char *argv[]) {
                 if (argc > optind)
                         execvpe(argv[optind], argv + optind, (char**) envp);
                 else {
-                        chdir(home? home : "/root");
+                        chdir(home ? home : "/root");
                         execle("/bin/bash", "-bash", NULL, (char**) envp);
                 }
 

commit 687d0825a4636b1841dc0c01fbcbf3160dddab74
Author: Michal Vyskocil <mvyskocil at suse.cz>
Date:   Wed Jun 29 14:22:46 2011 +0200

    nspawn: spawn shell under specified --user
    
    Add -u/--user option, which changes the effective and real user and
    group id to the new value. The user must exists in the chroot, otherwise
    it will fail. Both username and user id are accepted. The user home is
    created as well.
    
    It also setup HOME, USER, LOGNAME and SHELL variables .

diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index e1b33f7..03c39fc 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -139,6 +139,19 @@
                                 used.</para></listitem>
                         </varlistentry>
 
+                        <varlistentry>
+                                <term><option>--user=</option></term>
+                                <term><option>--u</option></term>
+
+                                <listitem><para>Run the command
+                                under specified user, create home
+                                directory and cd into it. As rest
+                                of systemd-nspawn, this is not
+                                the security feature and limits
+                                against accidental changes only.
+                                </para></listitem>
+                        </varlistentry>
+
                 </variablelist>
 
         </refsect1>
diff --git a/src/nspawn.c b/src/nspawn.c
index 1ade6e2..bead9ee 100644
--- a/src/nspawn.c
+++ b/src/nspawn.c
@@ -36,6 +36,7 @@
 #include <sys/epoll.h>
 #include <termios.h>
 #include <sys/signalfd.h>
+#include <grp.h>
 
 #include "log.h"
 #include "util.h"
@@ -45,13 +46,15 @@
 #include "strv.h"
 
 static char *arg_directory = NULL;
+static char *arg_user = NULL;
 
 static int help(void) {
 
         printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
                "Spawn a minimal namespace container for debugging, testing and building.\n\n"
                "  -h --help            Show this help\n"
-               "  -D --directory=NAME  Root directory for the container\n",
+               "  -D --directory=NAME  Root directory for the container\n"
+               "  -u --user=USER       Run the command under specified user or uid\n",
                program_invocation_short_name);
 
         return 0;
@@ -62,6 +65,7 @@ static int parse_argv(int argc, char *argv[]) {
         static const struct option options[] = {
                 { "help",      no_argument,       NULL, 'h' },
                 { "directory", required_argument, NULL, 'D' },
+                { "user",      optional_argument, NULL, 'u' },
                 { NULL,        0,                 NULL, 0   }
         };
 
@@ -70,7 +74,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hD:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hD:u:", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -87,6 +91,15 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case 'u':
+                        free(arg_user);
+                        if (!(arg_user = strdup(optarg))) {
+                                log_error("Failed to duplicate user name.");
+                                return -ENOMEM;
+                        }
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -693,14 +706,19 @@ int main(int argc, char *argv[]) {
                 /* child */
 
                 const char *hn;
+                const char *home = NULL;
+                uid_t uid = (uid_t) -1;
+                gid_t gid = (gid_t) -1;
                 const char *envp[] = {
-                        "HOME=/root",
                         "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
-                        NULL,
+                        NULL, /* TERM */
+                        NULL, /* HOME */
+                        NULL, /* USER */
+                        NULL, /* LOGNAME */
                         NULL
                 };
 
-                envp[2] = strv_find_prefix(environ, "TERM=");
+                envp[1] = strv_find_prefix(environ, "TERM=");
 
                 close_nointr_nofail(master);
 
@@ -757,13 +775,53 @@ int main(int argc, char *argv[]) {
                 if (drop_capabilities() < 0)
                         goto child_fail;
 
+                if (arg_user) {
+
+                        if (get_user_creds((const char**)&arg_user, &uid, &gid, &home) < 0) {
+                                log_error("get_user_creds() failed: %m");
+                                goto child_fail;
+                        }
+
+                        if (mkdir_parents(home, 0775) < 0) {
+                                log_error("mkdir_parents() failed: %m");
+                                goto child_fail;
+                        }
+
+                        if (safe_mkdir(home, 0775, uid, gid) < 0) {
+                                log_error("safe_mkdir() failed: %m");
+                                goto child_fail;
+                        }
+
+                        if (initgroups((const char*)arg_user, gid) < 0) {
+                                log_error("initgroups() failed: %m");
+                                goto child_fail;
+                        }
+
+                        if (setregid(gid, gid) < 0) {
+                                log_error("setregid() failed: %m");
+                                goto child_fail;
+                        }
+
+                        if (setreuid(uid, uid) < 0) {
+                                log_error("setreuid() failed: %m");
+                                goto child_fail;
+                        }
+                }
+
+                if ((asprintf((char**)(envp + 2), "HOME=%s", home? home: "/root") < 0) ||
+                    (asprintf((char**)(envp + 3), "USER=%s", arg_user? arg_user : "root") < 0) ||
+                    (asprintf((char**)(envp + 4), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) {
+                    log_error("environment setup failed: %m");
+                    goto child_fail;
+                }
+
                 if ((hn = file_name_from_path(arg_directory)))
                         sethostname(hn, strlen(hn));
 
                 if (argc > optind)
                         execvpe(argv[optind], argv + optind, (char**) envp);
                 else {
-                        chdir("/root");
+                        chdir(home? home : "/root");
                         execle("/bin/bash", "-bash", NULL, (char**) envp);
                 }
 

commit 1cccf435694675ca1584811179784fc2292e351b
Author: Michal Vyskocil <mvyskocil at suse.cz>
Date:   Fri Jul 1 23:49:56 2011 +0200

    nspawn: Move the get_user_creds from execute.c to utils.c for later usage in nspawn.c.

diff --git a/src/execute.c b/src/execute.c
index 9c390c0..92f4eaf 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -579,52 +579,6 @@ static int get_group_creds(const char *groupname, gid_t *gid) {
         return 0;
 }
 
-static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
-        struct passwd *p;
-        unsigned long lu;
-
-        assert(username);
-        assert(*username);
-        assert(uid);
-        assert(gid);
-        assert(home);
-
-        /* We enforce some special rules for uid=0: in order to avoid
-         * NSS lookups for root we hardcode its data. */
-
-        if (streq(*username, "root") || streq(*username, "0")) {
-                *username = "root";
-                *uid = 0;
-                *gid = 0;
-                *home = "/root";
-                return 0;
-        }
-
-        if (safe_atolu(*username, &lu) >= 0) {
-                errno = 0;
-                p = getpwuid((uid_t) lu);
-
-                /* If there are multiple users with the same id, make
-                 * sure to leave $USER to the configured value instead
-                 * of the first occurrence in the database. However if
-                 * the uid was configured by a numeric uid, then let's
-                 * pick the real username from /etc/passwd. */
-                if (*username && p)
-                        *username = p->pw_name;
-        } else {
-                errno = 0;
-                p = getpwnam(*username);
-        }
-
-        if (!p)
-                return errno != 0 ? -errno : -ESRCH;
-
-        *uid = p->pw_uid;
-        *gid = p->pw_gid;
-        *home = p->pw_dir;
-        return 0;
-}
-
 static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
         bool keep_groups = false;
         int r;
diff --git a/src/util.c b/src/util.c
index 270c7da..f75df7b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -5188,6 +5188,52 @@ int socket_from_display(const char *display, char **path) {
         return 0;
 }
 
+int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
+        struct passwd *p;
+        unsigned long lu;
+
+        assert(username);
+        assert(*username);
+        assert(uid);
+        assert(gid);
+        assert(home);
+
+        /* We enforce some special rules for uid=0: in order to avoid
+         * NSS lookups for root we hardcode its data. */
+
+        if (streq(*username, "root") || streq(*username, "0")) {
+                *username = "root";
+                *uid = 0;
+                *gid = 0;
+                *home = "/root";
+                return 0;
+        }
+
+        if (safe_atolu(*username, &lu) >= 0) {
+                errno = 0;
+                p = getpwuid((uid_t) lu);
+
+                /* If there are multiple users with the same id, make
+                 * sure to leave $USER to the configured value instead
+                 * of the first occurrence in the database. However if
+                 * the uid was configured by a numeric uid, then let's
+                 * pick the real username from /etc/passwd. */
+                if (p)
+                        *username = p->pw_name;
+        } else {
+                errno = 0;
+                p = getpwnam(*username);
+        }
+
+        if (!p)
+                return errno != 0 ? -errno : -ESRCH;
+
+        *uid = p->pw_uid;
+        *gid = p->pw_gid;
+        *home = p->pw_dir;
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/util.h b/src/util.h
index 083da2a..411efae 100644
--- a/src/util.h
+++ b/src/util.h
@@ -445,6 +445,8 @@ int audit_session_from_pid(pid_t pid, uint32_t *id);
 bool display_is_local(const char *display);
 int socket_from_display(const char *display, char **path);
 
+int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home);
+
 #define NULSTR_FOREACH(i, l)                                    \
         for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
 



More information about the systemd-commits mailing list