diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2024-09-16 13:43:38 +0200 |
---|---|---|
committer | Daan De Meyer <daan.j.demeyer@gmail.com> | 2024-10-02 15:07:59 +0200 |
commit | 164ca24d7464253e5f8375226b792ef8f6eaffd0 (patch) | |
tree | facef63d38b5eff053b4ebadca273349996da08a /src/home | |
parent | Move show_menu() to terminal-util.h (diff) | |
download | systemd-164ca24d7464253e5f8375226b792ef8f6eaffd0.tar.xz systemd-164ca24d7464253e5f8375226b792ef8f6eaffd0.zip |
home: Prompt for auxiliary groups in homectl firstboot
Diffstat (limited to 'src/home')
-rw-r--r-- | src/home/homectl.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/home/homectl.c b/src/home/homectl.c index c193715d96..a2678c8140 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -2424,6 +2424,58 @@ static int has_regular_user(void) { return false; } +static int acquire_group_list(char ***ret) { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + _cleanup_strv_free_ char **groups = NULL; + int r; + + assert(ret); + + r = groupdb_all(USERDB_SUPPRESS_SHADOW|USERDB_EXCLUDE_DYNAMIC_USER, &iterator); + if (r == -ENOLINK) + log_debug_errno(r, "No groups found. (Didn't check via Varlink.)"); + else if (r == -ESRCH) + log_debug_errno(r, "No groups found."); + else if (r < 0) + return log_debug_errno(r, "Failed to enumerate groups, ignoring: %m"); + else { + for (;;) { + _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; + + r = groupdb_iterator_get(iterator, &gr); + if (r == -ESRCH) + break; + if (r < 0) + return log_debug_errno(r, "Failed acquire next group: %m"); + + if (!IN_SET(group_record_disposition(gr), USER_REGULAR, USER_SYSTEM)) + continue; + + if (group_record_disposition(gr) == USER_REGULAR) { + _cleanup_(user_record_unrefp) UserRecord *ur = NULL; + + /* Filter groups here that belong to a specific user, and are named like them */ + + r = userdb_by_name(gr->group_name, USERDB_SUPPRESS_SHADOW|USERDB_EXCLUDE_DYNAMIC_USER, &ur); + if (r < 0 && r != -ESRCH) + return log_debug_errno(r, "Failed to check if matching user exists for group '%s': %m", gr->group_name); + + if (r >= 0 && ur->gid == gr->gid && user_record_disposition(ur) == USER_REGULAR) + continue; + } + + r = strv_extend(&groups, gr->group_name); + if (r < 0) + return log_oom(); + } + } + + strv_sort(groups); + + *ret = TAKE_PTR(groups); + return !!*ret; +} + static int create_interactively(void) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *username = NULL; @@ -2476,6 +2528,86 @@ static int create_interactively(void) { if (r < 0) return log_error_errno(r, "Failed to set userName field: %m"); + _cleanup_strv_free_ char **available = NULL, **groups = NULL; + + for (;;) { + _cleanup_free_ char *s = NULL; + unsigned u; + + r = ask_string(&s, + "%s Please enter an auxiliary group for user %s (empty to continue, \"list\" to list available groups): ", + special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), username); + if (r < 0) + return log_error_errno(r, "Failed to query user for auxiliary group: %m"); + + if (isempty(s)) + break; + + if (streq(s, "list")) { + if (!available) { + r = acquire_group_list(&available); + if (r < 0) + log_warning_errno(r, "Failed to enumerate available groups, ignoring: %m"); + if (r == 0) + log_notice("Did not find any available groups"); + if (r <= 0) + continue; + } + + r = show_menu(available, /*n_columns=*/ 3, /*width=*/ 20, /*percentage=*/ 60); + if (r < 0) + return r; + + putchar('\n'); + continue; + }; + + if (available) { + r = safe_atou(s, &u); + if (r >= 0) { + if (u <= 0 || u > strv_length(available)) { + log_error("Specified entry number out of range."); + continue; + } + + log_info("Selected '%s'.", available[u-1]); + + r = strv_extend(&groups, available[u-1]); + if (r < 0) + return log_oom(); + + continue; + } + } + + if (!valid_user_group_name(s, /* flags= */ 0)) { + log_notice("Specified group name is not a valid UNIX group name, try again: %s", s); + continue; + } + + r = groupdb_by_name(s, USERDB_SUPPRESS_SHADOW|USERDB_EXCLUDE_DYNAMIC_USER, /*ret=*/ NULL); + if (r == -ESRCH) { + log_notice("Specified auxiliary group does not exist, try again: %s", s); + continue; + } + if (r < 0) + return log_error_errno(r, "Failed to check if specified group '%s' already exists: %m", s); + + log_info("Selected '%s'.", s); + + r = strv_extend(&groups, s); + if (r < 0) + return log_oom(); + } + + if (groups) { + strv_sort_uniq(groups); + + r = sd_json_variant_set_field_strv(&arg_identity_extra, "memberOf", groups); + if (r < 0) + return log_error_errno(r, "Failed to set memberOf field: %m"); + } + return create_home_common(/* input= */ NULL); } |