diff options
Diffstat (limited to 'src/home/home-util.c')
-rw-r--r-- | src/home/home-util.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/home/home-util.c b/src/home/home-util.c new file mode 100644 index 0000000..c777d7b --- /dev/null +++ b/src/home/home-util.c @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dns-domain.h" +#include "home-util.h" +#include "libcrypt-util.h" +#include "memory-util.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" + +bool suitable_user_name(const char *name) { + + /* Checks whether the specified name is suitable for management via homed. Note that client-side + * we usually validate with the simple valid_user_group_name(), while server-side we are a bit more + * restrictive, so that we can change the rules server-side without having to update things + * client-side too. */ + + if (!valid_user_group_name(name, 0)) + return false; + + /* We generally rely on NSS to tell us which users not to care for, but let's filter out some + * particularly well-known users. */ + if (STR_IN_SET(name, + "root", + "nobody", + NOBODY_USER_NAME, NOBODY_GROUP_NAME)) + return false; + + /* Let's also defend our own namespace, as well as Debian's (unwritten?) logic of prefixing system + * users with underscores. */ + if (STARTSWITH_SET(name, "systemd-", "_")) + return false; + + return true; +} + +int suitable_realm(const char *realm) { + _cleanup_free_ char *normalized = NULL; + int r; + + /* Similar to the above: let's validate the realm a bit stricter server-side than client side */ + + r = dns_name_normalize(realm, 0, &normalized); /* this also checks general validity */ + if (r == -EINVAL) + return 0; + if (r < 0) + return r; + + if (!streq(realm, normalized)) /* is this normalized? */ + return false; + + if (dns_name_is_root(realm)) /* Don't allow top level domain */ + return false; + + return true; +} + +int suitable_image_path(const char *path) { + + return !empty_or_root(path) && + path_is_valid(path) && + path_is_absolute(path); +} + +bool supported_fstype(const char *fstype) { + /* Limit the set of supported file systems a bit, as protection against little tested kernel file + * systems. Also, we only support the resize ioctls for these file systems. */ + return STR_IN_SET(fstype, "ext4", "btrfs", "xfs"); +} + +int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm) { + _cleanup_free_ char *user_name = NULL, *realm = NULL; + const char *c; + int r; + + assert(t); + assert(ret_user_name); + assert(ret_realm); + + c = strchr(t, '@'); + if (!c) { + user_name = strdup(t); + if (!user_name) + return -ENOMEM; + } else { + user_name = strndup(t, c - t); + if (!user_name) + return -ENOMEM; + + realm = strdup(c + 1); + if (!realm) + return -ENOMEM; + } + + if (!suitable_user_name(user_name)) + return -EINVAL; + + if (realm) { + r = suitable_realm(realm); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + } + + *ret_user_name = TAKE_PTR(user_name); + *ret_realm = TAKE_PTR(realm); + + return 0; +} + +int bus_message_append_secret(sd_bus_message *m, UserRecord *secret) { + _cleanup_(erase_and_freep) char *formatted = NULL; + JsonVariant *v; + int r; + + assert(m); + assert(secret); + + if (!FLAGS_SET(secret->mask, USER_RECORD_SECRET)) + return sd_bus_message_append(m, "s", "{}"); + + v = json_variant_by_key(secret->json, "secret"); + if (!v) + return -EINVAL; + + r = json_variant_format(v, 0, &formatted); + if (r < 0) + return r; + + (void) sd_bus_message_sensitive(m); + + return sd_bus_message_append(m, "s", formatted); +} + +const char *home_record_dir(void) { + return secure_getenv("SYSTEMD_HOME_RECORD_DIR") ?: "/var/lib/systemd/home/"; +} |