dbe2fa545315b067c7a2d3092107e1101e68db83
[platform/upstream/dbus.git] / dbus / dbus-marshal-validate.c
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 #include "dbus-marshal-basic.h"
28 #include "dbus-signature.h"
29 #include "dbus-string.h"
30
31 /**
32  * @addtogroup DBusMarshal
33  *
34  * @{
35  */
36
37 /**
38  * Verifies that the range of type_str from type_pos to type_end is a
39  * valid signature.  If this function returns #TRUE, it will be safe
40  * to iterate over the signature with a types-only #DBusTypeReader.
41  * The range passed in should NOT include the terminating
42  * nul/DBUS_TYPE_INVALID.
43  *
44  * @todo verify that dict entries have exactly two fields
45  * 
46  * @todo require that dict entries are in an array
47  *
48  * @param type_str the string
49  * @param type_pos where the typecodes start
50  * @param len length of typecodes
51  * @returns #DBUS_VALID if valid, reason why invalid otherwise
52  */
53 DBusValidity
54 _dbus_validate_signature_with_reason (const DBusString *type_str,
55                                       int               type_pos,
56                                       int               len)
57 {
58   const unsigned char *p;
59   const unsigned char *end;
60   int last;
61   int struct_depth;
62   int array_depth;
63   int dict_entry_depth;
64
65   _dbus_assert (type_str != NULL);
66   _dbus_assert (type_pos < _DBUS_INT32_MAX - len);
67   _dbus_assert (len >= 0);
68   _dbus_assert (type_pos >= 0);
69
70   if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH)
71     return DBUS_INVALID_SIGNATURE_TOO_LONG;
72
73   p = _dbus_string_get_const_data_len (type_str, type_pos, 0);
74   end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0);
75   struct_depth = 0;
76   array_depth = 0;
77   dict_entry_depth = 0;
78   last = DBUS_TYPE_INVALID;
79
80   while (p != end)
81     {
82       switch (*p)
83         {
84         case DBUS_TYPE_BYTE:
85         case DBUS_TYPE_BOOLEAN:
86         case DBUS_TYPE_INT16:
87         case DBUS_TYPE_UINT16:
88         case DBUS_TYPE_INT32:
89         case DBUS_TYPE_UINT32:
90         case DBUS_TYPE_INT64:
91         case DBUS_TYPE_UINT64:
92         case DBUS_TYPE_DOUBLE:
93         case DBUS_TYPE_STRING:
94         case DBUS_TYPE_OBJECT_PATH:
95         case DBUS_TYPE_SIGNATURE:
96         case DBUS_TYPE_VARIANT:
97           break;
98
99         case DBUS_TYPE_ARRAY:
100           array_depth += 1;
101           if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
102             return DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
103           break;
104
105         case DBUS_STRUCT_BEGIN_CHAR:
106           struct_depth += 1;
107
108           if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
109             return DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
110           break;
111
112         case DBUS_STRUCT_END_CHAR:
113           if (struct_depth == 0)
114             return DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
115
116           if (last == DBUS_STRUCT_BEGIN_CHAR)
117             return DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
118
119           struct_depth -= 1;
120           break;
121
122         case DBUS_DICT_ENTRY_BEGIN_CHAR:
123           if (last != DBUS_TYPE_ARRAY)
124             return DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY;
125           
126           dict_entry_depth += 1;
127
128           if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
129             return DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
130           break;
131
132         case DBUS_DICT_ENTRY_END_CHAR:
133           if (dict_entry_depth == 0)
134             return DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
135           
136           if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
137             return DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
138
139           dict_entry_depth -= 1;
140           break;
141           
142         case DBUS_TYPE_STRUCT:     /* doesn't appear in signatures */
143         case DBUS_TYPE_DICT_ENTRY: /* ditto */
144         default:
145           return DBUS_INVALID_UNKNOWN_TYPECODE;
146         }
147
148       if (array_depth > 0)
149         {
150           if (*p == DBUS_TYPE_ARRAY)
151             ;
152           else if (*p == DBUS_STRUCT_END_CHAR ||
153                    *p == DBUS_DICT_ENTRY_END_CHAR)
154             return DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE;
155           else
156             array_depth = 0;
157         }
158
159       if (last == DBUS_DICT_ENTRY_BEGIN_CHAR &&
160           !dbus_type_is_basic (*p))
161         return DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
162       
163       last = *p;
164       ++p;
165     }
166
167   if (array_depth > 0)
168     return DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE;
169
170   if (struct_depth > 0)
171     return DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
172
173   if (dict_entry_depth > 0)
174     return DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
175
176   _dbus_assert (last != DBUS_TYPE_ARRAY);
177   _dbus_assert (last != DBUS_STRUCT_BEGIN_CHAR);
178   _dbus_assert (last != DBUS_DICT_ENTRY_BEGIN_CHAR);
179   
180   return DBUS_VALID;
181 }
182
183 static DBusValidity
184 validate_body_helper (DBusTypeReader       *reader,
185                       int                   byte_order,
186                       dbus_bool_t           walk_reader_to_end,
187                       const unsigned char  *p,
188                       const unsigned char  *end,
189                       const unsigned char **new_p)
190 {
191   int current_type;
192
193   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
194     {
195       const unsigned char *a;
196       int alignment;
197
198 #if 0
199       _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
200                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
201                      (int) (end - p));
202 #endif
203
204       /* Guarantee that p has one byte to look at */
205       if (p == end)
206         return DBUS_INVALID_NOT_ENOUGH_DATA;
207
208       switch (current_type)
209         {
210         case DBUS_TYPE_BYTE:
211           ++p;
212           break;
213           
214         case DBUS_TYPE_BOOLEAN:
215         case DBUS_TYPE_INT16:
216         case DBUS_TYPE_UINT16:
217         case DBUS_TYPE_INT32:
218         case DBUS_TYPE_UINT32:
219         case DBUS_TYPE_INT64:
220         case DBUS_TYPE_UINT64:
221         case DBUS_TYPE_DOUBLE:
222           alignment = _dbus_type_get_alignment (current_type);
223           a = _DBUS_ALIGN_ADDRESS (p, alignment);
224           if (a >= end)
225             return DBUS_INVALID_NOT_ENOUGH_DATA;
226           while (p != a)
227             {
228               if (*p != '\0')
229                 return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
230               ++p;
231             }
232           
233           if (current_type == DBUS_TYPE_BOOLEAN)
234             {
235               dbus_uint32_t v = _dbus_unpack_uint32 (byte_order,
236                                                      p);
237               if (!(v == 0 || v == 1))
238                 return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
239             }
240           
241           p += alignment;
242           break;
243
244         case DBUS_TYPE_ARRAY:
245         case DBUS_TYPE_STRING:
246         case DBUS_TYPE_OBJECT_PATH:
247           {
248             dbus_uint32_t claimed_len;
249
250             a = _DBUS_ALIGN_ADDRESS (p, 4);
251             if (a + 4 > end)
252               return DBUS_INVALID_NOT_ENOUGH_DATA;
253             while (p != a)
254               {
255                 if (*p != '\0')
256                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
257                 ++p;
258               }
259
260             claimed_len = _dbus_unpack_uint32 (byte_order, p);
261             p += 4;
262
263             /* p may now be == end */
264             _dbus_assert (p <= end);
265             
266             if (current_type == DBUS_TYPE_ARRAY)
267               {
268                 int array_elem_type = _dbus_type_reader_get_element_type (reader);
269                 alignment = _dbus_type_get_alignment (array_elem_type);
270                 p = _DBUS_ALIGN_ADDRESS (p, alignment);
271               }
272
273             if (claimed_len > (unsigned long) (end - p))
274               return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS;
275
276             if (current_type == DBUS_TYPE_OBJECT_PATH)
277               {
278                 DBusString str;
279                 _dbus_string_init_const_len (&str, p, claimed_len);
280                 if (!_dbus_validate_path (&str, 0,
281                                           _dbus_string_get_length (&str)))
282                   return DBUS_INVALID_BAD_PATH;
283
284                 p += claimed_len;
285               }
286             else if (current_type == DBUS_TYPE_STRING)
287               {
288                 DBusString str;
289                 _dbus_string_init_const_len (&str, p, claimed_len);
290                 if (!_dbus_string_validate_utf8 (&str, 0,
291                                                  _dbus_string_get_length (&str)))
292                   return DBUS_INVALID_BAD_UTF8_IN_STRING;
293
294                 p += claimed_len;
295               }
296             else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
297               {
298                 DBusTypeReader sub;
299                 DBusValidity validity;
300                 const unsigned char *array_end;
301
302                 if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH)
303                   return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM;
304                 
305                 /* Remember that the reader is types only, so we can't
306                  * use it to iterate over elements. It stays the same
307                  * for all elements.
308                  */
309                 _dbus_type_reader_recurse (reader, &sub);
310
311                 array_end = p + claimed_len;
312
313                 while (p < array_end)
314                   {
315                     /* FIXME we are calling a function per array element! very bad
316                      * need if (dbus_type_is_fixed(elem_type)) here to just skip
317                      * big blocks of ints/bytes/etc.
318                      */                     
319                     
320                     validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
321                     if (validity != DBUS_VALID)
322                       return validity;
323                   }
324
325                 if (p != array_end)
326                   return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
327               }
328
329             /* check nul termination */
330             if (current_type != DBUS_TYPE_ARRAY)
331               {
332                 if (p == end)
333                   return DBUS_INVALID_NOT_ENOUGH_DATA;
334
335                 if (*p != '\0')
336                   return DBUS_INVALID_STRING_MISSING_NUL;
337                 ++p;
338               }
339           }
340           break;
341
342         case DBUS_TYPE_SIGNATURE:
343           {
344             dbus_uint32_t claimed_len;
345             DBusString str;
346             DBusValidity validity;
347
348             claimed_len = *p;
349             ++p;
350
351             /* 1 is for nul termination */
352             if (claimed_len + 1 > (unsigned long) (end - p))
353               return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
354
355             _dbus_string_init_const_len (&str, p, claimed_len);
356             validity =
357               _dbus_validate_signature_with_reason (&str, 0,
358                                                     _dbus_string_get_length (&str));
359
360             if (validity != DBUS_VALID)
361               return validity;
362
363             p += claimed_len;
364
365             _dbus_assert (p < end);
366             if (*p != DBUS_TYPE_INVALID)
367               return DBUS_INVALID_SIGNATURE_MISSING_NUL;
368
369             ++p;
370
371             _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
372           }
373           break;
374
375         case DBUS_TYPE_VARIANT:
376           {
377             /* 1 byte sig len, sig typecodes, align to
378              * contained-type-boundary, values.
379              */
380
381             /* In addition to normal signature validation, we need to be sure
382              * the signature contains only a single (possibly container) type.
383              */
384             dbus_uint32_t claimed_len;
385             DBusString sig;
386             DBusTypeReader sub;
387             DBusValidity validity;
388             int contained_alignment;
389             int contained_type;
390
391             claimed_len = *p;
392             ++p;
393
394             /* + 1 for nul */
395             if (claimed_len + 1 > (unsigned long) (end - p))
396               return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
397
398             _dbus_string_init_const_len (&sig, p, claimed_len);
399             if (!_dbus_validate_signature (&sig, 0,
400                                            _dbus_string_get_length (&sig)))
401               return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
402
403             p += claimed_len;
404             
405             if (*p != DBUS_TYPE_INVALID)
406               return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
407             ++p;
408
409             contained_type = _dbus_first_type_in_signature (&sig, 0);
410             if (contained_type == DBUS_TYPE_INVALID)
411               return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
412             
413             contained_alignment = _dbus_type_get_alignment (contained_type);
414             
415             a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
416             if (a > end)
417               return DBUS_INVALID_NOT_ENOUGH_DATA;
418             while (p != a)
419               {
420                 if (*p != '\0')
421                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
422                 ++p;
423               }
424
425             _dbus_type_reader_init_types_only (&sub, &sig, 0);
426
427             _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);
428
429             validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
430             if (validity != DBUS_VALID)
431               return validity;
432
433             if (_dbus_type_reader_next (&sub))
434               return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;
435
436             _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
437           }
438           break;
439
440         case DBUS_TYPE_DICT_ENTRY:
441         case DBUS_TYPE_STRUCT:
442           {
443             DBusTypeReader sub;
444             DBusValidity validity;
445
446             a = _DBUS_ALIGN_ADDRESS (p, 8);
447             if (a > end)
448               return DBUS_INVALID_NOT_ENOUGH_DATA;
449             while (p != a)
450               {
451                 if (*p != '\0')
452                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
453                 ++p;
454               }
455
456             _dbus_type_reader_recurse (reader, &sub);
457
458             validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
459             if (validity != DBUS_VALID)
460               return validity;
461           }
462           break;
463
464         default:
465           _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
466           break;
467         }
468
469 #if 0
470       _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
471                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
472                      (int) (end - p));
473 #endif
474
475       if (p > end)
476         {
477           _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
478                          p, end, (int) (end - p));
479           return DBUS_INVALID_NOT_ENOUGH_DATA;
480         }
481
482       if (walk_reader_to_end)
483         _dbus_type_reader_next (reader);
484       else
485         break;
486     }
487
488   if (new_p)
489     *new_p = p;
490
491   return DBUS_VALID;
492 }
493
494 /**
495  * Verifies that the range of value_str from value_pos to value_end is
496  * a legitimate value of type expected_signature.  If this function
497  * returns #TRUE, it will be safe to iterate over the values with
498  * #DBusTypeReader. The signature is assumed to be already valid.
499  *
500  * If bytes_remaining is not #NULL, then leftover bytes will be stored
501  * there and #DBUS_VALID returned. If it is #NULL, then
502  * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left
503  * over.
504  *
505  * @param expected_signature the expected types in the value_str
506  * @param expected_signature_start where in expected_signature is the signature
507  * @param byte_order the byte order
508  * @param bytes_remaining place to store leftover bytes
509  * @param value_str the string containing the body
510  * @param value_pos where the values start
511  * @param len length of values after value_pos
512  * @returns #DBUS_VALID if valid, reason why invalid otherwise
513  */
514 DBusValidity
515 _dbus_validate_body_with_reason (const DBusString *expected_signature,
516                                  int               expected_signature_start,
517                                  int               byte_order,
518                                  int              *bytes_remaining,
519                                  const DBusString *value_str,
520                                  int               value_pos,
521                                  int               len)
522 {
523   DBusTypeReader reader;
524   const unsigned char *p;
525   const unsigned char *end;
526   DBusValidity validity;
527
528   _dbus_assert (len >= 0);
529   _dbus_assert (value_pos >= 0);
530   _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len);
531
532   _dbus_verbose ("validating body from pos %d len %d sig '%s'\n",
533                  value_pos, len, _dbus_string_get_const_data_len (expected_signature,
534                                                                   expected_signature_start,
535                                                                   0));
536
537   _dbus_type_reader_init_types_only (&reader,
538                                      expected_signature, expected_signature_start);
539
540   p = _dbus_string_get_const_data_len (value_str, value_pos, len);
541   end = p + len;
542
543   validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
544   if (validity != DBUS_VALID)
545     return validity;
546   
547   if (bytes_remaining)
548     {
549       *bytes_remaining = end - p;
550       return DBUS_VALID;
551     }
552   else if (p < end)
553     return DBUS_INVALID_TOO_MUCH_DATA;
554   else
555     {
556       _dbus_assert (p == end);
557       return DBUS_VALID;
558     }
559 }
560
561 /**
562  * Determine wether the given charater is valid as the first charater
563  * in a name.
564  */
565 #define VALID_INITIAL_NAME_CHARACTER(c)         \
566   ( ((c) >= 'A' && (c) <= 'Z') ||               \
567     ((c) >= 'a' && (c) <= 'z') ||               \
568     ((c) == '_') )
569
570 /**
571  * Determine wether the given charater is valid as a second or later
572  * character in a name
573  */
574 #define VALID_NAME_CHARACTER(c)                 \
575   ( ((c) >= '0' && (c) <= '9') ||               \
576     ((c) >= 'A' && (c) <= 'Z') ||               \
577     ((c) >= 'a' && (c) <= 'z') ||               \
578     ((c) == '_') )
579
580 /**
581  * Checks that the given range of the string is a valid object path
582  * name in the D-BUS protocol. Part of the validation ensures that
583  * the object path contains only ASCII.
584  *
585  * @todo this is inconsistent with most of DBusString in that
586  * it allows a start,len range that extends past the string end.
587  *
588  * @todo change spec to disallow more things, such as spaces in the
589  * path name
590  *
591  * @param str the string
592  * @param start first byte index to check
593  * @param len number of bytes to check
594  * @returns #TRUE if the byte range exists and is a valid name
595  */
596 dbus_bool_t
597 _dbus_validate_path (const DBusString  *str,
598                      int                start,
599                      int                len)
600 {
601   const unsigned char *s;
602   const unsigned char *end;
603   const unsigned char *last_slash;
604
605   _dbus_assert (start >= 0);
606   _dbus_assert (len >= 0);
607   _dbus_assert (start <= _dbus_string_get_length (str));
608   
609   if (len > _dbus_string_get_length (str) - start)
610     return FALSE;
611
612   if (len == 0)
613     return FALSE;
614
615   s = _dbus_string_get_const_data (str) + start;
616   end = s + len;
617
618   if (*s != '/')
619     return FALSE;
620   last_slash = s;
621   ++s;
622
623   while (s != end)
624     {
625       if (*s == '/')
626         {
627           if ((s - last_slash) < 2)
628             return FALSE; /* no empty path components allowed */
629
630           last_slash = s;
631         }
632       else
633         {
634           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
635             return FALSE;
636         }
637
638       ++s;
639     }
640
641   if ((end - last_slash) < 2 &&
642       len > 1)
643     return FALSE; /* trailing slash not allowed unless the string is "/" */
644
645   return TRUE;
646 }
647
648 /**
649  * Checks that the given range of the string is a valid interface name
650  * in the D-BUS protocol. This includes a length restriction and an
651  * ASCII subset, see the specification.
652  *
653  * @todo this is inconsistent with most of DBusString in that
654  * it allows a start,len range that extends past the string end.
655  *
656  * @param str the string
657  * @param start first byte index to check
658  * @param len number of bytes to check
659  * @returns #TRUE if the byte range exists and is a valid name
660  */
661 dbus_bool_t
662 _dbus_validate_interface (const DBusString  *str,
663                           int                start,
664                           int                len)
665 {
666   const unsigned char *s;
667   const unsigned char *end;
668   const unsigned char *iface;
669   const unsigned char *last_dot;
670
671   _dbus_assert (start >= 0);
672   _dbus_assert (len >= 0);
673   _dbus_assert (start <= _dbus_string_get_length (str));
674
675   if (len > _dbus_string_get_length (str) - start)
676     return FALSE;
677
678   if (len > DBUS_MAXIMUM_NAME_LENGTH)
679     return FALSE;
680
681   if (len == 0)
682     return FALSE;
683
684   last_dot = NULL;
685   iface = _dbus_string_get_const_data (str) + start;
686   end = iface + len;
687   s = iface;
688
689   /* check special cases of first char so it doesn't have to be done
690    * in the loop. Note we know len > 0
691    */
692   if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
693     return FALSE;
694   else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
695     return FALSE;
696   else
697     ++s;
698
699   while (s != end)
700     {
701       if (*s == '.')
702         {
703           if (_DBUS_UNLIKELY ((s + 1) == end))
704             return FALSE;
705           else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
706             return FALSE;
707           last_dot = s;
708           ++s; /* we just validated the next char, so skip two */
709         }
710       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
711         {
712           return FALSE;
713         }
714
715       ++s;
716     }
717
718   if (_DBUS_UNLIKELY (last_dot == NULL))
719     return FALSE;
720
721   return TRUE;
722 }
723
724 /**
725  * Checks that the given range of the string is a valid member name
726  * in the D-BUS protocol. This includes a length restriction, etc.,
727  * see the specification.
728  *
729  * @todo this is inconsistent with most of DBusString in that
730  * it allows a start,len range that extends past the string end.
731  *
732  * @param str the string
733  * @param start first byte index to check
734  * @param len number of bytes to check
735  * @returns #TRUE if the byte range exists and is a valid name
736  */
737 dbus_bool_t
738 _dbus_validate_member (const DBusString  *str,
739                        int                start,
740                        int                len)
741 {
742   const unsigned char *s;
743   const unsigned char *end;
744   const unsigned char *member;
745
746   _dbus_assert (start >= 0);
747   _dbus_assert (len >= 0);
748   _dbus_assert (start <= _dbus_string_get_length (str));
749
750   if (len > _dbus_string_get_length (str) - start)
751     return FALSE;
752
753   if (len > DBUS_MAXIMUM_NAME_LENGTH)
754     return FALSE;
755
756   if (len == 0)
757     return FALSE;
758
759   member = _dbus_string_get_const_data (str) + start;
760   end = member + len;
761   s = member;
762
763   /* check special cases of first char so it doesn't have to be done
764    * in the loop. Note we know len > 0
765    */
766
767   if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
768     return FALSE;
769   else
770     ++s;
771
772   while (s != end)
773     {
774       if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
775         {
776           return FALSE;
777         }
778
779       ++s;
780     }
781
782   return TRUE;
783 }
784
785 /**
786  * Checks that the given range of the string is a valid error name
787  * in the D-BUS protocol. This includes a length restriction, etc.,
788  * see the specification.
789  *
790  * @todo this is inconsistent with most of DBusString in that
791  * it allows a start,len range that extends past the string end.
792  *
793  * @param str the string
794  * @param start first byte index to check
795  * @param len number of bytes to check
796  * @returns #TRUE if the byte range exists and is a valid name
797  */
798 dbus_bool_t
799 _dbus_validate_error_name (const DBusString  *str,
800                            int                start,
801                            int                len)
802 {
803   /* Same restrictions as interface name at the moment */
804   return _dbus_validate_interface (str, start, len);
805 }
806
807 /* This assumes the first char exists and is ':' */
808 static dbus_bool_t
809 _dbus_validate_unique_name (const DBusString  *str,
810                             int                start,
811                             int                len)
812 {
813   const unsigned char *s;
814   const unsigned char *end;
815   const unsigned char *name;
816
817   _dbus_assert (start >= 0);
818   _dbus_assert (len >= 0);
819   _dbus_assert (start <= _dbus_string_get_length (str));
820
821   if (len > _dbus_string_get_length (str) - start)
822     return FALSE;
823
824   if (len > DBUS_MAXIMUM_NAME_LENGTH)
825     return FALSE;
826
827   _dbus_assert (len > 0);
828
829   name = _dbus_string_get_const_data (str) + start;
830   end = name + len;
831   _dbus_assert (*name == ':');
832   s = name + 1;
833
834   while (s != end)
835     {
836       if (*s == '.')
837         {
838           if (_DBUS_UNLIKELY ((s + 1) == end))
839             return FALSE;
840           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
841             return FALSE;
842           ++s; /* we just validated the next char, so skip two */
843         }
844       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
845         {
846           return FALSE;
847         }
848
849       ++s;
850     }
851
852   return TRUE;
853 }
854
855 /**
856  * Checks that the given range of the string is a valid bus name in
857  * the D-BUS protocol. This includes a length restriction, etc., see
858  * the specification.
859  *
860  * @todo this is inconsistent with most of DBusString in that
861  * it allows a start,len range that extends past the string end.
862  *
863  * @param str the string
864  * @param start first byte index to check
865  * @param len number of bytes to check
866  * @returns #TRUE if the byte range exists and is a valid name
867  */
868 dbus_bool_t
869 _dbus_validate_bus_name (const DBusString  *str,
870                          int                start,
871                          int                len)
872 {
873   if (_DBUS_UNLIKELY (len == 0))
874     return FALSE;
875   if (_dbus_string_get_byte (str, start) == ':')
876     return _dbus_validate_unique_name (str, start, len);
877   else
878     return _dbus_validate_interface (str, start, len);
879 }
880
881 /**
882  * Checks that the given range of the string is a valid message type
883  * signature in the D-BUS protocol.
884  *
885  * @todo this is inconsistent with most of DBusString in that
886  * it allows a start,len range that extends past the string end.
887  *
888  * @param str the string
889  * @param start first byte index to check
890  * @param len number of bytes to check
891  * @returns #TRUE if the byte range exists and is a valid signature
892  */
893 dbus_bool_t
894 _dbus_validate_signature (const DBusString  *str,
895                           int                start,
896                           int                len)
897 {
898   _dbus_assert (start >= 0);
899   _dbus_assert (start <= _dbus_string_get_length (str));
900   _dbus_assert (len >= 0);
901
902   if (len > _dbus_string_get_length (str) - start)
903     return FALSE;
904
905   return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID;
906 }
907
908 /** define _dbus_check_is_valid_path() */
909 DEFINE_DBUS_NAME_CHECK(path);
910 /** define _dbus_check_is_valid_interface() */
911 DEFINE_DBUS_NAME_CHECK(interface);
912 /** define _dbus_check_is_valid_member() */
913 DEFINE_DBUS_NAME_CHECK(member);
914 /** define _dbus_check_is_valid_error_name() */
915 DEFINE_DBUS_NAME_CHECK(error_name);
916 /** define _dbus_check_is_valid_bus_name() */
917 DEFINE_DBUS_NAME_CHECK(bus_name);
918 /** define _dbus_check_is_valid_signature() */
919 DEFINE_DBUS_NAME_CHECK(signature);
920
921 /** @} */
922
923 /* tests in dbus-marshal-validate-util.c */