chiark / gitweb /
Prep v229: Remove remaining emacs settings [3/6] src/libelogind
[elogind.git] / src / libelogind / sd-bus / bus-internal.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include "alloc-util.h"
21 #include "bus-internal.h"
22 #include "bus-message.h"
23 #include "hexdecoct.h"
24 #include "string-util.h"
25
26 bool object_path_is_valid(const char *p) {
27         const char *q;
28         bool slash;
29
30         if (!p)
31                 return false;
32
33         if (p[0] != '/')
34                 return false;
35
36         if (p[1] == 0)
37                 return true;
38
39         for (slash = true, q = p+1; *q; q++)
40                 if (*q == '/') {
41                         if (slash)
42                                 return false;
43
44                         slash = true;
45                 } else {
46                         bool good;
47
48                         good =
49                                 (*q >= 'a' && *q <= 'z') ||
50                                 (*q >= 'A' && *q <= 'Z') ||
51                                 (*q >= '0' && *q <= '9') ||
52                                 *q == '_';
53
54                         if (!good)
55                                 return false;
56
57                         slash = false;
58                 }
59
60         if (slash)
61                 return false;
62
63         return true;
64 }
65
66 char* object_path_startswith(const char *a, const char *b) {
67         const char *p;
68
69         if (!object_path_is_valid(a) ||
70             !object_path_is_valid(b))
71                 return NULL;
72
73         if (streq(b, "/"))
74                 return (char*) a + 1;
75
76         p = startswith(a, b);
77         if (!p)
78                 return NULL;
79
80         if (*p == 0)
81                 return (char*) p;
82
83         if (*p == '/')
84                 return (char*) p + 1;
85
86         return NULL;
87 }
88
89 bool interface_name_is_valid(const char *p) {
90         const char *q;
91         bool dot, found_dot = false;
92
93         if (isempty(p))
94                 return false;
95
96         for (dot = true, q = p; *q; q++)
97                 if (*q == '.') {
98                         if (dot)
99                                 return false;
100
101                         found_dot = dot = true;
102                 } else {
103                         bool good;
104
105                         good =
106                                 (*q >= 'a' && *q <= 'z') ||
107                                 (*q >= 'A' && *q <= 'Z') ||
108                                 (!dot && *q >= '0' && *q <= '9') ||
109                                 *q == '_';
110
111                         if (!good)
112                                 return false;
113
114                         dot = false;
115                 }
116
117         if (q - p > 255)
118                 return false;
119
120         if (dot)
121                 return false;
122
123         if (!found_dot)
124                 return false;
125
126         return true;
127 }
128
129 bool service_name_is_valid(const char *p) {
130         const char *q;
131         bool dot, found_dot = false, unique;
132
133         if (isempty(p))
134                 return false;
135
136         unique = p[0] == ':';
137
138         for (dot = true, q = unique ? p+1 : p; *q; q++)
139                 if (*q == '.') {
140                         if (dot)
141                                 return false;
142
143                         found_dot = dot = true;
144                 } else {
145                         bool good;
146
147                         good =
148                                 (*q >= 'a' && *q <= 'z') ||
149                                 (*q >= 'A' && *q <= 'Z') ||
150                                 ((!dot || unique) && *q >= '0' && *q <= '9') ||
151                                 *q == '_' || *q == '-';
152
153                         if (!good)
154                                 return false;
155
156                         dot = false;
157                 }
158
159         if (q - p > 255)
160                 return false;
161
162         if (dot)
163                 return false;
164
165         if (!found_dot)
166                 return false;
167
168         return true;
169 }
170
171 #if 0 /// UNNEEDED by elogind
172 char* service_name_startswith(const char *a, const char *b) {
173         const char *p;
174
175         if (!service_name_is_valid(a) ||
176             !service_name_is_valid(b))
177                 return NULL;
178
179         p = startswith(a, b);
180         if (!p)
181                 return NULL;
182
183         if (*p == 0)
184                 return (char*) p;
185
186         if (*p == '.')
187                 return (char*) p + 1;
188
189         return NULL;
190 }
191 #endif // 0
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 }