<xi:include href="version-info.xml" xpointer="v245"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>adopt</command> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>…]</term>
+
+ <listitem><para>Adopts one or more existing home directories on the local system. Takes one or more paths to
+ <filename>*.home</filename> LUKS home directories or <filename>*.homedir/</filename> standalone home
+ directories or subvolumes previously created by <filename>systemd-homed</filename> and makes them
+ available locally for login. The referenced files are not moved. This is an alternative for moving
+ such home directories into <filename>/home/</filename> (where they would be picked up
+ automatically).</para>
+
+ <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+ </varlistentry>
+
<varlistentry>
<term><command>remove</command> <replaceable>USER</replaceable></term>
@org.freedesktop.systemd1.Privileged("true")
DeactivateHome(in s user_name);
RegisterHome(in s user_record);
+ AdoptHome(in s image_path,
+ in t flags);
UnregisterHome(in s user_name);
CreateHome(in s user_record);
CreateHomeEx(in s user_record,
<variablelist class="dbus-method" generated="True" extra-ref="RegisterHome()"/>
+ <variablelist class="dbus-method" generated="True" extra-ref="AdoptHome()"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="UnregisterHome()"/>
<variablelist class="dbus-method" generated="True" extra-ref="CreateHome()"/>
is useful to register home directories locally that are not located where
<filename>systemd-homed.service</filename> would find them automatically.</para>
+ <para><function>AdoptHome()</function> also registers a new home directory locally. It takes a path to
+ a home directory itself, and will register it locally. This only works for <filename>*.home</filename>
+ and <filename>*.homedir/</filename> home directories. This operation is done automatically for all such
+ home areas showing up in <filename>/home/</filename>, but may be requested explicitly with this call for
+ directories elsewhere. The <varname>flags</varname> must be set to zero, currently.</para>
+
<para><function>UnregisterHome()</function> unregisters an existing home directory. It takes a user
name as argument and undoes what <function>RegisterHome()</function> does. It does not attempt to
remove the home directory itself, it just unregisters it with the local system. Note that if the home
<title>The Manager Object</title>
<para><function>ActivateHomeIfReferenced()</function>, <function>RefHomeUnrestricted()</function>,
<function>CreateHomeEx()</function>, and <function>UpdateHomeEx()</function> were added in version 256.</para>
- <para><function>ListSigningKeys()</function>, <function>GetSigningKey()</function>,
- <function>AddSigningKey()</function>, and <function>RemoveSigningKey()</function> were added in version
- 258.</para>
+ <para><function>AdoptHome()</function>, <function>ListSigningKeys()</function>,
+ <function>GetSigningKey()</function>, <function>AddSigningKey()</function>, and
+ <function>RemoveSigningKey()</function> were added in version 258.</para>
</refsect2>
<refsect2>
<title>Home Objects</title>
fi
local -A VERBS=(
- [STANDALONE]='list lock-all'
+ [STANDALONE]='list lock-all adopt'
[CREATE]='create'
[NAMES]='activate deactivate inspect authenticate remove lock unlock'
[NAME]='update passwd'
return create_home_common(/* input= */ NULL, /* show_enforce_password_policy_hint= */ true);
}
+static int verb_adopt_home(int argc, char *argv[], void *userdata) {
+ int r, ret = 0;
+
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ r = acquire_bus(&bus);
+ if (r < 0)
+ return r;
+
+ (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
+
+ STRV_FOREACH(i, strv_skip(argv, 1)) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ r = bus_message_new_method_call(bus, &m, bus_mgr, "AdoptHome");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "st", *i, UINT64_C(0));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Failed to adopt home: %s", bus_error_message(&error, r));
+ if (ret == 0)
+ ret = r;
+ }
+ }
+
+ return ret;
+}
+
static int remove_home(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r, ret = 0;
" inspect USER… Inspect a home area\n"
" authenticate USER… Authenticate a home area\n"
" create USER Create a home area\n"
+ " adopt PATH… Add an existing home area on this system\n"
" remove USER… Remove a home area\n"
" update USER Update a home area\n"
" passwd USER Change password of a home area\n"
{ "inspect", VERB_ANY, VERB_ANY, 0, inspect_home },
{ "authenticate", VERB_ANY, VERB_ANY, 0, authenticate_home },
{ "create", VERB_ANY, 2, 0, create_home },
+ { "adopt", VERB_ANY, VERB_ANY, 0, verb_adopt_home },
{ "remove", 2, VERB_ANY, 0, remove_home },
{ "update", VERB_ANY, 2, 0, update_home },
{ "passwd", VERB_ANY, 2, 0, passwd_home },
return sd_bus_reply_method_return(message, NULL);
}
+static int method_adopt_home(
+ sd_bus_message *message,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = ASSERT_PTR(userdata);
+ int r;
+
+ assert(message);
+
+ const char *image_path = NULL;
+ uint64_t flags = 0;
+ r = sd_bus_message_read(message, "st", &image_path, &flags);
+ if (r < 0)
+ return r;
+
+ if (!path_is_absolute(image_path) || !path_is_safe(image_path))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path is not absolute or not valid: %s", image_path);
+ if (flags != 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags field must be zero.");
+
+ r = bus_verify_polkit_async(
+ message,
+ "org.freedesktop.home1.create-home",
+ /* details= */ NULL,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ r = manager_adopt_home(m, image_path);
+ if (r == -EMEDIUMTYPE)
+ return sd_bus_error_setf(error, BUS_ERROR_UNRECOGNIZED_HOME_FORMAT, "Unrecognized format of home directory: %s", image_path);
+ if (r < 0)
+ return r;
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static int method_unregister_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return generic_home_method(userdata, message, bus_home_method_unregister, error);
}
SD_BUS_NO_RESULT,
method_register_home,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("AdoptHome",
+ SD_BUS_ARGS("s", image_path, "t", flags),
+ SD_BUS_NO_RESULT,
+ method_adopt_home,
+ SD_BUS_VTABLE_UNPRIVILEGED),
/* Remove the JSON record from homed, but don't remove actual $HOME */
SD_BUS_METHOD_WITH_ARGS("UnregisterHome",
else if (FLAGS_SET(event->mask, IN_MOVED_TO))
log_debug("%s has been moved in, having a look.", j);
- (void) manager_assess_image(m, -1, get_home_root(), event->name);
+ (void) manager_assess_image(m, /* dir_fd= */ -EBADF, get_home_root(), event->name);
(void) bus_manager_emit_auto_login_changed(m);
}
assert(dir_path);
assert(dentry_name);
+ /* Maybe registers the specified .home or .homedir as a home we manage. Returns:
+ *
+ * -EMEDIUMTYPE: Not a dir with .homedir suffix or a file with .home suffix */
+
luks_suffix = endswith(dentry_name, ".home");
if (luks_suffix)
directory_suffix = NULL;
/* Early filter out: by name */
if (!luks_suffix && !directory_suffix)
- return 0;
+ return -EMEDIUMTYPE;
path = path_join(dir_path, dentry_name);
if (!path)
_cleanup_free_ char *n = NULL, *user_name = NULL, *realm = NULL;
if (!luks_suffix)
- return 0;
+ return -EMEDIUMTYPE;
n = strndup(dentry_name, luks_suffix - dentry_name);
if (!n)
r = split_user_name_realm(n, &user_name, &realm);
if (r == -EINVAL) /* Not the right format: ignore */
- return 0;
+ return -EMEDIUMTYPE;
if (r < 0)
return log_error_errno(r, "Failed to split image name into user name/realm: %m");
UserStorage storage;
if (!directory_suffix)
- return 0;
+ return -EMEDIUMTYPE;
n = strndup(dentry_name, directory_suffix - dentry_name);
if (!n)
r = split_user_name_realm(n, &user_name, &realm);
if (r == -EINVAL) /* Not the right format: ignore */
- return 0;
+ return -EMEDIUMTYPE;
if (r < 0)
return log_error_errno(r, "Failed to split image name into user name/realm: %m");
return manager_add_home_by_image(m, user_name, realm, path, NULL, storage, st.st_uid);
}
- return 0;
+ return -EMEDIUMTYPE;
+}
+
+int manager_adopt_home(Manager *m, const char *path) {
+ int r;
+
+ assert(m);
+ assert(path);
+
+ _cleanup_free_ char *fn = NULL;
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return r;
+
+ _cleanup_free_ char *dir = NULL;
+ r = path_extract_directory(path, &dir);
+ if (r < 0)
+ return r;
+
+ return manager_assess_image(m, /* dir_fd= */ -EBADF, dir, fn);
}
int manager_enumerate_images(Manager *m) {
int manager_verify_user_record(Manager *m, UserRecord *hr);
+int manager_adopt_home(Manager *m, const char *path);
+
int manager_acquire_key_pair(Manager *m);
int manager_sign_user_record(Manager *m, UserRecord *u, UserRecord **ret, sd_bus_error *error);
SD_BUS_ERROR_MAP(BUS_ERROR_REBALANCE_NOT_NEEDED, EALREADY),
SD_BUS_ERROR_MAP(BUS_ERROR_HOME_NOT_REFERENCED, EBADR),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_KEY, ENOKEY),
+ SD_BUS_ERROR_MAP(BUS_ERROR_UNRECOGNIZED_HOME_FORMAT, EMEDIUMTYPE),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_UPDATE_CANDIDATE, EALREADY),
#define BUS_ERROR_REBALANCE_NOT_NEEDED "org.freedesktop.home1.RebalanceNotNeeded"
#define BUS_ERROR_HOME_NOT_REFERENCED "org.freedesktop.home1.HomeNotReferenced"
#define BUS_ERROR_NO_SUCH_KEY "org.freedesktop.home1.NoSuchKey"
+#define BUS_ERROR_UNRECOGNIZED_HOME_FORMAT "org.freedesktop.home1.UnrecognizedHomeFormat"
#define BUS_ERROR_NO_UPDATE_CANDIDATE "org.freedesktop.sysupdate1.NoCandidate"