]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-internal.c
Merge pull request #1359 from jengelh/ue
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-internal.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "alloc-util.h"
23 #include "bus-internal.h"
24 #include "bus-message.h"
25 #include "hexdecoct.h"
26 #include "string-util.h"
27
28 bool object_path_is_valid(const char *p) {
29 const char *q;
30 bool slash;
31
32 if (!p)
33 return false;
34
35 if (p[0] != '/')
36 return false;
37
38 if (p[1] == 0)
39 return true;
40
41 for (slash = true, q = p+1; *q; q++)
42 if (*q == '/') {
43 if (slash)
44 return false;
45
46 slash = true;
47 } else {
48 bool good;
49
50 good =
51 (*q >= 'a' && *q <= 'z') ||
52 (*q >= 'A' && *q <= 'Z') ||
53 (*q >= '0' && *q <= '9') ||
54 *q == '_';
55
56 if (!good)
57 return false;
58
59 slash = false;
60 }
61
62 if (slash)
63 return false;
64
65 return true;
66 }
67
68 char* object_path_startswith(const char *a, const char *b) {
69 const char *p;
70
71 if (!object_path_is_valid(a) ||
72 !object_path_is_valid(b))
73 return NULL;
74
75 if (streq(b, "/"))
76 return (char*) a + 1;
77
78 p = startswith(a, b);
79 if (!p)
80 return NULL;
81
82 if (*p == 0)
83 return (char*) p;
84
85 if (*p == '/')
86 return (char*) p + 1;
87
88 return NULL;
89 }
90
91 bool interface_name_is_valid(const char *p) {
92 const char *q;
93 bool dot, found_dot = false;
94
95 if (isempty(p))
96 return false;
97
98 for (dot = true, q = p; *q; q++)
99 if (*q == '.') {
100 if (dot)
101 return false;
102
103 found_dot = dot = true;
104 } else {
105 bool good;
106
107 good =
108 (*q >= 'a' && *q <= 'z') ||
109 (*q >= 'A' && *q <= 'Z') ||
110 (!dot && *q >= '0' && *q <= '9') ||
111 *q == '_';
112
113 if (!good)
114 return false;
115
116 dot = false;
117 }
118
119 if (q - p > 255)
120 return false;
121
122 if (dot)
123 return false;
124
125 if (!found_dot)
126 return false;
127
128 return true;
129 }
130
131 bool service_name_is_valid(const char *p) {
132 const char *q;
133 bool dot, found_dot = false, unique;
134
135 if (isempty(p))
136 return false;
137
138 unique = p[0] == ':';
139
140 for (dot = true, q = unique ? p+1 : p; *q; q++)
141 if (*q == '.') {
142 if (dot)
143 return false;
144
145 found_dot = dot = true;
146 } else {
147 bool good;
148
149 good =
150 (*q >= 'a' && *q <= 'z') ||
151 (*q >= 'A' && *q <= 'Z') ||
152 ((!dot || unique) && *q >= '0' && *q <= '9') ||
153 *q == '_' || *q == '-';
154
155 if (!good)
156 return false;
157
158 dot = false;
159 }
160
161 if (q - p > 255)
162 return false;
163
164 if (dot)
165 return false;
166
167 if (!found_dot)
168 return false;
169
170 return true;
171 }
172
173 char* service_name_startswith(const char *a, const char *b) {
174 const char *p;
175
176 if (!service_name_is_valid(a) ||
177 !service_name_is_valid(b))
178 return NULL;
179
180 p = startswith(a, b);
181 if (!p)
182 return NULL;
183
184 if (*p == 0)
185 return (char*) p;
186
187 if (*p == '.')
188 return (char*) p + 1;
189
190 return NULL;
191 }
192
193 bool member_name_is_valid(const char *p) {
194 const char *q;
195
196 if (isempty(p))
197 return false;
198
199 for (q = p; *q; q++) {
200 bool good;
201
202 good =
203 (*q >= 'a' && *q <= 'z') ||
204 (*q >= 'A' && *q <= 'Z') ||
205 (*q >= '0' && *q <= '9') ||
206 *q == '_';
207
208 if (!good)
209 return false;
210 }
211
212 if (q - p > 255)
213 return false;
214
215 return true;
216 }
217
218 /*
219 * Complex pattern match
220 * This checks whether @a is a 'complex-prefix' of @b, or @b is a
221 * 'complex-prefix' of @a, based on strings that consist of labels with @c as
222 * spearator. This function returns true if:
223 * - both strings are equal
224 * - either is a prefix of the other and ends with @c
225 * The second rule makes sure that either string needs to be fully included in
226 * the other, and the string which is considered the prefix needs to end with a
227 * separator.
228 */
229 static bool complex_pattern_check(char c, const char *a, const char *b) {
230 bool separator = false;
231
232 if (!a && !b)
233 return true;
234
235 if (!a || !b)
236 return false;
237
238 for (;;) {
239 if (*a != *b)
240 return (separator && (*a == 0 || *b == 0));
241
242 if (*a == 0)
243 return true;
244
245 separator = *a == c;
246
247 a++, b++;
248 }
249 }
250
251 bool namespace_complex_pattern(const char *pattern, const char *value) {
252 return complex_pattern_check('.', pattern, value);
253 }
254
255 bool path_complex_pattern(const char *pattern, const char *value) {
256 return complex_pattern_check('/', pattern, value);
257 }
258
259 /*
260 * Simple pattern match
261 * This checks whether @a is a 'simple-prefix' of @b, based on strings that
262 * consist of labels with @c as separator. This function returns true, if:
263 * - if @a and @b are equal
264 * - if @a is a prefix of @b, and the first following character in @b (or the
265 * last character in @a) is @c
266 * The second rule basically makes sure that if @a is a prefix of @b, then @b
267 * must follow with a new label separated by @c. It cannot extend the label.
268 */
269 static bool simple_pattern_check(char c, const char *a, const char *b) {
270 bool separator = false;
271
272 if (!a && !b)
273 return true;
274
275 if (!a || !b)
276 return false;
277
278 for (;;) {
279 if (*a != *b)
280 return *a == 0 && (*b == c || separator);
281
282 if (*a == 0)
283 return true;
284
285 separator = *a == c;
286
287 a++, b++;
288 }
289 }
290
291 bool namespace_simple_pattern(const char *pattern, const char *value) {
292 return simple_pattern_check('.', pattern, value);
293 }
294
295 bool path_simple_pattern(const char *pattern, const char *value) {
296 return simple_pattern_check('/', pattern, value);
297 }
298
299 int bus_message_type_from_string(const char *s, uint8_t *u) {
300 if (streq(s, "signal"))
301 *u = SD_BUS_MESSAGE_SIGNAL;
302 else if (streq(s, "method_call"))
303 *u = SD_BUS_MESSAGE_METHOD_CALL;
304 else if (streq(s, "error"))
305 *u = SD_BUS_MESSAGE_METHOD_ERROR;
306 else if (streq(s, "method_return"))
307 *u = SD_BUS_MESSAGE_METHOD_RETURN;
308 else
309 return -EINVAL;
310
311 return 0;
312 }
313
314 const char *bus_message_type_to_string(uint8_t u) {
315 if (u == SD_BUS_MESSAGE_SIGNAL)
316 return "signal";
317 else if (u == SD_BUS_MESSAGE_METHOD_CALL)
318 return "method_call";
319 else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
320 return "error";
321 else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
322 return "method_return";
323 else
324 return NULL;
325 }
326
327 char *bus_address_escape(const char *v) {
328 const char *a;
329 char *r, *b;
330
331 r = new(char, strlen(v)*3+1);
332 if (!r)
333 return NULL;
334
335 for (a = v, b = r; *a; a++) {
336
337 if ((*a >= '0' && *a <= '9') ||
338 (*a >= 'a' && *a <= 'z') ||
339 (*a >= 'A' && *a <= 'Z') ||
340 strchr("_-/.", *a))
341 *(b++) = *a;
342 else {
343 *(b++) = '%';
344 *(b++) = hexchar(*a >> 4);
345 *(b++) = hexchar(*a & 0xF);
346 }
347 }
348
349 *b = 0;
350 return r;
351 }
352
353 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
354 assert(m);
355
356 if (r < 0) {
357 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
358 sd_bus_reply_method_errno(m, r, error);
359
360 } else if (sd_bus_error_is_set(error)) {
361 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
362 sd_bus_reply_method_error(m, error);
363 } else
364 return r;
365
366 log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
367 bus_message_type_to_string(m->header->type),
368 strna(m->sender),
369 strna(m->path),
370 strna(m->interface),
371 strna(m->member),
372 strna(m->root_container.signature),
373 bus_error_message(error, r));
374
375 return 1;
376 }