chiark / gitweb /
Prep v221: Update and clean up build system to sync with upstream
[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-message.h"
23 #include "bus-internal.h"
24
25 bool object_path_is_valid(const char *p) {
26         const char *q;
27         bool slash;
28
29         if (!p)
30                 return false;
31
32         if (p[0] != '/')
33                 return false;
34
35         if (p[1] == 0)
36                 return true;
37
38         for (slash = true, q = p+1; *q; q++)
39                 if (*q == '/') {
40                         if (slash)
41                                 return false;
42
43                         slash = true;
44                 } else {
45                         bool good;
46
47                         good =
48                                 (*q >= 'a' && *q <= 'z') ||
49                                 (*q >= 'A' && *q <= 'Z') ||
50                                 (*q >= '0' && *q <= '9') ||
51                                 *q == '_';
52
53                         if (!good)
54                                 return false;
55
56                         slash = false;
57                 }
58
59         if (slash)
60                 return false;
61
62         return true;
63 }
64
65 char* object_path_startswith(const char *a, const char *b) {
66         const char *p;
67
68         if (!object_path_is_valid(a) ||
69             !object_path_is_valid(b))
70                 return NULL;
71
72         if (streq(b, "/"))
73                 return (char*) a + 1;
74
75         p = startswith(a, b);
76         if (!p)
77                 return NULL;
78
79         if (*p == 0)
80                 return (char*) p;
81
82         if (*p == '/')
83                 return (char*) p + 1;
84
85         return NULL;
86 }
87
88 bool interface_name_is_valid(const char *p) {
89         const char *q;
90         bool dot, found_dot = false;
91
92         if (isempty(p))
93                 return false;
94
95         for (dot = true, q = p; *q; q++)
96                 if (*q == '.') {
97                         if (dot)
98                                 return false;
99
100                         found_dot = dot = true;
101                 } else {
102                         bool good;
103
104                         good =
105                                 (*q >= 'a' && *q <= 'z') ||
106                                 (*q >= 'A' && *q <= 'Z') ||
107                                 (!dot && *q >= '0' && *q <= '9') ||
108                                 *q == '_';
109
110                         if (!good)
111                                 return false;
112
113                         dot = false;
114                 }
115
116         if (q - p > 255)
117                 return false;
118
119         if (dot)
120                 return false;
121
122         if (!found_dot)
123                 return false;
124
125         return true;
126 }
127
128 bool service_name_is_valid(const char *p) {
129         const char *q;
130         bool dot, found_dot = false, unique;
131
132         if (isempty(p))
133                 return false;
134
135         unique = p[0] == ':';
136
137         for (dot = true, q = unique ? p+1 : p; *q; q++)
138                 if (*q == '.') {
139                         if (dot)
140                                 return false;
141
142                         found_dot = dot = true;
143                 } else {
144                         bool good;
145
146                         good =
147                                 (*q >= 'a' && *q <= 'z') ||
148                                 (*q >= 'A' && *q <= 'Z') ||
149                                 ((!dot || unique) && *q >= '0' && *q <= '9') ||
150                                 *q == '_' || *q == '-';
151
152                         if (!good)
153                                 return false;
154
155                         dot = false;
156                 }
157
158         if (q - p > 255)
159                 return false;
160
161         if (dot)
162                 return false;
163
164         if (!found_dot)
165                 return false;
166
167         return true;
168 }
169
170 /// UNNEEDED by elogind
171 #if 0
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 }