D-Bus 1.12.4
dbus-marshal-validate-util.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-marshal-validate-util.c Would be in dbus-marshal-validate.c, but only used by tests/bus
3 *
4 * Copyright (C) 2005 Red Hat, Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24#include <config.h>
25#ifdef DBUS_ENABLE_EMBEDDED_TESTS
26
27#ifndef DOXYGEN_SHOULD_SKIP_THIS
28
29#include "dbus-internals.h"
30#include "dbus-marshal-validate.h"
31#include "dbus-marshal-recursive.h"
32
33#include "dbus-test.h"
34#include <stdio.h>
35
36typedef struct
37{
38 const char *data;
39 DBusValidity expected;
40} ValidityTest;
41
42static void
43run_validity_tests (const ValidityTest *tests,
44 int n_tests,
45 DBusValidity (* func) (const DBusString*,int,int))
46{
47 int i;
48
49 for (i = 0; i < n_tests; i++)
50 {
51 DBusString str;
53
54 _dbus_string_init_const (&str, tests[i].data);
55
56 v = (*func) (&str, 0, _dbus_string_get_length (&str));
57
58 if (v != tests[i].expected)
59 {
60 _dbus_warn ("Improper validation result %d for '%s'",
61 v, tests[i].data);
62 _dbus_assert_not_reached ("test failed");
63 }
64 }
65}
66
67static const ValidityTest signature_tests[] = {
68 { "", DBUS_VALID },
69 { "sss", DBUS_VALID },
70 { "i", DBUS_VALID },
71 { "b", DBUS_VALID },
72 { "ai", DBUS_VALID },
73 { "(i)", DBUS_VALID },
74 { "w", DBUS_INVALID_UNKNOWN_TYPECODE },
75 { "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
76 { "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
77 { "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
78 { "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
79 /* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */
80 { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
81 DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION },
82 { "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))",
83 DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION },
84 { ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
85 { "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
86 { "a)", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
87 { "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
88 { "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
89 { "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
90 { "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
91 { "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
92 { "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
93 { "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
94 { "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
95 { "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
96 { "(a)", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
97 { "a{ia}", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
98 { "a{}", DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS },
99 { "a{aii}", DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE },
100 { " ", DBUS_INVALID_UNKNOWN_TYPECODE },
101 { "not a valid signature", DBUS_INVALID_UNKNOWN_TYPECODE },
102 { "123", DBUS_INVALID_UNKNOWN_TYPECODE },
103 { ".", DBUS_INVALID_UNKNOWN_TYPECODE },
104 /* https://bugs.freedesktop.org/show_bug.cgi?id=17803 */
105 { "a{(ii)i}", DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE },
106 { "a{i}", DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD },
107 { "{is}", DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY },
108 { "a{isi}", DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS },
109};
110
112_dbus_marshal_validate_test (void)
113{
114 DBusString str;
115 int i;
116
117 const char *valid_paths[] = {
118 "/",
119 "/foo/bar",
120 "/foo",
121 "/foo/bar/baz"
122 };
123 const char *invalid_paths[] = {
124 "bar",
125 "bar/baz",
126 "/foo/bar/",
127 "/foo/",
128 "foo/",
129 "boo//blah",
130 "//",
131 "///",
132 "foo///blah/",
133 "Hello World",
134 "",
135 " ",
136 "foo bar"
137 };
138
139 const char *valid_interfaces[] = {
140 "org.freedesktop.Foo",
141 "Bar.Baz",
142 "Blah.Blah.Blah.Blah.Blah",
143 "a.b",
144 "a.b.c.d.e.f.g",
145 "a0.b1.c2.d3.e4.f5.g6",
146 "abc123.foo27"
147 };
148 const char *invalid_interfaces[] = {
149 ".",
150 "",
151 "..",
152 ".Foo.Bar",
153 "..Foo.Bar",
154 "Foo.Bar.",
155 "Foo.Bar..",
156 "Foo",
157 "9foo.bar.baz",
158 "foo.bar..baz",
159 "foo.bar...baz",
160 "foo.bar.b..blah",
161 ":",
162 ":0-1",
163 "10",
164 ":11.34324",
165 "0.0.0",
166 "0..0",
167 "foo.Bar.%",
168 "foo.Bar!!",
169 "!Foo.bar.bz",
170 "foo.$.blah",
171 "",
172 " ",
173 "foo bar"
174 };
175
176 const char *valid_unique_names[] = {
177 ":0",
178 ":a",
179 ":",
180 ":.a",
181 ":.1",
182 ":0.1",
183 ":000.2222",
184 ":.blah",
185 ":abce.freedesktop.blah"
186 };
187 const char *invalid_unique_names[] = {
188 //":-",
189 ":!",
190 //":0-10",
191 ":blah.",
192 ":blah.",
193 ":blah..org",
194 ":blah.org..",
195 ":..blah.org",
196 "",
197 " ",
198 "foo bar"
199 };
200
201 const char *valid_members[] = {
202 "Hello",
203 "Bar",
204 "foobar",
205 "_foobar",
206 "foo89"
207 };
208
209 const char *invalid_members[] = {
210 "9Hello",
211 "10",
212 "1",
213 "foo-bar",
214 "blah.org",
215 ".blah",
216 "blah.",
217 "Hello.",
218 "!foo",
219 "",
220 " ",
221 "foo bar"
222 };
223
224 /* Signature with reason */
225
226 run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests),
228
229 /* Path validation */
230 i = 0;
231 while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
232 {
233 _dbus_string_init_const (&str, valid_paths[i]);
234
235 if (!_dbus_validate_path (&str, 0,
236 _dbus_string_get_length (&str)))
237 {
238 _dbus_warn ("Path \"%s\" should have been valid", valid_paths[i]);
239 _dbus_assert_not_reached ("invalid path");
240 }
241
242 ++i;
243 }
244
245 i = 0;
246 while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
247 {
248 _dbus_string_init_const (&str, invalid_paths[i]);
249
250 if (_dbus_validate_path (&str, 0,
251 _dbus_string_get_length (&str)))
252 {
253 _dbus_warn ("Path \"%s\" should have been invalid", invalid_paths[i]);
254 _dbus_assert_not_reached ("valid path");
255 }
256
257 ++i;
258 }
259
260 /* Interface validation */
261 i = 0;
262 while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
263 {
264 _dbus_string_init_const (&str, valid_interfaces[i]);
265
266 if (!_dbus_validate_interface (&str, 0,
267 _dbus_string_get_length (&str)))
268 {
269 _dbus_warn ("Interface \"%s\" should have been valid", valid_interfaces[i]);
270 _dbus_assert_not_reached ("invalid interface");
271 }
272
273 ++i;
274 }
275
276 i = 0;
277 while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
278 {
279 _dbus_string_init_const (&str, invalid_interfaces[i]);
280
281 if (_dbus_validate_interface (&str, 0,
282 _dbus_string_get_length (&str)))
283 {
284 _dbus_warn ("Interface \"%s\" should have been invalid", invalid_interfaces[i]);
285 _dbus_assert_not_reached ("valid interface");
286 }
287
288 ++i;
289 }
290
291 /* Bus name validation (check that valid interfaces are valid bus names,
292 * and invalid interfaces are invalid services except if they start with ':')
293 */
294 i = 0;
295 while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
296 {
297 _dbus_string_init_const (&str, valid_interfaces[i]);
298
299 if (!_dbus_validate_bus_name (&str, 0,
300 _dbus_string_get_length (&str)))
301 {
302 _dbus_warn ("Bus name \"%s\" should have been valid", valid_interfaces[i]);
303 _dbus_assert_not_reached ("invalid bus name");
304 }
305
306 ++i;
307 }
308
309 i = 0;
310 while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
311 {
312 if (invalid_interfaces[i][0] != ':')
313 {
314 _dbus_string_init_const (&str, invalid_interfaces[i]);
315
316 if (_dbus_validate_bus_name (&str, 0,
317 _dbus_string_get_length (&str)))
318 {
319 _dbus_warn ("Bus name \"%s\" should have been invalid", invalid_interfaces[i]);
320 _dbus_assert_not_reached ("valid bus name");
321 }
322 }
323
324 ++i;
325 }
326
327 /* unique name validation */
328 i = 0;
329 while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names))
330 {
331 _dbus_string_init_const (&str, valid_unique_names[i]);
332
333 if (!_dbus_validate_bus_name (&str, 0,
334 _dbus_string_get_length (&str)))
335 {
336 _dbus_warn ("Bus name \"%s\" should have been valid", valid_unique_names[i]);
337 _dbus_assert_not_reached ("invalid unique name");
338 }
339
340 ++i;
341 }
342
343 i = 0;
344 while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names))
345 {
346 _dbus_string_init_const (&str, invalid_unique_names[i]);
347
348 if (_dbus_validate_bus_name (&str, 0,
349 _dbus_string_get_length (&str)))
350 {
351 _dbus_warn ("Bus name \"%s\" should have been invalid", invalid_unique_names[i]);
352 _dbus_assert_not_reached ("valid unique name");
353 }
354
355 ++i;
356 }
357
358
359 /* Error name validation (currently identical to interfaces)
360 */
361 i = 0;
362 while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
363 {
364 _dbus_string_init_const (&str, valid_interfaces[i]);
365
366 if (!_dbus_validate_error_name (&str, 0,
367 _dbus_string_get_length (&str)))
368 {
369 _dbus_warn ("Error name \"%s\" should have been valid", valid_interfaces[i]);
370 _dbus_assert_not_reached ("invalid error name");
371 }
372
373 ++i;
374 }
375
376 i = 0;
377 while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
378 {
379 if (invalid_interfaces[i][0] != ':')
380 {
381 _dbus_string_init_const (&str, invalid_interfaces[i]);
382
383 if (_dbus_validate_error_name (&str, 0,
384 _dbus_string_get_length (&str)))
385 {
386 _dbus_warn ("Error name \"%s\" should have been invalid", invalid_interfaces[i]);
387 _dbus_assert_not_reached ("valid error name");
388 }
389 }
390
391 ++i;
392 }
393
394 /* Member validation */
395 i = 0;
396 while (i < (int) _DBUS_N_ELEMENTS (valid_members))
397 {
398 _dbus_string_init_const (&str, valid_members[i]);
399
400 if (!_dbus_validate_member (&str, 0,
401 _dbus_string_get_length (&str)))
402 {
403 _dbus_warn ("Member \"%s\" should have been valid", valid_members[i]);
404 _dbus_assert_not_reached ("invalid member");
405 }
406
407 ++i;
408 }
409
410 i = 0;
411 while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
412 {
413 _dbus_string_init_const (&str, invalid_members[i]);
414
415 if (_dbus_validate_member (&str, 0,
416 _dbus_string_get_length (&str)))
417 {
418 _dbus_warn ("Member \"%s\" should have been invalid", invalid_members[i]);
419 _dbus_assert_not_reached ("valid member");
420 }
421
422 ++i;
423 }
424
425 /* Validate claimed length longer than real length */
426 _dbus_string_init_const (&str, "abc.efg");
427 if (_dbus_validate_bus_name (&str, 0, 8))
428 _dbus_assert_not_reached ("validated too-long string");
429 if (_dbus_validate_interface (&str, 0, 8))
430 _dbus_assert_not_reached ("validated too-long string");
431 if (_dbus_validate_error_name (&str, 0, 8))
432 _dbus_assert_not_reached ("validated too-long string");
433
434 _dbus_string_init_const (&str, "abc");
435 if (_dbus_validate_member (&str, 0, 4))
436 _dbus_assert_not_reached ("validated too-long string");
437
438 /* Validate string exceeding max name length */
439 if (!_dbus_string_init (&str))
440 _dbus_assert_not_reached ("no memory");
441
442 while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
443 if (!_dbus_string_append (&str, "abc.def"))
444 _dbus_assert_not_reached ("no memory");
445
446 if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
447 _dbus_assert_not_reached ("validated overmax string");
448 if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str)))
449 _dbus_assert_not_reached ("validated overmax string");
450 if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
451 _dbus_assert_not_reached ("validated overmax string");
452
453 /* overlong member */
454 _dbus_string_set_length (&str, 0);
455 while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
456 if (!_dbus_string_append (&str, "abc"))
457 _dbus_assert_not_reached ("no memory");
458
459 if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str)))
460 _dbus_assert_not_reached ("validated overmax string");
461
462 /* overlong unique name */
463 _dbus_string_set_length (&str, 0);
464 _dbus_string_append (&str, ":");
465 while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
466 if (!_dbus_string_append (&str, "abc"))
467 _dbus_assert_not_reached ("no memory");
468
469 if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
470 _dbus_assert_not_reached ("validated overmax string");
471
472 _dbus_string_free (&str);
473
474 /* Body validation; test basic validation of valid bodies for both endian */
475
476 {
477 int sequence;
478 DBusString signature;
479 DBusString body;
480
481 if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
483
484 sequence = 0;
485 while (dbus_internal_do_not_use_generate_bodies (sequence,
487 &signature, &body))
488 {
489 DBusValidity validity;
490
491 validity = _dbus_validate_body_with_reason (&signature, 0,
493 NULL, &body, 0,
494 _dbus_string_get_length (&body));
495 if (validity != DBUS_VALID)
496 {
497 _dbus_warn ("invalid code %d expected valid on sequence %d little endian",
498 validity, sequence);
499 _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
500 _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
501 _dbus_assert_not_reached ("test failed");
502 }
503
504 _dbus_string_set_length (&signature, 0);
505 _dbus_string_set_length (&body, 0);
506 ++sequence;
507 }
508
509 sequence = 0;
510 while (dbus_internal_do_not_use_generate_bodies (sequence,
512 &signature, &body))
513 {
514 DBusValidity validity;
515
516 validity = _dbus_validate_body_with_reason (&signature, 0,
518 NULL, &body, 0,
519 _dbus_string_get_length (&body));
520 if (validity != DBUS_VALID)
521 {
522 _dbus_warn ("invalid code %d expected valid on sequence %d big endian",
523 validity, sequence);
524 _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
525 _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
526 _dbus_assert_not_reached ("test failed");
527 }
528
529 _dbus_string_set_length (&signature, 0);
530 _dbus_string_set_length (&body, 0);
531 ++sequence;
532 }
533
534 _dbus_string_free (&signature);
535 _dbus_string_free (&body);
536 }
537
538 return TRUE;
539}
540
541#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
542
543#endif /* DBUS_ENABLE_EMBEDDED_TESTS */
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
#define NULL
A null pointer, defined appropriately for C or C++.
#define TRUE
Expands to "1".
DBusValidity
This is primarily used in unit testing, so we can verify that each invalid message is invalid for the...
DBusValidity _dbus_validate_signature_with_reason(const DBusString *type_str, int type_pos, int len)
Verifies that the range of type_str from type_pos to type_end is a valid signature.
DBUS_PRIVATE_EXPORT void _dbus_verbose_bytes_of_string(const DBusString *str, int start, int len)
Dump the given part of the string to verbose log.
dbus_bool_t _dbus_validate_error_name(const DBusString *str, int start, int len)
Checks that the given range of the string is a valid error name in the D-Bus protocol.
dbus_bool_t _dbus_validate_member(const DBusString *str, int start, int len)
Checks that the given range of the string is a valid member name in the D-Bus protocol.
dbus_bool_t _dbus_validate_path(const DBusString *str, int start, int len)
Checks that the given range of the string is a valid object path name in the D-Bus protocol.
dbus_bool_t _dbus_validate_interface(const DBusString *str, int start, int len)
Checks that the given range of the string is a valid interface name in the D-Bus protocol.
DBusValidity _dbus_validate_body_with_reason(const DBusString *expected_signature, int expected_signature_start, int byte_order, int *bytes_remaining, const DBusString *value_str, int value_pos, int len)
Verifies that the range of value_str from value_pos to value_end is a legitimate value of type expect...
dbus_bool_t _dbus_validate_bus_name(const DBusString *str, int start, int len)
Checks that the given range of the string is a valid bus name in the D-Bus protocol.
@ DBUS_VALID
the data is valid
#define DBUS_MAXIMUM_NAME_LENGTH
Max length in bytes of a bus name, interface, or member (not object path, paths are unlimited).
#define DBUS_LITTLE_ENDIAN
Code marking LSB-first byte order in the wire protocol.
Definition: dbus-protocol.h:53
#define DBUS_BIG_ENDIAN
Code marking MSB-first byte order in the wire protocol.
Definition: dbus-protocol.h:54
dbus_bool_t _dbus_string_set_length(DBusString *str, int length)
Sets the length of a string.
Definition: dbus-string.c:802
dbus_bool_t _dbus_string_append(DBusString *str, const char *buffer)
Appends a nul-terminated C-style string to a DBusString.
Definition: dbus-string.c:935
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
void _dbus_string_init_const(DBusString *str, const char *value)
Initializes a constant string.
Definition: dbus-string.c:190
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:259
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35