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