]>
Commit | Line | Data |
---|---|---|
70a5db58 LP |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | ||
3 | #include "dns-domain.h" | |
4 | #include "errno-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 | bool suitable_user_name(const char *name) { | |
14 | ||
2a4be3c5 ZJS |
15 | /* Checks whether the specified name is suitable for management via homed. Note that client-side we |
16 | * usually validate with the simple valid_user_group_name(), while server-side we are a bit more | |
17 | * restrictive, so that we can change the rules server-side without having to update things | |
18 | * client-side too. */ | |
70a5db58 LP |
19 | |
20 | if (!valid_user_group_name(name)) | |
21 | return false; | |
22 | ||
23 | /* We generally rely on NSS to tell us which users not to care for, but let's filter out some | |
24 | * particularly well-known users. */ | |
25 | if (STR_IN_SET(name, | |
26 | "root", | |
27 | "nobody", | |
28 | NOBODY_USER_NAME, NOBODY_GROUP_NAME)) | |
29 | return false; | |
30 | ||
31 | /* Let's also defend our own namespace, as well as Debian's (unwritten?) logic of prefixing system | |
32 | * users with underscores. */ | |
33 | if (STARTSWITH_SET(name, "systemd-", "_")) | |
34 | return false; | |
35 | ||
36 | return true; | |
37 | } | |
38 | ||
39 | int suitable_realm(const char *realm) { | |
40 | _cleanup_free_ char *normalized = NULL; | |
41 | int r; | |
42 | ||
43 | /* Similar to the above: let's validate the realm a bit stricter server-side than client side */ | |
44 | ||
45 | r = dns_name_normalize(realm, 0, &normalized); /* this also checks general validity */ | |
46 | if (r == -EINVAL) | |
47 | return 0; | |
48 | if (r < 0) | |
49 | return r; | |
50 | ||
51 | if (!streq(realm, normalized)) /* is this normalized? */ | |
52 | return false; | |
53 | ||
54 | if (dns_name_is_root(realm)) /* Don't allow top level domain */ | |
55 | return false; | |
56 | ||
57 | return true; | |
58 | } | |
59 | ||
60 | int suitable_image_path(const char *path) { | |
61 | ||
62 | return !empty_or_root(path) && | |
63 | path_is_valid(path) && | |
64 | path_is_absolute(path); | |
65 | } | |
66 | ||
67 | int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm) { | |
68 | _cleanup_free_ char *user_name = NULL, *realm = NULL; | |
69 | const char *c; | |
70 | int r; | |
71 | ||
72 | assert(t); | |
73 | assert(ret_user_name); | |
74 | assert(ret_realm); | |
75 | ||
76 | c = strchr(t, '@'); | |
77 | if (!c) { | |
78 | user_name = strdup(t); | |
79 | if (!user_name) | |
80 | return -ENOMEM; | |
81 | } else { | |
82 | user_name = strndup(t, c - t); | |
83 | if (!user_name) | |
84 | return -ENOMEM; | |
85 | ||
86 | realm = strdup(c + 1); | |
87 | if (!realm) | |
88 | return -ENOMEM; | |
89 | } | |
90 | ||
91 | if (!suitable_user_name(user_name)) | |
92 | return -EINVAL; | |
93 | ||
94 | if (realm) { | |
95 | r = suitable_realm(realm); | |
96 | if (r < 0) | |
97 | return r; | |
98 | if (r == 0) | |
99 | return -EINVAL; | |
100 | } | |
101 | ||
102 | *ret_user_name = TAKE_PTR(user_name); | |
103 | *ret_realm = TAKE_PTR(realm); | |
104 | ||
105 | return 0; | |
106 | } | |
107 | ||
108 | int bus_message_append_secret(sd_bus_message *m, UserRecord *secret) { | |
109 | _cleanup_(erase_and_freep) char *formatted = NULL; | |
110 | JsonVariant *v; | |
111 | int r; | |
112 | ||
113 | assert(m); | |
114 | assert(secret); | |
115 | ||
116 | if (!FLAGS_SET(secret->mask, USER_RECORD_SECRET)) | |
117 | return sd_bus_message_append(m, "s", "{}"); | |
118 | ||
119 | v = json_variant_by_key(secret->json, "secret"); | |
120 | if (!v) | |
121 | return -EINVAL; | |
122 | ||
123 | r = json_variant_format(v, 0, &formatted); | |
124 | if (r < 0) | |
125 | return r; | |
126 | ||
127 | return sd_bus_message_append(m, "s", formatted); | |
128 | } | |
129 | ||
130 | int test_password_one(const char *hashed_password, const char *password) { | |
131 | struct crypt_data cc = {}; | |
132 | const char *k; | |
133 | bool b; | |
134 | ||
135 | errno = 0; | |
136 | k = crypt_r(password, hashed_password, &cc); | |
137 | if (!k) { | |
138 | explicit_bzero_safe(&cc, sizeof(cc)); | |
139 | return errno_or_else(EINVAL); | |
140 | } | |
141 | ||
142 | b = streq(k, hashed_password); | |
143 | explicit_bzero_safe(&cc, sizeof(cc)); | |
144 | return b; | |
145 | } | |
146 | ||
147 | int test_password_many(char **hashed_password, const char *password) { | |
148 | char **hpw; | |
149 | int r; | |
150 | ||
151 | STRV_FOREACH(hpw, hashed_password) { | |
152 | r = test_password_one(*hpw, password); | |
153 | if (r < 0) | |
154 | return r; | |
155 | if (r > 0) | |
156 | return true; | |
157 | } | |
158 | ||
159 | return false; | |
160 | } |