Beispiel #1
0
/**
 * Hex-encode a UUID.
 *
 * @param uuid the uuid
 * @param encoded string to append hex uuid to
 * @returns #FALSE if no memory
 */
dbus_bool_t
_dbus_uuid_encode (const DBusGUID *uuid,
                   DBusString     *encoded)
{
  DBusString binary;
  _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
  return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
}
/**
 * Writes a struct of { byte, variant } with the given basic type.
 *
 * @param writer the writer (should be ready to write a struct)
 * @param type the type of the value
 * @param value the value as for _dbus_marshal_set_basic()
 * @returns #FALSE if no memory
 */
static dbus_bool_t
write_basic_field (DBusTypeWriter *writer,
                   int             field,
                   int             type,
                   const void     *value)
{
  DBusTypeWriter sub;
  DBusTypeWriter variant;
  int start;
  int padding;
  unsigned char field_byte;
  DBusString contained_type;
  char buf[2];

  start = writer->value_pos;
  padding = _dbus_string_get_length (writer->value_str) - start;

  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT,
                                  NULL, 0, &sub))
    goto append_failed;

  field_byte = field;
  if (!_dbus_type_writer_write_basic (&sub, DBUS_TYPE_BYTE,
                                      &field_byte))
    goto append_failed;

  buf[0] = type;
  buf[1] = '\0';
  _dbus_string_init_const_len (&contained_type, buf, 1);

  if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_VARIANT,
                                  &contained_type, 0, &variant))
    goto append_failed;

  if (!_dbus_type_writer_write_basic (&variant, type, value))
    goto append_failed;

  if (!_dbus_type_writer_unrecurse (&sub, &variant))
    goto append_failed;

  if (!_dbus_type_writer_unrecurse (writer, &sub))
    goto append_failed;

  return TRUE;

 append_failed:
  _dbus_string_delete (writer->value_str,
                       start,
                       _dbus_string_get_length (writer->value_str) - start - padding);
  return FALSE;
}
static DBusValidity
validate_body_helper (DBusTypeReader       *reader,
                      int                   byte_order,
                      dbus_bool_t           walk_reader_to_end,
                      const unsigned char  *p,
                      const unsigned char  *end,
                      const unsigned char **new_p)
{
  int current_type;

  while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
    {
      const unsigned char *a;
      int alignment;

#if 0
      _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
                     (int) (end - p));
#endif

      /* Guarantee that p has one byte to look at */
      if (p == end)
        return DBUS_INVALID_NOT_ENOUGH_DATA;

      switch (current_type)
        {
        case DBUS_TYPE_BYTE:
          ++p;
          break;
          
        case DBUS_TYPE_BOOLEAN:
        case DBUS_TYPE_INT16:
        case DBUS_TYPE_UINT16:
        case DBUS_TYPE_INT32:
        case DBUS_TYPE_UINT32:
        case DBUS_TYPE_INT64:
        case DBUS_TYPE_UINT64:
        case DBUS_TYPE_DOUBLE:
          alignment = _dbus_type_get_alignment (current_type);
          a = _DBUS_ALIGN_ADDRESS (p, alignment);
          if (a >= end)
            return DBUS_INVALID_NOT_ENOUGH_DATA;
          while (p != a)
            {
              if (*p != '\0')
                return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
              ++p;
            }
          
          if (current_type == DBUS_TYPE_BOOLEAN)
            {
              dbus_uint32_t v = _dbus_unpack_uint32 (byte_order,
                                                     p);
              if (!(v == 0 || v == 1))
                return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
            }
          
          p += alignment;
          break;

        case DBUS_TYPE_ARRAY:
        case DBUS_TYPE_STRING:
        case DBUS_TYPE_OBJECT_PATH:
          {
            dbus_uint32_t claimed_len;

            a = _DBUS_ALIGN_ADDRESS (p, 4);
            if (a + 4 > end)
              return DBUS_INVALID_NOT_ENOUGH_DATA;
            while (p != a)
              {
                if (*p != '\0')
                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                ++p;
              }

            claimed_len = _dbus_unpack_uint32 (byte_order, p);
            p += 4;

            /* p may now be == end */
            _dbus_assert (p <= end);
            
            if (current_type == DBUS_TYPE_ARRAY)
              {
                int array_elem_type = _dbus_type_reader_get_element_type (reader);
                alignment = _dbus_type_get_alignment (array_elem_type);
                p = _DBUS_ALIGN_ADDRESS (p, alignment);
              }

            if (claimed_len > (unsigned long) (end - p))
              return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS;

            if (current_type == DBUS_TYPE_OBJECT_PATH)
              {
                DBusString str;
                _dbus_string_init_const_len (&str, p, claimed_len);
                if (!_dbus_validate_path (&str, 0,
                                          _dbus_string_get_length (&str)))
                  return DBUS_INVALID_BAD_PATH;

                p += claimed_len;
              }
            else if (current_type == DBUS_TYPE_STRING)
              {
                DBusString str;
                _dbus_string_init_const_len (&str, p, claimed_len);
                if (!_dbus_string_validate_utf8 (&str, 0,
                                                 _dbus_string_get_length (&str)))
                  return DBUS_INVALID_BAD_UTF8_IN_STRING;

                p += claimed_len;
              }
            else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
              {
                DBusTypeReader sub;
                DBusValidity validity;
                const unsigned char *array_end;

                if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH)
                  return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM;
                
                /* Remember that the reader is types only, so we can't
                 * use it to iterate over elements. It stays the same
                 * for all elements.
                 */
                _dbus_type_reader_recurse (reader, &sub);

                array_end = p + claimed_len;

                while (p < array_end)
                  {
                    /* FIXME we are calling a function per array element! very bad
                     * need if (dbus_type_is_fixed(elem_type)) here to just skip
                     * big blocks of ints/bytes/etc.
                     */                     
                    
                    validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
                    if (validity != DBUS_VALID)
                      return validity;
                  }

                if (p != array_end)
                  return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
              }

            /* check nul termination */
            if (current_type != DBUS_TYPE_ARRAY)
              {
                if (p == end)
                  return DBUS_INVALID_NOT_ENOUGH_DATA;

                if (*p != '\0')
                  return DBUS_INVALID_STRING_MISSING_NUL;
                ++p;
              }
          }
          break;

        case DBUS_TYPE_SIGNATURE:
          {
            dbus_uint32_t claimed_len;
            DBusString str;
            DBusValidity validity;

            claimed_len = *p;
            ++p;

            /* 1 is for nul termination */
            if (claimed_len + 1 > (unsigned long) (end - p))
              return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;

            _dbus_string_init_const_len (&str, p, claimed_len);
            validity =
              _dbus_validate_signature_with_reason (&str, 0,
                                                    _dbus_string_get_length (&str));

            if (validity != DBUS_VALID)
              return validity;

            p += claimed_len;

            _dbus_assert (p < end);
            if (*p != DBUS_TYPE_INVALID)
              return DBUS_INVALID_SIGNATURE_MISSING_NUL;

            ++p;

            _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
          }
          break;

        case DBUS_TYPE_VARIANT:
          {
            /* 1 byte sig len, sig typecodes, align to
             * contained-type-boundary, values.
             */

            /* In addition to normal signature validation, we need to be sure
             * the signature contains only a single (possibly container) type.
             */
            dbus_uint32_t claimed_len;
            DBusString sig;
            DBusTypeReader sub;
            DBusValidity validity;
            int contained_alignment;
            int contained_type;
            DBusValidity reason;

            claimed_len = *p;
            ++p;

            /* + 1 for nul */
            if (claimed_len + 1 > (unsigned long) (end - p))
              return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;

            _dbus_string_init_const_len (&sig, p, claimed_len);
            reason = _dbus_validate_signature_with_reason (&sig, 0,
                                           _dbus_string_get_length (&sig));
            if (!(reason == DBUS_VALID))
              {
                if (reason == DBUS_VALIDITY_UNKNOWN_OOM_ERROR)
                  return reason;
                else 
                  return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
              }

            p += claimed_len;
            
            if (*p != DBUS_TYPE_INVALID)
              return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
            ++p;

            contained_type = _dbus_first_type_in_signature (&sig, 0);
            if (contained_type == DBUS_TYPE_INVALID)
              return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
            
            contained_alignment = _dbus_type_get_alignment (contained_type);
            
            a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
            if (a > end)
              return DBUS_INVALID_NOT_ENOUGH_DATA;
            while (p != a)
              {
                if (*p != '\0')
                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                ++p;
              }

            _dbus_type_reader_init_types_only (&sub, &sig, 0);

            _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);

            validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
            if (validity != DBUS_VALID)
              return validity;

            if (_dbus_type_reader_next (&sub))
              return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;

            _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
          }
          break;

        case DBUS_TYPE_DICT_ENTRY:
        case DBUS_TYPE_STRUCT:
          {
            DBusTypeReader sub;
            DBusValidity validity;

            a = _DBUS_ALIGN_ADDRESS (p, 8);
            if (a > end)
              return DBUS_INVALID_NOT_ENOUGH_DATA;
            while (p != a)
              {
                if (*p != '\0')
                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                ++p;
              }

            _dbus_type_reader_recurse (reader, &sub);

            validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
            if (validity != DBUS_VALID)
              return validity;
          }
          break;

        default:
          _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
          break;
        }

