1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/sequenced_task_runner.h"
11 #include "chrome/browser/chromeos/login/startup_utils.h"
12 #include "chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h"
13 #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
14 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
15 #include "chrome/browser/chromeos/settings/owner_key_util.h"
16 #include "policy/proto/device_management_backend.pb.h"
17
18 namespace em = enterprise_management;
19
20 namespace policy {
21
DeviceCloudPolicyStoreChromeOS(chromeos::DeviceSettingsService * device_settings_service,EnterpriseInstallAttributes * install_attributes,scoped_refptr<base::SequencedTaskRunner> background_task_runner)22 DeviceCloudPolicyStoreChromeOS::DeviceCloudPolicyStoreChromeOS(
23 chromeos::DeviceSettingsService* device_settings_service,
24 EnterpriseInstallAttributes* install_attributes,
25 scoped_refptr<base::SequencedTaskRunner> background_task_runner)
26 : device_settings_service_(device_settings_service),
27 install_attributes_(install_attributes),
28 background_task_runner_(background_task_runner),
29 enrollment_validation_done_(false),
30 weak_factory_(this) {
31 device_settings_service_->AddObserver(this);
32 }
33
~DeviceCloudPolicyStoreChromeOS()34 DeviceCloudPolicyStoreChromeOS::~DeviceCloudPolicyStoreChromeOS() {
35 device_settings_service_->RemoveObserver(this);
36 }
37
Store(const em::PolicyFetchResponse & policy)38 void DeviceCloudPolicyStoreChromeOS::Store(
39 const em::PolicyFetchResponse& policy) {
40 // Cancel all pending requests.
41 weak_factory_.InvalidateWeakPtrs();
42
43 scoped_refptr<chromeos::PublicKey> public_key(
44 device_settings_service_->GetPublicKey());
45 if (!install_attributes_->IsEnterpriseDevice() ||
46 !device_settings_service_->policy_data() || !public_key.get() ||
47 !public_key->is_loaded()) {
48 status_ = STATUS_BAD_STATE;
49 NotifyStoreError();
50 return;
51 }
52
53 scoped_ptr<DeviceCloudPolicyValidator> validator(CreateValidator(policy));
54 validator->ValidateSignature(public_key->as_string(),
55 GetPolicyVerificationKey(),
56 install_attributes_->GetDomain(),
57 true);
58 validator->ValidateAgainstCurrentPolicy(
59 device_settings_service_->policy_data(),
60 CloudPolicyValidatorBase::TIMESTAMP_REQUIRED,
61 CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
62 validator.release()->StartValidation(
63 base::Bind(&DeviceCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
64 weak_factory_.GetWeakPtr()));
65 }
66
Load()67 void DeviceCloudPolicyStoreChromeOS::Load() {
68 device_settings_service_->Load();
69 }
70
InstallInitialPolicy(const em::PolicyFetchResponse & policy)71 void DeviceCloudPolicyStoreChromeOS::InstallInitialPolicy(
72 const em::PolicyFetchResponse& policy) {
73 // Cancel all pending requests.
74 weak_factory_.InvalidateWeakPtrs();
75
76 if (!install_attributes_->IsEnterpriseDevice() &&
77 device_settings_service_->status() !=
78 chromeos::DeviceSettingsService::STORE_NO_POLICY) {
79 status_ = STATUS_BAD_STATE;
80 NotifyStoreError();
81 return;
82 }
83
84 scoped_ptr<DeviceCloudPolicyValidator> validator(CreateValidator(policy));
85 validator->ValidateInitialKey(GetPolicyVerificationKey(),
86 install_attributes_->GetDomain());
87 validator.release()->StartValidation(
88 base::Bind(&DeviceCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
89 weak_factory_.GetWeakPtr()));
90 }
91
OwnershipStatusChanged()92 void DeviceCloudPolicyStoreChromeOS::OwnershipStatusChanged() {
93 // Nothing to do.
94 }
95
DeviceSettingsUpdated()96 void DeviceCloudPolicyStoreChromeOS::DeviceSettingsUpdated() {
97 if (!weak_factory_.HasWeakPtrs())
98 UpdateFromService();
99 }
100
101 scoped_ptr<DeviceCloudPolicyValidator>
CreateValidator(const em::PolicyFetchResponse & policy)102 DeviceCloudPolicyStoreChromeOS::CreateValidator(
103 const em::PolicyFetchResponse& policy) {
104 scoped_ptr<DeviceCloudPolicyValidator> validator(
105 DeviceCloudPolicyValidator::Create(
106 scoped_ptr<em::PolicyFetchResponse>(
107 new em::PolicyFetchResponse(policy)),
108 background_task_runner_));
109 validator->ValidateDomain(install_attributes_->GetDomain());
110 validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
111 validator->ValidatePayload();
112 return validator.Pass();
113 }
114
OnPolicyToStoreValidated(DeviceCloudPolicyValidator * validator)115 void DeviceCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
116 DeviceCloudPolicyValidator* validator) {
117 if (!validator->success()) {
118 status_ = STATUS_VALIDATION_ERROR;
119 validation_status_ = validator->status();
120 NotifyStoreError();
121 return;
122 }
123
124 device_settings_service_->Store(
125 validator->policy().Pass(),
126 base::Bind(&DeviceCloudPolicyStoreChromeOS::OnPolicyStored,
127 weak_factory_.GetWeakPtr()));
128 }
129
OnPolicyStored()130 void DeviceCloudPolicyStoreChromeOS::OnPolicyStored() {
131 UpdateFromService();
132 }
133
UpdateFromService()134 void DeviceCloudPolicyStoreChromeOS::UpdateFromService() {
135 if (!install_attributes_->IsEnterpriseDevice()) {
136 status_ = STATUS_BAD_STATE;
137 NotifyStoreError();
138 return;
139 }
140
141 // Once per session, validate internal consistency of enrollment state (DM
142 // token must be present on enrolled devices) and in case of failure set flag
143 // to indicate that recovery is required.
144 const chromeos::DeviceSettingsService::Status status =
145 device_settings_service_->status();
146 switch (status) {
147 case chromeos::DeviceSettingsService::STORE_SUCCESS:
148 case chromeos::DeviceSettingsService::STORE_KEY_UNAVAILABLE:
149 case chromeos::DeviceSettingsService::STORE_NO_POLICY:
150 case chromeos::DeviceSettingsService::STORE_INVALID_POLICY:
151 case chromeos::DeviceSettingsService::STORE_VALIDATION_ERROR: {
152 if (!enrollment_validation_done_) {
153 enrollment_validation_done_ = true;
154 const bool has_dm_token =
155 status == chromeos::DeviceSettingsService::STORE_SUCCESS &&
156 device_settings_service_->policy_data() &&
157 device_settings_service_->policy_data()->has_request_token();
158
159 // At the time LoginDisplayHostImpl decides whether enrollment flow is
160 // to be started, policy hasn't been read yet. To work around this,
161 // once the need for recovery is detected upon policy load, a flag is
162 // stored in prefs which is accessed by LoginDisplayHostImpl early
163 // during (next) boot.
164 if (!has_dm_token) {
165 LOG(ERROR) << "Device policy read on enrolled device yields "
166 << "no DM token! Status: " << status << ".";
167 chromeos::StartupUtils::MarkEnrollmentRecoveryRequired();
168 }
169 UMA_HISTOGRAM_BOOLEAN("Enterprise.EnrolledPolicyHasDMToken",
170 has_dm_token);
171 }
172 break;
173 }
174 case chromeos::DeviceSettingsService::STORE_POLICY_ERROR:
175 case chromeos::DeviceSettingsService::STORE_OPERATION_FAILED:
176 case chromeos::DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR:
177 // Do nothing for write errors or transient read errors.
178 break;
179 }
180
181 switch (status) {
182 case chromeos::DeviceSettingsService::STORE_SUCCESS: {
183 status_ = STATUS_OK;
184 policy_.reset(new em::PolicyData());
185 if (device_settings_service_->policy_data())
186 policy_->MergeFrom(*device_settings_service_->policy_data());
187
188 PolicyMap new_policy_map;
189 if (is_managed()) {
190 DecodeDevicePolicy(*device_settings_service_->device_settings(),
191 &new_policy_map, install_attributes_);
192 }
193 policy_map_.Swap(&new_policy_map);
194
195 NotifyStoreLoaded();
196 return;
197 }
198 case chromeos::DeviceSettingsService::STORE_KEY_UNAVAILABLE:
199 status_ = STATUS_BAD_STATE;
200 break;
201 case chromeos::DeviceSettingsService::STORE_POLICY_ERROR:
202 case chromeos::DeviceSettingsService::STORE_OPERATION_FAILED:
203 status_ = STATUS_STORE_ERROR;
204 break;
205 case chromeos::DeviceSettingsService::STORE_NO_POLICY:
206 case chromeos::DeviceSettingsService::STORE_INVALID_POLICY:
207 case chromeos::DeviceSettingsService::STORE_VALIDATION_ERROR:
208 case chromeos::DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR:
209 status_ = STATUS_LOAD_ERROR;
210 break;
211 }
212
213 NotifyStoreError();
214 }
215
216 } // namespace policy
217