importd: properly support operation in per-user mode

This commit is contained in:
Lennart Poettering
2025-07-25 08:25:29 +02:00
parent b76a76ac15
commit f7c72e8725
6 changed files with 189 additions and 78 deletions

View 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,28 +1716,43 @@ 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 log_error_errno(r, "Failed to attach system bus to event loop: %m");
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 = bus_log_control_api_register(m->bus);
r = bus_log_control_api_register(m->api_bus);
if (r < 0)
return r;
r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
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 request name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %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,

View 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)

View File

@@ -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

View 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' },

View File

@@ -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}}

View File

@@ -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