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