device_settings_service.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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/logging.h"
9#include "base/message_loop/message_loop.h"
10#include "base/stl_util.h"
11#include "base/time/time.h"
12#include "chrome/browser/chrome_notification_types.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 "components/policy/core/common/cloud/cloud_policy_constants.h"
17#include "content/public/browser/browser_thread.h"
18#include "content/public/browser/notification_service.h"
19#include "content/public/browser/notification_source.h"
20#include "crypto/rsa_private_key.h"
21
22namespace em = enterprise_management;
23
24namespace {
25
26// Delay between load retries when there was a validation error.
27// NOTE: This code is here to mitigate clock loss on some devices where policy
28// loads will fail with a validation error caused by RTC clock being reset when
29// the battery is drained.
30int kLoadRetryDelayMs = 1000 * 5;
31// Maximal number of retries before we give up. Calculated to allow for 10 min
32// of retry time.
33int kMaxLoadRetries = (1000 * 60 * 10) / kLoadRetryDelayMs;
34
35}  // namespace
36
37namespace chromeos {
38
39DeviceSettingsService::Observer::~Observer() {}
40
41static DeviceSettingsService* g_device_settings_service = NULL;
42
43// static
44void DeviceSettingsService::Initialize() {
45  CHECK(!g_device_settings_service);
46  g_device_settings_service = new DeviceSettingsService();
47}
48
49// static
50bool DeviceSettingsService::IsInitialized() {
51  return g_device_settings_service;
52}
53
54// static
55void DeviceSettingsService::Shutdown() {
56  DCHECK(g_device_settings_service);
57  delete g_device_settings_service;
58  g_device_settings_service = NULL;
59}
60
61// static
62DeviceSettingsService* DeviceSettingsService::Get() {
63  CHECK(g_device_settings_service);
64  return g_device_settings_service;
65}
66
67DeviceSettingsService::DeviceSettingsService()
68    : session_manager_client_(NULL),
69      store_status_(STORE_SUCCESS),
70      load_retries_left_(kMaxLoadRetries),
71      weak_factory_(this) {
72}
73
74DeviceSettingsService::~DeviceSettingsService() {
75  DCHECK(pending_operations_.empty());
76}
77
78void DeviceSettingsService::SetSessionManager(
79    SessionManagerClient* session_manager_client,
80    scoped_refptr<OwnerKeyUtil> owner_key_util) {
81  DCHECK(session_manager_client);
82  DCHECK(owner_key_util.get());
83  DCHECK(!session_manager_client_);
84  DCHECK(!owner_key_util_.get());
85
86  session_manager_client_ = session_manager_client;
87  owner_key_util_ = owner_key_util;
88
89  session_manager_client_->AddObserver(this);
90
91  StartNextOperation();
92}
93
94void DeviceSettingsService::UnsetSessionManager() {
95  STLDeleteContainerPointers(pending_operations_.begin(),
96                             pending_operations_.end());
97  pending_operations_.clear();
98
99  if (session_manager_client_)
100    session_manager_client_->RemoveObserver(this);
101  session_manager_client_ = NULL;
102  owner_key_util_ = NULL;
103}
104
105scoped_refptr<PublicKey> DeviceSettingsService::GetPublicKey() {
106  return public_key_;
107}
108
109void DeviceSettingsService::Load() {
110  EnqueueLoad(false);
111}
112
113void DeviceSettingsService::SignAndStore(
114    scoped_ptr<em::ChromeDeviceSettingsProto> new_settings,
115    const base::Closure& callback) {
116  scoped_ptr<em::PolicyData> new_policy = AssemblePolicy(*new_settings);
117  if (!new_policy) {
118    HandleError(STORE_POLICY_ERROR, callback);
119    return;
120  }
121
122  EnqueueSignAndStore(new_policy.Pass(), callback);
123}
124
125void DeviceSettingsService::SetManagementSettings(
126    em::PolicyData::ManagementMode management_mode,
127    const std::string& request_token,
128    const std::string& device_id,
129    const base::Closure& callback) {
130  if (!CheckManagementModeTransition(management_mode)) {
131    LOG(ERROR) << "Invalid management mode transition: current mode = "
132               << GetManagementMode() << ", new mode = " << management_mode;
133    HandleError(STORE_POLICY_ERROR, callback);
134    return;
135  }
136
137  scoped_ptr<em::PolicyData> policy = AssemblePolicy(*device_settings_);
138  if (!policy) {
139    HandleError(STORE_POLICY_ERROR, callback);
140    return;
141  }
142
143  policy->set_management_mode(management_mode);
144  policy->set_request_token(request_token);
145  policy->set_device_id(device_id);
146
147  EnqueueSignAndStore(policy.Pass(), callback);
148}
149
150void DeviceSettingsService::Store(scoped_ptr<em::PolicyFetchResponse> policy,
151                                  const base::Closure& callback) {
152  Enqueue(
153      new StoreSettingsOperation(
154          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
155                     weak_factory_.GetWeakPtr(),
156                     callback),
157          policy.Pass()));
158}
159
160DeviceSettingsService::OwnershipStatus
161    DeviceSettingsService::GetOwnershipStatus() {
162  if (public_key_)
163    return public_key_->is_loaded() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
164  return OWNERSHIP_UNKNOWN;
165}
166
167void DeviceSettingsService::GetOwnershipStatusAsync(
168    const OwnershipStatusCallback& callback) {
169  if (public_key_) {
170    // If there is a key, report status immediately.
171    base::MessageLoop::current()->PostTask(
172        FROM_HERE, base::Bind(callback, GetOwnershipStatus()));
173  } else {
174    // If the key hasn't been loaded yet, enqueue the callback to be fired when
175    // the next SessionManagerOperation completes. If no operation is pending,
176    // start a load operation to fetch the key and report the result.
177    pending_ownership_status_callbacks_.push_back(callback);
178    if (pending_operations_.empty())
179      EnqueueLoad(false);
180  }
181}
182
183bool DeviceSettingsService::HasPrivateOwnerKey() {
184  return delegate_ && delegate_->IsOwner();
185}
186
187void DeviceSettingsService::InitOwner(
188    const std::string& username,
189    const base::WeakPtr<PrivateKeyDelegate>& delegate) {
190  if (!username_.empty())
191    return;
192  username_ = username;
193  delegate_ = delegate;
194
195  EnsureReload(true);
196}
197
198const std::string& DeviceSettingsService::GetUsername() const {
199  return username_;
200}
201
202void DeviceSettingsService::AddObserver(Observer* observer) {
203  observers_.AddObserver(observer);
204}
205
206void DeviceSettingsService::RemoveObserver(Observer* observer) {
207  observers_.RemoveObserver(observer);
208}
209
210void DeviceSettingsService::OwnerKeySet(bool success) {
211  if (!success) {
212    LOG(ERROR) << "Owner key change failed.";
213    return;
214  }
215
216  public_key_ = NULL;
217  EnsureReload(true);
218}
219
220void DeviceSettingsService::PropertyChangeComplete(bool success) {
221  if (!success) {
222    LOG(ERROR) << "Policy update failed.";
223    return;
224  }
225
226  EnsureReload(false);
227}
228
229void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) {
230  pending_operations_.push_back(operation);
231  if (pending_operations_.front() == operation)
232    StartNextOperation();
233}
234
235void DeviceSettingsService::EnqueueLoad(bool force_key_load) {
236  SessionManagerOperation* operation =
237      new LoadSettingsOperation(
238          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
239                     weak_factory_.GetWeakPtr(),
240                     base::Closure()));
241  operation->set_force_key_load(force_key_load);
242  operation->set_username(username_);
243  operation->set_delegate(delegate_);
244  Enqueue(operation);
245}
246
247void DeviceSettingsService::EnqueueSignAndStore(
248    scoped_ptr<em::PolicyData> policy,
249    const base::Closure& callback) {
250  SignAndStoreSettingsOperation* operation = new SignAndStoreSettingsOperation(
251      base::Bind(&DeviceSettingsService::HandleCompletedOperation,
252                 weak_factory_.GetWeakPtr(),
253                 callback),
254      policy.Pass());
255  operation->set_delegate(delegate_);
256  Enqueue(operation);
257}
258
259void DeviceSettingsService::EnsureReload(bool force_key_load) {
260  if (!pending_operations_.empty()) {
261    pending_operations_.front()->set_username(username_);
262    pending_operations_.front()->set_delegate(delegate_);
263    pending_operations_.front()->RestartLoad(force_key_load);
264  } else {
265    EnqueueLoad(force_key_load);
266  }
267}
268
269void DeviceSettingsService::StartNextOperation() {
270  if (!pending_operations_.empty() &&
271      session_manager_client_ &&
272      owner_key_util_.get()) {
273    pending_operations_.front()->Start(
274        session_manager_client_, owner_key_util_, public_key_);
275  }
276}
277
278void DeviceSettingsService::HandleCompletedOperation(
279    const base::Closure& callback,
280    SessionManagerOperation* operation,
281    Status status) {
282  DCHECK_EQ(operation, pending_operations_.front());
283  store_status_ = status;
284
285  OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN;
286  scoped_refptr<PublicKey> new_key(operation->public_key());
287  if (new_key.get()) {
288    ownership_status = new_key->is_loaded() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
289  } else {
290    NOTREACHED() << "Failed to determine key status.";
291  }
292
293  bool new_owner_key = false;
294  if (public_key_.get() != new_key.get()) {
295    public_key_ = new_key;
296    new_owner_key = true;
297  }
298
299  if (status == STORE_SUCCESS) {
300    policy_data_ = operation->policy_data().Pass();
301    device_settings_ = operation->device_settings().Pass();
302    load_retries_left_ = kMaxLoadRetries;
303  } else if (status != STORE_KEY_UNAVAILABLE) {
304    LOG(ERROR) << "Session manager operation failed: " << status;
305    // Validation errors can be temporary if the rtc has gone on holiday for a
306    // short while. So we will retry such loads for up to 10 minutes.
307    if (status == STORE_TEMP_VALIDATION_ERROR) {
308      if (load_retries_left_ > 0) {
309        load_retries_left_--;
310        LOG(ERROR) << "A re-load has been scheduled due to a validation error.";
311        content::BrowserThread::PostDelayedTask(
312            content::BrowserThread::UI,
313            FROM_HERE,
314            base::Bind(&DeviceSettingsService::Load, base::Unretained(this)),
315            base::TimeDelta::FromMilliseconds(kLoadRetryDelayMs));
316      } else {
317        // Once we've given up retrying, the validation error is not temporary
318        // anymore.
319        store_status_ = STORE_VALIDATION_ERROR;
320      }
321    }
322  }
323
324  if (new_owner_key) {
325    FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged());
326    content::NotificationService::current()->Notify(
327        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
328        content::Source<DeviceSettingsService>(this),
329        content::NotificationService::NoDetails());
330  }
331
332  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
333
334  std::vector<OwnershipStatusCallback> callbacks;
335  callbacks.swap(pending_ownership_status_callbacks_);
336  for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin());
337       iter != callbacks.end(); ++iter) {
338    iter->Run(ownership_status);
339  }
340
341  // The completion callback happens after the notification so clients can
342  // filter self-triggered updates.
343  if (!callback.is_null())
344    callback.Run();
345
346  // Only remove the pending operation here, so new operations triggered by any
347  // of the callbacks above are queued up properly.
348  pending_operations_.pop_front();
349  delete operation;
350
351  StartNextOperation();
352}
353
354void DeviceSettingsService::HandleError(Status status,
355                                        const base::Closure& callback) {
356  store_status_ = status;
357
358  LOG(ERROR) << "Session manager operation failed: " << status;
359
360  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
361
362  // The completion callback happens after the notification so clients can
363  // filter self-triggered updates.
364  if (!callback.is_null())
365    callback.Run();
366}
367
368scoped_ptr<em::PolicyData> DeviceSettingsService::AssemblePolicy(
369    const em::ChromeDeviceSettingsProto& settings) const {
370  scoped_ptr<em::PolicyData> policy(new em::PolicyData());
371  if (policy_data_) {
372    // Preserve management settings.
373    if (policy_data_->has_management_mode())
374      policy->set_management_mode(policy_data_->management_mode());
375    if (policy_data_->has_request_token())
376      policy->set_request_token(policy_data_->request_token());
377    if (policy_data_->has_device_id())
378      policy->set_device_id(policy_data_->device_id());
379  } else {
380    // If there's no previous policy data, this is the first time the device
381    // setting is set. We set the management mode to NOT_MANAGED initially.
382    policy->set_management_mode(em::PolicyData::NOT_MANAGED);
383  }
384  policy->set_policy_type(policy::dm_protocol::kChromeDevicePolicyType);
385  policy->set_timestamp((base::Time::Now() - base::Time::UnixEpoch()).
386                        InMilliseconds());
387  policy->set_username(username_);
388  if (!settings.SerializeToString(policy->mutable_policy_value()))
389    return scoped_ptr<em::PolicyData>();
390
391  return policy.Pass();
392}
393
394em::PolicyData::ManagementMode DeviceSettingsService::GetManagementMode()
395    const {
396  if (policy_data_ && policy_data_->has_management_mode())
397    return policy_data_->management_mode();
398  return em::PolicyData::NOT_MANAGED;
399}
400
401bool DeviceSettingsService::CheckManagementModeTransition(
402    em::PolicyData::ManagementMode new_mode) const {
403  em::PolicyData::ManagementMode current_mode = GetManagementMode();
404
405  // Mode is not changed.
406  if (current_mode == new_mode)
407    return true;
408
409  switch (current_mode) {
410    case em::PolicyData::NOT_MANAGED:
411      // For consumer management enrollment.
412      return new_mode == em::PolicyData::CONSUMER_MANAGED;
413
414    case em::PolicyData::ENTERPRISE_MANAGED:
415      // Management mode cannot be set when it is currently ENTERPRISE_MANAGED.
416      return false;
417
418    case em::PolicyData::CONSUMER_MANAGED:
419      // For consumer management unenrollment.
420      return new_mode == em::PolicyData::NOT_MANAGED;
421  }
422
423  NOTREACHED();
424  return false;
425}
426
427ScopedTestDeviceSettingsService::ScopedTestDeviceSettingsService() {
428  DeviceSettingsService::Initialize();
429}
430
431ScopedTestDeviceSettingsService::~ScopedTestDeviceSettingsService() {
432  // Clean pending operations.
433  DeviceSettingsService::Get()->UnsetSessionManager();
434  DeviceSettingsService::Shutdown();
435}
436
437}  // namespace chromeos
438