blob: 4e0c296d336ddcff92e80b3ec8c2f21b9e886960 [file] [log] [blame]
// 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_