1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Use of this source code is governed by a BSD-style license that can be
3731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// found in the LICENSE file.
4731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/chromeos/login/parallel_authenticator.h"
6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <string>
8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <vector>
9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/file_path.h"
11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/file_util.h"
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/logging.h"
13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/path_service.h"
14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/string_util.h"
153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/lock.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/third_party/nss/blapi.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/third_party/nss/sha256.h"
18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/chromeos/cros/cryptohome_library.h"
19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/chromeos/login/auth_response_handler.h"
20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/chromeos/login/authentication_notification_details.h"
21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/chromeos/login/login_status_consumer.h"
22731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/chromeos/login/ownership_service.h"
234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/chromeos/login/user_manager.h"
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/chrome_paths.h"
274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/net/gaia/gaia_constants.h"
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h"
31731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/base/load_flags.h"
32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/base/net_errors.h"
33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/url_request/url_request_status.h"
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "third_party/libjingle/source/talk/base/urlencode.h"
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing base::Time;
37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing base::TimeDelta;
38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing file_util::GetFileSize;
39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing file_util::PathExists;
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing file_util::ReadFile;
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing file_util::ReadFileToString;
42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
43731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace chromeos {
44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst char ParallelAuthenticator::kLocalaccountFile[] = "localaccount";
47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
48731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
49731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst int ParallelAuthenticator::kClientLoginTimeoutMs = 10000;
50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst int ParallelAuthenticator::kLocalaccountRetryIntervalMs = 20;
52731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
53731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst int kPassHashLen = 32;
54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
55731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer)
56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : Authenticator(consumer),
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      already_reported_success_(false),
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      checked_for_localaccount_(false) {
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If not already owned, this is a no-op.  If it is, this loads the owner's
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // public key off of disk.
62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  OwnershipService::GetSharedInstance()->StartLoadOwnerKeyAttempt();
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
65731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::~ParallelAuthenticator() {}
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParallelAuthenticator::AuthenticateToLogin(
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    Profile* profile,
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& username,
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& password,
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& login_token,
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& login_captcha) {
734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string canonicalized = Authenticator::Canonicalize(username);
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  current_state_.reset(
754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      new AuthAttemptState(canonicalized,
76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           password,
77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           HashPassword(password),
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           login_token,
794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           login_captcha,
804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           !UserManager::Get()->IsKnownUser(canonicalized)));
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  mounter_ = CryptohomeOp::CreateMountAttempt(current_state_.get(),
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                              this,
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                              false /* don't create */);
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  current_online_ = new OnlineAttempt(current_state_.get(), this);
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Sadly, this MUST be on the UI thread due to sending DBus traffic :-/
86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(mounter_.get(), &CryptohomeOp::Initiate));
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  current_online_->Initiate(profile);
90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::FILE, FROM_HERE,
92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(this,
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        &ParallelAuthenticator::LoadLocalaccount,
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        std::string(kLocalaccountFile)));
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParallelAuthenticator::AuthenticateToUnlock(const std::string& username,
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                 const std::string& password) {
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  current_state_.reset(
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new AuthAttemptState(Authenticator::Canonicalize(username),
102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           HashPassword(password)));
103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::FILE, FROM_HERE,
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(this,
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        &ParallelAuthenticator::LoadLocalaccount,
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        std::string(kLocalaccountFile)));
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  key_checker_ = CryptohomeOp::CreateCheckKeyAttempt(current_state_.get(),
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                     this);
110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Sadly, this MUST be on the UI thread due to sending DBus traffic :-/
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
113731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(key_checker_.get(), &CryptohomeOp::Initiate));
114731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
117731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::LoginOffTheRecord() {
1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  current_state_.reset(new AuthAttemptState("", "", "", "", "", false));
119731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  guest_mounter_ =
120731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      CryptohomeOp::CreateMountGuestAttempt(current_state_.get(), this);
121731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
122731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  guest_mounter_->Initiate();
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::OnLoginSuccess(
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GaiaAuthConsumer::ClientLoginResult& credentials,
127731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    bool request_pending) {
128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  VLOG(1) << "Login success";
130731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Send notification of success
131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AuthenticationNotificationDetails details(true);
132731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  NotificationService::current()->Notify(
133731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NotificationType::LOGIN_AUTHENTICATION,
134731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NotificationService::AllSources(),
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Details<AuthenticationNotificationDetails>(&details));
136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  {
1373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock for_this_block(success_lock_);
138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    already_reported_success_ = true;
139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  consumer_->OnLoginSuccess(current_state_->username,
141513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                            current_state_->password,
142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            credentials,
143731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            request_pending);
144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
145731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::OnOffTheRecordLoginSuccess() {
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Send notification of success
149731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AuthenticationNotificationDetails details(true);
150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  NotificationService::current()->Notify(
151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NotificationType::LOGIN_AUTHENTICATION,
152731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NotificationService::AllSources(),
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Details<AuthenticationNotificationDetails>(&details));
154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  consumer_->OnOffTheRecordLoginSuccess();
155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::OnPasswordChangeDetected(
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GaiaAuthConsumer::ClientLoginResult& credentials) {
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  consumer_->OnPasswordChangeDetected(credentials);
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::CheckLocalaccount(const LoginFailure& error) {
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  {
1653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock for_this_block(localaccount_lock_);
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    VLOG(2) << "Checking localaccount";
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!checked_for_localaccount_) {
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostDelayedTask(
169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::FILE, FROM_HERE,
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this,
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            &ParallelAuthenticator::CheckLocalaccount,
172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            error),
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          kLocalaccountRetryIntervalMs);
174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return;
175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!localaccount_.empty() && localaccount_ == current_state_->username) {
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Success.  Go mount a tmpfs for the profile, if necessary.
180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!current_state_->unlock) {
181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      guest_mounter_ =
182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          CryptohomeOp::CreateMountGuestAttempt(current_state_.get(), this);
183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
184731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
185731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(guest_mounter_.get(), &CryptohomeOp::Initiate));
186731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else {
187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            GaiaAuthConsumer::ClientLoginResult(), false));
191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
192731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
193731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Not the localaccount.  Fail, passing along cached error info.
194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
195731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::UI, FROM_HERE,
196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure, error));
197731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
198731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
199731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
200731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) {
201731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Send notification of failure
203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AuthenticationNotificationDetails details(false);
204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  NotificationService::current()->Notify(
205731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NotificationType::LOGIN_AUTHENTICATION,
206731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NotificationService::AllSources(),
207731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Details<AuthenticationNotificationDetails>(&details));
208731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  LOG(WARNING) << "Login failed: " << error.GetErrorString();
209731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  consumer_->OnLoginFailure(error);
210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
212731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::RecoverEncryptedData(
213731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& old_password,
214731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GaiaAuthConsumer::ClientLoginResult& credentials) {
215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string old_hash = HashPassword(old_password);
216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  key_migrator_ = CryptohomeOp::CreateMigrateAttempt(current_state_.get(),
217731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                     this,
218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                     true,
219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                     old_hash);
220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
221731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(this,
223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        &ParallelAuthenticator::ResyncRecoverHelper,
22421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                        key_migrator_));
225731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
226731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
227731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::ResyncEncryptedData(
228731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GaiaAuthConsumer::ClientLoginResult& credentials) {
229731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  data_remover_ =
230731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      CryptohomeOp::CreateRemoveAttempt(current_state_.get(), this);
231731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
232731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(this,
234731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        &ParallelAuthenticator::ResyncRecoverHelper,
23521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                        data_remover_));
236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
238731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::ResyncRecoverHelper(CryptohomeOp* to_initiate) {
239731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
240731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  current_state_->ResetCryptohomeStatus();
241731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
242731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
243731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(to_initiate, &CryptohomeOp::Initiate));
244731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
245731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
246731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::RetryAuth(Profile* profile,
247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      const std::string& username,
248731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      const std::string& password,
249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      const std::string& login_token,
250731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      const std::string& login_captcha) {
251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  reauth_state_.reset(
252731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new AuthAttemptState(Authenticator::Canonicalize(username),
253731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           password,
254731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           HashPassword(password),
255731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           login_token,
2564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           login_captcha,
2574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           false /* not a new user */));
258731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  current_online_ = new OnlineAttempt(reauth_state_.get(), this);
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  current_online_->Initiate(profile);
260731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
261731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::Resolve() {
263731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
264731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool request_pending = false;
265731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool create = false;
26621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ParallelAuthenticator::AuthState state = ResolveState();
26721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  VLOG(1) << "Resolved state to: " << state;
26821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  switch (state) {
269731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case CONTINUE:
270731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case POSSIBLE_PW_CHANGE:
271731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case NO_MOUNT:
272731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // These are intermediate states; we need more info from a request that
273731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // is still pending.
274731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case FAILED_MOUNT:
276731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // In this case, whether login succeeded or not, we can't log
277731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // the user in because their data is horked.  So, override with
278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // the appropriate failure.
279731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
280731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
281731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(
282731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              this,
283731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              &ParallelAuthenticator::OnLoginFailure,
284731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
285731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case FAILED_REMOVE:
287731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // In this case, we tried to remove the user's old cryptohome at her
288731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // request, and the remove failed.
289731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
290731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
291731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure,
292731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            LoginFailure(LoginFailure::DATA_REMOVAL_FAILED)));
293731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
294731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case FAILED_TMPFS:
295731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // In this case, we tried to mount a tmpfs for BWSI or the localaccount
296731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // user and failed.
297731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
298731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
299731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure,
300731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS)));
301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
302731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case CREATE_NEW:
303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      create = true;
304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case RECOVER_MOUNT:
305731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      current_state_->ResetCryptohomeStatus();
306731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      mounter_ = CryptohomeOp::CreateMountAttempt(current_state_.get(),
307731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                  this,
308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                  create);
309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(mounter_.get(), &CryptohomeOp::Initiate));
312731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case NEED_OLD_PW:
314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
315731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
316731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this,
317731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            &ParallelAuthenticator::OnPasswordChangeDetected,
318731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            current_state_->credentials()));
319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ONLINE_FAILED:
321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // In this case, we know online login was rejected because the account
322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // is disabled or something similarly fatal.  Sending the user through
323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // the same path they get when their password is rejected is cleaner
324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // for now.
325731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // TODO(cmasone): optimize this so that we don't send the user through
326731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // the 'changed password' path when we know doing so won't succeed.
327731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case NEED_NEW_PW:
328731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      {
3293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        base::AutoLock for_this_block(success_lock_);
330731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (!already_reported_success_) {
331731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          // This allows us to present the same behavior for "online:
332731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          // fail, offline: ok", regardless of the order in which we
333731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          // receive the results.  There will be cases in which we get
334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          // the online failure some time after the offline success,
335731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          // so we just force all cases in this category to present like this:
336731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          // OnLoginSuccess(..., ..., true) -> OnLoginFailure().
337731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::PostTask(
338731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              BrowserThread::UI, FROM_HERE,
339731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
340731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                current_state_->credentials(), true));
341731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
342731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
343731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
344731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
345731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this, &ParallelAuthenticator::OnLoginFailure,
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                            (reauth_state_.get() ?
34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                             reauth_state_->online_outcome() :
34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                             current_state_->online_outcome())));
349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case HAVE_NEW_PW:
351731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      key_migrator_ =
352731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          CryptohomeOp::CreateMigrateAttempt(reauth_state_.get(),
353731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                             this,
3544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                             true,
3554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                             current_state_->ascii_hash);
356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
357731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
358731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(key_migrator_.get(), &CryptohomeOp::Initiate));
359731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case OFFLINE_LOGIN:
36121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      VLOG(2) << "Offline login";
362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      request_pending = !current_state_->online_complete();
363731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Fall through.
364731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case UNLOCK:
365731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Fall through.
366731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ONLINE_LOGIN:
36721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      VLOG(2) << "Online login";
368731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
369731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
370731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
371731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            current_state_->credentials(), request_pending));
372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case LOCAL_LOGIN:
374731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
375731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::UI, FROM_HERE,
376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(
377731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              this,
378731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              &ParallelAuthenticator::OnOffTheRecordLoginSuccess));
379731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
380731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case LOGIN_FAILED:
381731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      current_state_->ResetCryptohomeStatus();
382731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
383731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::FILE, FROM_HERE,
384731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          NewRunnableMethod(this, &ParallelAuthenticator::CheckLocalaccount,
385731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            current_state_->online_outcome()));
386731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
387731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    default:
388731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NOTREACHED();
389731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      break;
390731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
391731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
392731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
393731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() {
394731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
395731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If we haven't mounted the user's home dir yet, we can't be done.
396731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // We never get past here if a cryptohome op is still pending.
397731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // This is an important invariant.
398731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!current_state_->cryptohome_complete())
399731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return CONTINUE;
400731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
401731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AuthState state = (reauth_state_.get() ? ResolveReauthState() : CONTINUE);
402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (state != CONTINUE)
403731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return state;
404731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
405731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (current_state_->cryptohome_outcome())
406731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    state = ResolveCryptohomeSuccessState();
407731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  else
408731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    state = ResolveCryptohomeFailureState();
409731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
410731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(current_state_->cryptohome_complete());  // Ensure invariant holds.
411731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  key_migrator_ = NULL;
412731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  data_remover_ = NULL;
413731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  guest_mounter_ = NULL;
414731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  key_checker_ = NULL;
415731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
416731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (state != POSSIBLE_PW_CHANGE &&
417731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      state != NO_MOUNT &&
418731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      state != OFFLINE_LOGIN)
419731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return state;
420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
421731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (current_state_->online_complete()) {
422731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (current_state_->online_outcome().reason() == LoginFailure::NONE) {
423731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Online attempt succeeded as well, so combine the results.
424731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return ResolveOnlineSuccessState(state);
425731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
426731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Online login attempt was rejected or failed to occur.
427731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ResolveOnlineFailureState(state);
428731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
429731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // if online isn't complete yet, just return the offline result.
430731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return state;
431731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
432731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
433731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::AuthState
434731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::ResolveReauthState() {
435731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
436731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (reauth_state_->cryptohome_complete()) {
437731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!reauth_state_->cryptohome_outcome()) {
438731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // If we've tried to migrate and failed, log the error and just wait
439731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // til next time the user logs in to migrate their cryptohome key.
440731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      LOG(ERROR) << "Failed to migrate cryptohome key: "
441731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                 << reauth_state_->cryptohome_code();
442731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
443731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    reauth_state_.reset(NULL);
444731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ONLINE_LOGIN;
445731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
446731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Haven't tried the migrate yet, must be processing the online auth attempt.
447731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!reauth_state_->online_complete()) {
448731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    NOTREACHED();  // Shouldn't be here at all, if online reauth isn't done!
449731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return CONTINUE;
450731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
451731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return (reauth_state_->online_outcome().reason() == LoginFailure::NONE) ?
452731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      HAVE_NEW_PW : NEED_NEW_PW;
453731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
454731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
455731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::AuthState
456731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::ResolveCryptohomeFailureState() {
457731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
458731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (data_remover_.get())
459731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return FAILED_REMOVE;
460731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (guest_mounter_.get())
461731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return FAILED_TMPFS;
462731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (key_migrator_.get())
463731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return NEED_OLD_PW;
464731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (key_checker_.get())
465731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return LOGIN_FAILED;
466731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (current_state_->cryptohome_code() ==
467731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      chromeos::kCryptohomeMountErrorKeyFailure) {
468731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // If we tried a mount but they used the wrong key, we may need to
469731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // ask the user for her old password.  We'll only know once we've
470731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // done the online check.
471731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return POSSIBLE_PW_CHANGE;
472731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
473731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (current_state_->cryptohome_code() ==
474731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      chromeos::kCryptohomeMountErrorUserDoesNotExist) {
475731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // If we tried a mount but the user did not exist, then we should wait
476731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // for online login to succeed and try again with the "create" flag set.
477731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return NO_MOUNT;
478731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
479731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return FAILED_MOUNT;
480731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
481731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
482731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::AuthState
483731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::ResolveCryptohomeSuccessState() {
484731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
485731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (data_remover_.get())
486731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return CREATE_NEW;
487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (guest_mounter_.get())
488731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return LOCAL_LOGIN;
489731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (key_migrator_.get())
490731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return RECOVER_MOUNT;
491731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (key_checker_.get())
492731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return UNLOCK;
493731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return OFFLINE_LOGIN;
494731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
495731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
496731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::AuthState
497731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::ResolveOnlineFailureState(
498731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ParallelAuthenticator::AuthState offline_state) {
499731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
500731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (offline_state == OFFLINE_LOGIN) {
501731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (current_state_->online_outcome().error().state() ==
502731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        GoogleServiceAuthError::CONNECTION_FAILED) {
503731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Couldn't do an online check, so just go with the offline result.
504731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return OFFLINE_LOGIN;
505731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
506731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Otherwise, online login was rejected!
507731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (current_state_->online_outcome().error().state() ==
508731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
509731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return NEED_NEW_PW;
510731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
511731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ONLINE_FAILED;
512731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
513731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return LOGIN_FAILED;
514731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
515731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
516731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::AuthState
517731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickParallelAuthenticator::ResolveOnlineSuccessState(
518731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ParallelAuthenticator::AuthState offline_state) {
519731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
520731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  switch (offline_state) {
521731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case POSSIBLE_PW_CHANGE:
522731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return NEED_OLD_PW;
523731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case NO_MOUNT:
524731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return CREATE_NEW;
525731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case OFFLINE_LOGIN:
526731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return ONLINE_LOGIN;
527731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    default:
528731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NOTREACHED();
529731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return offline_state;
530731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
531731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
532731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
533731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::LoadSystemSalt() {
534731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!system_salt_.empty())
535731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
536731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  system_salt_ = CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt();
537731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  CHECK(!system_salt_.empty());
538731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  CHECK_EQ(system_salt_.size() % 2, 0U);
539731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
540731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
541731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::LoadLocalaccount(const std::string& filename) {
542731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
543731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  {
5443f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock for_this_block(localaccount_lock_);
545731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (checked_for_localaccount_)
546731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return;
547731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
548731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  FilePath localaccount_file;
549731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string localaccount;
550731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (PathService::Get(base::DIR_EXE, &localaccount_file)) {
551731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    localaccount_file = localaccount_file.Append(filename);
55221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    VLOG(2) << "Looking for localaccount in " << localaccount_file.value();
553731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
554731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ReadFileToString(localaccount_file, &localaccount);
555731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    TrimWhitespaceASCII(localaccount, TRIM_TRAILING, &localaccount);
556731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Loading localaccount: " << localaccount;
557731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
558731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Assuming no localaccount";
559731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
560731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SetLocalaccount(localaccount);
561731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
562731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
563731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParallelAuthenticator::SetLocalaccount(const std::string& new_name) {
564731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  localaccount_ = new_name;
565731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  {  // extra braces for clarity about AutoLock scope.
5663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::AutoLock for_this_block(localaccount_lock_);
567731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    checked_for_localaccount_ = true;
568731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
569731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
570731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
571731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
572731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string ParallelAuthenticator::HashPassword(const std::string& password) {
573731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Get salt, ascii encode, update sha with that, then update with ascii
574731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // of password, then end.
575731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string ascii_salt = SaltAsAscii();
576731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  unsigned char passhash_buf[kPassHashLen];
577731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  char ascii_buf[kPassHashLen + 1];
578731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
579731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Hash salt and password
580731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SHA256Context ctx;
581731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SHA256_Begin(&ctx);
582731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SHA256_Update(&ctx,
583731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                reinterpret_cast<const unsigned char*>(ascii_salt.data()),
584731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                static_cast<unsigned int>(ascii_salt.length()));
585731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SHA256_Update(&ctx,
586731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                reinterpret_cast<const unsigned char*>(password.data()),
587731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                static_cast<unsigned int>(password.length()));
588731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SHA256_End(&ctx,
589731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick             passhash_buf,
590731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick             NULL,
591731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick             static_cast<unsigned int>(sizeof(passhash_buf)));
592731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
593731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::vector<unsigned char> passhash(passhash_buf,
594731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      passhash_buf + sizeof(passhash_buf));
595731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BinaryToHex(passhash,
596731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              passhash.size() / 2,  // only want top half, at least for now.
597731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              ascii_buf,
598731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              sizeof(ascii_buf));
599731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return std::string(ascii_buf, sizeof(ascii_buf) - 1);
600731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
601731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
602731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string ParallelAuthenticator::SaltAsAscii() {
603731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  LoadSystemSalt();  // no-op if it's already loaded.
604731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  unsigned int salt_len = system_salt_.size();
605731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  char ascii_salt[2 * salt_len + 1];
606731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (ParallelAuthenticator::BinaryToHex(system_salt_,
607731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                       salt_len,
608731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                       ascii_salt,
609731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                       sizeof(ascii_salt))) {
610731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return std::string(ascii_salt, sizeof(ascii_salt) - 1);
611731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
612731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return std::string();
613731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
614731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
615731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
616731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParallelAuthenticator::BinaryToHex(
617731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::vector<unsigned char>& binary,
618731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const unsigned int binary_len,
619731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    char* hex_string,
620731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const unsigned int len) {
621731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (len < 2*binary_len)
622731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
623731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  memset(hex_string, 0, len);
624731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (uint i = 0, j = 0; i < binary_len; i++, j+=2)
625731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    snprintf(hex_string + j, len - j, "%02x", binary[i]);
626731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
627731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
628731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
629731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}  // namespace chromeos
630