#if 0
      _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
                     (int) (end - p));
#endif

      if (p > end)
        {
          _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
                         p, end, (int) (end - p));
          return DBUS_INVALID_NOT_ENOUGH_DATA;
        }

      if (walk_reader_to_end)
        _dbus_type_reader_next (reader);
      else
        break;
    }

  if (new_p)
    *new_p = p;

  return DBUS_VALID;
}
static void
byteswap_body_helper (DBusTypeReader       *reader,
                      dbus_bool_t           walk_reader_to_end,
                      int                   old_byte_order,
                      int                   new_byte_order,
                      unsigned char        *p,
                      unsigned char       **new_p)
{
  int current_type;

  while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
    {
      switch (current_type)
        {
        case DBUS_TYPE_BYTE:
          ++p;
          break;

        case DBUS_TYPE_INT16:
        case DBUS_TYPE_UINT16:
          {
            p = _DBUS_ALIGN_ADDRESS (p, 2);
            *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p));
            p += 2;
          }
          break;
          
        case DBUS_TYPE_BOOLEAN:
        case DBUS_TYPE_INT32:
        case DBUS_TYPE_UINT32:
          {
            p = _DBUS_ALIGN_ADDRESS (p, 4);
            *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p));
            p += 4;
          }
          break;
          
        case DBUS_TYPE_INT64:
        case DBUS_TYPE_UINT64:
        case DBUS_TYPE_DOUBLE:
          {
            p = _DBUS_ALIGN_ADDRESS (p, 8);
#ifdef DBUS_HAVE_INT64
            *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p));
