dbus-marshal-validate.c revision 8873c90f99303f9cc308f15f8d03e637911f5b9e
1/* -*- mode: C; c-file-style: "gnu" -*- */
2/* dbus-marshal-validate.c Validation routines for marshaled data
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 */
23
24#include "dbus-internals.h"
25#include "dbus-marshal-validate.h"
26#include "dbus-marshal-recursive.h"
27
28/**
29 * @addtogroup DBusMarshal
30 *
31 * @{
32 */
33
34/**
35 * Verifies that the range of type_str from type_pos to type_end is a
36 * valid signature.  If this function returns #TRUE, it will be safe
37 * to iterate over the signature with a types-only #DBusTypeReader.
38 * The range passed in should NOT include the terminating
39 * nul/DBUS_TYPE_INVALID.
40 *
41 * @param type_str the string
42 * @param type_pos where the typecodes start
43 * @param len length of typecodes
44 * @returns #DBUS_VALID if valid, reason why invalid otherwise
45 */
46DBusValidity
47_dbus_validate_signature_with_reason (const DBusString *type_str,
48                                      int               type_pos,
49                                      int               len)
50{
51  const unsigned char *p;
52  const unsigned char *end;
53  int last;
54  int struct_depth;
55  int array_depth;
56
57  _dbus_assert (type_str != NULL);
58  _dbus_assert (type_pos < _DBUS_INT_MAX - len);
59  _dbus_assert (len >= 0);
60  _dbus_assert (type_pos >= 0);
61
62  if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH)
63    return DBUS_INVALID_SIGNATURE_TOO_LONG;
64
65  p = _dbus_string_get_const_data_len (type_str, type_pos, 0);
66  end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0);
67  struct_depth = 0;
68  array_depth = 0;
69  last = DBUS_TYPE_INVALID;
70
71  while (p != end)
72    {
73      switch (*p)
74        {
75        case DBUS_TYPE_BYTE:
76        case DBUS_TYPE_BOOLEAN:
77        case DBUS_TYPE_INT32:
78        case DBUS_TYPE_UINT32:
79        case DBUS_TYPE_INT64:
80        case DBUS_TYPE_UINT64:
81        case DBUS_TYPE_DOUBLE:
82        case DBUS_TYPE_STRING:
83        case DBUS_TYPE_OBJECT_PATH:
84        case DBUS_TYPE_SIGNATURE:
85        case DBUS_TYPE_VARIANT:
86          break;
87
88        case DBUS_TYPE_ARRAY:
89          array_depth += 1;
90          if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
91            return DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
92          break;
93
94        case DBUS_STRUCT_BEGIN_CHAR:
95          struct_depth += 1;
96
97          if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
98            return DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
99          break;
100
101        case DBUS_STRUCT_END_CHAR:
102          if (struct_depth == 0)
103            return DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
104
105          if (last == DBUS_STRUCT_BEGIN_CHAR)
106            return DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
107
108          struct_depth -= 1;
109          break;
110
111        case DBUS_TYPE_STRUCT: /* doesn't appear in signatures */
112        default:
113          return DBUS_INVALID_UNKNOWN_TYPECODE;
114        }
115
116      if (*p != DBUS_TYPE_ARRAY)
117        array_depth = 0;
118
119      last = *p;
120      ++p;
121    }
122
123  if (array_depth > 0)
124    return DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE;
125
126  if (struct_depth > 0)
127    return DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
128
129  return DBUS_VALID;
130}
131
132static DBusValidity
133validate_body_helper (DBusTypeReader       *reader,
134                      int                   byte_order,
135                      dbus_bool_t           walk_reader_to_end,
136                      const unsigned char  *p,
137                      const unsigned char  *end,
138                      const unsigned char **new_p)
139{
140  int current_type;
141
142  while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
143    {
144      const unsigned char *a;
145      int alignment;
146
147      _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
148                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
149                     (int) (end - p));
150
151      /* Guarantee that p has one byte to look at */
152      if (p == end)
153        return DBUS_INVALID_NOT_ENOUGH_DATA;
154
155      switch (current_type)
156        {
157        case DBUS_TYPE_BYTE:
158          ++p;
159          break;
160
161        case DBUS_TYPE_BOOLEAN:
162        case DBUS_TYPE_INT32:
163        case DBUS_TYPE_UINT32:
164        case DBUS_TYPE_INT64:
165        case DBUS_TYPE_UINT64:
166        case DBUS_TYPE_DOUBLE:
167          alignment = _dbus_type_get_alignment (current_type);
168          a = _DBUS_ALIGN_ADDRESS (p, alignment);
169          if (a >= end)
170            return DBUS_INVALID_NOT_ENOUGH_DATA;
171          while (p != a)
172            {
173              if (*p != '\0')
174                return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
175              ++p;
176            }
177
178          if (current_type == DBUS_TYPE_BOOLEAN)
179            {
180              dbus_uint32_t v = _dbus_unpack_uint32 (byte_order,
181                                                     p);
182              if (!(v == 0 || v == 1))
183                return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
184            }
185
186          p += alignment;
187          break;
188
189        case DBUS_TYPE_ARRAY:
190        case DBUS_TYPE_STRING:
191        case DBUS_TYPE_OBJECT_PATH:
192          {
193            dbus_uint32_t claimed_len;
194
195            a = _DBUS_ALIGN_ADDRESS (p, 4);
196            if (a + 4 >= end)
197              return DBUS_INVALID_NOT_ENOUGH_DATA;
198            while (p != a)
199              {
200                if (*p != '\0')
201                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
202                ++p;
203              }
204
205            claimed_len = _dbus_unpack_uint32 (byte_order, p);
206            p += 4;
207
208            if (current_type == DBUS_TYPE_ARRAY)
209              {
210                int array_elem_type = _dbus_type_reader_get_element_type (reader);
211                alignment = _dbus_type_get_alignment (array_elem_type);
212                p = _DBUS_ALIGN_ADDRESS (p, alignment);
213              }
214
215            if (claimed_len > (unsigned long) (end - p))
216              return DBUS_INVALID_STRING_LENGTH_OUT_OF_BOUNDS;
217
218            if (current_type == DBUS_TYPE_OBJECT_PATH)
219              {
220                DBusString str;
221                _dbus_string_init_const_len (&str, p, claimed_len);
222                if (!_dbus_validate_path (&str, 0,
223                                          _dbus_string_get_length (&str)))
224                  return DBUS_INVALID_BAD_PATH;
225
226                p += claimed_len;
227              }
228            else if (current_type == DBUS_TYPE_STRING)
229              {
230                DBusString str;
231                _dbus_string_init_const_len (&str, p, claimed_len);
232                if (!_dbus_string_validate_utf8 (&str, 0,
233                                                 _dbus_string_get_length (&str)))
234                  return DBUS_INVALID_BAD_UTF8_IN_STRING;
235
236                p += claimed_len;
237              }
238            else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
239              {
240                DBusTypeReader sub;
241                DBusValidity validity;
242                const unsigned char *array_end;
243
244                /* Remember that the reader is types only, so we can't
245                 * use it to iterate over elements. It stays the same
246                 * for all elements.
247                 */
248                _dbus_type_reader_recurse (reader, &sub);
249
250                array_end = p + claimed_len;
251
252                while (p < array_end)
253                  {
254                    validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
255                    if (validity != DBUS_VALID)
256                      return validity;
257                  }
258
259                if (p != array_end)
260                  return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
261              }
262
263            /* check nul termination */
264            if (current_type != DBUS_TYPE_ARRAY)
265              {
266                if (p == end)
267                  return DBUS_INVALID_NOT_ENOUGH_DATA;
268
269                if (*p != '\0')
270                  return DBUS_INVALID_STRING_MISSING_NUL;
271                ++p;
272              }
273          }
274          break;
275
276        case DBUS_TYPE_SIGNATURE:
277          {
278            dbus_uint32_t claimed_len;
279            DBusString str;
280
281            claimed_len = *p;
282            ++p;
283
284            /* 1 is for nul termination */
285            if (claimed_len + 1 > (unsigned long) (end - p))
286              return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
287
288            _dbus_string_init_const_len (&str, p, claimed_len);
289            if (!_dbus_validate_signature (&str, 0,
290                                           _dbus_string_get_length (&str)))
291              return DBUS_INVALID_BAD_SIGNATURE;
292
293            p += claimed_len;
294
295            _dbus_assert (p < end);
296            if (*p != DBUS_TYPE_INVALID)
297              return DBUS_INVALID_SIGNATURE_MISSING_NUL;
298
299            ++p;
300
301            _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
302          }
303          break;
304
305        case DBUS_TYPE_VARIANT:
306          {
307            /* 1 byte sig len, sig typecodes, align to
308             * contained-type-boundary, values.
309             */
310
311            /* In addition to normal signature validation, we need to be sure
312             * the signature contains only a single (possibly container) type.
313             */
314            dbus_uint32_t claimed_len;
315            DBusString sig;
316            DBusTypeReader sub;
317            DBusValidity validity;
318            int contained_alignment;
319
320            claimed_len = *p;
321            ++p;
322
323            /* + 1 for nul */
324            if (claimed_len + 1 > (unsigned long) (end - p))
325              return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
326
327            _dbus_string_init_const_len (&sig, p, claimed_len);
328            if (!_dbus_validate_signature (&sig, 0,
329                                           _dbus_string_get_length (&sig)))
330              return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
331
332            p += claimed_len;
333
334            if (*p != DBUS_TYPE_INVALID)
335              return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
336            ++p;
337
338            contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0));
339
340            a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
341            if (a > end)
342              return DBUS_INVALID_NOT_ENOUGH_DATA;
343            while (p != a)
344              {
345                if (*p != '\0')
346                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
347                ++p;
348              }
349
350            _dbus_type_reader_init_types_only (&sub, &sig, 0);
351
352            if (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID)
353              return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
354
355            validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
356            if (validity != DBUS_VALID)
357              return validity;
358
359            if (_dbus_type_reader_next (&sub))
360              return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;
361
362            _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
363          }
364          break;
365
366        case DBUS_TYPE_STRUCT:
367          {
368            DBusTypeReader sub;
369            DBusValidity validity;
370
371            a = _DBUS_ALIGN_ADDRESS (p, 8);
372            if (a > end)
373              return DBUS_INVALID_NOT_ENOUGH_DATA;
374            while (p != a)
375              {
376                if (*p != '\0')
377                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
378                ++p;
379              }
380
381            _dbus_type_reader_recurse (reader, &sub);
382
383            validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
384            if (validity != DBUS_VALID)
385              return validity;
386          }
387          break;
388
389        default:
390          _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
391          break;
392        }
393
394      _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
395                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
396                     (int) (end - p));
397
398      if (p > end)
399        {
400          _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
401                         p, end, (int) (end - p));
402          return DBUS_INVALID_NOT_ENOUGH_DATA;
403        }
404
405      if (walk_reader_to_end)
406        _dbus_type_reader_next (reader);
407      else
408        break;
409    }
410
411  if (new_p)
412    *new_p = p;
413
414  return DBUS_VALID;
415}
416
417/**
418 * Verifies that the range of value_str from value_pos to value_end is
419 * a legitimate value of type expected_signature.  If this function
420 * returns #TRUE, it will be safe to iterate over the values with
421 * #DBusTypeReader. The signature is assumed to be already valid.
422 *
423 * If bytes_remaining is not #NULL, then leftover bytes will be stored
424 * there and #DBUS_VALID returned. If it is #NULL, then
425 * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left
426 * over.
427 *
428 * @param expected_signature the expected types in the value_str
429 * @param expected_signature_start where in expected_signature is the signature
430 * @param byte_order the byte order
431 * @param bytes_remaining place to store leftover bytes
432 * @param value_str the string containing the body
433 * @param value_pos where the values start
434 * @param len length of values after value_pos
435 * @returns #DBUS_VALID if valid, reason why invalid otherwise
436 */
437DBusValidity
438_dbus_validate_body_with_reason (const DBusString *expected_signature,
439                                 int               expected_signature_start,
440                                 int               byte_order,
441                                 int              *bytes_remaining,
442                                 const DBusString *value_str,
443                                 int               value_pos,
444                                 int               len)
445{
446  DBusTypeReader reader;
447  const unsigned char *p;
448  const unsigned char *end;
449  DBusValidity validity;
450
451  _dbus_assert (len >= 0);
452  _dbus_assert (value_pos >= 0);
453  _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len);
454
455  _dbus_verbose ("validating body from pos %d len %d sig '%s'\n",
456                 value_pos, len, _dbus_string_get_const_data_len (expected_signature,
457                                                                  expected_signature_start,
458                                                                  0));
459
460  _dbus_type_reader_init_types_only (&reader,
461                                     expected_signature, expected_signature_start);
462
463  p = _dbus_string_get_const_data_len (value_str, value_pos, len);
464  end = p + len;
465
466  validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
467  if (validity != DBUS_VALID)
468    return validity;
469
470  if (bytes_remaining)
471    {
472      *bytes_remaining = end - p;
473      return DBUS_VALID;
474    }
475  else if (p < end)
476    return DBUS_INVALID_TOO_MUCH_DATA;
477  else
478    {
479      _dbus_assert (p == end);
480      return DBUS_VALID;
481    }
482}
483
484/**
485 * Determine wether the given charater is valid as the first charater
486 * in a name.
487 */
488#define VALID_INITIAL_NAME_CHARACTER(c)         \
489  ( ((c) >= 'A' && (c) <= 'Z') ||               \
490    ((c) >= 'a' && (c) <= 'z') ||               \
491    ((c) == '_') )
492
493/**
494 * Determine wether the given charater is valid as a second or later
495 * character in a name
496 */
497#define VALID_NAME_CHARACTER(c)                 \
498  ( ((c) >= '0' && (c) <= '9') ||               \
499    ((c) >= 'A' && (c) <= 'Z') ||               \
500    ((c) >= 'a' && (c) <= 'z') ||               \
501    ((c) == '_') )
502
503/**
504 * Checks that the given range of the string is a valid object path
505 * name in the D-BUS protocol. Part of the validation ensures that
506 * the object path contains only ASCII.
507 *
508 * @todo this is inconsistent with most of DBusString in that
509 * it allows a start,len range that extends past the string end.
510 *
511 * @todo change spec to disallow more things, such as spaces in the
512 * path name
513 *
514 * @param str the string
515 * @param start first byte index to check
516 * @param len number of bytes to check
517 * @returns #TRUE if the byte range exists and is a valid name
518 */
519dbus_bool_t
520_dbus_validate_path (const DBusString  *str,
521                     int                start,
522                     int                len)
523{
524  const unsigned char *s;
525  const unsigned char *end;
526  const unsigned char *last_slash;
527
528  _dbus_assert (start >= 0);
529  _dbus_assert (len >= 0);
530  _dbus_assert (start <= _dbus_string_get_length (str));
531
532  if (len > _dbus_string_get_length (str) - start)
533    return FALSE;
534
535  if (len == 0)
536    return FALSE;
537
538  s = _dbus_string_get_const_data (str) + start;
539  end = s + len;
540
541  if (*s != '/')
542    return FALSE;
543  last_slash = s;
544  ++s;
545
546  while (s != end)
547    {
548      if (*s == '/')
549        {
550          if ((s - last_slash) < 2)
551            return FALSE; /* no empty path components allowed */
552
553          last_slash = s;
554        }
555      else
556        {
557          if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
558            return FALSE;
559        }
560
561      ++s;
562    }
563
564  if ((end - last_slash) < 2 &&
565      len > 1)
566    return FALSE; /* trailing slash not allowed unless the string is "/" */
567
568  return TRUE;
569}
570
571/**
572 * Checks that the given range of the string is a valid interface name
573 * in the D-BUS protocol. This includes a length restriction and an
574 * ASCII subset, see the specification.
575 *
576 * @todo this is inconsistent with most of DBusString in that
577 * it allows a start,len range that extends past the string end.
578 *
579 * @param str the string
580 * @param start first byte index to check
581 * @param len number of bytes to check
582 * @returns #TRUE if the byte range exists and is a valid name
583 */
584dbus_bool_t
585_dbus_validate_interface (const DBusString  *str,
586                          int                start,
587                          int                len)
588{
589  const unsigned char *s;
590  const unsigned char *end;
591  const unsigned char *iface;
592  const unsigned char *last_dot;
593
594  _dbus_assert (start >= 0);
595  _dbus_assert (len >= 0);
596  _dbus_assert (start <= _dbus_string_get_length (str));
597
598  if (len > _dbus_string_get_length (str) - start)
599    return FALSE;
600
601  if (len > DBUS_MAXIMUM_NAME_LENGTH)
602    return FALSE;
603
604  if (len == 0)
605    return FALSE;
606
607  last_dot = NULL;
608  iface = _dbus_string_get_const_data (str) + start;
609  end = iface + len;
610  s = iface;
611
612  /* check special cases of first char so it doesn't have to be done
613   * in the loop. Note we know len > 0
614   */
615  if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
616    return FALSE;
617  else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
618    return FALSE;
619  else
620    ++s;
621
622  while (s != end)
623    {
624      if (*s == '.')
625        {
626          if (_DBUS_UNLIKELY ((s + 1) == end))
627            return FALSE;
628          else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
629            return FALSE;
630          last_dot = s;
631          ++s; /* we just validated the next char, so skip two */
632        }
633      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
634        {
635          return FALSE;
636        }
637
638      ++s;
639    }
640
641  if (_DBUS_UNLIKELY (last_dot == NULL))
642    return FALSE;
643
644  return TRUE;
645}
646
647/**
648 * Checks that the given range of the string is a valid member name
649 * in the D-BUS protocol. This includes a length restriction, etc.,
650 * see the specification.
651 *
652 * @todo this is inconsistent with most of DBusString in that
653 * it allows a start,len range that extends past the string end.
654 *
655 * @param str the string
656 * @param start first byte index to check
657 * @param len number of bytes to check
658 * @returns #TRUE if the byte range exists and is a valid name
659 */
660dbus_bool_t
661_dbus_validate_member (const DBusString  *str,
662                       int                start,
663                       int                len)
664{
665  const unsigned char *s;
666  const unsigned char *end;
667  const unsigned char *member;
668
669  _dbus_assert (start >= 0);
670  _dbus_assert (len >= 0);
671  _dbus_assert (start <= _dbus_string_get_length (str));
672
673  if (len > _dbus_string_get_length (str) - start)
674    return FALSE;
675
676  if (len > DBUS_MAXIMUM_NAME_LENGTH)
677    return FALSE;
678
679  if (len == 0)
680    return FALSE;
681
682  member = _dbus_string_get_const_data (str) + start;
683  end = member + len;
684  s = member;
685
686  /* check special cases of first char so it doesn't have to be done
687   * in the loop. Note we know len > 0
688   */
689
690  if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
691    return FALSE;
692  else
693    ++s;
694
695  while (s != end)
696    {
697      if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
698        {
699          return FALSE;
700        }
701
702      ++s;
703    }
704
705  return TRUE;
706}
707
708/**
709 * Checks that the given range of the string is a valid error name
710 * in the D-BUS protocol. This includes a length restriction, etc.,
711 * see the specification.
712 *
713 * @todo this is inconsistent with most of DBusString in that
714 * it allows a start,len range that extends past the string end.
715 *
716 * @param str the string
717 * @param start first byte index to check
718 * @param len number of bytes to check
719 * @returns #TRUE if the byte range exists and is a valid name
720 */
721dbus_bool_t
722_dbus_validate_error_name (const DBusString  *str,
723                           int                start,
724                           int                len)
725{
726  /* Same restrictions as interface name at the moment */
727  return _dbus_validate_interface (str, start, len);
728}
729
730/* This assumes the first char exists and is ':' */
731static dbus_bool_t
732_dbus_validate_unique_name (const DBusString  *str,
733                            int                start,
734                            int                len)
735{
736  const unsigned char *s;
737  const unsigned char *end;
738  const unsigned char *name;
739
740  _dbus_assert (start >= 0);
741  _dbus_assert (len >= 0);
742  _dbus_assert (start <= _dbus_string_get_length (str));
743
744  if (len > _dbus_string_get_length (str) - start)
745    return FALSE;
746
747  if (len > DBUS_MAXIMUM_NAME_LENGTH)
748    return FALSE;
749
750  _dbus_assert (len > 0);
751
752  name = _dbus_string_get_const_data (str) + start;
753  end = name + len;
754  _dbus_assert (*name == ':');
755  s = name + 1;
756
757  while (s != end)
758    {
759      if (*s == '.')
760        {
761          if (_DBUS_UNLIKELY ((s + 1) == end))
762            return FALSE;
763          if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
764            return FALSE;
765          ++s; /* we just validated the next char, so skip two */
766        }
767      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
768        {
769          return FALSE;
770        }
771
772      ++s;
773    }
774
775  return TRUE;
776}
777
778/**
779 * Checks that the given range of the string is a valid bus name in
780 * the D-BUS protocol. This includes a length restriction, etc., see
781 * the specification.
782 *
783 * @todo this is inconsistent with most of DBusString in that
784 * it allows a start,len range that extends past the string end.
785 *
786 * @param str the string
787 * @param start first byte index to check
788 * @param len number of bytes to check
789 * @returns #TRUE if the byte range exists and is a valid name
790 */
791dbus_bool_t
792_dbus_validate_bus_name (const DBusString  *str,
793                         int                start,
794                         int                len)
795{
796  if (_DBUS_UNLIKELY (len == 0))
797    return FALSE;
798  if (_dbus_string_get_byte (str, start) == ':')
799    return _dbus_validate_unique_name (str, start, len);
800  else
801    return _dbus_validate_interface (str, start, len);
802}
803
804/**
805 * Checks that the given range of the string is a valid message type
806 * signature in the D-BUS protocol.
807 *
808 * @todo this is inconsistent with most of DBusString in that
809 * it allows a start,len range that extends past the string end.
810 *
811 * @param str the string
812 * @param start first byte index to check
813 * @param len number of bytes to check
814 * @returns #TRUE if the byte range exists and is a valid signature
815 */
816dbus_bool_t
817_dbus_validate_signature (const DBusString  *str,
818                          int                start,
819                          int                len)
820{
821  _dbus_assert (start >= 0);
822  _dbus_assert (start <= _dbus_string_get_length (str));
823  _dbus_assert (len >= 0);
824
825  if (len > _dbus_string_get_length (str) - start)
826    return FALSE;
827
828  return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID;
829}
830
831/** define _dbus_check_is_valid_path() */
832DEFINE_DBUS_NAME_CHECK(path);
833/** define _dbus_check_is_valid_interface() */
834DEFINE_DBUS_NAME_CHECK(interface);
835/** define _dbus_check_is_valid_member() */
836DEFINE_DBUS_NAME_CHECK(member);
837/** define _dbus_check_is_valid_error_name() */
838DEFINE_DBUS_NAME_CHECK(error_name);
839/** define _dbus_check_is_valid_bus_name() */
840DEFINE_DBUS_NAME_CHECK(bus_name);
841/** define _dbus_check_is_valid_signature() */
842DEFINE_DBUS_NAME_CHECK(signature);
843
844/** @} */
845
846#ifdef DBUS_BUILD_TESTS
847#include "dbus-test.h"
848#include <stdio.h>
849
850typedef struct
851{
852  const char *data;
853  DBusValidity expected;
854} ValidityTest;
855
856static void
857run_validity_tests (const ValidityTest *tests,
858                    int                 n_tests,
859                    DBusValidity (* func) (const DBusString*,int,int))
860{
861  int i;
862
863  for (i = 0; i < n_tests; i++)
864    {
865      DBusString str;
866      DBusValidity v;
867
868      _dbus_string_init_const (&str, tests[i].data);
869
870      v = (*func) (&str, 0, _dbus_string_get_length (&str));
871
872      if (v != tests[i].expected)
873        {
874          _dbus_warn ("Improper validation result %d for '%s'\n",
875                      v, tests[i].data);
876          _dbus_assert_not_reached ("test failed");
877        }
878
879      ++i;
880    }
881}
882
883static const ValidityTest signature_tests[] = {
884  { "", DBUS_VALID },
885  { "i", DBUS_VALID },
886  { "ai", DBUS_VALID },
887  { "(i)", DBUS_VALID },
888  { "q", DBUS_INVALID_UNKNOWN_TYPECODE },
889  { "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
890  { "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
891  { "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
892  { "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
893  /* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */
894  { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
895    DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION },
896  { "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))",
897    DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION },
898  { ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
899  { "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
900  { "a)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
901  { "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
902  { "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
903  { "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
904  { "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
905  { "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
906  { "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
907  { "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
908  { "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
909  { "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }
910};
911
912dbus_bool_t
913_dbus_marshal_validate_test (void)
914{
915  DBusString str;
916  int i;
917
918  const char *valid_paths[] = {
919    "/",
920    "/foo/bar",
921    "/foo",
922    "/foo/bar/baz"
923  };
924  const char *invalid_paths[] = {
925    "bar",
926    "bar/baz",
927    "/foo/bar/",
928    "/foo/"
929    "foo/",
930    "boo//blah",
931    "//",
932    "///",
933    "foo///blah/",
934    "Hello World",
935    "",
936    "   ",
937    "foo bar"
938  };
939
940  const char *valid_interfaces[] = {
941    "org.freedesktop.Foo",
942    "Bar.Baz",
943    "Blah.Blah.Blah.Blah.Blah",
944    "a.b",
945    "a.b.c.d.e.f.g",
946    "a0.b1.c2.d3.e4.f5.g6",
947    "abc123.foo27"
948  };
949  const char *invalid_interfaces[] = {
950    ".",
951    "",
952    "..",
953    ".Foo.Bar",
954    "..Foo.Bar",
955    "Foo.Bar.",
956    "Foo.Bar..",
957    "Foo",
958    "9foo.bar.baz",
959    "foo.bar..baz",
960    "foo.bar...baz",
961    "foo.bar.b..blah",
962    ":",
963    ":0-1",
964    "10",
965    ":11.34324",
966    "0.0.0",
967    "0..0",
968    "foo.Bar.%",
969    "foo.Bar!!",
970    "!Foo.bar.bz",
971    "foo.$.blah",
972    "",
973    "   ",
974    "foo bar"
975  };
976
977  const char *valid_unique_names[] = {
978    ":0",
979    ":a",
980    ":",
981    ":.a",
982    ":.1",
983    ":0.1",
984    ":000.2222",
985    ":.blah",
986    ":abce.freedesktop.blah"
987  };
988  const char *invalid_unique_names[] = {
989    ":-",
990    ":!",
991    ":0-10",
992    ":blah.",
993    ":blah.",
994    ":blah..org",
995    ":blah.org..",
996    ":..blah.org",
997    "",
998    "   ",
999    "foo bar"
1000  };
1001
1002  const char *valid_members[] = {
1003    "Hello",
1004    "Bar",
1005    "foobar",
1006    "_foobar",
1007    "foo89"
1008  };
1009
1010  const char *invalid_members[] = {
1011    "9Hello",
1012    "10",
1013    "1",
1014    "foo-bar",
1015    "blah.org",
1016    ".blah",
1017    "blah.",
1018    "Hello.",
1019    "!foo",
1020    "",
1021    "   ",
1022    "foo bar"
1023  };
1024
1025  const char *valid_signatures[] = {
1026    "",
1027    "sss",
1028    "i",
1029    "b"
1030  };
1031
1032  const char *invalid_signatures[] = {
1033    " ",
1034    "not a valid signature",
1035    "123",
1036    ".",
1037    "("
1038  };
1039
1040  /* Signature with reason */
1041
1042  run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests),
1043                      _dbus_validate_signature_with_reason);
1044
1045  /* Path validation */
1046  i = 0;
1047  while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
1048    {
1049      _dbus_string_init_const (&str, valid_paths[i]);
1050
1051      if (!_dbus_validate_path (&str, 0,
1052                                _dbus_string_get_length (&str)))
1053        {
1054          _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]);
1055          _dbus_assert_not_reached ("invalid path");
1056        }
1057
1058      ++i;
1059    }
1060
1061  i = 0;
1062  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
1063    {
1064      _dbus_string_init_const (&str, invalid_paths[i]);
1065
1066      if (_dbus_validate_path (&str, 0,
1067                               _dbus_string_get_length (&str)))
1068        {
1069          _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]);
1070          _dbus_assert_not_reached ("valid path");
1071        }
1072
1073      ++i;
1074    }
1075
1076  /* Interface validation */
1077  i = 0;
1078  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
1079    {
1080      _dbus_string_init_const (&str, valid_interfaces[i]);
1081
1082      if (!_dbus_validate_interface (&str, 0,
1083                                     _dbus_string_get_length (&str)))
1084        {
1085          _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]);
1086          _dbus_assert_not_reached ("invalid interface");
1087        }
1088
1089      ++i;
1090    }
1091
1092  i = 0;
1093  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
1094    {
1095      _dbus_string_init_const (&str, invalid_interfaces[i]);
1096
1097      if (_dbus_validate_interface (&str, 0,
1098                                    _dbus_string_get_length (&str)))
1099        {
1100          _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]);
1101          _dbus_assert_not_reached ("valid interface");
1102        }
1103
1104      ++i;
1105    }
1106
1107  /* Bus name validation (check that valid interfaces are valid bus names,
1108   * and invalid interfaces are invalid services except if they start with ':')
1109   */
1110  i = 0;
1111  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
1112    {
1113      _dbus_string_init_const (&str, valid_interfaces[i]);
1114
1115      if (!_dbus_validate_bus_name (&str, 0,
1116                                   _dbus_string_get_length (&str)))
1117        {
1118          _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_interfaces[i]);
1119          _dbus_assert_not_reached ("invalid bus name");
1120        }
1121
1122      ++i;
1123    }
1124
1125  i = 0;
1126  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
1127    {
1128      if (invalid_interfaces[i][0] != ':')
1129        {
1130          _dbus_string_init_const (&str, invalid_interfaces[i]);
1131
1132          if (_dbus_validate_bus_name (&str, 0,
1133                                       _dbus_string_get_length (&str)))
1134            {
1135              _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_interfaces[i]);
1136              _dbus_assert_not_reached ("valid bus name");
1137            }
1138        }
1139
1140      ++i;
1141    }
1142
1143  /* unique name validation */
1144  i = 0;
1145  while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names))
1146    {
1147      _dbus_string_init_const (&str, valid_unique_names[i]);
1148
1149      if (!_dbus_validate_bus_name (&str, 0,
1150                                    _dbus_string_get_length (&str)))
1151        {
1152          _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_unique_names[i]);
1153          _dbus_assert_not_reached ("invalid unique name");
1154        }
1155
1156      ++i;
1157    }
1158
1159  i = 0;
1160  while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names))
1161    {
1162      _dbus_string_init_const (&str, invalid_unique_names[i]);
1163
1164      if (_dbus_validate_bus_name (&str, 0,
1165                                   _dbus_string_get_length (&str)))
1166        {
1167          _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_unique_names[i]);
1168          _dbus_assert_not_reached ("valid unique name");
1169        }
1170
1171      ++i;
1172    }
1173
1174
1175  /* Error name validation (currently identical to interfaces)
1176   */
1177  i = 0;
1178  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
1179    {
1180      _dbus_string_init_const (&str, valid_interfaces[i]);
1181
1182      if (!_dbus_validate_error_name (&str, 0,
1183                                      _dbus_string_get_length (&str)))
1184        {
1185          _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]);
1186          _dbus_assert_not_reached ("invalid error name");
1187        }
1188
1189      ++i;
1190    }
1191
1192  i = 0;
1193  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
1194    {
1195      if (invalid_interfaces[i][0] != ':')
1196        {
1197          _dbus_string_init_const (&str, invalid_interfaces[i]);
1198
1199          if (_dbus_validate_error_name (&str, 0,
1200                                         _dbus_string_get_length (&str)))
1201            {
1202              _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]);
1203              _dbus_assert_not_reached ("valid error name");
1204            }
1205        }
1206
1207      ++i;
1208    }
1209
1210  /* Member validation */
1211  i = 0;
1212  while (i < (int) _DBUS_N_ELEMENTS (valid_members))
1213    {
1214      _dbus_string_init_const (&str, valid_members[i]);
1215
1216      if (!_dbus_validate_member (&str, 0,
1217                                  _dbus_string_get_length (&str)))
1218        {
1219          _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]);
1220          _dbus_assert_not_reached ("invalid member");
1221        }
1222
1223      ++i;
1224    }
1225
1226  i = 0;
1227  while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
1228    {
1229      _dbus_string_init_const (&str, invalid_members[i]);
1230
1231      if (_dbus_validate_member (&str, 0,
1232                                 _dbus_string_get_length (&str)))
1233        {
1234          _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]);
1235          _dbus_assert_not_reached ("valid member");
1236        }
1237
1238      ++i;
1239    }
1240
1241  /* Signature validation */
1242  i = 0;
1243  while (i < (int) _DBUS_N_ELEMENTS (valid_signatures))
1244    {
1245      _dbus_string_init_const (&str, valid_signatures[i]);
1246
1247      if (!_dbus_validate_signature (&str, 0,
1248                                     _dbus_string_get_length (&str)))
1249        {
1250          _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]);
1251          _dbus_assert_not_reached ("invalid signature");
1252        }
1253
1254      ++i;
1255    }
1256
1257  i = 0;
1258  while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures))
1259    {
1260      _dbus_string_init_const (&str, invalid_signatures[i]);
1261
1262      if (_dbus_validate_signature (&str, 0,
1263                                    _dbus_string_get_length (&str)))
1264        {
1265          _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]);
1266          _dbus_assert_not_reached ("valid signature");
1267        }
1268
1269      ++i;
1270    }
1271
1272  /* Validate claimed length longer than real length */
1273  _dbus_string_init_const (&str, "abc.efg");
1274  if (_dbus_validate_bus_name (&str, 0, 8))
1275    _dbus_assert_not_reached ("validated too-long string");
1276  if (_dbus_validate_interface (&str, 0, 8))
1277    _dbus_assert_not_reached ("validated too-long string");
1278  if (_dbus_validate_error_name (&str, 0, 8))
1279    _dbus_assert_not_reached ("validated too-long string");
1280
1281  _dbus_string_init_const (&str, "abc");
1282  if (_dbus_validate_member (&str, 0, 4))
1283    _dbus_assert_not_reached ("validated too-long string");
1284
1285  _dbus_string_init_const (&str, "sss");
1286  if (_dbus_validate_signature (&str, 0, 4))
1287    _dbus_assert_not_reached ("validated too-long signature");
1288
1289  /* Validate string exceeding max name length */
1290  if (!_dbus_string_init (&str))
1291    _dbus_assert_not_reached ("no memory");
1292
1293  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
1294    if (!_dbus_string_append (&str, "abc.def"))
1295      _dbus_assert_not_reached ("no memory");
1296
1297  if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
1298    _dbus_assert_not_reached ("validated overmax string");
1299  if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str)))
1300    _dbus_assert_not_reached ("validated overmax string");
1301  if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
1302    _dbus_assert_not_reached ("validated overmax string");
1303
1304  /* overlong member */
1305  _dbus_string_set_length (&str, 0);
1306  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
1307    if (!_dbus_string_append (&str, "abc"))
1308      _dbus_assert_not_reached ("no memory");
1309
1310  if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str)))
1311    _dbus_assert_not_reached ("validated overmax string");
1312
1313  /* overlong unique name */
1314  _dbus_string_set_length (&str, 0);
1315  _dbus_string_append (&str, ":");
1316  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
1317    if (!_dbus_string_append (&str, "abc"))
1318      _dbus_assert_not_reached ("no memory");
1319
1320  if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
1321    _dbus_assert_not_reached ("validated overmax string");
1322
1323  _dbus_string_free (&str);
1324
1325  return TRUE;
1326}
1327
1328#endif /* DBUS_BUILD_TESTS */
1329