device_settings_service.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/device_settings_service.h"
6
7#include "base/bind.h"
8#include "base/file_util.h"
9#include "base/lazy_instance.h"
10#include "base/logging.h"
11#include "base/message_loop.h"
12#include "base/stl_util.h"
13#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
14#include "chrome/browser/chromeos/settings/owner_key_util.h"
15#include "chrome/browser/chromeos/settings/session_manager_operation.h"
16#include "chrome/browser/policy/cloud/proto/device_management_backend.pb.h"
17#include "chrome/common/chrome_notification_types.h"
18#include "content/public/browser/browser_thread.h"
19#include "content/public/browser/notification_service.h"
20#include "content/public/browser/notification_source.h"
21#include "crypto/rsa_private_key.h"
22
23namespace em = enterprise_management;
24
25namespace {
26
27// Delay between load retries when there was a validation error.
28// NOTE: This code is here to mitigate clock loss on some devices where policy
29// loads will fail with a validation error caused by RTC clock bing reset when
30// the battery is drained.
31int kLoadRetryDelayMs = 1000 * 5;
32// Maximal number of retries before we give up. Calculated to allow for 10 min
33// of retry time.
34int kMaxLoadRetries = (1000 * 60 * 10) / kLoadRetryDelayMs;
35
36}  // namespace
37
38namespace chromeos {
39
40static base::LazyInstance<DeviceSettingsService> g_device_settings_service =
41    LAZY_INSTANCE_INITIALIZER;
42
43OwnerKey::OwnerKey(scoped_ptr<std::vector<uint8> > public_key,
44                   scoped_ptr<crypto::RSAPrivateKey> private_key)
45    : public_key_(public_key.Pass()),
46      private_key_(private_key.Pass()) {}
47
48OwnerKey::~OwnerKey() {}
49
50DeviceSettingsService::Observer::~Observer() {}
51
52DeviceSettingsService::DeviceSettingsService()
53    : session_manager_client_(NULL),
54      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
55      store_status_(STORE_SUCCESS),
56      load_retries_left_(kMaxLoadRetries) {}
57
58DeviceSettingsService::~DeviceSettingsService() {
59  DCHECK(pending_operations_.empty());
60}
61
62// static
63DeviceSettingsService* DeviceSettingsService::Get() {
64  return g_device_settings_service.Pointer();
65}
66
67void DeviceSettingsService::Initialize(
68    SessionManagerClient* session_manager_client,
69    scoped_refptr<OwnerKeyUtil> owner_key_util) {
70  DCHECK(session_manager_client);
71  DCHECK(owner_key_util.get());
72  DCHECK(!session_manager_client_);
73  DCHECK(!owner_key_util_.get());
74
75  session_manager_client_ = session_manager_client;
76  owner_key_util_ = owner_key_util;
77
78  session_manager_client_->AddObserver(this);
79
80  StartNextOperation();
81}
82
83void DeviceSettingsService::Shutdown() {
84  STLDeleteContainerPointers(pending_operations_.begin(),
85                             pending_operations_.end());
86  pending_operations_.clear();
87
88  if (session_manager_client_)
89    session_manager_client_->RemoveObserver(this);
90  session_manager_client_ = NULL;
91  owner_key_util_ = NULL;
92}
93
94scoped_refptr<OwnerKey> DeviceSettingsService::GetOwnerKey() {
95  return owner_key_;
96}
97
98void DeviceSettingsService::Load() {
99  EnqueueLoad(false);
100}
101
102void DeviceSettingsService::SignAndStore(
103    scoped_ptr<em::ChromeDeviceSettingsProto> new_settings,
104    const base::Closure& callback) {
105  Enqueue(
106      new SignAndStoreSettingsOperation(
107          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
108                     weak_factory_.GetWeakPtr(),
109                     callback),
110          new_settings.Pass(),
111          username_));
112}
113
114void DeviceSettingsService::Store(scoped_ptr<em::PolicyFetchResponse> policy,
115                                  const base::Closure& callback) {
116  Enqueue(
117      new StoreSettingsOperation(
118          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
119                     weak_factory_.GetWeakPtr(),
120                     callback),
121          policy.Pass()));
122}
123
124DeviceSettingsService::OwnershipStatus
125    DeviceSettingsService::GetOwnershipStatus() {
126  if (owner_key_.get())
127    return owner_key_->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
128
129  return OWNERSHIP_UNKNOWN;
130}
131
132void DeviceSettingsService::GetOwnershipStatusAsync(
133    const OwnershipStatusCallback& callback) {
134  if (owner_key_.get()) {
135    // If there is a key, report status immediately.
136    MessageLoop::current()->PostTask(
137        FROM_HERE,
138        base::Bind(callback,
139                   owner_key_->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE,
140                   owner_key_->private_key() != NULL));
141  } else {
142    // If the key hasn't been loaded yet, enqueue the callback to be fired when
143    // the next SessionManagerOperation completes. If no operation is pending,
144    // start a load operation to fetch the key and report the result.
145    pending_ownership_status_callbacks_.push_back(callback);
146    if (pending_operations_.empty())
147      EnqueueLoad(false);
148  }
149}
150
151bool DeviceSettingsService::HasPrivateOwnerKey() {
152  return owner_key_.get() && owner_key_->private_key();
153}
154
155void DeviceSettingsService::SetUsername(const std::string& username) {
156  username_ = username;
157
158  // The private key may have become available, so force a key reload.
159  owner_key_ = NULL;
160  EnsureReload(true);
161}
162
163const std::string& DeviceSettingsService::GetUsername() const {
164  return username_;
165}
166
167void DeviceSettingsService::AddObserver(Observer* observer) {
168  observers_.AddObserver(observer);
169}
170
171void DeviceSettingsService::RemoveObserver(Observer* observer) {
172  observers_.RemoveObserver(observer);
173}
174
175void DeviceSettingsService::OwnerKeySet(bool success) {
176  if (!success) {
177    LOG(ERROR) << "Owner key change failed.";
178    return;
179  }
180
181  owner_key_ = NULL;
182  EnsureReload(true);
183}
184
185void DeviceSettingsService::PropertyChangeComplete(bool success) {
186  if (!success) {
187    LOG(ERROR) << "Policy update failed.";
188    return;
189  }
190
191  EnsureReload(false);
192}
193
194void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) {
195  pending_operations_.push_back(operation);
196  if (pending_operations_.front() == operation)
197    StartNextOperation();
198}
199
200void DeviceSettingsService::EnqueueLoad(bool force_key_load) {
201  SessionManagerOperation* operation =
202      new LoadSettingsOperation(
203          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
204                     weak_factory_.GetWeakPtr(),
205                     base::Closure()));
206  operation->set_force_key_load(force_key_load);
207  Enqueue(operation);
208}
209
210void DeviceSettingsService::EnsureReload(bool force_key_load) {
211  if (!pending_operations_.empty())
212    pending_operations_.front()->RestartLoad(force_key_load);
213  else
214    EnqueueLoad(force_key_load);
215}
216
217void DeviceSettingsService::StartNextOperation() {
218  if (!pending_operations_.empty() &&
219      session_manager_client_ &&
220      owner_key_util_.get()) {
221    pending_operations_.front()->Start(session_manager_client_,
222                                       owner_key_util_, owner_key_);
223  }
224}
225
226void DeviceSettingsService::HandleCompletedOperation(
227    const base::Closure& callback,
228    SessionManagerOperation* operation,
229    Status status) {
230  DCHECK_EQ(operation, pending_operations_.front());
231  store_status_ = status;
232
233  OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN;
234  bool is_owner = false;
235  scoped_refptr<OwnerKey> new_key(operation->owner_key());
236  if (new_key.get()) {
237    ownership_status =
238        new_key->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
239    is_owner = (new_key->private_key() != NULL);
240  } else {
241    NOTREACHED() << "Failed to determine key status.";
242  }
243
244  bool new_owner_key = false;
245  if (owner_key_.get() != new_key.get()) {
246    owner_key_ = new_key;
247    new_owner_key = true;
248  }
249
250  if (status == STORE_SUCCESS) {
251    policy_data_ = operation->policy_data().Pass();
252    device_settings_ = operation->device_settings().Pass();
253    load_retries_left_ = kMaxLoadRetries;
254  } else if (status != STORE_KEY_UNAVAILABLE) {
255    LOG(ERROR) << "Session manager operation failed: " << status;
256    // Validation errors can be temprary if the rtc has went on holiday for a
257    // short while. So we will retry such loads for up to 10 minutes.
258    if (status == STORE_TEMP_VALIDATION_ERROR) {
259      if (load_retries_left_ > 0) {
260        load_retries_left_--;
261        LOG(ERROR) << "A re-load has been scheduled due to a validation error.";
262        content::BrowserThread::PostDelayedTask(
263            content::BrowserThread::UI,
264            FROM_HERE,
265            base::Bind(&DeviceSettingsService::Load, base::Unretained(this)),
266            base::TimeDelta::FromMilliseconds(kLoadRetryDelayMs));
267      }
268    }
269  }
270
271  if (new_owner_key) {
272    FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged());
273    content::NotificationService::current()->Notify(
274        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
275        content::Source<DeviceSettingsService>(this),
276        content::NotificationService::NoDetails());
277  }
278
279  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
280
281  std::vector<OwnershipStatusCallback> callbacks;
282  callbacks.swap(pending_ownership_status_callbacks_);
283  for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin());
284       iter != callbacks.end(); ++iter) {
285    iter->Run(ownership_status, is_owner);
286  }
287
288  // The completion callback happens after the notification so clients can
289  // filter self-triggered updates.
290  if (!callback.is_null())
291    callback.Run();
292
293  // Only remove the pending operation here, so new operations triggered by any
294  // of the callbacks above are queued up properly.
295  pending_operations_.pop_front();
296  delete operation;
297
298  StartNextOperation();
299}
300
301}  // namespace chromeos
302