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: 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 34 virtual ~LoginLibraryImpl() { 35 if (session_connection_) { 36 chromeos::DisconnectSession(session_connection_); 37 } 38 } 39 40 bool EmitLoginPromptReady() { 41 return chromeos::EmitLoginPromptReady(); 42 } 43 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 55 void RequestRetrievePolicy(RetrievePolicyCallback callback, void* delegate) { 56 DCHECK(callback) << "must provide a callback to RequestRetrievePolicy()"; 57 chromeos::RetrievePolicy(callback, delegate); 58 } 59 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 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 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 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 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. 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 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 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 143 bool RestartEntd() { 144 return chromeos::RestartEntd(); 145 } 146 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: 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: 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: 204 StubDelegate() : polfetcher_(NULL) {} 205 virtual ~StubDelegate() {} 206 void set_fetcher(SignedSettings* s) { polfetcher_ = s; } 207 SignedSettings* fetcher() { return polfetcher_.get(); } 208 // Implementation of SignedSettings::Delegate 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 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 246 void Init() { 247 session_connection_ = chromeos::MonitorSession(&Handler, this); 248 } 249 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 271 void CompleteWhitelistOp(bool result) { 272 if (whitelist_op_callback_) { 273 whitelist_op_callback_->OnComplete(result); 274 whitelist_op_callback_ = NULL; 275 } 276 } 277 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: 298 LoginLibraryStubImpl() {} 299 virtual ~LoginLibraryStubImpl() {} 300 301 bool EmitLoginPromptReady() { return true; } 302 bool CheckWhitelist(const std::string& email, 303 std::vector<uint8>* OUT_signature) { 304 OUT_signature->assign(2, 0); 305 return true; 306 } 307 void RequestRetrievePolicy(RetrievePolicyCallback callback, void* delegate) { 308 callback(delegate, "", 0); 309 } 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 } 323 void RequestStorePolicy(const std::string& policy, 324 StorePolicyCallback callback, 325 void* delegate) { 326 callback(delegate, true); 327 } 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 } 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 } 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 } 353 bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) { 354 return true; 355 } 356 bool StartSession(const std::string& user_email, 357 const std::string& unique_id /* unused */) { return true; } 358 bool StopSession(const std::string& unique_id /* unused */) { return true; } 359 bool RestartJob(int pid, const std::string& command_line) { return true; } 360 bool RestartEntd() { return true; } 361 362 private: 363 static void DoStubCallback(Delegate* callback) { 364 callback->OnComplete(true); 365 } 366 367 DISALLOW_COPY_AND_ASSIGN(LoginLibraryStubImpl); 368 }; 369 370 // static 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