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