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