chiark / gitweb /
tree-wide: remove Lennart's copyright lines
[elogind.git] / src / libelogind / sd-bus / bus-internal.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 ***/
4
5 #include "alloc-util.h"
6 #include "bus-internal.h"
7 #include "bus-message.h"
8 #include "hexdecoct.h"
9 #include "string-util.h"
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 }
50
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
74 bool interface_name_is_valid(const char *p) {
75         const char *q;
76         bool dot, found_dot = false;
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;
116         bool dot, found_dot = false, unique;
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') ||
136                                 IN_SET(*q, '_', '-');
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;
154 }
155
156 #if 0 /// UNNEEDED by elogind
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 #endif // 0
177
178 bool member_name_is_valid(const char *p) {
179         const char *q;
180
181         if (isempty(p))
182                 return false;
183
184         for (q = p; *q; q++) {
185                 bool good;
186
187                 good =
188                         (*q >= 'a' && *q <= 'z') ||
189                         (*q >= 'A' && *q <= 'Z') ||
190                         (*q >= '0' && *q <= '9') ||
191                         *q == '_';
192
193                 if (!good)
194                         return false;
195         }
196
197         if (q - p > 255)
198                 return false;
199
200         return true;
201 }
202
203 /*
204  * Complex pattern match
205  * This checks whether @a is a 'complex-prefix' of @b, or @b is a
206  * 'complex-prefix' of @a, based on strings that consist of labels with @c as
207  * spearator. This function returns true if:
208  *   - both strings are equal
209  *   - either is a prefix of the other and ends with @c
210  * The second rule makes sure that either string needs to be fully included in
211  * the other, and the string which is considered the prefix needs to end with a
212  * separator.
213  */
214 static bool complex_pattern_check(char c, const char *a, const char *b) {
215         bool separator = false;
216
217         if (!a && !b)
218                 return true;
219
220         if (!a || !b)
221                 return false;
222
223         for (;;) {
224                 if (*a != *b)
225                         return (separator && (*a == 0 || *b == 0));
226
227                 if (*a == 0)
228                         return true;
229
230                 separator = *a == c;
231
232                 a++, b++;
233         }
234 }
235
236 bool namespace_complex_pattern(const char *pattern, const char *value) {
237         return complex_pattern_check('.', pattern, value);
238 }
239
240 bool path_complex_pattern(const char *pattern, const char *value) {
241         return complex_pattern_check('/', pattern, value);
242 }
243
244 /*
245  * Simple pattern match
246  * This checks whether @a is a 'simple-prefix' of @b, based on strings that
247  * consist of labels with @c as separator. This function returns true, if:
248  *   - if @a and @b are equal
249  *   - if @a is a prefix of @b, and the first following character in @b (or the
250  *     last character in @a) is @c
251  * The second rule basically makes sure that if @a is a prefix of @b, then @b
252  * must follow with a new label separated by @c. It cannot extend the label.
253  */
254 static bool simple_pattern_check(char c, const char *a, const char *b) {
255         bool separator = false;
256
257         if (!a && !b)
258                 return true;
259
260         if (!a || !b)
261                 return false;
262
263         for (;;) {
264                 if (*a != *b)
265                         return *a == 0 && (*b == c || separator);
266
267                 if (*a == 0)
268                         return true;
269
270                 separator = *a == c;
271
272                 a++, b++;
273         }
274 }
275
276 bool namespace_simple_pattern(const char *pattern, const char *value) {
277         return simple_pattern_check('.', pattern, value);
278 }
279
280 bool path_simple_pattern(const char *pattern, const char *value) {
281         return simple_pattern_check('/', pattern, value);
282 }
283
284 int bus_message_type_from_string(const char *s, uint8_t *u) {
285         if (streq(s, "signal"))
286                 *u = SD_BUS_MESSAGE_SIGNAL;
287         else if (streq(s, "method_call"))
288                 *u = SD_BUS_MESSAGE_METHOD_CALL;
289         else if (streq(s, "error"))
290                 *u = SD_BUS_MESSAGE_METHOD_ERROR;
291         else if (streq(s, "method_return"))
292                 *u = SD_BUS_MESSAGE_METHOD_RETURN;
293         else
294                 return -EINVAL;
295
296         return 0;
297 }
298
299 const char *bus_message_type_to_string(uint8_t u) {
300         if (u == SD_BUS_MESSAGE_SIGNAL)
301                 return "signal";
302         else if (u == SD_BUS_MESSAGE_METHOD_CALL)
303                 return "method_call";
304         else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
305                 return "error";
306         else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
307                  return "method_return";
308         else
309                 return NULL;
310 }
311
312 char *bus_address_escape(const char *v) {
313         const char *a;
314         char *r, *b;
315
316         r = new(char, strlen(v)*3+1);
317         if (!r)
318                 return NULL;
319
320         for (a = v, b = r; *a; a++) {
321
322                 if ((*a >= '0' && *a <= '9') ||
323                     (*a >= 'a' && *a <= 'z') ||
324                     (*a >= 'A' && *a <= 'Z') ||
325                     strchr("_-/.", *a))
326                         *(b++) = *a;
327                 else {
328                         *(b++) = '%';
329                         *(b++) = hexchar(*a >> 4);
330                         *(b++) = hexchar(*a & 0xF);
331                 }
332         }
333
334         *b = 0;
335         return r;
336 }
337
338 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
339         assert(m);
340
341         if (r < 0) {
342                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
343                         sd_bus_reply_method_errno(m, r, error);
344
345         } else if (sd_bus_error_is_set(error)) {
346                 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
347                         sd_bus_reply_method_error(m, error);
348         } else
349                 return r;
350
351         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",
352                   bus_message_type_to_string(m->header->type),
353                   strna(sd_bus_message_get_sender(m)),
354                   strna(sd_bus_message_get_destination(m)),
355                   strna(sd_bus_message_get_path(m)),
356                   strna(sd_bus_message_get_interface(m)),
357                   strna(sd_bus_message_get_member(m)),
358                   BUS_MESSAGE_COOKIE(m),
359                   m->reply_cookie,
360                   strna(m->root_container.signature),
361                   strna(m->error.name),
362                   strna(m->error.message),
363                   bus_error_message(error, r));
364
365         return 1;
366 }