Home | History | Annotate | Download | only in login
      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