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