]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined: add PIDFD D-Bus variants for registering/creating machines
authorLuca Boccassi <luca.boccassi@gmail.com>
Tue, 16 Sep 2025 13:45:58 +0000 (14:45 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 24 Sep 2025 13:11:59 +0000 (14:11 +0100)
Current methods take a numeric PID, but we know that is unreliable for
the usual reasons. Add variants that take a PIDFD instead, or a
PID + PIDFDID combination for remote users.

man/org.freedesktop.machine1.xml
src/machine/machined-dbus.c
src/machine/org.freedesktop.machine1.conf
src/nspawn/nspawn-register.c

index fcabd6da2b394cb5a6c0a8cf95f4026cb1783a69..39bd96d87c5ea79942062562d698c7c2cc9c4be4 100644 (file)
@@ -63,6 +63,10 @@ node /org/freedesktop/machine1 {
                                in  ai ifindices,
                                in  a(sv) scope_properties,
                                out o path);
+      CreateMachineEx(in  s name,
+                      in  a(sv) properties,
+                      in  a(sv) scope_properties,
+                      out o path);
       RegisterMachine(in  s name,
                       in  ay id,
                       in  s service,
@@ -78,6 +82,9 @@ node /org/freedesktop/machine1 {
                                  in  s root_directory,
                                  in  ai ifindices,
                                  out o path);
+      RegisterMachineEx(in  s name,
+                        in  a(sv) properties,
+                        out o path);
       UnregisterMachine(in  s name);
       TerminateMachine(in  s id);
       KillMachine(in  s name,
@@ -216,10 +223,14 @@ node /org/freedesktop/machine1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="CreateMachineWithNetwork()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="CreateMachineEx()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="RegisterMachine()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="RegisterMachineWithNetwork()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="RegisterMachineEx()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="UnregisterMachine()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="TerminateMachine()"/>
@@ -353,6 +364,31 @@ node /org/freedesktop/machine1 {
       multiple times, one instance for each container/VM they manage, and are invoked as system
       services.</para>
 
+      <para><function>RegisterMachineEx()</function> and <function>CreateMachineEx()</function> are similar
+      to the counterparts, but take a series of key/value pairs instead of a fixed number of parameters, to
+      allow for future extensions, and take a PIDFD instead of a PID for the leader parameter. The currently
+      supported parameters are:
+      <itemizedlist>
+        <listitem><para><literal>Id</literal> (<literal>ay</literal>): the machine UUID.</para></listitem>
+        <listitem><para><literal>Service</literal> (<literal>s</literal>): the service string.</para></listitem>
+        <listitem><para><literal>Class</literal> (<literal>s</literal>): the class string.</para></listitem>
+        <listitem><para><literal>LeaderPIDFD</literal> (<literal>h</literal>): A PIDFD for the leader process of the machine.
+        This parameter is optional. If it is specified, it is preferred over the combination of
+        <literal>LeaderPID</literal>
+        and <literal>LeaderPIDFDID</literal>.</para></listitem>
+        <listitem><para><literal>LeaderPID</literal> (<literal>u</literal>): A PID for the leader process of the
+        machine. This parameter is optional. Must be specified together with
+        <literal>LeaderPIDFDID</literal>.</para></listitem>
+        <listitem><para><literal>LeaderPIDFDID</literal> (<literal>t</literal>): A PIDFDID for the leader
+        process of the machine. This parameter is optional. Must be specified together with
+        <literal>LeaderPID</literal>.</para></listitem>
+        <listitem><para><literal>RootDirectory</literal> (<literal>s</literal>): The root directory of the container. This
+        parameter is optional and for informational purposes only.</para></listitem>
+        <listitem><para><literal>NetworkInterfaces</literal> (<literal>ai</literal>): An array of network
+        interface indices, as in
+        <function>CreateMachineWithNetwork()</function>. This parameter is optional.</para></listitem>
+      </itemizedlist></para>
+
       <para><function>CreateMachineWithNetwork()</function> and
       <function>RegisterMachineWithNetwork()</function> are similar to <function>CreateMachine()</function>
       and <function>RegisterMachine()</function> but take an extra argument: an array of network interface
@@ -753,6 +789,8 @@ $ gdbus introspect --system \
       <para><varname>LeaderPIDFDId</varname>, <varname>Supervisor</varname>,
       <varname>SupervisorPIDFDId</varname>, <varname>Subgroup</varname>, and <varname>UID</varname> were added
       in version 258.</para>
+      <para><function>CreateMachineEx()</function>, and <function>RegisterMachineEx()</function> were added
+      in version 259.</para>
     </refsect2>
   </refsect1>
 
index 91e5e218698b38df2052c6cce75e250305fcf38e..7d2e3dfb62cc1905a5fa7b6727213e7851320506 100644 (file)
@@ -33,6 +33,7 @@
 #include "operation.h"
 #include "os-util.h"
 #include "path-util.h"
+#include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "unit-def.h"
@@ -226,11 +227,140 @@ static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_
         return sd_bus_message_send(reply);
 }
 
+static int machine_add_from_params(
+                Manager *manager,
+                sd_bus_message *message,
+                const char *polkit_action,
+                const char *name,
+                MachineClass c,
+                sd_id128_t id,
+                const char *service,
+                PidRef *leader_pidref,
+                PidRef *supervisor_pidref,
+                const char *root_directory,
+                const int32_t *netif,
+                size_t n_netif,
+                unsigned cid,
+                const char *ssh_address,
+                const char *ssh_private_key_path,
+                Machine **ret,
+                sd_bus_error *error) {
+
+        Machine *m;
+        int r;
+
+        assert(manager);
+        assert(message);
+        assert(name);
+        assert(ret);
+
+        if (leader_pidref->pid == 1)
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
+        if (supervisor_pidref->pid == 1)
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supervisor PID");
+
+        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
+        if (r < 0)
+                return r;
+
+        uid_t uid;
+        r = sd_bus_creds_get_euid(creds, &uid);
+        if (r < 0)
+                return r;
+
+        /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
+        if (uid != 0) {
+                r = process_is_owned_by_uid(leader_pidref, uid);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users");
+        }
+
+        const char *details[] = {
+                "name",  name,
+                "class", machine_class_to_string(c),
+                NULL
+        };
+
+        r = bus_verify_polkit_async(
+                        message,
+                        polkit_action,
+                        details,
+                        &manager->polkit_registry,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 0; /* Will call us back */
+
+        r = manager_add_machine(manager, name, &m);
+        if (r < 0)
+                return r;
+
+        m->leader = TAKE_PIDREF(*leader_pidref);
+        m->supervisor = TAKE_PIDREF(*supervisor_pidref);
+        m->class = c;
+        m->id = id;
+        m->uid = uid;
+        m->vsock_cid = cid;
+
+        if (!isempty(service)) {
+                m->service = strdup(service);
+                if (!m->service) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (!isempty(root_directory)) {
+                m->root_directory = strdup(root_directory);
+                if (!m->root_directory) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (n_netif > 0) {
+                assert_cc(sizeof(int32_t) == sizeof(int));
+                m->netif = memdup(netif, sizeof(int32_t) * n_netif);
+                if (!m->netif) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                m->n_netif = n_netif;
+        }
+
+        if (!isempty(ssh_address)) {
+                m->ssh_address = strdup(ssh_address);
+                if (!m->ssh_address) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        if (!isempty(ssh_private_key_path)) {
+                m->ssh_private_key_path = strdup(ssh_private_key_path);
+                if (!m->ssh_private_key_path) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+        }
+
+        *ret = m;
+        return 1;
+
+fail:
+        machine_add_to_gc_queue(m);
+        return r;
+}
+
 static int method_create_or_register_machine(
                 Manager *manager,
                 sd_bus_message *message,
                 const char *polkit_action,
-                bool read_network,
                 Machine **ret,
                 sd_bus_error *error) {
 
@@ -240,7 +370,6 @@ static int method_create_or_register_machine(
         MachineClass c;
         uint32_t leader;
         sd_id128_t id;
-        Machine *m;
         size_t n_netif = 0;
         int r;
 
@@ -262,7 +391,7 @@ static int method_create_or_register_machine(
         if (r < 0)
                 return r;
 
-        if (read_network) {
+        if (endswith(sd_bus_message_get_member(message), "WithNetwork")) {
                 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
                 if (r < 0)
                         return r;
@@ -312,95 +441,224 @@ static int method_create_or_register_machine(
         if (hashmap_get(manager->machines, name))
                 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
 
-        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
-        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
+        return machine_add_from_params(
+                        manager,
+                        message,
+                        polkit_action,
+                        name,
+                        c,
+                        id,
+                        service,
+                        &leader_pidref,
+                        &supervisor_pidref,
+                        root_directory,
+                        netif,
+                        n_netif,
+                        /* cid= */ 0,
+                        /* ssh_address= */ NULL,
+                        /* ssh_private_key_path= */ NULL,
+                        ret,
+                        error);
+}
+
+static int method_create_or_register_machine_ex(
+                Manager *manager,
+                sd_bus_message *message,
+                const char *polkit_action,
+                Machine **ret,
+                sd_bus_error *error) {
+
+        const char *name = NULL, *service = NULL, *class = NULL, *root_directory = NULL, *ssh_address = NULL, *ssh_private_key_path = NULL;
+        _cleanup_(pidref_done) PidRef leader_pidref = PIDREF_NULL, supervisor_pidref = PIDREF_NULL;
+        sd_id128_t id = SD_ID128_NULL;
+        const int32_t *netif = NULL;
+        size_t n_netif = 0;
+        unsigned cid = 0;
+        MachineClass c;
+        uint64_t leader_pidfdid = 0;
+        uint32_t leader_pid = 0;
+        int r, leader_pidfd = -EBADF;
+
+        assert(manager);
+        assert(message);
+        assert(ret);
+
+        r = sd_bus_message_read(message, "s", &name);
         if (r < 0)
                 return r;
+        if (!hostname_is_valid(name, 0))
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
 
-        uid_t uid;
-        r = sd_bus_creds_get_euid(creds, &uid);
+        r = sd_bus_message_enter_container(message, 'a', "(sv)");
         if (r < 0)
                 return r;
 
-        /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
-        if (uid != 0) {
-                r = process_is_owned_by_uid(&leader_pidref, uid);
+        for (;;) {
+                const char *key;
+
+                r = sd_bus_message_enter_container(message, 'r', "sv");
                 if (r < 0)
                         return r;
                 if (r == 0)
-                        return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users");
-        }
+                        break;
 
-        const char *details[] = {
-                "name",  name,
-                "class", machine_class_to_string(c),
-                NULL
-        };
+                r = sd_bus_message_read(message, "s", &key);
+                if (r < 0)
+                        return r;
 
-        r = bus_verify_polkit_async(
-                        message,
-                        polkit_action,
-                        details,
-                        &manager->polkit_registry,
-                        error);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return 0; /* Will call us back */
+                r = sd_bus_message_enter_container(message, 'v', NULL);
+                if (r < 0)
+                        return r;
 
-        r = manager_add_machine(manager, name, &m);
+                if (streq(key, "Id")) {
+                        r = bus_message_read_id128(message, &id);
+                        if (r < 0)
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
+                } else if (streq(key, "Service")) {
+                        r = sd_bus_message_read(message, "s", &service);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "Class")) {
+                        r = sd_bus_message_read(message, "s", &class);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "LeaderPID")) {
+                        r = sd_bus_message_read(message, "u", &leader_pid);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "LeaderPIDFD")) {
+                        r = sd_bus_message_read(message, "h", &leader_pidfd);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "LeaderPIDFDID")) {
+                        r = sd_bus_message_read(message, "t", &leader_pidfdid);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "RootDirectory")) {
+                        r = sd_bus_message_read(message, "s", &root_directory);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "NetworkInterfaces")) {
+                        r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
+                        if (r < 0)
+                                return r;
+
+                        n_netif /= sizeof(int32_t);
+
+                        for (size_t i = 0; i < n_netif; i++)
+                                if (netif[i] <= 0)
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
+                } else if (streq(key, "VSockCID")) {
+                        r = sd_bus_message_read(message, "u", &cid);
+                        if (r < 0)
+                                return r;
+
+                        if (!VSOCK_CID_IS_REGULAR(cid))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "JSON field 'vSockCid' is not a regular VSOCK CID.");
+                } else if (streq(key, "SSHAddress")) {
+                        r = sd_bus_message_read(message, "s", &ssh_address);
+                        if (r < 0)
+                                return r;
+                } else if (streq(key, "SSHPrivateKeyPath")) {
+                        r = sd_bus_message_read(message, "s", &ssh_private_key_path);
+                        if (r < 0)
+                                return r;
+                } else
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown property '%s'", key);
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_exit_container(message);
         if (r < 0)
                 return r;
 
-        m->leader = TAKE_PIDREF(leader_pidref);
-        m->supervisor = TAKE_PIDREF(supervisor_pidref);
-        m->class = c;
-        m->id = id;
-        m->uid = uid;
-
-        if (!isempty(service)) {
-                m->service = strdup(service);
-                if (!m->service) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
+        if (isempty(class))
+                c = _MACHINE_CLASS_INVALID;
+        else {
+                c = machine_class_from_string(class);
+                if (c < 0)
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
         }
 
-        if (!isempty(root_directory)) {
-                m->root_directory = strdup(root_directory);
-                if (!m->root_directory) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-        }
+        if (!isempty(root_directory) && (!path_is_absolute(root_directory) || !path_is_valid(root_directory)))
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
 
-        if (n_netif > 0) {
-                assert_cc(sizeof(int32_t) == sizeof(int));
-                m->netif = memdup(netif, sizeof(int32_t) * n_netif);
-                if (!m->netif) {
-                        r = -ENOMEM;
-                        goto fail;
+        if (hashmap_get(manager->machines, name))
+                return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
+
+        /* If a PID is specified that's the leader, but if the client process is different from it, than that's the supervisor */
+        if (leader_pidfd >= 0) {
+                r = pidref_set_pidfd(&leader_pidref, leader_pidfd);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to parse PIDFD %d: %m", leader_pidfd);
+
+                if (leader_pid > 0 && leader_pidref.pid != (pid_t) leader_pid)
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "LeaderPID and LeaderPIDFD refer to different processes");
+                if (leader_pidfdid > 0) {
+                        r = pidref_acquire_pidfd_id(&leader_pidref);
+                        if (r >= 0 && leader_pidref.fd_id != leader_pidfdid)
+                                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "LeaderPIDFDID does not match the inode number of LeaderPIDFD");
                 }
+        } else if (leader_pid > 0 && leader_pidfdid > 0) {
+                r = pidref_set_pid_and_pidfd_id(&leader_pidref, leader_pid, leader_pidfdid);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to pin process " PID_FMT " by PIDFDID %" PRIu64 ": %m", (pid_t) leader_pid, leader_pidfdid);
+        } else if (leader_pid > 0 || leader_pidfdid > 0)
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Both LeaderPID and LeaderPIDFDID must be specified to identify the leader process by PIDFDID");
 
-                m->n_netif = n_netif;
-        }
+        if (pidref_is_set(&leader_pidref)) {
+                _cleanup_(pidref_done) PidRef client_pidref = PIDREF_NULL;
+                r = bus_query_sender_pidref(message, &client_pidref);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m");
 
-        *ret = m;
-        return 1;
+                if (!pidref_equal(&client_pidref, &leader_pidref))
+                        supervisor_pidref = TAKE_PIDREF(client_pidref);
+        } else {
+                /* If no PID is specified, the client is the leader */
+                r = bus_query_sender_pidref(message, &leader_pidref);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m");
+        }
 
-fail:
-        machine_add_to_gc_queue(m);
-        return r;
+        return machine_add_from_params(
+                        manager,
+                        message,
+                        polkit_action,
+                        name,
+                        c,
+                        id,
+                        service,
+                        &leader_pidref,
+                        &supervisor_pidref,
+                        root_directory,
+                        netif,
+                        n_netif,
+                        cid,
+                        ssh_address,
+                        ssh_private_key_path,
+                        ret,
+                        error);
 }
 
-static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
+static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *manager = ASSERT_PTR(userdata);
         Machine *m = NULL;
         int r;
 
         assert(message);
 
-        r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.create-machine", read_network, &m, error);
+        if (sd_bus_message_is_method_call(message, NULL, "CreateMachineEx"))
+                r = method_create_or_register_machine_ex(manager, message, "org.freedesktop.machine1.create-machines", &m, error);
+        else
+                r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.create-machine", &m, error);
         if (r < 0)
                 return r;
         if (r == 0)
@@ -422,15 +680,7 @@ fail:
         return r;
 }
 
-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_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_message *message, bool read_network, void *userdata, sd_bus_error *error) {
+static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *manager = ASSERT_PTR(userdata);
         _cleanup_free_ char *p = NULL;
         Machine *m = NULL;
@@ -438,7 +688,10 @@ static int method_register_machine_internal(sd_bus_message *message, bool read_n
 
         assert(message);
 
-        r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.register-machine", read_network, &m, error);
+        if (sd_bus_message_is_method_call(message, NULL, "RegisterMachineEx"))
+                r = method_create_or_register_machine_ex(manager, message, "org.freedesktop.machine1.register-machine", &m, error);
+        else
+                r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.register-machine", &m, error);
         if (r < 0)
                 return r;
         if (r == 0)
@@ -482,14 +735,6 @@ fail:
         return r;
 }
 
-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_message *message, void *userdata, sd_bus_error *error) {
-        return method_register_machine_internal(message, false, userdata, error);
-}
-
 static int redirect_method_to_machine(sd_bus_message *message, Manager *m, sd_bus_error *error, sd_bus_message_handler_t method) {
         Machine *machine;
         const char *name;
@@ -969,7 +1214,12 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork",
                                 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices, "a(sv)", scope_properties),
                                 SD_BUS_RESULT("o", path),
-                                method_create_machine_with_network,
+                                method_create_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("CreateMachineEx",
+                                SD_BUS_ARGS("s", name, "a(sv)", properties, "a(sv)", scope_properties),
+                                SD_BUS_RESULT("o", path),
+                                method_create_machine,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("RegisterMachine",
                                 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory),
@@ -979,7 +1229,12 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork",
                                 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices),
                                 SD_BUS_RESULT("o", path),
-                                method_register_machine_with_network,
+                                method_register_machine,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RegisterMachineEx",
+                                SD_BUS_ARGS("s", name, "a(sv)", properties),
+                                SD_BUS_RESULT("o", path),
+                                method_register_machine,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("UnregisterMachine",
                                 SD_BUS_ARGS("s", name),
index 5077294692995fbd9b4f723512e962394ba8b271..69fa2d20a70937014a63c0afac9a33aa6667aa79 100644 (file)
                        send_interface="org.freedesktop.machine1.Manager"
                        send_member="CreateMachineWithNetwork"/>
 
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
+                       send_member="CreateMachineEx"/>
+
                 <allow send_destination="org.freedesktop.machine1"
                        send_interface="org.freedesktop.machine1.Manager"
                        send_member="RegisterMachine"/>
                        send_interface="org.freedesktop.machine1.Manager"
                        send_member="RegisterMachineWithNetwork"/>
 
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
+                       send_member="RegisterMachineEx"/>
+
                 <!-- org.freedesktop.machine1.Machine Method Calls -->
 
                 <allow send_destination="org.freedesktop.machine1"
index 5046f5d79c08faae743474135fb47734bf37e40e..6dce6801b1e2f3528f33244226b5f85e9f0018dd 100644 (file)
@@ -131,6 +131,126 @@ static int can_set_coredump_receive(sd_bus *bus) {
         return r >= 0;
 }
 
+static int create_or_register_machine_ex(
+                sd_bus *bus,
+                const char *machine_name,
+                const PidRef *pid,
+                const char *directory,
+                sd_id128_t uuid,
+                int local_ifindex,
+                const char *slice,
+                CustomMount *mounts,
+                unsigned n_mounts,
+                int kill_signal,
+                char **properties,
+                sd_bus_message *properties_message,
+                const char *service,
+                StartMode start_mode,
+                sd_bus_error *error,
+                bool keep_unit) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        int r;
+
+        assert(error);
+
+        r = bus_message_new_method_call(bus, &m,  bus_machine_mgr, keep_unit ? "RegisterMachineEx" : "CreateMachineEx");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(m, "s", machine_name);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_open_container(m, 'a', "(sv)");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(
+                        m,
+                        "(sv)(sv)(sv)",
+                        "Id", "ay", SD_BUS_MESSAGE_APPEND_ID128(uuid),
+                        "Service", "s", service,
+                        "Class", "s", "container");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (pidref_is_set(pid)) {
+                if (pid->fd >= 0) {
+                        r = sd_bus_message_append(m, "(sv)", "LeaderPIDFD", "h", pid->fd);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                if (pid->fd_id > 0) {
+                        r = sd_bus_message_append(m, "(sv)", "LeaderPIDFDID", "t", pid->fd_id);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+
+                        r = sd_bus_message_append(m, "(sv)", "LeaderPID", "u", pid->pid);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+        }
+
+        if (!isempty(directory)) {
+                r = sd_bus_message_append(m, "(sv)", "RootDirectory", "s", directory);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        if (local_ifindex > 0) {
+                r = sd_bus_message_append(m, "(sv)", "NetworkInterfaces", "ai", 1, local_ifindex);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (!keep_unit) {
+                r = sd_bus_message_open_container(m, 'a', "(sv)");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                if (!isempty(slice)) {
+                        r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = append_controller_property(bus, m);
+                if (r < 0)
+                        return r;
+
+                r = append_machine_properties(
+                                m,
+                                mounts,
+                                n_mounts,
+                                kill_signal,
+                                start_mode == START_BOOT && can_set_coredump_receive(bus) > 0);
+                if (r < 0)
+                        return r;
+
+                if (properties_message) {
+                        r = sd_bus_message_copy(m, properties_message, true);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        return sd_bus_call(bus, m, 0, error, NULL);
+}
+
 int register_machine(
                 sd_bus *bus,
                 const char *machine_name,
@@ -153,6 +273,27 @@ int register_machine(
 
         assert(bus);
 
+        r = create_or_register_machine_ex(
+                        bus,
+                        machine_name,
+                        pid,
+                        directory,
+                        uuid,
+                        local_ifindex,
+                        slice,
+                        mounts,
+                        n_mounts,
+                        kill_signal,
+                        properties,
+                        properties_message,
+                        service,
+                        start_mode,
+                        &error,
+                        FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT));
+        if (r >= 0)
+                return 0;
+        if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
+                return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
         if (FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)) {
                 r = bus_call_method(
                                 bus,