| // Copyright 2015 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FIDES_SETTINGS_DOCUMENT_MANAGER_H_ |
| #define FIDES_SETTINGS_DOCUMENT_MANAGER_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <queue> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include <base/macros.h> |
| #include <base/observer_list.h> |
| |
| #include "fides/blob_ref.h" |
| #include "fides/blob_store.h" |
| #include "fides/settings_blob_parser.h" |
| #include "fides/settings_service.h" |
| #include "fides/source.h" |
| |
| namespace base { |
| class Value; |
| } // namespace base |
| |
| namespace fides { |
| |
| class SettingsDocument; |
| class SettingsMap; |
| |
| // SettingsDocumentManager maintains the set of currently installed settings |
| // documents and makes sure they are valid at all times. It checks document |
| // validity against the trust configuration, which is maintained (along with all |
| // other setting values in a SettingsMap). |
| // |
| // Whenever there is a change to trust configuration due to settings document |
| // insertion or removal in the SettingsMap, this SettingsDocumentManager |
| // resolves implications for existing settings documents. For example, inserting |
| // a document which changes a configuration source may invalidate existing |
| // settings documents generated by the affected source. Thus, settings documents |
| // depending on the modified source need to be re-validated. They'll get removed |
| // if validation fails in the updated trust configuration. |
| class SettingsDocumentManager : public SettingsService { |
| public: |
| // Indicates the result of a settings document insertion operation. |
| enum InsertionStatus { |
| kInsertionStatusSuccess, // Document inserted successfully. |
| kInsertionStatusVersionClash, // Source version already used. |
| kInsertionStatusCollision, // Collision with other document. |
| kInsertionStatusAccessViolation, // Document touches off-bounds keys. |
| kInsertionStatusParseError, // Failed to parse the blob. |
| kInsertionStatusValidationError, // Blob failed validation. |
| kInsertionStatusBadPayload, // Failed to decode blob payload. |
| kInsertionStatusStorageFailure, // Failed to write the blob to BlobStore. |
| kInsertionStatusUnknownSource, // Blob origin unknown. |
| }; |
| |
| // Constructs a new instance. The initial trust configuration must be passed |
| // in via |trusted_document|, which should be retrieved from a trusted source, |
| // such as a file from the OS image, protected by verified boot. |
| // |trusted_document| is typically used to allow the OS image to hard-code |
| // values for certain settings and to set up additional trusted configuration |
| // sources. |
| // |
| // WARNING: NEVER CALL THIS CONSTRUCTOR WITH A DOCUMENT RECEIVED FROM THE |
| // USER, NETWORK, UNTRUSTED STORAGE ETC. OR YOU WILL LOSE ALL END-TO-END |
| // SETTINGS AUTHENTICATION AFFORDED BY FIDES. |
| SettingsDocumentManager( |
| const SettingsBlobParserFunction& settings_blob_parser_function, |
| const SourceDelegateFactoryFunction& source_delegate_factory_function, |
| const std::string& storage_path, |
| std::unique_ptr<SettingsMap> settings_map, |
| std::unique_ptr<const SettingsDocument> trusted_document); |
| ~SettingsDocumentManager(); |
| |
| // Initializes the SettingsDocumentManager by inserting the trusted document |
| // into the SettingsMap and loading settings blobs for all known sources from |
| // disk. |
| void Init(); |
| |
| // SettingsService: |
| BlobRef GetValue(const Key& key) const override; |
| const std::set<Key> GetKeys(const Key& prefix) const override; |
| void AddSettingsObserver(SettingsObserver* observer) override; |
| void RemoveSettingsObserver(SettingsObserver* observer) override; |
| |
| // Decodes a binary settings blob and inserts the included settings document |
| // into the configuration. This runs the full set of validation against the |
| // settings blob, i.e. the blob gets validated against the source delegate |
| // (signature check etc.), it needs to have a valid non-conflicting version |
| // stamp, the source must have access to settings keys the document touches, |
| // etc. |
| // |
| // The return value indicates whether insertion was successful or hit an |
| // error. No settings changes will occur it the return value is not |
| // kInsertionStatusSuccess. |
| InsertionStatus InsertBlob(const std::string& source_id, BlobRef blob); |
| |
| private: |
| friend class SettingsDocumentManagerTest; |
| |
| // Keeps track of all known sources and their associated document entries. |
| struct SourceMapEntry { |
| explicit SourceMapEntry(const std::string& source_id); |
| ~SourceMapEntry(); |
| |
| // The current source configuration. This reflects the configuration |
| // specified in |settings_map_|. When the latter changes, the affected |
| // sources will get re-parsed. |
| Source source_; |
| |
| // All documents owned by the source and their respective handles, sorted |
| // according to |source_|'s version component in the document's version |
| // stamp. |
| std::vector<std::unique_ptr<const SettingsDocument>> documents_; |
| }; |
| |
| // Install a new settings document. The |document| must have |
| // |document->source_id_| and |document->handle_| filled in and is assumed to |
| // be fully validated against its source. The document gets inserted into |
| // |settings_map_|, and any trust configuration changes are processed and |
| // observers notified. |
| // |
| // The return value indicates whether the insertion succeeded or ran into an |
| // error. For return values other than kInsertionStatusSuccess no settings |
| // will be changed. |
| InsertionStatus InsertDocument( |
| std::unique_ptr<const SettingsDocument> document); |
| |
| // Finds the document in the corresponding SourceMapEntry, deletes the Blob |
| // associated with the document's handle in BlobStore and deletes the document |
| // from the SourceMapEntry. Returns true on success. Otherwise, returns false. |
| bool PurgeBlobAndDocument(const SettingsDocument* document); |
| |
| // Attempts to parse and validate a settings blob. On success, returns success |
| // status and populates |container| with the parsed and validated |
| // LockedSettingsContainer. On error, returns a status code indicating the |
| // failure mode. |
| SettingsDocumentManager::InsertionStatus ParseAndValidateBlob( |
| const Source* source, |
| BlobRef blob, |
| std::unique_ptr<LockedSettingsContainer>* container) const; |
| |
| // Revalidates a document, including trust configuration and signature checks. |
| // Returns true if the document is still valid against current trust |
| // configuration. |
| bool RevalidateDocument(const Source* source, |
| const SettingsDocument* doc) const; |
| |
| // Re-validate all documents belonging to a source. Documents that fail |
| // validation are removed from the SettingsMap, the SettingsDocument is |
| // deleted and the corresponding blob purged from the BlobStore. The keys that |
| // have changed due to the removal are added to |changed_keys| and the |
| // |sources_to_revalidate| queue is updated accordingly. |
| void RevalidateSourceDocuments( |
| const SourceMapEntry& entry, |
| std::set<Key>* changed_keys, |
| std::priority_queue<std::string>* sources_to_revalidate); |
| |
| // Updates trust configuration after |changed_keys| adjust their value. This |
| // re-parses all the source configurations affected by the change and |
| // re-verifies the settings documents belong to these sources. |
| // |
| // If any documents become invalid, they'll be removed. This may cascade to |
| // trigger further source changes. The process is guaranteed to terminate |
| // though as a source may only update trust configuration for lower-priority |
| // sources. |
| // |
| // The |changed_keys| set is updated to include any additional changes caused |
| // by cascading removals. |
| void UpdateTrustConfiguration(std::set<Key>* changed_keys); |
| |
| // Look up the source with the provided |source_id|. Returns |nullptr| if |
| // there's no such source. |
| const Source* FindSource(const std::string& source_id) const; |
| |
| // The parser used to decode binary settings blobs. |
| const SettingsBlobParserFunction settings_blob_parser_function_; |
| |
| // The source delegate factory. |
| const SourceDelegateFactoryFunction source_delegate_factory_function_; |
| |
| // The trusted document that bootstraps trust configuration. |
| std::unique_ptr<const SettingsDocument> trusted_document_; |
| |
| // The BlobStore responsible for storing, loading and enumerating settings |
| // blobs. |
| BlobStore blob_store_; |
| |
| // A map of all sources currently present, along with their documents. |
| std::map<std::string, SourceMapEntry> sources_; |
| |
| // The underlying settings map that tracks effective configuration. |
| std::unique_ptr<SettingsMap> settings_map_; |
| |
| base::ObserverList<SettingsObserver> observers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SettingsDocumentManager); |
| }; |
| |
| } // namespace fides |
| |
| #endif // FIDES_SETTINGS_DOCUMENT_MANAGER_H_ |