/** * Parses an unsigned integer contained in a DBusString. Either return * parameter may be #NULL if you aren't interested in it. The integer * is parsed and stored in value_return. Return parameters are not * initialized if the function returns #FALSE. * * @param str the string * @param start the byte index of the start of the integer * @param value_return return location of the integer value or #NULL * @param end_return return location of the end of the integer, or #NULL * @returns #TRUE on success */ dbus_bool_t _dbus_string_parse_uint (const DBusString *str, int start, unsigned long *value_return, int *end_return) { unsigned long v; const char *p; char *end; p = _dbus_string_get_const_data_len (str, start, _dbus_string_get_length (str) - start); end = NULL; _dbus_set_errno_to_zero (); v = strtoul (p, &end, 0); if (end == NULL || end == p || errno != 0) return FALSE; if (value_return) *value_return = v; if (end_return) *end_return = start + (end - p); return TRUE; }
/** * Parses a floating point number contained in a DBusString. Either * return parameter may be #NULL if you aren't interested in it. The * integer is parsed and stored in value_return. Return parameters are * not initialized if the function returns #FALSE. * * @param str the string * @param start the byte index of the start of the float * @param value_return return location of the float value or #NULL * @param end_return return location of the end of the float, or #NULL * @returns #TRUE on success */ dbus_bool_t _dbus_string_parse_double (const DBusString *str, int start, double *value_return, int *end_return) { double v; const char *p; char *end; p = _dbus_string_get_const_data_len (str, start, _dbus_string_get_length (str) - start); /* parsing hex works on linux but isn't portable, so intercept it * here to get uniform behavior. */ if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) return FALSE; end = NULL; errno = 0; v = ascii_strtod (p, &end); if (end == NULL || end == p || errno != 0) return FALSE; if (value_return) *value_return = v; if (end_return) *end_return = start + (end - p); return TRUE; }
/** * Verifies that the range of value_str from value_pos to value_end is * a legitimate value of type expected_signature. If this function * returns #TRUE, it will be safe to iterate over the values with * #DBusTypeReader. The signature is assumed to be already valid. * * If bytes_remaining is not #NULL, then leftover bytes will be stored * there and #DBUS_VALID returned. If it is #NULL, then * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left * over. * * @param expected_signature the expected types in the value_str * @param expected_signature_start where in expected_signature is the signature * @param byte_order the byte order * @param bytes_remaining place to store leftover bytes * @param value_str the string containing the body * @param value_pos where the values start * @param len length of values after value_pos * @returns #DBUS_VALID if valid, reason why invalid otherwise */ DBusValidity _dbus_validate_body_with_reason (const DBusString *expected_signature, int expected_signature_start, int byte_order, int *bytes_remaining, const DBusString *value_str, int value_pos, int len) { DBusTypeReader reader; const unsigned char *p; const unsigned char *end; DBusValidity validity; _dbus_assert (len >= 0); _dbus_assert (value_pos >= 0); _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len); _dbus_verbose ("validating body from pos %d len %d sig '%s'\n", value_pos, len, _dbus_string_get_const_data_len (expected_signature, expected_signature_start, 0)); _dbus_type_reader_init_types_only (&reader, expected_signature, expected_signature_start); 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); if (validity != DBUS_VALID) return validity; if (bytes_remaining) { *bytes_remaining = end - p; return DBUS_VALID; } else if (p < end) return DBUS_INVALID_TOO_MUCH_DATA; else { _dbus_assert (p == end); return DBUS_VALID; } }
/** * Gets a message flag bit, returning TRUE if the bit is set. * * @param header the header * @param flag the message flag to get * @returns #TRUE if the flag is set */ dbus_bool_t _dbus_header_get_flag (DBusHeader *header, dbus_uint32_t flag) { const unsigned char *flags_p; flags_p = _dbus_string_get_const_data_len (&header->data, FLAGS_OFFSET, 1); return (*flags_p & flag) != 0; }
/** * Verifies that the range of type_str from type_pos to type_end is a * valid signature. If this function returns #TRUE, it will be safe * to iterate over the signature with a types-only #DBusTypeReader. * The range passed in should NOT include the terminating * nul/DBUS_TYPE_INVALID. * * @param type_str the string * @param type_pos where the typecodes start * @param len length of typecodes * @returns #DBUS_VALID if valid, reason why invalid otherwise */ DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str, int type_pos, int len) { const unsigned char *p; const unsigned char *end; int last; int struct_depth; int array_depth; int dict_entry_depth; DBusValidity result; int element_count; DBusList *element_count_stack; result = DBUS_VALID; element_count_stack = NULL; if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } _dbus_assert (type_str != NULL); _dbus_assert (type_pos < _DBUS_INT32_MAX - len); _dbus_assert (len >= 0); _dbus_assert (type_pos >= 0); if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH) { result = DBUS_INVALID_SIGNATURE_TOO_LONG; goto out; } p = _dbus_string_get_const_data_len (type_str, type_pos, 0); end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0); struct_depth = 0; array_depth = 0; dict_entry_depth = 0; last = DBUS_TYPE_INVALID; while (p != end) { switch (*p) { case DBUS_TYPE_BYTE: 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: case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_SIGNATURE: case DBUS_TYPE_VARIANT: break; case DBUS_TYPE_ARRAY: array_depth += 1; if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) { result = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; goto out; } break; case DBUS_STRUCT_BEGIN_CHAR: struct_depth += 1; if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) { result = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; goto out; } if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } break; case DBUS_STRUCT_END_CHAR: if (struct_depth == 0) { result = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; goto out; } if (last == DBUS_STRUCT_BEGIN_CHAR) { result = DBUS_INVALID_STRUCT_HAS_NO_FIELDS; goto out; } _dbus_list_pop_last (&element_count_stack); struct_depth -= 1; break; case DBUS_DICT_ENTRY_BEGIN_CHAR: if (last != DBUS_TYPE_ARRAY) { result = DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY; goto out; } dict_entry_depth += 1; if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) { result = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION; goto out; } if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } break; case DBUS_DICT_ENTRY_END_CHAR: if (dict_entry_depth == 0) { result = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED; goto out; } dict_entry_depth -= 1; element_count = _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack)); if (element_count != 2) { if (element_count == 0) result = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS; else if (element_count == 1) result = DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD; else result = DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS; goto out; } break; case DBUS_TYPE_STRUCT: /* doesn't appear in signatures */ case DBUS_TYPE_DICT_ENTRY: /* ditto */ default: result = DBUS_INVALID_UNKNOWN_TYPECODE; goto out; } if (*p != DBUS_TYPE_ARRAY && *p != DBUS_DICT_ENTRY_BEGIN_CHAR && *p != DBUS_STRUCT_BEGIN_CHAR) { element_count = _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack)); ++element_count; if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (element_count))) { result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; goto out; } } if (array_depth > 0) { if (*p == DBUS_TYPE_ARRAY && p != end) { const char *p1; p1 = p + 1; if (*p1 == DBUS_STRUCT_END_CHAR || *p1 == DBUS_DICT_ENTRY_END_CHAR) { result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; goto out; } } else { array_depth = 0; } } if (last == DBUS_DICT_ENTRY_BEGIN_CHAR && !dbus_type_is_basic (*p)) { result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE; goto out; } last = *p; ++p; } if (array_depth > 0) { result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; goto out; } if (struct_depth > 0) { result = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; goto out; } if (dict_entry_depth > 0) { result = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED; goto out; } _dbus_assert (last != DBUS_TYPE_ARRAY); _dbus_assert (last != DBUS_STRUCT_BEGIN_CHAR); _dbus_assert (last != DBUS_DICT_ENTRY_BEGIN_CHAR); result = DBUS_VALID; out: _dbus_list_clear (&element_count_stack); return result; }