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