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