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