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/cros/login_library.h"
6
7 #include "base/message_loop.h"
8 #include "base/task.h"
9 #include "base/timer.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/chromeos/cros/cros_library.h"
12 #include "chrome/browser/chromeos/login/signed_settings.h"
13 #include "chrome/browser/chromeos/login/signed_settings_temp_storage.h"
14 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
15 #include "chrome/browser/prefs/pref_service.h"
16 #include "content/browser/browser_thread.h"
17 #include "content/common/notification_service.h"
18 #include "content/common/notification_type.h"
19
20 namespace em = enterprise_management;
21 namespace chromeos {
22
23 class LoginLibraryImpl : public LoginLibrary {
24 public:
LoginLibraryImpl()25 LoginLibraryImpl()
26 : job_restart_request_(NULL),
27 set_owner_key_callback_(NULL),
28 whitelist_op_callback_(NULL),
29 property_op_callback_(NULL) {
30 if (CrosLibrary::Get()->EnsureLoaded())
31 Init();
32 }
33
~LoginLibraryImpl()34 virtual ~LoginLibraryImpl() {
35 if (session_connection_) {
36 chromeos::DisconnectSession(session_connection_);
37 }
38 }
39
EmitLoginPromptReady()40 bool EmitLoginPromptReady() {
41 return chromeos::EmitLoginPromptReady();
42 }
43
CheckWhitelist(const std::string & email,std::vector<uint8> * OUT_signature)44 bool CheckWhitelist(const std::string& email,
45 std::vector<uint8>* OUT_signature) {
46 CryptoBlob* sig = NULL;
47 if (chromeos::CheckWhitelistSafe(email.c_str(), &sig)) {
48 OUT_signature->assign(sig->data, sig->data + sig->length);
49 chromeos::FreeCryptoBlob(sig);
50 return true;
51 }
52 return false;
53 }
54
RequestRetrievePolicy(RetrievePolicyCallback callback,void * delegate)55 void RequestRetrievePolicy(RetrievePolicyCallback callback, void* delegate) {
56 DCHECK(callback) << "must provide a callback to RequestRetrievePolicy()";
57 chromeos::RetrievePolicy(callback, delegate);
58 }
59
RequestRetrieveProperty(const std::string & name,RetrievePropertyCallback callback,void * user_data)60 void RequestRetrieveProperty(const std::string& name,
61 RetrievePropertyCallback callback,
62 void* user_data) {
63 DCHECK(callback) << "must provide a callback to RequestRetrieveProperty()";
64 chromeos::RequestRetrieveProperty(name.c_str(), callback, user_data);
65 }
66
RequestStorePolicy(const std::string & policy,StorePolicyCallback callback,void * delegate)67 void RequestStorePolicy(const std::string& policy,
68 StorePolicyCallback callback,
69 void* delegate) {
70 DCHECK(callback) << "must provide a callback to StorePolicy()";
71 chromeos::StorePolicy(policy.c_str(), policy.length(), callback, delegate);
72 }
73
StorePropertyAsync(const std::string & name,const std::string & value,const std::vector<uint8> & signature,Delegate * callback)74 bool StorePropertyAsync(const std::string& name,
75 const std::string& value,
76 const std::vector<uint8>& signature,
77 Delegate* callback) {
78 DCHECK(callback) << "must provide a callback to StorePropertyAsync()";
79 if (property_op_callback_)
80 return false;
81 property_op_callback_ = callback;
82 Property* prop = chromeos::CreateProperty(name.c_str(),
83 value.c_str(),
84 &signature[0],
85 signature.size());
86 bool rv = chromeos::StorePropertySafe(prop);
87 chromeos::FreeProperty(prop);
88 return rv;
89 }
90
UnwhitelistAsync(const std::string & email,const std::vector<uint8> & signature,Delegate * callback)91 bool UnwhitelistAsync(const std::string& email,
92 const std::vector<uint8>& signature,
93 Delegate* callback) {
94 DCHECK(callback) << "must provide a callback to UnwhitelistAsync()";
95 if (whitelist_op_callback_)
96 return false;
97 whitelist_op_callback_ = callback;
98 CryptoBlob* sig = chromeos::CreateCryptoBlob(&signature[0],
99 signature.size());
100 bool rv = chromeos::UnwhitelistSafe(email.c_str(), sig);
101 chromeos::FreeCryptoBlob(sig);
102 return rv;
103 }
104
WhitelistAsync(const std::string & email,const std::vector<uint8> & signature,Delegate * callback)105 bool WhitelistAsync(const std::string& email,
106 const std::vector<uint8>& signature,
107 Delegate* callback) {
108 DCHECK(callback) << "must provide a callback to WhitelistAsync()";
109 if (whitelist_op_callback_)
110 return false;
111 whitelist_op_callback_ = callback;
112 CryptoBlob* sig = chromeos::CreateCryptoBlob(&signature[0],
113 signature.size());
114 bool rv = chromeos::WhitelistSafe(email.c_str(), sig);
115 chromeos::FreeCryptoBlob(sig);
116 return rv;
117 }
118
119 // DEPRECATED.
EnumerateWhitelisted(std::vector<std::string> * whitelisted)120 bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
121 NOTREACHED();
122 UserList* list = NULL;
123 if (chromeos::EnumerateWhitelistedSafe(&list)) {
124 for (int i = 0; i < list->num_users; i++)
125 whitelisted->push_back(std::string(list->users[i]));
126 chromeos::FreeUserList(list);
127 return true;
128 }
129 return false;
130 }
131
StartSession(const std::string & user_email,const std::string & unique_id)132 bool StartSession(const std::string& user_email,
133 const std::string& unique_id /* unused */) {
134 // only pass unique_id through once we use it for something.
135 return chromeos::StartSession(user_email.c_str(), "");
136 }
137
StopSession(const std::string & unique_id)138 bool StopSession(const std::string& unique_id /* unused */) {
139 // only pass unique_id through once we use it for something.
140 return chromeos::StopSession("");
141 }
142
RestartEntd()143 bool RestartEntd() {
144 return chromeos::RestartEntd();
145 }
146
RestartJob(int pid,const std::string & command_line)147 bool RestartJob(int pid, const std::string& command_line) {
148 if (job_restart_request_) {
149 NOTREACHED();
150 return false;
151 }
152 job_restart_request_ = new JobRestartRequest(pid, command_line);
153 return true;
154 }
155
156 private:
157 class JobRestartRequest
158 : public base::RefCountedThreadSafe<JobRestartRequest> {
159 public:
JobRestartRequest(int pid,const std::string & command_line)160 JobRestartRequest(int pid, const std::string& command_line)
161 : pid_(pid),
162 command_line_(command_line),
163 local_state_(g_browser_process->local_state()) {
164 AddRef();
165 if (local_state_) {
166 // XXX: normally this call must not be needed, however RestartJob
167 // just kills us so settings may be lost. See http://crosbug.com/13102
168 local_state_->CommitPendingWrite();
169 timer_.Start(
170 base::TimeDelta::FromSeconds(3), this,
171 &JobRestartRequest::RestartJob);
172 // Post task on file thread thus it occurs last on task queue, so it
173 // would be executed after committing pending write on file thread.
174 BrowserThread::PostTask(
175 BrowserThread::FILE, FROM_HERE,
176 NewRunnableMethod(this, &JobRestartRequest::RestartJob));
177 } else {
178 RestartJob();
179 }
180 }
181
182 private:
RestartJob()183 void RestartJob() {
184 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
185 if (!chromeos::RestartJob(pid_, command_line_.c_str()))
186 NOTREACHED();
187 } else {
188 BrowserThread::PostTask(
189 BrowserThread::UI, FROM_HERE,
190 NewRunnableMethod(this, &JobRestartRequest::RestartJob));
191 MessageLoop::current()->AssertIdle();
192 }
193 }
194
195 int pid_;
196 std::string command_line_;
197 PrefService* local_state_;
198 base::OneShotTimer<JobRestartRequest> timer_;
199 };
200
201 class StubDelegate
202 : public SignedSettings::Delegate<const em::PolicyFetchResponse&> {
203 public:
StubDelegate()204 StubDelegate() : polfetcher_(NULL) {}
~StubDelegate()205 virtual ~StubDelegate() {}
set_fetcher(SignedSettings * s)206 void set_fetcher(SignedSettings* s) { polfetcher_ = s; }
fetcher()207 SignedSettings* fetcher() { return polfetcher_.get(); }
208 // Implementation of SignedSettings::Delegate
OnSettingsOpCompleted(SignedSettings::ReturnCode code,const em::PolicyFetchResponse & value)209 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
210 const em::PolicyFetchResponse& value) {
211 VLOG(2) << "Done Fetching Policy";
212 delete this;
213 }
214 private:
215 scoped_refptr<SignedSettings> polfetcher_;
216 DISALLOW_COPY_AND_ASSIGN(StubDelegate);
217 };
218
Handler(void * object,const OwnershipEvent & event)219 static void Handler(void* object, const OwnershipEvent& event) {
220 LoginLibraryImpl* self = static_cast<LoginLibraryImpl*>(object);
221 switch (event) {
222 case SetKeySuccess:
223 self->CompleteSetOwnerKey(true);
224 break;
225 case SetKeyFailure:
226 self->CompleteSetOwnerKey(false);
227 break;
228 case WhitelistOpSuccess:
229 self->CompleteWhitelistOp(true);
230 break;
231 case WhitelistOpFailure:
232 self->CompleteWhitelistOp(false);
233 break;
234 case PropertyOpSuccess:
235 self->CompletePropertyOp(true);
236 break;
237 case PropertyOpFailure:
238 self->CompletePropertyOp(false);
239 break;
240 default:
241 NOTREACHED();
242 break;
243 }
244 }
245
Init()246 void Init() {
247 session_connection_ = chromeos::MonitorSession(&Handler, this);
248 }
249
CompleteSetOwnerKey(bool value)250 void CompleteSetOwnerKey(bool value) {
251 VLOG(1) << "Owner key generation: " << (value ? "success" : "fail");
252 NotificationType result =
253 NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED;
254 if (!value)
255 result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_FAILED;
256
257 // Whether we exported the public key or not, send a notification indicating
258 // that we're done with this attempt.
259 NotificationService::current()->Notify(result,
260 NotificationService::AllSources(),
261 NotificationService::NoDetails());
262
263 // We stored some settings in transient storage before owner was assigned.
264 // Now owner is assigned and key is generated and we should persist
265 // those settings into signed storage.
266 if (g_browser_process && g_browser_process->local_state()) {
267 SignedSettingsTempStorage::Finalize(g_browser_process->local_state());
268 }
269 }
270
CompleteWhitelistOp(bool result)271 void CompleteWhitelistOp(bool result) {
272 if (whitelist_op_callback_) {
273 whitelist_op_callback_->OnComplete(result);
274 whitelist_op_callback_ = NULL;
275 }
276 }
277
CompletePropertyOp(bool result)278 void CompletePropertyOp(bool result) {
279 if (result) {
280 StubDelegate* stub = new StubDelegate(); // Manages its own lifetime.
281 stub->set_fetcher(SignedSettings::CreateRetrievePolicyOp(stub));
282 stub->fetcher()->Execute();
283 }
284 }
285
286 chromeos::SessionConnection session_connection_;
287 JobRestartRequest* job_restart_request_;
288
289 Delegate* set_owner_key_callback_;
290 Delegate* whitelist_op_callback_;
291 Delegate* property_op_callback_;
292
293 DISALLOW_COPY_AND_ASSIGN(LoginLibraryImpl);
294 };
295
296 class LoginLibraryStubImpl : public LoginLibrary {
297 public:
LoginLibraryStubImpl()298 LoginLibraryStubImpl() {}
~LoginLibraryStubImpl()299 virtual ~LoginLibraryStubImpl() {}
300
EmitLoginPromptReady()301 bool EmitLoginPromptReady() { return true; }
CheckWhitelist(const std::string & email,std::vector<uint8> * OUT_signature)302 bool CheckWhitelist(const std::string& email,
303 std::vector<uint8>* OUT_signature) {
304 OUT_signature->assign(2, 0);
305 return true;
306 }
RequestRetrievePolicy(RetrievePolicyCallback callback,void * delegate)307 void RequestRetrievePolicy(RetrievePolicyCallback callback, void* delegate) {
308 callback(delegate, "", 0);
309 }
RequestRetrieveProperty(const std::string & name,RetrievePropertyCallback callback,void * user_data)310 void RequestRetrieveProperty(const std::string& name,
311 RetrievePropertyCallback callback,
312 void* user_data) {
313 uint8 sig_bytes[] = { 0, 0 };
314 CryptoBlob sig = { sig_bytes, arraysize(sig_bytes) };
315 Property prop = {
316 "prop_name",
317 "stub",
318 &sig,
319 };
320
321 callback(user_data, true, &prop);
322 }
RequestStorePolicy(const std::string & policy,StorePolicyCallback callback,void * delegate)323 void RequestStorePolicy(const std::string& policy,
324 StorePolicyCallback callback,
325 void* delegate) {
326 callback(delegate, true);
327 }
StorePropertyAsync(const std::string & name,const std::string & value,const std::vector<uint8> & signature,Delegate * callback)328 bool StorePropertyAsync(const std::string& name,
329 const std::string& value,
330 const std::vector<uint8>& signature,
331 Delegate* callback) {
332 BrowserThread::PostTask(
333 BrowserThread::UI, FROM_HERE,
334 NewRunnableFunction(&DoStubCallback, callback));
335 return true;
336 }
UnwhitelistAsync(const std::string & email,const std::vector<uint8> & signature,Delegate * callback)337 bool UnwhitelistAsync(const std::string& email,
338 const std::vector<uint8>& signature,
339 Delegate* callback) {
340 BrowserThread::PostTask(
341 BrowserThread::UI, FROM_HERE,
342 NewRunnableFunction(&DoStubCallback, callback));
343 return true;
344 }
WhitelistAsync(const std::string & email,const std::vector<uint8> & signature,Delegate * callback)345 bool WhitelistAsync(const std::string& email,
346 const std::vector<uint8>& signature,
347 Delegate* callback) {
348 BrowserThread::PostTask(
349 BrowserThread::UI, FROM_HERE,
350 NewRunnableFunction(&DoStubCallback, callback));
351 return true;
352 }
EnumerateWhitelisted(std::vector<std::string> * whitelisted)353 bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
354 return true;
355 }
StartSession(const std::string & user_email,const std::string & unique_id)356 bool StartSession(const std::string& user_email,
357 const std::string& unique_id /* unused */) { return true; }
StopSession(const std::string & unique_id)358 bool StopSession(const std::string& unique_id /* unused */) { return true; }
RestartJob(int pid,const std::string & command_line)359 bool RestartJob(int pid, const std::string& command_line) { return true; }
RestartEntd()360 bool RestartEntd() { return true; }
361
362 private:
DoStubCallback(Delegate * callback)363 static void DoStubCallback(Delegate* callback) {
364 callback->OnComplete(true);
365 }
366
367 DISALLOW_COPY_AND_ASSIGN(LoginLibraryStubImpl);
368 };
369
370 // static
GetImpl(bool stub)371 LoginLibrary* LoginLibrary::GetImpl(bool stub) {
372 if (stub)
373 return new LoginLibraryStubImpl();
374 else
375 return new LoginLibraryImpl();
376 }
377
378 } // namespace chromeos
379