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