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