#else
            _dbus_swap_array (p, 1, 8);
#endif
            p += 8;
          }
          break;

        case DBUS_TYPE_ARRAY:
        case DBUS_TYPE_STRING:
        case DBUS_TYPE_OBJECT_PATH:
          {
            dbus_uint32_t array_len;
            
            p = _DBUS_ALIGN_ADDRESS (p, 4);

            array_len = _dbus_unpack_uint32 (old_byte_order, p);

            *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p));
            p += 4;

            if (current_type == DBUS_TYPE_ARRAY)
              {
                int elem_type;
                int alignment;

                elem_type = _dbus_type_reader_get_element_type (reader);
                alignment = _dbus_type_get_alignment (elem_type);

		_dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH);

                p = _DBUS_ALIGN_ADDRESS (p, alignment);
                
                if (dbus_type_is_fixed (elem_type))
                  {
                    if (alignment > 1)
		      _dbus_swap_array (p, array_len / alignment, alignment);
		    p += array_len;
                  }
                else
                  {
                    DBusTypeReader sub;
                    const unsigned char *array_end;

                    array_end = p + array_len;
                    
                    _dbus_type_reader_recurse (reader, &sub);

                    while (p < array_end)
                      {
                        byteswap_body_helper (&sub,
                                              FALSE,
                                              old_byte_order,
                                              new_byte_order,
                                              p, &p);
                      }
                  }
              }
            else
              {
                _dbus_assert (current_type == DBUS_TYPE_STRING ||
                              current_type == DBUS_TYPE_OBJECT_PATH);
                
                p += (array_len + 1); /* + 1 for nul */
              }
          }
          break;

        case DBUS_TYPE_SIGNATURE:
          {
            dbus_uint32_t sig_len;

            sig_len = *p;
            
            p += (sig_len + 2); /* +2 for len and nul */
          }
          break;

        case DBUS_TYPE_VARIANT:
          {
            /* 1 byte sig len, sig typecodes, align to
             * contained-type-boundary, values.
             */
            dbus_uint32_t sig_len;
            DBusString sig;
            DBusTypeReader sub;
            int contained_alignment;

            sig_len = *p;
            ++p;

            _dbus_string_init_const_len (&sig, p, sig_len);

            p += (sig_len + 1); /* 1 for nul */

            contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0));
            
            p = _DBUS_ALIGN_ADDRESS (p, contained_alignment);

            _dbus_type_reader_init_types_only (&sub, &sig, 0);

            byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p);
          }
          break;

        case DBUS_TYPE_STRUCT:
        case DBUS_TYPE_DICT_ENTRY:
          {
            DBusTypeReader sub;

            p = _DBUS_ALIGN_ADDRESS (p, 8);
            
            _dbus_type_reader_recurse (reader, &sub);
            
            byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p);
          }
          break;

        case DBUS_TYPE_UNIX_FD:
          /* fds can only be passed on a local machine, so byte order must always match */
          _dbus_assert_not_reached("attempted to byteswap unix fds which makes no sense");
          break;

        default:
          _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
          break;
        }

      if (walk_reader_to_end)
        _dbus_type_reader_next (reader);
      else
        break;
    }

  if (new_p)
    *new_p = p;
}
/* note: this function is also used to validate the header's values,
 * since the header is a valid body with a particular signature.
 */
