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