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