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/settings/session_manager_operation.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/files/file_path.h"
10#include "base/message_loop/message_loop.h"
11#include "base/stl_util.h"
12#include "base/task_runner_util.h"
13#include "base/threading/sequenced_worker_pool.h"
14#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
15#include "chrome/browser/net/nss_context.h"
16#include "components/ownership/owner_key_util.h"
17#include "components/policy/core/common/cloud/cloud_policy_constants.h"
18#include "content/public/browser/browser_thread.h"
19#include "crypto/rsa_private_key.h"
20#include "crypto/signature_creator.h"
21#include "policy/proto/device_management_backend.pb.h"
22
23using ownership::OwnerKeyUtil;
24using ownership::PublicKey;
25
26namespace em = enterprise_management;
27
28namespace chromeos {
29
30SessionManagerOperation::SessionManagerOperation(const Callback& callback)
31    : session_manager_client_(NULL),
32      callback_(callback),
33      force_key_load_(false),
34      is_loading_(false),
35      weak_factory_(this) {}
36
37SessionManagerOperation::~SessionManagerOperation() {}
38
39void SessionManagerOperation::Start(
40    SessionManagerClient* session_manager_client,
41    scoped_refptr<OwnerKeyUtil> owner_key_util,
42    scoped_refptr<PublicKey> public_key) {
43  session_manager_client_ = session_manager_client;
44  owner_key_util_ = owner_key_util;
45  public_key_ = public_key;
46  Run();
47}
48
49void SessionManagerOperation::RestartLoad(bool key_changed) {
50  if (key_changed)
51    public_key_ = NULL;
52
53  if (!is_loading_)
54    return;
55
56  // Abort previous load operations.
57  weak_factory_.InvalidateWeakPtrs();
58  // Mark as not loading to start loading again.
59  is_loading_ = false;
60  StartLoading();
61}
62
63void SessionManagerOperation::StartLoading() {
64  if (is_loading_)
65    return;
66  is_loading_ = true;
67  EnsurePublicKey(base::Bind(&SessionManagerOperation::RetrieveDeviceSettings,
68                             weak_factory_.GetWeakPtr()));
69}
70
71void SessionManagerOperation::ReportResult(
72    DeviceSettingsService::Status status) {
73  callback_.Run(this, status);
74}
75
76void SessionManagerOperation::EnsurePublicKey(const base::Closure& callback) {
77  if (force_key_load_ || !public_key_.get() || !public_key_->is_loaded()) {
78    scoped_refptr<base::TaskRunner> task_runner =
79        content::BrowserThread::GetBlockingPool()
80            ->GetTaskRunnerWithShutdownBehavior(
81                base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
82    base::PostTaskAndReplyWithResult(
83        task_runner.get(),
84        FROM_HERE,
85        base::Bind(&SessionManagerOperation::LoadPublicKey,
86                   owner_key_util_,
87                   public_key_),
88        base::Bind(&SessionManagerOperation::StorePublicKey,
89                   weak_factory_.GetWeakPtr(),
90                   callback));
91  } else {
92    callback.Run();
93  }
94}
95
96// static
97scoped_refptr<PublicKey> SessionManagerOperation::LoadPublicKey(
98    scoped_refptr<OwnerKeyUtil> util,
99    scoped_refptr<PublicKey> current_key) {
100  scoped_refptr<PublicKey> public_key(new PublicKey());
101
102  // Keep already-existing public key.
103  if (current_key.get() && current_key->is_loaded()) {
104    public_key->data() = current_key->data();
105  }
106  if (!public_key->is_loaded() && util->IsPublicKeyPresent()) {
107    if (!util->ImportPublicKey(&public_key->data()))
108      LOG(ERROR) << "Failed to load public owner key.";
109  }
110
111  return public_key;
112}
113
114void SessionManagerOperation::StorePublicKey(const base::Closure& callback,
115                                             scoped_refptr<PublicKey> new_key) {
116  force_key_load_ = false;
117  public_key_ = new_key;
118
119  if (!public_key_.get() || !public_key_->is_loaded()) {
120    ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE);
121    return;
122  }
123
124  callback.Run();
125}
126
127void SessionManagerOperation::RetrieveDeviceSettings() {
128  session_manager_client()->RetrieveDevicePolicy(
129      base::Bind(&SessionManagerOperation::ValidateDeviceSettings,
130                 weak_factory_.GetWeakPtr()));
131}
132
133void SessionManagerOperation::ValidateDeviceSettings(
134    const std::string& policy_blob) {
135  scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
136  if (policy_blob.empty()) {
137    ReportResult(DeviceSettingsService::STORE_NO_POLICY);
138    return;
139  }
140
141  if (!policy->ParseFromString(policy_blob) ||
142      !policy->IsInitialized()) {
143    ReportResult(DeviceSettingsService::STORE_INVALID_POLICY);
144    return;
145  }
146
147  base::SequencedWorkerPool* pool =
148      content::BrowserThread::GetBlockingPool();
149  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
150      pool->GetSequencedTaskRunnerWithShutdownBehavior(
151          pool->GetSequenceToken(),
152          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
153
154  policy::DeviceCloudPolicyValidator* validator =
155      policy::DeviceCloudPolicyValidator::Create(policy.Pass(),
156                                                 background_task_runner);
157
158
159  // Policy auto-generated by session manager doesn't include a timestamp, so
160  // the timestamp shouldn't be verified in that case.
161  //
162  // Additionally, offline devices can get their clock set backwards in time
163  // under some hardware conditions; checking the timestamp now could likely
164  // find a value in the future, and prevent the user from signing-in or
165  // starting guest mode. Tlsdate will eventually fix the clock when the device
166  // is back online, but the network configuration may come from device ONC.
167  //
168  // To prevent all of these issues the timestamp is just not verified when
169  // loading the device policy from the cache. Note that the timestamp is still
170  // verified during enrollment and when a new policy is fetched from the
171  // server.
172  validator->ValidateAgainstCurrentPolicy(
173      policy_data_.get(),
174      policy::CloudPolicyValidatorBase::TIMESTAMP_NOT_REQUIRED,
175      policy::CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED);
176  validator->ValidatePolicyType(policy::dm_protocol::kChromeDevicePolicyType);
177  validator->ValidatePayload();
178  // We don't check the DMServer verification key below, because the signing
179  // key is validated when it is installed.
180  validator->ValidateSignature(public_key_->as_string(),
181                               std::string(),  // No key validation check.
182                               std::string(),
183                               false);
184  validator->StartValidation(
185      base::Bind(&SessionManagerOperation::ReportValidatorStatus,
186                 weak_factory_.GetWeakPtr()));
187}
188
189void SessionManagerOperation::ReportValidatorStatus(
190    policy::DeviceCloudPolicyValidator* validator) {
191  DeviceSettingsService::Status status =
192      DeviceSettingsService::STORE_VALIDATION_ERROR;
193  if (validator->success()) {
194    status = DeviceSettingsService::STORE_SUCCESS;
195    policy_data_ = validator->policy_data().Pass();
196    device_settings_ = validator->payload().Pass();
197  } else {
198    LOG(ERROR) << "Policy validation failed: " << validator->status();
199
200    // Those are mostly caused by RTC loss and are recoverable.
201    if (validator->status() ==
202        policy::DeviceCloudPolicyValidator::VALIDATION_BAD_TIMESTAMP) {
203      status = DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR;
204    }
205  }
206
207  ReportResult(status);
208}
209
210LoadSettingsOperation::LoadSettingsOperation(const Callback& callback)
211    : SessionManagerOperation(callback) {}
212
213LoadSettingsOperation::~LoadSettingsOperation() {}
214
215void LoadSettingsOperation::Run() {
216  StartLoading();
217}
218
219StoreSettingsOperation::StoreSettingsOperation(
220    const Callback& callback,
221    scoped_ptr<em::PolicyFetchResponse> policy)
222    : SessionManagerOperation(callback),
223      policy_(policy.Pass()),
224      weak_factory_(this) {}
225
226StoreSettingsOperation::~StoreSettingsOperation() {}
227
228void StoreSettingsOperation::Run() {
229  session_manager_client()->StoreDevicePolicy(
230      policy_->SerializeAsString(),
231      base::Bind(&StoreSettingsOperation::HandleStoreResult,
232                 weak_factory_.GetWeakPtr()));
233}
234
235void StoreSettingsOperation::HandleStoreResult(bool success) {
236  if (!success)
237    ReportResult(DeviceSettingsService::STORE_OPERATION_FAILED);
238  else
239    StartLoading();
240}
241
242SignAndStoreSettingsOperation::SignAndStoreSettingsOperation(
243    const Callback& callback,
244    scoped_ptr<em::PolicyData> new_policy)
245    : SessionManagerOperation(callback),
246      new_policy_(new_policy.Pass()),
247      weak_factory_(this) {
248  DCHECK(new_policy_);
249}
250
251SignAndStoreSettingsOperation::~SignAndStoreSettingsOperation() {}
252
253void SignAndStoreSettingsOperation::Run() {
254  if (!owner_settings_service_) {
255    ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE);
256    return;
257  }
258  owner_settings_service_->IsOwnerAsync(
259      base::Bind(&SignAndStoreSettingsOperation::StartSigning,
260                 weak_factory_.GetWeakPtr()));
261}
262
263void SignAndStoreSettingsOperation::StartSigning(bool is_owner) {
264  if (!owner_settings_service_ || !is_owner) {
265    ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE);
266    return;
267  }
268
269  bool rv = owner_settings_service_->AssembleAndSignPolicyAsync(
270      content::BrowserThread::GetBlockingPool(),
271      new_policy_.Pass(),
272      base::Bind(&SignAndStoreSettingsOperation::StoreDeviceSettingsBlob,
273                 weak_factory_.GetWeakPtr()));
274  if (!rv) {
275    ReportResult(DeviceSettingsService::STORE_KEY_UNAVAILABLE);
276    return;
277  }
278}
279
280void SignAndStoreSettingsOperation::StoreDeviceSettingsBlob(
281    std::string device_settings_blob) {
282  if (device_settings_blob.empty()) {
283    ReportResult(DeviceSettingsService::STORE_POLICY_ERROR);
284    return;
285  }
286
287  session_manager_client()->StoreDevicePolicy(
288      device_settings_blob,
289      base::Bind(&SignAndStoreSettingsOperation::HandleStoreResult,
290                 weak_factory_.GetWeakPtr()));
291}
292
293void SignAndStoreSettingsOperation::HandleStoreResult(bool success) {
294  if (!success)
295    ReportResult(DeviceSettingsService::STORE_OPERATION_FAILED);
296  else
297    StartLoading();
298}
299
300}  // namespace chromeos
301