Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/login/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/login/owner_key_util.h" | |
| 14 #include "chrome/browser/chromeos/login/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 | |
| 23 namespace em = enterprise_management; | |
| 24 | |
| 25 namespace chromeos { | |
| 26 | |
| 27 static base::LazyInstance<DeviceSettingsService> g_device_settings_service = | |
| 28 LAZY_INSTANCE_INITIALIZER; | |
| 29 | |
| 30 OwnerKey::OwnerKey(scoped_ptr<std::vector<uint8> > public_key, | |
| 31 scoped_ptr<crypto::RSAPrivateKey> private_key) | |
| 32 : public_key_(public_key.Pass()), | |
| 33 private_key_(private_key.Pass()) {} | |
| 34 | |
| 35 OwnerKey::~OwnerKey() {} | |
| 36 | |
| 37 DeviceSettingsService::Observer::~Observer() {} | |
| 38 | |
| 39 DeviceSettingsService::DeviceSettingsService() | |
| 40 : session_manager_client_(NULL), | |
| 41 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | |
| 42 store_status_(STORE_SUCCESS), | |
| 43 ownership_status_(OWNERSHIP_UNKNOWN) {} | |
| 44 | |
| 45 DeviceSettingsService::~DeviceSettingsService() { | |
| 46 STLDeleteContainerPointers(pending_operations_.begin(), | |
| 47 pending_operations_.end()); | |
| 48 pending_operations_.clear(); | |
| 49 } | |
| 50 | |
| 51 // static | |
| 52 DeviceSettingsService* DeviceSettingsService::Get() { | |
| 53 return g_device_settings_service.Pointer(); | |
| 54 } | |
| 55 | |
| 56 void DeviceSettingsService::Initialize( | |
| 57 SessionManagerClient* session_manager_client, | |
| 58 scoped_refptr<OwnerKeyUtil> owner_key_util) { | |
| 59 DCHECK(session_manager_client); | |
| 60 DCHECK(owner_key_util.get()); | |
| 61 DCHECK(!session_manager_client_); | |
| 62 DCHECK(!owner_key_util_.get()); | |
| 63 | |
| 64 session_manager_client_ = session_manager_client; | |
| 65 owner_key_util_ = owner_key_util; | |
| 66 | |
| 67 session_manager_client_->AddObserver(this); | |
| 68 | |
| 69 StartNextOperation(); | |
| 70 } | |
| 71 | |
| 72 void DeviceSettingsService::Shutdown() { | |
| 73 session_manager_client_->RemoveObserver(this); | |
| 74 session_manager_client_ = NULL; | |
| 75 owner_key_util_ = NULL; | |
| 76 } | |
| 77 | |
| 78 scoped_refptr<OwnerKey> DeviceSettingsService::GetOwnerKey() { | |
| 79 return owner_key_; | |
| 80 } | |
| 81 | |
| 82 void DeviceSettingsService::Load() { | |
| 83 EnqueueLoad(false); | |
| 84 } | |
| 85 | |
| 86 void DeviceSettingsService::SignAndStore( | |
| 87 scoped_ptr<em::ChromeDeviceSettingsProto> settings, | |
| 88 const base::Closure& callback) { | |
| 89 Enqueue( | |
| 90 new SignAndStoreSettingsOperation( | |
| 91 base::Bind(&DeviceSettingsService::HandleCompletedOperation, | |
| 92 weak_factory_.GetWeakPtr(), | |
| 93 callback), | |
| 94 settings.Pass(), | |
| 95 username_)); | |
| 96 } | |
| 97 | |
| 98 void DeviceSettingsService::Store(const std::string& policy_blob, | |
| 99 const base::Closure& callback) { | |
| 100 Enqueue( | |
| 101 new StoreSettingsOperation( | |
| 102 base::Bind(&DeviceSettingsService::HandleCompletedOperation, | |
| 103 weak_factory_.GetWeakPtr(), | |
| 104 callback), | |
| 105 policy_blob)); | |
| 106 } | |
| 107 | |
| 108 DeviceSettingsService::OwnershipStatus | |
| 109 DeviceSettingsService::GetOwnershipStatus(bool blocking) { | |
| 110 OwnershipStatus status = OWNERSHIP_UNKNOWN; | |
| 111 bool is_owned = false; | |
| 112 if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
| 113 ownership_status_lock_.Acquire(); | |
| 114 status = ownership_status_; | |
| 115 ownership_status_lock_.Release(); | |
| 116 if (status != OWNERSHIP_UNKNOWN || !blocking) | |
| 117 return status; | |
| 118 // Under common usage there is very short lapse of time when ownership | |
| 119 // status is still unknown after constructing DeviceSettingsService. | |
| 120 LOG(ERROR) << "Blocking on UI thread in DeviceSettingsService::GetStatus"; | |
| 121 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 122 is_owned = owner_key_util_->IsPublicKeyPresent(); | |
| 123 } else { | |
| 124 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 125 is_owned = owner_key_util_->IsPublicKeyPresent(); | |
| 126 } | |
| 127 status = is_owned ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; | |
| 128 SetOwnershipStatus(status); | |
| 129 return status; | |
| 130 } | |
| 131 | |
| 132 void 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())); | |
| 141 } else { | |
| 142 // If the key hasn't been loaded yet, trigger a policy load operation or | |
| 143 // wait for an existing operation to finish. | |
| 144 pending_ownership_status_callbacks_.push_back(callback); | |
| 145 if (pending_operations_.empty()) | |
| 146 EnqueueLoad(false); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 bool DeviceSettingsService::HasPrivateOwnerKey() { | |
| 151 return owner_key_.get() && owner_key_->private_key(); | |
| 152 } | |
| 153 | |
| 154 void DeviceSettingsService::SetUsername(const std::string& username) { | |
| 155 username_ = username; | |
| 156 | |
| 157 // The private key may have become available, so force a key reload. | |
| 158 OwnerKeySet(true); | |
| 159 } | |
| 160 | |
| 161 const std::string& DeviceSettingsService::GetUsername() const { | |
| 162 return username_; | |
| 163 } | |
| 164 | |
| 165 void DeviceSettingsService::AddObserver(Observer* observer) { | |
| 166 observers_.AddObserver(observer); | |
| 167 } | |
| 168 | |
| 169 void DeviceSettingsService::RemoveObserver(Observer* observer) { | |
| 170 observers_.RemoveObserver(observer); | |
| 171 } | |
| 172 | |
| 173 void DeviceSettingsService::OwnerKeySet(bool success) { | |
| 174 if (!success) { | |
| 175 LOG(ERROR) << "Owner key change failed."; | |
| 176 return; | |
| 177 } | |
| 178 | |
| 179 owner_key_ = NULL; | |
| 180 EnsureReload(true); | |
| 181 } | |
| 182 | |
| 183 void DeviceSettingsService::PropertyChangeComplete(bool success) { | |
| 184 if (!success) { | |
| 185 LOG(ERROR) << "Policy update failed."; | |
| 186 return; | |
| 187 } | |
| 188 | |
| 189 EnsureReload(false); | |
| 190 } | |
| 191 | |
| 192 void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) { | |
| 193 pending_operations_.push_back(operation); | |
| 194 if (pending_operations_.front() == operation) | |
| 195 StartNextOperation(); | |
| 196 } | |
| 197 | |
| 198 void DeviceSettingsService::EnqueueLoad(bool force_key_load) { | |
| 199 SessionManagerOperation* operation = | |
| 200 new LoadSettingsOperation( | |
| 201 base::Bind(&DeviceSettingsService::HandleCompletedOperation, | |
| 202 weak_factory_.GetWeakPtr(), | |
| 203 base::Closure())); | |
| 204 operation->set_force_key_load(force_key_load); | |
| 205 Enqueue(operation); | |
| 206 } | |
| 207 | |
| 208 void DeviceSettingsService::EnsureReload(bool force_key_load) { | |
| 209 if (!pending_operations_.empty()) | |
| 210 pending_operations_.front()->RestartLoad(force_key_load); | |
|
pastarmovj
2012/07/30 12:19:19
What if the operation is a store op?
Mattias Nissler (ping if slow)
2012/07/31 13:02:15
If the Store op is still storing data, it'll not b
| |
| 211 else | |
| 212 EnqueueLoad(force_key_load); | |
| 213 } | |
| 214 | |
| 215 void DeviceSettingsService::StartNextOperation() { | |
| 216 if (!pending_operations_.empty() && | |
| 217 session_manager_client_ && | |
| 218 owner_key_util_.get()) { | |
| 219 pending_operations_.front()->Start(session_manager_client_, | |
| 220 owner_key_util_, owner_key_); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void DeviceSettingsService::HandleCompletedOperation( | |
| 225 const base::Closure& callback, | |
| 226 SessionManagerOperation* operation, | |
| 227 Status status) { | |
| 228 DCHECK_EQ(operation, pending_operations_.front()); | |
| 229 store_status_ = status; | |
| 230 | |
| 231 OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN; | |
| 232 bool is_owner = false; | |
| 233 scoped_refptr<OwnerKey> new_key(operation->owner_key()); | |
| 234 if (new_key.get()) { | |
| 235 ownership_status = | |
| 236 new_key->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; | |
| 237 is_owner = new_key->private_key(); | |
|
pastarmovj
2012/07/30 12:19:19
I think this will be clearer if you wrote down the
Mattias Nissler (ping if slow)
2012/07/31 13:02:15
Done.
| |
| 238 } else { | |
| 239 NOTREACHED() << "Failed to determine key status."; | |
| 240 } | |
| 241 SetOwnershipStatus(ownership_status); | |
| 242 | |
| 243 if (owner_key_.get() != new_key.get()) { | |
|
pastarmovj
2012/07/30 12:19:19
If I understand this right this code will now trig
Mattias Nissler (ping if slow)
2012/07/31 13:02:15
Yes, I verified key rotation thoroughly, and it st
| |
| 244 owner_key_ = new_key; | |
| 245 FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged()); | |
| 246 content::NotificationService::current()->Notify( | |
| 247 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, | |
| 248 content::Source<DeviceSettingsService>(this), | |
| 249 content::NotificationService::NoDetails()); | |
| 250 } | |
| 251 | |
| 252 if (status == STORE_SUCCESS) { | |
| 253 policy_data_ = operation->policy_data().Pass(); | |
| 254 device_settings_ = operation->device_settings().Pass(); | |
| 255 } else if (status != STORE_KEY_UNAVAILABLE) { | |
| 256 LOG(ERROR) << "Session manager operation failed: " << status; | |
| 257 } | |
| 258 | |
| 259 FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated()); | |
| 260 | |
| 261 std::vector<OwnershipStatusCallback> callbacks; | |
| 262 callbacks.swap(pending_ownership_status_callbacks_); | |
| 263 for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin()); | |
| 264 iter != callbacks.end(); ++iter) { | |
| 265 iter->Run(ownership_status, is_owner); | |
| 266 } | |
| 267 | |
| 268 // The completion callback happens after the notification so clients can | |
| 269 // filter self-triggered updates. | |
| 270 if (!callback.is_null()) | |
| 271 callback.Run(); | |
| 272 | |
| 273 // Only remove the pending operation here, so new operations triggered by any | |
| 274 // of the callbacks above are queued up properly. | |
| 275 pending_operations_.pop_front(); | |
| 276 delete operation; | |
| 277 | |
| 278 StartNextOperation(); | |
| 279 } | |
| 280 | |
| 281 void DeviceSettingsService::SetOwnershipStatus(OwnershipStatus new_status) { | |
| 282 DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE); | |
| 283 base::AutoLock lk(ownership_status_lock_); | |
| 284 ownership_status_ = new_status; | |
| 285 } | |
| 286 | |
| 287 } // namespace chromeos | |
| OLD | NEW |