]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/machine/machined-dbus.c
machined: always look for leader PID first
[thirdparty/systemd.git] / src / machine / machined-dbus.c
index adba8122f3a37b5bb28747b9c7410584d2c3f0e8..93514986f32ad3c97c16ad29dc1cf5d5aaafdc5e 100644 (file)
 #include <unistd.h>
 
 #include "sd-id128.h"
+#include "strv.h"
 #include "path-util.h"
 #include "unit-name.h"
 #include "bus-util.h"
 #include "bus-common-errors.h"
 #include "cgroup-util.h"
 #include "btrfs-util.h"
+#include "formats-util.h"
+#include "process-util.h"
 #include "machine-image.h"
 #include "machine-pool.h"
 #include "image-dbus.h"
@@ -76,7 +79,7 @@ static int property_get_pool_usage(
                 BtrfsQuotaInfo q;
 
                 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
-                        usage = q.referred;
+                        usage = q.referenced;
         }
 
         if (stat("/var/lib/machines.raw", &st) >= 0) {
@@ -112,7 +115,7 @@ static int property_get_pool_limit(
                 BtrfsQuotaInfo q;
 
                 if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
-                        size = q.referred_max;
+                        size = q.referenced_max;
         }
 
         if (stat("/var/lib/machines.raw", &st) >= 0) {
@@ -123,14 +126,13 @@ static int property_get_pool_limit(
         return sd_bus_message_append(reply, "t", size);
 }
 
-static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -149,13 +151,12 @@ static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userda
         return sd_bus_reply_method_return(message, "o", p);
 }
 
-static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
         Manager *m = userdata;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -176,14 +177,13 @@ static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata
         return sd_bus_reply_method_return(message, "o", p);
 }
 
-static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
         Manager *m = userdata;
         Machine *machine = NULL;
         pid_t pid;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -218,14 +218,13 @@ static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void
         return sd_bus_reply_method_return(message, "o", p);
 }
 
-static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         Manager *m = userdata;
         Machine *machine;
         Iterator i;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -257,7 +256,7 @@ static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *user
         if (r < 0)
                 return sd_bus_error_set_errno(error, r);
 
-        return sd_bus_send(bus, reply, NULL);
+        return sd_bus_send(NULL, reply, NULL);
 }
 
 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
@@ -385,11 +384,14 @@ fail:
         return r;
 }
 
-static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
+static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
         Manager *manager = userdata;
         Machine *m = NULL;
         int r;
 
+        assert(message);
+        assert(manager);
+
         r = method_create_or_register_machine(manager, message, read_network, &m, error);
         if (r < 0)
                 return r;
@@ -410,20 +412,23 @@ fail:
         return r;
 }
 
-static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_create_machine_internal(bus, message, true, userdata, error);
+static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_create_machine_internal(message, true, userdata, error);
 }
 
-static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_create_machine_internal(bus, message, false, userdata, error);
+static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_create_machine_internal(message, false, userdata, error);
 }
 
-static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
+static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
         Manager *manager = userdata;
         _cleanup_free_ char *p = NULL;
         Machine *m = NULL;
         int r;
 
+        assert(message);
+        assert(manager);
+
         r = method_create_or_register_machine(manager, message, read_network, &m, error);
         if (r < 0)
                 return r;
@@ -451,21 +456,20 @@ fail:
         return r;
 }
 
-static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_register_machine_internal(bus, message, true, userdata, error);
+static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_register_machine_internal(message, true, userdata, error);
 }
 
-static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_register_machine_internal(bus, message, false, userdata, error);
+static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return method_register_machine_internal(message, false, userdata, error);
 }
 
-static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -477,16 +481,15 @@ static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_terminate(bus, message, machine, error);
+        return bus_machine_method_terminate(message, machine, error);
 }
 
-static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -498,16 +501,15 @@ static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userd
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_kill(bus, message, machine, error);
+        return bus_machine_method_kill(message, machine, error);
 }
 
-static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -519,16 +521,15 @@ static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, vo
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_get_addresses(bus, message, machine, error);
+        return bus_machine_method_get_addresses(message, machine, error);
 }
 
