summaryrefslogtreecommitdiffstats
path: root/src/home
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2024-09-16 13:43:38 +0200
committerDaan De Meyer <daan.j.demeyer@gmail.com>2024-10-02 15:07:59 +0200
commit164ca24d7464253e5f8375226b792ef8f6eaffd0 (patch)
treefacef63d38b5eff053b4ebadca273349996da08a /src/home
parentMove show_menu() to terminal-util.h (diff)
downloadsystemd-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.c132
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);
}