| // Copyright 2021 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef DLP_DLP_ADAPTOR_H_ | |
| #define DLP_DLP_ADAPTOR_H_ | |
| #include <map> | |
| #include <memory> | |
| #include <set> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <base/containers/flat_set.h> | |
| #include <base/files/file_descriptor_watcher_posix.h> | |
| #include <base/files/scoped_file.h> | |
| #include <base/functional/callback.h> | |
| #include <base/task/single_thread_task_runner.h> | |
| #include <base/threading/thread.h> | |
| #include <base/memory/weak_ptr.h> | |
| #include <brillo/dbus/async_event_sequencer.h> | |
| #include <featured/feature_library.h> | |
| #include <metrics/metrics_library.h> | |
| #include "dlp/dbus-proxies.h" | |
| #include "dlp/dlp_database.h" | |
| #include "dlp/dlp_metrics.h" | |
| #include "dlp/dlp_requests_cache.h" | |
| #include "dlp/fanotify_watcher.h" | |
| #include "dlp/file_id.h" | |
| #include "dlp/org.chromium.Dlp.h" | |
| #include "dlp/proto_bindings/dlp_service.pb.h" | |
| namespace brillo { | |
| namespace dbus_utils { | |
| class DBusObject; | |
| } // namespace dbus_utils | |
| } // namespace brillo | |
| namespace dlp { | |
| class DlpAdaptor : public org::chromium::DlpAdaptor, | |
| public org::chromium::DlpInterface, | |
| public FanotifyWatcher::Delegate, | |
| public DlpDatabase::Delegate { | |
| public: | |
| DlpAdaptor(std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object, | |
| feature::PlatformFeaturesInterface* feature_lib, | |
| int fanotify_perm_fd, | |
| int fanotify_notif_fd, | |
| const base::FilePath& home_path); | |
| DlpAdaptor(const DlpAdaptor&) = delete; | |
| DlpAdaptor& operator=(const DlpAdaptor&) = delete; | |
| virtual ~DlpAdaptor(); | |
| // Opens the database |db_| to store files sources, |init_callback| called | |
| // after the database is set. | |
| void InitDatabase(const base::FilePath& database_path, | |
| base::OnceClosure init_callback); | |
| // Registers the D-Bus object and interfaces. | |
| void RegisterAsync(brillo::dbus_utils::AsyncEventSequencer::CompletionAction | |
| completion_callback); | |
| // org::chromium::DlpInterface: (see org.chromium.Dlp.xml). | |
| std::vector<uint8_t> SetDlpFilesPolicy( | |
| const std::vector<uint8_t>& request_blob) override; | |
| void AddFiles(std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| const std::vector<uint8_t>& request_blob) override; | |
| void RequestFileAccess( | |
| std::unique_ptr< | |
| brillo::dbus_utils::DBusMethodResponse<std::vector<uint8_t>, | |
| base::ScopedFD>> response, | |
| const std::vector<uint8_t>& request_blob) override; | |
| void GetFilesSources(std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| const std::vector<uint8_t>& request_blob) override; | |
| void CheckFilesTransfer( | |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| const std::vector<uint8_t>& request_blob) override; | |
| void GetDatabaseEntries( | |
| std::unique_ptr< | |
| brillo::dbus_utils::DBusMethodResponse<std::vector<uint8_t>>> | |
| response) override; | |
| void SetFanotifyWatcherStartedForTesting(bool is_started); | |
| void CloseDatabaseForTesting(); | |
| void SetMetricsLibraryForTesting( | |
| std::unique_ptr<MetricsLibraryInterface> metrics_lib); | |
| private: | |
| friend class DlpAdaptorTestHelper; | |
| // Callback on InitDatabase after initialization of the database. | |
| void OnDatabaseInitialized(base::OnceClosure init_callback, | |
| std::unique_ptr<DlpDatabase> db, | |
| const base::FilePath& database_path, | |
| std::pair<int, bool> db_status); | |
| // Callback on UpsertFileEntries during OnDatabaseInitialized. | |
| void OnPendingFilesUpserted(base::OnceClosure init_callback, | |
| std::unique_ptr<DlpDatabase> db, | |
| const base::FilePath& database_path, | |
| std::pair<int, bool> db_status, | |
| bool success); | |
| // Initializes |fanotify_watcher_| if not yet started. | |
| void EnsureFanotifyWatcherStarted(); | |
| // FanotifyWatcher::Delegate overrides: | |
| void ProcessFileOpenRequest(FileId id, | |
| int pid, | |
| base::OnceCallback<void(bool)> callback) override; | |
| void OnFileDeleted(ino64_t inode) override; | |
| void OnFanotifyError(FanotifyError error) override; | |
| // DlpDatabase::Delegate overrides: | |
| void OnDatabaseError(DatabaseError error) override; | |
| // Callback on ProcessFileOpenRequest after getting data from database. | |
| void ProcessFileOpenRequestWithData(int pid, | |
| base::OnceCallback<void(bool)> callback, | |
| std::map<FileId, FileEntry> file_entry); | |
| // Callbacks on DlpPolicyMatched D-Bus request for ProcessFileOpenRequest. | |
| void OnDlpPolicyMatched(base::OnceCallback<void(bool)> callback, | |
| const std::vector<uint8_t>& response_blob); | |
| void OnDlpPolicyMatchedError(base::OnceCallback<void(bool)> callback, | |
| brillo::Error* error); | |
| // Callback for RequestFileAccess after getting data from the database. | |
| void ProcessRequestFileAccessWithData( | |
| std::unique_ptr< | |
| brillo::dbus_utils::DBusMethodResponse<std::vector<uint8_t>, | |
| base::ScopedFD>> response, | |
| RequestFileAccessRequest request, | |
| base::ScopedFD local_fd, | |
| base::ScopedFD remote_fd, | |
| std::map<FileId, FileEntry> file_entries); | |
| using RequestFileAccessCallback = | |
| base::OnceCallback<void(bool, const std::string&)>; | |
| // Callbacks on IsFilesTransferRestricted D-Bus request for RequestFileAccess. | |
| void OnRequestFileAccess( | |
| std::vector<FileId> ids, | |
| std::vector<FileId> granted_ids, | |
| int pid, | |
| base::ScopedFD local_fd, | |
| RequestFileAccessCallback callback, | |
| base::OnceCallback<void(IsFilesTransferRestrictedResponse)> | |
| cache_callback, | |
| const std::vector<uint8_t>& response_blob); | |
| void OnRequestFileAccessError(RequestFileAccessCallback callback, | |
| brillo::Error* error); | |
| void ReplyOnRequestFileAccess( | |
| std::unique_ptr< | |
| brillo::dbus_utils::DBusMethodResponse<std::vector<uint8_t>, | |
| base::ScopedFD>> response, | |
| base::ScopedFD remote_fd, | |
| bool allowed, | |
| const std::string& error_message); | |
| // Callback on AddFiles after adding to the database. | |
| void OnFilesUpserted(std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| std::vector<base::FilePath> files_paths, | |
| std::vector<FileId> files_ids, | |
| bool success); | |
| // Helper to reply on AddFiles request. | |
| void ReplyOnAddFiles(std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| std::string error_messages); | |
| // Callback for CheckFilesTransfer after getting data from the database. | |
| void ProcessCheckFilesTransferWithData( | |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| CheckFilesTransferRequest request, | |
| std::map<FileId, FileEntry> file_entries); | |
| using CheckFilesTransferCallback = | |
| base::OnceCallback<void(std::vector<std::string>, const std::string&)>; | |
| // Callback on IsFilesTransferRestricted D-Bus request for CheckFilesTransfer. | |
| void OnIsFilesTransferRestricted( | |
| base::flat_set<std::string> transferred_files, | |
| std::vector<std::string> restricted_files, | |
| CheckFilesTransferCallback callback, | |
| base::OnceCallback<void(IsFilesTransferRestrictedResponse)> | |
| cache_callback, | |
| const std::vector<uint8_t>& response_blob); | |
| void OnIsFilesTransferRestrictedError(CheckFilesTransferCallback callback, | |
| brillo::Error* error); | |
| void ReplyOnCheckFilesTransfer( | |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| std::vector<std::string> restricted_files_paths, | |
| const std::string& error); | |
| // Callback on GetFilesSources after getting data from database. | |
| void ProcessGetFilesSourcesWithData( | |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| const std::vector<std::pair<FileId, std::string>>& requested_files, | |
| std::map<FileId, FileEntry> file_entries); | |
| // Functions and callbacks to handle lifeline fd. | |
| int AddLifelineFd(int dbus_fd); | |
| bool DeleteLifelineFd(int fd); | |
| void OnLifelineFdClosed(int fd); | |
| // Removes entries from |db| that are not present in |ids| and sets the | |
| // used database to |db|. |callback| is called if this successfully finishes. | |
| void CleanupAndSetDatabase( | |
| std::unique_ptr<DlpDatabase> db, | |
| base::OnceClosure callback, | |
| const std::set<std::pair<base::FilePath, FileId>>& ids); | |
| // Requests fanotify to add per-file watch (FAN_DELETE_SELF event) for each | |
| // of the provided files if they exist in the database. | |
| void AddPerFileWatch( | |
| const std::set<std::pair<base::FilePath, FileId>>& files); | |
| // Callback on AddPerFileWatch after recieving the list of tracked files. | |
| void ProcessAddPerFileWatchWithData( | |
| const std::set<std::pair<base::FilePath, FileId>>& files, | |
| std::map<FileId, FileEntry> file_entries); | |
| // Callback on CleanupAndSetDatabase after removing data from database. | |
| void OnDatabaseCleaned(std::unique_ptr<DlpDatabase> db, | |
| base::OnceClosure callback, | |
| bool success); | |
| // Runs migration of the database from old entries without crtime to the new | |
| // database with crtime. The crtime data is populated based on |files| data. | |
| void MigrateDatabase( | |
| std::unique_ptr<DlpDatabase> db, | |
| base::OnceClosure callback, | |
| const base::FilePath& database_path, | |
| const std::set<std::pair<base::FilePath, FileId>>& files); | |
| // Callback on MigratedDatabase called from the database after migration. | |
| void OnDatabaseMigrated(std::unique_ptr<DlpDatabase> db, | |
| base::OnceClosure init_callback, | |
| const base::FilePath& database_path, | |
| bool success); | |
| // Callback on GetDatabaseEntries after getting data from database. | |
| void ProcessGetDatabaseEntriesWithData( | |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse< | |
| std::vector<uint8_t>>> response, | |
| std::map<FileId, FileEntry> files_entries); | |
| // If true, DlpAdaptor won't try to initialise `fanotify_watcher_`. | |
| bool is_fanotify_watcher_started_for_testing_ = false; | |
| // Can be nullptr if failed to initialize or closed during a test. | |
| std::unique_ptr<DlpDatabase> db_; | |
| std::vector<DlpFilesRule> policy_rules_; | |
| std::unique_ptr<FanotifyWatcher> fanotify_watcher_; | |
| std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object_; | |
| feature::PlatformFeaturesInterface* feature_lib_ = nullptr; | |
| // Cache of IsFilesTransferRestricted replies from Chrome. | |
| DlpRequestsCache requests_cache_; | |
| // The root path to the watched directory. | |
| const base::FilePath home_path_; | |
| std::unique_ptr<org::chromium::DlpFilesPolicyServiceProxy> | |
| dlp_files_policy_service_; | |
| std::unique_ptr<DlpMetrics> dlp_metrics_; | |
| // Map holding the currently approved access requests. | |
| // Maps from the lifeline fd to a pair of list of files ids and pid. | |
| std::map<int, std::pair<std::vector<FileId>, int>> approved_requests_; | |
| // Map holding watchers for lifeline fd corresponding currently approved | |
| // requests. Maps from the lifeline fd to the watcher. | |
| std::map<int, std::unique_ptr<base::FileDescriptorWatcher::Controller>> | |
| lifeline_fd_controllers_; | |
| // Indicated whether adding per file watch for files in the database is | |
| // pending creation of the database. | |
| bool pending_per_file_watches_ = false; | |
| // Files that were added before database was initialized, so they need to be | |
| // added once it's ready. | |
| std::vector<FileEntry> pending_files_to_add_; | |
| // For long-running file enumeration tasks. | |
| base::Thread file_enumeration_thread_; | |
| scoped_refptr<base::SingleThreadTaskRunner> file_enumeration_task_runner_; | |
| // Declared last so weak pointers are invalidated first on destruction. | |
| base::WeakPtrFactory<DlpAdaptor> weak_factory_{this}; | |
| }; | |
| } // namespace dlp | |
| #endif // DLP_DLP_ADAPTOR_H_ |