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
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;
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
69static 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
105dbus_bool_t
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