]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machine: introduce io.systemd.Machine.{MapFrom, MapTo} methods
authorIvan Kruglov <mail@ikruglov.com>
Thu, 7 Nov 2024 09:39:41 +0000 (10:39 +0100)
committerIvan Kruglov <mail@ikruglov.com>
Tue, 17 Dec 2024 10:25:24 +0000 (11:25 +0100)
src/machine/machine-varlink.c
src/machine/machine-varlink.h
src/machine/machined-varlink.c
src/shared/varlink-io.systemd.Machine.c

index 8ad3c8746919ed31c5c53e73f552b3622a6affbc..1d2814b26a3cdffef73cdb72b4163435bf2b7c0c 100644 (file)
@@ -570,3 +570,161 @@ int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met
 
         return sd_varlink_reply(link, v);
 }
+
+typedef struct MachineMapParameters {
+        const char *name;
+        PidRef pidref;
+        uid_t uid;
+        gid_t gid;
+} MachineMapParameters;
+
+static void machine_map_paramaters_done(MachineMapParameters *p) {
+        assert(p);
+        pidref_done(&p->pidref);
+}
+
+int vl_method_map_from(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+        static const sd_json_dispatch_field dispatch_table[] = {
+                VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(MachineOpenParameters),
+                { "uid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(MachineMapParameters, uid), 0 },
+                { "gid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(MachineMapParameters, gid), 0 },
+                {}
+        };
+
+        Manager *manager = ASSERT_PTR(userdata);
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        _cleanup_(machine_map_paramaters_done) MachineMapParameters p = {
+                .pidref = PIDREF_NULL,
+                .uid = UID_INVALID,
+                .gid = GID_INVALID,
+        };
+        uid_t converted_uid = UID_INVALID;
+        gid_t converted_gid = GID_INVALID;
+        Machine *machine;
+        int r;
+
+        assert(link);
+        assert(parameters);
+
+        r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
+                return r;
+
+        if (p.uid != UID_INVALID && !uid_is_valid(p.uid))
+                return sd_varlink_error_invalid_parameter_name(link, "uid");
+
+        if (p.gid != GID_INVALID && !gid_is_valid(p.gid))
+                return sd_varlink_error_invalid_parameter_name(link, "gid");
+
+        r = lookup_machine_by_name_or_pidref(link, manager, p.name, &p.pidref, &machine);
+        if (r == -ESRCH)
+                return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
+        if (r < 0)
+                return r;
+
+        if (machine->class != MACHINE_CONTAINER)
+                return sd_varlink_error(link, "io.systemd.Machine.NotSupported", NULL);
+
+        if (p.uid != UID_INVALID) {
+                r = machine_translate_uid(machine, p.uid, &converted_uid);
+                if (r == -ESRCH)
+                        return sd_varlink_error(link, "io.systemd.Machine.NoSuchUser", NULL);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to map uid=%u for machine '%s': %m", p.uid, machine->name);
+        }
+
+        if (p.gid != UID_INVALID) {
+                r = machine_translate_gid(machine, p.gid, &converted_gid);
+                if (r == -ESRCH)
+                        return sd_varlink_error(link, "io.systemd.Machine.NoSuchGroup", NULL);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to map gid=%u for machine '%s': %m", p.gid, machine->name);
+        }
+
+        r = sd_json_buildo(&v,
+                           JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("uid", converted_uid, UID_INVALID),
+                           JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("gid", converted_gid, GID_INVALID));
+        if (r < 0)
+                return r;
+
+        return sd_varlink_reply(link, v);
+}
+
+int vl_method_map_to(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+        static const sd_json_dispatch_field dispatch_table[] = {
+                { "uid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(MachineMapParameters, uid), 0 },
+                { "gid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(MachineMapParameters, gid), 0 },
+                {}
+        };
+
+        Manager *manager = ASSERT_PTR(userdata);
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        _cleanup_(machine_map_paramaters_done) MachineMapParameters p = {
+                .pidref = PIDREF_NULL,
+                .uid = UID_INVALID,
+                .gid = GID_INVALID,
+        };
+        Machine *machine_by_uid = NULL, *machine_by_gid = NULL;
+        uid_t converted_uid = UID_INVALID;
+        gid_t converted_gid = GID_INVALID;
+        const char *machine_name = NULL;
+        int r;
+
+        assert(link);
+        assert(parameters);
+
+        r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
+                return r;
+
+        if (p.uid != UID_INVALID) {
+                if (!uid_is_valid(p.uid))
+                        return sd_varlink_error_invalid_parameter_name(link, "uid");
+                if (p.uid < 0x10000)
+                        return sd_varlink_error(link, "io.systemd.Machine.UserInHostRange", NULL);
+        }
+
+        if (p.gid != GID_INVALID) {
+                if (!gid_is_valid(p.gid))
+                        return sd_varlink_error_invalid_parameter_name(link, "gid");
+                if (p.gid < 0x10000)
+                        return sd_varlink_error(link, "io.systemd.Machine.GroupInHostRange", NULL);
+        }
+
+        if (p.uid != UID_INVALID) {
+                r = manager_find_machine_for_uid(manager, p.uid, &machine_by_uid, &converted_uid);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to find machine for uid=%u: %m", p.uid);
+                if (!r)
+                        return sd_varlink_error(link, "io.systemd.Machine.NoSuchUser", NULL);
+        }
+
+        if (p.gid != GID_INVALID) {
+                r = manager_find_machine_for_gid(manager, p.gid, &machine_by_gid, &converted_gid);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to find machine for gid=%u: %m", p.gid);
+                if (!r)
+                        return sd_varlink_error(link, "io.systemd.Machine.NoSuchGroup", NULL);
+        }
+
+        if (machine_by_uid && machine_by_gid && machine_by_uid != machine_by_gid) {
+                log_debug_errno(SYNTHETIC_ERRNO(ESRCH), "Mapping of UID %u and GID %u resulted in two different machines", p.uid, p.gid);
+                return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
+        }
+
+        if (machine_by_uid)
+                machine_name = machine_by_uid->name;
+        else if (machine_by_gid)
+                machine_name = machine_by_gid->name;
+        else
+                return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
+
+        r = sd_json_buildo(&v,
+                           JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("uid", converted_uid, UID_INVALID),
+                           JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("gid", converted_gid, GID_INVALID),
+                           JSON_BUILD_PAIR_STRING_NON_EMPTY("machineName", machine_name));
+        if (r < 0)
+                return r;
+
+        return sd_varlink_reply(link, v);
+}
index 380f011dbea5c98470caeba3c39468a969c08a9d..984a8d8f3ed78fb259ea379ec991b1c8fbb185c4 100644 (file)
@@ -25,3 +25,5 @@ int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters,
 int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
 int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
 int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_map_from(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_map_to(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
index 3385aa8a17838d51bd57cebcfe1daf0051e0bd9a..e0e27c4496483dc3bc3838f85f29be83ad31c97e 100644 (file)
@@ -771,6 +771,8 @@ static int manager_varlink_init_machine(Manager *m) {
                         "io.systemd.Machine.Terminate",   vl_method_terminate,
                         "io.systemd.Machine.Kill",        vl_method_kill,
                         "io.systemd.Machine.Open",        vl_method_open,
+                        "io.systemd.Machine.MapFrom",     vl_method_map_from,
+                        "io.systemd.Machine.MapTo",       vl_method_map_to,
                         "io.systemd.MachineImage.List",   vl_method_list_images,
                         "io.systemd.MachineImage.Update", vl_method_update_image,
                         "io.systemd.MachineImage.Clone",  vl_method_clone_image,
index 83a20f4f0ebd621e8d5c866f1c1d4ffd0618aa57..696d4020022572ca6e5b7e41399c0807b20e739c 100644 (file)
@@ -122,6 +122,31 @@ static SD_VARLINK_DEFINE_METHOD(
                 SD_VARLINK_FIELD_COMMENT("Path to the allocated pseudo TTY"),
                 SD_VARLINK_DEFINE_OUTPUT(ptyPath, SD_VARLINK_STRING, 0));
 
+static SD_VARLINK_DEFINE_METHOD(
+                MapFrom,
+                VARLINK_DEFINE_MACHINE_LOOKUP_AND_POLKIT_INPUT_FIELDS,
+                SD_VARLINK_FIELD_COMMENT("UID in the machine to map to host UID"),
+                SD_VARLINK_DEFINE_INPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("GID in the machine to map to host GID"),
+                SD_VARLINK_DEFINE_INPUT(gid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Mapped UID"),
+                SD_VARLINK_DEFINE_OUTPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Mapped GID"),
+                SD_VARLINK_DEFINE_OUTPUT(gid, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
+
+static SD_VARLINK_DEFINE_METHOD(
+                MapTo,
+                SD_VARLINK_FIELD_COMMENT("Host UID to map to machine UID"),
+                SD_VARLINK_DEFINE_INPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Host GID to map to machine GID"),
+                SD_VARLINK_DEFINE_INPUT(gid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Mapped UID"),
+                SD_VARLINK_DEFINE_OUTPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Mapped GID"),
+                SD_VARLINK_DEFINE_OUTPUT(gid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Machine's name which owns mapped UID/GID"),
+                SD_VARLINK_DEFINE_OUTPUT(machineName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
+
 static SD_VARLINK_DEFINE_ERROR(NoSuchMachine);
 static SD_VARLINK_DEFINE_ERROR(MachineExists);
 static SD_VARLINK_DEFINE_ERROR(NoPrivateNetworking);
@@ -130,6 +155,10 @@ static SD_VARLINK_DEFINE_ERROR(NoUIDShift);
 static SD_VARLINK_DEFINE_ERROR(NotAvailable);
 static SD_VARLINK_DEFINE_ERROR(NotSupported);
 static SD_VARLINK_DEFINE_ERROR(NoIPC);
+static SD_VARLINK_DEFINE_ERROR(NoSuchUser);
+static SD_VARLINK_DEFINE_ERROR(NoSuchGroup);
+static SD_VARLINK_DEFINE_ERROR(UserInHostRange);
+static SD_VARLINK_DEFINE_ERROR(GroupInHostRange);
 
 SD_VARLINK_DEFINE_INTERFACE(
                 io_systemd_Machine,
@@ -154,6 +183,10 @@ SD_VARLINK_DEFINE_INTERFACE(
                 &vl_type_MachineOpenMode,
                 SD_VARLINK_SYMBOL_COMMENT("Allocates a pseudo TTY in the container in various modes"),
                 &vl_method_Open,
+                SD_VARLINK_SYMBOL_COMMENT("Maps given machine's UID/GID to host's UID/GID"),
+                &vl_method_MapFrom,
+                SD_VARLINK_SYMBOL_COMMENT("Maps given host's UID/GID to a machine and corresponding UID/GID"),
+                &vl_method_MapTo,
                 SD_VARLINK_SYMBOL_COMMENT("No matching machine currently running"),
                 &vl_error_NoSuchMachine,
                 &vl_error_MachineExists,
@@ -168,4 +201,12 @@ SD_VARLINK_DEFINE_INTERFACE(
                 SD_VARLINK_SYMBOL_COMMENT("Requested operation is not supported"),
                 &vl_error_NotSupported,
                 SD_VARLINK_SYMBOL_COMMENT("There is no IPC service (such as system bus or varlink) in the container"),
-                &vl_error_NoIPC);
+                &vl_error_NoIPC,
+                SD_VARLINK_SYMBOL_COMMENT("No such user"),
+                &vl_error_NoSuchUser,
+                SD_VARLINK_SYMBOL_COMMENT("No such group"),
+                &vl_error_NoSuchGroup,
+                SD_VARLINK_SYMBOL_COMMENT("User belongs to host UID range"),
+                &vl_error_UserInHostRange,
+                SD_VARLINK_SYMBOL_COMMENT("Group belongs to host GID range"),
+                &vl_error_GroupInHostRange);