static DBusValidity
validate_body_helper (DBusTypeReader       *reader,
                      int                   byte_order,
                      dbus_bool_t           walk_reader_to_end,
                      int                   total_depth,
                      const unsigned char  *p,
                      const unsigned char  *end,
                      const unsigned char **new_p)
{
  int current_type;

  /* The spec allows arrays and structs to each nest 32, for total
   * nesting of 2*32. We want to impose the same limit on "dynamic"
   * value nesting (not visible in the signature) which is introduced
   * by DBUS_TYPE_VARIANT.
   */
  if (total_depth > (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH * 2))
    {
      return DBUS_INVALID_NESTED_TOO_DEEPLY;
    }

  while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
    {
      const unsigned char *a;
      int alignment;

#if 0
      _dbus_verbose ("   validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
                     (int) (end - p));
#endif

      /* Guarantee that p has one byte to look at */
      if (p == end)
        return DBUS_INVALID_NOT_ENOUGH_DATA;

      switch (current_type)
        {
        case DBUS_TYPE_BYTE:
          ++p;
          break;

        case DBUS_TYPE_BOOLEAN:
        case DBUS_TYPE_INT16:
        case DBUS_TYPE_UINT16:
        case DBUS_TYPE_INT32:
        case DBUS_TYPE_UINT32:
        case DBUS_TYPE_UNIX_FD:
        case DBUS_TYPE_INT64:
        case DBUS_TYPE_UINT64:
        case DBUS_TYPE_DOUBLE:
          alignment = _dbus_type_get_alignment (current_type);
          a = _DBUS_ALIGN_ADDRESS (p, alignment);
          if (a >= end)
            return DBUS_INVALID_NOT_ENOUGH_DATA;
          while (p != a)
            {
              if (*p != '\0')
                return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
              ++p;
            }
          
          if (current_type == DBUS_TYPE_BOOLEAN)
            {
              dbus_uint32_t v = _dbus_unpack_uint32 (byte_order,
                                                     p);
              if (!(v == 0 || v == 1))
                return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
            }
          
          p += alignment;
          break;

        case DBUS_TYPE_ARRAY:
        case DBUS_TYPE_STRING:
        case DBUS_TYPE_OBJECT_PATH:
          {
            dbus_uint32_t claimed_len;

            a = _DBUS_ALIGN_ADDRESS (p, 4);
            if (a + 4 > end)
              return DBUS_INVALID_NOT_ENOUGH_DATA;
            while (p != a)
              {
                if (*p != '\0')
                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                ++p;
              }

            claimed_len = _dbus_unpack_uint32 (byte_order, p);
            p += 4;

            /* p may now be == end */
            _dbus_assert (p <= end);

            if (current_type == DBUS_TYPE_ARRAY)
              {
                int array_elem_type = _dbus_type_reader_get_element_type (reader);

                if (!dbus_type_is_valid (array_elem_type))
                  {
                    return DBUS_INVALID_UNKNOWN_TYPECODE;
                  }

                alignment = _dbus_type_get_alignment (array_elem_type);

                a = _DBUS_ALIGN_ADDRESS (p, alignment);

                /* a may now be == end */
                if (a > end)
                  return DBUS_INVALID_NOT_ENOUGH_DATA;

                while (p != a)
                  {
                    if (*p != '\0')
                      return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                    ++p;
                  }
              }

            if (claimed_len > (unsigned long) (end - p))
              return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS;

            if (current_type == DBUS_TYPE_OBJECT_PATH)
              {
                DBusString str;
                _dbus_string_init_const_len (&str, (const char *) p, claimed_len);
                if (!_dbus_validate_path (&str, 0,
                                          _dbus_string_get_length (&str)))
                  return DBUS_INVALID_BAD_PATH;

                p += claimed_len;
              }
            else if (current_type == DBUS_TYPE_STRING)
              {
                DBusString str;
                _dbus_string_init_const_len (&str, (const char *) p, claimed_len);
                if (!_dbus_string_validate_utf8 (&str, 0,
                                                 _dbus_string_get_length (&str)))
                  return DBUS_INVALID_BAD_UTF8_IN_STRING;

                p += claimed_len;
              }
            else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0)
              {
                DBusTypeReader sub;
                DBusValidity validity;
                const unsigned char *array_end;
                int array_elem_type;

                if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH)
                  return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM;
                
                /* Remember that the reader is types only, so we can't
                 * use it to iterate over elements. It stays the same
                 * for all elements.
                 */
                _dbus_type_reader_recurse (reader, &sub);

                array_end = p + claimed_len;

                array_elem_type = _dbus_type_reader_get_element_type (reader);

                /* avoid recursive call to validate_body_helper if this is an array
                 * of fixed-size elements
                 */ 
                if (dbus_type_is_fixed (array_elem_type))
                  {
                    /* bools need to be handled differently, because they can
                     * have an invalid value
                     */
                    if (array_elem_type == DBUS_TYPE_BOOLEAN)
                      {
                        dbus_uint32_t v;
                        alignment = _dbus_type_get_alignment (array_elem_type);

                        while (p < array_end)
                          {
                            v = _dbus_unpack_uint32 (byte_order, p);

                            if (!(v == 0 || v == 1))
                              return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;

                            p += alignment;
                          }
                      }

                    else
                      {
                        p = array_end;
                      }
                  }

                else
                  {
                    while (p < array_end)
                      {
                        validity = validate_body_helper (&sub, byte_order, FALSE,
                                                         total_depth + 1,
                                                         p, end, &p);
                        if (validity != DBUS_VALID)
                          return validity;
                      }
                  }

                if (p != array_end)
                  return DBUS_INVALID_ARRAY_LENGTH_INCORRECT;
              }

            /* check nul termination */
            if (current_type != DBUS_TYPE_ARRAY)
              {
                if (p == end)
                  return DBUS_INVALID_NOT_ENOUGH_DATA;

                if (*p != '\0')
                  return DBUS_INVALID_STRING_MISSING_NUL;
                ++p;
              }
          }
          break;

        case DBUS_TYPE_SIGNATURE:
          {
            dbus_uint32_t claimed_len;
            DBusString str;
            DBusValidity validity;

            claimed_len = *p;
            ++p;

            /* 1 is for nul termination */
            if (claimed_len + 1 > (unsigned long) (end - p))
              return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS;

            _dbus_string_init_const_len (&str, (const char *) p, claimed_len);
            validity =
              _dbus_validate_signature_with_reason (&str, 0,
                                                    _dbus_string_get_length (&str));

            if (validity != DBUS_VALID)
              return validity;

            p += claimed_len;

            _dbus_assert (p < end);
            if (*p != DBUS_TYPE_INVALID)
              return DBUS_INVALID_SIGNATURE_MISSING_NUL;

            ++p;

            _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len);
          }
          break;

        case DBUS_TYPE_VARIANT:
          {
            /* 1 byte sig len, sig typecodes, align to
             * contained-type-boundary, values.
             */

            /* In addition to normal signature validation, we need to be sure
             * the signature contains only a single (possibly container) type.
             */
            dbus_uint32_t claimed_len;
            DBusString sig;
            DBusTypeReader sub;
            DBusValidity validity;
            int contained_alignment;
            int contained_type;
            DBusValidity reason;

            claimed_len = *p;
            ++p;

            /* + 1 for nul */
            if (claimed_len + 1 > (unsigned long) (end - p))
              return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS;

            _dbus_string_init_const_len (&sig, (const char *) p, claimed_len);
            reason = _dbus_validate_signature_with_reason (&sig, 0,
                                           _dbus_string_get_length (&sig));
            if (!(reason == DBUS_VALID))
              {
                if (reason == DBUS_VALIDITY_UNKNOWN_OOM_ERROR)
                  return reason;
                else 
                  return DBUS_INVALID_VARIANT_SIGNATURE_BAD;
              }

            p += claimed_len;
            
            if (*p != DBUS_TYPE_INVALID)
              return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL;
            ++p;

            contained_type = _dbus_first_type_in_signature (&sig, 0);
            if (contained_type == DBUS_TYPE_INVALID)
              return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY;
            
            contained_alignment = _dbus_type_get_alignment (contained_type);
            
            a = _DBUS_ALIGN_ADDRESS (p, contained_alignment);
            if (a > end)
              return DBUS_INVALID_NOT_ENOUGH_DATA;
            while (p != a)
              {
                if (*p != '\0')
                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                ++p;
              }

            _dbus_type_reader_init_types_only (&sub, &sig, 0);

            _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);

            validity = validate_body_helper (&sub, byte_order, FALSE,
                                             total_depth + 1,
                                             p, end, &p);
            if (validity != DBUS_VALID)
              return validity;

            if (_dbus_type_reader_next (&sub))
              return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES;

            _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID);
          }
          break;

        case DBUS_TYPE_DICT_ENTRY:
        case DBUS_TYPE_STRUCT:
          {
            DBusTypeReader sub;
            DBusValidity validity;

            a = _DBUS_ALIGN_ADDRESS (p, 8);
            if (a > end)
              return DBUS_INVALID_NOT_ENOUGH_DATA;
            while (p != a)
              {
                if (*p != '\0')
                  return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
                ++p;
              }

            _dbus_type_reader_recurse (reader, &sub);

            validity = validate_body_helper (&sub, byte_order, TRUE,
                                             total_depth + 1,
                                             p, end, &p);
            if (validity != DBUS_VALID)
              return validity;
          }
          break;

        default:
          _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
          break;
        }

#if 0
      _dbus_verbose ("   validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n",
                     _dbus_type_to_string (current_type), reader, reader->type_pos, p, end,
                     (int) (end - p));
#endif

      if (p > end)
        {
          _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n",
                         p, end, (int) (end - p));
          return DBUS_INVALID_NOT_ENOUGH_DATA;
        }

      if (walk_reader_to_end)
        _dbus_type_reader_next (reader);
      else
        break;
    }

  if (new_p)
    *new_p = p;

  return DBUS_VALID;
}