dbus-marshal-validate: Validate length of arrays of fixed-length items
[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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <config.h>
25 #include "dbus-internals.h"
26 #include "dbus-marshal-validate.h"
27 #include "dbus-marshal-recursive.h"
28 #include "dbus-marshal-basic.h"
29 #include "dbus-signature.h"
30 #include "dbus-string.h"
31
32 /**
33  * @addtogroup DBusMarshal
34  *
35  * @{
36  */
37
38 /**
39  * Verifies that the range of type_str from type_pos to type_end is a
40  * valid signature.  If this function returns #TRUE, it will be safe
41  * to iterate over the signature with a types-only #DBusTypeReader.
42  * The range passed in should NOT include the terminating
43  * nul/DBUS_TYPE_INVALID.
44  *
45  * @param type_str the string
46  * @param type_pos where the typecodes start
47  * @param len length of typecodes
48  * @returns #DBUS_VALID if valid, reason why invalid otherwise
49  */
50 DBusValidity
51 _dbus_validate_signature_with_reason (const DBusString *type_str,
52                                       int               type_pos,
53                                       int               len)
54 {
55   const unsigned char *p;
56   const unsigned char *end;
57   int last;
58   int struct_depth;
59   int array_depth;
60   int dict_entry_depth;
61   DBusValidity result;
62
63   int element_count;
64   DBusList *element_count_stack;
65
66   result = DBUS_VALID;
67   element_count_stack = NULL;
68
69   if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0)))
70     {
71       result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR;
72       goto out;
73     }
74
75   _dbus_assert (type_str != NULL);
76   _dbus_assert (type_pos < _DBUS_INT32_MAX - len);
77   _dbus_assert (len >= 0);
78   _dbus_assert (type_pos >= 0);
79
80   if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH)
81     {
82       result = DBUS_INVALID_SIGNATURE_TOO_LONG;
83       goto out;
84     }
85
86   p = _dbus_string_get_const_udata_len (type_str, type_pos, 0);
87
88   end = _dbus_string_get_const_udata_len (type_str, type_pos + len, 0);
89   struct_depth = 0;
90   array_depth = 0;
91   dict_entry_depth = 0;
92   last = DBUS_TYPE_INVALID;
93
94   while (p != end)
95     {
96       switch (*p)
97         {
98         case DBUS_TYPE_BYTE:
99         case DBUS_TYPE_BOOLEAN:
100         case DBUS_TYPE_INT16:
101         case DBUS_TYPE_UINT16:
102         case DBUS_TYPE_INT32:
103         case DBUS_TYPE_UINT32:
104         case DBUS_TYPE_UNIX_FD:
105         case DBUS_TYPE_INT64:
106         case DBUS_TYPE_UINT64:
107         case DBUS_TYPE_DOUBLE:
108         case DBUS_TYPE_STRING:
109         case DBUS_TYPE_OBJECT_PATH:
110         case DBUS_TYPE_SIGNATURE:
111         case DBUS_TYPE_VARIANT:
112           break;
113
114         case DBUS_TYPE_ARRAY:
115           array_depth += 1;
116           if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
117             {
118               result = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION;
119               goto out;
120             }
121           break;
122
123         case DBUS_STRUCT_BEGIN_CHAR:
124           struct_depth += 1;
125
126           if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
127             {
128               result = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION;
129               goto out;
130             }
131           
132           if (!_dbus_list_append (&element_count_stack, 
133                              _DBUS_INT_TO_POINTER (0)))
134             {
135               result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR;
136               goto out;
137             }
138
139           break;
140
141         case DBUS_STRUCT_END_CHAR:
142           if (struct_depth == 0)
143             {
144               result = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED;
145               goto out;
146             }
147
148           if (last == DBUS_STRUCT_BEGIN_CHAR)
149             {
150               result = DBUS_INVALID_STRUCT_HAS_NO_FIELDS;
151               goto out;
152             }
153
154           _dbus_list_pop_last (&element_count_stack);
155
156           struct_depth -= 1;
157           break;
158
159         case DBUS_DICT_ENTRY_BEGIN_CHAR:
160           if (last != DBUS_TYPE_ARRAY)
161             {
162               result = DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY;
163               goto out;
164             }
165             
166           dict_entry_depth += 1;
167
168           if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
169             {
170               result = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
171               goto out;
172             }
173
174           if (!_dbus_list_append (&element_count_stack, 
175                              _DBUS_INT_TO_POINTER (0)))
176             {
177               result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR;
178               goto out;
179             }
180
181           break;
182
183         case DBUS_DICT_ENTRY_END_CHAR:
184           if (dict_entry_depth == 0)
185             {
186               result = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
187               goto out;
188             }
189             
190           dict_entry_depth -= 1;
191
192           element_count = 
193             _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack));
194
195           if (element_count != 2)
196             {
197               if (element_count == 0)
198                 result = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
199               else if (element_count == 1)
200                 result = DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD;
201               else
202                 result = DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS;
203               
204               goto out;
205             }
206           break;
207           
208         case DBUS_TYPE_STRUCT:     /* doesn't appear in signatures */
209         case DBUS_TYPE_DICT_ENTRY: /* ditto */
210         default:
211           result = DBUS_INVALID_UNKNOWN_TYPECODE;
212           goto out;
213         }
214
215       if (*p != DBUS_TYPE_ARRAY && 
216           *p != DBUS_DICT_ENTRY_BEGIN_CHAR && 
217           *p != DBUS_STRUCT_BEGIN_CHAR) 
218         {
219           element_count = 
220             _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack));
221
222           ++element_count;
223
224           if (!_dbus_list_append (&element_count_stack, 
225                              _DBUS_INT_TO_POINTER (element_count)))
226             {
227               result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR;
228               goto out;
229             }
230         }
231       
232       if (array_depth > 0)
233         {
234           if (*p == DBUS_TYPE_ARRAY && p != end)
235             {
236                const unsigned char *p1;
237                p1 = p + 1;
238                if (*p1 == DBUS_STRUCT_END_CHAR ||
239                    *p1 == DBUS_DICT_ENTRY_END_CHAR)
240                  {
241                    result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE;
242                    goto out;
243                  }
244             }
245           else
246             {
247               array_depth = 0;
248             }
249         }
250
251       if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
252         {
253           if (!(dbus_type_is_valid (*p) && dbus_type_is_basic (*p)))
254             {
255               result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
256               goto out;
257             }
258         }
259
260       last = *p;
261       ++p;
262     }
263
264
265   if (array_depth > 0)
266     {
267       result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE;
268       goto out;
269     }
270     
271   if (struct_depth > 0)
272     {
273        result = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
274        goto out;
275     }
276     
277   if (dict_entry_depth > 0)
278     {
279       result =  DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
280       goto out;
281     }
282     
283   _dbus_assert (last != DBUS_TYPE_ARRAY);
284   _dbus_assert (last != DBUS_STRUCT_BEGIN_CHAR);
285   _dbus_assert (last != DBUS_DICT_ENTRY_BEGIN_CHAR);
286
287   result = DBUS_VALID;
288
289 out:
290   _dbus_list_clear (&element_count_stack);
291   return result;
292 }
293
294 /* note: this function is also used to validate the header's values,
295  * since the header is a valid body with a particular signature.
296  */
297 static DBusValidity
298 validate_body_helper (DBusTypeReader       *reader,
299                       int                   byte_order,
300                       dbus_bool_t           walk_reader_to_end,
301                       int                   total_depth,
302                       const unsigned char  *p,
303                       const unsigned char  *end,
304                       const unsigned char **new_p)
305 {
306   int current_type;
307
308   /* The spec allows arrays and structs to each nest 32, for total
309    * nesting of 2*32. We want to impose the same limit on "dynamic"
310    * value nesting (not visible in the signature) which is introduced
311    * by DBUS_TYPE_VARIANT.
312    */
313   if (total_depth > (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH * 2))
314     {
315       return DBUS_INVALID_NESTED_TOO_DEEPLY;
316     }
317
318   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
319     {
320       const unsigned char *a;
321       int alignment;
322
323 #if 0
324       _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
325                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
326                      (int) (end - p));
327 #endif
328
329       /* Guarantee that p has one byte to look at */
330       if (p == end)
331         return DBUS_INVALID_NOT_ENOUGH_DATA;
332
333       switch (current_type)
334         {
335         case DBUS_TYPE_BYTE:
336           ++p;
337           break;
338
339         case DBUS_TYPE_BOOLEAN:
340         case DBUS_TYPE_INT16:
341         case DBUS_TYPE_UINT16:
342         case DBUS_TYPE_INT32:
343         case DBUS_TYPE_UINT32:
344         case DBUS_TYPE_UNIX_FD:
345         case DBUS_TYPE_INT64:
346         case DBUS_TYPE_UINT64:
347         case DBUS_TYPE_DOUBLE:
348           alignment = _dbus_type_get_alignment (current_type);
349           a = _DBUS_ALIGN_ADDRESS (p, alignment);
350           if (a >= end)
351             return DBUS_INVALID_NOT_ENOUGH_DATA;
352           while (p != a)
353             {
354               if (*p != '\0')
355                 return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
356               ++p;
357             }
358           
359           if (current_type == DBUS_TYPE_BOOLEAN)
360             {
361               dbus_uint32_t v;
362
363               if (p + 4 > end)
364                 return DBUS_INVALID_NOT_ENOUGH_DATA;
365
366               v = _dbus_unpack_uint32 (byte_order, p);
367
368               if (!(v == 0 || v == 1))
369                 return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
370             }
371           
372           p += alignment;
373           break;
374
375         case DBUS_TYPE_ARRAY:
376         case DBUS_TYPE_STRING:
377         case DBUS_TYPE_OBJECT_PATH:
378           {
379             dbus_uint32_t claimed_len;
380
381             a = _DBUS_ALIGN_ADDRESS (p, 4);
382             if (a + 4 > end)
383               return DBUS_INVALID_NOT_ENOUGH_DATA;
384             while (p != a)
385               {
386                 if (*p != '\0')
387                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
388                 ++p;
389               }
390
391             claimed_len = _dbus_unpack_uint32 (byte_order, p);
392             p += 4;
393
394             /* p may now be == end */
395             _dbus_assert (p <= end);
396
397             if (current_type == DBUS_TYPE_ARRAY)
398               {
399                 int array_elem_type = _dbus_type_reader_get_element_type (reader);
400
401                 if (!dbus_type_is_valid (array_elem_type))
402                   {
403                     return DBUS_INVALID_UNKNOWN_TYPECODE;
404                   }
405
406                 alignment = _dbus_type_get_alignment (array_elem_type);
407
408                 a = _DBUS_ALIGN_ADDRESS (p, alignment);
409
410                 /* a may now be == end */
411                 if (a > end)
412                   return DBUS_INVALID_NOT_ENOUGH_DATA;
413
414                 while (p != a)
415                   {
416                     if (*p != '\0')
417                       return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
418                     ++p;
419                   }
420               }
421
422             if (claimed_len > (unsigned long) (end - p))
423               return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS;
424
425             if (current_type == DBUS_TYPE_OBJECT_PATH)
426               {
427                 DBusString str;
428                 _dbus_string_init_const_len (&str, (const char *) p, claimed_len);
429                 if (!_dbus_validate_path (&str, 0,
430                                           _dbus_string_get_length (&str)))
431                   return DBUS_INVALID_BAD_PATH;
432
433                 p += claimed_len;
434               }
435             else if (current_type == DBUS_TYPE_STRING)
436               {
437                 DBusString str;
438                 _dbus_string_init_const_len (&str, (const char *) p, claimed_len);
439                 if (!_dbus_string_validate_utf8 (&str, 0,
440                                                  _dbus_string_get_length (&str)))
441                   return DBUS_INVALID_BAD_UTF8_IN_STRING;
442
443                 p += claimed_len;
444               }
445             else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
446               {
447                 DBusTypeReader sub;
448                 DBusValidity validity;
449                 const unsigned char *array_end;
450                 int array_elem_type;
451
452                 if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH)
453                   return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM;
454                 
455                 /* Remember that the reader is types only, so we can't
456                  * use it to iterate over elements. It stays the same
457                  * for all elements.
458                  */
459                 _dbus_type_reader_recurse (reader, &sub);
460
461                 array_end = p + claimed_len;
462
463                 array_elem_type = _dbus_type_reader_get_element_type (reader);
464
465                 /* avoid recursive call to validate_body_helper if this is an array
466                  * of fixed-size elements
467                  */ 
468                 if (dbus_type_is_fixed (array_elem_type))
469                   {
470                     /* Note that fixed-size types all have sizes equal to
471                      * their alignments, so this is really the item size. */
472                     alignment = _dbus_type_get_alignment (array_elem_type);
473                     _dbus_assert (alignment == 1 || alignment == 2 ||
474                                   alignment == 4 || alignment == 8);
475
476                     /* Because the alignment is a power of 2, this is
477                      * equivalent to: (claimed_len % alignment) != 0,
478                      * but avoids slower integer division */
479                     if ((claimed_len & (alignment - 1)) != 0)
480                       return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
481
482                     /* bools need to be handled differently, because they can
483                      * have an invalid value
484                      */
485                     if (array_elem_type == DBUS_TYPE_BOOLEAN)
486                       {
487                         dbus_uint32_t v;
488
489                         while (p < array_end)
490                           {
491                             v = _dbus_unpack_uint32 (byte_order, p);
492
493                             if (!(v == 0 || v == 1))
494                               return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
495
496                             p += alignment;
497                           }
498                       }
499
500                     else
501                       {
502                         p = array_end;
503                       }
504                   }
505
506                 else
507                   {
508                     while (p < array_end)
509                       {
510                         validity = validate_body_helper (&sub, byte_order, FALSE,
511                                                          total_depth + 1,
512                                                          p, end, &p);
513                         if (validity != DBUS_VALID)
514                           return validity;
515                       }
516                   }
517
518                 if (p != array_end)
519                   return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
520               }
521
522             /* check nul termination */
523             if (current_type != DBUS_TYPE_ARRAY)
524               {
525                 if (p == end)
526                   return DBUS_INVALID_NOT_ENOUGH_DATA;
527
528                 if (*p != '\0')
529                   return DBUS_INVALID_STRING_MISSING_NUL;
530                 ++p;
531               }
532           }
533           break;
534
535         case DBUS_TYPE_SIGNATURE:
536           {
537             dbus_uint32_t claimed_len;
538             DBusString str;
539             DBusValidity validity;
540
541             claimed_len = *p;
542             ++p;
543
544             /* 1 is for nul termination */
545             if (claimed_len + 1 > (unsigned long) (end - p))
546               return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
547
548             _dbus_string_init_const_len (&str, (const char *) p, claimed_len);
549             validity =
550               _dbus_validate_signature_with_reason (&str, 0,
551                                                     _dbus_string_get_length (&str));
552
553             if (validity != DBUS_VALID)
554               return validity;
555
556             p += claimed_len;
557
558             _dbus_assert (p < end);
559             if (*p != DBUS_TYPE_INVALID)
560               return DBUS_INVALID_SIGNATURE_MISSING_NUL;
561
562             ++p;
563
564             _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
565           }
566           break;
567
568         case DBUS_TYPE_VARIANT:
569           {
570             /* 1 byte sig len, sig typecodes, align to
571              * contained-type-boundary, values.
572              */
573
574             /* In addition to normal signature validation, we need to be sure
575              * the signature contains only a single (possibly container) type.
576              */
577             dbus_uint32_t claimed_len;
578             DBusString sig;
579             DBusTypeReader sub;
580             DBusValidity validity;
581             int contained_alignment;
582             int contained_type;
583             DBusValidity reason;
584
585             claimed_len = *p;
586             ++p;
587
588             /* + 1 for nul */
589             if (claimed_len + 1 > (unsigned long) (end - p))
590               return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;
591
592             _dbus_string_init_const_len (&sig, (const char *) p, claimed_len);
593             reason = _dbus_validate_signature_with_reason (&sig, 0,
594                                            _dbus_string_get_length (&sig));
595             if (!(reason == DBUS_VALID))
596               {
597                 if (reason == DBUS_VALIDITY_UNKNOWN_OOM_ERROR)
598                   return reason;
599                 else 
600                   return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
601               }
602
603             p += claimed_len;
604             
605             if (*p != DBUS_TYPE_INVALID)
606               return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
607             ++p;
608
609             contained_type = _dbus_first_type_in_signature (&sig, 0);
610             if (contained_type == DBUS_TYPE_INVALID)
611               return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
612             
613             contained_alignment = _dbus_type_get_alignment (contained_type);
614             
615             a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
616             if (a > end)
617               return DBUS_INVALID_NOT_ENOUGH_DATA;
618             while (p != a)
619               {
620                 if (*p != '\0')
621                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
622                 ++p;
623               }
624
625             _dbus_type_reader_init_types_only (&sub, &sig, 0);
626
627             _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);
628
629             validity = validate_body_helper (&sub, byte_order, FALSE,
630                                              total_depth + 1,
631                                              p, end, &p);
632             if (validity != DBUS_VALID)
633               return validity;
634
635             if (_dbus_type_reader_next (&sub))
636               return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;
637
638             _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
639           }
640           break;
641
642         case DBUS_TYPE_DICT_ENTRY:
643         case DBUS_TYPE_STRUCT:
644           {
645             DBusTypeReader sub;
646             DBusValidity validity;
647
648             a = _DBUS_ALIGN_ADDRESS (p, 8);
649             if (a > end)
650               return DBUS_INVALID_NOT_ENOUGH_DATA;
651             while (p != a)
652               {
653                 if (*p != '\0')
654                   return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
655                 ++p;
656               }
657
658             _dbus_type_reader_recurse (reader, &sub);
659
660             validity = validate_body_helper (&sub, byte_order, TRUE,
661                                              total_depth + 1,
662                                              p, end, &p);
663             if (validity != DBUS_VALID)
664               return validity;
665           }
666           break;
667
668         default:
669           _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
670           break;
671         }
672
673 #if 0
674       _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
675                      _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
676                      (int) (end - p));
677 #endif
678
679       if (p > end)
680         {
681           _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
682                          p, end, (int) (end - p));
683           return DBUS_INVALID_NOT_ENOUGH_DATA;
684         }
685
686       if (walk_reader_to_end)
687         _dbus_type_reader_next (reader);
688       else
689         break;
690     }
691
692   if (new_p)
693     *new_p = p;
694
695   return DBUS_VALID;
696 }
697
698 /**
699  * Verifies that the range of value_str from value_pos to value_end is
700  * a legitimate value of type expected_signature.  If this function
701  * returns #TRUE, it will be safe to iterate over the values with
702  * #DBusTypeReader. The signature is assumed to be already valid.
703  *
704  * If bytes_remaining is not #NULL, then leftover bytes will be stored
705  * there and #DBUS_VALID returned. If it is #NULL, then
706  * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left
707  * over.
708  *
709  * @param expected_signature the expected types in the value_str
710  * @param expected_signature_start where in expected_signature is the signature
711  * @param byte_order the byte order
712  * @param bytes_remaining place to store leftover bytes
713  * @param value_str the string containing the body
714  * @param value_pos where the values start
715  * @param len length of values after value_pos
716  * @returns #DBUS_VALID if valid, reason why invalid otherwise
717  */
718 DBusValidity
719 _dbus_validate_body_with_reason (const DBusString *expected_signature,
720                                  int               expected_signature_start,
721                                  int               byte_order,
722                                  int              *bytes_remaining,
723                                  const DBusString *value_str,
724                                  int               value_pos,
725                                  int               len)
726 {
727   DBusTypeReader reader;
728   const unsigned char *p;
729   const unsigned char *end;
730   DBusValidity validity;
731
732   _dbus_assert (len >= 0);
733   _dbus_assert (value_pos >= 0);
734   _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len);
735
736   _dbus_verbose ("validating body from pos %d len %d sig '%s'\n",
737                  value_pos, len, _dbus_string_get_const_data_len (expected_signature,
738                                                                   expected_signature_start,
739                                                                   0));
740
741   _dbus_type_reader_init_types_only (&reader,
742                                      expected_signature, expected_signature_start);
743
744   p = _dbus_string_get_const_udata_len (value_str, value_pos, len);
745   end = p + len;
746
747   validity = validate_body_helper (&reader, byte_order, TRUE, 0, p, end, &p);
748   if (validity != DBUS_VALID)
749     return validity;
750   
751   if (bytes_remaining)
752     {
753       *bytes_remaining = end - p;
754       return DBUS_VALID;
755     }
756   else if (p < end)
757     return DBUS_INVALID_TOO_MUCH_DATA;
758   else
759     {
760       _dbus_assert (p == end);
761       return DBUS_VALID;
762     }
763 }
764
765 /**
766  * Determine wether the given character is valid as the first character
767  * in a name.
768  */
769 #define VALID_INITIAL_NAME_CHARACTER(c)         \
770   ( ((c) >= 'A' && (c) <= 'Z') ||               \
771     ((c) >= 'a' && (c) <= 'z') ||               \
772     ((c) == '_') )
773
774 /**
775  * Determine wether the given character is valid as a second or later
776  * character in a name
777  */
778 #define VALID_NAME_CHARACTER(c)                 \
779   ( ((c) >= '0' && (c) <= '9') ||               \
780     ((c) >= 'A' && (c) <= 'Z') ||               \
781     ((c) >= 'a' && (c) <= 'z') ||               \
782     ((c) == '_') )
783
784 /**
785  * Checks that the given range of the string is a valid object path
786  * name in the D-Bus protocol. Part of the validation ensures that
787  * the object path contains only ASCII.
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  * @todo change spec to disallow more things, such as spaces in the
793  * path name
794  *
795  * @param str the string
796  * @param start first byte index to check
797  * @param len number of bytes to check
798  * @returns #TRUE if the byte range exists and is a valid name
799  */
800 dbus_bool_t
801 _dbus_validate_path (const DBusString  *str,
802                      int                start,
803                      int                len)
804 {
805   const unsigned char *s;
806   const unsigned char *end;
807   const unsigned char *last_slash;
808
809   _dbus_assert (start >= 0);
810   _dbus_assert (len >= 0);
811   _dbus_assert (start <= _dbus_string_get_length (str));
812   
813   if (len > _dbus_string_get_length (str) - start)
814     return FALSE;
815
816   if (len == 0)
817     return FALSE;
818
819   s = _dbus_string_get_const_udata (str) + start;
820   end = s + len;
821
822   if (*s != '/')
823     return FALSE;
824   last_slash = s;
825   ++s;
826
827   while (s != end)
828     {
829       if (*s == '/')
830         {
831           if ((s - last_slash) < 2)
832             return FALSE; /* no empty path components allowed */
833
834           last_slash = s;
835         }
836       else
837         {
838           if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
839             return FALSE;
840         }
841
842       ++s;
843     }
844
845   if ((end - last_slash) < 2 &&
846       len > 1)
847     return FALSE; /* trailing slash not allowed unless the string is "/" */
848
849   return TRUE;
850 }
851
852 const char *
853 _dbus_validity_to_error_message (DBusValidity validity)
854 {
855   switch (validity)
856     {
857     case DBUS_VALIDITY_UNKNOWN_OOM_ERROR:                          return "Out of memory";
858     case DBUS_INVALID_FOR_UNKNOWN_REASON:                          return "Unknown reason";
859     case DBUS_VALID_BUT_INCOMPLETE:                                return "Valid but incomplete";
860     case DBUS_VALIDITY_UNKNOWN:                                    return "Validity unknown";
861     case DBUS_VALID:                                               return "Valid";
862     case DBUS_INVALID_UNKNOWN_TYPECODE:                            return "Unknown typecode";
863     case DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE:                  return "Missing array element type";
864     case DBUS_INVALID_SIGNATURE_TOO_LONG:                          return "Signature is too long";
865     case DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION:            return "Exceeded maximum array recursion";
866     case DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION:           return "Exceeded maximum struct recursion";
867     case DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED:                return "Struct ended but not started";
868     case DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED:                return "Struct started but not ended";
869     case DBUS_INVALID_STRUCT_HAS_NO_FIELDS:                        return "Struct has no fields";
870     case DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL:                   return "Alignment padding not null";
871     case DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE:                     return "Boolean is not zero or one";
872     case DBUS_INVALID_NOT_ENOUGH_DATA:                             return "Not enough data";
873     case DBUS_INVALID_TOO_MUCH_DATA:                               return "Too much data";
874     case DBUS_INVALID_BAD_BYTE_ORDER:                              return "Bad byte order";
875     case DBUS_INVALID_BAD_PROTOCOL_VERSION:                        return "Bad protocol version";
876     case DBUS_INVALID_BAD_MESSAGE_TYPE:                            return "Bad message type";
877     case DBUS_INVALID_BAD_SERIAL:                                  return "Bad serial";
878     case DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH:                  return "Insane fields array length";
879     case DBUS_INVALID_INSANE_BODY_LENGTH:                          return "Insane body length";
880     case DBUS_INVALID_MESSAGE_TOO_LONG:                            return "Message too long";
881     case DBUS_INVALID_HEADER_FIELD_CODE:                           return "Header field code";
882     case DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE:                 return "Header field has wrong type";
883     case DBUS_INVALID_USES_LOCAL_INTERFACE:                        return "Uses local interface";
884     case DBUS_INVALID_USES_LOCAL_PATH:                             return "Uses local path";
885     case DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE:                  return "Header field appears twice";
886     case DBUS_INVALID_BAD_DESTINATION:                             return "Bad destination";
887     case DBUS_INVALID_BAD_INTERFACE:                               return "Bad interface";
888     case DBUS_INVALID_BAD_MEMBER:                                  return "Bad member";
889     case DBUS_INVALID_BAD_ERROR_NAME:                              return "Bad error name";
890     case DBUS_INVALID_BAD_SENDER:                                  return "Bad sender";
891     case DBUS_INVALID_MISSING_PATH:                                return "Missing path";
892     case DBUS_INVALID_MISSING_INTERFACE:                           return "Missing interface";
893     case DBUS_INVALID_MISSING_MEMBER:                              return "Missing member";
894     case DBUS_INVALID_MISSING_ERROR_NAME:                          return "Missing error name";
895     case DBUS_INVALID_MISSING_REPLY_SERIAL:                        return "Missing reply serial";
896     case DBUS_INVALID_LENGTH_OUT_OF_BOUNDS:                        return "Length out of bounds";
897     case DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM:                return "Array length exceeds maximum";
898     case DBUS_INVALID_BAD_PATH:                                    return "Bad path";
899     case DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS:              return "Signature length out of bounds";
900     case DBUS_INVALID_BAD_UTF8_IN_STRING:                          return "Bad utf8 in string";
901     case DBUS_INVALID_ARRAY_LENGTH_INCORRECT:                      return "Array length incorrect";
902     case DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS:      return "Variant signature length out of bounds";
903     case DBUS_INVALID_VARIANT_SIGNATURE_BAD:                       return "Variant signature bad";
904     case DBUS_INVALID_VARIANT_SIGNATURE_EMPTY:                     return "Variant signature empty";
905     case DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES: return "Variant signature specifies multiple values";
906     case DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL:               return "Variant signature missing nul";
907     case DBUS_INVALID_STRING_MISSING_NUL:                          return "String missing nul";
908     case DBUS_INVALID_SIGNATURE_MISSING_NUL:                       return "Signature missing nul";
909     case DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION:       return "Exceeded maximum dict entry recursion";
910     case DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED:            return "Dict entry ended but not started";
911     case DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED:            return "Dict entry started but not ended";
912     case DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS:                    return "Dict entry has no fields";
913     case DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD:               return "Dict entry has only one field";
914     case DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS:              return "Dict entry has too many fields";
915     case DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY:                 return "Dict entry not inside array";
916     case DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE:                 return "Dict key must be basic type";
917     case DBUS_INVALID_MISSING_UNIX_FDS:                            return "Unix file descriptor missing";
918     case DBUS_INVALID_NESTED_TOO_DEEPLY:                           return "Variants cannot be used to create a hugely recursive tree of values";
919     case DBUS_VALIDITY_LAST:
920     default:
921       return "Invalid";
922     }
923 }
924
925 /**
926  * Checks that the given range of the string is a valid interface name
927  * in the D-Bus protocol. This includes a length restriction and an
928  * ASCII subset, see the specification.
929  *
930  * @todo this is inconsistent with most of DBusString in that
931  * it allows a start,len range that extends past the string end.
932  *
933  * @param str the string
934  * @param start first byte index to check
935  * @param len number of bytes to check
936  * @returns #TRUE if the byte range exists and is a valid name
937  */
938 dbus_bool_t
939 _dbus_validate_interface (const DBusString  *str,
940                           int                start,
941                           int                len)
942 {
943   const unsigned char *s;
944   const unsigned char *end;
945   const unsigned char *iface;
946   const unsigned char *last_dot;
947
948   _dbus_assert (start >= 0);
949   _dbus_assert (len >= 0);
950   _dbus_assert (start <= _dbus_string_get_length (str));
951
952   if (len > _dbus_string_get_length (str) - start)
953     return FALSE;
954
955   if (len > DBUS_MAXIMUM_NAME_LENGTH)
956     return FALSE;
957
958   if (len == 0)
959     return FALSE;
960
961   last_dot = NULL;
962   iface = _dbus_string_get_const_udata (str) + start;
963   end = iface + len;
964   s = iface;
965
966   /* check special cases of first char so it doesn't have to be done
967    * in the loop. Note we know len > 0
968    */
969   if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
970     return FALSE;
971   else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
972     return FALSE;
973   else
974     ++s;
975
976   while (s != end)
977     {
978       if (*s == '.')
979         {
980           if (_DBUS_UNLIKELY ((s + 1) == end))
981             return FALSE;
982           else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
983             return FALSE;
984           last_dot = s;
985           ++s; /* we just validated the next char, so skip two */
986         }
987       else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
988         {
989           return FALSE;
990         }
991
992       ++s;
993     }
994
995   if (_DBUS_UNLIKELY (last_dot == NULL))
996     return FALSE;
997
998   return TRUE;
999 }
1000
1001 /**
1002  * Checks that the given range of the string is a valid member name
1003  * in the D-Bus protocol. This includes a length restriction, etc.,
1004  * see the specification.
1005  *
1006  * @todo this is inconsistent with most of DBusString in that
1007  * it allows a start,len range that extends past the string end.
1008  *
1009  * @param str the string
1010  * @param start first byte index to check
1011  * @param len number of bytes to check
1012  * @returns #TRUE if the byte range exists and is a valid name
1013  */
1014 dbus_bool_t
1015 _dbus_validate_member (const DBusString  *str,
1016                        int                start,
1017                        int                len)
1018 {
1019   const unsigned char *s;
1020   const unsigned char *end;
1021   const unsigned char *member;
1022
1023   _dbus_assert (start >= 0);
1024   _dbus_assert (len >= 0);
1025   _dbus_assert (start <= _dbus_string_get_length (str));
1026
1027   if (len > _dbus_string_get_length (str) - start)
1028     return FALSE;
1029
1030   if (len > DBUS_MAXIMUM_NAME_LENGTH)
1031     return FALSE;
1032
1033   if (len == 0)
1034     return FALSE;
1035
1036   member = _dbus_string_get_const_udata (str) + start;
1037   end = member + len;
1038   s = member;
1039
1040   /* check special cases of first char so it doesn't have to be done
1041    * in the loop. Note we know len > 0
1042    */
1043
1044   if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
1045     return FALSE;
1046   else
1047     ++s;
1048
1049   while (s != end)
1050     {
1051       if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
1052         {
1053           return FALSE;
1054         }
1055
1056       ++s;
1057     }
1058
1059   return TRUE;
1060 }
1061
1062 /**
1063  * Checks that the given range of the string is a valid error name
1064  * in the D-Bus protocol. This includes a length restriction, etc.,
1065  * see the specification.
1066  *
1067  * @todo this is inconsistent with most of DBusString in that
1068  * it allows a start,len range that extends past the string end.
1069  *
1070  * @param str the string
1071  * @param start first byte index to check
1072  * @param len number of bytes to check
1073  * @returns #TRUE if the byte range exists and is a valid name
1074  */
1075 dbus_bool_t
1076 _dbus_validate_error_name (const DBusString  *str,
1077                            int                start,
1078                            int                len)
1079 {
1080   /* Same restrictions as interface name at the moment */
1081   return _dbus_validate_interface (str, start, len);
1082 }
1083
1084 /**
1085  * Determine wether the given character is valid as the first character
1086  * in a bus name.
1087  */
1088 #define VALID_INITIAL_BUS_NAME_CHARACTER(c)         \
1089   ( ((c) >= 'A' && (c) <= 'Z') ||               \
1090     ((c) >= 'a' && (c) <= 'z') ||               \
1091     ((c) == '_') || ((c) == '-'))
1092
1093 /**
1094  * Determine wether the given character is valid as a second or later
1095  * character in a bus name
1096  */
1097 #define VALID_BUS_NAME_CHARACTER(c)                 \
1098   ( ((c) >= '0' && (c) <= '9') ||               \
1099     ((c) >= 'A' && (c) <= 'Z') ||               \
1100     ((c) >= 'a' && (c) <= 'z') ||               \
1101     ((c) == '_') || ((c) == '-'))
1102
1103 static dbus_bool_t
1104 _dbus_validate_bus_name_full (const DBusString  *str,
1105                               int                start,
1106                               int                len,
1107                               dbus_bool_t        is_namespace)
1108 {
1109   const unsigned char *s;
1110   const unsigned char *end;
1111   const unsigned char *iface;
1112   const unsigned char *last_dot;
1113
1114   _dbus_assert (start >= 0);
1115   _dbus_assert (len >= 0);
1116   _dbus_assert (start <= _dbus_string_get_length (str));
1117
1118   if (len > _dbus_string_get_length (str) - start)
1119     return FALSE;
1120
1121   if (len > DBUS_MAXIMUM_NAME_LENGTH)
1122     return FALSE;
1123
1124   if (len == 0)
1125     return FALSE;
1126
1127   last_dot = NULL;
1128   iface = _dbus_string_get_const_udata (str) + start;
1129   end = iface + len;
1130   s = iface;
1131
1132   /* check special cases of first char so it doesn't have to be done
1133    * in the loop. Note we know len > 0
1134    */
1135   if (*s == ':')
1136   {
1137     /* unique name */
1138     ++s;
1139     while (s != end)
1140       {
1141         if (*s == '.')
1142           {
1143             if (_DBUS_UNLIKELY ((s + 1) == end))
1144               return FALSE;
1145             if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*(s + 1))))
1146               return FALSE;
1147             ++s; /* we just validated the next char, so skip two */
1148           }
1149         else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s)))
1150           {
1151             return FALSE;
1152           }
1153
1154         ++s;
1155       }
1156
1157     return TRUE;
1158   }
1159   else if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
1160     return FALSE;
1161   else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*s)))
1162     return FALSE;
1163   else
1164     ++s;
1165
1166   while (s != end)
1167     {
1168       if (*s == '.')
1169         {
1170           if (_DBUS_UNLIKELY ((s + 1) == end))
1171             return FALSE;
1172           else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*(s + 1))))
1173             return FALSE;
1174           last_dot = s;
1175           ++s; /* we just validated the next char, so skip two */
1176         }
1177       else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s)))
1178         {
1179           return FALSE;
1180         }
1181
1182       ++s;
1183     }
1184
1185   if (!is_namespace && _DBUS_UNLIKELY (last_dot == NULL))
1186     return FALSE;
1187
1188   return TRUE;
1189 }
1190
1191 /**
1192  * Checks that the given range of the string is a valid bus name in
1193  * the D-Bus protocol. This includes a length restriction, etc., see
1194  * the specification.
1195  *
1196  * @todo this is inconsistent with most of DBusString in that
1197  * it allows a start,len range that extends past the string end.
1198  *
1199  * @param str the string
1200  * @param start first byte index to check
1201  * @param len number of bytes to check
1202  * @returns #TRUE if the byte range exists and is a valid name
1203  */
1204 dbus_bool_t
1205 _dbus_validate_bus_name (const DBusString  *str,
1206                          int                start,
1207                          int                len)
1208 {
1209   return _dbus_validate_bus_name_full (str, start, len, FALSE);
1210 }
1211
1212 /**
1213  * Checks that the given range of the string is a prefix of a valid bus name in
1214  * the D-Bus protocol. Unlike _dbus_validate_bus_name(), this accepts strings
1215  * with only one period-separated component.
1216  *
1217  * @todo this is inconsistent with most of DBusString in that
1218  * it allows a start,len range that extends past the string end.
1219  *
1220  * @param str the string
1221  * @param start first byte index to check
1222  * @param len number of bytes to check
1223  * @returns #TRUE if the byte range exists and is a valid name
1224  */
1225 dbus_bool_t
1226 _dbus_validate_bus_namespace (const DBusString  *str,
1227                               int                start,
1228                               int                len)
1229 {
1230   return _dbus_validate_bus_name_full (str, start, len, TRUE);
1231 }
1232
1233 /** define _dbus_check_is_valid_path() */
1234 DEFINE_DBUS_NAME_CHECK(path)
1235 /** define _dbus_check_is_valid_interface() */
1236 DEFINE_DBUS_NAME_CHECK(interface)
1237 /** define _dbus_check_is_valid_member() */
1238 DEFINE_DBUS_NAME_CHECK(member)
1239 /** define _dbus_check_is_valid_error_name() */
1240 DEFINE_DBUS_NAME_CHECK(error_name)
1241 /** define _dbus_check_is_valid_bus_name() */
1242 DEFINE_DBUS_NAME_CHECK(bus_name)
1243 /** define _dbus_check_is_valid_utf8() */
1244 DEFINE_DBUS_NAME_CHECK(utf8)
1245
1246 /** @} */
1247
1248 /* tests in dbus-marshal-validate-util.c */