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