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