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