chiark / gitweb /
bus: let magic ":no-sender" pass the validation
[elogind.git] / src / libsystemd-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 bool sender_name_is_valid(const char *p) {
170         if (isempty(p))
171                 return false;
172
173         if (streq(p, ":no-sender"))
174                 return true;
175
176         return service_name_is_valid(p);
177 }
178
179 bool member_name_is_valid(const char *p) {
180         const char *q;
181
182         if (isempty(p))
183                 return false;
184
185         for (q = p; *q; q++) {
186                 bool good;
187
188                 good =
189                         (*q >= 'a' && *q <= 'z') ||
190                         (*q >= 'A' && *q <= 'Z') ||
191                         (*q >= '0' && *q <= '9') ||
192                         *q == '_';
193
194                 if (!good)
195                         return false;
196         }
197
198         if (q - p > 255)
199                 return false;
200
201         return true;
202 }
203
204 static bool complex_pattern_check(char c, const char *a, const char *b) {
205         bool separator = false;
206
207         if (!a && !b)
208                 return true;
209
210         if (!a || !b)
211                 return false;
212
213         for (;;) {
214                 if (*a != *b)
215                         return (separator && (*a == 0 || *b == 0)) ||
216                                 (*a == 0 && *b == c && b[1] == 0) ||
217                                 (*b == 0 && *a == c && a[1] == 0);
218
219                 if (*a == 0)
220                         return true;
221
222                 separator = *a == c;
223
224                 a++, b++;
225         }
226 }
227
228 bool namespace_complex_pattern(const char *pattern, const char *value) {
229         return complex_pattern_check('.', pattern, value);
230 }
231
232 bool path_complex_pattern(const char *pattern, const char *value) {
233         return complex_pattern_check('/', pattern, value);
234 }
235
236 static bool simple_pattern_check(char c, const char *a, const char *b) {
237
238         if (!a && !b)
239                 return true;
240
241         if (!a || !b)
242                 return false;
243
244         for (;;) {
245                 if (*a != *b)
246                         return *a == 0 && *b == c;
247
248                 if (*a == 0)
249                         return true;
250
251                 a++, b++;
252         }
253 }
254
255 bool namespace_simple_pattern(const char *pattern, const char *value) {
256         return simple_pattern_check('.', pattern, value);
257 }
258
259 bool path_simple_pattern(const char *pattern, const char *value) {
260         return simple_pattern_check('/', pattern, value);
261 }
262
263 int bus_message_type_from_string(const char *s, uint8_t *u) {
264         if (streq(s, "signal"))
265                 *u = SD_BUS_MESSAGE_SIGNAL;
266         else if (streq(s, "method_call"))
267                 *u = SD_BUS_MESSAGE_METHOD_CALL;
268         else if (streq(s, "error"))
269                 *u = SD_BUS_MESSAGE_METHOD_ERROR;
270         else if (streq(s, "method_return"))
271                 *u = SD_BUS_MESSAGE_METHOD_RETURN;
272         else
273                 return -EINVAL;
274
275         return 0;
276 }
277
278 const char *bus_message_type_to_string(uint8_t u) {
279         if (u == SD_BUS_MESSAGE_SIGNAL)
280                 return "signal";
281         else if (u == SD_BUS_MESSAGE_METHOD_CALL)
282                 return "method_call";
283         else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
284                 return "error";
285         else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
286                  return "method_return";
287         else
288                 return NULL;
289 }
290
291 char *bus_address_escape(const char *v) {
292         const char *a;
293         char *r, *b;
294
295         r = new(char, strlen(v)*3+1);
296         if (!r)
297                 return NULL;
298
299         for (a = v, b = r; *a; a++) {
300
301                 if ((*a >= '0' && *a <= '9') ||
302                     (*a >= 'a' && *a <= 'z') ||
303                     (*a >= 'A' && *a <= 'Z') ||
304                     strchr("_-/.", *a))
305                         *(b++) = *a;
306                 else {
307                         *(b++) = '%';
308                         *(b++) = hexchar(*a >> 4);
309                         *(b++) = hexchar(*a & 0xF);
310                 }
311         }
312
313         *b = 0;
314         return r;
315 }