Commit a12b78ab authored by Pavol Marko's avatar Pavol Marko Committed by Commit Bot

Perform initial enrollment check for Chrome OS

If FRE is not performed, and initial enrollment is enabled according to
command line flags and device state, performs initial enrollment check.
Specifically, the initial enrollment check is done if all of the
following conditions are true:
- the device was not enterprise enrolled or in consumer mode before
  (according to the check_enrollment VPD variable)
- the RLZ embargo date has passed
  (to ensure not to do initial enrollment exchanges on the factory floor)
- Initial enrollment is enabled usinga  command-line switch
- serial number and RLZ brand code are available.

Bug: 839353
Change-Id: I259c06a5e5274f3bdef54ccc0161e6f642f9499f
Reviewed-on: https://chromium-review.googlesource.com/1052707Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarRoger Tawa <rogerta@chromium.org>
Reviewed-by: default avatarMaksim Ivanov <emaxx@chromium.org>
Commit-Queue: Pavol Marko <pmarko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558797}
parent acb53bd0
...@@ -76,9 +76,7 @@ void AutoEnrollmentCheckScreen::ClearState() { ...@@ -76,9 +76,7 @@ void AutoEnrollmentCheckScreen::ClearState() {
void AutoEnrollmentCheckScreen::Show() { void AutoEnrollmentCheckScreen::Show() {
// If the decision got made already, don't show the screen at all. // If the decision got made already, don't show the screen at all.
if (AutoEnrollmentController::GetMode() != if (!AutoEnrollmentController::IsEnabled() || IsCompleted()) {
AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT ||
IsCompleted()) {
SignalCompletion(); SignalCompletion();
return; return;
} }
...@@ -210,7 +208,7 @@ bool AutoEnrollmentCheckScreen::UpdateAutoEnrollmentState( ...@@ -210,7 +208,7 @@ bool AutoEnrollmentCheckScreen::UpdateAutoEnrollmentState(
return false; return false;
case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR: case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR:
if (auto_enrollment_controller_->GetFRERequirement() != if (auto_enrollment_controller_->GetFRERequirement() !=
AutoEnrollmentController::EXPLICITLY_REQUIRED) { AutoEnrollmentController::FRERequirement::kExplicitlyRequired) {
return false; return false;
} }
// Fall to the same behavior like any connection error if the device is // Fall to the same behavior like any connection error if the device is
...@@ -265,7 +263,7 @@ bool AutoEnrollmentCheckScreen::IsCompleted() const { ...@@ -265,7 +263,7 @@ bool AutoEnrollmentCheckScreen::IsCompleted() const {
case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR: case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR:
// Server errors should block OOBE for enrolled devices. // Server errors should block OOBE for enrolled devices.
return auto_enrollment_controller_->GetFRERequirement() != return auto_enrollment_controller_->GetFRERequirement() !=
AutoEnrollmentController::EXPLICITLY_REQUIRED; AutoEnrollmentController::FRERequirement::kExplicitlyRequired;
case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT: case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ZERO_TOUCH: case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ZERO_TOUCH:
case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT: case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
......
...@@ -17,6 +17,10 @@ ...@@ -17,6 +17,10 @@
#include "chrome/browser/chromeos/policy/auto_enrollment_client.h" #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/chromeos/settings/device_settings_service.h"
namespace base {
class CommandLine;
}
namespace cryptohome { namespace cryptohome {
class BaseReply; class BaseReply;
} // namespace cryptohome } // namespace cryptohome
...@@ -36,33 +40,55 @@ class AutoEnrollmentController { ...@@ -36,33 +40,55 @@ class AutoEnrollmentController {
static const char kForcedReEnrollmentNever[]; static const char kForcedReEnrollmentNever[];
static const char kForcedReEnrollmentOfficialBuild[]; static const char kForcedReEnrollmentOfficialBuild[];
// Auto-enrollment modes. // Parameter values for the kEnterpriseEnableInitialEnrollment flag.
enum Mode { static const char kInitialEnrollmentAlways[];
// No automatic enrollment. static const char kInitialEnrollmentNever[];
MODE_NONE, static const char kInitialEnrollmentOfficialBuild[];
// Forced re-enrollment.
MODE_FORCED_RE_ENROLLMENT,
};
// Requirement for forced re-enrollment check. // Requirement for forced re-enrollment check.
enum FRERequirement { enum class FRERequirement {
// The device was setup (has kActivateDateKey) but doesn't have the // The device was setup (has kActivateDateKey) but doesn't have the
// kCheckEnrollmentKey entry in VPD, or the VPD is corrupted. // kCheckEnrollmentKey entry in VPD, or the VPD is corrupted.
REQUIRED, kRequired,
// The device doesn't have kActivateDateKey, nor kCheckEnrollmentKey entry // The device doesn't have kActivateDateKey, nor kCheckEnrollmentKey entry
// while the serial number has been successfully read from VPD. // while the serial number has been successfully read from VPD.
NOT_REQUIRED, kNotRequired,
// FRE check explicitly required by the flag in VPD. // FRE check explicitly required by the flag in VPD.
EXPLICITLY_REQUIRED, kExplicitlyRequired,
// FRE check to be skipped, explicitly stated by the flag in VPD. // FRE check to be skipped, explicitly stated by the flag in VPD.
EXPLICITLY_NOT_REQUIRED, kExplicitlyNotRequired,
};
// Requirement for initial enrollment check.
enum class InitialEnrollmentRequirement {
// Initial enrollment check is not required.
kNotRequired,
// Initial enrollment check is required.
kRequired
}; };
// Gets the auto-enrollment mode based on command-line flags and official // Type of auto enrollment check.
// build status. enum class AutoEnrollmentCheckType {
static Mode GetMode(); kNone,
// Forced Re-Enrollment check.
kFRE,
// Initial enrollment check.
kInitialEnrollment
};
// Returns true if forced re-enrollment is enabled based on command-line flags
// and official build status.
static bool IsFREEnabled();
// Returns true if initial enrollment is enabled based on command-line
// flags and official build status.
static bool IsInitialEnrollmentEnabled();
// Returns whether the auto-enrollment check is required. When // Returns true if any auto enrollment check is enabled based on command-line
// flags and official build status.
static bool IsEnabled();
// Returns whether the FRE auto-enrollment check is required. When
// kCheckEnrollmentKey VPD entry is present, it is explicitly stating whether // kCheckEnrollmentKey VPD entry is present, it is explicitly stating whether
// the forced re-enrollment is required or not. Otherwise, for backward // the forced re-enrollment is required or not. Otherwise, for backward
// compatibility with devices upgrading from an older version of Chrome OS, // compatibility with devices upgrading from an older version of Chrome OS,
...@@ -74,6 +100,15 @@ class AutoEnrollmentController { ...@@ -74,6 +100,15 @@ class AutoEnrollmentController {
// is required. // is required.
static FRERequirement GetFRERequirement(); static FRERequirement GetFRERequirement();
// Returns whether the initial enrollment check is required.
static InitialEnrollmentRequirement GetInitialEnrollmentRequirement();
// Returns the type of auto-enrollment check performed by this client. This
// will be |AutoEnrollmentCheckType::kNone| before |Start()| has been called.
AutoEnrollmentCheckType auto_enrollment_check_type() const {
return auto_enrollment_check_type_;
}
AutoEnrollmentController(); AutoEnrollmentController();
~AutoEnrollmentController(); ~AutoEnrollmentController();
...@@ -91,12 +126,27 @@ class AutoEnrollmentController { ...@@ -91,12 +126,27 @@ class AutoEnrollmentController {
policy::AutoEnrollmentState state() const { return state_; } policy::AutoEnrollmentState state() const { return state_; }
private: private:
// Determines the type of auto-enrollment check that should be done. Sets
// |auto_enrollment_check_type_| and |fre_requirement_|.
void DetermineAutoEnrollmentCheckType();
// Returns true if the FRE check should be done according to command-line
// switches and device state.
static bool ShouldDoFRECheck(base::CommandLine* command_line,
FRERequirement fre_requirement);
// Returns true if the Initial Enrollment check should be done according to
// command-line switches and device state.
static bool ShouldDoInitialEnrollmentCheck();
// Callback for the ownership status check. // Callback for the ownership status check.
void OnOwnershipStatusCheckDone( void OnOwnershipStatusCheckDone(
DeviceSettingsService::OwnershipStatus status); DeviceSettingsService::OwnershipStatus status);
// Starts the auto-enrollment client. // Starts the auto-enrollment client for forced re-enrollment.
void StartClient(const std::vector<std::string>& state_keys); void StartClientForFRE(const std::vector<std::string>& state_keys);
// Starts the auto-enrollment client for initial enrollment.
void StartClientForInitialEnrollment();
// Sets |state_| and notifies |progress_callbacks_|. // Sets |state_| and notifies |progress_callbacks_|.
void UpdateState(policy::AutoEnrollmentState state); void UpdateState(policy::AutoEnrollmentState state);
...@@ -136,7 +186,12 @@ class AutoEnrollmentController { ...@@ -136,7 +186,12 @@ class AutoEnrollmentController {
base::Timer safeguard_timer_{false, false}; base::Timer safeguard_timer_{false, false};
// Whether the forced re-enrollment check has to be applied. // Whether the forced re-enrollment check has to be applied.
FRERequirement fre_requirement_ = REQUIRED; FRERequirement fre_requirement_ = FRERequirement::kRequired;
// Which type of auto-enrollment check is being performed by this
// |AutoEnrollmentClient|.
AutoEnrollmentCheckType auto_enrollment_check_type_ =
AutoEnrollmentCheckType::kNone;
// TODO(igorcov): Merge the two weak_ptr factories in one. // TODO(igorcov): Merge the two weak_ptr factories in one.
base::WeakPtrFactory<AutoEnrollmentController> client_start_weak_factory_{ base::WeakPtrFactory<AutoEnrollmentController> client_start_weak_factory_{
......
...@@ -100,8 +100,7 @@ bool GetMachineFlag(const std::string& key, bool default_value) { ...@@ -100,8 +100,7 @@ bool GetMachineFlag(const std::string& key, bool default_value) {
// Checks whether forced re-enrollment is enabled. // Checks whether forced re-enrollment is enabled.
bool ForcedReEnrollmentEnabled() { bool ForcedReEnrollmentEnabled() {
return chromeos::AutoEnrollmentController::GetMode() == return chromeos::AutoEnrollmentController::IsFREEnabled();
chromeos::AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT;
} }
} // namespace } // namespace
......
...@@ -344,8 +344,7 @@ void EnrollmentHandlerChromeOS::HandleStateKeysResult( ...@@ -344,8 +344,7 @@ void EnrollmentHandlerChromeOS::HandleStateKeysResult(
DCHECK_EQ(STEP_STATE_KEYS, enrollment_step_); DCHECK_EQ(STEP_STATE_KEYS, enrollment_step_);
// Make sure state keys are available if forced re-enrollment is on. // Make sure state keys are available if forced re-enrollment is on.
if (chromeos::AutoEnrollmentController::GetMode() == if (chromeos::AutoEnrollmentController::IsFREEnabled()) {
chromeos::AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT) {
client_->SetStateKeysToUpload(state_keys); client_->SetStateKeysToUpload(state_keys);
current_state_key_ = state_keys_broker_->current_state_key(); current_state_key_ = state_keys_broker_->current_state_key();
if (state_keys.empty() || current_state_key_.empty()) { if (state_keys.empty() || current_state_key_.empty()) {
......
...@@ -40,16 +40,15 @@ ServerBackedStateKeysBroker::RegisterUpdateCallback( ...@@ -40,16 +40,15 @@ ServerBackedStateKeysBroker::RegisterUpdateCallback(
return update_callbacks_.Add(callback); return update_callbacks_.Add(callback);
} }
void ServerBackedStateKeysBroker::RequestStateKeys( void ServerBackedStateKeysBroker::RequestStateKeys(StateKeysCallback callback) {
const StateKeysCallback& callback) {
if (pending()) { if (pending()) {
request_callbacks_.push_back(callback); request_callbacks_.push_back(std::move(callback));
FetchStateKeys(); FetchStateKeys();
return; return;
} }
if (!callback.is_null()) if (!callback.is_null())
callback.Run(state_keys_); std::move(callback).Run(state_keys_);
return; return;
} }
...@@ -87,12 +86,9 @@ void ServerBackedStateKeysBroker::StoreStateKeys( ...@@ -87,12 +86,9 @@ void ServerBackedStateKeysBroker::StoreStateKeys(
std::vector<StateKeysCallback> callbacks; std::vector<StateKeysCallback> callbacks;
request_callbacks_.swap(callbacks); request_callbacks_.swap(callbacks);
for (std::vector<StateKeysCallback>::const_iterator callback( for (auto& callback : callbacks) {
callbacks.begin()); if (!callback.is_null())
callback != callbacks.end(); std::move(callback).Run(state_keys_);
++callback) {
if (!callback->is_null())
callback->Run(state_keys_);
} }
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
......
...@@ -27,7 +27,7 @@ class ServerBackedStateKeysBroker { ...@@ -27,7 +27,7 @@ class ServerBackedStateKeysBroker {
public: public:
typedef std::unique_ptr<base::CallbackList<void()>::Subscription> typedef std::unique_ptr<base::CallbackList<void()>::Subscription>
Subscription; Subscription;
typedef base::Callback<void(const std::vector<std::string>&)> typedef base::OnceCallback<void(const std::vector<std::string>&)>
StateKeysCallback; StateKeysCallback;
ServerBackedStateKeysBroker( ServerBackedStateKeysBroker(
...@@ -46,7 +46,7 @@ class ServerBackedStateKeysBroker { ...@@ -46,7 +46,7 @@ class ServerBackedStateKeysBroker {
// empty. If |this| gets destroyed before the callback happens or if the time // empty. If |this| gets destroyed before the callback happens or if the time
// sync fails / the network is not established, then the |callback| is never // sync fails / the network is not established, then the |callback| is never
// invoked. See http://crbug.com/649422 for more context. // invoked. See http://crbug.com/649422 for more context.
void RequestStateKeys(const StateKeysCallback& callback); void RequestStateKeys(StateKeysCallback callback);
static base::TimeDelta GetPollIntervalForTesting(); static base::TimeDelta GetPollIntervalForTesting();
......
...@@ -215,7 +215,8 @@ void ShouldOfferUpdateViaPowerwash( ...@@ -215,7 +215,8 @@ void ShouldOfferUpdateViaPowerwash(
// get enrolled and the admin allows TPM firmware update via powerwash. // get enrolled and the admin allows TPM firmware update via powerwash.
const AutoEnrollmentController::FRERequirement requirement = const AutoEnrollmentController::FRERequirement requirement =
AutoEnrollmentController::GetFRERequirement(); AutoEnrollmentController::GetFRERequirement();
if (requirement == AutoEnrollmentController::EXPLICITLY_REQUIRED) { if (requirement ==
AutoEnrollmentController::FRERequirement::kExplicitlyRequired) {
callback.Run(false); callback.Run(false);
return; return;
} }
......
...@@ -407,7 +407,8 @@ void CoreOobeHandler::HandleToggleResetScreen() { ...@@ -407,7 +407,8 @@ void CoreOobeHandler::HandleToggleResetScreen() {
// effect of dropping the FRE requirement if it was previously in effect. // effect of dropping the FRE requirement if it was previously in effect.
const AutoEnrollmentController::FRERequirement requirement = const AutoEnrollmentController::FRERequirement requirement =
AutoEnrollmentController::GetFRERequirement(); AutoEnrollmentController::GetFRERequirement();
if (requirement != AutoEnrollmentController::EXPLICITLY_REQUIRED) { if (requirement !=
AutoEnrollmentController::FRERequirement::kExplicitlyRequired) {
LaunchResetScreen(); LaunchResetScreen();
} }
} }
......
...@@ -392,6 +392,10 @@ const char kEnterpriseDisableLicenseTypeSelection[] = ...@@ -392,6 +392,10 @@ const char kEnterpriseDisableLicenseTypeSelection[] =
const char kEnterpriseEnableForcedReEnrollment[] = const char kEnterpriseEnableForcedReEnrollment[] =
"enterprise-enable-forced-re-enrollment"; "enterprise-enable-forced-re-enrollment";
// Whether to enable initial enterprise enrollment.
const char kEnterpriseEnableInitialEnrollment[] =
"enterprise-enable-initial-enrollment";
// Enables the zero-touch enterprise enrollment flow. // Enables the zero-touch enterprise enrollment flow.
const char kEnterpriseEnableZeroTouchEnrollment[] = const char kEnterpriseEnableZeroTouchEnrollment[] =
"enterprise-enable-zero-touch-enrollment"; "enterprise-enable-zero-touch-enrollment";
......
...@@ -115,6 +115,7 @@ CHROMEOS_EXPORT extern const char kEnableZipArchiverUnpacker[]; ...@@ -115,6 +115,7 @@ CHROMEOS_EXPORT extern const char kEnableZipArchiverUnpacker[];
CHROMEOS_EXPORT extern const char kEnterpriseDisableArc[]; CHROMEOS_EXPORT extern const char kEnterpriseDisableArc[];
CHROMEOS_EXPORT extern const char kEnterpriseDisableLicenseTypeSelection[]; CHROMEOS_EXPORT extern const char kEnterpriseDisableLicenseTypeSelection[];
CHROMEOS_EXPORT extern const char kEnterpriseEnableForcedReEnrollment[]; CHROMEOS_EXPORT extern const char kEnterpriseEnableForcedReEnrollment[];
CHROMEOS_EXPORT extern const char kEnterpriseEnableInitialEnrollment[];
CHROMEOS_EXPORT extern const char kEnterpriseEnableZeroTouchEnrollment[]; CHROMEOS_EXPORT extern const char kEnterpriseEnableZeroTouchEnrollment[];
CHROMEOS_EXPORT extern const char kEnterpriseEnrollmentInitialModulus[]; CHROMEOS_EXPORT extern const char kEnterpriseEnrollmentInitialModulus[];
CHROMEOS_EXPORT extern const char kEnterpriseEnrollmentModulusLimit[]; CHROMEOS_EXPORT extern const char kEnterpriseEnrollmentModulusLimit[];
......
...@@ -84,38 +84,6 @@ std::string GetKeyName(const std::string& key, Product product) { ...@@ -84,38 +84,6 @@ std::string GetKeyName(const std::string& key, Product product) {
return key + "." + GetProductName(product) + "." + brand; return key + "." + GetProductName(product) + "." + brand;
} }
// Returns true if the |rlz_embargo_end_date| present in VPD has passed
// compared to the current time.
bool HasRlzEmbargoEndDatePassed() {
chromeos::system::StatisticsProvider* stats =
chromeos::system::StatisticsProvider::GetInstance();
std::string rlz_embargo_end_date;
if (!stats->GetMachineStatistic(chromeos::system::kRlzEmbargoEndDateKey,
&rlz_embargo_end_date)) {
// |rlz_embargo_end_date| only exists on new devices that have not yet
// launched. When the field doesn't exist, returns true so it's a no-op.
return true;
}
base::Time parsed_time;
if (!base::Time::FromUTCString(rlz_embargo_end_date.c_str(), &parsed_time)) {
LOG(ERROR) << "|rlz_embargo_end_date| exists but cannot be parsed.";
return true;
}
if (parsed_time - base::Time::Now() >=
base::TimeDelta::FromDays(
RlzValueStoreChromeOS::kRlzEmbargoEndDateGarbageDateThresholdDays)) {
// If |rlz_embargo_end_date| is more than this many days in the future,
// ignore it. Because it indicates that the device is not connected to an
// ntp server in the factory, and its internal clock could be off when the
// date is written.
return true;
}
return base::Time::Now() > parsed_time;
}
} // namespace } // namespace
const int RlzValueStoreChromeOS::kRlzEmbargoEndDateGarbageDateThresholdDays = const int RlzValueStoreChromeOS::kRlzEmbargoEndDateGarbageDateThresholdDays =
...@@ -323,6 +291,45 @@ void RlzValueStoreChromeOS::CollectGarbage() { ...@@ -323,6 +291,45 @@ void RlzValueStoreChromeOS::CollectGarbage() {
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
// static
RlzValueStoreChromeOS::EmbargoState
RlzValueStoreChromeOS::GetRlzEmbargoState() {
chromeos::system::StatisticsProvider* stats =
chromeos::system::StatisticsProvider::GetInstance();
std::string rlz_embargo_end_date;
if (!stats->GetMachineStatistic(chromeos::system::kRlzEmbargoEndDateKey,
&rlz_embargo_end_date)) {
// |rlz_embargo_end_date| only exists on new devices that have not yet
// launched.
return EmbargoState::kMissingOrMalformed;
}
base::Time parsed_time;
if (!base::Time::FromUTCString(rlz_embargo_end_date.c_str(), &parsed_time)) {
LOG(ERROR) << "|rlz_embargo_end_date| exists but cannot be parsed.";
return EmbargoState::kMissingOrMalformed;
}
if (parsed_time - base::Time::Now() >=
base::TimeDelta::FromDays(
RlzValueStoreChromeOS::kRlzEmbargoEndDateGarbageDateThresholdDays)) {
// If |rlz_embargo_end_date| is more than this many days in the future,
// ignore it. Because it indicates that the device is not connected to an
// ntp server in the factory, and its internal clock could be off when the
// date is written.
// TODO(pmarko): UMA stat for how often this happens.
return EmbargoState::kInvalid;
}
return base::Time::Now() > parsed_time ? EmbargoState::kPassed
: EmbargoState::kNotPassed;
}
// static
bool RlzValueStoreChromeOS::HasRlzEmbargoEndDatePassed() {
return GetRlzEmbargoState() != EmbargoState::kNotPassed;
}
void RlzValueStoreChromeOS::ReadStore() { void RlzValueStoreChromeOS::ReadStore() {
int error_code = 0; int error_code = 0;
std::string error_msg; std::string error_msg;
......
...@@ -63,7 +63,20 @@ class RlzValueStoreChromeOS : public RlzValueStore { ...@@ -63,7 +63,20 @@ class RlzValueStoreChromeOS : public RlzValueStore {
void CollectGarbage() override; void CollectGarbage() override;
enum class EmbargoState {
kMissingOrMalformed,
kInvalid,
kNotPassed,
kPassed
};
static EmbargoState GetRlzEmbargoState();
private: private:
// Returns true if the |rlz_embargo_end_date| present in VPD has passed
// compared to the current time.
static bool HasRlzEmbargoEndDatePassed();
// Reads RLZ store from file. // Reads RLZ store from file.
void ReadStore(); void ReadStore();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment