1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/password_manager/native_backend_gnome_x.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <dbus/dbus-glib.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <dlfcn.h>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <gnome-keyring.h>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <map>
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/waitable_event.h"
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing webkit_glue::PasswordForm;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Many of the gnome_keyring_* functions use variable arguments, which makes
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// them difficult if not impossible to wrap in C. Therefore, we want the
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// actual uses below to either call the functions directly (if we are linking
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// against libgnome-keyring), or call them via appropriately-typed function
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// pointers (if we are dynamically loading libgnome-keyring).
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Thus, instead of making a wrapper class with two implementations, we use
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the preprocessor to rename the calls below in the dynamic load case, and
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// provide a function to initialize a set of function pointers that have the
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// alternate names. We also make sure the types are correct, since otherwise
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dynamic loading like this would leave us vulnerable to signature changes.
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(DLOPEN_GNOME_KEYRING)
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Call a given parameter with the name of each function we use from GNOME
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Keyring.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define GNOME_KEYRING_FOR_EACH_FUNC(F)          \
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(is_available)                               \
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(store_password)                             \
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(delete_password)                            \
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(find_itemsv)                                \
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(result_to_message)                          \
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  F(list_keyring_names)                         \
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(list_item_ids)                              \
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(item_get_attributes)                        \
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(item_get_info)                              \
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  F(item_info_get_secret)
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Define the actual function pointers that we'll use in application code.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define GNOME_KEYRING_DEFINE_WRAPPER(name) \
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typeof(&gnome_keyring_##name) wrap_gnome_keyring_##name;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DEFINE_WRAPPER)
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#undef GNOME_KEYRING_DEFINE_WRAPPER
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Make it easy to initialize the function pointers above with a loop below.
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define GNOME_KEYRING_FUNCTION(name) \
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {"gnome_keyring_"#name, reinterpret_cast<void**>(&wrap_gnome_keyring_##name)},
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst struct {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char* name;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void** pointer;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} gnome_keyring_functions[] = {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION)
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {NULL, NULL}
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#undef GNOME_KEYRING_FUNCTION
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#undef GNOME_KEYRING_FOR_EACH_FUNC
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Allow application code below to use the normal function names, but actually
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// end up using the function pointers above instead.
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_is_available \
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrap_gnome_keyring_is_available
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_store_password \
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrap_gnome_keyring_store_password
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_delete_password \
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrap_gnome_keyring_delete_password
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_find_itemsv \
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrap_gnome_keyring_find_itemsv
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_result_to_message \
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrap_gnome_keyring_result_to_message
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define gnome_keyring_list_keyring_names \
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wrap_gnome_keyring_list_keyring_names
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_list_item_ids \
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrap_gnome_keyring_list_item_ids
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_item_get_attributes \
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wrap_gnome_keyring_item_get_attributes
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_item_get_info \
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wrap_gnome_keyring_item_get_info
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define gnome_keyring_item_info_get_secret \
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wrap_gnome_keyring_item_info_get_secret
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* Load the library and initialize the function pointers. */
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool LoadGnomeKeyring() {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void* handle = dlopen("libgnome-keyring.so.0", RTLD_NOW | RTLD_GLOBAL);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!handle) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We wanted to use GNOME Keyring, but we couldn't load it. Warn, because
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // either the user asked for this, or we autodetected it incorrectly. (Or
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the system has broken libraries, which is also good to warn about.)
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror();
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; gnome_keyring_functions[i].name; ++i) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dlerror();
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *gnome_keyring_functions[i].pointer =
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        dlsym(handle, gnome_keyring_functions[i].name);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* error = dlerror();
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (error) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Unable to load symbol "
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << gnome_keyring_functions[i].name << ": " << error;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dlclose(handle);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We leak the library handle. That's OK: this function is called only once.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Older versions of GNOME Keyring have bugs that prevent them from working
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// correctly with the find_itemsv API. (In particular, the non-pageable memory
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// allocator is rather busted.) There is no official way to check the version,
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// nor could we figure out any reasonable unofficial way to do it. So we work
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// around it by using a much slower API.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else  // !defined(DLOPEN_GNOME_KEYRING)
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool LoadGnomeKeyring() {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't need to do anything here. When linking directly, we also assume
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that whoever is compiling this code has checked that the version is OK.
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // !defined(DLOPEN_GNOME_KEYRING)
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define GNOME_KEYRING_APPLICATION_CHROME "chrome"
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Convert the attributes of a given keyring entry into a new PasswordForm.
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Note: does *not* get the actual password, as that is not a key attribute!
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns NULL if the attributes are for the wrong application.
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPasswordForm* FormFromAttributes(GnomeKeyringAttributeList* attrs) {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Read the string and int attributes into the appropriate map.
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<std::string, std::string> string_attr_map;
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<std::string, uint32_t> uint_attr_map;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (guint i = 0; i < attrs->len; ++i) {
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING)
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      string_attr_map[attr.name] = attr.value.string;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32)
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      uint_attr_map[attr.name] = attr.value.integer;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check to make sure this is a password we care about.
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (string_attr_map["application"] != GNOME_KEYRING_APPLICATION_CHROME)
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordForm* form = new PasswordForm();
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->origin = GURL(string_attr_map["origin_url"]);
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->action = GURL(string_attr_map["action_url"]);
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->username_element = UTF8ToUTF16(string_attr_map["username_element"]);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->username_value = UTF8ToUTF16(string_attr_map["username_value"]);
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->password_element = UTF8ToUTF16(string_attr_map["password_element"]);
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->signon_realm = string_attr_map["signon_realm"];
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->ssl_valid = uint_attr_map["ssl_valid"];
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->preferred = uint_attr_map["preferred"];
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 date_created = 0;
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool date_ok = base::StringToInt64(string_attr_map["date_created"],
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     &date_created);
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(date_ok);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->date_created = base::Time::FromTimeT(date_created);
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"];
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return form;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Parse all the results from the given GList into a PasswordFormList, and free
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the GList. PasswordForms are allocated on the heap, and should be deleted by
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the consumer.
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ConvertFormList(GList* found,
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     NativeBackendGnome::PasswordFormList* forms) {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GList* element = g_list_first(found);
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (element != NULL) {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GnomeKeyringAttributeList* attrs = data->attributes;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PasswordForm* form = FormFromAttributes(attrs);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (form) {
19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (data->secret) {
19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        form->password_value = UTF8ToUTF16(data->secret);
19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      } else {
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        LOG(WARNING) << "Unable to access password from list element!";
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      forms->push_back(form);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "Could not initialize PasswordForm from attributes!";
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    element = g_list_next(element);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Schema is analagous to the fields in PasswordForm.
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst GnomeKeyringPasswordSchema kGnomeSchema = {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GNOME_KEYRING_ITEM_GENERIC_SECRET, {
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "action_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "ssl_valid", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "preferred", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This field is always "chrome" so that we can search for it.
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    { NULL }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sadly, PasswordStore goes to great lengths to switch from the originally
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// calling thread to the DB thread, and to provide an asynchronous API to
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// callers while using a synchronous (virtual) API provided by subclasses like
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// PasswordStoreX -- but GNOME Keyring really wants to be on the GLib main
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// thread, which is the UI thread to us. So we end up having to switch threads
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// again, possibly back to the very same thread (in case the UI thread is the
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// caller, e.g. in the password management UI), and *block* the DB thread
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// waiting for a response from the UI thread to provide the synchronous API
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// PasswordStore expects of us. (It will then in turn switch back to the
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// original caller to send the asynchronous reply to the original request.)
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class represents a call to a GNOME Keyring method. A RunnableMethod
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// should be posted to the UI thread to call one of its action methods, and then
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a WaitResult() method should be called to wait for the result. Each instance
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// supports only one outstanding method at a time, though multiple instances may
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// be used in parallel.
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass GKRMethod {
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typedef NativeBackendGnome::PasswordFormList PasswordFormList;
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod() : event_(false, false), result_(GNOME_KEYRING_RESULT_CANCELLED) {}
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Action methods. These call gnome_keyring_* functions. Call from UI thread.
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void AddLogin(const PasswordForm& form);
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void AddLoginSearch(const PasswordForm& form);
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void UpdateLoginSearch(const PasswordForm& form);
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RemoveLogin(const PasswordForm& form);
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void GetLogins(const PasswordForm& form);
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void GetLoginsList(uint32_t blacklisted_by_user);
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void GetAllLogins();
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void GetKeyrings();
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void GetItemIds(const char* keyring);
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void GetItemAttrs(const char* keyring, guint id);
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void GetItemInfo(const char* keyring, guint id);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Use after AddLogin, RemoveLogin.
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult WaitResult();
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Use after AddLoginSearch, UpdateLoginSearch, GetLogins, GetLoginsList,
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // GetAllLogins.
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult WaitResult(PasswordFormList* forms);
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Use after GetKeyrings().
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GnomeKeyringResult WaitResult(std::vector<std::string>* keyrings);
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Use after GetItemIds().
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult WaitResult(std::vector<guint>* item_ids);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Use after GetItemAttrs().
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult WaitResult(PasswordForm** form);
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Use after GetItemInfo().
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult WaitResult(string16* password);
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // All these callbacks are called on UI thread.
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnOperationDone(GnomeKeyringResult result, gpointer data);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnOperationGetList(GnomeKeyringResult result, GList* list,
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 gpointer data);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static void OnOperationGetKeyrings(GnomeKeyringResult result, GList* list,
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                     gpointer data);
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnOperationGetIds(GnomeKeyringResult result, GList* list,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                gpointer data);
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnOperationGetAttrs(GnomeKeyringResult result,
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  GnomeKeyringAttributeList* attrs,
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  gpointer data);
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void OnOperationGetInfo(GnomeKeyringResult result,
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 GnomeKeyringItemInfo* info,
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 gpointer data);
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::WaitableEvent event_;
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result_;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NativeBackendGnome::PasswordFormList forms_;
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<std::string> keyrings_;
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<guint> item_ids_;
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<PasswordForm> form_;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 password_;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::AddLogin(const PasswordForm& form) {
323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
32472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  time_t date_created = form.date_created.ToTimeT();
32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // If we are asked to save a password with 0 date, use the current time.
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // We don't want to actually save passwords as though on January 1, 1970.
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!date_created)
32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    date_created = time(NULL);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gnome_keyring_store_password(
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      &kGnomeSchema,
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // Default keyring.
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      form.origin.spec().c_str(),  // Display name.
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(form.password_value).c_str(),
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OnOperationDone,
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this,  // data
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // destroy_data
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "origin_url", form.origin.spec().c_str(),
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "action_url", form.action.spec().c_str(),
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "username_element", UTF16ToUTF8(form.username_element).c_str(),
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "username_value", UTF16ToUTF8(form.username_value).c_str(),
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "password_element", UTF16ToUTF8(form.password_element).c_str(),
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "submit_element", UTF16ToUTF8(form.submit_element).c_str(),
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "signon_realm", form.signon_realm.c_str(),
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "ssl_valid", form.ssl_valid,
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "preferred", form.preferred,
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      "date_created", base::Int64ToString(date_created).c_str(),
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "blacklisted_by_user", form.blacklisted_by_user,
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "scheme", form.scheme,
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "application", GNOME_KEYRING_APPLICATION_CHROME,
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GKRMethod::AddLoginSearch(const PasswordForm& form) {
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Search GNOME Keyring for matching passwords to update.
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gnome_keyring_find_itemsv(
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GNOME_KEYRING_ITEM_GENERIC_SECRET,
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      OnOperationGetList,
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this,  // data
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NULL,  // destroy_data
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      form.origin.spec().c_str(),
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      UTF16ToUTF8(form.username_element).c_str(),
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      UTF16ToUTF8(form.username_value).c_str(),
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      UTF16ToUTF8(form.password_element).c_str(),
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      UTF16ToUTF8(form.submit_element).c_str(),
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      form.signon_realm.c_str(),
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GNOME_KEYRING_APPLICATION_CHROME,
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NULL);
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::UpdateLoginSearch(const PasswordForm& form) {
379731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Search GNOME Keyring for matching passwords to update.
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gnome_keyring_find_itemsv(
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_ITEM_GENERIC_SECRET,
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OnOperationGetList,
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this,  // data
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // destroy_data
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      form.origin.spec().c_str(),
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(form.username_element).c_str(),
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(form.username_value).c_str(),
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(form.password_element).c_str(),
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      form.signon_realm.c_str(),
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_APPLICATION_CHROME,
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::RemoveLogin(const PasswordForm& form) {
402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We find forms using the same fields as LoginDatabase::RemoveLogin().
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gnome_keyring_delete_password(
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      &kGnomeSchema,
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OnOperationDone,
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this,  // data
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // destroy_data
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "origin_url", form.origin.spec().c_str(),
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "action_url", form.action.spec().c_str(),
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "username_element", UTF16ToUTF8(form.username_element).c_str(),
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "username_value", UTF16ToUTF8(form.username_value).c_str(),
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "password_element", UTF16ToUTF8(form.password_element).c_str(),
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "submit_element", UTF16ToUTF8(form.submit_element).c_str(),
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "signon_realm", form.signon_realm.c_str(),
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::GetLogins(const PasswordForm& form) {
420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Search GNOME Keyring for matching passwords.
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gnome_keyring_find_itemsv(
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_ITEM_GENERIC_SECRET,
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OnOperationGetList,
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this,  // data
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // destroy_data
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      form.signon_realm.c_str(),
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_APPLICATION_CHROME,
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::GetLoginsList(uint32_t blacklisted_by_user) {
436731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Search GNOME Keyring for matching passwords.
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gnome_keyring_find_itemsv(
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_ITEM_GENERIC_SECRET,
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OnOperationGetList,
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this,  // data
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // destroy_data
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32,
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      blacklisted_by_user,
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_APPLICATION_CHROME,
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::GetAllLogins() {
451731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We need to search for something, otherwise we get no results - so
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we search for the fixed application string.
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gnome_keyring_find_itemsv(
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_ITEM_GENERIC_SECRET,
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      OnOperationGetList,
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this,  // data
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL,  // destroy_data
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GNOME_KEYRING_APPLICATION_CHROME,
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL);
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GKRMethod::GetKeyrings() {
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gnome_keyring_list_keyring_names(OnOperationGetKeyrings, this, NULL);
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GKRMethod::GetItemIds(const char* keyring) {
470731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gnome_keyring_list_item_ids(keyring, OnOperationGetIds, this, NULL);
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GKRMethod::GetItemAttrs(const char* keyring, guint id) {
475731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gnome_keyring_item_get_attributes(keyring, id, OnOperationGetAttrs, this,
477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                    NULL);
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GKRMethod::GetItemInfo(const char* keyring, guint id) {
481731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gnome_keyring_item_get_info(keyring, id, OnOperationGetInfo, this, NULL);
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGnomeKeyringResult GKRMethod::WaitResult() {
487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event_.Wait();
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result_;
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGnomeKeyringResult GKRMethod::WaitResult(PasswordFormList* forms) {
493731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event_.Wait();
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  forms->swap(forms_);
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result_;
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenGnomeKeyringResult GKRMethod::WaitResult(std::vector<std::string>* keyrings) {
501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  event_.Wait();
503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  keyrings->swap(keyrings_);
504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return result_;
505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGnomeKeyringResult GKRMethod::WaitResult(std::vector<guint>* item_ids) {
508731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event_.Wait();
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  item_ids->swap(item_ids_);
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result_;
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGnomeKeyringResult GKRMethod::WaitResult(PasswordForm** form) {
515731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event_.Wait();
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *form = form_.release();
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result_;
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGnomeKeyringResult GKRMethod::WaitResult(string16* password) {
522731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event_.Wait();
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *password = password_;
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result_;
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::OnOperationDone(GnomeKeyringResult result, gpointer data) {
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod* method = static_cast<GKRMethod*>(data);
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->result_ = result;
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->event_.Signal();
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list,
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   gpointer data) {
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod* method = static_cast<GKRMethod*>(data);
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->result_ = result;
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->forms_.clear();
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |list| will be freed after this callback returns, so convert it now.
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConvertFormList(list, &method->forms_);
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->event_.Signal();
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid GKRMethod::OnOperationGetKeyrings(GnomeKeyringResult result, GList* list,
550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       gpointer data) {
551ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GKRMethod* method = static_cast<GKRMethod*>(data);
552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  method->result_ = result;
553ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  method->keyrings_.clear();
554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GList* element = g_list_first(list);
555ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (element != NULL) {
556ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const char* data = static_cast<const char*>(element->data);
557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    method->keyrings_.push_back(std::string(data));
558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    element = g_list_next(element);
559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  method->event_.Signal();
561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
563ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::OnOperationGetIds(GnomeKeyringResult result, GList* list,
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  gpointer data) {
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod* method = static_cast<GKRMethod*>(data);
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->result_ = result;
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->item_ids_.clear();
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |list| will be freed after this callback returns, so save it now.
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (GList* i = list; i; i = i->next) {
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    guint id = GPOINTER_TO_UINT(i->data);
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    method->item_ids_.push_back(id);
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->event_.Signal();
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::OnOperationGetAttrs(GnomeKeyringResult result,
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    GnomeKeyringAttributeList* attrs,
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    gpointer data) {
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod* method = static_cast<GKRMethod*>(data);
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->result_ = result;
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |attrs| will be freed after this callback returns, so convert it now.
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == GNOME_KEYRING_RESULT_OK)
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    method->form_.reset(FormFromAttributes(attrs));
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->event_.Signal();
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GKRMethod::OnOperationGetInfo(GnomeKeyringResult result,
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   GnomeKeyringItemInfo* info,
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   gpointer data) {
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod* method = static_cast<GKRMethod*>(data);
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->result_ = result;
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |info| will be freed after this callback returns, so use it now.
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == GNOME_KEYRING_RESULT_OK) {
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    char* secret = gnome_keyring_item_info_get_secret(info);
59872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (secret) {
59972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      method->password_ = UTF8ToUTF16(secret);
60072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // gnome_keyring_item_info_get_secret() allocates and returns a new copy
60172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // of the secret, so we have to free it afterward.
60272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      free(secret);
60372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else {
60472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LOG(WARNING) << "Unable to access password from item info!";
60572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method->event_.Signal();
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// GKRMethod isn't reference counted, but it always outlasts runnable
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// methods against it because the caller waits for those methods to run.
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtemplate<>
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct RunnableMethodTraits<GKRMethod> {
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RetainCallee(GKRMethod*) {}
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void ReleaseCallee(GKRMethod*) {}
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNativeBackendGnome::NativeBackendGnome() {
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNativeBackendGnome::~NativeBackendGnome() {
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::Init() {
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return LoadGnomeKeyring() && gnome_keyring_is_available();
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
631ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool NativeBackendGnome::RawAddLogin(const PasswordForm& form) {
632731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod method;
634731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
635731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          NewRunnableMethod(&method,
636731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            &GKRMethod::AddLogin,
637731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            form));
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result = method.WaitResult();
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Keyring save failed: "
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
647ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool NativeBackendGnome::AddLogin(const PasswordForm& form) {
648ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Based on LoginDatabase::AddLogin(), we search for an existing match based
649ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // on origin_url, username_element, username_value, password_element, submit
650ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // element, and signon_realm first, remove that, and then add the new entry.
651ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We'd add the new one first, and then delete the original, but then the
652ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // delete might actually delete the newly-added entry!
653ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
654ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GKRMethod method;
655ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
656ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         NewRunnableMethod(&method,
657ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           &GKRMethod::AddLoginSearch,
658ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           form));
659ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PasswordFormList forms;
660ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GnomeKeyringResult result = method.WaitResult(&forms);
661ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (result != GNOME_KEYRING_RESULT_OK &&
662ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result != GNOME_KEYRING_RESULT_NO_MATCH) {
663ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(ERROR) << "Keyring find failed: "
664ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen               << gnome_keyring_result_to_message(result);
665ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
666ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
667ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (forms.size() > 0) {
668ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (forms.size() > 1) {
669ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(WARNING) << "Adding login when there are " << forms.size() <<
670ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                   " matching logins already! Will replace only the first.";
671ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
672ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RemoveLogin(*forms[0]);
673ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 0; i < forms.size(); ++i)
674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delete forms[i];
675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
676ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return RawAddLogin(form);
677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
678ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::UpdateLogin(const PasswordForm& form) {
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Based on LoginDatabase::UpdateLogin(), we search for forms to update by
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // origin_url, username_element, username_value, password_element, and
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // signon_realm. We then compare the result to the updated form. If they
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // differ in any of the action, password_value, ssl_valid, or preferred
684ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // fields, then we remove the original, and then add the new entry. We'd add
685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the new one first, and then delete the original, but then the delete might
686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // actually delete the newly-added entry!
687731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod method;
689731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         NewRunnableMethod(&method,
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           &GKRMethod::UpdateLoginSearch,
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           form));
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordFormList forms;
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result = method.WaitResult(&forms);
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Keyring find failed: "
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool ok = true;
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < forms.size(); ++i) {
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (forms[i]->action != form.action ||
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        forms[i]->password_value != form.password_value ||
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        forms[i]->ssl_valid != form.ssl_valid ||
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        forms[i]->preferred != form.preferred) {
706ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      RemoveLogin(*forms[i]);
707ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
708ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
709ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < forms.size(); ++i) {
710ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (forms[i]->action != form.action ||
711ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        forms[i]->password_value != form.password_value ||
712ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        forms[i]->ssl_valid != form.ssl_valid ||
713ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        forms[i]->preferred != form.preferred) {
714ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      forms[i]->action = form.action;
715ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      forms[i]->password_value = form.password_value;
716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      forms[i]->ssl_valid = form.ssl_valid;
717ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      forms[i]->preferred = form.preferred;
718ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!RawAddLogin(*forms[i]))
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ok = false;
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete forms[i];
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ok;
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::RemoveLogin(const PasswordForm& form) {
727731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod method;
729731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
730731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          NewRunnableMethod(&method,
731731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            &GKRMethod::RemoveLogin,
732731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            form));
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result = method.WaitResult();
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Keyring delete failed: "
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::RemoveLoginsCreatedBetween(
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const base::Time& delete_begin,
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const base::Time& delete_end) {
745731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool ok = true;
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We could walk the list and delete items as we find them, but it is much
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // easier to build the list and use RemoveLogin() to delete them.
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordFormList forms;
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetAllLogins(&forms))
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < forms.size(); ++i) {
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (delete_begin <= forms[i]->date_created &&
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (delete_end.is_null() || forms[i]->date_created < delete_end)) {
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!RemoveLogin(*forms[i]))
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ok = false;
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete forms[i];
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ok;
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::GetLogins(const PasswordForm& form,
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   PasswordFormList* forms) {
766731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod method;
768731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
769731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI,
770731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      FROM_HERE,
771731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NewRunnableMethod(&method, &GKRMethod::GetLogins, form));
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result = method.WaitResult(forms);
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == GNOME_KEYRING_RESULT_NO_MATCH)
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Keyring find failed: "
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin,
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 const base::Time& get_end,
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 PasswordFormList* forms) {
786731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We could walk the list and add items as we find them, but it is much
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // easier to build the list and then filter the results.
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordFormList all_forms;
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetAllLogins(&all_forms))
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  forms->reserve(forms->size() + all_forms.size());
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < all_forms.size(); ++i) {
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (get_begin <= all_forms[i]->date_created &&
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (get_end.is_null() || all_forms[i]->date_created < get_end)) {
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      forms->push_back(all_forms[i]);
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete all_forms[i];
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::GetAutofillableLogins(PasswordFormList* forms) {
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetLoginsList(forms, true);
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) {
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetLoginsList(forms, false);
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::GetLoginsList(PasswordFormList* forms,
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       bool autofillable) {
816731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uint32_t blacklisted_by_user = !autofillable;
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod method;
822731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
823731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          NewRunnableMethod(&method,
824731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            &GKRMethod::GetLoginsList,
825731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            blacklisted_by_user));
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result = method.WaitResult(forms);
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == GNOME_KEYRING_RESULT_NO_MATCH)
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Keyring find failed: "
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordFormList all_forms;
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetAllLogins(&all_forms))
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now manually filter the results for the values we care about.
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < all_forms.size(); ++i) {
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (all_forms[i]->blacklisted_by_user == blacklisted_by_user)
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      forms->push_back(all_forms[i]);
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete all_forms[i];
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) {
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GKRMethod method;
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION)
853731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
854731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          NewRunnableMethod(&method,
855731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                            &GKRMethod::GetAllLogins));
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GnomeKeyringResult result = method.WaitResult(forms);
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == GNOME_KEYRING_RESULT_NO_MATCH)
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Keyring find failed: "
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
866731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
867731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          NewRunnableMethod(&method,
868ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            &GKRMethod::GetKeyrings));
869ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<std::string> keyrings;
870ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GnomeKeyringResult result = method.WaitResult(&keyrings);
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != GNOME_KEYRING_RESULT_OK) {
872ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(ERROR) << "Keyring list failed: "
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << gnome_keyring_result_to_message(result);
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
877ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We could parallelize this, but there probably aren't many keyrings.
878ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<std::pair<const char *, guint> > item_list;
879ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < keyrings.size(); ++i) {
880ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const char *keyring = keyrings[i].c_str();
881ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
882ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            NewRunnableMethod(&method,
883ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              &GKRMethod::GetItemIds,
884ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              keyring));
885ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<guint> item_ids;
886ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GnomeKeyringResult result = method.WaitResult(&item_ids);
887ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (result != GNOME_KEYRING_RESULT_OK) {
888ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(ERROR) << "Keyring itemid list failed: "
889ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 << gnome_keyring_result_to_message(result);
890ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
891ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
892ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t j = 0; j < item_ids.size(); ++j)
893ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      item_list.push_back(std::make_pair(keyring, item_ids[j]));
894ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
895ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We can parallelize getting the item attributes.
897ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GKRMethod* methods = new GKRMethod[item_list.size()];
898ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < item_list.size(); ++i) {
899731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
900731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            NewRunnableMethod(&methods[i],
901731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                              &GKRMethod::GetItemAttrs,
902ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              item_list[i].first,
903ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              item_list[i].second));
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool success = true;
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We can also parallelize getting the item info (i.e. passwords).
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordFormList all_forms;
910ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  all_forms.resize(item_list.size());
911ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < item_list.size(); ++i) {
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = methods[i].WaitResult(&all_forms[i]);
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (result != GNOME_KEYRING_RESULT_OK) {
91472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LOG(ERROR) << "Keyring get item attributes failed: "
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << gnome_keyring_result_to_message(result);
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We explicitly do not break out here. We must wait on all the other
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // methods first, and we may have already posted new methods. So, we just
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // note the failure and continue.
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success = false;
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (all_forms[i]) {
922731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
923731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              NewRunnableMethod(&methods[i],
924731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                                &GKRMethod::GetItemInfo,
925ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                item_list[i].first,
926ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                item_list[i].second));
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now just wait for all the passwords to come in.
931ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < item_list.size(); ++i) {
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!all_forms[i])
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = methods[i].WaitResult(&all_forms[i]->password_value);
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (result != GNOME_KEYRING_RESULT_OK) {
93672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LOG(ERROR) << "Keyring get item info failed: "
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << gnome_keyring_result_to_message(result);
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete all_forms[i];
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      all_forms[i] = NULL;
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We explicitly do not break out here (see above).
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      success = false;
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete[] methods;
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (success) {
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we succeeded, output all the forms.
949ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 0; i < item_list.size(); ++i) {
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (all_forms[i])
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        forms->push_back(all_forms[i]);
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Otherwise, free them.
955ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 0; i < item_list.size(); ++i)
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete all_forms[i];
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return success;
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
962