-static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -540,10 +541,10 @@ static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, v
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_get_os_release(bus, message, machine, error);
+        return bus_machine_method_get_os_release(message, machine, error);
 }
 
-static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
         Manager *m = userdata;
@@ -551,7 +552,6 @@ static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userda
         Iterator i;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -594,16 +594,15 @@ static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userda
         if (r < 0)
                 return r;
 
-        return sd_bus_send(bus, reply, NULL);
+        return sd_bus_send(NULL, reply, NULL);
 }
 
-static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -615,16 +614,15 @@ static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *u
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_open_pty(bus, message, machine, error);
+        return bus_machine_method_open_pty(message, machine, error);
 }
 
-static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -636,16 +634,16 @@ static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_open_login(bus, message, machine, error);
+        return bus_machine_method_open_login(message, machine, error);
 }
 
-static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_open_machine_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
+
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -657,16 +655,35 @@ static int method_bind_mount_machine(sd_bus *bus, sd_bus_message *message, void
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_bind_mount(bus, message, machine, error);
+        return bus_machine_method_open_shell(message, machine, error);
 }
 
-static int method_copy_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        Machine *machine;
+        const char *name;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return r;
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        return bus_machine_method_bind_mount(message, machine, error);
+}
+
+static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -678,15 +695,14 @@ static int method_copy_machine(sd_bus *bus, sd_bus_message *message, void *userd
         if (!machine)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
 
-        return bus_machine_method_copy(bus, message, machine, error);
+        return bus_machine_method_copy(message, machine, error);
 }
 
-static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image* i = NULL;
         const char *name;
         int r;
 
-        assert(bus);
         assert(message);
 
         r = sd_bus_message_read(message, "s", &name);
@@ -703,15 +719,14 @@ static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userd
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
 
         i->userdata = userdata;
-        return bus_image_method_remove(bus, message, i, error);
+        return bus_image_method_remove(message, i, error);
 }
 
-static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image* i = NULL;
         const char *old_name;
         int r;
 
-        assert(bus);
         assert(message);
 
         r = sd_bus_message_read(message, "s", &old_name);
@@ -728,15 +743,16 @@ static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userd
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
 
         i->userdata = userdata;
-        return bus_image_method_rename(bus, message, i, error);
+        return bus_image_method_rename(message, i, error);
 }
 
-static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image *i = NULL;
         const char *old_name;
         int r;
 
-        assert(bus);
+        assert(message);
+
         r = sd_bus_message_read(message, "s", &old_name);
         if (r < 0)
                 return r;
@@ -751,15 +767,16 @@ static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userda
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
 
         i->userdata = userdata;
-        return bus_image_method_clone(bus, message, i, error);
+        return bus_image_method_clone(message, i, error);
 }
 
-static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image *i = NULL;
         const char *name;
         int r;
 
-        assert(bus);
+        assert(message);
+
         r = sd_bus_message_read(message, "s", &name);
         if (r < 0)
                 return r;
@@ -774,15 +791,16 @@ static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, voi
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
 
         i->userdata = userdata;
-        return bus_image_method_mark_read_only(bus, message, i, error);
+        return bus_image_method_mark_read_only(message, i, error);
 }
 
-static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         uint64_t limit;
         int r;
 
-        assert(bus);
+        assert(message);
+
         r = sd_bus_message_read(message, "t", &limit);
         if (r < 0)
                 return r;
@@ -820,12 +838,13 @@ static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *use
         return sd_bus_reply_method_return(message, NULL);
 }
 
-static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image *i = NULL;
         const char *name;
         int r;
 
-        assert(bus);
+        assert(message);
+
         r = sd_bus_message_read(message, "s", &name);
         if (r < 0)
                 return r;
@@ -840,7 +859,231 @@ static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *us
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
 
         i->userdata = userdata;
