*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+#include <config.h>
#include "dbus-internals.h"
#include "dbus-marshal-validate.h"
#include "dbus-marshal-recursive.h"
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:
}
}
- if (last == DBUS_DICT_ENTRY_BEGIN_CHAR &&
- !dbus_type_is_basic (*p))
+ if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
{
- result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
- goto out;
+ if (!(dbus_type_is_valid (*p) && dbus_type_is_basic (*p)))
+ {
+ result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
+ goto out;
+ }
}
-
+
last = *p;
++p;
}
return result;
}
+/* 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;
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:
/* 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);
- p = _DBUS_ALIGN_ADDRESS (p, alignment);
+
+ 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))
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;
array_end = p + claimed_len;
- while (p < array_end)
+ 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
{
- /* 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;
+ 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)
_dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);
- validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
+ validity = validate_body_helper (&sub, byte_order, FALSE,
+ total_depth + 1,
+ p, end, &p);
if (validity != DBUS_VALID)
return validity;
_dbus_type_reader_recurse (reader, &sub);
- validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
+ validity = validate_body_helper (&sub, byte_order, TRUE,
+ total_depth + 1,
+ p, end, &p);
if (validity != DBUS_VALID)
return validity;
}
p = _dbus_string_get_const_data_len (value_str, value_pos, len);
end = p + len;
- validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
+ validity = validate_body_helper (&reader, byte_order, TRUE, 0, p, end, &p);
if (validity != DBUS_VALID)
return validity;
return TRUE;
}
+const char *
+_dbus_validity_to_error_message (DBusValidity validity)
+{
+ switch (validity)
+ {
+ case DBUS_VALIDITY_UNKNOWN_OOM_ERROR: return "Out of memory";
+ case DBUS_INVALID_FOR_UNKNOWN_REASON: return "Unknown reason";
+ case DBUS_VALID_BUT_INCOMPLETE: return "Valid but incomplete";
+ case DBUS_VALIDITY_UNKNOWN: return "Validity unknown";
+ case DBUS_VALID: return "Valid";
+ case DBUS_INVALID_UNKNOWN_TYPECODE: return "Unknown typecode";
+ case DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE: return "Missing array element type";
+ case DBUS_INVALID_SIGNATURE_TOO_LONG: return "Signature is too long";
+ case DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION: return "Exceeded maximum array recursion";
+ case DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION: return "Exceeded maximum struct recursion";
+ case DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED: return "Struct ended but not started";
+ case DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED: return "Struct started but not ended";
+ case DBUS_INVALID_STRUCT_HAS_NO_FIELDS: return "Struct has no fields";
+ case DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL: return "Alignment padding not null";
+ case DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE: return "Boolean is not zero or one";
+ case DBUS_INVALID_NOT_ENOUGH_DATA: return "Not enough data";
+ case DBUS_INVALID_TOO_MUCH_DATA: return "Too much data";
+ case DBUS_INVALID_BAD_BYTE_ORDER: return "Bad byte order";
+ case DBUS_INVALID_BAD_PROTOCOL_VERSION: return "Bad protocol version";
+ case DBUS_INVALID_BAD_MESSAGE_TYPE: return "Bad message type";
+ case DBUS_INVALID_BAD_SERIAL: return "Bad serial";
+ case DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH: return "Insane fields array length";
+ case DBUS_INVALID_INSANE_BODY_LENGTH: return "Insane body length";
+ case DBUS_INVALID_MESSAGE_TOO_LONG: return "Message too long";
+ case DBUS_INVALID_HEADER_FIELD_CODE: return "Header field code";
+ case DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE: return "Header field has wrong type";
+ case DBUS_INVALID_USES_LOCAL_INTERFACE: return "Uses local interface";
+ case DBUS_INVALID_USES_LOCAL_PATH: return "Uses local path";
+ case DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE: return "Header field appears twice";
+ case DBUS_INVALID_BAD_DESTINATION: return "Bad destination";
+ case DBUS_INVALID_BAD_INTERFACE: return "Bad interface";
+ case DBUS_INVALID_BAD_MEMBER: return "Bad member";
+ case DBUS_INVALID_BAD_ERROR_NAME: return "Bad error name";
+ case DBUS_INVALID_BAD_SENDER: return "Bad sender";
+ case DBUS_INVALID_MISSING_PATH: return "Missing path";
+ case DBUS_INVALID_MISSING_INTERFACE: return "Missing interface";
+ case DBUS_INVALID_MISSING_MEMBER: return "Missing member";
+ case DBUS_INVALID_MISSING_ERROR_NAME: return "Missing error name";
+ case DBUS_INVALID_MISSING_REPLY_SERIAL: return "Missing reply serial";
+ case DBUS_INVALID_LENGTH_OUT_OF_BOUNDS: return "Length out of bounds";
+ case DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM: return "Array length exceeds maximum";
+ case DBUS_INVALID_BAD_PATH: return "Bad path";
+ case DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS: return "Signature length out of bounds";
+ case DBUS_INVALID_BAD_UTF8_IN_STRING: return "Bad utf8 in string";
+ case DBUS_INVALID_ARRAY_LENGTH_INCORRECT: return "Array length incorrect";
+ case DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS: return "Variant signature length out of bounds";
+ case DBUS_INVALID_VARIANT_SIGNATURE_BAD: return "Variant signature bad";
+ case DBUS_INVALID_VARIANT_SIGNATURE_EMPTY: return "Variant signature empty";
+ case DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES: return "Variant signature specifies multiple values";
+ case DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL: return "Variant signature missing nul";
+ case DBUS_INVALID_STRING_MISSING_NUL: return "String missing nul";
+ case DBUS_INVALID_SIGNATURE_MISSING_NUL: return "Signature missing nul";
+ case DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION: return "Exceeded maximum dict entry recursion";
+ case DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED: return "Dict entry ended but not started";
+ case DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED: return "Dict entry started but not ended";
+ case DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS: return "Dict entry has no fields";
+ case DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD: return "Dict entry has only one field";
+ case DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS: return "Dict entry has too many fields";
+ case DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY: return "Dict entry not inside array";
+ case DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE: return "Dict key must be basic type";
+ case DBUS_INVALID_NESTED_TOO_DEEPLY: return "Variants cannot be used to create a hugely recursive tree of values";
+ default:
+ return "Invalid";
+ }
+}
+
/**
* Checks that the given range of the string is a valid interface name
* in the D-Bus protocol. This includes a length restriction and an
((c) >= 'a' && (c) <= 'z') || \
((c) == '_') || ((c) == '-'))
-/**
- * Checks that the given range of the string is a valid bus name in
- * the D-Bus protocol. This includes a length restriction, etc., see
- * the specification.
- *
- * @todo this is inconsistent with most of DBusString in that
- * it allows a start,len range that extends past the string end.
- *
- * @param str the string
- * @param start first byte index to check
- * @param len number of bytes to check
- * @returns #TRUE if the byte range exists and is a valid name
- */
-dbus_bool_t
-_dbus_validate_bus_name (const DBusString *str,
- int start,
- int len)
+static dbus_bool_t
+_dbus_validate_bus_name_full (const DBusString *str,
+ int start,
+ int len,
+ dbus_bool_t is_namespace)
{
const unsigned char *s;
const unsigned char *end;
++s;
}
- if (_DBUS_UNLIKELY (last_dot == NULL))
+ if (!is_namespace && _DBUS_UNLIKELY (last_dot == NULL))
return FALSE;
return TRUE;
}
/**
+ * Checks that the given range of the string is a valid bus name in
+ * the D-Bus protocol. This includes a length restriction, etc., see
+ * the specification.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that extends past the string end.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_validate_bus_name (const DBusString *str,
+ int start,
+ int len)
+{
+ return _dbus_validate_bus_name_full (str, start, len, FALSE);
+}
+
+/**
+ * Checks that the given range of the string is a prefix of a valid bus name in
+ * the D-Bus protocol. Unlike _dbus_validate_bus_name(), this accepts strings
+ * with only one period-separated component.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that extends past the string end.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_validate_bus_namespace (const DBusString *str,
+ int start,
+ int len)
+{
+ return _dbus_validate_bus_name_full (str, start, len, TRUE);
+}
+
+/**
* Checks that the given range of the string is a valid message type
* signature in the D-Bus protocol.
*
DEFINE_DBUS_NAME_CHECK(bus_name)
/** define _dbus_check_is_valid_signature() */
DEFINE_DBUS_NAME_CHECK(signature)
+/** define _dbus_check_is_valid_utf8() */
+DEFINE_DBUS_NAME_CHECK(utf8)
/** @} */