]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
de1c301e | 2 | |
b5efdb8a | 3 | #include "alloc-util.h" |
de1c301e | 4 | #include "bus-internal.h" |
07630cea | 5 | #include "bus-message.h" |
e4e73a63 | 6 | #include "hexdecoct.h" |
07630cea | 7 | #include "string-util.h" |
ac89bf1d LP |
8 | |
9 | bool object_path_is_valid(const char *p) { | |
10 | const char *q; | |
11 | bool slash; | |
12 | ||
13 | if (!p) | |
14 | return false; | |
15 | ||
16 | if (p[0] != '/') | |
17 | return false; | |
18 | ||
19 | if (p[1] == 0) | |
20 | return true; | |
21 | ||
22 | for (slash = true, q = p+1; *q; q++) | |
23 | if (*q == '/') { | |
24 | if (slash) | |
25 | return false; | |
26 | ||
27 | slash = true; | |
28 | } else { | |
29 | bool good; | |
30 | ||
31 | good = | |
32 | (*q >= 'a' && *q <= 'z') || | |
33 | (*q >= 'A' && *q <= 'Z') || | |
34 | (*q >= '0' && *q <= '9') || | |
35 | *q == '_'; | |
36 | ||
37 | if (!good) | |
38 | return false; | |
39 | ||
40 | slash = false; | |
41 | } | |
42 | ||
43 | if (slash) | |
44 | return false; | |
45 | ||
61397a60 | 46 | return (q - p) <= BUS_PATH_SIZE_MAX; |
ac89bf1d | 47 | } |
6693860f | 48 | |
29ddb38f LP |
49 | char* object_path_startswith(const char *a, const char *b) { |
50 | const char *p; | |
51 | ||
52 | if (!object_path_is_valid(a) || | |
53 | !object_path_is_valid(b)) | |
54 | return NULL; | |
55 | ||
56 | if (streq(b, "/")) | |
57 | return (char*) a + 1; | |
58 | ||
59 | p = startswith(a, b); | |
60 | if (!p) | |
61 | return NULL; | |
62 | ||
63 | if (*p == 0) | |
64 | return (char*) p; | |
65 | ||
66 | if (*p == '/') | |
67 | return (char*) p + 1; | |
68 | ||
69 | return NULL; | |
70 | } | |
71 | ||
6693860f LP |
72 | bool interface_name_is_valid(const char *p) { |
73 | const char *q; | |
f5f6e41a | 74 | bool dot, found_dot = false; |
6693860f LP |
75 | |
76 | if (isempty(p)) | |
77 | return false; | |
78 | ||
79 | for (dot = true, q = p; *q; q++) | |
80 | if (*q == '.') { | |
81 | if (dot) | |
82 | return false; | |
83 | ||
84 | found_dot = dot = true; | |
85 | } else { | |
86 | bool good; | |
87 | ||
88 | good = | |
89 | (*q >= 'a' && *q <= 'z') || | |
90 | (*q >= 'A' && *q <= 'Z') || | |
91 | (!dot && *q >= '0' && *q <= '9') || | |
92 | *q == '_'; | |
93 | ||
94 | if (!good) | |
95 | return false; | |
96 | ||
97 | dot = false; | |
98 | } | |
99 | ||
100 | if (q - p > 255) | |
101 | return false; | |
102 | ||
103 | if (dot) | |
104 | return false; | |
105 | ||
106 | if (!found_dot) | |
107 | return false; | |
108 | ||
109 | return true; | |
110 | } | |
111 | ||
112 | bool service_name_is_valid(const char *p) { | |
113 | const char *q; | |
f5f6e41a | 114 | bool dot, found_dot = false, unique; |
6693860f LP |
115 | |
116 | if (isempty(p)) | |
117 | return false; | |
118 | ||
119 | unique = p[0] == ':'; | |
120 | ||
121 | for (dot = true, q = unique ? p+1 : p; *q; q++) | |
122 | if (*q == '.') { | |
123 | if (dot) | |
124 | return false; | |
125 | ||
126 | found_dot = dot = true; | |
127 | } else { | |
128 | bool good; | |
129 | ||
130 | good = | |
131 | (*q >= 'a' && *q <= 'z') || | |
132 | (*q >= 'A' && *q <= 'Z') || | |
133 | ((!dot || unique) && *q >= '0' && *q <= '9') || | |
945c2931 | 134 | IN_SET(*q, '_', '-'); |
6693860f LP |
135 | |
136 | if (!good) | |
137 | return false; | |
138 | ||
139 | dot = false; | |
140 | } | |
141 | ||
142 | if (q - p > 255) | |
143 | return false; | |
144 | ||
145 | if (dot) | |
146 | return false; | |
147 | ||
148 | if (!found_dot) | |
149 | return false; | |
150 | ||
151 | return true; | |
6693860f LP |
152 | } |
153 | ||
154 | bool member_name_is_valid(const char *p) { | |
155 | const char *q; | |
156 | ||
157 | if (isempty(p)) | |
158 | return false; | |
159 | ||
160 | for (q = p; *q; q++) { | |
161 | bool good; | |
162 | ||
163 | good = | |
164 | (*q >= 'a' && *q <= 'z') || | |
165 | (*q >= 'A' && *q <= 'Z') || | |
166 | (*q >= '0' && *q <= '9') || | |
167 | *q == '_'; | |
168 | ||
169 | if (!good) | |
170 | return false; | |
171 | } | |
172 | ||
173 | if (q - p > 255) | |
174 | return false; | |
175 | ||
176 | return true; | |
177 | } | |
392d5b37 | 178 | |
744dccdd DH |
179 | /* |
180 | * Complex pattern match | |
181 | * This checks whether @a is a 'complex-prefix' of @b, or @b is a | |
182 | * 'complex-prefix' of @a, based on strings that consist of labels with @c as | |
183 | * spearator. This function returns true if: | |
184 | * - both strings are equal | |
185 | * - either is a prefix of the other and ends with @c | |
186 | * The second rule makes sure that either string needs to be fully included in | |
187 | * the other, and the string which is considered the prefix needs to end with a | |
188 | * separator. | |
189 | */ | |
392d5b37 LP |
190 | static bool complex_pattern_check(char c, const char *a, const char *b) { |
191 | bool separator = false; | |
192 | ||
42c5aaf3 LP |
193 | if (!a && !b) |
194 | return true; | |
195 | ||
196 | if (!a || !b) | |
197 | return false; | |
198 | ||
392d5b37 LP |
199 | for (;;) { |
200 | if (*a != *b) | |
744dccdd | 201 | return (separator && (*a == 0 || *b == 0)); |
392d5b37 LP |
202 | |
203 | if (*a == 0) | |
204 | return true; | |
205 | ||
206 | separator = *a == c; | |
207 | ||
208 | a++, b++; | |
209 | } | |
210 | } | |
211 | ||
212 | bool namespace_complex_pattern(const char *pattern, const char *value) { | |
213 | return complex_pattern_check('.', pattern, value); | |
214 | } | |
215 | ||
216 | bool path_complex_pattern(const char *pattern, const char *value) { | |
217 | return complex_pattern_check('/', pattern, value); | |
218 | } | |
219 | ||
744dccdd DH |
220 | /* |
221 | * Simple pattern match | |
222 | * This checks whether @a is a 'simple-prefix' of @b, based on strings that | |
223 | * consist of labels with @c as separator. This function returns true, if: | |
224 | * - if @a and @b are equal | |
225 | * - if @a is a prefix of @b, and the first following character in @b (or the | |
226 | * last character in @a) is @c | |
227 | * The second rule basically makes sure that if @a is a prefix of @b, then @b | |
228 | * must follow with a new label separated by @c. It cannot extend the label. | |
229 | */ | |
392d5b37 | 230 | static bool simple_pattern_check(char c, const char *a, const char *b) { |
744dccdd | 231 | bool separator = false; |
42c5aaf3 LP |
232 | |
233 | if (!a && !b) | |
234 | return true; | |
235 | ||
236 | if (!a || !b) | |
237 | return false; | |
238 | ||
392d5b37 LP |
239 | for (;;) { |
240 | if (*a != *b) | |
744dccdd | 241 | return *a == 0 && (*b == c || separator); |
392d5b37 LP |
242 | |
243 | if (*a == 0) | |
244 | return true; | |
245 | ||
744dccdd DH |
246 | separator = *a == c; |
247 | ||
392d5b37 LP |
248 | a++, b++; |
249 | } | |
250 | } | |
251 | ||
252 | bool namespace_simple_pattern(const char *pattern, const char *value) { | |
253 | return simple_pattern_check('.', pattern, value); | |
254 | } | |
255 | ||
256 | bool path_simple_pattern(const char *pattern, const char *value) { | |
257 | return simple_pattern_check('/', pattern, value); | |
258 | } | |
259 | ||
260 | int bus_message_type_from_string(const char *s, uint8_t *u) { | |
261 | if (streq(s, "signal")) | |
40ca29a1 | 262 | *u = SD_BUS_MESSAGE_SIGNAL; |
392d5b37 | 263 | else if (streq(s, "method_call")) |
40ca29a1 | 264 | *u = SD_BUS_MESSAGE_METHOD_CALL; |
392d5b37 | 265 | else if (streq(s, "error")) |
40ca29a1 | 266 | *u = SD_BUS_MESSAGE_METHOD_ERROR; |
392d5b37 | 267 | else if (streq(s, "method_return")) |
40ca29a1 | 268 | *u = SD_BUS_MESSAGE_METHOD_RETURN; |
392d5b37 LP |
269 | else |
270 | return -EINVAL; | |
271 | ||
272 | return 0; | |
273 | } | |
a56f19c4 LP |
274 | |
275 | const char *bus_message_type_to_string(uint8_t u) { | |
40ca29a1 | 276 | if (u == SD_BUS_MESSAGE_SIGNAL) |
a56f19c4 | 277 | return "signal"; |
40ca29a1 | 278 | else if (u == SD_BUS_MESSAGE_METHOD_CALL) |
a56f19c4 | 279 | return "method_call"; |
40ca29a1 | 280 | else if (u == SD_BUS_MESSAGE_METHOD_ERROR) |
a56f19c4 | 281 | return "error"; |
40ca29a1 | 282 | else if (u == SD_BUS_MESSAGE_METHOD_RETURN) |
a56f19c4 LP |
283 | return "method_return"; |
284 | else | |
285 | return NULL; | |
286 | } | |
0f8bd8de LP |
287 | |
288 | char *bus_address_escape(const char *v) { | |
289 | const char *a; | |
290 | char *r, *b; | |
291 | ||
292 | r = new(char, strlen(v)*3+1); | |
293 | if (!r) | |
294 | return NULL; | |
295 | ||
296 | for (a = v, b = r; *a; a++) { | |
297 | ||
298 | if ((*a >= '0' && *a <= '9') || | |
299 | (*a >= 'a' && *a <= 'z') || | |
300 | (*a >= 'A' && *a <= 'Z') || | |
301 | strchr("_-/.", *a)) | |
302 | *(b++) = *a; | |
303 | else { | |
304 | *(b++) = '%'; | |
305 | *(b++) = hexchar(*a >> 4); | |
306 | *(b++) = hexchar(*a & 0xF); | |
307 | } | |
308 | } | |
309 | ||
310 | *b = 0; | |
311 | return r; | |
312 | } | |
a095315b KS |
313 | |
314 | int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) { | |
315 | assert(m); | |
316 | ||
317 | if (r < 0) { | |
318 | if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) | |
319 | sd_bus_reply_method_errno(m, r, error); | |
320 | ||
321 | } else if (sd_bus_error_is_set(error)) { | |
322 | if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) | |
323 | sd_bus_reply_method_error(m, error); | |
324 | } else | |
325 | return r; | |
326 | ||
e32fd6b4 | 327 | log_debug("Failed to process message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s: %s", |
a095315b | 328 | bus_message_type_to_string(m->header->type), |
e32fd6b4 LP |
329 | strna(sd_bus_message_get_sender(m)), |
330 | strna(sd_bus_message_get_destination(m)), | |
331 | strna(sd_bus_message_get_path(m)), | |
332 | strna(sd_bus_message_get_interface(m)), | |
333 | strna(sd_bus_message_get_member(m)), | |
334 | BUS_MESSAGE_COOKIE(m), | |
335 | m->reply_cookie, | |
a095315b | 336 | strna(m->root_container.signature), |
e32fd6b4 LP |
337 | strna(m->error.name), |
338 | strna(m->error.message), | |
a095315b KS |
339 | bus_error_message(error, r)); |
340 | ||
341 | return 1; | |
342 | } |