-        return bus_image_method_set_limit(bus, message, i, error);
+        return bus_image_method_set_limit(message, i, error);
+}
+
+static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Manager *m = userdata;
+        const char *name, *p;
+        Machine *machine;
+        uint32_t uid;
+        int r;
+
+        r = sd_bus_message_read(message, "su", &name, &uid);
+        if (r < 0)
+                return r;
+
+        if (UID_IS_INVALID(uid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        p = procfs_file_alloca(machine->leader, "uid_map");
+        f = fopen(p, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                uid_t uid_base, uid_shift, uid_range, converted;
+                int k;
+
+                errno = 0;
+                k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+                if (k < 0 && feof(f))
+                        break;
+                if (k != 3) {
+                        if (ferror(f) && errno != 0)
+                                return -errno;
+
+                        return -EIO;
+                }
+
+                if (uid < uid_base || uid >= uid_base + uid_range)
+                        continue;
+
+                converted = uid - uid_base + uid_shift;
+                if (UID_IS_INVALID(converted))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+                return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
+}
+
+static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        Machine *machine;
+        uid_t uid;
+        Iterator i;
+        int r;
+
+        r = sd_bus_message_read(message, "u", &uid);
+        if (r < 0)
+                return r;
+        if (UID_IS_INVALID(uid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+        if (uid < 0x10000)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
+
+        HASHMAP_FOREACH(machine, m->machines, i) {
+                _cleanup_fclose_ FILE *f = NULL;
+                char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+                xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
+                f = fopen(p, "re");
+                if (!f) {
+                        log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+                        continue;
+                }
+
+                for (;;) {
+                        _cleanup_free_ char *o = NULL;
+                        uid_t uid_base, uid_shift, uid_range, converted;
+                        int k;
+
+                        errno = 0;
+                        k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
+                        if (k < 0 && feof(f))
+                                break;
+                        if (k != 3) {
+                                if (ferror(f) && errno != 0)
+                                        return -errno;
+
+                                return -EIO;
+                        }
+
+                        if (uid < uid_shift || uid >= uid_shift + uid_range)
+                                continue;
+
+                        converted = (uid - uid_shift + uid_base);
+                        if (UID_IS_INVALID(converted))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
+
+                        o = machine_bus_path(machine);
+                        if (!o)
+                                return -ENOMEM;
+
+                        return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+                }
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
+}
+
+static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Manager *m = groupdata;
+        const char *name, *p;
+        Machine *machine;
+        uint32_t gid;
+        int r;
+
+        r = sd_bus_message_read(message, "su", &name, &gid);
+        if (r < 0)
+                return r;
+
+        if (GID_IS_INVALID(gid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        p = procfs_file_alloca(machine->leader, "gid_map");
+        f = fopen(p, "re");
+        if (!f)
+                return -errno;
+
+        for (;;) {
+                gid_t gid_base, gid_shift, gid_range, converted;
+                int k;
+
+                errno = 0;
+                k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+                if (k < 0 && feof(f))
+                        break;
+                if (k != 3) {
+                        if (ferror(f) && errno != 0)
+                                return -errno;
+
+                        return -EIO;
+                }
+
+                if (gid < gid_base || gid >= gid_base + gid_range)
+                        continue;
+
+                converted = gid - gid_base + gid_shift;
+                if (GID_IS_INVALID(converted))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+                return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
+}
+
+static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
+        Manager *m = groupdata;
+        Machine *machine;
+        gid_t gid;
+        Iterator i;
+        int r;
+
+        r = sd_bus_message_read(message, "u", &gid);
+        if (r < 0)
+                return r;
+        if (GID_IS_INVALID(gid))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+        if (gid < 0x10000)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
+
+        HASHMAP_FOREACH(machine, m->machines, i) {
+                _cleanup_fclose_ FILE *f = NULL;
+                char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
+
+                xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
+                f = fopen(p, "re");
+                if (!f) {
+                        log_warning_errno(errno, "Failed top open %s, ignoring,", p);
+                        continue;
+                }
+
+                for (;;) {
+                        _cleanup_free_ char *o = NULL;
+                        gid_t gid_base, gid_shift, gid_range, converted;
+                        int k;
+
+                        errno = 0;
+                        k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
+                        if (k < 0 && feof(f))
+                                break;
+                        if (k != 3) {
+                                if (ferror(f) && errno != 0)
+                                        return -errno;
+
+                                return -EIO;
+                        }
+
+                        if (gid < gid_shift || gid >= gid_shift + gid_range)
+                                continue;
+
+                        converted = (gid - gid_shift + gid_base);
+                        if (GID_IS_INVALID(converted))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
+
+                        o = machine_bus_path(machine);
+                        if (!o)
+                                return -ENOMEM;
+
+                        return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
+                }
+        }
+
+        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
 }
 
 const sd_bus_vtable manager_vtable[] = {
@@ -863,6 +1106,7 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
         SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("OpenMachineShell", "sssasas", "hs", method_open_machine_shell, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -872,26 +1116,29 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_SIGNAL("MachineNew", "so", 0),
         SD_BUS_SIGNAL("MachineRemoved", "so", 0),
         SD_BUS_VTABLE_END
 };
 
-int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         const char *path, *result, *unit;
         Manager *m = userdata;
         Machine *machine;
         uint32_t id;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
         r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
         if (r < 0) {
                 bus_log_parse_error(r);
-                return r;
+                return 0;
         }
 
         machine = hashmap_get(m->machine_units, unit);
@@ -899,8 +1146,7 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
                 return 0;
 
         if (streq_ptr(path, machine->scope_job)) {
-                free(machine->scope_job);
-                machine->scope_job = NULL;
+                machine->scope_job = mfree(machine->scope_job);
 
                 if (machine->started) {
                         if (streq(result, "done"))
@@ -912,22 +1158,22 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
 
                                 machine_send_create_reply(machine, &e);
                         }
-                } else
-                        machine_save(machine);
+                }
+
+                machine_save(machine);
         }
 
         machine_add_to_gc_queue(machine);
         return 0;
 }
 
-int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *unit = NULL;
+        const char *path;
         Manager *m = userdata;
         Machine *machine;
-        const char *path;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
@@ -938,51 +1184,55 @@ int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdat
         r = unit_name_from_dbus_path(path, &unit);
         if (r == -EINVAL) /* not for a unit */
                 return 0;
-        if (r < 0)
-                return r;
+        if (r < 0){
+                log_oom();
+                return 0;
+        }
 
         machine = hashmap_get(m->machine_units, unit);
-        if (machine)
-                machine_add_to_gc_queue(machine);
+        if (!machine)
+                return 0;
 
+        machine_add_to_gc_queue(machine);
         return 0;
 }
 
-int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         const char *path, *unit;
         Manager *m = userdata;
         Machine *machine;
         int r;
 
-        assert(bus);
         assert(message);
         assert(m);
 
         r = sd_bus_message_read(message, "so", &unit, &path);
         if (r < 0) {
                 bus_log_parse_error(r);
-                return r;
+                return 0;
         }
 
         machine = hashmap_get(m->machine_units, unit);
-        if (machine)
-                machine_add_to_gc_queue(machine);
+        if (!machine)
+                return 0;
 
+        machine_add_to_gc_queue(machine);
         return 0;
 }
 
-int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         Machine *machine;
         Iterator i;
         int b, r;
 
-        assert(bus);
+        assert(message);
+        assert(m);
 
         r = sd_bus_message_read(message, "b", &b);
         if (r < 0) {
                 bus_log_parse_error(r);
-                return r;
+                return 0;
         }
         if (b)
                 return 0;
@@ -1189,7 +1439,7 @@ int manager_unit_is_active(Manager *manager, const char *unit) {
         if (r < 0)
                 return -EINVAL;
 
-        return !streq(state, "inactive") && !streq(state, "failed");
+        return !STR_IN_SET(state, "inactive", "failed");
 }
 
 int manager_job_is_active(Manager *manager, const char *path) {
@@ -1227,7 +1477,6 @@ int manager_job_is_active(Manager *manager, const char *path) {
 }
 
 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
-        _cleanup_free_ char *unit = NULL;
         Machine *mm;
         int r;
 
@@ -1235,12 +1484,14 @@ int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
         assert(pid >= 1);
         assert(machine);
 
-        r = cg_pid_get_unit(pid, &unit);
-        if (r < 0)
-                mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
-        else
-                mm = hashmap_get(m->machine_units, unit);
+        mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
+        if (!mm) {
+                _cleanup_free_ char *unit = NULL;
 
+                r = cg_pid_get_unit(pid, &unit);
+                if (r >= 0)
+                        mm = hashmap_get(m->machine_units, unit);
+        }
         if (!mm)
                 return 0;