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