• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
GetSharedInstance()24 OwnershipService* OwnershipService::GetSharedInstance() {
25   return g_ownership_service.Pointer();
26 }
27 
OwnershipService()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 
~OwnershipService()39 OwnershipService::~OwnershipService() {}
40 
Prewarm()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 
set_cached_policy(const em::PolicyData & pol)59 void OwnershipService::set_cached_policy(const em::PolicyData& pol) {
60   policy_.reset(pol.New());
61   policy_->CheckTypeAndMergeFrom(pol);
62 }
63 
has_cached_policy()64 bool OwnershipService::has_cached_policy() {
65   return policy_.get();
66 }
67 
cached_policy()68 const em::PolicyData& OwnershipService::cached_policy() {
69   return *(policy_.get());
70 }
71 
IsAlreadyOwned()72 bool OwnershipService::IsAlreadyOwned() {
73   return file_util::PathExists(utils_->GetOwnerKeyFilePath());
74 }
75 
GetStatus(bool blocking)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 
StartLoadOwnerKeyAttempt()99 void OwnershipService::StartLoadOwnerKeyAttempt() {
100   BrowserThread::PostTask(
101       BrowserThread::FILE, FROM_HERE,
102       NewRunnableFunction(&TryLoadOwnerKeyAttempt, this));
103 }
104 
StartUpdateOwnerKey(const std::vector<uint8> & new_key,OwnerManager::KeyUpdateDelegate * d)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 
StartSigningAttempt(const std::string & data,OwnerManager::Delegate * d)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 
StartVerifyAttempt(const std::string & data,const std::vector<uint8> & signature,OwnerManager::Delegate * d)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
CurrentUserIsOwner()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
UpdateOwnerKey(OwnershipService * service,const BrowserThread::ID thread_id,const std::vector<uint8> & new_key,OwnerManager::KeyUpdateDelegate * d)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
TryLoadOwnerKeyAttempt(OwnershipService * service)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
TrySigningAttempt(OwnershipService * service,const BrowserThread::ID thread_id,const std::string & data,OwnerManager::Delegate * d)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
TryVerifyAttempt(OwnershipService * service,const BrowserThread::ID thread_id,const std::string & data,const std::vector<uint8> & signature,OwnerManager::Delegate * d)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
FailAttempt(OwnerManager::Delegate * d)222 void OwnershipService::FailAttempt(OwnerManager::Delegate* d) {
223   d->OnKeyOpComplete(OwnerManager::KEY_UNAVAILABLE, std::vector<uint8>());
224 }
225 
FetchStatus()226 void OwnershipService::FetchStatus() {
227   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
228   Status status = IsAlreadyOwned() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
229   SetStatus(status);
230 }
231 
SetStatus(Status new_status)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