1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "dns-domain.h"
4 #include "home-util.h"
5 #include "libcrypt-util.h"
6 #include "memory-util.h"
7 #include "path-util.h"
8 #include "string-util.h"
9 #include "strv.h"
10 #include "user-util.h"
11
suitable_user_name(const char * name)12 bool suitable_user_name(const char *name) {
13
14 /* Checks whether the specified name is suitable for management via homed. Note that client-side
15 * we usually validate with the simple valid_user_group_name(), while server-side we are a bit more
16 * restrictive, so that we can change the rules server-side without having to update things
17 * client-side too. */
18
19 if (!valid_user_group_name(name, 0))
20 return false;
21
22 /* We generally rely on NSS to tell us which users not to care for, but let's filter out some
23 * particularly well-known users. */
24 if (STR_IN_SET(name,
25 "root",
26 "nobody",
27 NOBODY_USER_NAME, NOBODY_GROUP_NAME))
28 return false;
29
30 /* Let's also defend our own namespace, as well as Debian's (unwritten?) logic of prefixing system
31 * users with underscores. */
32 if (STARTSWITH_SET(name, "systemd-", "_"))
33 return false;
34
35 return true;
36 }
37
suitable_realm(const char * realm)38 int suitable_realm(const char *realm) {
39 _cleanup_free_ char *normalized = NULL;
40 int r;
41
42 /* Similar to the above: let's validate the realm a bit stricter server-side than client side */
43
44 r = dns_name_normalize(realm, 0, &normalized); /* this also checks general validity */
45 if (r == -EINVAL)
46 return 0;
47 if (r < 0)
48 return r;
49
50 if (!streq(realm, normalized)) /* is this normalized? */
51 return false;
52
53 if (dns_name_is_root(realm)) /* Don't allow top level domain */
54 return false;
55
56 return true;
57 }
58
suitable_image_path(const char * path)59 int suitable_image_path(const char *path) {
60
61 return !empty_or_root(path) &&
62 path_is_valid(path) &&
63 path_is_absolute(path);
64 }
65
supported_fstype(const char * fstype)66 bool supported_fstype(const char *fstype) {
67 /* Limit the set of supported file systems a bit, as protection against little tested kernel file
68 * systems. Also, we only support the resize ioctls for these file systems. */
69 return STR_IN_SET(fstype, "ext4", "btrfs", "xfs");
70 }
71
split_user_name_realm(const char * t,char ** ret_user_name,char ** ret_realm)72 int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm) {
73 _cleanup_free_ char *user_name = NULL, *realm = NULL;
74 const char *c;
75 int r;
76
77 assert(t);
78 assert(ret_user_name);
79 assert(ret_realm);
80
81 c = strchr(t, '@');
82 if (!c) {
83 user_name = strdup(t);
84 if (!user_name)
85 return -ENOMEM;
86 } else {
87 user_name = strndup(t, c - t);
88 if (!user_name)
89 return -ENOMEM;
90
91 realm = strdup(c + 1);
92 if (!realm)
93 return -ENOMEM;
94 }
95
96 if (!suitable_user_name(user_name))
97 return -EINVAL;
98
99 if (realm) {
100 r = suitable_realm(realm);
101 if (r < 0)
102 return r;
103 if (r == 0)
104 return -EINVAL;
105 }
106
107 *ret_user_name = TAKE_PTR(user_name);
108 *ret_realm = TAKE_PTR(realm);
109
110 return 0;
111 }
112
bus_message_append_secret(sd_bus_message * m,UserRecord * secret)113 int bus_message_append_secret(sd_bus_message *m, UserRecord *secret) {
114 _cleanup_(erase_and_freep) char *formatted = NULL;
115 JsonVariant *v;
116 int r;
117
118 assert(m);
119 assert(secret);
120
121 if (!FLAGS_SET(secret->mask, USER_RECORD_SECRET))
122 return sd_bus_message_append(m, "s", "{}");
123
124 v = json_variant_by_key(secret->json, "secret");
125 if (!v)
126 return -EINVAL;
127
128 r = json_variant_format(v, 0, &formatted);
129 if (r < 0)
130 return r;
131
132 (void) sd_bus_message_sensitive(m);
133
134 return sd_bus_message_append(m, "s", formatted);
135 }
136
home_record_dir(void)137 const char *home_record_dir(void) {
138 return secure_getenv("SYSTEMD_HOME_RECORD_DIR") ?: "/var/lib/systemd/home/";
139 }
140