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"
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"
33 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
34 #include "chrome/browser/password_manager/password_store_x.h"
37 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && \
41 const LocalProfileId kInvalidLocalProfileId
=
42 static_cast<LocalProfileId
>(0);
47 scoped_refptr
<PasswordStore
> PasswordStoreFactory::GetForProfile(
49 Profile::ServiceAccessType sat
) {
50 if (sat
== Profile::IMPLICIT_ACCESS
&& profile
->IsOffTheRecord()) {
51 NOTREACHED() << "This profile is OffTheRecord";
55 return static_cast<PasswordStore
*>(
56 GetInstance()->GetServiceForProfile(profile
, true).get());
60 PasswordStoreFactory
* PasswordStoreFactory::GetInstance() {
61 return Singleton
<PasswordStoreFactory
>::get();
64 PasswordStoreFactory::PasswordStoreFactory()
65 : RefcountedProfileKeyedServiceFactory(
67 ProfileDependencyManager::GetInstance()) {
68 DependsOn(WebDataServiceFactory::GetInstance());
71 PasswordStoreFactory::~PasswordStoreFactory() {}
73 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && \
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
<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.";
113 ps
= new PasswordStoreWin(
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
);
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
;
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
));
158 VLOG(1) << "Using KWallet for password storage.";
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
));
168 VLOG(1) << "Using GNOME keyring for password storage.";
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());
187 if (!ps
|| !ps
->Init()) {
188 NOTREACHED() << "Could not initialize password manager.";
195 void PasswordStoreFactory::RegisterUserPrefs(PrefService
* prefs
) {
196 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID) \
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
);
208 bool PasswordStoreFactory::ServiceRedirectedInIncognito() {
212 bool PasswordStoreFactory::ServiceIsNULLWhileTesting() {