]> git.proxmox.com Git - systemd.git/blame - src/libsystemd/sd-bus/bus-internal.c
New upstream version 236
[systemd.git] / src / libsystemd / sd-bus / bus-internal.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
663996b3
MS
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
db2df898 21#include "alloc-util.h"
663996b3 22#include "bus-internal.h"
db2df898
MP
23#include "bus-message.h"
24#include "hexdecoct.h"
25#include "string-util.h"
663996b3
MS
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}
66
60f067b4
JS
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
663996b3
MS
90bool interface_name_is_valid(const char *p) {
91 const char *q;
60f067b4 92 bool dot, found_dot = false;
663996b3
MS
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;
60f067b4 132 bool dot, found_dot = false, unique;
663996b3
MS
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') ||
f5e65279 152 IN_SET(*q, '_', '-');
663996b3
MS
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
f47781d8
MP
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
663996b3
MS
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}
216
86f210e9
MP
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 */
663996b3
MS
228static 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)
86f210e9 239 return (separator && (*a == 0 || *b == 0));
663996b3
MS
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
86f210e9
MP
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 */
663996b3 268static bool simple_pattern_check(char c, const char *a, const char *b) {
86f210e9 269 bool separator = false;
663996b3
MS
270
271 if (!a && !b)
272 return true;
273
274 if (!a || !b)
275 return false;
276
277 for (;;) {
278 if (*a != *b)
86f210e9 279 return *a == 0 && (*b == c || separator);
663996b3
MS
280
281 if (*a == 0)
282 return true;
283
86f210e9
MP
284 separator = *a == c;
285
663996b3
MS
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"))
60f067b4 300 *u = SD_BUS_MESSAGE_SIGNAL;
663996b3 301 else if (streq(s, "method_call"))
60f067b4 302 *u = SD_BUS_MESSAGE_METHOD_CALL;
663996b3 303 else if (streq(s, "error"))
60f067b4 304 *u = SD_BUS_MESSAGE_METHOD_ERROR;
663996b3 305 else if (streq(s, "method_return"))
60f067b4 306 *u = SD_BUS_MESSAGE_METHOD_RETURN;
663996b3
MS
307 else
308 return -EINVAL;
309
310 return 0;
311}
312
313const char *bus_message_type_to_string(uint8_t u) {
60f067b4 314 if (u == SD_BUS_MESSAGE_SIGNAL)
663996b3 315 return "signal";
60f067b4 316 else if (u == SD_BUS_MESSAGE_METHOD_CALL)
663996b3 317 return "method_call";
60f067b4 318 else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
663996b3 319 return "error";
60f067b4 320 else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
663996b3
MS
321 return "method_return";
322 else
323 return NULL;
324}
60f067b4
JS
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}
86f210e9
MP
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}