Bug 18064 - more efficient validation for fixed-size type arrays
[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
378                 if (!_dbus_type_is_valid (array_elem_type))
379                   {
380                     return DBUS_INVALID_UNKNOWN_TYPECODE;
381                   }
382
383                 alignment = _dbus_type_get_alignment (array_elem_type);
384
385                 a = _DBUS_ALIGN_ADDRESS (p, alignment);
386
387                 /* a may now be == end */
388                 if (a > end)
389                   return DBUS_INVALID_NOT_ENOUGH_DATA;
390
391                 while (p != a)
392                   {
393                     if (*p != '\0')
394                       return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
395                     ++p;
396                   }
397               }
398
399             if (claimed_len > (unsigned long) (end - p))
400               return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS;
401
402             if (current_type == DBUS_TYPE_OBJECT_PATH)
403               {
404                 DBusString str;
405                 _dbus_string_init_const_len (&str, p, claimed_len);
406                 if (!_dbus_validate_path (&str, 0,
407                                           _dbus_string_get_length (&str)))
408                   return DBUS_INVALID_BAD_PATH;
409
410                 p += claimed_len;
411               }
412             else if (current_type == DBUS_TYPE_STRING)
413               {
414                 DBusString str;
415                 _dbus_string_init_const_len (&str, p, claimed_len);
416                 if (!_dbus_string_validate_utf8 (&str, 0,
417                                                  _dbus_string_get_length (&str)))
418                   return DBUS_INVALID_BAD_UTF8_IN_STRING;
419
420                 p += claimed_len;
421               }
422             else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
423               {
424                 DBusTypeReader sub;
425                 DBusValidity validity;
426                 const unsigned char *array_end;
427                 int array_elem_type;
428
429                 if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH)
430                   return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM;
431                 
432                 /* Remember that the reader is types only, so we can't
433                  * use it to iterate over elements. It stays the same
434                  * for all elements.
435                  */
436                 _dbus_type_reader_recurse (reader, &sub);
437
438                 array_end = p + claimed_len;
439
440                 array_elem_type = _dbus_type_reader_get_element_type (reader);
441
442                 /* avoid recursive call to validate_body_helper if this is an array
443                  * of fixed-size elements
444                  */ 
445                 if (dbus_type_is_fixed (array_elem_type))
446                   {
447                     /* bools need to be handled differently, because they can
448                      * have an invalid value
449                      */
450                     if (array_elem_type == DBUS_TYPE_BOOLEAN)
451                       {
452                         dbus_uint32_t v;
453                         alignment = _dbus_type_get_alignment (array_elem_type);
454
455                         while (p < array_end)
456                           {
457                             v = _dbus_unpack_uint32 (byte_order, p);
458
459                             if (!(v == 0 || v == 1))
460                               return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
461
462                             p += alignment;
463                           }
464                       }
465
466                     else
467                       {
468                         p = array_end;
469                       }
470                   }
471
472                 else
473                   {
474                     while (p < array_end)
475                       {
476                         validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
477                         if (validity != DBUS_VALID)
478                           return validity;
479                       }
480                   }
481
482                 if (p != array_end)
483                   return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
484               }
485
486             /* check nul termination */
487             if (current_type != DBUS_TYPE_ARRAY)
488               {
489                 if (p == end)
490                   return DBUS_INVALID_NOT_ENOUGH_DATA;
491
492                 if (*p != '\0')
493                   return DBUS_INVALID_STRING_MISSING_NUL;
494                 ++p;
495               }
496           }
497           break;
498
499         case DBUS_TYPE_SIGNATURE:
500           {
501             dbus_uint32_t claimed_len;
502             DBusString str;
503             DBusValidity validity;
504
505             claimed_len = *p;
506             ++p;
507
508             /* 1 is for nul termination */
509             if (claimed_len + 1 > (unsigned long) (end - p))
510               return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
511
512             _dbus_string_init_const_len (&str, p, claimed_len);
513             validity =
514               _dbus_validate_signature_with_reason (&str, 0,
515                                                     _dbus_string_get_length (&str));
516
517             if (validity != DBUS_VALID)
518               return validity;
519
520             p += claimed_len;
521
522             _dbus_assert (p < end);
523             if (*p != DBUS_TYPE_INVALID)
524               return DBUS_INVALID_SIGNATURE_MISSING_NUL;
525
526             ++p;
527
528             _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
529           }
530           break;
531
532         case DBUS_TYPE_VARIANT:
533           {
534             /* 1 byte sig len, sig typecodes, align to
535              * contained-type-boundary, values.
536              */
537
538             /* In addition to normal signature validation, we need to be sure
539              * the signature contains only a single (possibly container) type.
540              */
541             dbus_uint32_t claimed_len;
542             DBusString sig;
543             DBusTypeReader sub;
544             DBusValidity validity;
545             int contained_alignment;
546             int contained_type;
547             DBusValidity reason;
548
549             claimed_len = *p;
550             ++p;
551
552             /* + 1 for nul */
553             if (claimed_len + 1 > (unsigned long) (end - p))
554               return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
555
556             _dbus_string_init_const_len (&sig, p, claimed_len);
557             reason = _dbus_validate_signature_with_reason (&sig, 0,
558                                            _dbus_string_get_length (&sig));
559             if (!(reason == DBUS_VALID))
560               {
561                 if (reason == DBUS_VALIDITY_UNKNOWN_OOM_ERROR)
562                   return reason;
563                 else 
564                   return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
565               }
566
567             p += claimed_len;
568             
569             if (*p != DBUS_TYPE_INVALID)
570               return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
571             ++p;
572
573             contained_type = _dbus_first_type_in_signature (&sig, 0);
574             if (contained_type == DBUS_TYPE_INVALID)
575               return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
576             
577             contained_alignment = _dbus_type_get_alignment (contained_type);
578             
579             a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
580             if (a > end)
581               return DBUS_INVALID_NOT_ENOUGH_DATA;
582             while (p != a)
583               {
584                 if (*p != '\0')
585                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
586                 ++p;
587               }
588
589             _dbus_type_reader_init_types_only (&sub, &sig, 0);
590
591             _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);
592
593             validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
594             if (validity != DBUS_VALID)
595               return validity;
596
597             if (_dbus_type_reader_next (&sub))
598               return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;
599
600             _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
601           }
602           break;
603
604         case DBUS_TYPE_DICT_ENTRY:
605         case DBUS_TYPE_STRUCT:
606           {
607             DBusTypeReader sub;
608             DBusValidity validity;
609
610             a = _DBUS_ALIGN_ADDRESS (p, 8);
611             if (a > end)
612               return DBUS_INVALID_NOT_ENOUGH_DATA;
613             while (p != a)
614               {
615                 if (*p != '\0')
616                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
617                 ++p;
618               }
619
620             _dbus_type_reader_recurse (reader, &sub);
621
622             validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
623             if (validity != DBUS_VALID)
624               return validity;
625           }
626           break;
627
628         default:
629           _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
630           break;
631         }
632
633 #if 0
634       _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
635                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
636                      (int) (end - p));
637 #endif
638
639       if (p > end)
640         {
641           _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
642                          p, end, (int) (end - p));
643           return DBUS_INVALID_NOT_ENOUGH_DATA;
644         }
645
646       if (walk_reader_to_end)
647         _dbus_type_reader_next (reader);
648       else
649         break;
650     }
651
652   if (new_p)
653     *new_p = p;
654
655   return DBUS_VALID;
656 }
657
658 /**
659  * Verifies that the range of value_str from value_pos to value_end is
660  * a legitimate value of type expected_signature.  If this function
661  * returns #TRUE, it will be safe to iterate over the values with
662  * #DBusTypeReader. The signature is assumed to be already valid.
663  *
664  * If bytes_remaining is not #NULL, then leftover bytes will be stored
665  * there and #DBUS_VALID returned. If it is #NULL, then
666  * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left
667  * over.
668  *
669  * @param expected_signature the expected types in the value_str
670  * @param expected_signature_start where in expected_signature is the signature
671  * @param byte_order the byte order
672  * @param bytes_remaining place to store leftover bytes
673  * @param value_str the string containing the body
674  * @param value_pos where the values start
675  * @param len length of values after value_pos
676  * @returns #DBUS_VALID if valid, reason why invalid otherwise
677  */
678 DBusValidity
679 _dbus_validate_body_with_reason (const DBusString *expected_signature,
680                                  int               expected_signature_start,
681                                  int               byte_order,
682                                  int              *bytes_remaining,
683                                  const DBusString *value_str,
684                                  int               value_pos,
685                                  int               len)
686 {
687   DBusTypeReader reader;
688   const unsigned char *p;
689   const unsigned char *end;
690   DBusValidity validity;
691
692   _dbus_assert (len >= 0);
693   _dbus_assert (value_pos >= 0);
694   _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len);
695
696   _dbus_verbose ("validating body from pos %d len %d sig '%s'\n",
697                  value_pos, len, _dbus_string_get_const_data_len (expected_signature,
698                                                                   expected_signature_start,
699                                                                   0));
700
701   _dbus_type_reader_init_types_only (&reader,
702                                      expected_signature, expected_signature_start);
703
704   p = _dbus_string_get_const_data_len (value_str, value_pos, len);
705   end = p + len;
706
707   validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
708   if (validity != DBUS_VALID)
709     return validity;
710   
711   if (bytes_remaining)
712     {
713       *bytes_remaining = end - p;
714       return DBUS_VALID;
715     }
716   else if (p < end)
717     return DBUS_INVALID_TOO_MUCH_DATA;
718   else
719     {
720       _dbus_assert (p == end);
721       return DBUS_VALID;
722     }
723 }
724
725 /**
726  * Determine wether the given character is valid as the first character
727  * in a name.
728  */
729 #define VALID_INITIAL_NAME_CHARACTER(c)         \
730   ( ((c) >= 'A' && (c) <= 'Z') ||               \
731     ((c) >= 'a' && (c) <= 'z') ||               \
732     ((c) == '_') )
733
734 /**
735  * Determine wether the given character is valid as a second or later
736  * character in a name
737  */
738 #define VALID_NAME_CHARACTER(c)                 \
739   ( ((c) >= '0' && (c) <= '9') ||               \
740     ((c) >= 'A' && (c) <= 'Z') ||               \
741     ((c) >= 'a' && (c) <= 'z') ||               \
742     ((c) == '_') )
743
744 /**
745  * Checks that the given range of the string is a valid object path
746  * name in the D-Bus protocol. Part of the validation ensures that
747  * the object path contains only ASCII.
748  *
749  * @todo this is inconsistent with most of DBusString in that
750  * it allows a start,len range that extends past the string end.
751  *
752  * @todo change spec to disallow more things, such as spaces in the
753  * path name
754  *
755  * @param str the string
756  * @param start first byte index to check
757  * @param len number of bytes to check
758  * @returns #TRUE if the byte range exists and is a valid name
759  */
760 dbus_bool_t
761 _dbus_validate_path (const DBusString  *str,
762                      int                start,
763                      int                len)
764 {
765   const unsigned char *s;
766   const unsigned char *end;
767   const unsigned char *last_slash;
768
769   _dbus_assert (start >= 0);
770   _dbus_assert (len >= 0);
771   _dbus_assert (start <= _dbus_string_get_length (str));
772   
773   if (len > _dbus_string_get_length (str) - start)
774     return FALSE;
775
776   if (len == 0)
777     return FALSE;
778
779   s = _dbus_string_get_const_data (str) + start;
780   end = s + len;
781
782   if (*s != '/')
783     return FALSE;
784   last_slash = s;
785   ++s;
786
787   while (s != end)
788     {
789       if (*s == '/')
790         {
791           if ((s - last_slash) < 2)
792             return FALSE; /* no empty path components allowed */
793
794           last_slash = s;
795         }
796       else
797         {
798           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
799             return FALSE;
800         }
801
802       ++s;
803     }
804
805   if ((end - last_slash) < 2 &&
806       len > 1)
807     return FALSE; /* trailing slash not allowed unless the string is "/" */
808
809   return TRUE;
810 }
811
812 /**
813  * Checks that the given range of the string is a valid interface name
814  * in the D-Bus protocol. This includes a length restriction and an
815  * ASCII subset, see the specification.
816  *
817  * @todo this is inconsistent with most of DBusString in that
818  * it allows a start,len range that extends past the string end.
819  *
820  * @param str the string
821  * @param start first byte index to check
822  * @param len number of bytes to check
823  * @returns #TRUE if the byte range exists and is a valid name
824  */
825 dbus_bool_t
826 _dbus_validate_interface (const DBusString  *str,
827                           int                start,
828                           int                len)
829 {
830   const unsigned char *s;
831   const unsigned char *end;
832   const unsigned char *iface;
833   const unsigned char *last_dot;
834
835   _dbus_assert (start >= 0);
836   _dbus_assert (len >= 0);
837   _dbus_assert (start <= _dbus_string_get_length (str));
838
839   if (len > _dbus_string_get_length (str) - start)
840     return FALSE;
841
842   if (len > DBUS_MAXIMUM_NAME_LENGTH)
843     return FALSE;
844
845   if (len == 0)
846     return FALSE;
847
848   last_dot = NULL;
849   iface = _dbus_string_get_const_data (str) + start;
850   end = iface + len;
851   s = iface;
852
853   /* check special cases of first char so it doesn't have to be done
854    * in the loop. Note we know len > 0
855    */
856   if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
857     return FALSE;
858   else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
859     return FALSE;
860   else
861     ++s;
862
863   while (s != end)
864     {
865       if (*s == '.')
866         {
867           if (_DBUS_UNLIKELY ((s + 1) == end))
868             return FALSE;
869           else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
870             return FALSE;
871           last_dot = s;
872           ++s; /* we just validated the next char, so skip two */
873         }
874       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
875         {
876           return FALSE;
877         }
878
879       ++s;
880     }
881
882   if (_DBUS_UNLIKELY (last_dot == NULL))
883     return FALSE;
884
885   return TRUE;
886 }
887
888 /**
889  * Checks that the given range of the string is a valid member name
890  * in the D-Bus protocol. This includes a length restriction, etc.,
891  * see the specification.
892  *
893  * @todo this is inconsistent with most of DBusString in that
894  * it allows a start,len range that extends past the string end.
895  *
896  * @param str the string
897  * @param start first byte index to check
898  * @param len number of bytes to check
899  * @returns #TRUE if the byte range exists and is a valid name
900  */
901 dbus_bool_t
902 _dbus_validate_member (const DBusString  *str,
903                        int                start,
904                        int                len)
905 {
906   const unsigned char *s;
907   const unsigned char *end;
908   const unsigned char *member;
909
910   _dbus_assert (start >= 0);
911   _dbus_assert (len >= 0);
912   _dbus_assert (start <= _dbus_string_get_length (str));
913
914   if (len > _dbus_string_get_length (str) - start)
915     return FALSE;
916
917   if (len > DBUS_MAXIMUM_NAME_LENGTH)
918     return FALSE;
919
920   if (len == 0)
921     return FALSE;
922
923   member = _dbus_string_get_const_data (str) + start;
924   end = member + len;
925   s = member;
926
927   /* check special cases of first char so it doesn't have to be done
928    * in the loop. Note we know len > 0
929    */
930
931   if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
932     return FALSE;
933   else
934     ++s;
935
936   while (s != end)
937     {
938       if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
939         {
940           return FALSE;
941         }
942
943       ++s;
944     }
945
946   return TRUE;
947 }
948
949 /**
950  * Checks that the given range of the string is a valid error name
951  * in the D-Bus protocol. This includes a length restriction, etc.,
952  * see the specification.
953  *
954  * @todo this is inconsistent with most of DBusString in that
955  * it allows a start,len range that extends past the string end.
956  *
957  * @param str the string
958  * @param start first byte index to check
959  * @param len number of bytes to check
960  * @returns #TRUE if the byte range exists and is a valid name
961  */
962 dbus_bool_t
963 _dbus_validate_error_name (const DBusString  *str,
964                            int                start,
965                            int                len)
966 {
967   /* Same restrictions as interface name at the moment */
968   return _dbus_validate_interface (str, start, len);
969 }
970
971 /**
972  * Determine wether the given character is valid as the first character
973  * in a bus name.
974  */
975 #define VALID_INITIAL_BUS_NAME_CHARACTER(c)         \
976   ( ((c) >= 'A' && (c) <= 'Z') ||               \
977     ((c) >= 'a' && (c) <= 'z') ||               \
978     ((c) == '_') || ((c) == '-'))
979
980 /**
981  * Determine wether the given character is valid as a second or later
982  * character in a bus name
983  */
984 #define VALID_BUS_NAME_CHARACTER(c)                 \
985   ( ((c) >= '0' && (c) <= '9') ||               \
986     ((c) >= 'A' && (c) <= 'Z') ||               \
987     ((c) >= 'a' && (c) <= 'z') ||               \
988     ((c) == '_') || ((c) == '-'))
989
990 /**
991  * Checks that the given range of the string is a valid bus name in
992  * the D-Bus protocol. This includes a length restriction, etc., see
993  * the specification.
994  *
995  * @todo this is inconsistent with most of DBusString in that
996  * it allows a start,len range that extends past the string end.
997  *
998  * @param str the string
999  * @param start first byte index to check
1000  * @param len number of bytes to check
1001  * @returns #TRUE if the byte range exists and is a valid name
1002  */
1003 dbus_bool_t
1004 _dbus_validate_bus_name (const DBusString  *str,
1005                          int                start,
1006                          int                len)
1007 {
1008   const unsigned char *s;
1009   const unsigned char *end;
1010   const unsigned char *iface;
1011   const unsigned char *last_dot;
1012
1013   _dbus_assert (start >= 0);
1014   _dbus_assert (len >= 0);
1015   _dbus_assert (start <= _dbus_string_get_length (str));
1016
1017   if (len > _dbus_string_get_length (str) - start)
1018     return FALSE;
1019
1020   if (len > DBUS_MAXIMUM_NAME_LENGTH)
1021     return FALSE;
1022
1023   if (len == 0)
1024     return FALSE;
1025
1026   last_dot = NULL;
1027   iface = _dbus_string_get_const_data (str) + start;
1028   end = iface + len;
1029   s = iface;
1030
1031   /* check special cases of first char so it doesn't have to be done
1032    * in the loop. Note we know len > 0
1033    */
1034   if (*s == ':')
1035   {
1036     /* unique name */
1037     ++s;
1038     while (s != end)
1039       {
1040         if (*s == '.')
1041           {
1042             if (_DBUS_UNLIKELY ((s + 1) == end))
1043               return FALSE;
1044             if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*(s + 1))))
1045               return FALSE;
1046             ++s; /* we just validated the next char, so skip two */
1047           }
1048         else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s)))
1049           {
1050             return FALSE;
1051           }
1052
1053         ++s;
1054       }
1055
1056     return TRUE;
1057   }
1058   else if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
1059     return FALSE;
1060   else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*s)))
1061     return FALSE;
1062   else
1063     ++s;
1064
1065   while (s != end)
1066     {
1067       if (*s == '.')
1068         {
1069           if (_DBUS_UNLIKELY ((s + 1) == end))
1070             return FALSE;
1071           else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*(s + 1))))
1072             return FALSE;
1073           last_dot = s;
1074           ++s; /* we just validated the next char, so skip two */
1075         }
1076       else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s)))
1077         {
1078           return FALSE;
1079         }
1080
1081       ++s;
1082     }
1083
1084   if (_DBUS_UNLIKELY (last_dot == NULL))
1085     return FALSE;
1086
1087   return TRUE;
1088 }
1089
1090 /**
1091  * Checks that the given range of the string is a valid message type
1092  * signature in the D-Bus protocol.
1093  *
1094  * @todo this is inconsistent with most of DBusString in that
1095  * it allows a start,len range that extends past the string end.
1096  *
1097  * @param str the string
1098  * @param start first byte index to check
1099  * @param len number of bytes to check
1100  * @returns #TRUE if the byte range exists and is a valid signature
1101  */
1102 dbus_bool_t
1103 _dbus_validate_signature (const DBusString  *str,
1104                           int                start,
1105                           int                len)
1106 {
1107   _dbus_assert (start >= 0);
1108   _dbus_assert (start <= _dbus_string_get_length (str));
1109   _dbus_assert (len >= 0);
1110
1111   if (len > _dbus_string_get_length (str) - start)
1112     return FALSE;
1113
1114   return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID;
1115 }
1116
1117 /** define _dbus_check_is_valid_path() */
1118 DEFINE_DBUS_NAME_CHECK(path)
1119 /** define _dbus_check_is_valid_interface() */
1120 DEFINE_DBUS_NAME_CHECK(interface)
1121 /** define _dbus_check_is_valid_member() */
1122 DEFINE_DBUS_NAME_CHECK(member)
1123 /** define _dbus_check_is_valid_error_name() */
1124 DEFINE_DBUS_NAME_CHECK(error_name)
1125 /** define _dbus_check_is_valid_bus_name() */
1126 DEFINE_DBUS_NAME_CHECK(bus_name)
1127 /** define _dbus_check_is_valid_signature() */
1128 DEFINE_DBUS_NAME_CHECK(signature)
1129
1130 /** @} */
1131
1132 /* tests in dbus-marshal-validate-util.c */