// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/login/ownership_service.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/lazy_instance.h" #include "base/synchronization/lock.h" #include "chrome/browser/browser_process.h" #include "content/browser/browser_thread.h" // We want to use NewRunnableMethod for non-static methods of this class but // need to disable reference counting since it is singleton. DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::OwnershipService); namespace chromeos { static base::LazyInstance g_ownership_service( base::LINKER_INITIALIZED); // static OwnershipService* OwnershipService::GetSharedInstance() { return g_ownership_service.Pointer(); } OwnershipService::OwnershipService() : manager_(new OwnerManager), utils_(OwnerKeyUtils::Create()), policy_(NULL), ownership_status_(OWNERSHIP_UNKNOWN) { notification_registrar_.Add( this, NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, NotificationService::AllSources()); } OwnershipService::~OwnershipService() {} void OwnershipService::Prewarm() { // Note that we cannot prewarm in constructor because in current codebase // object is created before spawning threads. if (g_ownership_service == this) { // Start getting ownership status. BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod(this, &OwnershipService::FetchStatus)); } else { // This can happen only for particular test: OwnershipServiceTest. It uses // mocks and for that uses OwnershipService not as a regular singleton but // as a resurrecting object. This behaviour conflicts with // DISABLE_RUNNABLE_METHOD_REFCOUNT. So avoid posting task in those // circumstances in order to avoid accessing already deleted object. } } void OwnershipService::set_cached_policy(const em::PolicyData& pol) { policy_.reset(pol.New()); policy_->CheckTypeAndMergeFrom(pol); } bool OwnershipService::has_cached_policy() { return policy_.get(); } const em::PolicyData& OwnershipService::cached_policy() { return *(policy_.get()); } bool OwnershipService::IsAlreadyOwned() { return file_util::PathExists(utils_->GetOwnerKeyFilePath()); } OwnershipService::Status OwnershipService::GetStatus(bool blocking) { Status status = OWNERSHIP_UNKNOWN; bool is_owned = false; if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { ownership_status_lock_.Acquire(); status = ownership_status_; ownership_status_lock_.Release(); if (status != OWNERSHIP_UNKNOWN || !blocking) return status; // Under common usage there is very short lapse of time when ownership // status is still unknown after constructing OwnershipService. LOG(ERROR) << "Blocking on UI thread in OwnershipService::GetStatus"; base::ThreadRestrictions::ScopedAllowIO allow_io; is_owned = IsAlreadyOwned(); } else { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); is_owned = IsAlreadyOwned(); } status = is_owned ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; SetStatus(status); return status; } void OwnershipService::StartLoadOwnerKeyAttempt() { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableFunction(&TryLoadOwnerKeyAttempt, this)); } void OwnershipService::StartUpdateOwnerKey(const std::vector& new_key, OwnerManager::KeyUpdateDelegate* d) { BrowserThread::ID thread_id; if (!BrowserThread::GetCurrentThreadIdentifier(&thread_id)) thread_id = BrowserThread::UI; BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableFunction(&OwnershipService::UpdateOwnerKey, this, thread_id, new_key, d)); return; } void OwnershipService::StartSigningAttempt(const std::string& data, OwnerManager::Delegate* d) { BrowserThread::ID thread_id; if (!BrowserThread::GetCurrentThreadIdentifier(&thread_id)) thread_id = BrowserThread::UI; BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableFunction(&OwnershipService::TrySigningAttempt, this, thread_id, data, d)); return; } void OwnershipService::StartVerifyAttempt(const std::string& data, const std::vector& signature, OwnerManager::Delegate* d) { BrowserThread::ID thread_id; if (!BrowserThread::GetCurrentThreadIdentifier(&thread_id)) thread_id = BrowserThread::UI; BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableFunction(&OwnershipService::TryVerifyAttempt, this, thread_id, data, signature, d)); return; } void OwnershipService::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { if (type.value == NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { SetStatus(OWNERSHIP_TAKEN); notification_registrar_.RemoveAll(); } else { NOTREACHED(); } } bool OwnershipService::CurrentUserIsOwner() { // If this user has the private key associated with the owner's // public key, this user is the owner. return IsAlreadyOwned() && manager_->EnsurePrivateKey(); } // static void OwnershipService::UpdateOwnerKey(OwnershipService* service, const BrowserThread::ID thread_id, const std::vector& new_key, OwnerManager::KeyUpdateDelegate* d) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); service->manager()->UpdateOwnerKey(thread_id, new_key, d); } // static void OwnershipService::TryLoadOwnerKeyAttempt(OwnershipService* service) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (!service->IsAlreadyOwned()) { VLOG(1) << "Device not yet owned"; return; } service->manager()->LoadOwnerKey(); } // static void OwnershipService::TrySigningAttempt(OwnershipService* service, const BrowserThread::ID thread_id, const std::string& data, OwnerManager::Delegate* d) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (!service->IsAlreadyOwned()) { LOG(ERROR) << "Device not yet owned"; BrowserThread::PostTask( thread_id, FROM_HERE, NewRunnableFunction(&OwnershipService::FailAttempt, d)); return; } service->manager()->Sign(thread_id, data, d); } // static void OwnershipService::TryVerifyAttempt(OwnershipService* service, const BrowserThread::ID thread_id, const std::string& data, const std::vector& signature, OwnerManager::Delegate* d) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (!service->IsAlreadyOwned()) { LOG(ERROR) << "Device not yet owned"; BrowserThread::PostTask( thread_id, FROM_HERE, NewRunnableFunction(&OwnershipService::FailAttempt, d)); return; } service->manager()->Verify(thread_id, data, signature, d); } // static void OwnershipService::FailAttempt(OwnerManager::Delegate* d) { d->OnKeyOpComplete(OwnerManager::KEY_UNAVAILABLE, std::vector()); } void OwnershipService::FetchStatus() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); Status status = IsAlreadyOwned() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE; SetStatus(status); } void OwnershipService::SetStatus(Status new_status) { DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE); base::AutoLock lk(ownership_status_lock_); ownership_status_ = new_status; } } // namespace chromeos