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