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