diff --git a/src/basic/runtime-scope.h b/src/basic/runtime-scope.h index 54c797e742..94c2d2ea6a 100644 --- a/src/basic/runtime-scope.h +++ b/src/basic/runtime-scope.h @@ -15,3 +15,20 @@ const char* runtime_scope_to_string(RuntimeScope scope) _const_; RuntimeScope runtime_scope_from_string(const char *s) _const_; const char* runtime_scope_cmdline_option_to_string(RuntimeScope scope) _const_; + +static inline mode_t runtime_scope_to_socket_mode(RuntimeScope scope) { + /* Returns the right socket mode to use for binding AF_UNIX sockets intended for the specified + * scope. If system mode is selected the whole system can connect to it, if user mode is selected + * only the user can connect to it. */ + + switch (scope) { + case RUNTIME_SCOPE_SYSTEM: + return 0666; + + case RUNTIME_SCOPE_USER: + return 0600; + + default: + return MODE_INVALID; + } +} diff --git a/src/home/homed.c b/src/home/homed.c index bb319925d0..9aaabd5c19 100644 --- a/src/home/homed.c +++ b/src/home/homed.c @@ -25,6 +25,7 @@ static int run(int argc, char *argv[]) { "A service to create, remove, change or inspect home areas.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 06fb3f2878..9ba3d312bd 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -1988,6 +1988,7 @@ static int run(int argc, char *argv[]) { "Manage the system hostname and related metadata.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/import/importd.c b/src/import/importd.c index f2715691ab..8603069047 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -2019,6 +2019,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, argc, argv); if (r <= 0) return r; diff --git a/src/libsystemd/sd-path/path-lookup.c b/src/libsystemd/sd-path/path-lookup.c index 55d9d4353a..3ae217a7c5 100644 --- a/src/libsystemd/sd-path/path-lookup.c +++ b/src/libsystemd/sd-path/path-lookup.c @@ -33,32 +33,54 @@ int user_search_dirs(const char *suffix, char ***ret_config_dirs, char ***ret_da return 0; } -int runtime_directory(RuntimeScope scope, const char *suffix, char **ret) { +int runtime_directory_generic(RuntimeScope scope, const char *suffix, char **ret) { int r; - assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER)); - assert(suffix); assert(ret); - /* Accept $RUNTIME_DIRECTORY as authoritative + /* This does not bother with $RUNTIME_DIRECTORY, and hence can be applied to get other service's + * runtime dir */ + + switch (scope) { + case RUNTIME_SCOPE_USER: + r = xdg_user_runtime_dir(suffix, ret); + if (r < 0) + return r; + break; + + case RUNTIME_SCOPE_SYSTEM: { + char *d = path_join("/run", suffix); + if (!d) + return -ENOMEM; + *ret = d; + break; + } + + default: + return -EINVAL; + } + + return 0; +} + +int runtime_directory(RuntimeScope scope, const char *fallback_suffix, char **ret) { + int r; + + assert(ret); + + /* Accept $RUNTIME_DIRECTORY as authoritative, i.e. only works for our service's own runtime dir. + * * If it's missing, apply the suffix to /run/, or $XDG_RUNTIME_DIR if we are in a user runtime scope. * - * Return value indicates whether the suffix was applied or not */ + * Return value indicates whether the suffix was applied or not. */ const char *e = secure_getenv("RUNTIME_DIRECTORY"); if (e) return strdup_to(ret, e); - if (scope == RUNTIME_SCOPE_USER) { - r = xdg_user_runtime_dir(suffix, ret); - if (r < 0) - return r; - } else { - char *d = path_join("/run", suffix); - if (!d) - return -ENOMEM; - *ret = d; - } + r = runtime_directory_generic(scope, fallback_suffix, ret); + if (r < 0) + return r; return 1; } diff --git a/src/libsystemd/sd-path/path-lookup.h b/src/libsystemd/sd-path/path-lookup.h index 8457053339..b706e1a6df 100644 --- a/src/libsystemd/sd-path/path-lookup.h +++ b/src/libsystemd/sd-path/path-lookup.h @@ -57,7 +57,8 @@ int lookup_paths_init_or_warn(LookupPaths *lp, RuntimeScope scope, LookupPathsFl void lookup_paths_log(LookupPaths *p); void lookup_paths_done(LookupPaths *p); -int runtime_directory(RuntimeScope scope, const char *suffix, char **ret); +int runtime_directory_generic(RuntimeScope scope, const char *suffix, char **ret); +int runtime_directory(RuntimeScope scope, const char *fallback_suffix, char **ret); /* We don't treat /etc/xdg/systemd/ in these functions as the xdg base dir spec suggests because we assume * that is a link to /etc/systemd/ anyway. */ diff --git a/src/locale/localed.c b/src/locale/localed.c index 11d9130bbc..041ba29cd8 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -635,6 +635,7 @@ static int run(int argc, char *argv[]) { "Manage system locale settings and key mappings.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/login/logind.c b/src/login/logind.c index 9427bae815..e1219fe73a 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1340,6 +1340,7 @@ static int run(int argc, char *argv[]) { "Manager for user logins and devices and privileged operations.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 8bc6565079..9d4db0521f 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -40,22 +40,24 @@ int bus_image_method_remove( if (m->n_operations >= OPERATIONS_MAX) return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations."); - const char *details[] = { - "image", image->name, - "verb", "remove", - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "image", image->name, + "verb", "remove", + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-images", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-images", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m"); @@ -65,7 +67,7 @@ int bus_image_method_remove( return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); if (r == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - r = image_remove(image); + r = image_remove(image, m->runtime_scope); report_errno_and_exit(errno_pipe_fd[1], r); } @@ -101,23 +103,25 @@ int bus_image_method_rename( if (!image_name_is_valid(new_name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name); - const char *details[] = { - "image", image->name, - "verb", "rename", - "new_name", new_name, - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "image", image->name, + "verb", "rename", + "new_name", new_name, + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-images", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-images", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = rename_image_and_update_cache(m, image, new_name); if (r < 0) @@ -150,23 +154,25 @@ int bus_image_method_clone( if (!image_name_is_valid(new_name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name); - const char *details[] = { - "image", image->name, - "verb", "clone", - "new_name", new_name, - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "image", image->name, + "verb", "clone", + "new_name", new_name, + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-images", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-images", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m"); @@ -199,7 +205,7 @@ int bus_image_method_mark_read_only( sd_bus_error *error) { Image *image = userdata; - Manager *m = image->userdata; + Manager *m = ASSERT_PTR(image->userdata); int read_only, r; assert(message); @@ -208,25 +214,27 @@ int bus_image_method_mark_read_only( if (r < 0) return r; - const char *details[] = { - "image", image->name, - "verb", "mark_read_only", - "read_only", one_zero(read_only), - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "image", image->name, + "verb", "mark_read_only", + "read_only", one_zero(read_only), + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-images", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-images", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } - r = image_read_only(image, read_only); + r = image_read_only(image, read_only, m->runtime_scope); if (r < 0) return r; @@ -251,22 +259,24 @@ int bus_image_method_set_limit( if (!FILE_SIZE_VALID_OR_INFINITY(limit)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range"); - const char *details[] = { - "machine", image->name, - "verb", "set_limit", - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", image->name, + "verb", "set_limit", + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-images", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-images", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = image_set_limit(image, limit); if (r < 0) @@ -280,11 +290,12 @@ int bus_image_method_get_hostname( void *userdata, sd_bus_error *error) { - Image *image = userdata; + Image *image = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(image->userdata); int r; if (!image->metadata_valid) { - r = image_read_metadata(image, &image_policy_container); + r = image_read_metadata(image, &image_policy_container, m->runtime_scope); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -298,11 +309,12 @@ int bus_image_method_get_machine_id( sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - Image *image = userdata; + Image *image = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(image->userdata); int r; if (!image->metadata_valid) { - r = image_read_metadata(image, &image_policy_container); + r = image_read_metadata(image, &image_policy_container, m->runtime_scope); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -326,11 +338,12 @@ int bus_image_method_get_machine_info( void *userdata, sd_bus_error *error) { - Image *image = userdata; + Image *image = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(image->userdata); int r; if (!image->metadata_valid) { - r = image_read_metadata(image, &image_policy_container); + r = image_read_metadata(image, &image_policy_container, m->runtime_scope); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -343,11 +356,12 @@ int bus_image_method_get_os_release( void *userdata, sd_bus_error *error) { - Image *image = userdata; + Image *image = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(image->userdata); int r; if (!image->metadata_valid) { - r = image_read_metadata(image, &image_policy_container); + r = image_read_metadata(image, &image_policy_container, m->runtime_scope); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } diff --git a/src/machine/image-varlink.c b/src/machine/image-varlink.c index 42f53049b7..b2a3bd4c93 100644 --- a/src/machine/image-varlink.c +++ b/src/machine/image-varlink.c @@ -66,15 +66,17 @@ int vl_method_update_image(sd_varlink *link, sd_json_variant *parameters, sd_var if (r < 0) return r; - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-images", - (const char**) STRV_MAKE("image", image->name, - "verb", "update"), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-images", + (const char**) STRV_MAKE("image", image->name, + "verb", "update"), + &manager->polkit_registry); + if (r <= 0) + return r; + } if (p.new_name) { r = rename_image_and_update_cache(manager, image, p.new_name); @@ -83,7 +85,7 @@ int vl_method_update_image(sd_varlink *link, sd_json_variant *parameters, sd_var } if (p.read_only >= 0) { - r = image_read_only(image, p.read_only); + r = image_read_only(image, p.read_only, manager->runtime_scope); if (r < 0) RET_GATHER(ret, log_debug_errno(r, "Failed to toggle image read only, ignoring: %m")); } @@ -139,16 +141,18 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl if (r < 0) return r; - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-images", - (const char**) STRV_MAKE("image", image->name, - "verb", "clone", - "new_name", p.new_name), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-images", + (const char**) STRV_MAKE("image", image->name, + "verb", "clone", + "new_name", p.new_name), + &manager->polkit_registry); + if (r <= 0) + return r; + } if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) return log_debug_errno(errno, "Failed to open pipe: %m"); @@ -207,15 +211,17 @@ int vl_method_remove_image(sd_varlink *link, sd_json_variant *parameters, sd_var if (r < 0) return r; - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-images", - (const char**) STRV_MAKE("image", image->name, - "verb", "remove"), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-images", + (const char**) STRV_MAKE("image", image->name, + "verb", "remove"), + &manager->polkit_registry); + if (r <= 0) + return r; + } if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) return log_debug_errno(errno, "Failed to open pipe: %m"); @@ -225,7 +231,7 @@ int vl_method_remove_image(sd_varlink *link, sd_json_variant *parameters, sd_var return log_debug_errno(r, "Failed to fork: %m"); if (r == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - r = image_remove(image); + r = image_remove(image, manager->runtime_scope); report_errno_and_exit(errno_pipe_fd[1], r); } @@ -262,21 +268,23 @@ int vl_method_set_pool_limit(sd_varlink *link, sd_json_variant *parameters, sd_v if (!FILE_SIZE_VALID_OR_INFINITY(limit)) return sd_varlink_error_invalid_parameter_name(link, "limit"); - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-images", - (const char**) STRV_MAKE("verb", "set_pool_limit"), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-images", + (const char**) STRV_MAKE("verb", "set_pool_limit"), + &manager->polkit_registry); + if (r <= 0) + return r; + } /* Set up the machine directory if necessary */ r = setup_machine_directory(/* error = */ NULL, /* use_btrfs_subvol= */ true, /* use_btrfs_quota= */ true); if (r < 0) return r; - r = image_set_pool_limit(IMAGE_MACHINE, limit); + r = image_set_pool_limit(manager->runtime_scope, IMAGE_MACHINE, limit); if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) return sd_varlink_error(link, VARLINK_ERROR_MACHINE_IMAGE_NOT_SUPPORTED, NULL); if (r < 0) @@ -394,15 +402,17 @@ int vl_method_clean_pool(sd_varlink *link, sd_json_variant *parameters, sd_varli if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-images", - (const char**) STRV_MAKE("mode", image_clean_pool_mode_to_string(mode), - "verb", "clean_pool"), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-images", + (const char**) STRV_MAKE("mode", image_clean_pool_mode_to_string(mode), + "verb", "clean_pool"), + &manager->polkit_registry); + if (r <= 0) + return r; + } Operation *op; r = image_clean_pool_operation(manager, mode, &op); diff --git a/src/machine/image.c b/src/machine/image.c index 9b080e3dc0..0a5b6d27ae 100644 --- a/src/machine/image.c +++ b/src/machine/image.c @@ -143,7 +143,7 @@ int image_clean_pool_operation(Manager *manager, ImageCleanPoolMode mode, Operat if (mode == IMAGE_CLEAN_POOL_REMOVE_HIDDEN && !image_is_hidden(image)) continue; - r = image_remove(image); + r = image_remove(image, manager->runtime_scope); if (r == -EBUSY) { log_debug("Keeping image '%s' because it's currently used.", image->name); continue; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 388a584a12..69159f4eb0 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -55,24 +55,26 @@ int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bu assert(message); - const char *details[] = { - "machine", m->name, - "verb", "unregister", - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "unregister", + NULL + }; - r = bus_verify_polkit_async_full( - message, - "org.freedesktop.machine1.manage-machines", - details, - m->uid, - /* flags= */ 0, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async_full( + message, + "org.freedesktop.machine1.manage-machines", + details, + m->uid, + /* flags= */ 0, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = machine_finalize(m); if (r < 0) @@ -87,24 +89,26 @@ int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus assert(message); - const char *details[] = { - "machine", m->name, - "verb", "terminate", - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "terminate", + NULL + }; - r = bus_verify_polkit_async_full( - message, - "org.freedesktop.machine1.manage-machines", - details, - m->uid, - /* flags= */ 0, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async_full( + message, + "org.freedesktop.machine1.manage-machines", + details, + m->uid, + /* flags= */ 0, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = machine_stop(m); if (r < 0) @@ -137,24 +141,26 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro if (!SIGNAL_VALID(signo)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); - const char *details[] = { - "machine", m->name, - "verb", "kill", - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "kill", + NULL + }; - r = bus_verify_polkit_async_full( - message, - "org.freedesktop.machine1.manage-machines", - details, - m->uid, - /* flags= */ 0, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async_full( + message, + "org.freedesktop.machine1.manage-machines", + details, + m->uid, + /* flags= */ 0, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = machine_kill(m, whom, signo); if (r < 0) @@ -260,23 +266,25 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_ assert(message); - const char *details[] = { - "machine", m->name, - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + NULL + }; - r = bus_verify_polkit_async_full( - message, - m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty", - details, - m->uid, - /* flags= */ 0, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async_full( + message, + m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty", + details, + m->uid, + /* flags= */ 0, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name); if (master < 0) @@ -302,24 +310,26 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu assert(message); - const char *details[] = { - "machine", m->name, - "verb", "login", - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "login", + NULL + }; - r = bus_verify_polkit_async_full( - message, - m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login", - details, - m->uid, - /* flags= */ 0, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async_full( + message, + m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login", + details, + m->uid, + /* flags= */ 0, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name); if (master < 0) @@ -345,7 +355,6 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu _cleanup_free_ char *pty_name = NULL; _cleanup_close_ int master = -EBADF; _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL; - _cleanup_free_ char *command_line = NULL; Machine *m = ASSERT_PTR(userdata); const char *user, *path; int r; @@ -402,29 +411,32 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (!strv_env_is_valid(env)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); - command_line = strv_join(args, " "); - if (!command_line) - return -ENOMEM; - const char *details[] = { - "machine", m->name, - "user", user, - "program", path, - "command_line", command_line, - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + _cleanup_free_ char *command_line = strv_join(args, " "); + if (!command_line) + return -ENOMEM; - r = bus_verify_polkit_async_full( - message, - m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell", - details, - m->uid, - /* flags= */ 0, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + const char *details[] = { + "machine", m->name, + "user", user, + "program", path, + "command_line", command_line, + NULL + }; + + r = bus_verify_polkit_async_full( + message, + m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell", + details, + m->uid, + /* flags= */ 0, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name); if (master < 0) @@ -470,25 +482,27 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu else if (!path_is_absolute(dest) || !path_is_normalized(dest)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized."); - const char *details[] = { - "machine", m->name, - "verb", "bind", - "src", src, - "dest", dest, - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "bind", + "src", src, + "dest", dest, + NULL + }; - /* NB: For now not opened up to owner of machine without auth */ - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-machines", - details, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + /* NB: For now not opened up to owner of machine without auth */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-machines", + details, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = machine_get_uid_shift(m, &uid); if (r < 0) @@ -556,25 +570,27 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro else if (!path_is_absolute(dest)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute."); - const char *details[] = { - "machine", m->name, - "verb", "copy", - "src", src, - "dest", dest, - NULL - }; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "copy", + "src", src, + "dest", dest, + NULL + }; - /* NB: For now not opened up to owner of machine without auth */ - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-machines", - details, - &manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + /* NB: For now not opened up to owner of machine without auth */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-machines", + details, + &manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom"); @@ -602,23 +618,25 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda assert(message); - const char *details[] = { - "machine", m->name, - "verb", "open_root_directory", - NULL - }; + if (m->manager->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "machine", m->name, + "verb", "open_root_directory", + NULL + }; - /* NB: For now not opened up to owner of machine without auth */ - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-machines", - details, - &m->manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + /* NB: For now not opened up to owner of machine without auth */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-machines", + details, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } fd = machine_open_root_directory(m); if (ERRNO_IS_NEG_NOT_SUPPORTED(fd)) @@ -862,7 +880,7 @@ int machine_send_signal(Machine *m, bool new_machine) { return -ENOMEM; return sd_bus_emit_signal( - m->manager->bus, + m->manager->api_bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", new_machine ? "MachineNew" : "MachineRemoved", diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index 5a2f67129e..1551608a68 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -155,15 +155,17 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink if (r != 0) return r; - r = varlink_verify_polkit_async( - link, - manager->bus, - machine->allocate_unit ? "org.freedesktop.machine1.create-machine" : "org.freedesktop.machine1.register-machine", - (const char**) STRV_MAKE("name", machine->name, - "class", machine_class_to_string(machine->class)), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + machine->allocate_unit ? "org.freedesktop.machine1.create-machine" : "org.freedesktop.machine1.register-machine", + (const char**) STRV_MAKE("name", machine->name, + "class", machine_class_to_string(machine->class)), + &manager->polkit_registry); + if (r <= 0) + return r; + } if (!pidref_is_set(&machine->leader)) { r = varlink_get_peer_pidref(link, &machine->leader); @@ -306,17 +308,19 @@ int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters, Manager *manager = ASSERT_PTR(machine->manager); int r; - r = varlink_verify_polkit_async_full( - link, - manager->bus, - "org.freedesktop.machine1.manage-machines", - (const char**) STRV_MAKE("name", machine->name, - "verb", "unregister"), - machine->uid, - /* flags= */ 0, - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async_full( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-machines", + (const char**) STRV_MAKE("name", machine->name, + "verb", "unregister"), + machine->uid, + /* flags= */ 0, + &manager->polkit_registry); + if (r <= 0) + return r; + } r = machine_finalize(machine); if (r < 0) @@ -330,17 +334,19 @@ int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters, Manager *manager = ASSERT_PTR(machine->manager); int r; - r = varlink_verify_polkit_async_full( - link, - manager->bus, - "org.freedesktop.machine1.manage-machines", - (const char**) STRV_MAKE("name", machine->name, - "verb", "terminate"), - machine->uid, - /* flags= */ 0, - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async_full( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-machines", + (const char**) STRV_MAKE("name", machine->name, + "verb", "terminate"), + machine->uid, + /* flags= */ 0, + &manager->polkit_registry); + if (r <= 0) + return r; + } r = machine_stop(machine); if (r < 0) @@ -400,17 +406,19 @@ int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met return sd_varlink_error_invalid_parameter_name(link, "whom"); } - r = varlink_verify_polkit_async_full( - link, - manager->bus, - "org.freedesktop.machine1.manage-machines", - (const char**) STRV_MAKE("name", machine->name, - "verb", "kill"), - machine->uid, - /* flags= */ 0, - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async_full( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-machines", + (const char**) STRV_MAKE("name", machine->name, + "verb", "kill"), + machine->uid, + /* flags= */ 0, + &manager->polkit_registry); + if (r <= 0) + return r; + } r = machine_kill(machine, whom, p.signo); if (r < 0) @@ -509,8 +517,8 @@ int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met }; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_free_ char *ptmx_name = NULL, *command_line = NULL; - _cleanup_strv_free_ char **polkit_details = NULL, **args = NULL; const char *user = NULL, *path = NULL; /* gcc complains about uninitialized variables */ + _cleanup_strv_free_ char **args = NULL; Machine *machine; int r, ptmx_fd_idx; @@ -543,17 +551,21 @@ int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met if (r < 0) return r; - polkit_details = machine_open_polkit_details(p.mode, machine->name, user, path, command_line); - r = varlink_verify_polkit_async_full( - link, - manager->bus, - machine_open_polkit_action(p.mode, machine->class), - (const char**) polkit_details, - machine->uid, - /* flags= */ 0, - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + _cleanup_strv_free_ char **polkit_details = NULL; + + polkit_details = machine_open_polkit_details(p.mode, machine->name, user, path, command_line); + r = varlink_verify_polkit_async_full( + link, + manager->system_bus, + machine_open_polkit_action(p.mode, machine->class), + (const char**) polkit_details, + machine->uid, + /* flags= */ 0, + &manager->polkit_registry); + if (r <= 0) + return r; + } ptmx_fd = machine_openpt(machine, O_RDWR|O_NOCTTY|O_CLOEXEC, &ptmx_name); if (ERRNO_IS_NEG_NOT_SUPPORTED(ptmx_fd)) @@ -824,18 +836,20 @@ int vl_method_bind_mount(sd_varlink *link, sd_json_variant *parameters, sd_varli if (machine->class != MACHINE_CONTAINER) return sd_varlink_error(link, VARLINK_ERROR_MACHINE_NOT_SUPPORTED, NULL); - /* NB: For now not opened up to owner of machine without auth */ - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-machines", - (const char**) STRV_MAKE("name", machine->name, - "verb", "bind", - "src", p.src, - "dest", dest), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + /* NB: For now not opened up to owner of machine without auth */ + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-machines", + (const char**) STRV_MAKE("name", machine->name, + "verb", "bind", + "src", p.src, + "dest", dest), + &manager->polkit_registry); + if (r <= 0) + return r; + } r = machine_get_uid_shift(machine, &uid_shift); if (r < 0) @@ -936,18 +950,20 @@ int vl_method_copy_internal(sd_varlink *link, sd_json_variant *parameters, sd_va if (machine->class != MACHINE_CONTAINER) return sd_varlink_error(link, VARLINK_ERROR_MACHINE_NOT_SUPPORTED, NULL); - /* NB: For now not opened up to owner of machine without auth */ - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-machines", - (const char**) STRV_MAKE("name", machine->name, - "verb", "copy", - "src", p.src, - "dest", dest), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + /* NB: For now not opened up to owner of machine without auth */ + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-machines", + (const char**) STRV_MAKE("name", machine->name, + "verb", "copy", + "src", p.src, + "dest", dest), + &manager->polkit_registry); + if (r <= 0) + return r; + } Operation *op; r = machine_copy_from_to_operation(manager, machine, host_path, container_path, copy_from, copy_flags, &op); @@ -967,15 +983,17 @@ int vl_method_open_root_directory_internal(sd_varlink *link, sd_json_variant *pa int r; /* NB: For now not opened up to owner of machine without auth */ - r = varlink_verify_polkit_async( - link, - manager->bus, - "org.freedesktop.machine1.manage-machines", - (const char**) STRV_MAKE("name", machine->name, - "verb", "open_root_directory"), - &manager->polkit_registry); - if (r <= 0) - return r; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + r = varlink_verify_polkit_async( + link, + manager->system_bus, + "org.freedesktop.machine1.manage-machines", + (const char**) STRV_MAKE("name", machine->name, + "verb", "open_root_directory"), + &manager->polkit_registry); + if (r <= 0) + return r; + } fd = machine_open_root_directory(machine); if (ERRNO_IS_NEG_NOT_SUPPORTED(fd)) diff --git a/src/machine/machine.c b/src/machine/machine.c index e651026fa9..ff376c7047 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -88,7 +88,7 @@ int machine_link(Manager *manager, Machine *machine) { return -EINVAL; if (machine->class != MACHINE_HOST) { - char *temp = path_join("/run/systemd/machines", machine->name); + char *temp = path_join(manager->state_dir, machine->name); if (!temp) return -ENOMEM; @@ -170,14 +170,14 @@ int machine_save(Machine *m) { _cleanup_(unlink_and_freep) char *sl = NULL; /* auto-unlink! */ if (m->unit && !m->subgroup) { - sl = strjoin("/run/systemd/machines/unit:", m->unit); + sl = strjoin(m->manager->state_dir, "/unit:", m->unit); if (!sl) return log_oom(); } - r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, MKDIR_WARN_MODE); + r = mkdir_safe_label(m->manager->state_dir, 0755, 0, 0, MKDIR_WARN_MODE); if (r < 0) - return log_error_errno(r, "Failed to create /run/systemd/machines/: %m"); + return log_error_errno(r, "Failed to create '%s': %m", m->manager->state_dir); _cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -267,7 +267,7 @@ static void machine_unlink(Machine *m) { assert(m); if (m->unit && !m->subgroup) { - const char *sl = strjoina("/run/systemd/machines/unit:", m->unit); + const char *sl = strjoina(m->manager->state_dir, "/unit:", m->unit); (void) unlink(sl); } @@ -438,7 +438,7 @@ static int machine_start_scope( return log_oom(); r = bus_message_new_method_call( - machine->manager->bus, + machine->manager->api_bus, &m, bus_systemd_mgr, "StartTransientUnit"); @@ -920,7 +920,7 @@ int machine_start_getty(Machine *m, const char *ptmx_name, sd_bus_error *error) if (r < 0) return log_debug_errno(r, "Failed to create DBus to machine: %m"); - container_bus = allocated_bus ?: m->manager->bus; + container_bus = allocated_bus ?: m->manager->system_bus; getty = strjoina("container-getty@", p, ".service"); r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, /* ret_reply = */ NULL, "ss", getty, "replace"); @@ -966,7 +966,7 @@ int machine_start_shell( if (r < 0) return log_debug_errno(r, "Failed to create DBus to machine: %m"); - container_bus = allocated_bus ?: m->manager->bus; + container_bus = allocated_bus ?: m->manager->system_bus; r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit"); if (r < 0) return r; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index fd37bde874..c64b8b5bba 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -104,6 +104,7 @@ static const char* arg_format = NULL; static const char *arg_uid = NULL; static char **arg_setenv = NULL; static unsigned arg_max_addresses = 1; +static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_setenv, strv_freep); @@ -2099,6 +2100,8 @@ static int help(int argc, char *argv[], void *userdata) { " --no-ask-password Do not ask for system passwords\n" " -H --host=[USER@]HOST Operate on remote host\n" " -M --machine=CONTAINER Operate on local container\n" + " --system Connect to system machine manager\n" + " --user Connect to user machine manager\n" " -p --property=NAME Show only properties by this name\n" " --value When showing properties, only print the value\n" " -P NAME Equivalent to --value --property=NAME\n" @@ -2152,6 +2155,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_FORMAT, ARG_UID, ARG_MAX_ADDRESSES, + ARG_SYSTEM, + ARG_USER, }; static const struct option options[] = { @@ -2181,6 +2186,8 @@ static int parse_argv(int argc, char *argv[]) { { "uid", required_argument, NULL, ARG_UID }, { "setenv", required_argument, NULL, 'E' }, { "max-addresses", required_argument, NULL, ARG_MAX_ADDRESSES }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, {} }; @@ -2404,6 +2411,14 @@ static int parse_argv(int argc, char *argv[]) { "Invalid number of addresses: %s", optarg); break; + case ARG_USER: + arg_runtime_scope = RUNTIME_SCOPE_USER; + break; + + case ARG_SYSTEM: + arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; + break; + case '?': return -EINVAL; @@ -2488,9 +2503,9 @@ static int run(int argc, char *argv[]) { "list-transfers", "cancel-transfer")) return chainload_importctl(argc, argv); - r = bus_connect_transport(arg_transport, arg_host, RUNTIME_SCOPE_SYSTEM, &bus); + r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus); if (r < 0) - return bus_log_connect_error(r, arg_transport, RUNTIME_SCOPE_SYSTEM); + return bus_log_connect_error(r, arg_transport, arg_runtime_scope); (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 7d2e3dfb62..ec34cbac36 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -278,22 +278,24 @@ static int machine_add_from_params( 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 - }; + if (manager->runtime_scope != RUNTIME_SCOPE_USER) { + 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 = 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) @@ -697,7 +699,18 @@ static int method_register_machine(sd_bus_message *message, void *userdata, sd_b if (r == 0) return 1; /* Will call us back */ - r = cg_pidref_get_unit_full(&m->leader, &m->unit, &m->subgroup); + switch (manager->runtime_scope) { + case RUNTIME_SCOPE_USER: + r = cg_pidref_get_user_unit_full(&m->leader, &m->unit, &m->subgroup); + break; + + case RUNTIME_SCOPE_SYSTEM: + r = cg_pidref_get_unit_full(&m->leader, &m->unit, &m->subgroup); + break; + + default: + assert_not_reached(); + } if (r < 0) { r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %m", @@ -983,22 +996,24 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm); - const char *details[] = { - "verb", "clean_pool", - "mode", mm, - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "verb", "clean_pool", + "mode", mm, + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-machines", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-machines", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } r = image_clean_pool_operation(m, mode, &operation); if (r < 0) @@ -1022,28 +1037,30 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus if (!FILE_SIZE_VALID_OR_INFINITY(limit)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range"); - const char *details[] = { - "verb", "set_pool_limit", - NULL - }; + if (m->runtime_scope != RUNTIME_SCOPE_USER) { + const char *details[] = { + "verb", "set_pool_limit", + NULL + }; - r = bus_verify_polkit_async( - message, - "org.freedesktop.machine1.manage-machines", - details, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ + r = bus_verify_polkit_async( + message, + "org.freedesktop.machine1.manage-machines", + details, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + } /* Set up the machine directory if necessary */ r = setup_machine_directory(error, /* use_btrfs_subvol= */ true, /* use_btrfs_quota= */ true); if (r < 0) return r; - r = image_set_pool_limit(IMAGE_MACHINE, limit); + r = image_set_pool_limit(m->runtime_scope, IMAGE_MACHINE, limit); if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); if (r < 0) @@ -1534,7 +1551,7 @@ int manager_unref_unit( assert(m); assert(unit); - return bus_call_method(m->bus, bus_systemd_mgr, "UnrefUnit", error, NULL, "s", unit); + return bus_call_method(m->api_bus, bus_systemd_mgr, "UnrefUnit", error, NULL, "s", unit); } int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { @@ -1544,7 +1561,7 @@ int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, c assert(manager); assert(unit); - r = bus_call_method(manager->bus, bus_systemd_mgr, "StopUnit", error, &reply, "ss", unit, "fail"); + r = bus_call_method(manager->api_bus, bus_systemd_mgr, "StopUnit", error, &reply, "ss", unit, "fail"); if (r < 0) { if (sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT, BUS_ERROR_LOAD_FAILED)) { @@ -1582,9 +1599,9 @@ int manager_kill_unit(Manager *manager, const char *unit, const char *subgroup, assert(unit); if (empty_or_root(subgroup)) - return bus_call_method(manager->bus, bus_systemd_mgr, "KillUnit", reterr_error, NULL, "ssi", unit, "all", signo); + return bus_call_method(manager->api_bus, bus_systemd_mgr, "KillUnit", reterr_error, NULL, "ssi", unit, "all", signo); - return bus_call_method(manager->bus, bus_systemd_mgr, "KillUnitSubgroup", reterr_error, NULL, "sssi", unit, "cgroup", subgroup, signo); + return bus_call_method(manager->api_bus, bus_systemd_mgr, "KillUnitSubgroup", reterr_error, NULL, "sssi", unit, "cgroup", subgroup, signo); } int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *reterr_error) { @@ -1602,7 +1619,7 @@ int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *ret return -ENOMEM; r = sd_bus_get_property( - manager->bus, + manager->api_bus, "org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Unit", @@ -1638,7 +1655,7 @@ int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *rete assert(path); r = sd_bus_get_property( - manager->bus, + manager->api_bus, "org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Job", diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c index 52b1fc12d2..a00dda1b73 100644 --- a/src/machine/machined-varlink.c +++ b/src/machine/machined-varlink.c @@ -18,6 +18,7 @@ #include "machine-varlink.h" #include "machined.h" #include "machined-varlink.h" +#include "path-lookup.h" #include "string-util.h" #include "strv.h" #include "user-util.h" @@ -614,14 +615,15 @@ static int vl_method_open_root_directory(sd_varlink *link, sd_json_variant *para return lookup_machine_and_call_method(link, parameters, flags, userdata, vl_method_open_root_directory_internal); } -static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image, bool more, AcquireMetadata am) { +static int list_image_one_and_maybe_read_metadata(Manager *m, sd_varlink *link, Image *image, bool more, AcquireMetadata am) { int r; + assert(m); assert(link); assert(image); if (should_acquire_metadata(am) && !image->metadata_valid) { - r = image_read_metadata(image, &image_policy_container); + r = image_read_metadata(image, &image_policy_container, m->runtime_scope); if (r < 0 && am != ACQUIRE_METADATA_GRACEFUL) return log_debug_errno(r, "Failed to read image metadata: %m"); if (r < 0) @@ -697,7 +699,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, if (r < 0) return log_debug_errno(r, "Failed to find image: %m"); - return list_image_one_and_maybe_read_metadata(link, found, /* more = */ false, p.acquire_metadata); + return list_image_one_and_maybe_read_metadata(m, link, found, /* more = */ false, p.acquire_metadata); } if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) @@ -711,7 +713,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, Image *image, *previous = NULL; HASHMAP_FOREACH(image, images) { if (previous) { - r = list_image_one_and_maybe_read_metadata(link, previous, /* more = */ true, p.acquire_metadata); + r = list_image_one_and_maybe_read_metadata(m, link, previous, /* more = */ true, p.acquire_metadata); if (r < 0) return r; } @@ -720,7 +722,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, } if (previous) - return list_image_one_and_maybe_read_metadata(link, previous, /* more = */ false, p.acquire_metadata); + return list_image_one_and_maybe_read_metadata(m, link, previous, /* more = */ false, p.acquire_metadata); return sd_varlink_error(link, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE, NULL); } @@ -733,6 +735,8 @@ static int manager_varlink_init_userdb(Manager *m) { if (m->varlink_userdb_server) return 0; + if (m->runtime_scope != RUNTIME_SCOPE_SYSTEM) /* no userdb in per-user mode! */ + return 0; r = varlink_server_new(&s, SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA, m); if (r < 0) @@ -817,11 +821,20 @@ static int manager_varlink_init_machine(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(s, "/run/systemd/machine/io.systemd.Machine", 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); + _cleanup_free_ char *socket_path = NULL; + r = runtime_directory_generic(m->runtime_scope, "systemd/machine/io.systemd.Machine", &socket_path); + if (r < 0) + return log_error_errno(r, "Failed to determine socket path: %m"); + + r = sd_varlink_server_listen_address(s, 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 io.systemd.Machine varlink socket: %m"); - r = sd_varlink_server_listen_address(s, "/run/systemd/machine/io.systemd.MachineImage", 0666); + socket_path = mfree(socket_path); + r = runtime_directory_generic(m->runtime_scope, "systemd/machine/io.systemd.MachineImage", &socket_path); + if (r < 0) + return log_error_errno(r, "Failed to determine socket path: %m"); + r = sd_varlink_server_listen_address(s, socket_path, runtime_scope_to_socket_mode(m->runtime_scope)); if (r < 0) return log_error_errno(r, "Failed to bind to io.systemd.MachineImage varlink socket: %m"); } diff --git a/src/machine/machined.c b/src/machine/machined.c index 46395d7df4..c6b13e6cba 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -27,6 +27,7 @@ #include "main-func.h" #include "mkdir-label.h" #include "operation.h" +#include "path-lookup.h" #include "service-util.h" #include "signal-util.h" #include "socket-util.h" @@ -38,7 +39,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref); DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(machine_hash_ops, char, string_hash_func, string_compare_func, Machine, machine_free); -static int manager_new(Manager **ret) { +static int manager_new(RuntimeScope scope, Manager **ret) { _cleanup_(manager_unrefp) Manager *m = NULL; int r; @@ -49,9 +50,13 @@ static int manager_new(Manager **ret) { return -ENOMEM; *m = (Manager) { - .runtime_scope = RUNTIME_SCOPE_SYSTEM, + .runtime_scope = scope, }; + r = runtime_directory_generic(scope, "systemd/machines", &m->state_dir); + if (r < 0) + return r; + m->machines = hashmap_new(&machine_hash_ops); if (!m->machines) return -ENOMEM; @@ -105,9 +110,12 @@ static Manager* manager_unref(Manager *m) { manager_varlink_done(m); - sd_bus_flush_close_unref(m->bus); + sd_bus_flush_close_unref(m->api_bus); + sd_bus_flush_close_unref(m->system_bus); sd_event_unref(m->event); + free(m->state_dir); + return mfree(m); } @@ -118,6 +126,8 @@ static int manager_add_host_machine(Manager *m) { Machine *t; int r; + if (m->runtime_scope != RUNTIME_SCOPE_SYSTEM) + return 0; if (m->host_machine) return 0; @@ -174,12 +184,12 @@ static int manager_enumerate_machines(Manager *m) { return r; /* Read in machine data stored on disk */ - d = opendir("/run/systemd/machines"); + d = opendir(m->state_dir); if (!d) { if (errno == ENOENT) return 0; - return log_error_errno(errno, "Failed to open %s: %m", "/run/systemd/machines"); + return log_error_errno(errno, "Failed to open '%s': %m", m->state_dir); } FOREACH_DIRENT(de, d, return -errno) { @@ -214,26 +224,45 @@ static int manager_connect_bus(Manager *m) { int r; assert(m); - assert(!m->bus); + assert(!m->system_bus); + assert(!m->api_bus); - r = sd_bus_default_system(&m->bus); + r = sd_bus_default_system(&m->system_bus); if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %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 connect to user bus: %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_match_signal_async(m->bus, NULL, bus_systemd_mgr, "JobRemoved", match_job_removed, NULL, m); + r = bus_match_signal_async(m->api_bus, NULL, bus_systemd_mgr, "JobRemoved", match_job_removed, NULL, m); if (r < 0) return log_error_errno(r, "Failed to add match for JobRemoved: %m"); - r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "UnitRemoved", match_unit_removed, NULL, m); + r = bus_match_signal_async(m->api_bus, NULL, bus_systemd_mgr, "UnitRemoved", match_unit_removed, NULL, m); if (r < 0) return log_error_errno(r, "Failed to request match for UnitRemoved: %m"); r = sd_bus_match_signal_async( - m->bus, + m->api_bus, NULL, "org.freedesktop.systemd1", NULL, @@ -243,26 +272,22 @@ static int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to request match for PropertiesChanged: %m"); - r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "Reloading", match_reloading, NULL, m); + r = bus_match_signal_async(m->api_bus, NULL, bus_systemd_mgr, "Reloading", match_reloading, NULL, m); if (r < 0) return log_error_errno(r, "Failed to request match for Reloading: %m"); - r = bus_call_method_async(m->bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL); + r = bus_call_method_async(m->api_bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL); if (r < 0) return log_error_errno(r, "Failed to enable subscription: %m"); - 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.machine1", 0, NULL, NULL); + r = sd_bus_request_name_async(m->api_bus, NULL, "org.freedesktop.machine1", 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; } @@ -315,6 +340,7 @@ static bool check_idle(void *userdata) { static int run(int argc, char *argv[]) { _cleanup_(manager_unrefp) Manager *m = NULL; + RuntimeScope scope = RUNTIME_SCOPE_SYSTEM; int r; log_set_facility(LOG_AUTH); @@ -324,6 +350,7 @@ static int run(int argc, char *argv[]) { "Manage registrations of local VMs and containers.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + &scope, argc, argv); if (r <= 0) return r; @@ -333,11 +360,12 @@ static int run(int argc, char *argv[]) { /* Always create the directories people can create inotify watches in. Note that some applications might check * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always * make sure this check stays in. */ - (void) mkdir_label("/run/systemd/machines", 0755); + if (scope == RUNTIME_SCOPE_SYSTEM) + (void) mkdir_label("/run/systemd/machines", 0755); assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ 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"); @@ -351,7 +379,7 @@ static int run(int argc, char *argv[]) { r = bus_event_loop_with_idle( m->event, - m->bus, + m->api_bus, "org.freedesktop.machine1", DEFAULT_EXIT_USEC, check_idle, m); diff --git a/src/machine/machined.h b/src/machine/machined.h index d03577be3c..483d41abed 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -7,7 +7,8 @@ typedef struct Manager { sd_event *event; - sd_bus *bus; + sd_bus *api_bus; /* this is where we offer our services */ + sd_bus *system_bus; /* this is where we talk to system services on, for example PK or so */ Hashmap *machines; Hashmap *machines_by_unit; /* This hashmap only tracks machines where a system-level encapsulates @@ -32,7 +33,8 @@ typedef struct Manager { sd_varlink_server *varlink_userdb_server; sd_varlink_server *varlink_machine_server; - RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */ + RuntimeScope runtime_scope; + char *state_dir; } Manager; int manager_add_machine(Manager *m, const char *name, Machine **ret); diff --git a/src/machine/meson.build b/src/machine/meson.build index 9370077fdc..8de7d7d2ae 100644 --- a/src/machine/meson.build +++ b/src/machine/meson.build @@ -49,5 +49,8 @@ install_data('org.freedesktop.machine1.conf', install_dir : dbuspolicydir) install_data('org.freedesktop.machine1.service', install_dir : dbussystemservicedir) +install_data('org.freedesktop.machine1.service-for-session', + install_dir : dbussessionservicedir, + rename : 'org.freedesktop.machine1.service') install_data('org.freedesktop.machine1.policy', install_dir : polkitpolicydir) diff --git a/src/machine/org.freedesktop.machine1.service-for-session b/src/machine/org.freedesktop.machine1.service-for-session new file mode 100644 index 0000000000..44c2e24b52 --- /dev/null +++ b/src/machine/org.freedesktop.machine1.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.machine1 +Exec=/bin/false +SystemdService=dbus-org.freedesktop.machine1.service diff --git a/src/network/networkd.c b/src/network/networkd.c index 2ce32fe4f3..7e09629ddb 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -29,6 +29,7 @@ static int run(int argc, char *argv[]) { r = service_parse_argv("systemd-networkd.service", "Manage and configure network devices, create virtual network devices", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index adc550ed24..a790f2d8a3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -6055,6 +6055,7 @@ static int run(int argc, char *argv[]) { /* We take an exclusive lock on this image, since it's our private, ephemeral copy * only owned by us and no one else. */ r = image_path_lock( + arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, np, LOCK_EX|LOCK_NB, arg_privileged ? &tree_global_lock : NULL, @@ -6091,6 +6092,7 @@ static int run(int argc, char *argv[]) { goto finish; r = image_path_lock( + arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, arg_directory, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, arg_privileged ? &tree_global_lock : NULL, @@ -6218,6 +6220,7 @@ static int run(int argc, char *argv[]) { /* Always take an exclusive lock on our own ephemeral copy. */ r = image_path_lock( + arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, np, LOCK_EX|LOCK_NB, arg_privileged ? &tree_global_lock : NULL, @@ -6245,6 +6248,7 @@ static int run(int argc, char *argv[]) { remove_image = true; } else { r = image_path_lock( + arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, arg_privileged ? &tree_global_lock : NULL, diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index e8bcb900ef..68cf916924 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -61,7 +61,7 @@ int bus_image_common_get_os_release( return 1; if (!image->metadata_valid) { - r = image_read_metadata(image, &image_policy_service); + r = image_read_metadata(image, &image_policy_service, m->runtime_scope); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m"); } @@ -539,7 +539,7 @@ int bus_image_common_remove( if (r == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - r = image_remove(image); + r = image_remove(image, m->runtime_scope); if (r < 0) { (void) write(errno_pipe_fd[1], &r, sizeof(r)); _exit(EXIT_FAILURE); @@ -801,7 +801,7 @@ int bus_image_common_mark_read_only( if (r == 0) return 1; /* Will call us back */ - r = image_read_only(image, read_only); + r = image_read_only(image, read_only, m->runtime_scope); if (r < 0) return r; diff --git a/src/portable/portabled.c b/src/portable/portabled.c index 65ceaf40b6..4059de01ed 100644 --- a/src/portable/portabled.c +++ b/src/portable/portabled.c @@ -133,6 +133,7 @@ static int run(int argc, char *argv[]) { "Manage registrations of portable images.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index ea3e6a689c..aa165927a4 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -30,6 +30,7 @@ static int run(int argc, char *argv[]) { "Provide name resolution with caching using DNS, mDNS, LLMNR.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 58777c683b..15875968b7 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -19,6 +19,7 @@ #include "chase.h" #include "chattr-util.h" #include "copy.h" +#include "devnum-util.h" #include "dirent-util.h" #include "discover-image.h" #include "dissect-image.h" @@ -37,6 +38,7 @@ #include "mkdir.h" #include "nulstr-util.h" #include "os-util.h" +#include "path-lookup.h" #include "path-util.h" #include "rm-rf.h" #include "runtime-scope.h" @@ -119,6 +121,15 @@ static const char *const image_root_runtime_table[_IMAGE_CLASS_MAX] = { DEFINE_STRING_TABLE_LOOKUP_TO_STRING(image_root_runtime, ImageClass); +static const char *const image_dirname_table[_IMAGE_CLASS_MAX] = { + [IMAGE_MACHINE] = "machines", + [IMAGE_PORTABLE] = "portables", + [IMAGE_SYSEXT] = "extensions", + [IMAGE_CONFEXT] = "confexts", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(image_dirname, ImageClass); + static Image* image_free(Image *i) { assert(i); @@ -138,7 +149,7 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(Image, image, image_free); DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(image_hash_ops, char, string_hash_func, string_compare_func, Image, image_unref); -static char** image_settings_path(Image *image) { +static char** image_settings_path(Image *image, RuntimeScope scope) { _cleanup_strv_free_ char **l = NULL; _cleanup_free_ char *fn = NULL; size_t i = 0; @@ -146,7 +157,7 @@ static char** image_settings_path(Image *image) { assert(image); - l = new0(char*, 4); + l = new0(char*, 5); if (!l) return NULL; @@ -154,7 +165,41 @@ static char** image_settings_path(Image *image) { if (!fn) return NULL; - FOREACH_STRING(s, "/etc/systemd/nspawn", "/run/systemd/nspawn") { + static const uint64_t system_locations[] = { + SD_PATH_SYSTEM_CONFIGURATION, + SD_PATH_SYSTEM_RUNTIME, + SD_PATH_SYSTEM_LIBRARY_PRIVATE, + UINT64_MAX + }; + static const uint64_t user_locations[] = { + SD_PATH_USER_CONFIGURATION, + SD_PATH_USER_RUNTIME, + SD_PATH_USER_LIBRARY_PRIVATE, + UINT64_MAX + }; + const uint64_t *locations; + + switch (scope) { + case RUNTIME_SCOPE_SYSTEM: + locations = system_locations; + break; + + case RUNTIME_SCOPE_USER: + locations = user_locations; + break; + + default: + assert_not_reached(); + } + + for (size_t k = 0; locations[k] != UINT64_MAX; k++) { + _cleanup_free_ char *s = NULL; + r = sd_path_lookup(locations[k], "systemd/nspawn", &s); + if (r == -ENXIO) + continue; + if (r < 0) + return NULL; + l[i] = path_join(s, fn); if (!l[i]) return NULL; @@ -1086,7 +1131,7 @@ int image_discover( return 0; } -int image_remove(Image *i) { +int image_remove(Image *i, RuntimeScope scope) { _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; _cleanup_strv_free_ char **settings = NULL; _cleanup_free_ char *roothash = NULL; @@ -1097,7 +1142,7 @@ int image_remove(Image *i) { if (image_is_vendor(i) || image_is_host(i)) return -EROFS; - settings = image_settings_path(i); + settings = image_settings_path(i, scope); if (!settings) return -ENOMEM; @@ -1106,7 +1151,7 @@ int image_remove(Image *i) { return r; /* Make sure we don't interfere with a running nspawn */ - r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); + r = image_path_lock(scope, i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); if (r < 0) return r; @@ -1192,7 +1237,7 @@ int image_rename(Image *i, const char *new_name, RuntimeScope scope) { if (image_is_vendor(i) || image_is_host(i)) return -EROFS; - settings = image_settings_path(i); + settings = image_settings_path(i, scope); if (!settings) return -ENOMEM; @@ -1201,14 +1246,14 @@ int image_rename(Image *i, const char *new_name, RuntimeScope scope) { return r; /* Make sure we don't interfere with a running nspawn */ - r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); + r = image_path_lock(scope, i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); if (r < 0) return r; /* Make sure nobody takes the new name, between the time we * checked it is currently unused in all search paths, and the * time we take possession of it */ - r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock); + r = image_name_lock(scope, new_name, LOCK_EX|LOCK_NB, &name_lock); if (r < 0) return r; @@ -1299,11 +1344,64 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch return copy_file_atomic(path, rs, 0664, COPY_REFLINK); } +static int get_pool_directory( + RuntimeScope scope, + ImageClass class, + const char *fname, + const char *suffix, + char **ret) { + + int r; + + assert(scope >= 0); + assert(scope < _RUNTIME_SCOPE_MAX); + assert(class >= 0); + assert(class < _IMAGE_CLASS_MAX); + assert(ret); + + _cleanup_free_ char *root = NULL; + switch (scope) { + + case RUNTIME_SCOPE_SYSTEM: + r = sd_path_lookup(SD_PATH_SYSTEM_STATE_PRIVATE, /* suffix= */ NULL, &root); + break; + + case RUNTIME_SCOPE_USER: + r = sd_path_lookup(SD_PATH_USER_STATE_PRIVATE, /* suffix= */ NULL, &root); + break; + + default: + return -EOPNOTSUPP; + } + if (r < 0) + return r; + + const char *n = image_dirname_to_string(class); + if (!n) + return -EOPNOTSUPP; + + _cleanup_free_ char *j = NULL; + const char *fn; + if (fname && suffix) { + j = strjoin(fname, suffix); + if (!j) + return -ENOMEM; + fn = j; + } else + fn = fname ?: suffix; + + _cleanup_free_ char *p = path_join(root, n, fn); + if (!p) + return -ENOMEM; + + *ret = TAKE_PTR(p); + return 0; +} + int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope) { _cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT; _cleanup_strv_free_ char **settings = NULL; _cleanup_free_ char *roothash = NULL; - const char *new_path; int r; assert(i); @@ -1311,7 +1409,7 @@ int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope sco if (!image_name_is_valid(new_name)) return -EINVAL; - settings = image_settings_path(i); + settings = image_settings_path(i, scope); if (!settings) return -ENOMEM; @@ -1322,11 +1420,11 @@ int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope sco /* Make sure nobody takes the new name, between the time we * checked it is currently unused in all search paths, and the * time we take possession of it */ - r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock); + r = image_name_lock(scope, new_name, LOCK_EX|LOCK_NB, &name_lock); if (r < 0) return r; - r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL); + r = image_find(scope, i->class, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -1335,11 +1433,14 @@ int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope sco switch (i->type) { case IMAGE_SUBVOLUME: - case IMAGE_DIRECTORY: + case IMAGE_DIRECTORY: { /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain * directory. */ - new_path = strjoina("/var/lib/machines/", new_name); + _cleanup_free_ char *new_path = NULL; + r = get_pool_directory(scope, i->class, new_name, /* suffix= */ NULL, &new_path); + if (r < 0) + return r; r = btrfs_subvol_snapshot_at(AT_FDCWD, i->path, AT_FDCWD, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | @@ -1353,19 +1454,23 @@ int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope sco (void) btrfs_subvol_auto_qgroup(new_path, 0, true); break; + } - case IMAGE_RAW: - new_path = strjoina("/var/lib/machines/", new_name, ".raw"); + case IMAGE_RAW: { + _cleanup_free_ char *new_path = NULL; + r = get_pool_directory(scope, i->class, new_name, ".raw", &new_path); + if (r < 0) + return r; r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, COPY_REFLINK|COPY_CRTIME|COPY_NOCOW_AFTER); break; + } case IMAGE_BLOCK: default: return -EOPNOTSUPP; } - if (r < 0) return r; @@ -1382,7 +1487,7 @@ int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope sco return 0; } -int image_read_only(Image *i, bool b) { +int image_read_only(Image *i, bool b, RuntimeScope scope) { _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; int r; @@ -1392,7 +1497,7 @@ int image_read_only(Image *i, bool b) { return -EROFS; /* Make sure we don't interfere with a running nspawn */ - r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); + r = image_path_lock(scope, i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); if (r < 0) return r; @@ -1469,12 +1574,33 @@ int image_read_only(Image *i, bool b) { return 0; } -static void make_lock_dir(void) { - (void) mkdir_p("/run/systemd/nspawn", 0755); - (void) mkdir("/run/systemd/nspawn/locks", 0700); +static int make_lock_dir(RuntimeScope scope) { + int r; + + _cleanup_free_ char *p = NULL; + r = runtime_directory_generic(scope, "systemd", &p); + if (r < 0) + return r; + + _cleanup_close_ int pfd = open_mkdir_at(AT_FDCWD, p, O_CLOEXEC, 0755); + if (pfd < 0) + return pfd; + + _cleanup_close_ int nfd = open_mkdir_at(pfd, "nspawn", O_CLOEXEC, 0755); + if (nfd < 0) + return nfd; + + r = RET_NERRNO(mkdirat(nfd, "locks", 0700)); + if (r == -EEXIST) + return 0; + if (r < 0) + return r; + + return 1; } int image_path_lock( + RuntimeScope scope, const char *path, int operation, LockFile *ret_global, @@ -1490,7 +1616,7 @@ int image_path_lock( assert(ret_local); /* Locks an image path. This actually creates two locks: one "local" one, next to the image path - * itself, which might be shared via NFS. And another "global" one, in /run, that uses the + * itself, which might be shared via NFS. And another "global" one, in /run/, that uses the * device/inode number. This has the benefit that we can even lock a tree that is a mount point, * correctly. */ @@ -1534,15 +1660,21 @@ int image_path_lock( } if (ret_global) { - if (stat(path, &st) >= 0) { + if (stat(path, &st) < 0) + log_debug_errno(errno, "Failed to stat() image '%s', not locking image: %m", path); + else { + r = runtime_directory_generic(scope, "systemd/nspawn/locks/", &p); + if (r < 0) + return r; + if (S_ISBLK(st.st_mode)) - r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev)); + r = strextendf(&p, "block-" DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(st.st_rdev)); else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) - r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino); + r = strextendf(&p, "inode-%" PRIu64 ":%" PRIu64, (uint64_t) st.st_dev, (uint64_t) st.st_ino); else return -ENOTTY; if (r < 0) - return -ENOMEM; + return r; } } @@ -1551,15 +1683,15 @@ int image_path_lock( if (!path_startswith(path, "/dev/")) { r = make_lock_file_for(path, operation, &t); if (r < 0) { - if (!exclusive && r == -EROFS) - log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path); - else + if (exclusive || r != -EROFS) return r; + + log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path); } } if (p) { - make_lock_dir(); + (void) make_lock_dir(scope); r = make_lock_file(p, operation, ret_global); if (r < 0) { @@ -1599,36 +1731,39 @@ int image_set_limit(Image *i, uint64_t referenced_max) { return 0; } -int image_set_pool_limit(ImageClass class, uint64_t referenced_max) { - const char *dir; +int image_set_pool_limit(RuntimeScope scope, ImageClass class, uint64_t referenced_max) { int r; + assert(scope >= 0 && scope < _RUNTIME_SCOPE_MAX); assert(class >= 0 && class < _IMAGE_CLASS_MAX); - dir = image_root_to_string(class); + _cleanup_free_ char *pool = NULL; + r = get_pool_directory(scope, class, /* fname= */ NULL, /* suffix= */ NULL, &pool); + if (r < 0) + return r; - r = btrfs_qgroup_set_limit(dir, /* qgroupid = */ 0, referenced_max); + r = btrfs_qgroup_set_limit(pool, /* qgroupid = */ 0, referenced_max); if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) return r; if (r < 0) - log_debug_errno(r, "Failed to set limit on btrfs quota group for '%s', ignoring: %m", dir); + log_debug_errno(r, "Failed to set limit on btrfs quota group for '%s', ignoring: %m", pool); - r = btrfs_subvol_set_subtree_quota_limit(dir, /* subvol_id = */ 0, referenced_max); + r = btrfs_subvol_set_subtree_quota_limit(pool, /* subvol_id = */ 0, referenced_max); if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) return r; if (r < 0) - return log_debug_errno(r, "Failed to set subtree quota limit for '%s': %m", dir); + return log_debug_errno(r, "Failed to set subtree quota limit for '%s': %m", pool); return 0; } -int image_read_metadata(Image *i, const ImagePolicy *image_policy) { +int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope scope) { _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; int r; assert(i); - r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock); + r = image_path_lock(scope, i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock); if (r < 0) return r; @@ -1758,8 +1893,13 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy) { return 0; } -int image_name_lock(const char *name, int operation, LockFile *ret) { - const char *p; +int image_name_lock( + RuntimeScope scope, + const char *name, + int operation, + LockFile *ret) { + + int r; assert(name); assert(ret); @@ -1777,9 +1917,16 @@ int image_name_lock(const char *name, int operation, LockFile *ret) { return 0; } - make_lock_dir(); + (void) make_lock_dir(scope); + + _cleanup_free_ char *p = NULL; + r = runtime_directory_generic(scope, "systemd/nspawn/locks/name-", &p); + if (r < 0) + return r; + + if (!strextend(&p, name)) + return -ENOMEM; - p = strjoina("/run/systemd/nspawn/locks/name-", name); return make_lock_file(p, operation, ret); } diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h index 60f5a4dce1..55476259d7 100644 --- a/src/shared/discover-image.h +++ b/src/shared/discover-image.h @@ -55,21 +55,21 @@ int image_from_path(const char *path, Image **ret); int image_find_harder(RuntimeScope scope, ImageClass class, const char *name_or_path, const char *root, Image **ret); int image_discover(RuntimeScope scope, ImageClass class, const char *root, Hashmap **images); -int image_remove(Image *i); +int image_remove(Image *i, RuntimeScope scope); int image_rename(Image *i, const char *new_name, RuntimeScope scope); int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope); -int image_read_only(Image *i, bool b); +int image_read_only(Image *i, bool b, RuntimeScope scope); const char* image_type_to_string(ImageType t) _const_; ImageType image_type_from_string(const char *s) _pure_; -int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local); -int image_name_lock(const char *name, int operation, LockFile *ret); +int image_path_lock(RuntimeScope scope, const char *path, int operation, LockFile *global, LockFile *local); +int image_name_lock(RuntimeScope scope, const char *name, int operation, LockFile *ret); int image_set_limit(Image *i, uint64_t referenced_max); -int image_set_pool_limit(ImageClass class, uint64_t referenced_max); +int image_set_pool_limit(RuntimeScope scope, ImageClass class, uint64_t referenced_max); -int image_read_metadata(Image *i, const ImagePolicy *image_policy); +int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope scope); bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image); diff --git a/src/shared/service-util.c b/src/shared/service-util.c index 2645fe2c40..70d59af6c5 100644 --- a/src/shared/service-util.c +++ b/src/shared/service-util.c @@ -8,9 +8,19 @@ #include "bus-object.h" #include "log.h" #include "pretty-print.h" +#include "runtime-scope.h" #include "service-util.h" -static int help(const char *program_path, const char *service, const char *description, bool bus_introspect) { +typedef enum HelpFlags { + HELP_WITH_BUS_INTROSPECT = 1 << 0, + HELP_WITH_RUNTIME_SCOPE = 1 << 1, +} HelpFlags; + +static int help(const char *program_path, + const char *service, + const char *description, + HelpFlags flags) { + _cleanup_free_ char *link = NULL; int r; @@ -25,6 +35,7 @@ static int help(const char *program_path, const char *service, const char *descr " -h --help Show this help\n" " --version Show package version\n" "%8$s" + "%9$s" "\nSee the %2$s for details.\n", program_path, link, @@ -33,7 +44,9 @@ static int help(const char *program_path, const char *service, const char *descr ansi_highlight(), ansi_normal(), description, - bus_introspect ? " --bus-introspect=PATH Write D-Bus XML introspection data\n" : ""); + FLAGS_SET(flags, HELP_WITH_BUS_INTROSPECT) ? " --bus-introspect=PATH Write D-Bus XML introspection data\n" : "", + FLAGS_SET(flags, HELP_WITH_RUNTIME_SCOPE) ? " --system Start service in system mode\n" + " --user Start service in user mode\n" : ""); return 0; /* No further action */ } @@ -42,17 +55,22 @@ int service_parse_argv( const char *service, const char *description, const BusObjectImplementation* const* bus_objects, + RuntimeScope *runtime_scope, int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_BUS_INTROSPECT, + ARG_SYSTEM, + ARG_USER, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "user", no_argument, NULL, ARG_USER }, {} }; @@ -65,7 +83,11 @@ int service_parse_argv( switch (c) { case 'h': - return help(argv[0], service, description, bus_objects); + return help(argv[0], + service, + description, + (bus_objects ? HELP_WITH_BUS_INTROSPECT : 0) | + (runtime_scope ? HELP_WITH_RUNTIME_SCOPE : 0)); case ARG_VERSION: return version(); @@ -76,6 +98,14 @@ int service_parse_argv( optarg, bus_objects); + case ARG_SYSTEM: + case ARG_USER: + if (!runtime_scope) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This service cannot be run in --system or --user mode, refusing."); + + *runtime_scope = c == ARG_SYSTEM ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER; + break; + case '?': return -EINVAL; diff --git a/src/shared/service-util.h b/src/shared/service-util.h index af36354e80..462ba2b3fa 100644 --- a/src/shared/service-util.h +++ b/src/shared/service-util.h @@ -7,4 +7,5 @@ int service_parse_argv( const char *service, const char *description, const BusObjectImplementation* const* bus_objects, + RuntimeScope *runtime_scope, int argc, char *argv[]); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index c8c75d68bd..5255ac1df1 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -2127,7 +2127,7 @@ static int image_discover_and_read_metadata(ImageClass image_class, Hashmap **re return log_error_errno(r, "Failed to discover images: %m"); HASHMAP_FOREACH(img, images) { - r = image_read_metadata(img, image_class_info[image_class].default_image_policy); + r = image_read_metadata(img, image_class_info[image_class].default_image_policy, RUNTIME_SCOPE_SYSTEM); if (r < 0) return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name); } diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index b1438ff825..1ade24b374 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -2079,6 +2079,7 @@ static int run(int argc, char *argv[]) { "System update management service.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 662cc29ac5..6e21d1a73a 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -1164,6 +1164,7 @@ static int run(int argc, char *argv[]) { "Manage the system clock and timezone and NTP enablement.", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 40305c046b..96d0dd5c2b 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -151,6 +151,7 @@ static int run(int argc, char *argv[]) { r = service_parse_argv("systemd-timesyncd.service", "Network time synchronization", BUS_IMPLEMENTATIONS(&manager_object, &log_control_object), + /* runtime_scope= */ NULL, argc, argv); if (r <= 0) return r; diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in index 47aa5deeed..2dac42a673 100644 --- a/units/systemd-machined.service.in +++ b/units/systemd-machined.service.in @@ -11,7 +11,6 @@ Description=Virtual Machine and Container Registration Service Documentation=man:systemd-machined.service(8) Documentation=man:org.freedesktop.machine1(5) - Wants=machine.slice After=machine.slice RequiresMountsFor=/var/lib/machines diff --git a/units/user/meson.build b/units/user/meson.build index d8d3d9fdac..7f04cf191c 100644 --- a/units/user/meson.build +++ b/units/user/meson.build @@ -18,6 +18,16 @@ units = [ 'file' : 'machines.target', 'conditions' : ['ENABLE_MACHINED'], }, + { + 'file' : 'systemd-machined.service.in', + 'conditions' : ['ENABLE_MACHINED'], + 'symlinks' : ['dbus-org.freedesktop.machine1.service'], + }, + { + 'file' : 'systemd-machined.socket', + 'conditions' : ['ENABLE_MACHINED'], + 'symlinks' : ['sockets.target.wants/'], + }, { 'file' : 'paths.target' }, { 'file' : 'printer.target' }, { 'file' : 'session.slice' }, diff --git a/units/user/systemd-machined.service.in b/units/user/systemd-machined.service.in new file mode 100644 index 0000000000..9f4208e78a --- /dev/null +++ b/units/user/systemd-machined.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=Virtual Machine and Container Registration Service +Documentation=man:systemd-machined.service(8) +Documentation=man:org.freedesktop.machine1(5) +Wants=machine.slice +After=machine.slice + +[Service] +BusName=org.freedesktop.machine1 +ExecStart={{LIBEXECDIR}}/systemd-machined --user +LockPersonality=yes +MemoryDenyWriteExecute=yes +NoNewPrivileges=yes +RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 +RestrictRealtime=yes +SystemCallArchitectures=native +SystemCallErrorNumber=EPERM +SystemCallFilter=@system-service @mount +{{SERVICE_WATCHDOG}} diff --git a/units/user/systemd-machined.socket b/units/user/systemd-machined.socket new file mode 100644 index 0000000000..d368215e98 --- /dev/null +++ b/units/user/systemd-machined.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=Virtual Machine and Container Registration Service Socket +Documentation=man:systemd-machined.service(8) + +[Socket] +ListenStream=%t/systemd/machine/io.systemd.Machine +ListenStream=%t/systemd/machine/io.systemd.MachineImage +FileDescriptorName=varlink +SocketMode=0600