From: Lennart Poettering Date: Thu, 20 Feb 2025 09:21:57 +0000 (+0100) Subject: homectl: expose "register" verb to register a user record locally X-Git-Tag: v258-rc1~1143^2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e8801cc5b3e1661965a7c533d10c88856c9b417c;p=thirdparty%2Fsystemd.git homectl: expose "register" verb to register a user record locally --- diff --git a/man/homectl.xml b/man/homectl.xml index 610c69ccc12..1acb338bbb2 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -1197,6 +1197,55 @@ + + register FILE [FILE…] + + Registers one or more users, without creating their home directories. Takes one or + more paths to JSON user record files. If the path is specified as - reads the + JSON user record from standard input. + + Registering a user makes it accessible on the local system without creating a new home + directory. This is particularly useful for making a user accessible on a system it was not originally + created on. + + Here's an example how to make a local user account with its home directory accessible on a + remote system, using SMB/CIFS file sharing. With Samba installed in its default configuration invoke + as root: + + # smbpasswd -a lennart + + Continue as regular user lennart: + +$ homectl update lennart --ssh-authorized-keys=… -N --storage=cifs --cifs-service="//$HOSTNAME/lennart" +$ homectl get-signing-key | ssh targetsystem homectl add-signing-key --key-name="$HOSTNAME".public +$ homectl inspect -E lennart | ssh targetsystem homectl register - +$ ssh lennart@targetsystem + + This first ensures the user account lennart is known to and accessible by + Samba. It then registers a local SSH access that shall be used for accessing this user, and + configures CIFS as default storage for non-local systems on the account. It then adds the local + system's account signing key to the target system. Then it registers the local user account with the + target system. Finally it logs into the account on the target system. The target system will then + connect back via SMB/CIFS to access the home directory. + + + + + + unregister USER… + + Unregisters one or more user accounts. This only removes the user record from the + local system, it does not delete the home directory. The home directory can be readded via the + register or adopt command later, on this or another + system. Note that unregistering a user whose home directory is placed in /home/ + will not make the user disappear from the local user database, as all supported home directories + placed there will show up in the user database. However, the user record will become "unfixated", + i.e. lose its binding to the local system. When logged into it will automatically regain the binding, + and acquire a local UID/GID pair. + + + + remove USER diff --git a/shell-completion/bash/homectl b/shell-completion/bash/homectl index 3bd29fc808b..1b365fbb712 100644 --- a/shell-completion/bash/homectl +++ b/shell-completion/bash/homectl @@ -173,7 +173,7 @@ _homectl() { fi local -A VERBS=( - [STANDALONE]='list lock-all adopt' + [STANDALONE]='list lock-all register unregister adopt' [CREATE]='create' [NAMES]='activate deactivate inspect authenticate remove lock unlock' [NAME]='update passwd' diff --git a/src/home/homectl.c b/src/home/homectl.c index 123fcd99985..12d3c403f9c 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -1596,6 +1596,101 @@ static int verb_adopt_home(int argc, char *argv[], void *userdata) { return ret; } +static int register_home_one(sd_bus *bus, FILE *f, const char *path) { + int r; + + assert(bus); + assert(path); + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + unsigned line = 0, column = 0; + r = sd_json_parse_file(f, path, SD_JSON_PARSE_SENSITIVE, &v, &line, &column); + if (r < 0) + return log_error_errno(r, "[%s:%u:%u] Failed to parse user record: %m", path, line, column); + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + r = bus_message_new_method_call(bus, &m, bus_mgr, "RegisterHome"); + if (r < 0) + return bus_log_create_error(r); + + _cleanup_free_ char *formatted = NULL; + r = sd_json_variant_format(v, /* flags= */ 0, &formatted); + if (r < 0) + return log_error_errno(r, "Failed to format JSON record: %m"); + + r = sd_bus_message_append(m, "s", formatted); + 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) + return log_error_errno(r, "Failed to register home: %s", bus_error_message(&error, r)); + + return 0; +} + +static int verb_register_home(int argc, char *argv[], void *userdata) { + int r; + + _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); + + if (arg_identity) { + if (argc > 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not accepting an arguments if --identity= is specified, refusing."); + + return register_home_one(bus, /* f= */ NULL, arg_identity); + } + + if (argc == 1 || (argc == 2 && streq(argv[1], "-"))) + return register_home_one(bus, /* f= */ stdin, ""); + + r = 0; + STRV_FOREACH(i, strv_skip(argv, 1)) { + if (streq(*i, "-")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Refusing reading from standard input if multiple user records are specified."); + + RET_GATHER(r, register_home_one(bus, /* f= */ NULL, *i)); + } + + return r; +} + +static int verb_unregister_home(int argc, char *argv[], void *userdata) { + int r; + + _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); + + int ret = 0; + 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, "UnregisterHome"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "s", *i); + 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, /* ret_reply= */ NULL); + if (r < 0) + RET_GATHER(ret, log_error_errno(r, "Failed to unregister home: %s", bus_error_message(&error, 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; @@ -2841,6 +2936,8 @@ static int help(int argc, char *argv[], void *userdata) { " 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" + " register PATH… Register a user record locally\n" + " unregister USER… Unregister a user record locally\n" " remove USER… Remove a home area\n" " update USER Update a home area\n" " passwd USER Change password of a home area\n" @@ -5276,6 +5373,8 @@ static int run(int argc, char *argv[]) { { "authenticate", VERB_ANY, VERB_ANY, 0, authenticate_home }, { "create", VERB_ANY, 2, 0, create_home }, { "adopt", VERB_ANY, VERB_ANY, 0, verb_adopt_home }, + { "register", VERB_ANY, VERB_ANY, 0, verb_register_home }, + { "unregister", 2, VERB_ANY, 0, verb_unregister_home }, { "remove", 2, VERB_ANY, 0, remove_home }, { "update", VERB_ANY, 2, 0, update_home }, { "passwd", VERB_ANY, 2, 0, passwd_home },