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 "base/prefs/pref_service.h"
10 #include "chrome/browser/password_manager/login_database.h"
11 #include "chrome/browser/password_manager/password_store.h"
12 #include "chrome/browser/password_manager/password_store_default.h"
13 #include "chrome/browser/profiles/incognito_helpers.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"
19 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
20 #include "components/user_prefs/pref_registry_syncable.h"
23 #include "chrome/browser/password_manager/password_store_win.h"
24 #elif defined(OS_MACOSX)
25 #include "chrome/browser/password_manager/password_store_mac.h"
26 #include "crypto/apple_keychain.h"
27 #include "crypto/mock_apple_keychain.h"
28 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
29 // Don't do anything. We're going to use the default store.
30 #elif defined(USE_X11)
31 #include "base/nix/xdg_util.h"
32 #if defined(USE_GNOME_KEYRING)
33 #include "chrome/browser/password_manager/native_backend_gnome_x.h"
35 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
36 #include "chrome/browser/password_manager/password_store_x.h"
39 #if !defined(OS_CHROMEOS) && defined(USE_X11)
42 const LocalProfileId kInvalidLocalProfileId
=
43 static_cast<LocalProfileId
>(0);
48 scoped_refptr
<PasswordStore
> PasswordStoreFactory::GetForProfile(
50 Profile::ServiceAccessType sat
) {
51 if (sat
== Profile::IMPLICIT_ACCESS
&& profile
->IsOffTheRecord()) {
52 NOTREACHED() << "This profile is OffTheRecord";
56 return static_cast<PasswordStore
*>(
57 GetInstance()->GetServiceForBrowserContext(profile
, true).get());
61 PasswordStoreFactory
* PasswordStoreFactory::GetInstance() {
62 return Singleton
<PasswordStoreFactory
>::get();
65 PasswordStoreFactory::PasswordStoreFactory()
66 : RefcountedBrowserContextKeyedServiceFactory(
68 BrowserContextDependencyManager::GetInstance()) {
69 DependsOn(WebDataServiceFactory::GetInstance());
72 PasswordStoreFactory::~PasswordStoreFactory() {}
74 #if !defined(OS_CHROMEOS) && defined(USE_X11)
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);
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
);
96 scoped_refptr
<RefcountedBrowserContextKeyedService
>
97 PasswordStoreFactory::BuildServiceInstanceFor(
98 content::BrowserContext
* context
) const {
99 Profile
* profile
= static_cast<Profile
*>(context
);
101 scoped_refptr
<PasswordStore
> ps
;
102 base::FilePath login_db_file_path
= profile
->GetPath();
103 login_db_file_path
= login_db_file_path
.Append(chrome::kLoginDataFileName
);
104 LoginDatabase
* login_db
= new LoginDatabase();
106 // TODO(paivanof@gmail.com): execution of login_db->Init() should go
107 // to DB thread. http://crbug.com/138903
108 base::ThreadRestrictions::ScopedAllowIO allow_io
;
109 if (!login_db
->Init(login_db_file_path
)) {
110 LOG(ERROR
) << "Could not initialize login database.";
116 ps
= new PasswordStoreWin(
118 WebDataService::FromBrowserContext(profile
));
119 #elif defined(OS_MACOSX)
120 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseMockKeychain
)) {
121 ps
= new PasswordStoreMac(new crypto::MockAppleKeychain(), login_db
);
123 ps
= new PasswordStoreMac(new crypto::AppleKeychain(), login_db
);
125 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
126 // For now, we use PasswordStoreDefault. We might want to make a native
127 // backend for PasswordStoreX (see below) in the future though.
128 ps
= new PasswordStoreDefault(login_db
, profile
);
129 #elif defined(USE_X11)
130 // On POSIX systems, we try to use the "native" password management system of
131 // the desktop environment currently running, allowing GNOME Keyring in XFCE.
132 // (In all cases we fall back on the basic store in case of failure.)
133 base::nix::DesktopEnvironment desktop_env
;
134 std::string store_type
=
135 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
136 switches::kPasswordStore
);
137 if (store_type
== "kwallet") {
138 desktop_env
= base::nix::DESKTOP_ENVIRONMENT_KDE4
;
139 } else if (store_type
== "gnome") {
140 desktop_env
= base::nix::DESKTOP_ENVIRONMENT_GNOME
;
141 } else if (store_type
== "basic") {
142 desktop_env
= base::nix::DESKTOP_ENVIRONMENT_OTHER
;
144 // Detect the store to use automatically.
145 scoped_ptr
<base::Environment
> env(base::Environment::Create());
146 desktop_env
= base::nix::GetDesktopEnvironment(env
.get());
147 const char* name
= base::nix::GetDesktopEnvironmentName(desktop_env
);
148 VLOG(1) << "Password storage detected desktop environment: "
149 << (name
? name
: "(unknown)");
152 PrefService
* prefs
= profile
->GetPrefs();
153 LocalProfileId id
= GetLocalProfileId(prefs
);
155 scoped_ptr
<PasswordStoreX::NativeBackend
> backend
;
156 if (desktop_env
== base::nix::DESKTOP_ENVIRONMENT_KDE4
) {
157 // KDE3 didn't use DBus, which our KWallet store uses.
158 VLOG(1) << "Trying KWallet for password storage.";
159 backend
.reset(new NativeBackendKWallet(id
, prefs
));
161 VLOG(1) << "Using KWallet for password storage.";
164 } else if (desktop_env
== base::nix::DESKTOP_ENVIRONMENT_GNOME
||
165 desktop_env
== base::nix::DESKTOP_ENVIRONMENT_UNITY
||
166 desktop_env
== base::nix::DESKTOP_ENVIRONMENT_XFCE
) {
167 #if defined(USE_GNOME_KEYRING)
168 VLOG(1) << "Trying GNOME keyring for password storage.";
169 backend
.reset(new NativeBackendGnome(id
, prefs
));
171 VLOG(1) << "Using GNOME keyring for password storage.";
174 #endif // defined(USE_GNOME_KEYRING)
177 if (!backend
.get()) {
178 LOG(WARNING
) << "Using basic (unencrypted) store for password storage. "
179 "See http://code.google.com/p/chromium/wiki/LinuxPasswordStorage for "
180 "more information about password storage options.";
183 ps
= new PasswordStoreX(login_db
, profile
, backend
.release());
184 #elif defined(USE_OZONE)
185 ps
= new PasswordStoreDefault(login_db
, profile
);
192 if (!ps
.get() || !ps
->Init()) {
193 NOTREACHED() << "Could not initialize password manager.";
200 void PasswordStoreFactory::RegisterProfilePrefs(
201 user_prefs::PrefRegistrySyncable
* registry
) {
202 #if !defined(OS_CHROMEOS) && defined(USE_X11)
203 registry
->RegisterIntegerPref(
204 prefs::kLocalProfileId
,
205 kInvalidLocalProfileId
,
206 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
208 // Notice that the preprocessor conditions above are exactly those that will
209 // result in using PasswordStoreX in CreatePasswordStore() below.
210 PasswordStoreX::RegisterProfilePrefs(registry
);
214 content::BrowserContext
* PasswordStoreFactory::GetBrowserContextToUse(
215 content::BrowserContext
* context
) const {
216 return chrome::GetBrowserContextRedirectedInIncognito(context
);
219 bool PasswordStoreFactory::ServiceIsNULLWhileTesting() const {