dbus-marshal-validate.c revision 62e465339a306fa564b69935da494dad6e1b474a
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 8-boundary, values. */
308            /* In addition to normal signature validation, we need to be sure
309             * the signature contains only a single (possibly container) type.
310             */
311            dbus_uint32_t claimed_len;
312            DBusString sig;
313            DBusTypeReader sub;
314            DBusValidity validity;
315
316            claimed_len = *p;
317            ++p;
318
319            /* + 1 for nul */
320            if (claimed_len + 1 > (unsigned long) (end - p))
321              return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
322
323            _dbus_string_init_const_len (&sig, p, claimed_len);
324            if (!_dbus_validate_signature (&sig, 0,
325                                           _dbus_string_get_length (&sig)))
326              return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
327
328            p += claimed_len;
329
330            if (*p != DBUS_TYPE_INVALID)
331              return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
332            ++p;
333
334            a = _DBUS_ALIGN_ADDRESS (p, 8);
335            if (a > end)
336              return DBUS_INVALID_NOT_ENOUGH_DATA;
337            while (p != a)
338              {
339                if (*p != '\0')
340                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
341                ++p;
342              }
343
344            _dbus_type_reader_init_types_only (&sub, &sig, 0);
345
346            if (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID)
347              return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
348
349            validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
350            if (validity != DBUS_VALID)
351              return validity;
352
353            if (_dbus_type_reader_next (&sub))
354              return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;
355
356            _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
357          }
358          break;
359
360        case DBUS_TYPE_STRUCT:
361          {
362            DBusTypeReader sub;
363            DBusValidity validity;
364
365            a = _DBUS_ALIGN_ADDRESS (p, 8);
366            if (a > end)
367              return DBUS_INVALID_NOT_ENOUGH_DATA;
368            while (p != a)
369              {
370                if (*p != '\0')
371                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
372                ++p;
373              }
374
375            _dbus_type_reader_recurse (reader, &sub);
376
377            validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
378            if (validity != DBUS_VALID)
379              return validity;
380          }
381          break;
382
383        default:
384          _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
385          break;
386        }
387
388      _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
389                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
390                     (int) (end - p));
391
392      if (p > end)
393        {
394          _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
395                         p, end, (int) (end - p));
396          return DBUS_INVALID_NOT_ENOUGH_DATA;
397        }
398
399      if (walk_reader_to_end)
400        _dbus_type_reader_next (reader);
401      else
402        break;
403    }
404
405  if (new_p)
406    *new_p = p;
407
408  return DBUS_VALID;
409}
410
411/**
412 * Verifies that the range of value_str from value_pos to value_end is
413 * a legitimate value of type expected_signature.  If this function
414 * returns #TRUE, it will be safe to iterate over the values with
415 * #DBusTypeReader. The signature is assumed to be already valid.
416 *
417 * If bytes_remaining is not #NULL, then leftover bytes will be stored
418 * there and #DBUS_VALID returned. If it is #NULL, then
419 * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left
420 * over.
421 *
422 * @param expected_signature the expected types in the value_str
423 * @param expected_signature_start where in expected_signature is the signature
424 * @param byte_order the byte order
425 * @param bytes_remaining place to store leftover bytes
426 * @param value_str the string containing the body
427 * @param value_pos where the values start
428 * @param len length of values after value_pos
429 * @returns #DBUS_VALID if valid, reason why invalid otherwise
430 */
431DBusValidity
432_dbus_validate_body_with_reason (const DBusString *expected_signature,
433                                 int               expected_signature_start,
434                                 int               byte_order,
435                                 int              *bytes_remaining,
436                                 const DBusString *value_str,
437                                 int               value_pos,
438                                 int               len)
439{
440  DBusTypeReader reader;
441  const unsigned char *p;
442  const unsigned char *end;
443  DBusValidity validity;
444
445  _dbus_assert (len >= 0);
446  _dbus_assert (value_pos >= 0);
447  _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len);
448
449  _dbus_verbose ("validating body from pos %d len %d sig '%s'\n",
450                 value_pos, len, _dbus_string_get_const_data_len (expected_signature,
451                                                                  expected_signature_start,
452                                                                  0));
453
454  _dbus_type_reader_init_types_only (&reader,
455                                     expected_signature, expected_signature_start);
456
457  p = _dbus_string_get_const_data_len (value_str, value_pos, len);
458  end = p + len;
459
460  validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
461  if (validity != DBUS_VALID)
462    return validity;
463
464  if (p < end)
465    {
466      if (bytes_remaining)
467        *bytes_remaining = end - p;
468      else
469        return DBUS_INVALID_TOO_MUCH_DATA;
470    }
471
472  return DBUS_VALID;
473}
474
475/**
476 * Checks that the given range of the string is a valid object path
477 * name in the D-BUS protocol. Part of the validation ensures that
478 * the object path contains only ASCII.
479 *
480 * @todo this is inconsistent with most of DBusString in that
481 * it allows a start,len range that extends past the string end.
482 *
483 * @todo change spec to disallow more things, such as spaces in the
484 * path name
485 *
486 * @param str the string
487 * @param start first byte index to check
488 * @param len number of bytes to check
489 * @returns #TRUE if the byte range exists and is a valid name
490 */
491dbus_bool_t
492_dbus_validate_path (const DBusString  *str,
493                     int                start,
494                     int                len)
495{
496  const unsigned char *s;
497  const unsigned char *end;
498  const unsigned char *last_slash;
499
500  _dbus_assert (start >= 0);
501  _dbus_assert (len >= 0);
502  _dbus_assert (start <= _dbus_string_get_length (str));
503
504  if (len > _dbus_string_get_length (str) - start)
505    return FALSE;
506
507  if (len == 0)
508    return FALSE;
509
510  s = _dbus_string_get_const_data (str) + start;
511  end = s + len;
512
513  if (*s != '/')
514    return FALSE;
515  last_slash = s;
516  ++s;
517
518  while (s != end)
519    {
520      if (*s == '/')
521        {
522          if ((s - last_slash) < 2)
523            return FALSE; /* no empty path components allowed */
524
525          last_slash = s;
526        }
527      else
528        {
529          if (_DBUS_UNLIKELY (!_DBUS_ISASCII (*s)))
530            return FALSE;
531        }
532
533      ++s;
534    }
535
536  if ((end - last_slash) < 2 &&
537      len > 1)
538    return FALSE; /* trailing slash not allowed unless the string is "/" */
539
540  return TRUE;
541}
542
543/**
544 * Determine wether the given charater is valid as the first charater
545 * in a name.
546 */
547#define VALID_INITIAL_NAME_CHARACTER(c)         \
548  ( ((c) >= 'A' && (c) <= 'Z') ||               \
549    ((c) >= 'a' && (c) <= 'z') ||               \
550    ((c) == '_') )
551
552/**
553 * Determine wether the given charater is valid as a second or later
554 * character in a name
555 */
556#define VALID_NAME_CHARACTER(c)                 \
557  ( ((c) >= '0' && (c) <= '9') ||               \
558    ((c) >= 'A' && (c) <= 'Z') ||               \
559    ((c) >= 'a' && (c) <= 'z') ||               \
560    ((c) == '_') )
561
562/**
563 * Checks that the given range of the string is a valid interface name
564 * in the D-BUS protocol. This includes a length restriction and an
565 * ASCII subset, see the specification.
566 *
567 * @todo this is inconsistent with most of DBusString in that
568 * it allows a start,len range that extends past the string end.
569 *
570 * @param str the string
571 * @param start first byte index to check
572 * @param len number of bytes to check
573 * @returns #TRUE if the byte range exists and is a valid name
574 */
575dbus_bool_t
576_dbus_validate_interface (const DBusString  *str,
577                          int                start,
578                          int                len)
579{
580  const unsigned char *s;
581  const unsigned char *end;
582  const unsigned char *iface;
583  const unsigned char *last_dot;
584
585  _dbus_assert (start >= 0);
586  _dbus_assert (len >= 0);
587  _dbus_assert (start <= _dbus_string_get_length (str));
588
589  if (len > _dbus_string_get_length (str) - start)
590    return FALSE;
591
592  if (len > DBUS_MAXIMUM_NAME_LENGTH)
593    return FALSE;
594
595  if (len == 0)
596    return FALSE;
597
598  last_dot = NULL;
599  iface = _dbus_string_get_const_data (str) + start;
600  end = iface + len;
601  s = iface;
602
603  /* check special cases of first char so it doesn't have to be done
604   * in the loop. Note we know len > 0
605   */
606  if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
607    return FALSE;
608  else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
609    return FALSE;
610  else
611    ++s;
612
613  while (s != end)
614    {
615      if (*s == '.')
616        {
617          if (_DBUS_UNLIKELY ((s + 1) == end))
618            return FALSE;
619          else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
620            return FALSE;
621          last_dot = s;
622          ++s; /* we just validated the next char, so skip two */
623        }
624      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
625        {
626          return FALSE;
627        }
628
629      ++s;
630    }
631
632  if (_DBUS_UNLIKELY (last_dot == NULL))
633    return FALSE;
634
635  return TRUE;
636}
637
638/**
639 * Checks that the given range of the string is a valid member name
640 * in the D-BUS protocol. This includes a length restriction, etc.,
641 * see the specification.
642 *
643 * @todo this is inconsistent with most of DBusString in that
644 * it allows a start,len range that extends past the string end.
645 *
646 * @param str the string
647 * @param start first byte index to check
648 * @param len number of bytes to check
649 * @returns #TRUE if the byte range exists and is a valid name
650 */
651dbus_bool_t
652_dbus_validate_member (const DBusString  *str,
653                       int                start,
654                       int                len)
655{
656  const unsigned char *s;
657  const unsigned char *end;
658  const unsigned char *member;
659
660  _dbus_assert (start >= 0);
661  _dbus_assert (len >= 0);
662  _dbus_assert (start <= _dbus_string_get_length (str));
663
664  if (len > _dbus_string_get_length (str) - start)
665    return FALSE;
666
667  if (len > DBUS_MAXIMUM_NAME_LENGTH)
668    return FALSE;
669
670  if (len == 0)
671    return FALSE;
672
673  member = _dbus_string_get_const_data (str) + start;
674  end = member + len;
675  s = member;
676
677  /* check special cases of first char so it doesn't have to be done
678   * in the loop. Note we know len > 0
679   */
680
681  if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
682    return FALSE;
683  else
684    ++s;
685
686  while (s != end)
687    {
688      if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
689        {
690          return FALSE;
691        }
692
693      ++s;
694    }
695
696  return TRUE;
697}
698
699/**
700 * Checks that the given range of the string is a valid error name
701 * in the D-BUS protocol. This includes a length restriction, etc.,
702 * see the specification.
703 *
704 * @todo this is inconsistent with most of DBusString in that
705 * it allows a start,len range that extends past the string end.
706 *
707 * @param str the string
708 * @param start first byte index to check
709 * @param len number of bytes to check
710 * @returns #TRUE if the byte range exists and is a valid name
711 */
712dbus_bool_t
713_dbus_validate_error_name (const DBusString  *str,
714                           int                start,
715                           int                len)
716{
717  /* Same restrictions as interface name at the moment */
718  return _dbus_validate_interface (str, start, len);
719}
720
721/* This assumes the first char exists and is ':' */
722static dbus_bool_t
723_dbus_validate_base_service (const DBusString  *str,
724                             int                start,
725                             int                len)
726{
727  const unsigned char *s;
728  const unsigned char *end;
729  const unsigned char *service;
730
731  _dbus_assert (start >= 0);
732  _dbus_assert (len >= 0);
733  _dbus_assert (start <= _dbus_string_get_length (str));
734
735  if (len > _dbus_string_get_length (str) - start)
736    return FALSE;
737
738  if (len > DBUS_MAXIMUM_NAME_LENGTH)
739    return FALSE;
740
741  _dbus_assert (len > 0);
742
743  service = _dbus_string_get_const_data (str) + start;
744  end = service + len;
745  _dbus_assert (*service == ':');
746  s = service + 1;
747
748  while (s != end)
749    {
750      if (*s == '.')
751        {
752          if (_DBUS_UNLIKELY ((s + 1) == end))
753            return FALSE;
754          if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
755            return FALSE;
756          ++s; /* we just validated the next char, so skip two */
757        }
758      else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
759        {
760          return FALSE;
761        }
762
763      ++s;
764    }
765
766  return TRUE;
767}
768
769/**
770 * Checks that the given range of the string is a valid service name
771 * in the D-BUS protocol. This includes a length restriction, etc.,
772 * see the specification.
773 *
774 * @todo this is inconsistent with most of DBusString in that
775 * it allows a start,len range that extends past the string end.
776 *
777 * @param str the string
778 * @param start first byte index to check
779 * @param len number of bytes to check
780 * @returns #TRUE if the byte range exists and is a valid name
781 */
782dbus_bool_t
783_dbus_validate_service (const DBusString  *str,
784                        int                start,
785                        int                len)
786{
787  if (_DBUS_UNLIKELY (len == 0))
788    return FALSE;
789  if (_dbus_string_get_byte (str, start) == ':')
790    return _dbus_validate_base_service (str, start, len);
791  else
792    return _dbus_validate_interface (str, start, len);
793}
794
795/**
796 * Checks that the given range of the string is a valid message type
797 * signature in the D-BUS protocol.
798 *
799 * @todo this is inconsistent with most of DBusString in that
800 * it allows a start,len range that extends past the string end.
801 *
802 * @param str the string
803 * @param start first byte index to check
804 * @param len number of bytes to check
805 * @returns #TRUE if the byte range exists and is a valid signature
806 */
807dbus_bool_t
808_dbus_validate_signature (const DBusString  *str,
809                          int                start,
810                          int                len)
811{
812  _dbus_assert (start >= 0);
813  _dbus_assert (start <= _dbus_string_get_length (str));
814  _dbus_assert (len >= 0);
815
816  if (len > _dbus_string_get_length (str) - start)
817    return FALSE;
818
819  return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID;
820}
821
822/** define _dbus_check_is_valid_path() */
823DEFINE_DBUS_NAME_CHECK(path);
824/** define _dbus_check_is_valid_interface() */
825DEFINE_DBUS_NAME_CHECK(interface);
826/** define _dbus_check_is_valid_member() */
827DEFINE_DBUS_NAME_CHECK(member);
828/** define _dbus_check_is_valid_error_name() */
829DEFINE_DBUS_NAME_CHECK(error_name);
830/** define _dbus_check_is_valid_service() */
831DEFINE_DBUS_NAME_CHECK(service);
832/** define _dbus_check_is_valid_signature() */
833DEFINE_DBUS_NAME_CHECK(signature);
834
835/** @} */
836
837#ifdef DBUS_BUILD_TESTS
838#include "dbus-test.h"
839#include <stdio.h>
840
841typedef struct
842{
843  const char *data;
844  DBusValidity expected;
845} ValidityTest;
846
847static void
848run_validity_tests (const ValidityTest *tests,
849                    int                 n_tests,
850                    DBusValidity (* func) (const DBusString*,int,int))
851{
852  int i;
853
854  for (i = 0; i < n_tests; i++)
855    {
856      DBusString str;
857      DBusValidity v;
858
859      _dbus_string_init_const (&str, tests[i].data);
860
861      v = (*func) (&str, 0, _dbus_string_get_length (&str));
862
863      if (v != tests[i].expected)
864        {
865          _dbus_warn ("Improper validation result %d for '%s'\n",
866                      v, tests[i].data);
867          _dbus_assert_not_reached ("test failed");
868        }
869
870      ++i;
871    }
872}
873
874static const ValidityTest signature_tests[] = {
875  { "", DBUS_VALID },
876  { "i", DBUS_VALID },
877  { "ai", DBUS_VALID },
878  { "(i)", DBUS_VALID },
879  { "q", DBUS_INVALID_UNKNOWN_TYPECODE },
880  { "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
881  { "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
882  { "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
883  { "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE },
884  /* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */
885  { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
886    DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION },
887  { "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))",
888    DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION },
889  { ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
890  { "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
891  { "a)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED },
892  { "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
893  { "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
894  { "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
895  { "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED },
896  { "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
897  { "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
898  { "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
899  { "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS },
900  { "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }
901};
902
903dbus_bool_t
904_dbus_marshal_validate_test (void)
905{
906  DBusString str;
907  int i;
908
909  const char *valid_paths[] = {
910    "/",
911    "/foo/bar",
912    "/foo",
913    "/foo/bar/baz"
914  };
915  const char *invalid_paths[] = {
916    "bar",
917    "bar/baz",
918    "/foo/bar/",
919    "/foo/"
920    "foo/",
921    "boo//blah",
922    "//",
923    "///",
924    "foo///blah/",
925    "Hello World",
926    "",
927    "   ",
928    "foo bar"
929  };
930
931  const char *valid_interfaces[] = {
932    "org.freedesktop.Foo",
933    "Bar.Baz",
934    "Blah.Blah.Blah.Blah.Blah",
935    "a.b",
936    "a.b.c.d.e.f.g",
937    "a0.b1.c2.d3.e4.f5.g6",
938    "abc123.foo27"
939  };
940  const char *invalid_interfaces[] = {
941    ".",
942    "",
943    "..",
944    ".Foo.Bar",
945    "..Foo.Bar",
946    "Foo.Bar.",
947    "Foo.Bar..",
948    "Foo",
949    "9foo.bar.baz",
950    "foo.bar..baz",
951    "foo.bar...baz",
952    "foo.bar.b..blah",
953    ":",
954    ":0-1",
955    "10",
956    ":11.34324",
957    "0.0.0",
958    "0..0",
959    "foo.Bar.%",
960    "foo.Bar!!",
961    "!Foo.bar.bz",
962    "foo.$.blah",
963    "",
964    "   ",
965    "foo bar"
966  };
967
968  const char *valid_base_services[] = {
969    ":0",
970    ":a",
971    ":",
972    ":.a",
973    ":.1",
974    ":0.1",
975    ":000.2222",
976    ":.blah",
977    ":abce.freedesktop.blah"
978  };
979  const char *invalid_base_services[] = {
980    ":-",
981    ":!",
982    ":0-10",
983    ":blah.",
984    ":blah.",
985    ":blah..org",
986    ":blah.org..",
987    ":..blah.org",
988    "",
989    "   ",
990    "foo bar"
991  };
992
993  const char *valid_members[] = {
994    "Hello",
995    "Bar",
996    "foobar",
997    "_foobar",
998    "foo89"
999  };
1000
1001  const char *invalid_members[] = {
1002    "9Hello",
1003    "10",
1004    "1",
1005    "foo-bar",
1006    "blah.org",
1007    ".blah",
1008    "blah.",
1009    "Hello.",
1010    "!foo",
1011    "",
1012    "   ",
1013    "foo bar"
1014  };
1015
1016  const char *valid_signatures[] = {
1017    "",
1018    "sss",
1019    "i",
1020    "b"
1021  };
1022
1023  const char *invalid_signatures[] = {
1024    " ",
1025    "not a valid signature",
1026    "123",
1027    ".",
1028    "("
1029  };
1030
1031  /* Signature with reason */
1032
1033  run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests),
1034                      _dbus_validate_signature_with_reason);
1035
1036  /* Path validation */
1037  i = 0;
1038  while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
1039    {
1040      _dbus_string_init_const (&str, valid_paths[i]);
1041
1042      if (!_dbus_validate_path (&str, 0,
1043                                _dbus_string_get_length (&str)))
1044        {
1045          _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]);
1046          _dbus_assert_not_reached ("invalid path");
1047        }
1048
1049      ++i;
1050    }
1051
1052  i = 0;
1053  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
1054    {
1055      _dbus_string_init_const (&str, invalid_paths[i]);
1056
1057      if (_dbus_validate_path (&str, 0,
1058                               _dbus_string_get_length (&str)))
1059        {
1060          _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]);
1061          _dbus_assert_not_reached ("valid path");
1062        }
1063
1064      ++i;
1065    }
1066
1067  /* Interface validation */
1068  i = 0;
1069  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
1070    {
1071      _dbus_string_init_const (&str, valid_interfaces[i]);
1072
1073      if (!_dbus_validate_interface (&str, 0,
1074                                     _dbus_string_get_length (&str)))
1075        {
1076          _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]);
1077          _dbus_assert_not_reached ("invalid interface");
1078        }
1079
1080      ++i;
1081    }
1082
1083  i = 0;
1084  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
1085    {
1086      _dbus_string_init_const (&str, invalid_interfaces[i]);
1087
1088      if (_dbus_validate_interface (&str, 0,
1089                                    _dbus_string_get_length (&str)))
1090        {
1091          _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]);
1092          _dbus_assert_not_reached ("valid interface");
1093        }
1094
1095      ++i;
1096    }
1097
1098  /* Service validation (check that valid interfaces are valid services,
1099   * and invalid interfaces are invalid services except if they start with ':')
1100   */
1101  i = 0;
1102  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
1103    {
1104      _dbus_string_init_const (&str, valid_interfaces[i]);
1105
1106      if (!_dbus_validate_service (&str, 0,
1107                                   _dbus_string_get_length (&str)))
1108        {
1109          _dbus_warn ("Service \"%s\" should have been valid\n", valid_interfaces[i]);
1110          _dbus_assert_not_reached ("invalid service");
1111        }
1112
1113      ++i;
1114    }
1115
1116  i = 0;
1117  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
1118    {
1119      if (invalid_interfaces[i][0] != ':')
1120        {
1121          _dbus_string_init_const (&str, invalid_interfaces[i]);
1122
1123          if (_dbus_validate_service (&str, 0,
1124                                      _dbus_string_get_length (&str)))
1125            {
1126              _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_interfaces[i]);
1127              _dbus_assert_not_reached ("valid service");
1128            }
1129        }
1130
1131      ++i;
1132    }
1133
1134  /* Base service validation */
1135  i = 0;
1136  while (i < (int) _DBUS_N_ELEMENTS (valid_base_services))
1137    {
1138      _dbus_string_init_const (&str, valid_base_services[i]);
1139
1140      if (!_dbus_validate_service (&str, 0,
1141                                   _dbus_string_get_length (&str)))
1142        {
1143          _dbus_warn ("Service \"%s\" should have been valid\n", valid_base_services[i]);
1144          _dbus_assert_not_reached ("invalid base service");
1145        }
1146
1147      ++i;
1148    }
1149
1150  i = 0;
1151  while (i < (int) _DBUS_N_ELEMENTS (invalid_base_services))
1152    {
1153      _dbus_string_init_const (&str, invalid_base_services[i]);
1154
1155      if (_dbus_validate_service (&str, 0,
1156                                  _dbus_string_get_length (&str)))
1157        {
1158          _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_base_services[i]);
1159          _dbus_assert_not_reached ("valid base service");
1160        }
1161
1162      ++i;
1163    }
1164
1165
1166  /* Error name validation (currently identical to interfaces)
1167   */
1168  i = 0;
1169  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
1170    {
1171      _dbus_string_init_const (&str, valid_interfaces[i]);
1172
1173      if (!_dbus_validate_error_name (&str, 0,
1174                                      _dbus_string_get_length (&str)))
1175        {
1176          _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]);
1177          _dbus_assert_not_reached ("invalid error name");
1178        }
1179
1180      ++i;
1181    }
1182
1183  i = 0;
1184  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
1185    {
1186      if (invalid_interfaces[i][0] != ':')
1187        {
1188          _dbus_string_init_const (&str, invalid_interfaces[i]);
1189
1190          if (_dbus_validate_error_name (&str, 0,
1191                                         _dbus_string_get_length (&str)))
1192            {
1193              _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]);
1194              _dbus_assert_not_reached ("valid error name");
1195            }
1196        }
1197
1198      ++i;
1199    }
1200
1201  /* Member validation */
1202  i = 0;
1203  while (i < (int) _DBUS_N_ELEMENTS (valid_members))
1204    {
1205      _dbus_string_init_const (&str, valid_members[i]);
1206
1207      if (!_dbus_validate_member (&str, 0,
1208                                  _dbus_string_get_length (&str)))
1209        {
1210          _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]);
1211          _dbus_assert_not_reached ("invalid member");
1212        }
1213
1214      ++i;
1215    }
1216
1217  i = 0;
1218  while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
1219    {
1220      _dbus_string_init_const (&str, invalid_members[i]);
1221
1222      if (_dbus_validate_member (&str, 0,
1223                                 _dbus_string_get_length (&str)))
1224        {
1225          _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]);
1226          _dbus_assert_not_reached ("valid member");
1227        }
1228
1229      ++i;
1230    }
1231
1232  /* Signature validation */
1233  i = 0;
1234  while (i < (int) _DBUS_N_ELEMENTS (valid_signatures))
1235    {
1236      _dbus_string_init_const (&str, valid_signatures[i]);
1237
1238      if (!_dbus_validate_signature (&str, 0,
1239                                     _dbus_string_get_length (&str)))
1240        {
1241          _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]);
1242          _dbus_assert_not_reached ("invalid signature");
1243        }
1244
1245      ++i;
1246    }
1247
1248  i = 0;
1249  while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures))
1250    {
1251      _dbus_string_init_const (&str, invalid_signatures[i]);
1252
1253      if (_dbus_validate_signature (&str, 0,
1254                                    _dbus_string_get_length (&str)))
1255        {
1256          _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]);
1257          _dbus_assert_not_reached ("valid signature");
1258        }
1259
1260      ++i;
1261    }
1262
1263  /* Validate claimed length longer than real length */
1264  _dbus_string_init_const (&str, "abc.efg");
1265  if (_dbus_validate_service (&str, 0, 8))
1266    _dbus_assert_not_reached ("validated too-long string");
1267  if (_dbus_validate_interface (&str, 0, 8))
1268    _dbus_assert_not_reached ("validated too-long string");
1269  if (_dbus_validate_error_name (&str, 0, 8))
1270    _dbus_assert_not_reached ("validated too-long string");
1271
1272  _dbus_string_init_const (&str, "abc");
1273  if (_dbus_validate_member (&str, 0, 4))
1274    _dbus_assert_not_reached ("validated too-long string");
1275
1276  _dbus_string_init_const (&str, "sss");
1277  if (_dbus_validate_signature (&str, 0, 4))
1278    _dbus_assert_not_reached ("validated too-long signature");
1279
1280  /* Validate string exceeding max name length */
1281  if (!_dbus_string_init (&str))
1282    _dbus_assert_not_reached ("no memory");
1283
1284  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
1285    if (!_dbus_string_append (&str, "abc.def"))
1286      _dbus_assert_not_reached ("no memory");
1287
1288  if (_dbus_validate_service (&str, 0, _dbus_string_get_length (&str)))
1289    _dbus_assert_not_reached ("validated overmax string");
1290  if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str)))
1291    _dbus_assert_not_reached ("validated overmax string");
1292  if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
1293    _dbus_assert_not_reached ("validated overmax string");
1294
1295  /* overlong member */
1296  _dbus_string_set_length (&str, 0);
1297  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
1298    if (!_dbus_string_append (&str, "abc"))
1299      _dbus_assert_not_reached ("no memory");
1300
1301  if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str)))
1302    _dbus_assert_not_reached ("validated overmax string");
1303
1304  /* overlong base service */
1305  _dbus_string_set_length (&str, 0);
1306  _dbus_string_append (&str, ":");
1307  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
1308    if (!_dbus_string_append (&str, "abc"))
1309      _dbus_assert_not_reached ("no memory");
1310
1311  if (_dbus_validate_service (&str, 0, _dbus_string_get_length (&str)))
1312    _dbus_assert_not_reached ("validated overmax string");
1313
1314  _dbus_string_free (&str);
1315
1316  return TRUE;
1317}
1318
1319#endif /* DBUS_BUILD_TESTS */
1320