Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include "alloc-util.h"
4 : #include "bus-internal.h"
5 : #include "bus-message.h"
6 : #include "hexdecoct.h"
7 : #include "string-util.h"
8 :
9 373 : bool object_path_is_valid(const char *p) {
10 : const char *q;
11 : bool slash;
12 :
13 373 : if (!p)
14 0 : return false;
15 :
16 373 : if (p[0] != '/')
17 3 : return false;
18 :
19 370 : if (p[1] == 0)
20 48 : return true;
21 :
22 4299 : for (slash = true, q = p+1; *q; q++)
23 3981 : if (*q == '/') {
24 457 : if (slash)
25 3 : return false;
26 :
27 454 : slash = true;
28 : } else {
29 : bool good;
30 :
31 3524 : good =
32 3286 : (*q >= 'a' && *q <= 'z') ||
33 238 : (*q >= 'A' && *q <= 'Z') ||
34 7066 : (*q >= '0' && *q <= '9') ||
35 18 : *q == '_';
36 :
37 3524 : if (!good)
38 1 : return false;
39 :
40 3523 : slash = false;
41 : }
42 :
43 318 : if (slash)
44 2 : return false;
45 :
46 316 : return (q - p) <= BUS_PATH_SIZE_MAX;
47 : }
48 :
49 39 : char* object_path_startswith(const char *a, const char *b) {
50 : const char *p;
51 :
52 39 : if (!object_path_is_valid(a) ||
53 39 : !object_path_is_valid(b))
54 1 : return NULL;
55 :
56 38 : if (streq(b, "/"))
57 6 : return (char*) a + 1;
58 :
59 32 : p = startswith(a, b);
60 32 : if (!p)
61 4 : return NULL;
62 :
63 28 : if (*p == 0)
64 4 : return (char*) p;
65 :
66 24 : if (*p == '/')
67 24 : return (char*) p + 1;
68 :
69 0 : return NULL;
70 : }
71 :
72 240 : bool interface_name_is_valid(const char *p) {
73 : const char *q;
74 240 : bool dot, found_dot = false;
75 :
76 240 : if (isempty(p))
77 0 : return false;
78 :
79 6338 : for (dot = true, q = p; *q; q++)
80 6098 : if (*q == '.') {
81 607 : if (dot)
82 0 : return false;
83 :
84 607 : found_dot = dot = true;
85 : } else {
86 : bool good;
87 :
88 5491 : good =
89 5057 : (*q >= 'a' && *q <= 'z') ||
90 434 : (*q >= 'A' && *q <= 'Z') ||
91 10982 : (!dot && *q >= '0' && *q <= '9') ||
92 0 : *q == '_';
93 :
94 5491 : if (!good)
95 0 : return false;
96 :
97 5491 : dot = false;
98 : }
99 :
100 240 : if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
101 0 : return false;
102 :
103 240 : if (dot)
104 0 : return false;
105 :
106 240 : if (!found_dot)
107 0 : return false;
108 :
109 240 : return true;
110 : }
111 :
112 295 : bool service_name_is_valid(const char *p) {
113 : const char *q;
114 295 : bool dot, found_dot = false, unique;
115 :
116 295 : if (isempty(p))
117 0 : return false;
118 :
119 295 : unique = p[0] == ':';
120 :
121 5693 : for (dot = true, q = unique ? p+1 : p; *q; q++)
122 5398 : if (*q == '.') {
123 591 : if (dot)
124 0 : return false;
125 :
126 591 : found_dot = dot = true;
127 : } else {
128 : bool good;
129 :
130 4807 : good =
131 4091 : (*q >= 'a' && *q <= 'z') ||
132 716 : (*q >= 'A' && *q <= 'Z') ||
133 9616 : ((!dot || unique) && *q >= '0' && *q <= '9') ||
134 2 : IN_SET(*q, '_', '-');
135 :
136 4807 : if (!good)
137 0 : return false;
138 :
139 4807 : dot = false;
140 : }
141 :
142 295 : if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
143 0 : return false;
144 :
145 295 : if (dot)
146 0 : return false;
147 :
148 295 : if (!found_dot)
149 0 : return false;
150 :
151 295 : return true;
152 : }
153 :
154 364 : bool member_name_is_valid(const char *p) {
155 : const char *q;
156 :
157 364 : if (isempty(p))
158 0 : return false;
159 :
160 3981 : for (q = p; *q; q++) {
161 : bool good;
162 :
163 3617 : good =
164 3014 : (*q >= 'a' && *q <= 'z') ||
165 603 : (*q >= 'A' && *q <= 'Z') ||
166 7242 : (*q >= '0' && *q <= '9') ||
167 8 : *q == '_';
168 :
169 3617 : if (!good)
170 0 : return false;
171 : }
172 :
173 364 : if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
174 0 : return false;
175 :
176 364 : return true;
177 : }
178 :
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 : * separator. 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 : */
190 22 : static bool complex_pattern_check(char c, const char *a, const char *b) {
191 22 : bool separator = false;
192 :
193 22 : if (!a && !b)
194 0 : return true;
195 :
196 22 : if (!a || !b)
197 0 : return false;
198 :
199 : for (;;) {
200 120 : if (*a != *b)
201 16 : return (separator && (*a == 0 || *b == 0));
202 :
203 104 : if (*a == 0)
204 6 : return true;
205 :
206 98 : separator = *a == c;
207 :
208 98 : a++, b++;
209 : }
210 : }
211 :
212 10 : bool namespace_complex_pattern(const char *pattern, const char *value) {
213 10 : return complex_pattern_check('.', pattern, value);
214 : }
215 :
216 12 : bool path_complex_pattern(const char *pattern, const char *value) {
217 12 : return complex_pattern_check('/', pattern, value);
218 : }
219 :
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 : */
230 16 : static bool simple_pattern_check(char c, const char *a, const char *b) {
231 16 : bool separator = false;
232 :
233 16 : if (!a && !b)
234 0 : return true;
235 :
236 16 : if (!a || !b)
237 0 : return false;
238 :
239 : for (;;) {
240 85 : if (*a != *b)
241 13 : return *a == 0 && (*b == c || separator);
242 :
243 72 : if (*a == 0)
244 3 : return true;
245 :
246 69 : separator = *a == c;
247 :
248 69 : a++, b++;
249 : }
250 : }
251 :
252 11 : bool namespace_simple_pattern(const char *pattern, const char *value) {
253 11 : return simple_pattern_check('.', pattern, value);
254 : }
255 :
256 5 : bool path_simple_pattern(const char *pattern, const char *value) {
257 5 : return simple_pattern_check('/', pattern, value);
258 : }
259 :
260 34 : int bus_message_type_from_string(const char *s, uint8_t *u) {
261 34 : if (streq(s, "signal"))
262 33 : *u = SD_BUS_MESSAGE_SIGNAL;
263 1 : else if (streq(s, "method_call"))
264 1 : *u = SD_BUS_MESSAGE_METHOD_CALL;
265 0 : else if (streq(s, "error"))
266 0 : *u = SD_BUS_MESSAGE_METHOD_ERROR;
267 0 : else if (streq(s, "method_return"))
268 0 : *u = SD_BUS_MESSAGE_METHOD_RETURN;
269 : else
270 0 : return -EINVAL;
271 :
272 34 : return 0;
273 : }
274 :
275 39 : const char *bus_message_type_to_string(uint8_t u) {
276 39 : if (u == SD_BUS_MESSAGE_SIGNAL)
277 6 : return "signal";
278 33 : else if (u == SD_BUS_MESSAGE_METHOD_CALL)
279 20 : return "method_call";
280 13 : else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
281 0 : return "error";
282 13 : else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
283 13 : return "method_return";
284 : else
285 0 : return NULL;
286 : }
287 :
288 7 : char *bus_address_escape(const char *v) {
289 : const char *a;
290 : char *r, *b;
291 :
292 7 : r = new(char, strlen(v)*3+1);
293 7 : if (!r)
294 0 : return NULL;
295 :
296 51 : for (a = v, b = r; *a; a++) {
297 :
298 44 : if ((*a >= '0' && *a <= '9') ||
299 40 : (*a >= 'a' && *a <= 'z') ||
300 12 : (*a >= 'A' && *a <= 'Z') ||
301 12 : strchr("_-/.", *a))
302 32 : *(b++) = *a;
303 : else {
304 12 : *(b++) = '%';
305 12 : *(b++) = hexchar(*a >> 4);
306 12 : *(b++) = hexchar(*a & 0xF);
307 : }
308 : }
309 :
310 7 : *b = 0;
311 7 : return r;
312 : }
313 :
314 56 : int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
315 56 : assert(m);
316 :
317 56 : if (r < 0) {
318 0 : if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
319 0 : sd_bus_reply_method_errno(m, r, error);
320 :
321 56 : } else if (sd_bus_error_is_set(error)) {
322 0 : if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
323 0 : sd_bus_reply_method_error(m, error);
324 : } else
325 56 : return r;
326 :
327 0 : 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",
328 : bus_message_type_to_string(m->header->type),
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,
336 : strna(m->root_container.signature),
337 : strna(m->error.name),
338 : strna(m->error.message),
339 : bus_error_message(error, r));
340 :
341 0 : return 1;
342 : }
|