Rename MacKeychain to AppleKeychain
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_factory.cc
bloba46d809997cbdc388a6f1b73fe204f3ee87fed70
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.
5 #include "chrome/browser/password_manager/password_store_factory.h"
7 #include "base/command_line.h"
8 #include "base/environment.h"
9 #include "chrome/browser/password_manager/login_database.h"
10 #include "chrome/browser/password_manager/password_store.h"
11 #include "chrome/browser/password_manager/password_store_default.h"
12 #include "chrome/browser/prefs/pref_service.h"
13 #include "chrome/browser/profiles/profile_dependency_manager.h"
14 #include "chrome/browser/webdata/web_data_service.h"
15 #include "chrome/browser/webdata/web_data_service_factory.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/pref_names.h"
20 #if defined(OS_WIN)
21 #include "chrome/browser/password_manager/password_store_win.h"
22 #elif defined(OS_MACOSX)
23 #include "chrome/browser/password_manager/password_store_mac.h"
24 #include "crypto/apple_keychain.h"
25 #include "crypto/mock_apple_keychain.h"
26 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
27 // Don't do anything. We're going to use the default store.
28 #elif defined(OS_POSIX)
29 #include "base/nix/xdg_util.h"
30 #if defined(USE_GNOME_KEYRING)
31 #include "chrome/browser/password_manager/native_backend_gnome_x.h"
32 #endif
33 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
34 #include "chrome/browser/password_manager/password_store_x.h"
35 #endif
37 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && \
38 defined(OS_POSIX)
39 namespace {
41 const LocalProfileId kInvalidLocalProfileId =
42 static_cast<LocalProfileId>(0);
44 } // namespace
45 #endif
47 scoped_refptr<PasswordStore> PasswordStoreFactory::GetForProfile(
48 Profile* profile,
49 Profile::ServiceAccessType sat) {
50 if (sat == Profile::IMPLICIT_ACCESS && profile->IsOffTheRecord()) {
51 NOTREACHED() << "This profile is OffTheRecord";
52 return NULL;
55 return static_cast<PasswordStore*>(
56 GetInstance()->GetServiceForProfile(profile, true).get());
59 // static
60 PasswordStoreFactory* PasswordStoreFactory::GetInstance() {
61 return Singleton<PasswordStoreFactory>::get();
64 PasswordStoreFactory::PasswordStoreFactory()
65 : RefcountedProfileKeyedServiceFactory(
66 "PasswordStore",
67 ProfileDependencyManager::GetInstance()) {
68 DependsOn(WebDataServiceFactory::GetInstance());
71 PasswordStoreFactory::~PasswordStoreFactory() {}
73 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && \
74 defined(OS_POSIX)
75 LocalProfileId PasswordStoreFactory::GetLocalProfileId(
76 PrefService* prefs) const {
77 LocalProfileId id = prefs->GetInteger(prefs::kLocalProfileId);
78 if (id == kInvalidLocalProfileId) {
79 // Note that there are many more users than this. Thus, by design, this is
80 // not a unique id. However, it is large enough that it is very unlikely
81 // that it would be repeated twice on a single machine. It is still possible
82 // for that to occur though, so the potential results of it actually
83 // happening should be considered when using this value.
84 static const LocalProfileId kLocalProfileIdMask =
85 static_cast<LocalProfileId>((1 << 24) - 1);
86 do {
87 id = rand() & kLocalProfileIdMask;
88 // TODO(mdm): scan other profiles to make sure they are not using this id?
89 } while (id == kInvalidLocalProfileId);
90 prefs->SetInteger(prefs::kLocalProfileId, id);
92 return id;
94 #endif
96 scoped_refptr<RefcountedProfileKeyedService>
97 PasswordStoreFactory::BuildServiceInstanceFor(Profile* profile) const {
98 scoped_refptr<PasswordStore> ps;
99 FilePath login_db_file_path = profile->GetPath();
100 login_db_file_path = login_db_file_path.Append(chrome::kLoginDataFileName);
101 LoginDatabase* login_db = new LoginDatabase();
103 // TODO(paivanof@gmail.com): execution of login_db->Init() should go
104 // to DB thread. http://crbug.com/138903
105 base::ThreadRestrictions::ScopedAllowIO allow_io;
106 if (!login_db->Init(login_db_file_path)) {
107 LOG(ERROR) << "Could not initialize login database.";
108 delete login_db;
109 return NULL;
112 #if defined(OS_WIN)
113 ps = new PasswordStoreWin(
114 login_db, profile,
115 WebDataServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS));
116 #elif defined(OS_MACOSX)
117 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseMockKeychain)) {
118 ps = new PasswordStoreMac(new crypto::MockAppleKeychain(), login_db);
119 } else {
120 ps = new PasswordStoreMac(new crypto::AppleKeychain(), login_db);
122 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
123 // For now, we use PasswordStoreDefault. We might want to make a native
124 // backend for PasswordStoreX (see below) in the future though.
125 ps = new PasswordStoreDefault(login_db, profile);
126 #elif defined(OS_POSIX)
127 // On POSIX systems, we try to use the "native" password management system of
128 // the desktop environment currently running, allowing GNOME Keyring in XFCE.
129 // (In all cases we fall back on the basic store in case of failure.)
130 base::nix::DesktopEnvironment desktop_env;
131 std::string store_type =
132 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
133 switches::kPasswordStore);
134 if (store_type == "kwallet") {
135 desktop_env = base::nix::DESKTOP_ENVIRONMENT_KDE4;
136 } else if (store_type == "gnome") {
137 desktop_env = base::nix::DESKTOP_ENVIRONMENT_GNOME;
138 } else if (store_type == "basic") {
139 desktop_env = base::nix::DESKTOP_ENVIRONMENT_OTHER;
140 } else {
141 // Detect the store to use automatically.
142 scoped_ptr<base::Environment> env(base::Environment::Create());
143 desktop_env = base::nix::GetDesktopEnvironment(env.get());
144 const char* name = base::nix::GetDesktopEnvironmentName(desktop_env);
145 VLOG(1) << "Password storage detected desktop environment: "
146 << (name ? name : "(unknown)");
149 PrefService* prefs = profile->GetPrefs();
150 LocalProfileId id = GetLocalProfileId(prefs);
152 scoped_ptr<PasswordStoreX::NativeBackend> backend;
153 if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) {
154 // KDE3 didn't use DBus, which our KWallet store uses.
155 VLOG(1) << "Trying KWallet for password storage.";
156 backend.reset(new NativeBackendKWallet(id, prefs));
157 if (backend->Init())
158 VLOG(1) << "Using KWallet for password storage.";
159 else
160 backend.reset();
161 } else if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_GNOME ||
162 desktop_env == base::nix::DESKTOP_ENVIRONMENT_UNITY ||
163 desktop_env == base::nix::DESKTOP_ENVIRONMENT_XFCE) {
164 #if defined(USE_GNOME_KEYRING)
165 VLOG(1) << "Trying GNOME keyring for password storage.";
166 backend.reset(new NativeBackendGnome(id, prefs));
167 if (backend->Init())
168 VLOG(1) << "Using GNOME keyring for password storage.";
169 else
170 backend.reset();
171 #endif // defined(USE_GNOME_KEYRING)
174 if (!backend.get()) {
175 LOG(WARNING) << "Using basic (unencrypted) store for password storage. "
176 "See http://code.google.com/p/chromium/wiki/LinuxPasswordStorage for "
177 "more information about password storage options.";
180 ps = new PasswordStoreX(login_db, profile, backend.release());
181 #else
182 NOTIMPLEMENTED();
183 #endif
184 if (!ps)
185 delete login_db;
187 if (!ps || !ps->Init()) {
188 NOTREACHED() << "Could not initialize password manager.";
189 return NULL;
192 return ps;
195 void PasswordStoreFactory::RegisterUserPrefs(PrefService* prefs) {
196 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID) \
197 && defined(OS_POSIX)
198 prefs->RegisterIntegerPref(prefs::kLocalProfileId,
199 kInvalidLocalProfileId,
200 PrefService::UNSYNCABLE_PREF);
202 // Notice that the preprocessor conditions above are exactly those that will
203 // result in using PasswordStoreX in CreatePasswordStore() below.
204 PasswordStoreX::RegisterUserPrefs(prefs);
205 #endif
208 bool PasswordStoreFactory::ServiceRedirectedInIncognito() {
209 return true;
212 bool PasswordStoreFactory::ServiceIsNULLWhileTesting() {
213 return true;