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