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