Line data Source code
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 "bus-message.h"
23 : #include "bus-internal.h"
24 :
25 15856 : bool object_path_is_valid(const char *p) {
26 : const char *q;
27 : bool slash;
28 :
29 15856 : if (!p)
30 0 : return false;
31 :
32 15856 : if (p[0] != '/')
33 3 : return false;
34 :
35 15853 : if (p[1] == 0)
36 15548 : return true;
37 :
38 3112 : for (slash = true, q = p+1; *q; q++)
39 2811 : if (*q == '/') {
40 394 : if (slash)
41 3 : return false;
42 :
43 391 : slash = true;
44 : } else {
45 : bool good;
46 :
47 2417 : good =
48 4834 : (*q >= 'a' && *q <= 'z') ||
49 119 : (*q >= 'A' && *q <= 'Z') ||
50 2494 : (*q >= '0' && *q <= '9') ||
51 18 : *q == '_';
52 :
53 2417 : if (!good)
54 1 : return false;
55 :
56 2416 : slash = false;
57 : }
58 :
59 301 : if (slash)
60 2 : return false;
61 :
62 299 : return true;
63 : }
64 :
65 61 : char* object_path_startswith(const char *a, const char *b) {
66 : const char *p;
67 :
68 122 : if (!object_path_is_valid(a) ||
69 61 : !object_path_is_valid(b))
70 1 : return NULL;
71 :
72 60 : if (streq(b, "/"))
73 21 : return (char*) a + 1;
74 :
75 39 : p = startswith(a, b);
76 39 : if (!p)
77 4 : return NULL;
78 :
79 35 : if (*p == 0)
80 4 : return (char*) p;
81 :
82 31 : if (*p == '/')
83 31 : return (char*) p + 1;
84 :
85 0 : return NULL;
86 : }
87 :
88 15668 : bool interface_name_is_valid(const char *p) {
89 : const char *q;
90 15668 : bool dot, found_dot = false;
91 :
92 15668 : if (isempty(p))
93 0 : return false;
94 :
95 267548 : for (dot = true, q = p; *q; q++)
96 251880 : if (*q == '.') {
97 15907 : if (dot)
98 0 : return false;
99 :
100 15907 : found_dot = dot = true;
101 : } else {
102 : bool good;
103 :
104 235973 : good =
105 471946 : (*q >= 'a' && *q <= 'z') ||
106 404 : (*q >= 'A' && *q <= 'Z') ||
107 235975 : (!dot && *q >= '0' && *q <= '9') ||
108 0 : *q == '_';
109 :
110 235973 : if (!good)
111 0 : return false;
112 :
113 235973 : dot = false;
114 : }
115 :
116 15668 : if (q - p > 255)
117 0 : return false;
118 :
119 15668 : if (dot)
120 0 : return false;
121 :
122 15668 : if (!found_dot)
123 0 : return false;
124 :
125 15668 : return true;
126 : }
127 :
128 15617 : bool service_name_is_valid(const char *p) {
129 : const char *q;
130 15617 : bool dot, found_dot = false, unique;
131 :
132 15617 : if (isempty(p))
133 0 : return false;
134 :
135 15617 : unique = p[0] == ':';
136 :
137 127392 : for (dot = true, q = unique ? p+1 : p; *q; q++)
138 111775 : if (*q == '.') {
139 15837 : if (dot)
140 0 : return false;
141 :
142 15837 : found_dot = dot = true;
143 : } else {
144 : bool good;
145 :
146 95938 : good =
147 191876 : (*q >= 'a' && *q <= 'z') ||
148 185974 : (*q >= 'A' && *q <= 'Z') ||
149 123921 : ((!dot || unique) && *q >= '0' && *q <= '9') ||
150 95938 : *q == '_' || *q == '-';
151 :
152 95938 : if (!good)
153 0 : return false;
154 :
155 95938 : dot = false;
156 : }
157 :
158 15617 : if (q - p > 255)
159 0 : return false;
160 :
161 15617 : if (dot)
162 0 : return false;
163 :
164 15617 : if (!found_dot)
165 0 : return false;
166 :
167 15617 : return true;
168 : }
169 :
170 8 : char* service_name_startswith(const char *a, const char *b) {
171 : const char *p;
172 :
173 16 : if (!service_name_is_valid(a) ||
174 8 : !service_name_is_valid(b))
175 0 : return NULL;
176 :
177 8 : p = startswith(a, b);
178 8 : if (!p)
179 2 : return NULL;
180 :
181 6 : if (*p == 0)
182 1 : return (char*) p;
183 :
184 5 : if (*p == '.')
185 2 : return (char*) p + 1;
186 :
187 3 : return NULL;
188 : }
189 :
190 15684 : bool member_name_is_valid(const char *p) {
191 : const char *q;
192 :
193 15684 : if (isempty(p))
194 0 : return false;
195 :
196 79377 : for (q = p; *q; q++) {
197 : bool good;
198 :
199 63693 : good =
200 127386 : (*q >= 'a' && *q <= 'z') ||
201 31618 : (*q >= 'A' && *q <= 'Z') ||
202 63713 : (*q >= '0' && *q <= '9') ||
203 0 : *q == '_';
204 :
205 63693 : if (!good)
206 0 : return false;
207 : }
208 :
209 15684 : if (q - p > 255)
210 0 : return false;
211 :
212 15684 : return true;
213 : }
214 :
215 : /*
216 : * Complex pattern match
217 : * This checks whether @a is a 'complex-prefix' of @b, or @b is a
218 : * 'complex-prefix' of @a, based on strings that consist of labels with @c as
219 : * spearator. This function returns true if:
220 : * - both strings are equal
221 : * - either is a prefix of the other and ends with @c
222 : * The second rule makes sure that either string needs to be fully included in
223 : * the other, and the string which is considered the prefix needs to end with a
224 : * separator.
225 : */
226 26 : static bool complex_pattern_check(char c, const char *a, const char *b) {
227 26 : bool separator = false;
228 :
229 26 : if (!a && !b)
230 0 : return true;
231 :
232 26 : if (!a || !b)
233 0 : return false;
234 :
235 : for (;;) {
236 142 : if (*a != *b)
237 19 : return (separator && (*a == 0 || *b == 0));
238 :
239 123 : if (*a == 0)
240 7 : return true;
241 :
242 116 : separator = *a == c;
243 :
244 116 : a++, b++;
245 116 : }
246 : }
247 :
248 10 : bool namespace_complex_pattern(const char *pattern, const char *value) {
249 10 : return complex_pattern_check('.', pattern, value);
250 : }
251 :
252 16 : bool path_complex_pattern(const char *pattern, const char *value) {
253 16 : return complex_pattern_check('/', pattern, value);
254 : }
255 :
256 : /*
257 : * Simple pattern match
258 : * This checks whether @a is a 'simple-prefix' of @b, based on strings that
259 : * consist of labels with @c as separator. This function returns true, if:
260 : * - if @a and @b are equal
261 : * - if @a is a prefix of @b, and the first following character in @b (or the
262 : * last character in @a) is @c
263 : * The second rule basically makes sure that if @a is a prefix of @b, then @b
264 : * must follow with a new label separated by @c. It cannot extend the label.
265 : */
266 22 : static bool simple_pattern_check(char c, const char *a, const char *b) {
267 22 : bool separator = false;
268 :
269 22 : if (!a && !b)
270 0 : return true;
271 :
272 22 : if (!a || !b)
273 0 : return false;
274 :
275 : for (;;) {
276 124 : if (*a != *b)
277 17 : return *a == 0 && (*b == c || separator);
278 :
279 107 : if (*a == 0)
280 5 : return true;
281 :
282 102 : separator = *a == c;
283 :
284 102 : a++, b++;
285 102 : }
286 : }
287 :
288 11 : bool namespace_simple_pattern(const char *pattern, const char *value) {
289 11 : return simple_pattern_check('.', pattern, value);
290 : }
291 :
292 11 : bool path_simple_pattern(const char *pattern, const char *value) {
293 11 : return simple_pattern_check('/', pattern, value);
294 : }
295 :
296 28 : int bus_message_type_from_string(const char *s, uint8_t *u) {
297 28 : if (streq(s, "signal"))
298 12 : *u = SD_BUS_MESSAGE_SIGNAL;
299 16 : else if (streq(s, "method_call"))
300 8 : *u = SD_BUS_MESSAGE_METHOD_CALL;
301 8 : else if (streq(s, "error"))
302 4 : *u = SD_BUS_MESSAGE_METHOD_ERROR;
303 4 : else if (streq(s, "method_return"))
304 4 : *u = SD_BUS_MESSAGE_METHOD_RETURN;
305 : else
306 0 : return -EINVAL;
307 :
308 28 : return 0;
309 : }
310 :
311 128 : const char *bus_message_type_to_string(uint8_t u) {
312 128 : if (u == SD_BUS_MESSAGE_SIGNAL)
313 97 : return "signal";
314 31 : else if (u == SD_BUS_MESSAGE_METHOD_CALL)
315 20 : return "method_call";
316 11 : else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
317 5 : return "error";
318 6 : else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
319 6 : return "method_return";
320 : else
321 0 : return NULL;
322 : }
323 :
324 0 : char *bus_address_escape(const char *v) {
325 : const char *a;
326 : char *r, *b;
327 :
328 0 : r = new(char, strlen(v)*3+1);
329 0 : if (!r)
330 0 : return NULL;
331 :
332 0 : for (a = v, b = r; *a; a++) {
333 :
334 0 : if ((*a >= '0' && *a <= '9') ||
335 0 : (*a >= 'a' && *a <= 'z') ||
336 0 : (*a >= 'A' && *a <= 'Z') ||
337 0 : strchr("_-/.", *a))
338 0 : *(b++) = *a;
339 : else {
340 0 : *(b++) = '%';
341 0 : *(b++) = hexchar(*a >> 4);
342 0 : *(b++) = hexchar(*a & 0xF);
343 : }
344 : }
345 :
346 0 : *b = 0;
347 0 : return r;
348 : }
349 :
350 53 : int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
351 53 : assert(m);
352 :
353 53 : if (r < 0) {
354 0 : if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
355 0 : sd_bus_reply_method_errno(m, r, error);
356 :
357 53 : } else if (sd_bus_error_is_set(error)) {
358 0 : if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
359 0 : sd_bus_reply_method_error(m, error);
360 : } else
361 53 : return r;
362 :
363 0 : log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s",
364 : bus_message_type_to_string(m->header->type),
365 : strna(m->sender),
366 : strna(m->path),
367 : strna(m->interface),
368 : strna(m->member),
369 : strna(m->root_container.signature),
370 : bus_error_message(error, r));
371 :
372 0 : return 1;
373 : }
|