blob: cd9aa2cb5199303ba2128970c46669fa77a509f5 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_POLICY_ENROLLMENT_AUTO_ENROLLMENT_CONTROLLER_H_
#define CHROME_BROWSER_ASH_POLICY_ENROLLMENT_AUTO_ENROLLMENT_CONTROLLER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/callback_list.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_client.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.h"
#include "chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.h"
#include "chrome/browser/ash/policy/enrollment/psm/rlwe_dmserver_client_impl.h"
#include "chrome/browser/ash/settings/device_settings_service.h"
#include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace ash {
class SystemClockSyncObservation;
class InstallAttributesClient;
}
namespace policy {
// Helper class to obtain FWMP flags.
// See b/268267865.
class EnrollmentFwmpHelper {
public:
using ResultCallback = base::OnceCallback<void(bool)>;
// `install_attributes_client` has to be not nullptr. It will be used to
// obtain the FWMP flags.
explicit EnrollmentFwmpHelper(
ash::InstallAttributesClient* install_attributes_client);
EnrollmentFwmpHelper(const EnrollmentFwmpHelper&) = delete;
EnrollmentFwmpHelper& operator=(const EnrollmentFwmpHelper&) = delete;
~EnrollmentFwmpHelper();
// Read FWMP.dev_disable_boot (a.k.a. block_devmode) and return the
// value asynchronously via result_callback.
// Return `false` in case of errors (e.g. `install_attributes_client_` or
// FMWP not available).
void DetermineDevDisableBoot(ResultCallback result_callback);
private:
void RequestFirmwareManagementParameters(ResultCallback result_callback,
bool service_is_ready);
void OnGetFirmwareManagementParametersReceived(
ResultCallback result_callback,
absl::optional<user_data_auth::GetFirmwareManagementParametersReply>
reply);
raw_ptr<ash::InstallAttributesClient> install_attributes_client_;
base::WeakPtrFactory<EnrollmentFwmpHelper> weak_ptr_factory_{this};
};
// Drives the forced re-enrollment check (for historical reasons called
// auto-enrollment check), running an AutoEnrollmentClient if appropriate to
// make a decision.
class AutoEnrollmentController {
public:
using ProgressCallbackList =
base::RepeatingCallbackList<void(AutoEnrollmentState)>;
using RlweClientFactory =
policy::psm::RlweDmserverClientImpl::RlweClientFactory;
// State of the system clock.
enum class SystemClockSyncState {
// This `AutoEnrollmentController` has not tried to wait for the system
// clock sync state yet.
kCanWaitForSync,
// Currently waiting for the system clock to become synchronized.
kWaitingForSync,
// Waiting for the system clock to become synchronized timed out.
kSyncFailed,
// The system clock is synchronized
kSynchronized
};
AutoEnrollmentController();
AutoEnrollmentController(const AutoEnrollmentController&) = delete;
AutoEnrollmentController& operator=(const AutoEnrollmentController&) = delete;
~AutoEnrollmentController();
// Starts the auto-enrollment check. Safe to call multiple times: aborts in
// case a check is currently running or a decision has already been made.
void Start();
// Retry checking.
void Retry();
// Registers a callback to invoke on state changes.
base::CallbackListSubscription RegisterProgressCallback(
const ProgressCallbackList::CallbackType& callback);
AutoEnrollmentState state() const { return state_; }
// Returns the auto-enrollment check type performed by this client.
// The returned value will be `CheckType::kNone` before calling `Start()`.
AutoEnrollmentTypeChecker::CheckType auto_enrollment_check_type() const {
return auto_enrollment_check_type_;
}
// Sets the factory function that will be used to create the
// `psm::RlweClient` for tests.
void SetRlweClientFactoryForTesting(RlweClientFactory test_factory);
// Sets the factory that will be used to create the `AutoEnrollmentClient`.
// Ownership is not transferred when calling this - the caller must ensure
// that the `Factory` pointed to by `auto_enrollment_client_factory` remains
// valid while this `AutoEnrollmentController` is using it.
// To use the default factory again, call with nullptr.
void SetAutoEnrollmentClientFactoryForTesting(
AutoEnrollmentClient::Factory* auto_enrollment_client_factory);
// Sets factory that will be used to create `EnrollmentStateFetcher`. To use
// the default factory again, call with `base::NullCallback()`.
void SetEnrollmentStateFetcherFactoryForTesting(
EnrollmentStateFetcher::Factory enrollment_state_fetcher_factory);
// Returns safeguard timer. Used for testing
base::OneShotTimer& SafeguardTimerForTesting() { return safeguard_timer_; }
private:
void OnDevDisableBootDetermined(bool dev_disable_boot);
// Determines the FRE and Initial Enrollment requirement and starts initial
// enrollment if necessary. If Initial Enrollment would be skipped and the
// system clock has not been synchronized yet, triggers waiting for system
// clock sync and will be called again when the system clock state is known.
void StartWithSystemClockSyncState();
// Callback for the ownership status check.
void OnOwnershipStatusCheckDone(
ash::DeviceSettingsService::OwnershipStatus status);
// Starts the auto-enrollment client for forced re-enrollment.
void StartClientForFRE(const std::vector<std::string>& state_keys);
// Called when the system clock has been synchronized or a timeout has been
// reached while waiting for the system clock sync.
void OnSystemClockSyncResult(bool system_clock_synchronized);
// Starts the auto-enrollment client for initial enrollment.
void StartClientForInitialEnrollment();
// Sets `state_` and notifies `progress_callbacks_`.
void UpdateState(AutoEnrollmentState state);
// Clears everything that needs to be cleared at OOBE if
// the device gets the response that forced re-enrollment is not required.
// This currently removes firmware management parameters and sets
// block_devmode=0 and check_enrollment=0 in RW_VPD by making asynchronous
// calls to the respective D-Bus services.
// The notifications have to be sent only after the FWMP and VPD is cleared,
// because the user might try to switch to devmode. In this case, if
// block_devmode is in FWMP and the clear operation didn't finish, the switch
// would be denied. Also the safeguard timer has to be active until the FWMP
// is cleared to avoid the risk of blocked flow.
void StartCleanupForcedReEnrollment();
// Makes a D-Bus call to cryptohome to remove the firmware management
// parameters (FWMP) from TPM. Stops the `safeguard_timer_` and notifies the
// `progress_callbacks_` in case cryptohome does not become available and the
// timer is still running.
// `service_is_ready` indicates if the cryptohome D-Bus service is ready.
void StartRemoveFirmwareManagementParameters(bool service_is_ready);
// Callback for RemoveFirmwareManagementParameters(). If an error is received
// here, it is logged only, without changing the flow after that, because
// the FWMP is used only for newer devices.
// This also starts the VPD clearing process.
void OnFirmwareManagementParametersRemoved(
absl::optional<user_data_auth::RemoveFirmwareManagementParametersReply>
reply);
// Makes a D-Bus call to session_manager to set block_devmode=0 and
// check_enrollment=0 in RW_VPD. Stops the `safeguard_timer_` and notifies the
// `progress_callbacks_` in case session manager does not become available
// and the timer is still running.
// `service_is_ready` indicates if the session manager D-Bus service is ready.
void StartClearForcedReEnrollmentVpd(bool service_is_ready);
// Callback for ClearForcedReEnrollmentVpd(). If an error is received
// here, it is logged only, without changing the flow after that.
// This also notifies the `progress_callbacks_` since the forced re-enrollment
// cleanup is finished at this point.
void OnForcedReEnrollmentVpdCleared(bool reply);
// Handles timeout of the safeguard timer and stops waiting for a result.
void Timeout();
// Returns the factory that should be used to construct a new
// `AutoEnrollmentClient`.
AutoEnrollmentClient::Factory* GetAutoEnrollmentClientFactory();
// Returns the factory that should be used to construct a new
// `EnrollmentStateFetcher`.
EnrollmentStateFetcher::Factory CreateEnrollmentStateFetcherFactory();
EnrollmentFwmpHelper enrollment_fwmp_helper_;
// Unowned pointer. If not nullptr, this will be used to create the `client_`.
// It can be set using `SetAutoEnrollmentClientFactoryForTesting`.
raw_ptr<AutoEnrollmentClient::Factory, ExperimentalAsh>
testing_auto_enrollment_client_factory_ = nullptr;
// Constructs the PSM RLWE client. It will either create a fake or real
// implementation of the client.
// It is only used for PSM during creating the client for initial enrollment.
RlweClientFactory psm_rlwe_client_factory_;
AutoEnrollmentState state_ = AutoEnrollmentState::kIdle;
ProgressCallbackList progress_callbacks_;
std::unique_ptr<AutoEnrollmentClient> client_;
// This timer acts as a belt-and-suspenders safety for the case where one of
// the asynchronous steps required to make the auto-enrollment decision
// doesn't come back. Even though in theory they should all terminate, better
// safe than sorry: There are DBus interactions, an entire network stack etc.
// - just too many moving pieces to be confident there are no bugs. If
// something goes wrong, the timer will ensure that a decision gets made
// eventually, which is crucial to not block OOBE forever. See
// http://crbug.com/433634 for background.
base::OneShotTimer safeguard_timer_;
// Enrollment state fetcher. Invokes `UpdateState` on success or failure.
std::unique_ptr<EnrollmentStateFetcher> enrollment_state_fetcher_;
// Factory to create the `enrollment_state_fetcher_`. By default, it is set to
// `EnrollmentStateFetcher::Create`, but can be overridden with
// `SetEnrollmentStateFetcherFactoryForTesting`.
EnrollmentStateFetcher::Factory enrollment_state_fetcher_factory_;
bool dev_disable_boot_ = false;
// Which type of auto-enrollment check is being performed by this
// `AutoEnrollmentClient`.
AutoEnrollmentTypeChecker::CheckType auto_enrollment_check_type_ =
AutoEnrollmentTypeChecker::CheckType::kNone;
// Utility for waiting until the system clock has been synchronized.
std::unique_ptr<ash::SystemClockSyncObservation>
system_clock_sync_observation_;
// Current system clock sync state. This is only modified in
// `OnSystemClockSyncResult` after `system_clock_sync_wait_requested_` has
// been set to true.
SystemClockSyncState system_clock_sync_state_ =
SystemClockSyncState::kCanWaitForSync;
// Keeps track of number of tries to request state keys.
int request_state_keys_tries_ = 0;
// TODO(igorcov): Merge the two weak_ptr factories in one.
base::WeakPtrFactory<AutoEnrollmentController> client_start_weak_factory_{
this};
base::WeakPtrFactory<AutoEnrollmentController> weak_ptr_factory_{this};
};
} // namespace policy
#endif // CHROME_BROWSER_ASH_POLICY_ENROLLMENT_AUTO_ENROLLMENT_CONTROLLER_H_