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