]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-internal.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-internal.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
de1c301e
LP
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
b5efdb8a 21#include "alloc-util.h"
de1c301e 22#include "bus-internal.h"
07630cea 23#include "bus-message.h"
e4e73a63 24#include "hexdecoct.h"
07630cea 25#include "string-util.h"
ac89bf1d
LP
26
27bool 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}
6693860f 66
29ddb38f
LP
67char* 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
6693860f
LP
90bool interface_name_is_valid(const char *p) {
91 const char *q;
f5f6e41a 92 bool dot, found_dot = false;
6693860f
LP
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
130bool service_name_is_valid(const char *p) {
131 const char *q;
f5f6e41a 132 bool dot, found_dot = false, unique;
6693860f
LP
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') ||
945c2931 152 IN_SET(*q, '_', '-');
6693860f
LP
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;
6693860f
LP
170}
171
f5d8989c
LP
172char* 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
6693860f
LP
192bool 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}
392d5b37 216
744dccdd
DH
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 */
392d5b37
LP
228static bool complex_pattern_check(char c, const char *a, const char *b) {
229 bool separator = false;
230
42c5aaf3
LP
231 if (!a && !b)
232 return true;
233
234 if (!a || !b)
235 return false;
236
392d5b37
LP
237 for (;;) {
238 if (*a != *b)
744dccdd 239 return (separator && (*a == 0 || *b == 0));
392d5b37
LP
240
241 if (*a == 0)
242 return true;
243
244 separator = *a == c;
245
246 a++, b++;
247 }
248}
249
250bool namespace_complex_pattern(const char *pattern, const char *value) {
251 return complex_pattern_check('.', pattern, value);
252}
253
254bool path_complex_pattern(const char *pattern, const char *value) {
255 return complex_pattern_check('/', pattern, value);
256}
257
744dccdd
DH
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 */
392d5b37 268static bool simple_pattern_check(char c, const char *a, const char *b) {
744dccdd 269 bool separator = false;
42c5aaf3
LP
270
271 if (!a && !b)
272 return true;
273
274 if (!a || !b)
275 return false;
276
392d5b37
LP
277 for (;;) {
278 if (*a != *b)
744dccdd 279 return *a == 0 && (*b == c || separator);
392d5b37
LP
280
281 if (*a == 0)
282 return true;
283
744dccdd
DH
284 separator = *a == c;
285
392d5b37
LP
286 a++, b++;
287 }
288}
289
290bool namespace_simple_pattern(const char *pattern, const char *value) {
291 return simple_pattern_check('.', pattern, value);
292}
293
294bool path_simple_pattern(const char *pattern, const char *value) {
295 return simple_pattern_check('/', pattern, value);
296}
297
298int bus_message_type_from_string(const char *s, uint8_t *u) {
299 if (streq(s, "signal"))
40ca29a1 300 *u = SD_BUS_MESSAGE_SIGNAL;
392d5b37 301 else if (streq(s, "method_call"))
40ca29a1 302 *u = SD_BUS_MESSAGE_METHOD_CALL;
392d5b37 303 else if (streq(s, "error"))
40ca29a1 304 *u = SD_BUS_MESSAGE_METHOD_ERROR;
392d5b37 305 else if (streq(s, "method_return"))
40ca29a1 306 *u = SD_BUS_MESSAGE_METHOD_RETURN;
392d5b37
LP
307 else
308 return -EINVAL;
309
310 return 0;
311}
a56f19c4
LP
312
313const char *bus_message_type_to_string(uint8_t u) {
40ca29a1 314 if (u == SD_BUS_MESSAGE_SIGNAL)
a56f19c4 315 return "signal";
40ca29a1 316 else if (u == SD_BUS_MESSAGE_METHOD_CALL)
a56f19c4 317 return "method_call";
40ca29a1 318 else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
a56f19c4 319 return "error";
40ca29a1 320 else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
a56f19c4
LP
321 return "method_return";
322 else
323 return NULL;
324}
0f8bd8de
LP
325
326char *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}
a095315b
KS
351
352int 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}