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_BUILD_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 
36 typedef struct
37 {
38   const char *data;
39   DBusValidity expected;
40 } ValidityTest;
41 
42 static void
run_validity_tests(const ValidityTest * tests,int n_tests,DBusValidity (* func)(const DBusString *,int,int))43 run_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;
52       DBusValidity v;
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'\n",
61                       v, tests[i].data);
62           _dbus_assert_not_reached ("test failed");
63         }
64 
65       ++i;
66     }
67 }
68 
69 static const ValidityTest signature_tests[] = {
70   { "", DBUS_VALID },
71   { "i", 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_STRUCT_ENDED_BUT_NOT_STARTED },
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   /* { "a{i}", DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD }, */
101   /* { "{is}", DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY }, */
102   /* { "a{isi}", DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS }, */
103 };
104 
105 dbus_bool_t
_dbus_marshal_validate_test(void)106 _dbus_marshal_validate_test (void)
107 {
108   DBusString str;
109   int i;
110 
111   const char *valid_paths[] = {
112     "/",
113     "/foo/bar",
114     "/foo",
115     "/foo/bar/baz"
116   };
117   const char *invalid_paths[] = {
118     "bar",
119     "bar/baz",
120     "/foo/bar/",
121     "/foo/"
122     "foo/",
123     "boo//blah",
124     "//",
125     "///",
126     "foo///blah/",
127     "Hello World",
128     "",
129     "   ",
130     "foo bar"
131   };
132 
133   const char *valid_interfaces[] = {
134     "org.freedesktop.Foo",
135     "Bar.Baz",
136     "Blah.Blah.Blah.Blah.Blah",
137     "a.b",
138     "a.b.c.d.e.f.g",
139     "a0.b1.c2.d3.e4.f5.g6",
140     "abc123.foo27"
141   };
142   const char *invalid_interfaces[] = {
143     ".",
144     "",
145     "..",
146     ".Foo.Bar",
147     "..Foo.Bar",
148     "Foo.Bar.",
149     "Foo.Bar..",
150     "Foo",
151     "9foo.bar.baz",
152     "foo.bar..baz",
153     "foo.bar...baz",
154     "foo.bar.b..blah",
155     ":",
156     ":0-1",
157     "10",
158     ":11.34324",
159     "0.0.0",
160     "0..0",
161     "foo.Bar.%",
162     "foo.Bar!!",
163     "!Foo.bar.bz",
164     "foo.$.blah",
165     "",
166     "   ",
167     "foo bar"
168   };
169 
170   const char *valid_unique_names[] = {
171     ":0",
172     ":a",
173     ":",
174     ":.a",
175     ":.1",
176     ":0.1",
177     ":000.2222",
178     ":.blah",
179     ":abce.freedesktop.blah"
180   };
181   const char *invalid_unique_names[] = {
182     //":-",
183     ":!",
184     //":0-10",
185     ":blah.",
186     ":blah.",
187     ":blah..org",
188     ":blah.org..",
189     ":..blah.org",
190     "",
191     "   ",
192     "foo bar"
193   };
194 
195   const char *valid_members[] = {
196     "Hello",
197     "Bar",
198     "foobar",
199     "_foobar",
200     "foo89"
201   };
202 
203   const char *invalid_members[] = {
204     "9Hello",
205     "10",
206     "1",
207     "foo-bar",
208     "blah.org",
209     ".blah",
210     "blah.",
211     "Hello.",
212     "!foo",
213     "",
214     "   ",
215     "foo bar"
216   };
217 
218   const char *valid_signatures[] = {
219     "",
220     "sss",
221     "i",
222     "b"
223   };
224 
225   const char *invalid_signatures[] = {
226     " ",
227     "not a valid signature",
228     "123",
229     ".",
230     "(",
231     "a{(ii)i}" /* https://bugs.freedesktop.org/show_bug.cgi?id=17803 */
232   };
233 
234   /* Signature with reason */
235 
236   run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests),
237                       _dbus_validate_signature_with_reason);
238 
239   /* Path validation */
240   i = 0;
241   while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
242     {
243       _dbus_string_init_const (&str, valid_paths[i]);
244 
245       if (!_dbus_validate_path (&str, 0,
246                                 _dbus_string_get_length (&str)))
247         {
248           _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]);
249           _dbus_assert_not_reached ("invalid path");
250         }
251 
252       ++i;
253     }
254 
255   i = 0;
256   while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
257     {
258       _dbus_string_init_const (&str, invalid_paths[i]);
259 
260       if (_dbus_validate_path (&str, 0,
261                                _dbus_string_get_length (&str)))
262         {
263           _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]);
264           _dbus_assert_not_reached ("valid path");
265         }
266 
267       ++i;
268     }
269 
270   /* Interface validation */
271   i = 0;
272   while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
273     {
274       _dbus_string_init_const (&str, valid_interfaces[i]);
275 
276       if (!_dbus_validate_interface (&str, 0,
277                                      _dbus_string_get_length (&str)))
278         {
279           _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]);
280           _dbus_assert_not_reached ("invalid interface");
281         }
282 
283       ++i;
284     }
285 
286   i = 0;
287   while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
288     {
289       _dbus_string_init_const (&str, invalid_interfaces[i]);
290 
291       if (_dbus_validate_interface (&str, 0,
292                                     _dbus_string_get_length (&str)))
293         {
294           _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]);
295           _dbus_assert_not_reached ("valid interface");
296         }
297 
298       ++i;
299     }
300 
301   /* Bus name validation (check that valid interfaces are valid bus names,
302    * and invalid interfaces are invalid services except if they start with ':')
303    */
304   i = 0;
305   while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
306     {
307       _dbus_string_init_const (&str, valid_interfaces[i]);
308 
309       if (!_dbus_validate_bus_name (&str, 0,
310                                    _dbus_string_get_length (&str)))
311         {
312           _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_interfaces[i]);
313           _dbus_assert_not_reached ("invalid bus name");
314         }
315 
316       ++i;
317     }
318 
319   i = 0;
320   while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
321     {
322       if (invalid_interfaces[i][0] != ':')
323         {
324           _dbus_string_init_const (&str, invalid_interfaces[i]);
325 
326           if (_dbus_validate_bus_name (&str, 0,
327                                        _dbus_string_get_length (&str)))
328             {
329               _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_interfaces[i]);
330               _dbus_assert_not_reached ("valid bus name");
331             }
332         }
333 
334       ++i;
335     }
336 
337   /* unique name validation */
338   i = 0;
339   while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names))
340     {
341       _dbus_string_init_const (&str, valid_unique_names[i]);
342 
343       if (!_dbus_validate_bus_name (&str, 0,
344                                     _dbus_string_get_length (&str)))
345         {
346           _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_unique_names[i]);
347           _dbus_assert_not_reached ("invalid unique name");
348         }
349 
350       ++i;
351     }
352 
353   i = 0;
354   while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names))
355     {
356       _dbus_string_init_const (&str, invalid_unique_names[i]);
357 
358       if (_dbus_validate_bus_name (&str, 0,
359                                    _dbus_string_get_length (&str)))
360         {
361           _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_unique_names[i]);
362           _dbus_assert_not_reached ("valid unique name");
363         }
364 
365       ++i;
366     }
367 
368 
369   /* Error name validation (currently identical to interfaces)
370    */
371   i = 0;
372   while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
373     {
374       _dbus_string_init_const (&str, valid_interfaces[i]);
375 
376       if (!_dbus_validate_error_name (&str, 0,
377                                       _dbus_string_get_length (&str)))
378         {
379           _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]);
380           _dbus_assert_not_reached ("invalid error name");
381         }
382 
383       ++i;
384     }
385 
386   i = 0;
387   while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
388     {
389       if (invalid_interfaces[i][0] != ':')
390         {
391           _dbus_string_init_const (&str, invalid_interfaces[i]);
392 
393           if (_dbus_validate_error_name (&str, 0,
394                                          _dbus_string_get_length (&str)))
395             {
396               _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]);
397               _dbus_assert_not_reached ("valid error name");
398             }
399         }
400 
401       ++i;
402     }
403 
404   /* Member validation */
405   i = 0;
406   while (i < (int) _DBUS_N_ELEMENTS (valid_members))
407     {
408       _dbus_string_init_const (&str, valid_members[i]);
409 
410       if (!_dbus_validate_member (&str, 0,
411                                   _dbus_string_get_length (&str)))
412         {
413           _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]);
414           _dbus_assert_not_reached ("invalid member");
415         }
416 
417       ++i;
418     }
419 
420   i = 0;
421   while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
422     {
423       _dbus_string_init_const (&str, invalid_members[i]);
424 
425       if (_dbus_validate_member (&str, 0,
426                                  _dbus_string_get_length (&str)))
427         {
428           _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]);
429           _dbus_assert_not_reached ("valid member");
430         }
431 
432       ++i;
433     }
434 
435   /* Signature validation */
436   i = 0;
437   while (i < (int) _DBUS_N_ELEMENTS (valid_signatures))
438     {
439       _dbus_string_init_const (&str, valid_signatures[i]);
440 
441       if (!_dbus_validate_signature (&str, 0,
442                                      _dbus_string_get_length (&str)))
443         {
444           _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]);
445           _dbus_assert_not_reached ("invalid signature");
446         }
447 
448       ++i;
449     }
450 
451   i = 0;
452   while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures))
453     {
454       _dbus_string_init_const (&str, invalid_signatures[i]);
455 
456       if (_dbus_validate_signature (&str, 0,
457                                     _dbus_string_get_length (&str)))
458         {
459           _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]);
460           _dbus_assert_not_reached ("valid signature");
461         }
462 
463       ++i;
464     }
465 
466   /* Validate claimed length longer than real length */
467   _dbus_string_init_const (&str, "abc.efg");
468   if (_dbus_validate_bus_name (&str, 0, 8))
469     _dbus_assert_not_reached ("validated too-long string");
470   if (_dbus_validate_interface (&str, 0, 8))
471     _dbus_assert_not_reached ("validated too-long string");
472   if (_dbus_validate_error_name (&str, 0, 8))
473     _dbus_assert_not_reached ("validated too-long string");
474 
475   _dbus_string_init_const (&str, "abc");
476   if (_dbus_validate_member (&str, 0, 4))
477     _dbus_assert_not_reached ("validated too-long string");
478 
479   _dbus_string_init_const (&str, "sss");
480   if (_dbus_validate_signature (&str, 0, 4))
481     _dbus_assert_not_reached ("validated too-long signature");
482 
483   /* Validate string exceeding max name length */
484   if (!_dbus_string_init (&str))
485     _dbus_assert_not_reached ("no memory");
486 
487   while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
488     if (!_dbus_string_append (&str, "abc.def"))
489       _dbus_assert_not_reached ("no memory");
490 
491   if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
492     _dbus_assert_not_reached ("validated overmax string");
493   if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str)))
494     _dbus_assert_not_reached ("validated overmax string");
495   if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
496     _dbus_assert_not_reached ("validated overmax string");
497 
498   /* overlong member */
499   _dbus_string_set_length (&str, 0);
500   while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
501     if (!_dbus_string_append (&str, "abc"))
502       _dbus_assert_not_reached ("no memory");
503 
504   if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str)))
505     _dbus_assert_not_reached ("validated overmax string");
506 
507   /* overlong unique name */
508   _dbus_string_set_length (&str, 0);
509   _dbus_string_append (&str, ":");
510   while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
511     if (!_dbus_string_append (&str, "abc"))
512       _dbus_assert_not_reached ("no memory");
513 
514   if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
515     _dbus_assert_not_reached ("validated overmax string");
516 
517   _dbus_string_free (&str);
518 
519   /* Body validation; test basic validation of valid bodies for both endian */
520 
521   {
522     int sequence;
523     DBusString signature;
524     DBusString body;
525 
526     if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
527       _dbus_assert_not_reached ("oom");
528 
529     sequence = 0;
530     while (dbus_internal_do_not_use_generate_bodies (sequence,
531                                                      DBUS_LITTLE_ENDIAN,
532                                                      &signature, &body))
533       {
534         DBusValidity validity;
535 
536         validity = _dbus_validate_body_with_reason (&signature, 0,
537                                                     DBUS_LITTLE_ENDIAN,
538                                                     NULL, &body, 0,
539                                                     _dbus_string_get_length (&body));
540         if (validity != DBUS_VALID)
541           {
542             _dbus_warn ("invalid code %d expected valid on sequence %d little endian\n",
543                         validity, sequence);
544             _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
545             _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
546             _dbus_assert_not_reached ("test failed");
547           }
548 
549         _dbus_string_set_length (&signature, 0);
550         _dbus_string_set_length (&body, 0);
551         ++sequence;
552       }
553 
554     sequence = 0;
555     while (dbus_internal_do_not_use_generate_bodies (sequence,
556                                                      DBUS_BIG_ENDIAN,
557                                                      &signature, &body))
558       {
559         DBusValidity validity;
560 
561         validity = _dbus_validate_body_with_reason (&signature, 0,
562                                                     DBUS_BIG_ENDIAN,
563                                                     NULL, &body, 0,
564                                                     _dbus_string_get_length (&body));
565         if (validity != DBUS_VALID)
566           {
567             _dbus_warn ("invalid code %d expected valid on sequence %d big endian\n",
568                         validity, sequence);
569             _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
570             _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
571             _dbus_assert_not_reached ("test failed");
572           }
573 
574         _dbus_string_set_length (&signature, 0);
575         _dbus_string_set_length (&body, 0);
576         ++sequence;
577       }
578 
579     _dbus_string_free (&signature);
580     _dbus_string_free (&body);
581   }
582 
583   return TRUE;
584 }
585 
586 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
587 
588 #endif /* DBUS_BUILD_TESTS */
589