| 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/ownership_service.h" | |
| 6 | |
| 7 #include "base/command_line.h" | |
| 8 #include "base/bind.h" | |
| 9 #include "base/bind_helpers.h" | |
| 10 #include "base/file_path.h" | |
| 11 #include "base/file_util.h" | |
| 12 #include "base/lazy_instance.h" | |
| 13 #include "base/synchronization/lock.h" | |
| 14 #include "base/task_runner_util.h" | |
| 15 #include "chrome/browser/browser_process.h" | |
| 16 #include "chrome/common/chrome_notification_types.h" | |
| 17 #include "chrome/common/chrome_switches.h" | |
| 18 #include "content/public/browser/browser_thread.h" | |
| 19 #include "content/public/browser/notification_service.h" | |
| 20 | |
| 21 using content::BrowserThread; | |
| 22 | |
| 23 namespace chromeos { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 typedef std::pair<OwnershipService::Status, bool> OwnershipStatusReturnType; | |
| 28 | |
| 29 // Makes the check for ownership on the FILE thread and stores the result in the | |
| 30 // provided pointers. | |
| 31 OwnershipStatusReturnType CheckStatusOnFileThread() { | |
| 32 bool current_user_is_owner; | |
| 33 OwnershipService::Status status; | |
| 34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 35 status = OwnershipService::GetSharedInstance()->IsAlreadyOwned() ? | |
| 36 OwnershipService::OWNERSHIP_TAKEN : OwnershipService::OWNERSHIP_NONE; | |
| 37 current_user_is_owner = | |
| 38 OwnershipService::GetSharedInstance()->IsCurrentUserOwner(); | |
| 39 return OwnershipStatusReturnType(status, current_user_is_owner); | |
| 40 } | |
| 41 | |
| 42 } // namespace | |
| 43 | |
| 44 static base::LazyInstance<OwnershipService> g_ownership_service = | |
| 45 LAZY_INSTANCE_INITIALIZER; | |
| 46 | |
| 47 // static | |
| 48 OwnershipService* OwnershipService::GetSharedInstance() { | |
| 49 return g_ownership_service.Pointer(); | |
| 50 } | |
| 51 | |
| 52 OwnershipService::OwnershipService() | |
| 53 : manager_(new OwnerManager), | |
| 54 utils_(OwnerKeyUtils::Create()), | |
| 55 ownership_status_(OWNERSHIP_UNKNOWN), | |
| 56 force_ownership_(CommandLine::ForCurrentProcess()->HasSwitch( | |
| 57 switches::kStubCrosSettings)) { | |
| 58 notification_registrar_.Add( | |
| 59 this, | |
| 60 chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, | |
| 61 content::NotificationService::AllSources()); | |
| 62 } | |
| 63 | |
| 64 OwnershipService::~OwnershipService() {} | |
| 65 | |
| 66 void OwnershipService::Prewarm() { | |
| 67 // Note that we cannot prewarm in constructor because in current codebase | |
| 68 // object is created before spawning threads. | |
| 69 if (g_ownership_service == this) { | |
| 70 // Start getting ownership status. | |
| 71 BrowserThread::PostTask( | |
| 72 BrowserThread::FILE, FROM_HERE, | |
| 73 base::Bind(&OwnershipService::FetchStatus, base::Unretained(this))); | |
| 74 } else { | |
| 75 // This can happen only for particular test: OwnershipServiceTest. It uses | |
| 76 // mocks and for that uses OwnershipService not as a regular singleton but | |
| 77 // as a resurrecting object. This behaviour conflicts with | |
| 78 // base::Unretained(). So avoid posting task in those circumstances | |
| 79 // in order to avoid accessing already deleted object. | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 bool OwnershipService::IsAlreadyOwned() { | |
| 84 return file_util::PathExists(utils_->GetOwnerKeyFilePath()); | |
| 85 } | |
| 86 | |
| 87 OwnershipService::Status OwnershipService::GetStatus(bool blocking) { | |
| 88 if (force_ownership_) | |
| 89 return OWNERSHIP_TAKEN; | |
| 90 Status status = OWNERSHIP_UNKNOWN; | |
| 91 bool is_owned = false; | |
| 92 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 93 ownership_status_lock_.Acquire(); | |
| 94 status = ownership_status_; | |
| 95 ownership_status_lock_.Release(); | |
| 96 if (status != OWNERSHIP_UNKNOWN || !blocking) | |
| 97 return status; | |
| 98 // Under common usage there is very short lapse of time when ownership | |
| 99 // status is still unknown after constructing OwnershipService. | |
| 100 LOG(ERROR) << "Blocking on UI thread in OwnershipService::GetStatus"; | |
| 101 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 102 is_owned = IsAlreadyOwned(); | |
| 103 } else { | |
| 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 105 is_owned = IsAlreadyOwned(); | |
| 106 } | |
| 107 status = is_owned ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; | |
| 108 SetStatus(status); | |
| 109 return status; | |
| 110 } | |
| 111 | |
| 112 void OwnershipService::StartLoadOwnerKeyAttempt() { | |
| 113 BrowserThread::PostTask( | |
| 114 BrowserThread::FILE, FROM_HERE, | |
| 115 base::Bind(&TryLoadOwnerKeyAttempt, base::Unretained(this))); | |
| 116 } | |
| 117 | |
| 118 void OwnershipService::StartUpdateOwnerKey(const std::vector<uint8>& new_key, | |
| 119 OwnerManager::KeyUpdateDelegate* d) { | |
| 120 BrowserThread::ID thread_id; | |
| 121 if (!BrowserThread::GetCurrentThreadIdentifier(&thread_id)) | |
| 122 thread_id = BrowserThread::UI; | |
| 123 BrowserThread::PostTask( | |
| 124 BrowserThread::FILE, FROM_HERE, | |
| 125 base::Bind(&OwnershipService::UpdateOwnerKey, base::Unretained(this), | |
| 126 thread_id, new_key, d)); | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 void OwnershipService::StartSigningAttempt(const std::string& data, | |
| 131 OwnerManager::Delegate* d) { | |
| 132 BrowserThread::ID thread_id; | |
| 133 if (!BrowserThread::GetCurrentThreadIdentifier(&thread_id)) | |
| 134 thread_id = BrowserThread::UI; | |
| 135 BrowserThread::PostTask( | |
| 136 BrowserThread::FILE, FROM_HERE, | |
| 137 base::Bind(&OwnershipService::TrySigningAttempt, base::Unretained(this), | |
| 138 thread_id, data, d)); | |
| 139 return; | |
| 140 } | |
| 141 | |
| 142 void OwnershipService::StartVerifyAttempt(const std::string& data, | |
| 143 const std::vector<uint8>& signature, | |
| 144 OwnerManager::Delegate* d) { | |
| 145 BrowserThread::ID thread_id; | |
| 146 if (!BrowserThread::GetCurrentThreadIdentifier(&thread_id)) | |
| 147 thread_id = BrowserThread::UI; | |
| 148 BrowserThread::PostTask( | |
| 149 BrowserThread::FILE, FROM_HERE, | |
| 150 base::Bind(&OwnershipService::TryVerifyAttempt, base::Unretained(this), | |
| 151 thread_id, data, signature, d)); | |
| 152 return; | |
| 153 } | |
| 154 | |
| 155 void OwnershipService::Observe(int type, | |
| 156 const content::NotificationSource& source, | |
| 157 const content::NotificationDetails& details) { | |
| 158 if (type == chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { | |
| 159 SetStatus(OWNERSHIP_TAKEN); | |
| 160 notification_registrar_.RemoveAll(); | |
| 161 } else { | |
| 162 NOTREACHED(); | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 bool OwnershipService::IsCurrentUserOwner() { | |
| 167 if (force_ownership_) | |
| 168 return true; | |
| 169 // If this user has the private key associated with the owner's | |
| 170 // public key, this user is the owner. | |
| 171 return IsAlreadyOwned() && manager_->EnsurePrivateKey(); | |
| 172 } | |
| 173 | |
| 174 void OwnershipService::GetStatusAsync(const Callback& callback) { | |
| 175 PostTaskAndReplyWithResult( | |
| 176 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | |
| 177 FROM_HERE, | |
| 178 base::Bind(&CheckStatusOnFileThread), | |
| 179 base::Bind(&OwnershipService::ReturnStatus, | |
| 180 callback)); | |
| 181 } | |
| 182 | |
| 183 | |
| 184 // static | |
| 185 void OwnershipService::UpdateOwnerKey(OwnershipService* service, | |
| 186 const BrowserThread::ID thread_id, | |
| 187 const std::vector<uint8>& new_key, | |
| 188 OwnerManager::KeyUpdateDelegate* d) { | |
| 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 190 service->manager()->UpdateOwnerKey(thread_id, new_key, d); | |
| 191 } | |
| 192 | |
| 193 // static | |
| 194 void OwnershipService::TryLoadOwnerKeyAttempt(OwnershipService* service) { | |
| 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 196 if (!service->IsAlreadyOwned()) { | |
| 197 VLOG(1) << "Device not yet owned"; | |
| 198 return; | |
| 199 } | |
| 200 service->manager()->LoadOwnerKey(); | |
| 201 } | |
| 202 | |
| 203 // static | |
| 204 void OwnershipService::TrySigningAttempt(OwnershipService* service, | |
| 205 const BrowserThread::ID thread_id, | |
| 206 const std::string& data, | |
| 207 OwnerManager::Delegate* d) { | |
| 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 209 if (!service->IsAlreadyOwned()) { | |
| 210 LOG(ERROR) << "Device not yet owned"; | |
| 211 BrowserThread::PostTask( | |
| 212 thread_id, FROM_HERE, | |
| 213 base::Bind(&OwnershipService::FailAttempt, d)); | |
| 214 return; | |
| 215 } | |
| 216 service->manager()->Sign(thread_id, data, d); | |
| 217 } | |
| 218 | |
| 219 // static | |
| 220 void OwnershipService::TryVerifyAttempt(OwnershipService* service, | |
| 221 const BrowserThread::ID thread_id, | |
| 222 const std::string& data, | |
| 223 const std::vector<uint8>& signature, | |
| 224 OwnerManager::Delegate* d) { | |
| 225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 226 if (!service->IsAlreadyOwned()) { | |
| 227 LOG(ERROR) << "Device not yet owned"; | |
| 228 BrowserThread::PostTask( | |
| 229 thread_id, FROM_HERE, | |
| 230 base::Bind(&OwnershipService::FailAttempt, d)); | |
| 231 return; | |
| 232 } | |
| 233 service->manager()->Verify(thread_id, data, signature, d); | |
| 234 } | |
| 235 | |
| 236 // static | |
| 237 void OwnershipService::FailAttempt(OwnerManager::Delegate* d) { | |
| 238 d->OnKeyOpComplete(OwnerManager::KEY_UNAVAILABLE, std::vector<uint8>()); | |
| 239 } | |
| 240 | |
| 241 void OwnershipService::FetchStatus() { | |
| 242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 243 Status status = IsAlreadyOwned() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; | |
| 244 SetStatus(status); | |
| 245 } | |
| 246 | |
| 247 void OwnershipService::SetStatus(Status new_status) { | |
| 248 DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE); | |
| 249 base::AutoLock lk(ownership_status_lock_); | |
| 250 ownership_status_ = new_status; | |
| 251 } | |
| 252 | |
| 253 // static | |
| 254 void OwnershipService::ReturnStatus(const Callback& callback, | |
| 255 OwnershipStatusReturnType status) { | |
| 256 callback.Run(status.first, status.second); | |
| 257 } | |
| 258 | |
| 259 } // namespace chromeos | |
| OLD | NEW |