From: Lennart Poettering Date: Fri, 25 Jul 2025 06:25:29 +0000 (+0200) Subject: importd: properly support operation in per-user mode X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f7c72e87258e285fa006125f751daebeb6089c2c;p=thirdparty%2Fsystemd.git importd: properly support operation in per-user mode --- diff --git a/src/import/importd.c b/src/import/importd.c index e9923d93ade..99b8af580d1 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -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, diff --git a/src/import/meson.build b/src/import/meson.build index 4aec57373af..3a50d13b0c5 100644 --- a/src/import/meson.build +++ b/src/import/meson.build @@ -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 index 00000000000..6e6c4a4c94b --- /dev/null +++ b/src/import/org.freedesktop.import1.service-for-session @@ -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 diff --git a/units/user/meson.build b/units/user/meson.build index 8ad3f0eb761..71d24250380 100644 --- a/units/user/meson.build +++ b/units/user/meson.build @@ -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 index 00000000000..420fb061059 --- /dev/null +++ b/units/user/systemd-importd.service.in @@ -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 index 00000000000..d266d927f85 --- /dev/null +++ b/units/user/systemd-importd.socket @@ -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