device_settings_service.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/settings/owner_key_util.h"
14#include "chrome/browser/chromeos/settings/session_manager_operation.h"
15#include "chrome/browser/policy/proto/chrome_device_policy.pb.h"
16#include "chrome/browser/policy/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  session_manager_client_->RemoveObserver(this);
89  session_manager_client_ = NULL;
90  owner_key_util_ = NULL;
91}
92
93scoped_refptr<OwnerKey> DeviceSettingsService::GetOwnerKey() {
94  return owner_key_;
95}
96
97void DeviceSettingsService::Load() {
98  EnqueueLoad(false);
99}
100
101void DeviceSettingsService::SignAndStore(
102    scoped_ptr<em::ChromeDeviceSettingsProto> new_settings,
103    const base::Closure& callback) {
104  Enqueue(
105      new SignAndStoreSettingsOperation(
106          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
107                     weak_factory_.GetWeakPtr(),
108                     callback),
109          new_settings.Pass(),
110          username_));
111}
112
113void DeviceSettingsService::Store(scoped_ptr<em::PolicyFetchResponse> policy,
114                                  const base::Closure& callback) {
115  Enqueue(
116      new StoreSettingsOperation(
117          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
118                     weak_factory_.GetWeakPtr(),
119                     callback),
120          policy.Pass()));
121}
122
123DeviceSettingsService::OwnershipStatus
124    DeviceSettingsService::GetOwnershipStatus() {
125  if (owner_key_.get())
126    return owner_key_->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
127
128  return OWNERSHIP_UNKNOWN;
129}
130
131void DeviceSettingsService::GetOwnershipStatusAsync(
132    const OwnershipStatusCallback& callback) {
133  if (owner_key_.get()) {
134    // If there is a key, report status immediately.
135    MessageLoop::current()->PostTask(
136        FROM_HERE,
137        base::Bind(callback,
138                   owner_key_->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE,
139                   owner_key_->private_key() != NULL));
140  } else {
141    // If the key hasn't been loaded yet, enqueue the callback to be fired when
142    // the next SessionManagerOperation completes. If no operation is pending,
143    // start a load operation to fetch the key and report the result.
144    pending_ownership_status_callbacks_.push_back(callback);
145    if (pending_operations_.empty())
146      EnqueueLoad(false);
147  }
148}
149
150bool DeviceSettingsService::HasPrivateOwnerKey() {
151  return owner_key_.get() && owner_key_->private_key();
152}
153
154void DeviceSettingsService::SetUsername(const std::string& username) {
155  username_ = username;
156
157  // The private key may have become available, so force a key reload.
158  owner_key_ = NULL;
159  EnsureReload(true);
160}
161
162const std::string& DeviceSettingsService::GetUsername() const {
163  return username_;
164}
165
166void DeviceSettingsService::AddObserver(Observer* observer) {
167  observers_.AddObserver(observer);
168}
169
170void DeviceSettingsService::RemoveObserver(Observer* observer) {
171  observers_.RemoveObserver(observer);
172}
173
174void DeviceSettingsService::OwnerKeySet(bool success) {
175  if (!success) {
176    LOG(ERROR) << "Owner key change failed.";
177    return;
178  }
179
180  owner_key_ = NULL;
181  EnsureReload(true);
182}
183
184void DeviceSettingsService::PropertyChangeComplete(bool success) {
185  if (!success) {
186    LOG(ERROR) << "Policy update failed.";
187    return;
188  }
189
190  EnsureReload(false);
191}
192
193void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) {
194  pending_operations_.push_back(operation);
195  if (pending_operations_.front() == operation)
196    StartNextOperation();
197}
198
199void DeviceSettingsService::EnqueueLoad(bool force_key_load) {
200  SessionManagerOperation* operation =
201      new LoadSettingsOperation(
202          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
203                     weak_factory_.GetWeakPtr(),
204                     base::Closure()));
205  operation->set_force_key_load(force_key_load);
206  Enqueue(operation);
207}
208
209void DeviceSettingsService::EnsureReload(bool force_key_load) {
210  if (!pending_operations_.empty())
211    pending_operations_.front()->RestartLoad(force_key_load);
212  else
213    EnqueueLoad(force_key_load);
214}
215
216void DeviceSettingsService::StartNextOperation() {
217  if (!pending_operations_.empty() &&
218      session_manager_client_ &&
219      owner_key_util_.get()) {
220    pending_operations_.front()->Start(session_manager_client_,
221                                       owner_key_util_, owner_key_);
222  }
223}
224
225void DeviceSettingsService::HandleCompletedOperation(
226    const base::Closure& callback,
227    SessionManagerOperation* operation,
228    Status status) {
229  DCHECK_EQ(operation, pending_operations_.front());
230  store_status_ = status;
231
232  OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN;
233  bool is_owner = false;
234  scoped_refptr<OwnerKey> new_key(operation->owner_key());
235  if (new_key.get()) {
236    ownership_status =
237        new_key->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
238    is_owner = (new_key->private_key() != NULL);
239  } else {
240    NOTREACHED() << "Failed to determine key status.";
241  }
242
243  bool new_owner_key = false;
244  if (owner_key_.get() != new_key.get()) {
245    owner_key_ = new_key;
246    new_owner_key = true;
247  }
248
249  if (status == STORE_SUCCESS) {
250    policy_data_ = operation->policy_data().Pass();
251    device_settings_ = operation->device_settings().Pass();
252    load_retries_left_ = kMaxLoadRetries;
253  } else if (status != STORE_KEY_UNAVAILABLE) {
254    LOG(ERROR) << "Session manager operation failed: " << status;
255    // Validation errors can be temprary if the rtc has went on holiday for a
256    // short while. So we will retry such loads for up to 10 minutes.
257    if (status == STORE_TEMP_VALIDATION_ERROR) {
258      if (load_retries_left_ > 0) {
259        load_retries_left_--;
260        LOG(ERROR) << "A re-load has been scheduled due to a validation error.";
261        content::BrowserThread::PostDelayedTask(
262            content::BrowserThread::UI,
263            FROM_HERE,
264            base::Bind(&DeviceSettingsService::Load, base::Unretained(this)),
265            base::TimeDelta::FromMilliseconds(kLoadRetryDelayMs));
266      }
267    }
268  }
269
270  if (new_owner_key) {
271    FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged());
272    content::NotificationService::current()->Notify(
273        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
274        content::Source<DeviceSettingsService>(this),
275        content::NotificationService::NoDetails());
276  }
277
278  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
279
280  std::vector<OwnershipStatusCallback> callbacks;
281  callbacks.swap(pending_ownership_status_callbacks_);
282  for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin());
283       iter != callbacks.end(); ++iter) {
284    iter->Run(ownership_status, is_owner);
285  }
286
287  // The completion callback happens after the notification so clients can
288  // filter self-triggered updates.
289  if (!callback.is_null())
290    callback.Run();
291
292  // Only remove the pending operation here, so new operations triggered by any
293  // of the callbacks above are queued up properly.
294  pending_operations_.pop_front();
295  delete operation;
296
297  StartNextOperation();
298}
299
300}  // namespace chromeos
301