]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
importd: properly support operation in per-user mode
authorLennart Poettering <lennart@poettering.net>
Fri, 25 Jul 2025 06:25:29 +0000 (08:25 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 21 Oct 2025 21:09:50 +0000 (23:09 +0200)
src/import/importd.c
src/import/meson.build
src/import/org.freedesktop.import1.service-for-session [new file with mode: 0644]
units/user/meson.build
units/user/systemd-importd.service.in [new file with mode: 0644]
units/user/systemd-importd.socket [new file with mode: 0644]

index e9923d93adea922b961d6963e6c79ed43002efad..99b8af580d178e47817ffc58cd83d026c5fc1136 100644 (file)
@@ -32,6 +32,7 @@
 #include "notify-recv.h"
 #include "os-util.h"
 #include "parse-util.h"
+#include "path-lookup.h"
 #include "percent-util.h"
 #include "pidref.h"
 #include "process-util.h"
@@ -100,7 +101,8 @@ typedef struct Transfer {
 
 typedef struct Manager {
         sd_event *event;
-        sd_bus *bus;
+        sd_bus *api_bus;
+        sd_bus *system_bus;
         sd_varlink_server *varlink_server;
 
         uint32_t current_transfer_id;
@@ -113,7 +115,7 @@ typedef struct Manager {
         bool use_btrfs_subvol;
         bool use_btrfs_quota;
 
-        RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */
+        RuntimeScope runtime_scope;
 } Manager;
 
 #define TRANSFERS_MAX 64
@@ -223,7 +225,7 @@ static void transfer_send_log_line(Transfer *t, const char *line) {
         log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line);
 
         r = sd_bus_emit_signal(
-                        t->manager->bus,
+                        t->manager->api_bus,
                         t->object_path,
                         "org.freedesktop.import1.Transfer",
                         "LogMessage",
@@ -254,7 +256,7 @@ static void transfer_send_progress_update(Transfer *t) {
         double progress = transfer_percent_as_double(t);
 
         r = sd_bus_emit_signal(
-                        t->manager->bus,
+                        t->manager->api_bus,
                         t->object_path,
                         "org.freedesktop.import1.Transfer",
                         "ProgressUpdate",
@@ -335,7 +337,7 @@ static int transfer_finalize(Transfer *t, bool success) {
         transfer_send_logs(t, true);
 
         r = sd_bus_emit_signal(
-                        t->manager->bus,
+                        t->manager->api_bus,
                         "/org/freedesktop/import1",
                         "org.freedesktop.import1.Manager",
                         "TransferRemoved",
@@ -443,6 +445,7 @@ static int transfer_start(Transfer *t) {
                 const char *cmd[] = {
                         NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
                         NULL, /* tar, raw  */
+                        NULL, /* --system or --user */
                         NULL, /* --verify= */
                         NULL, /* verify argument */
                         NULL, /* --class= */
@@ -524,6 +527,8 @@ static int transfer_start(Transfer *t) {
                         ;
                 }
 
+                cmd[k++] = runtime_scope_cmdline_option_to_string(t->manager->runtime_scope);
+
                 if (t->verify != _IMPORT_VERIFY_INVALID) {
                         cmd[k++] = "--verify";
                         cmd[k++] = import_verify_to_string(t->verify);
@@ -602,7 +607,7 @@ static int transfer_start(Transfer *t) {
                 return r;
 
         r = sd_bus_emit_signal(
-                        t->manager->bus,
+                        t->manager->api_bus,
                         "/org/freedesktop/import1",
                         "org.freedesktop.import1.Manager",
                         "TransferNew",
@@ -630,7 +635,8 @@ static Manager *manager_unref(Manager *m) {
 
         hashmap_free(m->polkit_registry);
 
-        m->bus = sd_bus_flush_close_unref(m->bus);
+        m->api_bus = sd_bus_flush_close_unref(m->api_bus);
+        m->system_bus = sd_bus_flush_close_unref(m->system_bus);
         m->varlink_server = sd_varlink_server_unref(m->varlink_server);
 
         sd_event_unref(m->event);
@@ -681,7 +687,7 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
         return 0;
 }
 
-static int manager_new(Manager **ret) {
+static int manager_new(RuntimeScope scope, Manager **ret) {
         _cleanup_(manager_unrefp) Manager *m = NULL;
         int r;
 
@@ -694,7 +700,7 @@ static int manager_new(Manager **ret) {
         *m = (Manager) {
                 .use_btrfs_subvol = true,
                 .use_btrfs_quota = true,
-                .runtime_scope = RUNTIME_SCOPE_SYSTEM,
+                .runtime_scope = scope,
         };
 
         r = sd_event_default(&m->event);
@@ -757,16 +763,18 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
 
         assert(msg);
 
-        r = bus_verify_polkit_async(
-                        msg,
-                        "org.freedesktop.import1.import",
-                        /* details= */ NULL,
-                        &m->polkit_registry,
-                        error);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return 1; /* Will call us back */
+        if (m->runtime_scope != RUNTIME_SCOPE_USER) {
+                r = bus_verify_polkit_async(
+                                msg,
+                                "org.freedesktop.import1.import",
+                                /* details= */ NULL,
+                                &m->polkit_registry,
+                                error);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return 1; /* Will call us back */
+        }
 
         if (endswith(sd_bus_message_get_member(msg), "Ex")) {
                 const char *sclass;
@@ -858,16 +866,18 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
 
         assert(msg);
 
-        r = bus_verify_polkit_async(
-                        msg,
-                        "org.freedesktop.import1.import",
-                        /* details= */ NULL,
-                        &m->polkit_registry,
-                        error);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return 1; /* Will call us back */
+        if (m->runtime_scope != RUNTIME_SCOPE_USER) {
+                r = bus_verify_polkit_async(
+                                msg,
+                                "org.freedesktop.import1.import",
+                                /* details= */ NULL,
+                                &m->polkit_registry,
+                                error);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return 1; /* Will call us back */
+        }
 
         if (endswith(sd_bus_message_get_member(msg), "Ex")) {
                 const char *sclass;
@@ -956,16 +966,18 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
 
         assert(msg);
 
-        r = bus_verify_polkit_async(
-                        msg,
-                        "org.freedesktop.import1.export",
-                        /* details= */ NULL,
-                        &m->polkit_registry,
-                        error);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return 1; /* Will call us back */
+        if (m->runtime_scope != RUNTIME_SCOPE_USER) {
+                r = bus_verify_polkit_async(
+                                msg,
+                                "org.freedesktop.import1.export",
+                                /* details= */ NULL,
+                                &m->polkit_registry,
+                                error);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return 1; /* Will call us back */
+        }
 
         if (endswith(sd_bus_message_get_member(msg), "Ex")) {
                 const char *sclass;
@@ -1054,16 +1066,18 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
 
         assert(msg);
 
-        r = bus_verify_polkit_async(
-                        msg,
-                        "org.freedesktop.import1.pull",
-                        /* details= */ NULL,
-                        &m->polkit_registry,
-                        error);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return 1; /* Will call us back */
+        if (m->runtime_scope != RUNTIME_SCOPE_USER) {
+                r = bus_verify_polkit_async(
+                                msg,
+                                "org.freedesktop.import1.pull",
+                                /* details= */ NULL,
+                                &m->polkit_registry,
+                                error);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return 1; /* Will call us back */
+        }
 
         if (endswith(sd_bus_message_get_member(msg), "Ex")) {
                 const char *sclass;
@@ -1702,27 +1716,42 @@ static int manager_connect_bus(Manager *m) {
 
         assert(m);
         assert(m->event);
-        assert(!m->bus);
+        assert(!m->system_bus);
+        assert(!m->api_bus);
 
-        r = bus_open_system_watch_bind(&m->bus);
+        r = bus_open_system_watch_bind(&m->system_bus);
         if (r < 0)
                 return log_error_errno(r, "Failed to get system bus connection: %m");
 
-        r = bus_add_implementation(m->bus, &manager_object, m);
+        r = sd_bus_attach_event(m->system_bus, m->event, 0);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to attach system bus to event loop: %m");
 
-        r = bus_log_control_api_register(m->bus);
+        if (m->runtime_scope == RUNTIME_SCOPE_SYSTEM)
+                m->api_bus = sd_bus_ref(m->system_bus);
+        else {
+                assert(m->runtime_scope == RUNTIME_SCOPE_USER);
+
+                r = sd_bus_default_user(&m->api_bus);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get user bus connection: %m");
+
+                r = sd_bus_attach_event(m->api_bus, m->event, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to attach user bus to event loop: %m");
+        }
+
+        r = bus_add_implementation(m->api_bus, &manager_object, m);
         if (r < 0)
                 return r;
 
-        r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
+        r = bus_log_control_api_register(m->api_bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to request name: %m");
+                return r;
 
-        r = sd_bus_attach_event(m->bus, m->event, 0);
+        r = sd_bus_request_name_async(m->api_bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to attach bus to event loop: %m");
+                return log_error_errno(r, "Failed to request name: %m");
 
         return 0;
 }
@@ -1867,19 +1896,21 @@ static int vl_method_pull(sd_varlink *link, sd_json_variant *parameters, sd_varl
         if (manager_find(m, tt, p.remote))
                 return sd_varlink_errorbo(link, "io.systemd.Import.AlreadyInProgress", SD_JSON_BUILD_PAIR_STRING("remote", p.remote));
 
-        r = varlink_verify_polkit_async(
-                        link,
-                        m->bus,
-                        "org.freedesktop.import1.pull",
-                        (const char**) STRV_MAKE(
-                                        "remote", p.remote,
-                                        "local",  p.local,
-                                        "class",  image_class_to_string(p.class),
-                                        "type",   import_type_to_string(p.type),
-                                        "verify", import_verify_to_string(p.verify)),
-                        &m->polkit_registry);
-        if (r <= 0)
-                return r;
+        if (m->runtime_scope != RUNTIME_SCOPE_USER) {
+                r = varlink_verify_polkit_async(
+                                link,
+                                m->system_bus,
+                                "org.freedesktop.import1.pull",
+                                (const char**) STRV_MAKE(
+                                                "remote", p.remote,
+                                                "local",  p.local,
+                                                "class",  image_class_to_string(p.class),
+                                                "type",   import_type_to_string(p.type),
+                                                "verify", import_verify_to_string(p.verify)),
+                                &m->polkit_registry);
+                if (r <= 0)
+                        return r;
+        }
 
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
 
@@ -1938,9 +1969,11 @@ static int manager_connect_varlink(Manager *m) {
         assert(m->event);
         assert(!m->varlink_server);
 
-        r = varlink_server_new(&m->varlink_server,
-                               SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
-                               m);
+        r = varlink_server_new(
+                        &m->varlink_server,
+                        (m->runtime_scope != RUNTIME_SCOPE_USER ? SD_VARLINK_SERVER_ACCOUNT_UID : 0)|
+                        SD_VARLINK_SERVER_INHERIT_USERDATA,
+                        m);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate varlink server object: %m");
 
@@ -1969,7 +2002,12 @@ static int manager_connect_varlink(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to bind to passed Varlink sockets: %m");
         if (r == 0) {
-                r = sd_varlink_server_listen_address(m->varlink_server, "/run/systemd/io.systemd.Import", 0666);
+                _cleanup_free_ char *socket_path = NULL;
+                r = runtime_directory_generic(m->runtime_scope, "systemd/io.systemd.Import", &socket_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to determine socket path: %m");
+
+                r = sd_varlink_server_listen_address(m->varlink_server, socket_path, runtime_scope_to_socket_mode(m->runtime_scope) | SD_VARLINK_SERVER_MODE_MKDIR_0755);
                 if (r < 0)
                         return log_error_errno(r, "Failed to bind to Varlink socket: %m");
         }
@@ -2009,6 +2047,7 @@ static void manager_parse_env(Manager *m) {
 
 static int run(int argc, char *argv[]) {
         _cleanup_(manager_unrefp) Manager *m = NULL;
+        RuntimeScope scope = RUNTIME_SCOPE_SYSTEM;
         int r;
 
         log_setup();
@@ -2017,7 +2056,7 @@ static int run(int argc, char *argv[]) {
                                "VM and container image import and export service.",
                                BUS_IMPLEMENTATIONS(&manager_object,
                                                    &log_control_object),
-                               /* runtime_scope= */ NULL,
+                               &scope,
                                argc, argv);
         if (r <= 0)
                 return r;
@@ -2026,7 +2065,7 @@ static int run(int argc, char *argv[]) {
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
 
-        r = manager_new(&m);
+        r = manager_new(scope, &m);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate manager object: %m");
 
@@ -2046,7 +2085,7 @@ static int run(int argc, char *argv[]) {
 
         r = bus_event_loop_with_idle(
                         m->event,
-                        m->bus,
+                        m->api_bus,
                         "org.freedesktop.import1",
                         DEFAULT_EXIT_USEC,
                         manager_check_idle,
index 4aec57373affa93bfeda611c84bd10e6c572d2fd..3a50d13b0c56c669004cdef0b8a21276b680d67a 100644 (file)
@@ -111,6 +111,9 @@ install_data('org.freedesktop.import1.conf',
              install_dir : dbuspolicydir)
 install_data('org.freedesktop.import1.service',
              install_dir : dbussystemservicedir)
+install_data('org.freedesktop.import1.service-for-session',
+             install_dir : dbussessionservicedir,
+             rename : 'org.freedesktop.import1.service')
 install_data('org.freedesktop.import1.policy',
              install_dir : polkitpolicydir)
 
diff --git a/src/import/org.freedesktop.import1.service-for-session b/src/import/org.freedesktop.import1.service-for-session
new file mode 100644 (file)
index 0000000..6e6c4a4
--- /dev/null
@@ -0,0 +1,13 @@
+#  SPDX-License-Identifier: LGPL-2.1-or-later
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[D-BUS Service]
+Name=org.freedesktop.import1
+Exec=/bin/false
+SystemdService=dbus-org.freedesktop.import1.service
index 8ad3f0eb7617749c73bea9172695d461d7255d3b..71d242503802046fad6fb305df33c8b975a29db3 100644 (file)
@@ -28,6 +28,16 @@ units = [
           'conditions' : ['ENABLE_MACHINED'],
           'symlinks' : ['sockets.target.wants/'],
         },
+        {
+          'file' : 'systemd-importd.service.in',
+          'conditions' : ['ENABLE_IMPORTD'],
+          'symlinks' : ['dbus-org.freedesktop.import1.service'],
+        },
+        {
+          'file' : 'systemd-importd.socket',
+          'conditions' : ['ENABLE_IMPORTD'],
+          'symlinks' : ['sockets.target.wants/'],
+        },
         { 'file' : 'paths.target' },
         { 'file' : 'printer.target' },
         { 'file' : 'session.slice' },
diff --git a/units/user/systemd-importd.service.in b/units/user/systemd-importd.service.in
new file mode 100644 (file)
index 0000000..420fb06
--- /dev/null
@@ -0,0 +1,28 @@
+#  SPDX-License-Identifier: LGPL-2.1-or-later
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Disk Image Download Service
+Documentation=man:systemd-importd.service(8)
+Documentation=man:org.freedesktop.import1(5)
+
+[Service]
+Type=notify
+ExecStart={{LIBEXECDIR}}/systemd-importd --user
+BusName=org.freedesktop.import1
+KillMode=mixed
+NoNewPrivileges=yes
+MemoryDenyWriteExecute=yes
+RestrictRealtime=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+SystemCallFilter=@system-service @mount
+SystemCallErrorNumber=EPERM
+SystemCallArchitectures=native
+LockPersonality=yes
+{{SERVICE_WATCHDOG}}
diff --git a/units/user/systemd-importd.socket b/units/user/systemd-importd.socket
new file mode 100644 (file)
index 0000000..d266d92
--- /dev/null
@@ -0,0 +1,18 @@
+#  SPDX-License-Identifier: LGPL-2.1-or-later
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Disk Image Download Service Socket
+Documentation=man:systemd-importd.service(8)
+Documentation=man:org.freedesktop.import1(5)
+
+[Socket]
+ListenStream=%t/systemd/io.systemd.Import
+FileDescriptorName=varlink
+SocketMode=0600