From: DaanDeMeyer Date: Thu, 3 Jul 2025 19:22:41 +0000 (+0200) Subject: userdb: Add userdb.transient credentials X-Git-Tag: v258-rc1~110 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc43510a139bd3002768c89c2d233158aaf418ca;p=thirdparty%2Fsystemd.git userdb: Add userdb.transient credentials To implement --bind-user in systemd-vmspawn, we need a transient version of these credentials. These are useful when the home directory of the user is mounted into the container/vm and every trace of the user will be (mostly) gone again when the container/vm is shut down. --- diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index 73c36c19153..d436cff5d48 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -475,6 +475,8 @@ userdb.user.* userdb.group.* + userdb.transient.user.* + userdb.transient.group.* Configure JSON user and group records. Read by @@ -499,7 +501,10 @@ userdb.user.foobar the suffix is foobar) must match the user or group name field from the user or group record. - Note that the records are created in /etc/userdb/ + Note that the records created for userdb.user.* and + userdb.group.* credentials are created in /etc/userdb/ and + the records created for userdb.transient.user.* and + userdb.transient.group.* are created in /run/userdb/ (/etc/passwd and /etc/group are not modified). diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index 5c7b8aae458..0c366714174 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -1181,18 +1181,32 @@ static int ssh_authorized_keys(int argc, char *argv[], void *userdata) { return r; } -static int load_credential_one(int credential_dir_fd, const char *name, int userdb_dir_fd) { +static int load_credential_one( + int credential_dir_fd, + const char *name, + int userdb_dir_persist_fd, + int userdb_dir_transient_fd) { + int r; assert(credential_dir_fd >= 0); assert(name); - assert(userdb_dir_fd >= 0); + assert(userdb_dir_persist_fd >= 0); + assert(userdb_dir_transient_fd >= 0); + + const char *suffix = startswith(name, "userdb."); + if (!suffix) + return 0; - const char *user = startswith(name, "userdb.user."); - const char *group = startswith(name, "userdb.group."); + const char *transient = startswith(suffix, "transient."), + *user = startswith(transient ?: suffix, "user."), + *group = startswith(transient ?: suffix, "group."); if (!user && !group) return 0; + const char *userdb_dir = transient ? "/run/userdb" : "/etc/userdb"; + int userdb_dir_fd = transient ? userdb_dir_transient_fd : userdb_dir_persist_fd; + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; unsigned line = 0, column = 0; r = sd_json_parse_file_at(NULL, credential_dir_fd, name, SD_JSON_PARSE_SENSITIVE, &v, &line, &column); @@ -1350,12 +1364,12 @@ static int load_credential_one(int credential_dir_fd, const char *name, int user r = write_string_file_at(userdb_dir_fd, fn, formatted, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); if (r < 0) - return log_error_errno(r, "Failed to write JSON record to /etc/userdb/%s: %m", fn); + return log_error_errno(r, "Failed to write JSON record to %s/%s: %m", userdb_dir, fn); if (symlinkat(fn, userdb_dir_fd, link) < 0) return log_error_errno(errno, "Failed to create symlink from %s to %s: %m", link, fn); - log_info("Installed /etc/userdb/%s from credential.", fn); + log_info("Installed %s/%s from credential.", userdb_dir, fn); if ((ur && !sd_json_variant_is_blank_object(ur_privileged->json)) || (gr && !sd_json_variant_is_blank_object(gr_privileged->json))) { @@ -1371,7 +1385,7 @@ static int load_credential_one(int credential_dir_fd, const char *name, int user r = write_string_file_at(userdb_dir_fd, fn, formatted, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MODE_0600); if (r < 0) - return log_error_errno(r, "Failed to write JSON record to /etc/userdb/%s: %m", fn); + return log_error_errno(r, "Failed to write JSON record to %s/%s: %m", userdb_dir, fn); link = mfree(link); @@ -1386,7 +1400,7 @@ static int load_credential_one(int credential_dir_fd, const char *name, int user if (symlinkat(fn, userdb_dir_fd, link) < 0) return log_error_errno(errno, "Failed to create symlink from %s to %s: %m", link, fn); - log_info("Installed /etc/userdb/%s from credential.", fn); + log_info("Installed %s/%s from credential.", userdb_dir, fn); } if (ur) @@ -1399,7 +1413,7 @@ static int load_credential_one(int credential_dir_fd, const char *name, int user if (fd < 0) return log_error_errno(errno, "Failed to create %s: %m", membership); - log_info("Installed /etc/userdb/%s from credential.", membership); + log_info("Installed %s/%s from credential.", userdb_dir, membership); } else STRV_FOREACH(u, gr->members) { @@ -1411,7 +1425,7 @@ static int load_credential_one(int credential_dir_fd, const char *name, int user if (fd < 0) return log_error_errno(errno, "Failed to create %s: %m", membership); - log_info("Installed /etc/userdb/%s from credential.", membership); + log_info("Installed %s/%s from credential.", userdb_dir, membership); } if (ur && user_record_disposition(ur) == USER_REGULAR) { @@ -1461,13 +1475,21 @@ static int load_credentials(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to enumerate credentials: %m"); - _cleanup_close_ int userdb_dir_fd = xopenat_full( - AT_FDCWD, "/etc/userdb", - /* open_flags= */ O_DIRECTORY|O_CREAT|O_CLOEXEC, - /* xopen_flags= */ XO_LABEL, - /* mode= */ 0755); - if (userdb_dir_fd < 0) - return log_error_errno(userdb_dir_fd, "Failed to open %s: %m", "/etc/userdb/"); + _cleanup_close_ int userdb_persist_dir_fd = xopenat_full( + AT_FDCWD, "/etc/userdb", + /* open_flags= */ O_DIRECTORY|O_CREAT|O_CLOEXEC, + /* xopen_flags= */ XO_LABEL, + /* mode= */ 0755); + if (userdb_persist_dir_fd < 0) + return log_error_errno(userdb_persist_dir_fd, "Failed to open /etc/userdb/: %m"); + + _cleanup_close_ int userdb_transient_dir_fd = xopenat_full( + AT_FDCWD, "/run/userdb", + /* open_flags= */ O_DIRECTORY|O_CREAT|O_CLOEXEC, + /* xopen_flags= */ XO_LABEL, + /* mode= */ 0755); + if (userdb_transient_dir_fd < 0) + return log_error_errno(userdb_transient_dir_fd, "Failed to open /run/userdb/: %m"); FOREACH_ARRAY(i, des->entries, des->n_entries) { struct dirent *de = *i; @@ -1475,7 +1497,11 @@ static int load_credentials(int argc, char *argv[], void *userdata) { if (de->d_type != DT_REG) continue; - RET_GATHER(r, load_credential_one(credential_dir_fd, de->d_name, userdb_dir_fd)); + RET_GATHER(r, load_credential_one( + credential_dir_fd, + de->d_name, + userdb_persist_dir_fd, + userdb_transient_dir_fd)); } return r; diff --git a/units/systemd-userdb-load-credentials.service b/units/systemd-userdb-load-credentials.service index 5bcd6d18966..e926a03dd6a 100644 --- a/units/systemd-userdb-load-credentials.service +++ b/units/systemd-userdb-load-credentials.service @@ -26,6 +26,8 @@ RemainAfterExit=yes ExecStart=userdbctl load-credentials ImportCredential=userdb.user.* ImportCredential=userdb.group.* +ImportCredential=userdb.transient.user.* +ImportCredential=userdb.transient.group.* [Install] WantedBy=sysinit.target