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/managed/managed_user_authenticator.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_util.h" 10 #include "chrome/browser/chromeos/boot_times_loader.h" 11 #include "chrome/browser/chromeos/login/parallel_authenticator.h" 12 #include "chromeos/cryptohome/async_method_caller.h" 13 #include "chromeos/cryptohome/system_salt_getter.h" 14 #include "chromeos/dbus/cryptohome_client.h" 15 #include "chromeos/dbus/dbus_thread_manager.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "crypto/sha2.h" 18 #include "google_apis/gaia/gaia_auth_util.h" 19 #include "third_party/cros_system_api/dbus/service_constants.h" 20 21 using content::BrowserThread; 22 23 namespace chromeos { 24 25 namespace { 26 27 // Records status and calls resolver->Resolve(). 28 void TriggerResolve(ManagedUserAuthenticator::AuthAttempt* attempt, 29 scoped_refptr<ManagedUserAuthenticator> resolver, 30 bool success, 31 cryptohome::MountError return_code) { 32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 33 attempt->RecordCryptohomeStatus(success, return_code); 34 resolver->Resolve(); 35 } 36 37 // Records status and calls resolver->Resolve(). 38 void TriggerResolveResult(ManagedUserAuthenticator::AuthAttempt* attempt, 39 scoped_refptr<ManagedUserAuthenticator> resolver, 40 bool success, 41 const std::string& result) { 42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 43 attempt->RecordHash(result); 44 resolver->Resolve(); 45 } 46 47 // Calls TriggerResolve while adding login time marker. 48 void TriggerResolveWithLoginTimeMarker( 49 const std::string& marker_name, 50 ManagedUserAuthenticator::AuthAttempt* attempt, 51 scoped_refptr<ManagedUserAuthenticator> resolver, 52 bool success, 53 cryptohome::MountError return_code) { 54 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false); 55 TriggerResolve(attempt, resolver, success, return_code); 56 } 57 58 // Calls cryptohome's mount method. 59 void Mount(ManagedUserAuthenticator::AuthAttempt* attempt, 60 scoped_refptr<ManagedUserAuthenticator> resolver, 61 int flags, 62 const std::string& system_salt) { 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 64 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 65 "CryptohomeMount-LMU-Start", false); 66 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount( 67 attempt->username, 68 ParallelAuthenticator::HashPassword(attempt->password, system_salt), 69 flags, 70 base::Bind(&TriggerResolveWithLoginTimeMarker, 71 "CryptohomeMount-LMU-End", 72 attempt, 73 resolver)); 74 75 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( 76 attempt->username, 77 base::Bind(&TriggerResolveResult, attempt, resolver)); 78 } 79 80 // Calls cryptohome's addKey method. 81 void AddKey(ManagedUserAuthenticator::AuthAttempt* attempt, 82 scoped_refptr<ManagedUserAuthenticator> resolver, 83 const std::string& master_key, 84 const std::string& system_salt) { 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 86 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 87 "CryptohomeAddKey-LMU-Start", false); 88 cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey( 89 attempt->username, 90 ParallelAuthenticator::HashPassword(attempt->password, system_salt), 91 ParallelAuthenticator::HashPassword(master_key, system_salt), 92 base::Bind(&TriggerResolveWithLoginTimeMarker, 93 "CryptohomeAddKey-LMU-End", 94 attempt, 95 resolver)); 96 } 97 98 } // namespace 99 100 ManagedUserAuthenticator::ManagedUserAuthenticator(AuthStatusConsumer* consumer) 101 : consumer_(consumer) {} 102 103 void ManagedUserAuthenticator::AuthenticateToMount( 104 const std::string& username, 105 const std::string& password) { 106 std::string canonicalized = gaia::CanonicalizeEmail(username); 107 108 current_state_.reset(new ManagedUserAuthenticator::AuthAttempt( 109 canonicalized, password, false)); 110 111 SystemSaltGetter::Get()->GetSystemSalt( 112 base::Bind(&Mount, 113 current_state_.get(), 114 scoped_refptr<ManagedUserAuthenticator>(this), 115 cryptohome::MOUNT_FLAGS_NONE)); 116 } 117 118 void ManagedUserAuthenticator::AuthenticateToCreate( 119 const std::string& username, 120 const std::string& password) { 121 std::string canonicalized = gaia::CanonicalizeEmail(username); 122 123 current_state_.reset(new ManagedUserAuthenticator::AuthAttempt( 124 canonicalized, password, false)); 125 126 SystemSaltGetter::Get()->GetSystemSalt( 127 base::Bind(&Mount, 128 current_state_.get(), 129 scoped_refptr<ManagedUserAuthenticator>(this), 130 cryptohome::CREATE_IF_MISSING)); 131 } 132 133 void ManagedUserAuthenticator::AddMasterKey( 134 const std::string& username, 135 const std::string& password, 136 const std::string& master_key) { 137 std::string canonicalized = gaia::CanonicalizeEmail(username); 138 139 current_state_.reset(new ManagedUserAuthenticator::AuthAttempt( 140 canonicalized, password, true)); 141 142 SystemSaltGetter::Get()->GetSystemSalt( 143 base::Bind(&AddKey, 144 current_state_.get(), 145 scoped_refptr<ManagedUserAuthenticator>(this), 146 master_key)); 147 } 148 149 void ManagedUserAuthenticator::OnAuthenticationSuccess( 150 const std::string& mount_hash, 151 bool add_key) { 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 153 VLOG(1) << "Locally managed user authentication success"; 154 if (consumer_) { 155 if (add_key) 156 consumer_->OnAddKeySuccess(); 157 else 158 consumer_->OnMountSuccess(mount_hash); 159 } 160 } 161 162 void ManagedUserAuthenticator::OnAuthenticationFailure( 163 ManagedUserAuthenticator::AuthState state) { 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 165 LOG(WARNING) << "Locally managed user authentication failure"; 166 if (consumer_) 167 consumer_->OnAuthenticationFailure(state); 168 } 169 170 void ManagedUserAuthenticator::Resolve() { 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 172 ManagedUserAuthenticator::AuthState state = ResolveState(); 173 VLOG(1) << "Resolved state to: " << state; 174 switch (state) { 175 case CONTINUE: 176 // These are intermediate states; we need more info from a request that 177 // is still pending. 178 break; 179 case FAILED_MOUNT: 180 // In this case, whether login succeeded or not, we can't log 181 // the user in because their data is horked. So, override with 182 // the appropriate failure. 183 BrowserThread::PostTask( 184 BrowserThread::UI, 185 FROM_HERE, 186 base::Bind( 187 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state)); 188 break; 189 case NO_MOUNT: 190 // In this case, whether login succeeded or not, we can't log 191 // the user in because no data exist. So, override with 192 // the appropriate failure. 193 BrowserThread::PostTask( 194 BrowserThread::UI, 195 FROM_HERE, 196 base::Bind( 197 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state)); 198 break; 199 case FAILED_TPM: 200 // In this case, we tried to create/mount cryptohome and failed 201 // because of the critical TPM error. 202 // Chrome will notify user and request reboot. 203 BrowserThread::PostTask( 204 BrowserThread::UI, 205 FROM_HERE, 206 base::Bind( 207 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state)); 208 break; 209 case SUCCESS: 210 VLOG(2) << "Locally managed user login"; 211 BrowserThread::PostTask( 212 BrowserThread::UI, 213 FROM_HERE, 214 base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess, 215 this, 216 current_state_->hash(), 217 current_state_->add_key)); 218 break; 219 default: 220 NOTREACHED(); 221 break; 222 } 223 } 224 225 ManagedUserAuthenticator::~ManagedUserAuthenticator() {} 226 227 ManagedUserAuthenticator::AuthState ManagedUserAuthenticator::ResolveState() { 228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 229 // If we haven't mounted the user's home dir yet, we can't be done. 230 // We never get past here if a cryptohome op is still pending. 231 // This is an important invariant. 232 if (!current_state_->cryptohome_complete()) 233 return CONTINUE; 234 if (!current_state_->add_key && !current_state_->hash_obtained()) 235 return CONTINUE; 236 237 AuthState state; 238 239 if (current_state_->cryptohome_outcome()) 240 state = ResolveCryptohomeSuccessState(); 241 else 242 state = ResolveCryptohomeFailureState(); 243 244 DCHECK(current_state_->cryptohome_complete()); 245 DCHECK(current_state_->hash_obtained() || current_state_->add_key); 246 return state; 247 } 248 249 ManagedUserAuthenticator::AuthState 250 ManagedUserAuthenticator::ResolveCryptohomeFailureState() { 251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 252 if (current_state_->cryptohome_code() == 253 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { 254 // Critical TPM error detected, reboot needed. 255 return FAILED_TPM; 256 } 257 258 if (current_state_->cryptohome_code() == 259 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) { 260 // If we tried a mount but the user did not exist, then we should wait 261 // for online login to succeed and try again with the "create" flag set. 262 return NO_MOUNT; 263 } 264 265 return FAILED_MOUNT; 266 } 267 268 ManagedUserAuthenticator::AuthState 269 ManagedUserAuthenticator::ResolveCryptohomeSuccessState() { 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 271 return SUCCESS; 272 } 273 274 ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string& username, 275 const std::string& password, 276 bool add_key_attempt) 277 : username(username), 278 password(password), 279 add_key(add_key_attempt), 280 cryptohome_complete_(false), 281 cryptohome_outcome_(false), 282 hash_obtained_(false), 283 cryptohome_code_(cryptohome::MOUNT_ERROR_NONE) {} 284 285 ManagedUserAuthenticator::AuthAttempt::~AuthAttempt() {} 286 287 void ManagedUserAuthenticator::AuthAttempt::RecordCryptohomeStatus( 288 bool cryptohome_outcome, 289 cryptohome::MountError cryptohome_code) { 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 291 cryptohome_complete_ = true; 292 cryptohome_outcome_ = cryptohome_outcome; 293 cryptohome_code_ = cryptohome_code; 294 } 295 296 void ManagedUserAuthenticator::AuthAttempt::RecordHash( 297 const std::string& hash) { 298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 299 hash_obtained_ = true; 300 hash_ = hash; 301 } 302 303 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_complete() { 304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 305 return cryptohome_complete_; 306 } 307 308 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_outcome() { 309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 310 return cryptohome_outcome_; 311 } 312 313 cryptohome::MountError 314 ManagedUserAuthenticator::AuthAttempt::cryptohome_code() { 315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 316 return cryptohome_code_; 317 } 318 319 bool ManagedUserAuthenticator::AuthAttempt::hash_obtained() { 320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 321 return hash_obtained_; 322 } 323 324 std::string ManagedUserAuthenticator::AuthAttempt::hash() { 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 326 return hash_; 327 } 328 329 } // namespace chromeos 330