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