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