summaryrefslogtreecommitdiffstats
path: root/chrome/browser/password_manager
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-30 00:51:16 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-30 00:51:16 +0000
commitc01ec9515d1892e2a62d3e4423a2bb37ac79e551 (patch)
treee5906c772e92e04e3b333716b78a4b43d185c7f6 /chrome/browser/password_manager
parent70d56be631ab6616cd7661468df6ba91c5821193 (diff)
downloadchromium_src-c01ec9515d1892e2a62d3e4423a2bb37ac79e551.zip
chromium_src-c01ec9515d1892e2a62d3e4423a2bb37ac79e551.tar.gz
chromium_src-c01ec9515d1892e2a62d3e4423a2bb37ac79e551.tar.bz2
Re-land the password store work from bug 8205, with changes that should fix bug 12479. The Linux pieces are still disabled, however.
BUG=8205 TEST=Password autofill should continue to work on Windows. Review URL: http://codereview.chromium.org/114057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17273 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/password_manager')
-rw-r--r--chrome/browser/password_manager/password_form_manager.cc87
-rw-r--r--chrome/browser/password_manager/password_form_manager.h23
-rw-r--r--chrome/browser/password_manager/password_form_manager_win.cc77
-rw-r--r--chrome/browser/password_manager/password_manager.cc4
-rw-r--r--chrome/browser/password_manager/password_manager.h2
-rw-r--r--chrome/browser/password_manager/password_store.cc92
-rw-r--r--chrome/browser/password_manager/password_store.h115
-rw-r--r--chrome/browser/password_manager/password_store_default.cc83
-rw-r--r--chrome/browser/password_manager/password_store_default.h67
-rw-r--r--chrome/browser/password_manager/password_store_gnome.cc177
-rw-r--r--chrome/browser/password_manager/password_store_gnome.h40
-rw-r--r--chrome/browser/password_manager/password_store_kwallet.cc387
-rw-r--r--chrome/browser/password_manager/password_store_kwallet.h111
-rw-r--r--chrome/browser/password_manager/password_store_win.cc105
-rw-r--r--chrome/browser/password_manager/password_store_win.h39
15 files changed, 1257 insertions, 152 deletions
diff --git a/chrome/browser/password_manager/password_form_manager.cc b/chrome/browser/password_manager/password_form_manager.cc
index cf40a1b..26ebd4c 100644
--- a/chrome/browser/password_manager/password_form_manager.cc
+++ b/chrome/browser/password_manager/password_form_manager.cc
@@ -21,7 +21,7 @@ PasswordFormManager::PasswordFormManager(Profile* profile,
observed_form_(observed_form),
is_new_login_(true),
password_manager_(password_manager),
- pending_login_query_(NULL),
+ pending_login_query_(0),
preferred_match_(NULL),
state_(PRE_MATCHING_PHASE),
profile_(profile) {
@@ -168,25 +168,21 @@ void PasswordFormManager::FetchMatchingLoginsFromWebDatabase() {
DCHECK_EQ(state_, PRE_MATCHING_PHASE);
DCHECK(!pending_login_query_);
state_ = MATCHING_PHASE;
- WebDataService* web_data_service =
- profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
- if (!web_data_service) {
+ PasswordStore* password_store =
+ profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS);
+ if (!password_store) {
NOTREACHED();
return;
}
- pending_login_query_ = web_data_service->GetLogins(observed_form_, this);
+ pending_login_query_ = password_store->GetLogins(observed_form_, this);
}
bool PasswordFormManager::HasCompletedMatching() {
return state_ == POST_MATCHING_PHASE;
}
-void PasswordFormManager::OnRequestDone(WebDataService::Handle h,
- const WDTypedResult* result) {
- // Get the result from the database into a usable form.
- const WDResult<std::vector<PasswordForm*> >* r =
- static_cast<const WDResult<std::vector<PasswordForm*> >*>(result);
- std::vector<PasswordForm*> logins_result = r->GetValue();
+void PasswordFormManager::OnRequestDone(int handle,
+ const std::vector<PasswordForm*>& logins_result) {
// Note that the result gets deleted after this call completes, but we own
// the PasswordForm objects pointed to by the result vector, thus we keep
// copies to a minimum here.
@@ -239,14 +235,6 @@ void PasswordFormManager::OnRequestDone(WebDataService::Handle h,
// We're done matching now.
state_ = POST_MATCHING_PHASE;
- if (best_score <= 0) {
-#if defined(OS_WIN)
- state_ = PRE_MATCHING_PHASE;
- FetchMatchingIE7LoginFromWebDatabase();
-#endif
- return;
- }
-
for (std::vector<PasswordForm>::const_iterator it = empties.begin();
it != empties.end(); ++it) {
// If we don't already have a result with the same username, add the
@@ -272,30 +260,17 @@ void PasswordFormManager::OnRequestDone(WebDataService::Handle h,
}
}
-void PasswordFormManager::OnWebDataServiceRequestDone(WebDataService::Handle h,
- const WDTypedResult* result) {
+void PasswordFormManager::OnPasswordStoreRequestDone(
+ int handle, const std::vector<PasswordForm*>& result) {
DCHECK_EQ(state_, MATCHING_PHASE);
- DCHECK_EQ(pending_login_query_, h);
- DCHECK(result);
- pending_login_query_ = NULL;
+ DCHECK_EQ(pending_login_query_, handle);
- if (!result)
+ if (result.empty()) {
+ state_ = POST_MATCHING_PHASE;
return;
-
- switch (result->GetType()) {
- case PASSWORD_RESULT: {
- OnRequestDone(h, result);
- break;
- }
-#if defined(OS_WIN)
- case PASSWORD_IE7_RESULT: {
- OnIE7RequestDone(h, result);
- break;
- }
-#endif
- default:
- NOTREACHED();
}
+
+ OnRequestDone(handle, result);
}
bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const {
@@ -322,14 +297,15 @@ void PasswordFormManager::SaveAsNewLogin() {
DCHECK(!profile_->IsOffTheRecord());
- WebDataService* web_data_service =
- profile_->GetWebDataService(Profile::IMPLICIT_ACCESS);
- if (!web_data_service) {
+ PasswordStore* password_store =
+ profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS);
+ if (!password_store) {
NOTREACHED();
return;
}
+
pending_credentials_.date_created = Time::Now();
- web_data_service->AddLogin(pending_credentials_);
+ password_store->AddLogin(pending_credentials_);
}
void PasswordFormManager::UpdateLogin() {
@@ -341,9 +317,9 @@ void PasswordFormManager::UpdateLogin() {
DCHECK(!IsNewLogin() && pending_credentials_.preferred);
DCHECK(!profile_->IsOffTheRecord());
- WebDataService* web_data_service =
- profile_->GetWebDataService(Profile::IMPLICIT_ACCESS);
- if (!web_data_service) {
+ PasswordStore* password_store =
+ profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS);
+ if (!password_store) {
NOTREACHED();
return;
}
@@ -355,7 +331,7 @@ void PasswordFormManager::UpdateLogin() {
iter->second->preferred) {
// This wasn't the selected login but it used to be preferred.
iter->second->preferred = false;
- web_data_service->UpdateLogin(*iter->second);
+ password_store->UpdateLogin(*iter->second);
}
}
// Update the new preferred login.
@@ -380,23 +356,20 @@ void PasswordFormManager::UpdateLogin() {
PasswordForm copy(pending_credentials_);
copy.origin = observed_form_.origin;
copy.action = observed_form_.action;
- web_data_service->AddLogin(copy);
+ password_store->AddLogin(copy);
} else {
- web_data_service->UpdateLogin(pending_credentials_);
+ password_store->UpdateLogin(pending_credentials_);
}
}
void PasswordFormManager::CancelLoginsQuery() {
- if (!pending_login_query_)
- return;
- WebDataService* web_data_service =
- profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
- if (!web_data_service) {
- NOTREACHED();
+ PasswordStore* password_store =
+ profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS);
+ if (!password_store) {
+ // Can be NULL in unit tests.
return;
}
- web_data_service->CancelRequest(pending_login_query_);
- pending_login_query_ = NULL;
+ password_store->CancelLoginsQuery(pending_login_query_);
}
int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
diff --git a/chrome/browser/password_manager/password_form_manager.h b/chrome/browser/password_manager/password_form_manager.h
index 332eea3..90ffc86 100644
--- a/chrome/browser/password_manager/password_form_manager.h
+++ b/chrome/browser/password_manager/password_form_manager.h
@@ -8,6 +8,7 @@
#include "build/build_config.h"
#include "base/stl_util-inl.h"
+#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "webkit/glue/password_form.h"
@@ -16,7 +17,7 @@ class Profile;
// Per-password-form-{on-page, dialog} class responsible for interactions
// between a given form, the per-tab PasswordManager, and the web database.
-class PasswordFormManager : public WebDataServiceConsumer {
+class PasswordFormManager : public PasswordStoreConsumer {
public:
// web_data_service allows access to current profile's Web Data
// password_manager owns this object
@@ -34,9 +35,6 @@ class PasswordFormManager : public WebDataServiceConsumer {
// Retrieves potential matching logins from the database.
void FetchMatchingLoginsFromWebDatabase();
-#if defined(OS_WIN)
- void FetchMatchingIE7LoginFromWebDatabase();
-#endif
// Simple state-check to verify whether this object as received a callback
// from the web database and completed its matching phase. Note that the
@@ -60,19 +58,12 @@ class PasswordFormManager : public WebDataServiceConsumer {
// managed by this.
bool IsNewLogin();
- // WebDataServiceConsumer implementation. If matches were found
- // (in *result), this is where we determine we need to autofill.
- virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
- const WDTypedResult* result);
-
// Determines if we need to autofill given the results of the query.
- void OnRequestDone(WebDataService::Handle h, const WDTypedResult* result);
+ void OnRequestDone(int handle, const std::vector<PasswordForm*>& result);
-#if defined(OS_WIN)
- // Determines if we need to autofill given the results of the query in the
- // ie7_password table.
- void OnIE7RequestDone(WebDataService::Handle h, const WDTypedResult* result);
-#endif
+ // PasswordStoreConsumer implementation.
+ virtual void OnPasswordStoreRequestDone(
+ int handle, const std::vector<PasswordForm*>& result);
// A user opted to 'never remember' passwords for this form.
// Blacklist it so that from now on when it is seen we ignore it.
@@ -141,7 +132,7 @@ class PasswordFormManager : public WebDataServiceConsumer {
const PasswordManager* const password_manager_;
// Handle to any pending WebDataService::GetLogins query.
- WebDataService::Handle pending_login_query_;
+ int pending_login_query_;
// Convenience pointer to entry in best_matches_ that is marked
// as preferred. This is only allowed to be null if there are no best matches
diff --git a/chrome/browser/password_manager/password_form_manager_win.cc b/chrome/browser/password_manager/password_form_manager_win.cc
index a075617..e69de29 100644
--- a/chrome/browser/password_manager/password_form_manager_win.cc
+++ b/chrome/browser/password_manager/password_form_manager_win.cc
@@ -1,77 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/password_manager/password_form_manager.h"
-
-#include "base/string_util.h"
-#include "chrome/browser/password_manager/ie7_password.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/profile.h"
-
-void PasswordFormManager::FetchMatchingIE7LoginFromWebDatabase() {
- DCHECK_EQ(state_, PRE_MATCHING_PHASE);
- DCHECK(!pending_login_query_);
- state_ = MATCHING_PHASE;
- WebDataService* web_data_service =
- profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
- if (!web_data_service) {
- NOTREACHED();
- return;
- }
-
- IE7PasswordInfo info;
- std::wstring url = ASCIIToWide(observed_form_.origin.spec());
- info.url_hash = ie7_password::GetUrlHash(url);
- pending_login_query_ = web_data_service->GetIE7Login(info, this);
-}
-
-void PasswordFormManager::OnIE7RequestDone(WebDataService::Handle h,
- const WDTypedResult* result) {
- // Get the result from the database into a usable form.
- const WDResult<IE7PasswordInfo>* r =
- static_cast<const WDResult<IE7PasswordInfo>*>(result);
- IE7PasswordInfo result_value = r->GetValue();
-
- state_ = POST_MATCHING_PHASE;
-
- if (!result_value.encrypted_data.empty()) {
- // We got a result.
- // Delete the entry. If it's good we will add it to the real saved password
- // table.
- WebDataService* web_data_service =
- profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
- if (!web_data_service) {
- NOTREACHED();
- return;
- }
- web_data_service->RemoveIE7Login(result_value);
-
- std::wstring username;
- std::wstring password;
- std::wstring url = ASCIIToWide(observed_form_.origin.spec());
- if (!ie7_password::DecryptPassword(url, result_value.encrypted_data,
- &username, &password)) {
- return;
- }
-
- PasswordForm* auto_fill = new PasswordForm(observed_form_);
- auto_fill->username_value = username;
- auto_fill->password_value = password;
- auto_fill->preferred = true;
- auto_fill->ssl_valid = observed_form_.origin.SchemeIsSecure();
- auto_fill->date_created = result_value.date_created;
- // Add this PasswordForm to the saved password table.
- web_data_service->AddLogin(*auto_fill);
-
- if (IgnoreResult(*auto_fill)) {
- delete auto_fill;
- return;
- }
-
- best_matches_[auto_fill->username_value] = auto_fill;
- preferred_match_ = auto_fill;
- password_manager_->Autofill(observed_form_, best_matches_,
- preferred_match_);
- }
-}
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index b558bf94..e09aa08 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -8,6 +8,7 @@
#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_registrar.h"
@@ -234,8 +235,9 @@ void PasswordManager::Autofill(
return;
}
default:
- if (observer_)
+ if (observer_) {
observer_->OnAutofillDataAvailable(preferred_match->username_value,
preferred_match->password_value);
+ }
}
}
diff --git a/chrome/browser/password_manager/password_manager.h b/chrome/browser/password_manager/password_manager.h
index 9c80714..175e4cd 100644
--- a/chrome/browser/password_manager/password_manager.h
+++ b/chrome/browser/password_manager/password_manager.h
@@ -7,13 +7,13 @@
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
-#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/views/login_view.h"
#include "chrome/common/pref_member.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/password_form_dom_manager.h"
+class PasswordFormManager;
class PrefService;
class TabContents;
diff --git a/chrome/browser/password_manager/password_store.cc b/chrome/browser/password_manager/password_store.cc
new file mode 100644
index 0000000..d84b788
--- /dev/null
+++ b/chrome/browser/password_manager/password_store.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_store.h"
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+
+using std::vector;
+
+PasswordStore::PasswordStore() : handle_(0) {
+}
+
+bool PasswordStore::Init() {
+ thread_.reset(new base::Thread("Chrome_PasswordStore_Thread"));
+
+ if (!thread_->Start()) {
+ thread_.reset(NULL);
+ return false;
+ }
+
+ return true;
+}
+
+void PasswordStore::ScheduleTask(Task* task) {
+ if (thread_.get()) {
+ thread_->message_loop()->PostTask(FROM_HERE, task);
+ }
+}
+
+void PasswordStore::AddLogin(const PasswordForm& form) {
+ ScheduleTask(NewRunnableMethod(
+ this, &PasswordStore::AddLoginImpl, form));
+}
+
+void PasswordStore::UpdateLogin(const PasswordForm& form) {
+ ScheduleTask(NewRunnableMethod(
+ this, &PasswordStore::UpdateLoginImpl, form));
+}
+
+void PasswordStore::RemoveLogin(const PasswordForm& form) {
+ ScheduleTask(NewRunnableMethod(
+ this, &PasswordStore::RemoveLoginImpl, form));
+}
+
+int PasswordStore::GetLogins(const PasswordForm& form,
+ PasswordStoreConsumer* consumer) {
+ int handle = handle_++;
+ GetLoginsRequest* request = new GetLoginsRequest(form, consumer, handle);
+
+ pending_requests_.insert(handle);
+
+ ScheduleTask(NewRunnableMethod(this, &PasswordStore::GetLoginsImpl, request));
+ return handle;
+}
+
+void PasswordStore::NotifyConsumer(GetLoginsRequest* request,
+ const vector<PasswordForm*> forms) {
+ scoped_ptr<GetLoginsRequest> request_ptr(request);
+
+ DCHECK(MessageLoop::current() == thread_->message_loop());
+ request->message_loop->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &PasswordStore::NotifyConsumerImpl,
+ request->consumer, request->handle, forms));
+}
+
+void PasswordStore::NotifyConsumerImpl(PasswordStoreConsumer* consumer,
+ int handle,
+ const vector<PasswordForm*> forms) {
+ // Don't notify the consumer if the request was canceled.
+ if (pending_requests_.find(handle) == pending_requests_.end())
+ return;
+ pending_requests_.erase(handle);
+
+ consumer->OnPasswordStoreRequestDone(handle, forms);
+}
+
+void PasswordStore::CancelLoginsQuery(int handle) {
+ pending_requests_.erase(handle);
+}
+
+PasswordStore::GetLoginsRequest::GetLoginsRequest(
+ const PasswordForm& form,
+ PasswordStoreConsumer* consumer,
+ int handle)
+ : form(form),
+ consumer(consumer),
+ handle(handle),
+ message_loop(MessageLoop::current()) {
+}
diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h
new file mode 100644
index 0000000..7b2144c
--- /dev/null
+++ b/chrome/browser/password_manager/password_store.h
@@ -0,0 +1,115 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE
+
+#include <set>
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/thread.h"
+#include "webkit/glue/password_form.h"
+
+class Profile;
+class Task;
+
+class PasswordStoreConsumer {
+ public:
+ virtual ~PasswordStoreConsumer() {}
+ // Call this when the request is finished. If there are no results, call it
+ // anyway with an empty vector.
+ virtual void OnPasswordStoreRequestDone(
+ int handle, const std::vector<PasswordForm*>& result) = 0;
+};
+
+// Interface for storing form passwords in a platform-specific secure way.
+// The login request/manipulation API is not threadsafe.
+class PasswordStore : public base::RefCountedThreadSafe<PasswordStore> {
+ public:
+ PasswordStore();
+ virtual ~PasswordStore() {}
+
+ // Reimplement this to add custom initialization. Always call this too.
+ virtual bool Init();
+
+ // Adds the given PasswordForm to the secure password store asynchronously.
+ void AddLogin(const PasswordForm& form);
+ // Updates the matching PasswordForm in the secure password store (async).
+ void UpdateLogin(const PasswordForm& form);
+ // Removes the matching PasswordForm from the secure password store (async).
+ void RemoveLogin(const PasswordForm& form);
+ // Searches for a matching PasswordForm and returns a handle so the async
+ // request can be tracked. Implement the PasswordStoreConsumer interface to
+ // be notified on completion.
+ int GetLogins(const PasswordForm& form,
+ PasswordStoreConsumer* consumer);
+
+ // Cancels a previous GetLogins query (async)
+ virtual void CancelLoginsQuery(int handle);
+
+ protected:
+ // Simple container class that represents a GetLogins request.
+ // Created in GetLogins and passed to GetLoginsImpl.
+ struct GetLoginsRequest {
+ GetLoginsRequest(const PasswordForm& f,
+ PasswordStoreConsumer* c,
+ int handle);
+
+ // The query form that was originally passed to GetLogins
+ PasswordForm form;
+ // The consumer to notify when this GetLogins request is complete
+ PasswordStoreConsumer* consumer;
+ // A unique handle for the request
+ int handle;
+ // The message loop that the GetLogins request was made from. We send the
+ // result back to the consumer in this same message loop.
+ MessageLoop* message_loop;
+
+ DISALLOW_COPY_AND_ASSIGN(GetLoginsRequest);
+ };
+
+ // Schedule the given task to be run in the PasswordStore's own thread.
+ void ScheduleTask(Task* task);
+
+ // These will be run in PasswordStore's own thread.
+ // Synchronous implementation to add the given login.
+ virtual void AddLoginImpl(const PasswordForm& form) = 0;
+ // Synchronous implementation to update the given login.
+ virtual void UpdateLoginImpl(const PasswordForm& form) = 0;
+ // Synchronous implementation to remove the given login.
+ virtual void RemoveLoginImpl(const PasswordForm& form) = 0;
+ // Should find all PasswordForms with the same signon_realm. The results
+ // will then be scored by the PasswordFormManager. Once they are found
+ // (or not), the consumer should be notified.
+ virtual void GetLoginsImpl(GetLoginsRequest* request) = 0;
+
+ // Notifies the consumer that GetLoginsImpl() is complete.
+ void NotifyConsumer(GetLoginsRequest* request,
+ const std::vector<PasswordForm*> forms);
+
+ // Next handle to return from GetLogins() to allow callers to track
+ // their request.
+ int handle_;
+
+ // Thread that the synchronous methods are run in.
+ scoped_ptr<base::Thread> thread_;
+
+ private:
+ // Called by NotifyConsumer, but runs in the consumer's thread. Will not
+ // call the consumer if the request was canceled. This extra layer is here so
+ // that PasswordStoreConsumer doesn't have to be reference counted (we assume
+ // consumers will cancel their requests before they are destroyed).
+ void NotifyConsumerImpl(PasswordStoreConsumer* consumer, int handle,
+ const std::vector<PasswordForm*> forms);
+
+ // List of pending request handles. Handles are removed from the set when
+ // they finish or are canceled.
+ std::set<int> pending_requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordStore);
+};
+
+#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE
diff --git a/chrome/browser/password_manager/password_store_default.cc b/chrome/browser/password_manager/password_store_default.cc
new file mode 100644
index 0000000..c7e89c5
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_default.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_store_default.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/common/chrome_constants.h"
+
+#include "base/logging.h"
+#include "base/task.h"
+
+PasswordStoreDefault::PasswordStoreDefault(WebDataService* web_data_service)
+ : web_data_service_(web_data_service) {
+}
+
+void PasswordStoreDefault::AddLoginImpl(const PasswordForm& form) {
+ web_data_service_->AddLogin(form);
+}
+
+void PasswordStoreDefault::RemoveLoginImpl(const PasswordForm& form) {
+ web_data_service_->RemoveLogin(form);
+}
+
+void PasswordStoreDefault::UpdateLoginImpl(const PasswordForm& form) {
+ web_data_service_->UpdateLogin(form);
+}
+
+void PasswordStoreDefault::GetLoginsImpl(GetLoginsRequest* request) {
+ int web_data_handle = web_data_service_->GetLogins(request->form, this);
+ AddPendingWebDataServiceRequest(web_data_handle, request);
+}
+
+void PasswordStoreDefault::OnWebDataServiceRequestDone(
+ WebDataService::Handle h,
+ const WDTypedResult *result) {
+ // Look up this handle in our request map to get the original
+ // GetLoginsRequest.
+ PendingRequestMap::iterator it(pending_requests_.find(h));
+ DCHECK(it != pending_requests_.end());
+
+ GetLoginsRequest* request = it->second;
+ pending_requests_.erase(it);
+
+ DCHECK(result);
+ if (!result)
+ return;
+
+ const WDResult<std::vector<PasswordForm*> >* r =
+ static_cast<const WDResult<std::vector<PasswordForm*> >*>(result);
+
+ NotifyConsumer(request, r->GetValue());
+
+ RemovePendingWebDataServiceRequest(h);
+}
+
+void PasswordStoreDefault::AddPendingWebDataServiceRequest(
+ WebDataService::Handle handle, GetLoginsRequest* request) {
+ pending_requests_.insert(PendingRequestMap::value_type(handle, request));
+
+ // WebDataService callbacks are non-retaining. Since there would be a race
+ // around cancelling the requests in the desctructor vs. getting a callback
+ // in this worker thread, just make sure that we stick around instead.
+ this->AddRef();
+}
+
+void PasswordStoreDefault::RemovePendingWebDataServiceRequest(
+ WebDataService::Handle handle) {
+ PendingRequestMap::iterator it(pending_requests_.find(handle));
+ DCHECK(it != pending_requests_.end());
+ pending_requests_.erase(it);
+
+ // Balance the AddRef in AddPendingWebDataServiceRequest.
+ this->Release();
+}
+
+PasswordStore::GetLoginsRequest*
+ PasswordStoreDefault::GetLoginsRequestForWebDataServiceRequest(
+ WebDataService::Handle handle) {
+ PendingRequestMap::iterator it(pending_requests_.find(handle));
+ if (it == pending_requests_.end())
+ return NULL;
+ return it->second;
+}
diff --git a/chrome/browser/password_manager/password_store_default.h b/chrome/browser/password_manager/password_store_default.h
new file mode 100644
index 0000000..c979da19
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_default.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_DEFAULT
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_DEFAULT
+
+#include <map>
+
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/password_manager/password_store.h"
+#include "chrome/browser/webdata/web_data_service.h"
+
+class Task;
+
+// Simple password store implementation that delegates everything to
+// the WebDatabase.
+// TODO(stuartmorgan): This is a temprorary shim for Windows from the new
+// PasswordStore interface to the old model of storing passwords in the
+// WebDatabase. This should be replaced by a self-contained Windows
+// implementation once PasswordStore is completed.
+class PasswordStoreDefault : public PasswordStore,
+ public WebDataServiceConsumer {
+ public:
+ explicit PasswordStoreDefault(WebDataService* web_data_service);
+ virtual ~PasswordStoreDefault() {}
+
+ protected:
+ // Implements PasswordStore interface.
+ void AddLoginImpl(const PasswordForm& form);
+ void UpdateLoginImpl(const PasswordForm& form);
+ void RemoveLoginImpl(const PasswordForm& form);
+ void GetLoginsImpl(GetLoginsRequest* request);
+
+ // Called when a WebDataService method finishes.
+ // Overrides must call RemovePendingWebDataServiceRequest.
+ virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
+ const WDTypedResult* result);
+
+ // Keeps track of a pending WebDataService request, and the original
+ // GetLogins request it is associated with.
+ // Increases the reference count of |this|, so must be balanced with a
+ // call to RemovePendingWebDataServiceRequest.
+ void AddPendingWebDataServiceRequest(WebDataService::Handle handle,
+ GetLoginsRequest* request);
+ // Removes a WebDataService request from the list of pending requests,
+ // and reduces the reference count of |this|.
+ void RemovePendingWebDataServiceRequest(WebDataService::Handle handle);
+ // Returns the GetLoginsRequest associated with |handle|.
+ GetLoginsRequest* GetLoginsRequestForWebDataServiceRequest(
+ WebDataService::Handle handle);
+
+ scoped_refptr<WebDataService> web_data_service_;
+
+ private:
+ // Methods in this class call async WebDataService methods. This mapping
+ // remembers which WebDataService request corresponds to which PasswordStore
+ // request.
+ typedef std::map<WebDataService::Handle, GetLoginsRequest*> PendingRequestMap;
+ PendingRequestMap pending_requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordStoreDefault);
+};
+
+#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_DEFAULT
diff --git a/chrome/browser/password_manager/password_store_gnome.cc b/chrome/browser/password_manager/password_store_gnome.cc
new file mode 100644
index 0000000..93f3b6f
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_gnome.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_store_gnome.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "base/time.h"
+
+using std::map;
+using std::string;
+using std::vector;
+
+// Schema is analagous to the fields in PasswordForm.
+const GnomeKeyringPasswordSchema PasswordStoreGnome::kGnomeSchema = {
+ GNOME_KEYRING_ITEM_GENERIC_SECRET, {
+ { "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "action_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "ssl_valid", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
+ { "preferred", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
+ { "date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+ { "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
+ { "scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
+ { NULL }
+ }
+};
+
+PasswordStoreGnome::PasswordStoreGnome() {
+}
+
+PasswordStoreGnome::~PasswordStoreGnome() {
+}
+
+bool PasswordStoreGnome::Init() {
+ return PasswordStore::Init() && gnome_keyring_is_available();
+}
+
+void PasswordStoreGnome::AddLoginImpl(const PasswordForm& form) {
+ AutoLock l(gnome_keyring_lock_);
+ GnomeKeyringResult result = gnome_keyring_store_password_sync(
+ &kGnomeSchema,
+ NULL, // Default keyring.
+ // TODO(johnmaguire@google.com): Localise this.
+ "Form password stored by Chrome",
+ WideToASCII(form.password_value).c_str(),
+ "origin_url", form.origin.spec().c_str(),
+ "action_url", form.action.spec().c_str(),
+ "username_element", form.username_element.c_str(),
+ "username_value", form.username_value.c_str(),
+ "password_element", form.password_element.c_str(),
+ "submit_element", form.submit_element.c_str(),
+ "signon_realm", form.signon_realm.c_str(),
+ "ssl_valid", form.ssl_valid,
+ "preferred", form.preferred,
+ "date_created", Int64ToString(base::Time::Now().ToTimeT()).c_str(),
+ "blacklisted_by_user", form.blacklisted_by_user,
+ "scheme", form.scheme,
+ NULL);
+
+ if (result != GNOME_KEYRING_RESULT_OK) {
+ LOG(ERROR) << "Keyring save failed: "
+ << gnome_keyring_result_to_message(result);
+ }
+}
+
+void PasswordStoreGnome::UpdateLoginImpl(const PasswordForm& form) {
+ AddLoginImpl(form); // Add & Update are the same in gnome keyring.
+}
+
+void PasswordStoreGnome::RemoveLoginImpl(const PasswordForm& form) {
+ AutoLock l(gnome_keyring_lock_);
+ GnomeKeyringResult result = gnome_keyring_delete_password_sync(
+ &kGnomeSchema,
+ "origin_url", form.origin.spec().c_str(),
+ "action_url", form.action.spec().c_str(),
+ "username_element", form.username_element.c_str(),
+ "username_value", form.username_value.c_str(),
+ "password_element", form.password_element.c_str(),
+ "submit_element", form.submit_element.c_str(),
+ "signon_realm", form.signon_realm.c_str(),
+ "ssl_valid", form.ssl_valid,
+ "preferred", form.preferred,
+ "date_created", Int64ToString(form.date_created.ToTimeT()).c_str(),
+ "blacklisted_by_user", form.blacklisted_by_user,
+ "scheme", form.scheme,
+ NULL);
+ if (result != GNOME_KEYRING_RESULT_OK) {
+ LOG(ERROR) << "Keyring delete failed: "
+ << gnome_keyring_result_to_message(result);
+ }
+}
+
+void PasswordStoreGnome::GetLoginsImpl(GetLoginsRequest* request) {
+ AutoLock l(gnome_keyring_lock_);
+ GList* found = NULL;
+ // Search gnome keyring for matching passwords.
+ GnomeKeyringResult result = gnome_keyring_find_itemsv_sync(
+ GNOME_KEYRING_ITEM_GENERIC_SECRET,
+ &found,
+ "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+ request->form.signon_realm.c_str(),
+ NULL);
+ vector<PasswordForm*> forms;
+ if (result == GNOME_KEYRING_RESULT_NO_MATCH) {
+ NotifyConsumer(request, forms);
+ return;
+ } else if (result != GNOME_KEYRING_RESULT_OK) {
+ LOG(ERROR) << "Keyring find failed: "
+ << gnome_keyring_result_to_message(result);
+ NotifyConsumer(request, forms);
+ return;
+ }
+
+ // Parse all the results from the returned GList into a
+ // vector<PasswordForm*>. PasswordForms are allocated on the heap. These
+ // will be deleted by the consumer.
+ GList* element = g_list_first(found);
+ while (element != NULL) {
+ GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data);
+ char* password = data->secret;
+
+ GnomeKeyringAttributeList* attributes = data->attributes;
+ // Read the string & int attributes into the appropriate map.
+ map<string, string> string_attribute_map;
+ map<string, uint32> uint_attribute_map;
+ for (unsigned int i = 0; i < attributes->len; ++i) {
+ GnomeKeyringAttribute attribute =
+ gnome_keyring_attribute_list_index(attributes, i);
+ if (attribute.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
+ string_attribute_map[string(attribute.name)] =
+ string(attribute.value.string);
+ } else if (attribute.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) {
+ uint_attribute_map[string(attribute.name)] = attribute.value.integer;
+ }
+ }
+
+ PasswordForm* form = new PasswordForm();
+ form->origin = GURL(string_attribute_map["origin_url"]);
+ form->action = GURL(string_attribute_map["action_url"]);
+ form->username_element =
+ ASCIIToWide(string(string_attribute_map["username_element"]));
+ form->username_value =
+ ASCIIToWide(string(string_attribute_map["username_value"]));
+ form->password_element =
+ ASCIIToWide(string(string_attribute_map["password_element"]));
+ form->password_value = ASCIIToWide(string(password));
+ form->submit_element =
+ ASCIIToWide(string(string_attribute_map["submit_element"]));
+ form->signon_realm = uint_attribute_map["signon_realm"];
+ form->ssl_valid = uint_attribute_map["ssl_valid"];
+ form->preferred = uint_attribute_map["preferred"];
+ string date = string_attribute_map["date_created"];
+ int64 date_created = 0;
+ DCHECK(StringToInt64(date, &date_created) && date_created != 0);
+ form->date_created = base::Time::FromTimeT(date_created);
+ form->blacklisted_by_user = uint_attribute_map["blacklisted_by_user"];
+ form->scheme =
+ static_cast<PasswordForm::Scheme>(uint_attribute_map["scheme"]);
+
+ forms.push_back(form);
+
+ element = g_list_next(element);
+ }
+ gnome_keyring_found_list_free(found);
+ found = NULL;
+
+ NotifyConsumer(request, forms);
+}
diff --git a/chrome/browser/password_manager/password_store_gnome.h b/chrome/browser/password_manager/password_store_gnome.h
new file mode 100644
index 0000000..abbd054
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_gnome.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_GNOME
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_GNOME
+
+extern "C" {
+#include <gnome-keyring.h>
+}
+
+#include "base/lock.h"
+#include "chrome/browser/password_manager/password_store.h"
+
+class Profile;
+class Task;
+
+// PasswordStore implementation using Gnome Keyring.
+class PasswordStoreGnome : public PasswordStore {
+ public:
+ PasswordStoreGnome();
+ virtual ~PasswordStoreGnome();
+
+ virtual bool Init();
+
+ private:
+ void AddLoginImpl(const PasswordForm& form);
+ void UpdateLoginImpl(const PasswordForm& form);
+ void RemoveLoginImpl(const PasswordForm& form);
+ void GetLoginsImpl(GetLoginsRequest* request);
+
+ static const GnomeKeyringPasswordSchema kGnomeSchema;
+
+ // Mutex for all interactions with Gnome Keyring.
+ Lock gnome_keyring_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordStoreGnome);
+};
+
+#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_GNOME
diff --git a/chrome/browser/password_manager/password_store_kwallet.cc b/chrome/browser/password_manager/password_store_kwallet.cc
new file mode 100644
index 0000000..1c50e3e
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_kwallet.cc
@@ -0,0 +1,387 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_store_kwallet.h"
+
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/pickle.h"
+#include "base/string_util.h"
+#include "base/task.h"
+
+using std::string;
+using std::vector;
+
+const char* PasswordStoreKWallet::kAppId = "Chrome";
+const char* PasswordStoreKWallet::kKWalletFolder = "Chrome Form Data";
+
+const char* PasswordStoreKWallet::kKWalletServiceName = "org.kde.kwalletd";
+const char* PasswordStoreKWallet::kKWalletPath = "/modules/kwalletd";
+const char* PasswordStoreKWallet::kKWalletInterface = "org.kde.KWallet";
+const char* PasswordStoreKWallet::kKLauncherServiceName = "org.kde.klauncher";
+const char* PasswordStoreKWallet::kKLauncherPath = "/KLauncher";
+const char* PasswordStoreKWallet::kKLauncherInterface = "org.kde.KLauncher";
+
+PasswordStoreKWallet::PasswordStoreKWallet()
+ : error_(NULL),
+ connection_(NULL),
+ proxy_(NULL) {
+}
+
+PasswordStoreKWallet::~PasswordStoreKWallet() {
+ if (proxy_) {
+ g_object_unref(proxy_);
+ }
+}
+
+bool PasswordStoreKWallet::Init() {
+ thread_.reset(new base::Thread("Chrome_KeyringThread"));
+
+ if (!thread_->Start()) {
+ thread_.reset(NULL);
+ return false;
+ }
+
+ // Initialize threading in dbus-glib - it should be fine for
+ // dbus_g_thread_init to be called multiple times.
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+ dbus_g_thread_init();
+
+ // Get a connection to the session bus.
+ connection_ = dbus_g_bus_get(DBUS_BUS_SESSION, &error_);
+ if (CheckError())
+ return false;
+
+ if (!StartKWalletd()) return false;
+ if (!InitWallet()) return false;
+
+ return true;
+}
+
+bool PasswordStoreKWallet::StartKWalletd() {
+ // Sadly kwalletd doesn't use DBUS activation, so we have to make a call to
+ // klauncher to start it.
+ DBusGProxy* klauncher_proxy =
+ dbus_g_proxy_new_for_name(connection_, kKLauncherServiceName,
+ kKLauncherPath, kKLauncherInterface);
+
+ char* empty_string_list = NULL;
+ int ret = 1;
+ char* error = NULL;
+ dbus_g_proxy_call(klauncher_proxy, "start_service_by_desktop_name", &error_,
+ G_TYPE_STRING, "kwalletd", // serviceName
+ G_TYPE_STRV, &empty_string_list, // urls
+ G_TYPE_STRV, &empty_string_list, // envs
+ G_TYPE_STRING, "", // startup_id
+ G_TYPE_BOOLEAN, (gboolean) false, // blind
+ G_TYPE_INVALID,
+ G_TYPE_INT, &ret, // result
+ G_TYPE_STRING, NULL, // dubsName
+ G_TYPE_STRING, &error, // error
+ G_TYPE_INT, NULL, // pid
+ G_TYPE_INVALID);
+
+ if (error && *error) {
+ LOG(ERROR) << "Error launching kwalletd: " << error;
+ ret = 1; // Make sure we return false after freeing.
+ }
+
+ g_free(error);
+ g_object_unref(klauncher_proxy);
+
+ if (CheckError() || ret != 0)
+ return false;
+ return true;
+}
+
+bool PasswordStoreKWallet::InitWallet() {
+ // Make a proxy to KWallet.
+ proxy_ = dbus_g_proxy_new_for_name(connection_, kKWalletServiceName,
+ kKWalletPath, kKWalletInterface);
+
+ // Check KWallet is enabled.
+ gboolean is_enabled = false;
+ dbus_g_proxy_call(proxy_, "isEnabled", &error_,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &is_enabled,
+ G_TYPE_INVALID);
+ if (CheckError() || !is_enabled)
+ return false;
+
+ // Get the wallet name.
+ char* wallet_name = NULL;
+ dbus_g_proxy_call(proxy_, "networkWallet", &error_,
+ G_TYPE_INVALID,
+ G_TYPE_STRING, &wallet_name,
+ G_TYPE_INVALID);
+ if (CheckError() || !wallet_name)
+ return false;
+
+ wallet_name_.assign(wallet_name);
+ g_free(wallet_name);
+
+ return true;
+}
+
+void PasswordStoreKWallet::AddLoginImpl(const PasswordForm& form) {
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle == kInvalidKWalletHandle)
+ return;
+
+ PasswordFormList forms;
+ GetLoginsList(&forms, form, wallet_handle);
+
+ forms.push_back(const_cast<PasswordForm*>(&form));
+
+ SetLoginsList(forms, form, wallet_handle);
+}
+
+void PasswordStoreKWallet::UpdateLoginImpl(const PasswordForm& form) {
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle == kInvalidKWalletHandle)
+ return;
+
+ PasswordFormList forms;
+ GetLoginsList(&forms, form, wallet_handle);
+
+ for (uint i = 0; i < forms.size(); ++i) {
+ if (CompareForms(form, *forms[i])) {
+ forms.erase(forms.begin() + i);
+ forms.insert(forms.begin() + i, const_cast<PasswordForm*>(&form));
+ }
+ }
+
+ SetLoginsList(forms, form, wallet_handle);
+}
+
+void PasswordStoreKWallet::RemoveLoginImpl(const PasswordForm& form) {
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle == kInvalidKWalletHandle)
+ return;
+
+ PasswordFormList forms;
+ GetLoginsList(&forms, form, wallet_handle);
+
+ for (uint i = 0; i < forms.size(); ++i) {
+ if (CompareForms(form, *forms[i])) {
+ forms.erase(forms.begin() + i);
+ --i;
+ }
+ }
+
+ if (forms.empty()) {
+ // No items left? Remove the entry from the wallet.
+ int ret = 0;
+ dbus_g_proxy_call(proxy_, "removeEntry", &error_,
+ G_TYPE_INT, wallet_handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, form.signon_realm.c_str(), // key
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_INT, &ret,
+ G_TYPE_INVALID);
+ CheckError();
+ if (ret)
+ LOG(ERROR) << "Bad return code " << ret << " from kwallet removeEntry";
+ } else {
+ // Otherwise update the entry in the wallet.
+ SetLoginsList(forms, form, wallet_handle);
+ }
+}
+
+void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request) {
+ PasswordFormList forms;
+
+ AutoLock l(kwallet_lock_);
+ int wallet_handle = WalletHandle();
+ if (wallet_handle != kInvalidKWalletHandle)
+ GetLoginsList(&forms, request->form, wallet_handle);
+
+ NotifyConsumer(request, forms);
+}
+
+void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms,
+ const PasswordForm& key,
+ int wallet_handle) {
+ // Is there an entry in the wallet?
+ gboolean has_entry = false;
+ dbus_g_proxy_call(proxy_, "hasEntry", &error_,
+ G_TYPE_INT, wallet_handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, key.signon_realm.c_str(), // key
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &has_entry,
+ G_TYPE_INVALID);
+
+ if (CheckError() || !has_entry)
+ return;
+
+ GArray* byte_array = NULL;
+ dbus_g_proxy_call(proxy_, "readEntry", &error_,
+ G_TYPE_INT, wallet_handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, key.signon_realm.c_str(), // key
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
+ G_TYPE_INVALID);
+
+ if (CheckError() || !byte_array || !byte_array->len)
+ return;
+
+ Pickle pickle(byte_array->data, byte_array->len);
+ DeserializeValue(key, pickle, forms);
+}
+
+void PasswordStoreKWallet::SetLoginsList(const PasswordFormList& forms,
+ const PasswordForm& key,
+ int wallet_handle) {
+ Pickle value;
+ SerializeValue(forms, &value);
+
+ // Convert the pickled bytes to a GByteArray.
+ GArray* byte_array = g_array_sized_new(false, false, sizeof(char),
+ value.size());
+ g_array_append_vals(byte_array, value.data(), value.size());
+
+ // Make the call.
+ int ret = 0;
+ dbus_g_proxy_call(proxy_, "writeEntry", &error_,
+ G_TYPE_INT, wallet_handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, key.signon_realm.c_str(), // key
+ DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_INT, &ret,
+ G_TYPE_INVALID);
+ g_array_free(byte_array, true);
+
+ CheckError();
+ if (ret)
+ LOG(ERROR) << "Bad return code " << ret << " from kwallet writeEntry";
+}
+
+bool PasswordStoreKWallet::CompareForms(const PasswordForm& a,
+ const PasswordForm& b) {
+ return a.origin == b.origin &&
+ a.password_element == b.password_element &&
+ a.signon_realm == b.signon_realm &&
+ a.submit_element == b.submit_element &&
+ a.username_element == b.username_element &&
+ a.username_value == b.username_value;
+}
+
+void PasswordStoreKWallet::SerializeValue(const PasswordFormList& forms,
+ Pickle* pickle) {
+ pickle->WriteInt(forms.size());
+ for (PasswordFormList::const_iterator it = forms.begin() ;
+ it != forms.end() ; ++it) {
+ const PasswordForm* form = *it;
+ pickle->WriteInt(form->scheme);
+ pickle->WriteString(form->origin.spec());
+ pickle->WriteString(form->action.spec());
+ pickle->WriteWString(form->username_element);
+ pickle->WriteWString(form->username_value);
+ pickle->WriteWString(form->password_element);
+ pickle->WriteWString(form->password_value);
+ pickle->WriteWString(form->submit_element);
+ pickle->WriteBool(form->ssl_valid);
+ pickle->WriteBool(form->preferred);
+ pickle->WriteBool(form->blacklisted_by_user);
+ }
+}
+
+void PasswordStoreKWallet::DeserializeValue(const PasswordForm& key,
+ const Pickle& pickle,
+ PasswordFormList* forms) {
+ void* iter = NULL;
+
+ int count = 0;
+ pickle.ReadInt(&iter, &count);
+
+ for (int i = 0; i < count; ++i) {
+ PasswordForm* form = new PasswordForm();
+ form->signon_realm.assign(key.signon_realm);
+
+ pickle.ReadInt(&iter, reinterpret_cast<int*>(&form->scheme));
+ ReadGURL(pickle, &iter, &form->origin);
+ ReadGURL(pickle, &iter, &form->action);
+ pickle.ReadWString(&iter, &form->username_element);
+ pickle.ReadWString(&iter, &form->username_value);
+ pickle.ReadWString(&iter, &form->password_element);
+ pickle.ReadWString(&iter, &form->password_value);
+ pickle.ReadWString(&iter, &form->submit_element);
+ pickle.ReadBool(&iter, &form->ssl_valid);
+ pickle.ReadBool(&iter, &form->preferred);
+ pickle.ReadBool(&iter, &form->blacklisted_by_user);
+ forms->push_back(form);
+ }
+}
+
+void PasswordStoreKWallet::ReadGURL(const Pickle& pickle, void** iter,
+ GURL* url) {
+ string url_string;
+ pickle.ReadString(iter, &url_string);
+ *url = GURL(url_string);
+}
+
+bool PasswordStoreKWallet::CheckError() {
+ if (error_) {
+ LOG(ERROR) << "Failed to complete KWallet call: " << error_->message;
+ g_error_free(error_);
+ error_ = NULL;
+ return true;
+ }
+ return false;
+}
+
+int PasswordStoreKWallet::WalletHandle() {
+ // Open the wallet.
+ int handle = kInvalidKWalletHandle;
+ dbus_g_proxy_call(proxy_, "open", &error_,
+ G_TYPE_STRING, wallet_name_.c_str(), // wallet
+ G_TYPE_INT64, 0LL, // wid
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_INT, &handle,
+ G_TYPE_INVALID);
+ if (CheckError() || handle == kInvalidKWalletHandle)
+ return kInvalidKWalletHandle;
+
+ // Check if our folder exists.
+ gboolean has_folder = false;
+ dbus_g_proxy_call(proxy_, "hasFolder", &error_,
+ G_TYPE_INT, handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &has_folder,
+ G_TYPE_INVALID);
+ if (CheckError())
+ return kInvalidKWalletHandle;
+
+ // Create it if it didn't.
+ if (!has_folder) {
+ gboolean success = false;
+ dbus_g_proxy_call(proxy_, "createFolder", &error_,
+ G_TYPE_INT, handle, // handle
+ G_TYPE_STRING, kKWalletFolder, // folder
+ G_TYPE_STRING, kAppId, // appid
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &success,
+ G_TYPE_INVALID);
+ if (CheckError() || !success)
+ return kInvalidKWalletHandle;
+ }
+
+ return handle;
+}
diff --git a/chrome/browser/password_manager/password_store_kwallet.h b/chrome/browser/password_manager/password_store_kwallet.h
new file mode 100644
index 0000000..f0ca283
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_kwallet.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_KWALLET
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_KWALLET
+
+#include <dbus/dbus-glib.h>
+#include <glib.h>
+
+#include <string>
+#include <vector>
+
+#include "base/lock.h"
+#include "base/thread.h"
+#include "chrome/browser/password_manager/password_store.h"
+#include "webkit/glue/password_form.h"
+
+class Pickle;
+class Profile;
+class Task;
+
+class PasswordStoreKWallet : public PasswordStore {
+ public:
+ PasswordStoreKWallet();
+ virtual ~PasswordStoreKWallet();
+
+ bool Init();
+
+ private:
+ typedef std::vector<PasswordForm*> PasswordFormList;
+
+ // Implements PasswordStore interface.
+ void AddLoginImpl(const PasswordForm& form);
+ void UpdateLoginImpl(const PasswordForm& form);
+ void RemoveLoginImpl(const PasswordForm& form);
+ void GetLoginsImpl(GetLoginsRequest* request);
+
+ // Initialisation.
+ bool StartKWalletd();
+ bool InitWallet();
+
+ // Reads a list of PasswordForms from the wallet that match the signon_realm
+ // of key.
+ void GetLoginsList(PasswordFormList* forms, const PasswordForm& key,
+ int wallet_handle);
+
+ // Writes a list of PasswordForms to the wallet with the signon_realm from
+ // key. Overwrites any existing list for this key.
+ void SetLoginsList(const PasswordFormList& forms, const PasswordForm& key,
+ int wallet_handle);
+
+ // Checks if the last dbus call returned an error. If it did, logs the error
+ // message, frees it and returns true.
+ // This must be called after every dbus call.
+ bool CheckError();
+
+ // Opens the wallet and ensures that the "Chrome Form Data" folder exists.
+ // Returns kInvalidWalletHandle on error.
+ int WalletHandle();
+
+ // Compares two PasswordForms and returns true if they are the same.
+ // Checks only the fields that we persist in KWallet, and ignores
+ // password_value.
+ static bool CompareForms(const PasswordForm& a, const PasswordForm& b);
+
+ // Serializes a list of PasswordForms to be stored in the wallet.
+ static void SerializeValue(const PasswordFormList& forms, Pickle* pickle);
+
+ // Deserializes a list of PasswordForms from the wallet.
+ static void DeserializeValue(const PasswordForm& key, const Pickle& pickle,
+ PasswordFormList* forms);
+
+ // Convenience function to read a GURL from a Pickle. Assumes the URL has
+ // been written as a std::string.
+ static void ReadGURL(const Pickle& pickle, void** iter, GURL* url);
+
+ // Name of the application - will appear in kwallet's dialogs.
+ static const char* kAppId;
+ // Name of the folder to store passwords in.
+ static const char* kKWalletFolder;
+
+ // DBUS stuff.
+ static const char* kKWalletServiceName;
+ static const char* kKWalletPath;
+ static const char* kKWalletInterface;
+ static const char* kKLauncherServiceName;
+ static const char* kKLauncherPath;
+ static const char* kKLauncherInterface;
+
+ // Invalid handle returned by WalletHandle().
+ static const int kInvalidKWalletHandle = -1;
+
+ // Controls all access to kwallet dbus calls.
+ Lock kwallet_lock_;
+
+ // Error from the last dbus call. NULL when there's no error. Freed and
+ // cleared by CheckError().
+ GError* error_;
+ // Connection to the dbus session bus.
+ DBusGConnection* connection_;
+ // Proxy to the kwallet dbus service.
+ DBusGProxy* proxy_;
+
+ // The name of the wallet we've opened. Set during Init().
+ std::string wallet_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordStoreKWallet);
+};
+
+#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_KWALLET
diff --git a/chrome/browser/password_manager/password_store_win.cc b/chrome/browser/password_manager/password_store_win.cc
new file mode 100644
index 0000000..7eea14f
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_win.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_store_win.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/browser/password_manager/ie7_password.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/profile.h"
+
+using std::map;
+using std::vector;
+
+PasswordStoreWin::PasswordStoreWin(WebDataService* web_data_service)
+ : PasswordStoreDefault(web_data_service) {
+}
+
+void PasswordStoreWin::OnWebDataServiceRequestDone(
+ WebDataService::Handle h, const WDTypedResult *result) {
+ // Look up this handle in our request map to get the original
+ // GetLoginsRequest.
+ GetLoginsRequest* request = GetLoginsRequestForWebDataServiceRequest(h);
+ DCHECK(request);
+ // Remove our pending request, but make sure that we won't be destroyed until
+ // we're done with this function.
+ scoped_refptr<PasswordStoreWin> life_preserver(this);
+ RemovePendingWebDataServiceRequest(h);
+
+ DCHECK(result);
+ if (!result)
+ return;
+
+ switch (result->GetType()) {
+ case PASSWORD_RESULT: {
+ // This is a response from WebDataService::GetLogins.
+ const WDResult<std::vector<PasswordForm*> >* r =
+ static_cast<const WDResult<std::vector<PasswordForm*> >*>(result);
+ std::vector<PasswordForm*> result_value = r->GetValue();
+
+ if (result_value.size()) {
+ // If we found some results then return them now.
+ NotifyConsumer(request, result_value);
+ return;
+ } else {
+ // Otherwise try finding IE7 logins.
+ IE7PasswordInfo info;
+ std::wstring url = ASCIIToWide(request->form.origin.spec());
+ info.url_hash = ie7_password::GetUrlHash(url);
+
+ if (web_data_service_->IsRunning()) {
+ WebDataService::Handle web_data_handle =
+ web_data_service_->GetIE7Login(info, this);
+ AddPendingWebDataServiceRequest(web_data_handle, request);
+ }
+ }
+ break;
+ }
+
+ case PASSWORD_IE7_RESULT: {
+ // This is a response from WebDataService::GetIE7Login.
+ PasswordForm* ie7_form = GetIE7Result(result, request->form);
+
+ std::vector<PasswordForm*> forms;
+ if (ie7_form)
+ forms.push_back(ie7_form);
+
+ NotifyConsumer(request, forms);
+ break;
+ }
+ }
+}
+
+PasswordForm* PasswordStoreWin::GetIE7Result(const WDTypedResult *result,
+ const PasswordForm& form) {
+ const WDResult<IE7PasswordInfo>* r =
+ static_cast<const WDResult<IE7PasswordInfo>*>(result);
+ IE7PasswordInfo info = r->GetValue();
+
+ if (!info.encrypted_data.empty()) {
+ // We got a result.
+ // Delete the entry. If it's good we will add it to the real saved password
+ // table.
+ web_data_service_->RemoveIE7Login(info);
+ std::wstring username;
+ std::wstring password;
+ std::wstring url = ASCIIToWide(form.origin.spec());
+ if (!ie7_password::DecryptPassword(url, info.encrypted_data,
+ &username, &password)) {
+ return NULL;
+ }
+
+ PasswordForm* auto_fill = new PasswordForm(form);
+ auto_fill->username_value = username;
+ auto_fill->password_value = password;
+ auto_fill->preferred = true;
+ auto_fill->ssl_valid = form.origin.SchemeIsSecure();
+ auto_fill->date_created = info.date_created;
+ // Add this PasswordForm to the saved password table.
+ AddLogin(*auto_fill);
+ return auto_fill;
+ }
+ return NULL;
+}
diff --git a/chrome/browser/password_manager/password_store_win.h b/chrome/browser/password_manager/password_store_win.h
new file mode 100644
index 0000000..a56b416
--- /dev/null
+++ b/chrome/browser/password_manager/password_store_win.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_WIN
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_WIN
+
+#include <map>
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/password_manager/password_store.h"
+#include "chrome/browser/password_manager/password_store_default.h"
+#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/browser/webdata/web_database.h"
+
+// Windows PasswordStore implementation that uses the default implementation,
+// but also uses IE7 passwords if no others found.
+class PasswordStoreWin : public PasswordStoreDefault {
+ public:
+ // FilePath specifies path to WebDatabase.
+ explicit PasswordStoreWin(WebDataService* web_data_service);
+ virtual ~PasswordStoreWin() {}
+
+ private:
+ // See PasswordStoreDefault.
+ void OnWebDataServiceRequestDone(WebDataService::Handle h,
+ const WDTypedResult* result);
+
+ // Gets logins from IE7 if no others are found. Also copies them into
+ // Chrome's WebDatabase so we don't need to look next time.
+ PasswordForm* GetIE7Result(const WDTypedResult* result,
+ const PasswordForm& form);
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordStoreWin);
+};
+
+#endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_WIN