dbus_bool_t _dbus_string_get_dirname (const DBusString *filename, DBusString *dirname) { int sep; _dbus_assert (filename != dirname); _dbus_assert (filename != NULL); _dbus_assert (dirname != NULL); /* Ignore any separators on the end */ sep = _dbus_string_get_length (filename); if (sep == 0) return _dbus_string_append (dirname, "."); /* empty string passed in */ while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') --sep; _dbus_assert (sep >= 0); if (sep == 0) return _dbus_string_append (dirname, "/"); /* Now find the previous separator */ _dbus_string_find_byte_backward (filename, sep, '/', &sep); if (sep < 0) return _dbus_string_append (dirname, "."); /* skip multiple separators */ while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') --sep; _dbus_assert (sep >= 0); if (sep == 0 && _dbus_string_get_byte (filename, 0) == '/') return _dbus_string_append (dirname, "/"); else return _dbus_string_copy_len (filename, 0, sep - 0, dirname, _dbus_string_get_length (dirname)); }
/** * Split paths into a list of char strings * * @param dirs string with pathes * @param suffix string concated to each path in dirs * @param dir_list contains a list of splitted pathes * return #TRUE is pathes could be splittes,#FALSE in oom case */ dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs, const char *suffix, DBusList **dir_list) { int start; int i; int len; char *cpath; DBusString file_suffix; start = 0; i = 0; _dbus_string_init_const (&file_suffix, suffix); len = _dbus_string_get_length (dirs); while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i)) { DBusString path; if (!_dbus_string_init (&path)) goto oom; if (!_dbus_string_copy_len (dirs, start, i - start, &path, 0)) { _dbus_string_free (&path); goto oom; } _dbus_string_chop_white (&path); /* check for an empty path */ if (_dbus_string_get_length (&path) == 0) goto next; if (!_dbus_concat_dir_and_file (&path, &file_suffix)) { _dbus_string_free (&path); goto oom; } if (!_dbus_string_copy_data(&path, &cpath)) { _dbus_string_free (&path); goto oom; } if (!_dbus_list_append (dir_list, cpath)) { _dbus_string_free (&path); dbus_free (cpath); goto oom; } next: _dbus_string_free (&path); start = i + 1; } if (start != len) { DBusString path; if (!_dbus_string_init (&path)) goto oom; if (!_dbus_string_copy_len (dirs, start, len - start, &path, 0)) { _dbus_string_free (&path); goto oom; } if (!_dbus_concat_dir_and_file (&path, &file_suffix)) { _dbus_string_free (&path); goto oom; } if (!_dbus_string_copy_data(&path, &cpath)) { _dbus_string_free (&path); goto oom; } if (!_dbus_list_append (dir_list, cpath)) { _dbus_string_free (&path); dbus_free (cpath); goto oom; } _dbus_string_free (&path); } return TRUE; oom: _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); _dbus_list_clear (dir_list); return FALSE; }
static dbus_bool_t parse_key_value (BusDesktopFileParser *parser, DBusError *error) { int line_end; int key_start, key_end; int value_start; int p; char *value, *tmp; DBusString key; BusDesktopFileLine *line; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_find (&parser->data, parser->pos, "\n", &line_end)) line_end = parser->len; p = parser->pos; key_start = p; while (p < line_end && (valid[_dbus_string_get_byte (&parser->data, p)] & VALID_KEY_CHAR)) p++; key_end = p; if (key_start == key_end) { report_error (parser, "Empty key name", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); parser_free (parser); return FALSE; } /* We ignore locales for now */ if (p < line_end && _dbus_string_get_byte (&parser->data, p) == '[') { if (line_end == parser->len) parser->pos = parser->len; else parser->pos = line_end + 1; parser->line_num += 1; return TRUE; } /* Skip space before '=' */ while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ') p++; if (p < line_end && _dbus_string_get_byte (&parser->data, p) != '=') { report_error (parser, "Invalid characters in key name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error); parser_free (parser); return FALSE; } if (p == line_end) { report_error (parser, "No '=' in key/value pair", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); parser_free (parser); return FALSE; } /* Skip the '=' */ p++; /* Skip space after '=' */ while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ') p++; value_start = p; value = unescape_string (parser, &parser->data, value_start, line_end, error); if (value == NULL) { parser_free (parser); return FALSE; } line = new_line (parser); if (line == NULL) { parser_free (parser); return FALSE; } if (!_dbus_string_init (&key)) { parser_free (parser); return FALSE; } if (!_dbus_string_copy_len (&parser->data, key_start, key_end - key_start, &key, 0)) { parser_free (parser); return FALSE; } if (!_dbus_string_steal_data (&key, &tmp)) { parser_free (parser); return FALSE; } _dbus_string_free (&key); line->key = tmp; line->value = value; if (line_end == parser->len) parser->pos = parser->len; else parser->pos = line_end + 1; parser->line_num += 1; return TRUE; }
/** * Creates a message header from potentially-untrusted data. The * return value is #TRUE if there was enough memory and the data was * valid. If it returns #TRUE, the header will be created. If it * returns #FALSE and *validity == #DBUS_VALIDITY_UNKNOWN_OOM_ERROR, * then there wasn't enough memory. If it returns #FALSE * and *validity != #DBUS_VALIDITY_UNKNOWN_OOM_ERROR then the data was * invalid. * * The byte_order, fields_array_len, and body_len args should be from * _dbus_header_have_message_untrusted(). Validation performed in * _dbus_header_have_message_untrusted() is assumed to have been * already done. * * @param header the header (must be initialized) * @param mode whether to do validation * @param validity return location for invalidity reason * @param byte_order byte order from header * @param fields_array_len claimed length of fields array * @param body_len claimed length of body * @param header_len claimed length of header * @param str a string * @param start start of header, 8-aligned * @param len length of string to look at * @returns #FALSE if no memory or data was invalid, #TRUE otherwise */ dbus_bool_t _dbus_header_load (DBusHeader *header, DBusValidationMode mode, DBusValidity *validity, int byte_order, int fields_array_len, int header_len, int body_len, const DBusString *str, int start, int len) { int leftover; DBusValidity v; DBusTypeReader reader; DBusTypeReader array_reader; unsigned char v_byte; dbus_uint32_t v_uint32; dbus_uint32_t serial; int padding_start; int padding_len; int i; _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); _dbus_assert (header_len <= len); _dbus_assert (_dbus_string_get_length (&header->data) == 0); if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0)) { _dbus_verbose ("Failed to copy buffer into new header\n"); *validity = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; return FALSE; } if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { leftover = len - header_len - body_len - start; } else { v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0, byte_order, &leftover, str, start, len); if (v != DBUS_VALID) { *validity = v; goto invalid; } } _dbus_assert (leftover < len); padding_len = header_len - (FIRST_FIELD_OFFSET + fields_array_len); padding_start = start + FIRST_FIELD_OFFSET + fields_array_len; _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8)); _dbus_assert (start + header_len == padding_start + padding_len); if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { if (!_dbus_string_validate_nul (str, padding_start, padding_len)) { *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; goto invalid; } } header->padding = padding_len; if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) { *validity = DBUS_VALID; return TRUE; } /* We now know the data is well-formed, but we have to check that * it's valid. */ _dbus_type_reader_init (&reader, byte_order, &_dbus_header_signature_str, 0, str, start); /* BYTE ORDER */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BYTE_ORDER_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); _dbus_assert (v_byte == byte_order); header->byte_order = byte_order; /* MESSAGE TYPE */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == TYPE_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); /* unknown message types are supposed to be ignored, so only validation here is * that it isn't invalid */ if (v_byte == DBUS_MESSAGE_TYPE_INVALID) { *validity = DBUS_INVALID_BAD_MESSAGE_TYPE; goto invalid; } /* FLAGS */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FLAGS_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); /* unknown flags should be ignored */ /* PROTOCOL VERSION */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == VERSION_OFFSET); _dbus_type_reader_read_basic (&reader, &v_byte); _dbus_type_reader_next (&reader); if (v_byte != DBUS_MAJOR_PROTOCOL_VERSION) { *validity = DBUS_INVALID_BAD_PROTOCOL_VERSION; goto invalid; } /* BODY LENGTH */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BODY_LENGTH_OFFSET); _dbus_type_reader_read_basic (&reader, &v_uint32); _dbus_type_reader_next (&reader); _dbus_assert (body_len == (signed) v_uint32); /* SERIAL */ _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == SERIAL_OFFSET); _dbus_type_reader_read_basic (&reader, &serial); _dbus_type_reader_next (&reader); if (serial == 0) { *validity = DBUS_INVALID_BAD_SERIAL; goto invalid; } _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_ARRAY); _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FIELDS_ARRAY_LENGTH_OFFSET); _dbus_type_reader_recurse (&reader, &array_reader); while (_dbus_type_reader_get_current_type (&array_reader) != DBUS_TYPE_INVALID) { DBusTypeReader struct_reader; DBusTypeReader variant_reader; unsigned char field_code; _dbus_assert (_dbus_type_reader_get_current_type (&array_reader) == DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (&array_reader, &struct_reader); _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_BYTE); _dbus_type_reader_read_basic (&struct_reader, &field_code); _dbus_type_reader_next (&struct_reader); if (field_code == DBUS_HEADER_FIELD_INVALID) { _dbus_verbose ("invalid header field code\n"); *validity = DBUS_INVALID_HEADER_FIELD_CODE; goto invalid; } if (field_code > DBUS_HEADER_FIELD_LAST) { _dbus_verbose ("unknown header field code %d, skipping\n", field_code); goto next_field; } _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_VARIANT); _dbus_type_reader_recurse (&struct_reader, &variant_reader); v = load_and_validate_field (header, field_code, &variant_reader); if (v != DBUS_VALID) { _dbus_verbose ("Field %d was invalid\n", field_code); *validity = v; goto invalid; } next_field: _dbus_type_reader_next (&array_reader); } /* Anything we didn't fill in is now known not to exist */ i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { if (header->fields[i].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; ++i; } v = check_mandatory_fields (header); if (v != DBUS_VALID) { _dbus_verbose ("Mandatory fields were missing, code %d\n", v); *validity = v; goto invalid; } *validity = DBUS_VALID; return TRUE; invalid: _dbus_string_set_length (&header->data, 0); return FALSE; }