// 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.
#include "chrome/browser/ash/system/device_disabling_manager.h"
#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/ash/login/existing_user_controller.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/server_backed_state/server_backed_device_state.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/common/pref_names.h"
#include "chromeos/ash/components/install_attributes/install_attributes.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "chromeos/ash/components/settings/cros_settings_provider.h"
#include "chromeos/ash/components/system/statistics_provider.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
namespace ash {
namespace system {
DeviceDisablingManager::Observer::~Observer() = default;
DeviceDisablingManager::Delegate::~Delegate() = default;
DeviceDisablingManager::DeviceDisablingManager(
Delegate* delegate,
CrosSettings* cros_settings,
user_manager::UserManager* user_manager)
: delegate_(delegate),
browser_policy_connector_(
g_browser_process->platform_part()->browser_policy_connector_ash()),
cros_settings_(cros_settings),
user_manager_(user_manager),
device_disabled_(false) {
CHECK(delegate_);
}
DeviceDisablingManager::~DeviceDisablingManager() = default;
void DeviceDisablingManager::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void DeviceDisablingManager::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void DeviceDisablingManager::Init() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableDeviceDisabling)) {
// If device disabling is turned off by flags, do not start monitoring cros
// settings.
return;
}
device_disabled_subscription_ = cros_settings_->AddSettingsObserver(
kDeviceDisabled,
base::BindRepeating(&DeviceDisablingManager::UpdateFromCrosSettings,
weak_factory_.GetWeakPtr()));
disabled_message_subscription_ = cros_settings_->AddSettingsObserver(
kDeviceDisabledMessage,
base::BindRepeating(&DeviceDisablingManager::UpdateFromCrosSettings,
weak_factory_.GetWeakPtr()));
UpdateFromCrosSettings();
}
void DeviceDisablingManager::CacheDisabledMessageAndNotify(
const std::string& disabled_message) {
if (disabled_message == disabled_message_)
return;
disabled_message_ = disabled_message;
for (auto& observer : observers_)
observer.OnDisabledMessageChanged(disabled_message_);
}
void DeviceDisablingManager::CheckWhetherDeviceDisabledDuringOOBE(
DeviceDisabledCheckCallback callback) {
if (policy::GetDeviceStateMode() != policy::RESTORE_MODE_DISABLED ||
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableDeviceDisabling)) {
// Indicate that the device is not disabled if it is not marked as such in
// local state or device disabling has been turned off by flag.
std::move(callback).Run(false);
return;
}
if (browser_policy_connector_->GetDeviceMode() ==
policy::DEVICE_MODE_PENDING) {
// If the device mode is not known yet, request to be called back once it
// becomes known.
browser_policy_connector_->GetInstallAttributes()->ReadImmutableAttributes(
base::BindOnce(
&DeviceDisablingManager::CheckWhetherDeviceDisabledDuringOOBE,
weak_factory_.GetWeakPtr(), std::move(callback)));
return;
}
if (browser_policy_connector_->GetDeviceMode() !=
policy::DEVICE_MODE_NOT_SET) {
// If the device is owned already, this method must have been called after
// OOBE, which is an error. Indicate that the device is not disabled to
// prevent spurious disabling. Actual device disabling after OOBE will be
// handled elsewhere, by checking for disabled state in cros settings.
LOG(ERROR) << "CheckWhetherDeviceDisabledDuringOOBE() called after OOBE.";
std::move(callback).Run(false);
return;
}
// The device is marked as disabled in local state (based on the device state
// retrieved early during OOBE). Since device disabling has not been turned
// off by flag and the device is still unowned, we honor the information in
// local state and consider the device disabled.
// Update the enrollment domain.
enrollment_domain_.clear();
const std::string* maybe_enrollment_domain =
g_browser_process->local_state()
->GetDict(prefs::kServerBackedDeviceState)
.FindString(policy::kDeviceStateManagementDomain);
enrollment_domain_ =
maybe_enrollment_domain ? *maybe_enrollment_domain : std::string();
// Update the serial number.
serial_number_ = std::string(
StatisticsProvider::GetInstance()->GetMachineID().value_or(""));
// Update the disabled message.
const std::string* maybe_disabled_message =
g_browser_process->local_state()
->GetDict(prefs::kServerBackedDeviceState)
.FindString(policy::kDeviceStateDisabledMessage);
std::string disabled_message =
maybe_disabled_message ? *maybe_disabled_message : std::string();
CacheDisabledMessageAndNotify(disabled_message);
// Indicate that the device is disabled.
std::move(callback).Run(true);
}
// static
bool DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation() {
if (!HonorDeviceDisablingDuringNormalOperation()) {
return false;
}
bool device_disabled = false;
CrosSettings::Get()->GetBoolean(kDeviceDisabled, &device_disabled);
return device_disabled;
}
// static
bool DeviceDisablingManager::HonorDeviceDisablingDuringNormalOperation() {
// Device disabling should be honored when the device is enterprise managed
// and device disabling has not been turned off by flag.
return g_browser_process->platform_part()
->browser_policy_connector_ash()
->IsDeviceEnterpriseManaged() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableDeviceDisabling);
}
void DeviceDisablingManager::UpdateFromCrosSettings() {
if (cros_settings_->PrepareTrustedValues(base::BindOnce(
&DeviceDisablingManager::UpdateFromCrosSettings,
weak_factory_.GetWeakPtr())) != CrosSettingsProvider::TRUSTED) {
// If the cros settings are not trusted yet, request to be called back
// later.
return;
}
if (!IsDeviceDisabledDuringNormalOperation()) {
// The device should not be disabled because: (a) device is not enterprise
// managed, (b) device disabling has been turned off by flag, or (c)
// cros settings indicates that device should not be disabled.
if (!device_disabled_) {
// If the device is currently not disabled, there is nothing to do.
return;
}
// Re-enable the device.
device_disabled_ = false;
// The device was disabled and has been re-enabled. Normal function should
// be resumed. Since the device disabled screen abruptly interrupts the
// regular login screen flows, Chrome should be restarted to return to a
// well-defined state.
delegate_->RestartToLoginScreen();
return;
}
// Update the disabled message.
std::string disabled_message;
cros_settings_->GetString(kDeviceDisabledMessage, &disabled_message);
CacheDisabledMessageAndNotify(disabled_message);
if (device_disabled_) {
// If the device was disabled already, updating the disabled message is the
// only action required.
return;
}
device_disabled_ = true;
const ExistingUserController* existing_user_controller =
ExistingUserController::current_controller();
if (user_manager_->GetActiveUser() ||
(existing_user_controller &&
existing_user_controller->IsSigninInProgress())) {
// If a session or a login is in progress, restart Chrome and return to the
// login screen. Chrome will show the device disabled screen after the
// restart.
delegate_->RestartToLoginScreen();
return;
}
// Cache the enrollment domain.
enrollment_domain_ =
browser_policy_connector_->GetEnterpriseEnrollmentDomain();
// Cache the device serial number.
serial_number_ = std::string(
StatisticsProvider::GetInstance()->GetMachineID().value_or(""));
// If no session or login is in progress, show the device disabled screen.
delegate_->ShowDeviceDisabledScreen();
}
} // namespace system
} // namespace ash