// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/port.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/attestation/attestation_policy_observer.h" #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h" #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h" #include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h" #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h" #include "chrome/browser/chromeos/policy/server_backed_device_state.h" #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h" #include "chrome/common/chrome_content_client.h" #include "chrome/common/pref_names.h" #include "chromeos/chromeos_constants.h" #include "chromeos/chromeos_switches.h" #include "chromeos/system/statistics_provider.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "components/policy/core/common/cloud/cloud_policy_store.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/cloud/system_policy_request_context.h" #include "content/public/browser/browser_thread.h" #include "crypto/sha2.h" #include "policy/proto/device_management_backend.pb.h" #include "url/gurl.h" using content::BrowserThread; namespace em = enterprise_management; namespace policy { namespace { // Overridden no requisition value. const char kNoRequisition[] = "none"; // Overridden no requisition value. const char kRemoraRequisition[] = "remora"; // These are the machine serial number keys that we check in order until we // find a non-empty serial number. The VPD spec says the serial number should be // in the "serial_number" key for v2+ VPDs. However, legacy devices used a // different key to report their serial number, which we fall back to if // "serial_number" is not present. // // Product_S/N is still special-cased due to inconsistencies with serial // numbers on Lumpy devices: On these devices, serial_number is identical to // Product_S/N with an appended checksum. Unfortunately, the sticker on the // packaging doesn't include that checksum either (the sticker on the device // does though!). The former sticker is the source of the serial number used by // device management service, so we prefer Product_S/N over serial number to // match the server. // // TODO(mnissler): Move serial_number back to the top once the server side uses // the correct serial number. const char* kMachineInfoSerialNumberKeys[] = { "Product_S/N", // Lumpy/Alex devices "serial_number", // VPD v2+ devices "Product_SN", // Mario "sn", // old ZGB devices (more recent ones use serial_number) }; // Fetches a machine statistic value from StatisticsProvider, returns an empty // string on failure. std::string GetMachineStatistic(const std::string& key) { std::string value; chromeos::system::StatisticsProvider* provider = chromeos::system::StatisticsProvider::GetInstance(); if (!provider->GetMachineStatistic(key, &value)) return std::string(); return value; } // Gets a machine flag from StatisticsProvider, returns the given // |default_value| if not present. bool GetMachineFlag(const std::string& key, bool default_value) { bool value = default_value; chromeos::system::StatisticsProvider* provider = chromeos::system::StatisticsProvider::GetInstance(); if (!provider->GetMachineFlag(key, &value)) return default_value; return value; } // Checks whether forced re-enrollment is enabled. bool ForcedReEnrollmentEnabled() { return chromeos::AutoEnrollmentController::GetMode() == chromeos::AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT; } } // namespace DeviceCloudPolicyManagerChromeOS::DeviceCloudPolicyManagerChromeOS( scoped_ptr store, const scoped_refptr& task_runner, const scoped_refptr& background_task_runner, EnterpriseInstallAttributes* install_attributes, ServerBackedStateKeysBroker* state_keys_broker) : CloudPolicyManager( PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string()), store.get(), task_runner, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)), device_store_(store.Pass()), background_task_runner_(background_task_runner), install_attributes_(install_attributes), state_keys_broker_(state_keys_broker), device_management_service_(NULL), local_state_(NULL) { } DeviceCloudPolicyManagerChromeOS::~DeviceCloudPolicyManagerChromeOS() {} void DeviceCloudPolicyManagerChromeOS::Connect( PrefService* local_state, DeviceManagementService* device_management_service, scoped_ptr device_status_provider) { CHECK(!device_management_service_); CHECK(device_management_service); CHECK(local_state); local_state_ = local_state; device_management_service_ = device_management_service; device_status_provider_ = device_status_provider.Pass(); state_keys_update_subscription_ = state_keys_broker_->RegisterUpdateCallback( base::Bind(&DeviceCloudPolicyManagerChromeOS::OnStateKeysUpdated, base::Unretained(this))); InitializeRequisition(); StartIfManaged(); } void DeviceCloudPolicyManagerChromeOS::StartEnrollment( const std::string& auth_token, bool is_auto_enrollment, const AllowedDeviceModes& allowed_device_modes, const EnrollmentCallback& callback) { CHECK(device_management_service_); CHECK(!enrollment_handler_); core()->Disconnect(); enrollment_handler_.reset(new EnrollmentHandlerChromeOS( device_store_.get(), install_attributes_, state_keys_broker_, CreateClient(), background_task_runner_, auth_token, install_attributes_->GetDeviceId(), is_auto_enrollment, GetDeviceRequisition(), allowed_device_modes, base::Bind(&DeviceCloudPolicyManagerChromeOS::EnrollmentCompleted, base::Unretained(this), callback))); enrollment_handler_->StartEnrollment(); } void DeviceCloudPolicyManagerChromeOS::CancelEnrollment() { if (enrollment_handler_) { enrollment_handler_.reset(); StartIfManaged(); } } std::string DeviceCloudPolicyManagerChromeOS::GetDeviceRequisition() const { std::string requisition; const PrefService::Preference* pref = local_state_->FindPreference( prefs::kDeviceEnrollmentRequisition); if (!pref->IsDefaultValue()) pref->GetValue()->GetAsString(&requisition); if (requisition == kNoRequisition) requisition.clear(); return requisition; } void DeviceCloudPolicyManagerChromeOS::SetDeviceRequisition( const std::string& requisition) { if (local_state_) { if (requisition.empty()) { local_state_->ClearPref(prefs::kDeviceEnrollmentRequisition); local_state_->ClearPref(prefs::kDeviceEnrollmentAutoStart); local_state_->ClearPref(prefs::kDeviceEnrollmentCanExit); } else { local_state_->SetString(prefs::kDeviceEnrollmentRequisition, requisition); if (requisition == kNoRequisition) { local_state_->ClearPref(prefs::kDeviceEnrollmentAutoStart); local_state_->ClearPref(prefs::kDeviceEnrollmentCanExit); } else { local_state_->SetBoolean(prefs::kDeviceEnrollmentAutoStart, true); local_state_->SetBoolean(prefs::kDeviceEnrollmentCanExit, false); } } } } bool DeviceCloudPolicyManagerChromeOS::ShouldAutoStartEnrollment() const { std::string restore_mode = GetRestoreMode(); if (restore_mode == kDeviceStateRestoreModeReEnrollmentRequested || restore_mode == kDeviceStateRestoreModeReEnrollmentEnforced) { return true; } if (local_state_->HasPrefPath(prefs::kDeviceEnrollmentAutoStart)) return local_state_->GetBoolean(prefs::kDeviceEnrollmentAutoStart); return GetMachineFlag(chromeos::system::kOemIsEnterpriseManagedKey, false); } bool DeviceCloudPolicyManagerChromeOS::ShouldRecoverEnrollment() const { if (install_attributes_->IsEnterpriseDevice() && chromeos::StartupUtils::IsEnrollmentRecoveryRequired()) { LOG(WARNING) << "Enrollment recovery required according to pref."; if (!DeviceCloudPolicyManagerChromeOS::GetMachineID().empty()) return true; LOG(WARNING) << "Postponing recovery because machine id is missing."; } return false; } std::string DeviceCloudPolicyManagerChromeOS::GetEnrollmentRecoveryDomain() const { return install_attributes_->GetDomain(); } bool DeviceCloudPolicyManagerChromeOS::CanExitEnrollment() const { if (GetRestoreMode() == kDeviceStateRestoreModeReEnrollmentEnforced) return false; if (local_state_->HasPrefPath(prefs::kDeviceEnrollmentCanExit)) return local_state_->GetBoolean(prefs::kDeviceEnrollmentCanExit); return GetMachineFlag(chromeos::system::kOemCanExitEnterpriseEnrollmentKey, true); } std::string DeviceCloudPolicyManagerChromeOS::GetForcedEnrollmentDomain() const { const base::DictionaryValue* device_state_dict = local_state_->GetDictionary(prefs::kServerBackedDeviceState); std::string management_domain; device_state_dict->GetString(kDeviceStateManagementDomain, &management_domain); return management_domain; } void DeviceCloudPolicyManagerChromeOS::Shutdown() { state_keys_update_subscription_.reset(); CloudPolicyManager::Shutdown(); device_status_provider_.reset(); } void DeviceCloudPolicyManagerChromeOS::OnStoreLoaded(CloudPolicyStore* store) { CloudPolicyManager::OnStoreLoaded(store); StartIfManaged(); } // static void DeviceCloudPolicyManagerChromeOS::RegisterPrefs( PrefRegistrySimple* registry) { registry->RegisterStringPref(prefs::kDeviceEnrollmentRequisition, std::string()); registry->RegisterBooleanPref(prefs::kDeviceEnrollmentAutoStart, false); registry->RegisterBooleanPref(prefs::kDeviceEnrollmentCanExit, true); registry->RegisterDictionaryPref(prefs::kServerBackedDeviceState); } // static std::string DeviceCloudPolicyManagerChromeOS::GetMachineID() { std::string machine_id; chromeos::system::StatisticsProvider* provider = chromeos::system::StatisticsProvider::GetInstance(); for (size_t i = 0; i < arraysize(kMachineInfoSerialNumberKeys); i++) { if (provider->GetMachineStatistic(kMachineInfoSerialNumberKeys[i], &machine_id) && !machine_id.empty()) { break; } } if (machine_id.empty()) LOG(WARNING) << "Failed to get machine id."; return machine_id; } // static std::string DeviceCloudPolicyManagerChromeOS::GetMachineModel() { return GetMachineStatistic(chromeos::system::kHardwareClassKey); } scoped_ptr DeviceCloudPolicyManagerChromeOS::CreateClient() { scoped_refptr request_context = new SystemPolicyRequestContext( g_browser_process->system_request_context(), GetUserAgent()); scoped_ptr client( new CloudPolicyClient(GetMachineID(), GetMachineModel(), kPolicyVerificationKeyHash, USER_AFFILIATION_NONE, device_status_provider_.get(), device_management_service_, request_context)); return client.Pass(); } void DeviceCloudPolicyManagerChromeOS::EnrollmentCompleted( const EnrollmentCallback& callback, EnrollmentStatus status) { if (status.status() == EnrollmentStatus::STATUS_SUCCESS) StartConnection(enrollment_handler_->ReleaseClient()); else StartIfManaged(); enrollment_handler_.reset(); if (!callback.is_null()) callback.Run(status); } void DeviceCloudPolicyManagerChromeOS::StartIfManaged() { if (device_management_service_ && local_state_ && store()->is_initialized() && store()->has_policy() && !device_store_->policy()->request_token().empty() && !state_keys_broker_->pending() && !enrollment_handler_ && !service()) { StartConnection(CreateClient()); } } void DeviceCloudPolicyManagerChromeOS::StartConnection( scoped_ptr client_to_connect) { // Set state keys here so the first policy fetch submits them to the server. if (ForcedReEnrollmentEnabled()) client_to_connect->SetStateKeysToUpload(state_keys_broker_->state_keys()); core()->Connect(client_to_connect.Pass()); core()->StartRefreshScheduler(); core()->TrackRefreshDelayPref(local_state_, prefs::kDevicePolicyRefreshRate); attestation_policy_observer_.reset( new chromeos::attestation::AttestationPolicyObserver(client())); } void DeviceCloudPolicyManagerChromeOS::OnStateKeysUpdated() { if (client()) { if (ForcedReEnrollmentEnabled()) client()->SetStateKeysToUpload(state_keys_broker_->state_keys()); } else { StartIfManaged(); } } void DeviceCloudPolicyManagerChromeOS::InitializeRequisition() { // OEM statistics are only loaded when OOBE is not completed. if (chromeos::StartupUtils::IsOobeCompleted()) return; const PrefService::Preference* pref = local_state_->FindPreference( prefs::kDeviceEnrollmentRequisition); if (pref->IsDefaultValue()) { std::string requisition = GetMachineStatistic(chromeos::system::kOemDeviceRequisitionKey); if (!requisition.empty()) { local_state_->SetString(prefs::kDeviceEnrollmentRequisition, requisition); if (requisition == kRemoraRequisition) { local_state_->SetBoolean(prefs::kDeviceEnrollmentAutoStart, true); local_state_->SetBoolean(prefs::kDeviceEnrollmentCanExit, false); } else { local_state_->SetBoolean( prefs::kDeviceEnrollmentAutoStart, GetMachineFlag(chromeos::system::kOemIsEnterpriseManagedKey, false)); local_state_->SetBoolean( prefs::kDeviceEnrollmentCanExit, GetMachineFlag(chromeos::system::kOemCanExitEnterpriseEnrollmentKey, false)); } } } } std::string DeviceCloudPolicyManagerChromeOS::GetRestoreMode() const { const base::DictionaryValue* device_state_dict = local_state_->GetDictionary(prefs::kServerBackedDeviceState); std::string restore_mode; device_state_dict->GetString(kDeviceStateRestoreMode, &restore_mode); return restore_mode; } } // namespace policy