OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/password_manager/native_backend_gnome_x.h" | 5 #include "chrome/browser/password_manager/native_backend_gnome_x.h" |
6 | 6 |
| 7 #include <dbus/dbus-glib.h> |
| 8 #include <dlfcn.h> |
| 9 #include <gnome-keyring.h> |
| 10 |
7 #include <map> | 11 #include <map> |
8 #include <string> | 12 #include <string> |
9 | 13 #include <vector> |
10 #include <dbus/dbus-glib.h> | |
11 #include <dlfcn.h> | |
12 | 14 |
13 #include "base/logging.h" | 15 #include "base/logging.h" |
14 #include "base/string_util.h" | 16 #include "base/string_util.h" |
15 #include "base/time.h" | 17 #include "base/time.h" |
16 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
| 19 #include "base/waitable_event.h" |
17 #include "chrome/browser/chrome_thread.h" | 20 #include "chrome/browser/chrome_thread.h" |
18 | 21 |
19 using webkit_glue::PasswordForm; | 22 using webkit_glue::PasswordForm; |
20 | 23 |
21 namespace { | 24 namespace { |
22 | 25 |
23 /* Many of the gnome_keyring_* functions use variable arguments, which makes | 26 // Many of the gnome_keyring_* functions use variable arguments, which makes |
24 * them difficult if not impossible to wrap in C. Therefore, we want the | 27 // them difficult if not impossible to wrap in C. Therefore, we want the |
25 * actual uses below to either call the functions directly (if we are linking | 28 // actual uses below to either call the functions directly (if we are linking |
26 * against libgnome-keyring), or call them via appropriately-typed function | 29 // against libgnome-keyring), or call them via appropriately-typed function |
27 * pointers (if we are dynamically loading libgnome-keyring). | 30 // pointers (if we are dynamically loading libgnome-keyring). |
28 * | 31 |
29 * Thus, instead of making a wrapper class with two implementations, we use | 32 // Thus, instead of making a wrapper class with two implementations, we use |
30 * the preprocessor to rename the calls below in the dynamic load case, and | 33 // the preprocessor to rename the calls below in the dynamic load case, and |
31 * provide a function to initialize a set of function pointers that have the | 34 // provide a function to initialize a set of function pointers that have the |
32 * alternate names. We also make sure the types are correct, since otherwise | 35 // alternate names. We also make sure the types are correct, since otherwise |
33 * dynamic loading like this would leave us vulnerable to signature changes. */ | 36 // dynamic loading like this would leave us vulnerable to signature changes. |
34 | 37 |
35 #if defined(DLOPEN_GNOME_KEYRING) | 38 #if defined(DLOPEN_GNOME_KEYRING) |
36 | 39 |
37 // Call a given parameter with the name of each func we use from | 40 // Call a given parameter with the name of each function we use from GNOME |
38 // gnome keyring. | 41 // Keyring. |
39 #define GNOME_KEYRING_FOR_EACH_FUNC(F) \ | 42 #define GNOME_KEYRING_FOR_EACH_FUNC(F) \ |
40 F(is_available) \ | 43 F(is_available) \ |
41 F(store_password_sync) \ | 44 F(store_password) \ |
42 F(delete_password_sync) \ | 45 F(delete_password) \ |
43 F(find_itemsv_sync) \ | 46 F(find_itemsv) \ |
44 F(result_to_message) \ | 47 F(result_to_message) \ |
45 F(found_list_free) \ | 48 F(list_item_ids) \ |
46 F(list_item_ids_sync) \ | 49 F(item_get_attributes) \ |
47 F(item_get_attributes_sync) \ | 50 F(item_get_info) \ |
48 F(attribute_list_free) \ | 51 F(item_info_get_secret) |
49 F(item_get_info_sync) \ | |
50 F(item_info_get_secret) \ | |
51 F(item_info_free) | |
52 | 52 |
53 #define GNOME_KEYRING_DECLARE_TYPE(name) \ | 53 // Define the actual function pointers that we'll use in application code. |
| 54 #define GNOME_KEYRING_DEFINE_WRAPPER(name) \ |
54 typeof(&gnome_keyring_##name) wrap_gnome_keyring_##name; | 55 typeof(&gnome_keyring_##name) wrap_gnome_keyring_##name; |
55 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DECLARE_TYPE) | 56 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DEFINE_WRAPPER) |
56 #undef GNOME_KEYRING_DECLARE_TYPE | 57 #undef GNOME_KEYRING_DEFINE_WRAPPER |
57 | 58 |
58 // Make it easy to initialize the function pointers above with a loop below. | 59 // Make it easy to initialize the function pointers above with a loop below. |
59 #define GNOME_KEYRING_FUNCTION(name) \ | 60 #define GNOME_KEYRING_FUNCTION(name) \ |
60 {"gnome_keyring_"#name, reinterpret_cast<void**>(&wrap_gnome_keyring_##name)}, | 61 {"gnome_keyring_"#name, reinterpret_cast<void**>(&wrap_gnome_keyring_##name)}, |
61 const struct { | 62 const struct { |
62 const char* name; | 63 const char* name; |
63 void** pointer; | 64 void** pointer; |
64 } gnome_keyring_functions[] = { | 65 } gnome_keyring_functions[] = { |
65 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION) | 66 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION) |
66 {NULL, NULL} | 67 {NULL, NULL} |
67 }; | 68 }; |
68 #undef GNOME_KEYRING_FUNCTION | 69 #undef GNOME_KEYRING_FUNCTION |
69 | 70 |
70 #undef GNOME_KEYRING_FOR_EACH_FUNC | 71 #undef GNOME_KEYRING_FOR_EACH_FUNC |
71 | 72 |
72 // Allow application code below to use the normal function names, but actually | 73 // Allow application code below to use the normal function names, but actually |
73 // end up using the function pointers above instead. | 74 // end up using the function pointers above instead. |
74 #define gnome_keyring_is_available \ | 75 #define gnome_keyring_is_available \ |
75 wrap_gnome_keyring_is_available | 76 wrap_gnome_keyring_is_available |
76 #define gnome_keyring_store_password_sync \ | 77 #define gnome_keyring_store_password \ |
77 wrap_gnome_keyring_store_password_sync | 78 wrap_gnome_keyring_store_password |
78 #define gnome_keyring_delete_password_sync \ | 79 #define gnome_keyring_delete_password \ |
79 wrap_gnome_keyring_delete_password_sync | 80 wrap_gnome_keyring_delete_password |
80 #define gnome_keyring_find_itemsv_sync \ | 81 #define gnome_keyring_find_itemsv \ |
81 wrap_gnome_keyring_find_itemsv_sync | 82 wrap_gnome_keyring_find_itemsv |
82 #define gnome_keyring_result_to_message \ | 83 #define gnome_keyring_result_to_message \ |
83 wrap_gnome_keyring_result_to_message | 84 wrap_gnome_keyring_result_to_message |
84 #define gnome_keyring_found_list_free \ | 85 #define gnome_keyring_list_item_ids \ |
85 wrap_gnome_keyring_found_list_free | 86 wrap_gnome_keyring_list_item_ids |
86 #define gnome_keyring_list_item_ids_sync \ | 87 #define gnome_keyring_item_get_attributes \ |
87 wrap_gnome_keyring_list_item_ids_sync | 88 wrap_gnome_keyring_item_get_attributes |
88 #define gnome_keyring_item_get_attributes_sync \ | 89 #define gnome_keyring_item_get_info \ |
89 wrap_gnome_keyring_item_get_attributes_sync | 90 wrap_gnome_keyring_item_get_info |
90 #define gnome_keyring_attribute_list_free \ | |
91 wrap_gnome_keyring_attribute_list_free | |
92 #define gnome_keyring_item_get_info_sync \ | |
93 wrap_gnome_keyring_item_get_info_sync | |
94 #define gnome_keyring_item_info_get_secret \ | 91 #define gnome_keyring_item_info_get_secret \ |
95 wrap_gnome_keyring_item_info_get_secret | 92 wrap_gnome_keyring_item_info_get_secret |
96 #define gnome_keyring_item_info_free \ | |
97 wrap_gnome_keyring_item_info_free | |
98 | 93 |
99 /* Load the library and initialize the function pointers. */ | 94 /* Load the library and initialize the function pointers. */ |
100 bool LoadGnomeKeyring() { | 95 bool LoadGnomeKeyring() { |
101 void* handle = dlopen("libgnome-keyring.so.0", RTLD_NOW | RTLD_GLOBAL); | 96 void* handle = dlopen("libgnome-keyring.so.0", RTLD_NOW | RTLD_GLOBAL); |
102 if (!handle) { | 97 if (!handle) { |
103 // We wanted to use GNOME Keyring, but we couldn't load it. Warn, because | 98 // We wanted to use GNOME Keyring, but we couldn't load it. Warn, because |
104 // either the user asked for this, or we autodetected it incorrectly. (Or | 99 // either the user asked for this, or we autodetected it incorrectly. (Or |
105 // the system has broken libraries, which is also good to warn about.) | 100 // the system has broken libraries, which is also good to warn about.) |
106 LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror(); | 101 LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror(); |
107 return false; | 102 return false; |
108 } | 103 } |
109 for (size_t i = 0; gnome_keyring_functions[i].name; ++i) { | 104 for (size_t i = 0; gnome_keyring_functions[i].name; ++i) { |
110 dlerror(); | 105 dlerror(); |
111 *gnome_keyring_functions[i].pointer = | 106 *gnome_keyring_functions[i].pointer = |
112 dlsym(handle, gnome_keyring_functions[i].name); | 107 dlsym(handle, gnome_keyring_functions[i].name); |
113 const char* error = dlerror(); | 108 const char* error = dlerror(); |
114 if (error) { | 109 if (error) { |
115 LOG(ERROR) << "Unable to load symbol " << | 110 LOG(ERROR) << "Unable to load symbol " |
116 gnome_keyring_functions[i].name << ": " << error; | 111 << gnome_keyring_functions[i].name << ": " << error; |
117 dlclose(handle); | 112 dlclose(handle); |
118 return false; | 113 return false; |
119 } | 114 } |
120 } | 115 } |
121 // We leak the library handle. That's OK: this function is called only once. | 116 // We leak the library handle. That's OK: this function is called only once. |
122 return true; | 117 return true; |
123 } | 118 } |
124 | 119 |
125 // Older versions of GNOME Keyring have bugs that prevent them from | 120 // Older versions of GNOME Keyring have bugs that prevent them from working |
126 // working correctly with the find_itemsv API. (In particular, the | 121 // correctly with the find_itemsv API. (In particular, the non-pageable memory |
127 // non-pageable memory allocator is rather busted.) There is no | 122 // allocator is rather busted.) There is no official way to check the version, |
128 // official way to check the version, nor could we figure out any | 123 // nor could we figure out any reasonable unofficial way to do it. So we work |
129 // reasonable unofficial way to do it. So we work around it by using | 124 // around it by using a much slower API. |
130 // a much slower API. | 125 #define GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION |
131 #define GNOME_KEYRING_WORKAROUND_MEMORY_CORRUPTION | |
132 | 126 |
133 #else // !defined(DLOPEN_GNOME_KEYRING) | 127 #else // !defined(DLOPEN_GNOME_KEYRING) |
134 | 128 |
135 bool LoadGnomeKeyring() { | 129 bool LoadGnomeKeyring() { |
136 // We don't need to do anything here. When linking directly, we | 130 // We don't need to do anything here. When linking directly, we also assume |
137 // assume that whoever is compiling this code has checked that the | 131 // that whoever is compiling this code has checked that the version is OK. |
138 // version is OK. | |
139 return true; | 132 return true; |
140 } | 133 } |
141 | 134 |
142 #endif // !defined(DLOPEN_GNOME_KEYRING) | 135 #endif // !defined(DLOPEN_GNOME_KEYRING) |
143 | 136 |
144 #define GNOME_KEYRING_APPLICATION_CHROME "chrome" | 137 #define GNOME_KEYRING_APPLICATION_CHROME "chrome" |
145 | 138 |
146 // Convert the attributes of a given keyring entry into a new | 139 // Convert the attributes of a given keyring entry into a new PasswordForm. |
147 // PasswordForm. Note: does *not* get the actual password, as that is | 140 // Note: does *not* get the actual password, as that is not a key attribute! |
148 // not a key attribute! Returns NULL if the attributes are for the | 141 // Returns NULL if the attributes are for the wrong application. |
149 // wrong application. | |
150 PasswordForm* FormFromAttributes(GnomeKeyringAttributeList* attrs) { | 142 PasswordForm* FormFromAttributes(GnomeKeyringAttributeList* attrs) { |
151 // Read the string and int attributes into the appropriate map. | 143 // Read the string and int attributes into the appropriate map. |
152 std::map<std::string, std::string> string_attr_map; | 144 std::map<std::string, std::string> string_attr_map; |
153 std::map<std::string, uint32_t> uint_attr_map; | 145 std::map<std::string, uint32_t> uint_attr_map; |
154 for (guint i = 0; i < attrs->len; ++i) { | 146 for (guint i = 0; i < attrs->len; ++i) { |
155 GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i); | 147 GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i); |
156 if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) { | 148 if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) |
157 if (std::string(attr.name) == "application" && | |
158 std::string(attr.value.string) != GNOME_KEYRING_APPLICATION_CHROME) { | |
159 // This is not a password we care about. | |
160 return NULL; | |
161 } | |
162 string_attr_map[attr.name] = attr.value.string; | 149 string_attr_map[attr.name] = attr.value.string; |
163 } else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) { | 150 else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) |
164 uint_attr_map[attr.name] = attr.value.integer; | 151 uint_attr_map[attr.name] = attr.value.integer; |
165 } | |
166 } | 152 } |
| 153 // Check to make sure this is a password we care about. |
| 154 if (string_attr_map["application"] != GNOME_KEYRING_APPLICATION_CHROME) |
| 155 return NULL; |
167 | 156 |
168 PasswordForm* form = new PasswordForm(); | 157 PasswordForm* form = new PasswordForm(); |
169 form->origin = GURL(string_attr_map["origin_url"]); | 158 form->origin = GURL(string_attr_map["origin_url"]); |
170 form->action = GURL(string_attr_map["action_url"]); | 159 form->action = GURL(string_attr_map["action_url"]); |
171 form->username_element = UTF8ToUTF16(string_attr_map["username_element"]); | 160 form->username_element = UTF8ToUTF16(string_attr_map["username_element"]); |
172 form->username_value = UTF8ToUTF16(string_attr_map["username_value"]); | 161 form->username_value = UTF8ToUTF16(string_attr_map["username_value"]); |
173 form->password_element = UTF8ToUTF16(string_attr_map["password_element"]); | 162 form->password_element = UTF8ToUTF16(string_attr_map["password_element"]); |
174 form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]); | 163 form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]); |
175 form->signon_realm = string_attr_map["signon_realm"]; | 164 form->signon_realm = string_attr_map["signon_realm"]; |
176 form->ssl_valid = uint_attr_map["ssl_valid"]; | 165 form->ssl_valid = uint_attr_map["ssl_valid"]; |
177 form->preferred = uint_attr_map["preferred"]; | 166 form->preferred = uint_attr_map["preferred"]; |
178 int64 date_created = 0; | 167 int64 date_created = 0; |
179 bool date_ok = StringToInt64(string_attr_map["date_created"], | 168 bool date_ok = StringToInt64(string_attr_map["date_created"], |
180 &date_created); | 169 &date_created); |
181 DCHECK(date_ok); | 170 DCHECK(date_ok); |
182 DCHECK_NE(date_created, 0); | 171 DCHECK_NE(date_created, 0); |
183 form->date_created = base::Time::FromTimeT(date_created); | 172 form->date_created = base::Time::FromTimeT(date_created); |
184 form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"]; | 173 form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"]; |
185 form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]); | 174 form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]); |
186 | 175 |
187 return form; | 176 return form; |
188 } | 177 } |
189 | 178 |
190 } // namespace | 179 // Parse all the results from the given GList into a PasswordFormList, and free |
| 180 // the GList. PasswordForms are allocated on the heap, and should be deleted by |
| 181 // the consumer. |
| 182 void ConvertFormList(GList* found, |
| 183 NativeBackendGnome::PasswordFormList* forms) { |
| 184 GList* element = g_list_first(found); |
| 185 while (element != NULL) { |
| 186 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); |
| 187 GnomeKeyringAttributeList* attrs = data->attributes; |
| 188 |
| 189 PasswordForm* form = FormFromAttributes(attrs); |
| 190 if (form) { |
| 191 form->password_value = UTF8ToUTF16(data->secret); |
| 192 forms->push_back(form); |
| 193 } else { |
| 194 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; |
| 195 } |
| 196 |
| 197 element = g_list_next(element); |
| 198 } |
| 199 } |
191 | 200 |
192 // Schema is analagous to the fields in PasswordForm. | 201 // Schema is analagous to the fields in PasswordForm. |
193 const GnomeKeyringPasswordSchema NativeBackendGnome::kGnomeSchema = { | 202 const GnomeKeyringPasswordSchema kGnomeSchema = { |
194 GNOME_KEYRING_ITEM_GENERIC_SECRET, { | 203 GNOME_KEYRING_ITEM_GENERIC_SECRET, { |
195 { "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 204 { "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
196 { "action_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 205 { "action_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
197 { "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 206 { "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
198 { "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 207 { "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
199 { "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 208 { "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
200 { "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 209 { "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
201 { "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 210 { "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
202 { "ssl_valid", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | 211 { "ssl_valid", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, |
203 { "preferred", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | 212 { "preferred", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, |
204 { "date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 213 { "date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
205 { "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | 214 { "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, |
206 { "scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | 215 { "scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, |
207 // This field is always "chrome" so that we can search for it. | 216 // This field is always "chrome" so that we can search for it. |
208 { "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | 217 { "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, |
209 { NULL } | 218 { NULL } |
210 } | 219 } |
211 }; | 220 }; |
212 | 221 |
213 NativeBackendGnome::NativeBackendGnome() { | 222 // Sadly, PasswordStore goes to great lengths to switch from the originally |
214 } | 223 // calling thread to the DB thread, and to provide an asynchronous API to |
| 224 // callers while using a synchronous (virtual) API provided by subclasses like |
| 225 // PasswordStoreX -- but GNOME Keyring really wants to be on the GLib main |
| 226 // thread, which is the UI thread to us. So we end up having to switch threads |
| 227 // again, possibly back to the very same thread (in case the UI thread is the |
| 228 // caller, e.g. in the password management UI), and *block* the DB thread |
| 229 // waiting for a response from the UI thread to provide the synchronous API |
| 230 // PasswordStore expects of us. (It will then in turn switch back to the |
| 231 // original caller to send the asynchronous reply to the original request.) |
215 | 232 |
216 NativeBackendGnome::~NativeBackendGnome() { | 233 // This class represents a call to a GNOME Keyring method. A RunnableMethod |
217 } | 234 // should be posted to the UI thread to call one of its action methods, and then |
| 235 // a WaitResult() method should be called to wait for the result. Each instance |
| 236 // supports only one outstanding method at a time, though multiple instances may |
| 237 // be used in parallel. |
| 238 class GKRMethod { |
| 239 public: |
| 240 typedef NativeBackendGnome::PasswordFormList PasswordFormList; |
218 | 241 |
219 bool NativeBackendGnome::Init() { | 242 GKRMethod() : event_(false, false), result_(GNOME_KEYRING_RESULT_CANCELLED) {} |
220 return LoadGnomeKeyring() && gnome_keyring_is_available(); | |
221 } | |
222 | 243 |
223 bool NativeBackendGnome::AddLogin(const PasswordForm& form) { | 244 // Action methods. These call gnome_keyring_* functions. Call from UI thread. |
224 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 245 void AddLogin(const PasswordForm& form); |
225 GnomeKeyringResult result = gnome_keyring_store_password_sync( | 246 void UpdateLoginSearch(const PasswordForm& form); |
| 247 void RemoveLogin(const PasswordForm& form); |
| 248 void GetLogins(const PasswordForm& form); |
| 249 #if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 250 void GetLoginsList(uint32_t blacklisted_by_user); |
| 251 void GetAllLogins(); |
| 252 #else |
| 253 void GetItemIds(); |
| 254 void GetItemAttrs(guint id); |
| 255 void GetItemInfo(guint id); |
| 256 #endif |
| 257 |
| 258 // Use after AddLogin, RemoveLogin. |
| 259 GnomeKeyringResult WaitResult(); |
| 260 |
| 261 // Use after UpdateLoginSearch, GetLogins, GetLoginsList, GetAllLogins. |
| 262 GnomeKeyringResult WaitResult(PasswordFormList* forms); |
| 263 |
| 264 #if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 265 // Use after GetItemIds(). |
| 266 GnomeKeyringResult WaitResult(std::vector<guint>* item_ids); |
| 267 |
| 268 // Use after GetItemAttrs(). |
| 269 GnomeKeyringResult WaitResult(PasswordForm** form); |
| 270 |
| 271 // Use after GetItemInfo(). |
| 272 GnomeKeyringResult WaitResult(string16* password); |
| 273 #endif |
| 274 |
| 275 private: |
| 276 // All these callbacks are called on UI thread. |
| 277 static void OnOperationDone(GnomeKeyringResult result, gpointer data); |
| 278 |
| 279 static void OnOperationGetList(GnomeKeyringResult result, GList* list, |
| 280 gpointer data); |
| 281 |
| 282 #if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 283 static void OnOperationGetIds(GnomeKeyringResult result, GList* list, |
| 284 gpointer data); |
| 285 |
| 286 static void OnOperationGetAttrs(GnomeKeyringResult result, |
| 287 GnomeKeyringAttributeList* attrs, |
| 288 gpointer data); |
| 289 |
| 290 static void OnOperationGetInfo(GnomeKeyringResult result, |
| 291 GnomeKeyringItemInfo* info, |
| 292 gpointer data); |
| 293 #endif |
| 294 |
| 295 base::WaitableEvent event_; |
| 296 GnomeKeyringResult result_; |
| 297 NativeBackendGnome::PasswordFormList forms_; |
| 298 #if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 299 std::vector<guint> item_ids_; |
| 300 scoped_ptr<PasswordForm> form_; |
| 301 string16 password_; |
| 302 #endif |
| 303 }; |
| 304 |
| 305 void GKRMethod::AddLogin(const PasswordForm& form) { |
| 306 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 307 gnome_keyring_store_password( |
226 &kGnomeSchema, | 308 &kGnomeSchema, |
227 NULL, // Default keyring. | 309 NULL, // Default keyring. |
228 form.origin.spec().c_str(), // Display name. | 310 form.origin.spec().c_str(), // Display name. |
229 UTF16ToUTF8(form.password_value).c_str(), | 311 UTF16ToUTF8(form.password_value).c_str(), |
| 312 OnOperationDone, |
| 313 this, // data |
| 314 NULL, // destroy_data |
230 "origin_url", form.origin.spec().c_str(), | 315 "origin_url", form.origin.spec().c_str(), |
231 "action_url", form.action.spec().c_str(), | 316 "action_url", form.action.spec().c_str(), |
232 "username_element", UTF16ToUTF8(form.username_element).c_str(), | 317 "username_element", UTF16ToUTF8(form.username_element).c_str(), |
233 "username_value", UTF16ToUTF8(form.username_value).c_str(), | 318 "username_value", UTF16ToUTF8(form.username_value).c_str(), |
234 "password_element", UTF16ToUTF8(form.password_element).c_str(), | 319 "password_element", UTF16ToUTF8(form.password_element).c_str(), |
235 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), | 320 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), |
236 "signon_realm", form.signon_realm.c_str(), | 321 "signon_realm", form.signon_realm.c_str(), |
237 "ssl_valid", form.ssl_valid, | 322 "ssl_valid", form.ssl_valid, |
238 "preferred", form.preferred, | 323 "preferred", form.preferred, |
239 "date_created", Int64ToString(form.date_created.ToTimeT()).c_str(), | 324 "date_created", Int64ToString(form.date_created.ToTimeT()).c_str(), |
240 "blacklisted_by_user", form.blacklisted_by_user, | 325 "blacklisted_by_user", form.blacklisted_by_user, |
241 "scheme", form.scheme, | 326 "scheme", form.scheme, |
242 "application", GNOME_KEYRING_APPLICATION_CHROME, | 327 "application", GNOME_KEYRING_APPLICATION_CHROME, |
243 NULL); | 328 NULL); |
244 | 329 } |
| 330 |
| 331 void GKRMethod::UpdateLoginSearch(const PasswordForm& form) { |
| 332 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 333 // Search GNOME Keyring for matching passwords to update. |
| 334 gnome_keyring_find_itemsv( |
| 335 GNOME_KEYRING_ITEM_GENERIC_SECRET, |
| 336 OnOperationGetList, |
| 337 this, // data |
| 338 NULL, // destroy_data |
| 339 "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 340 form.origin.spec().c_str(), |
| 341 "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 342 UTF16ToUTF8(form.username_element).c_str(), |
| 343 "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 344 UTF16ToUTF8(form.username_value).c_str(), |
| 345 "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 346 UTF16ToUTF8(form.password_element).c_str(), |
| 347 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 348 form.signon_realm.c_str(), |
| 349 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 350 GNOME_KEYRING_APPLICATION_CHROME, |
| 351 NULL); |
| 352 } |
| 353 |
| 354 void GKRMethod::RemoveLogin(const PasswordForm& form) { |
| 355 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 356 // We find forms using the same fields as LoginDatabase::RemoveLogin(). |
| 357 gnome_keyring_delete_password( |
| 358 &kGnomeSchema, |
| 359 OnOperationDone, |
| 360 this, // data |
| 361 NULL, // destroy_data |
| 362 "origin_url", form.origin.spec().c_str(), |
| 363 "action_url", form.action.spec().c_str(), |
| 364 "username_element", UTF16ToUTF8(form.username_element).c_str(), |
| 365 "username_value", UTF16ToUTF8(form.username_value).c_str(), |
| 366 "password_element", UTF16ToUTF8(form.password_element).c_str(), |
| 367 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), |
| 368 "signon_realm", form.signon_realm.c_str(), |
| 369 NULL); |
| 370 } |
| 371 |
| 372 void GKRMethod::GetLogins(const PasswordForm& form) { |
| 373 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 374 // Search GNOME Keyring for matching passwords. |
| 375 gnome_keyring_find_itemsv( |
| 376 GNOME_KEYRING_ITEM_GENERIC_SECRET, |
| 377 OnOperationGetList, |
| 378 this, // data |
| 379 NULL, // destroy_data |
| 380 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 381 form.signon_realm.c_str(), |
| 382 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 383 GNOME_KEYRING_APPLICATION_CHROME, |
| 384 NULL); |
| 385 } |
| 386 |
| 387 #if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 388 void GKRMethod::GetLoginsList(uint32_t blacklisted_by_user) { |
| 389 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 390 // Search GNOME Keyring for matching passwords. |
| 391 gnome_keyring_find_itemsv( |
| 392 GNOME_KEYRING_ITEM_GENERIC_SECRET, |
| 393 OnOperationGetList, |
| 394 this, // data |
| 395 NULL, // destroy_data |
| 396 "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32, |
| 397 blacklisted_by_user, |
| 398 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 399 GNOME_KEYRING_APPLICATION_CHROME, |
| 400 NULL); |
| 401 } |
| 402 |
| 403 void GKRMethod::GetAllLogins() { |
| 404 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 405 // We need to search for something, otherwise we get no results - so |
| 406 // we search for the fixed application string. |
| 407 gnome_keyring_find_itemsv( |
| 408 GNOME_KEYRING_ITEM_GENERIC_SECRET, |
| 409 OnOperationGetList, |
| 410 this, // data |
| 411 NULL, // destroy_data |
| 412 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, |
| 413 GNOME_KEYRING_APPLICATION_CHROME, |
| 414 NULL); |
| 415 } |
| 416 #else |
| 417 void GKRMethod::GetItemIds() { |
| 418 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 419 gnome_keyring_list_item_ids(NULL, OnOperationGetIds, this, NULL); |
| 420 } |
| 421 |
| 422 void GKRMethod::GetItemAttrs(guint id) { |
| 423 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 424 gnome_keyring_item_get_attributes(NULL, id, OnOperationGetAttrs, this, NULL); |
| 425 } |
| 426 |
| 427 void GKRMethod::GetItemInfo(guint id) { |
| 428 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 429 gnome_keyring_item_get_info(NULL, id, OnOperationGetInfo, this, NULL); |
| 430 } |
| 431 #endif |
| 432 |
| 433 GnomeKeyringResult GKRMethod::WaitResult() { |
| 434 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 435 event_.Wait(); |
| 436 return result_; |
| 437 } |
| 438 |
| 439 GnomeKeyringResult GKRMethod::WaitResult(PasswordFormList* forms) { |
| 440 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 441 event_.Wait(); |
| 442 forms->swap(forms_); |
| 443 return result_; |
| 444 } |
| 445 |
| 446 #if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 447 GnomeKeyringResult GKRMethod::WaitResult(std::vector<guint>* item_ids) { |
| 448 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 449 event_.Wait(); |
| 450 item_ids->swap(item_ids_); |
| 451 return result_; |
| 452 } |
| 453 |
| 454 GnomeKeyringResult GKRMethod::WaitResult(PasswordForm** form) { |
| 455 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 456 event_.Wait(); |
| 457 *form = form_.release(); |
| 458 return result_; |
| 459 } |
| 460 |
| 461 GnomeKeyringResult GKRMethod::WaitResult(string16* password) { |
| 462 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 463 event_.Wait(); |
| 464 *password = password_; |
| 465 return result_; |
| 466 } |
| 467 #endif |
| 468 |
| 469 // static |
| 470 void GKRMethod::OnOperationDone(GnomeKeyringResult result, gpointer data) { |
| 471 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 472 method->result_ = result; |
| 473 method->event_.Signal(); |
| 474 } |
| 475 |
| 476 // static |
| 477 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, |
| 478 gpointer data) { |
| 479 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 480 method->result_ = result; |
| 481 method->forms_.clear(); |
| 482 // |list| will be freed after this callback returns, so convert it now. |
| 483 ConvertFormList(list, &method->forms_); |
| 484 method->event_.Signal(); |
| 485 } |
| 486 |
| 487 #if defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
| 488 // static |
| 489 void GKRMethod::OnOperationGetIds(GnomeKeyringResult result, GList* list, |
| 490 gpointer data) { |
| 491 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 492 method->result_ = result; |
| 493 method->item_ids_.clear(); |
| 494 // |list| will be freed after this callback returns, so save it now. |
| 495 for (GList* i = list; i; i = i->next) { |
| 496 guint id = GPOINTER_TO_UINT(i->data); |
| 497 method->item_ids_.push_back(id); |
| 498 } |
| 499 method->event_.Signal(); |
| 500 } |
| 501 |
| 502 // static |
| 503 void GKRMethod::OnOperationGetAttrs(GnomeKeyringResult result, |
| 504 GnomeKeyringAttributeList* attrs, |
| 505 gpointer data) { |
| 506 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 507 method->result_ = result; |
| 508 // |attrs| will be freed after this callback returns, so convert it now. |
| 509 if (result == GNOME_KEYRING_RESULT_OK) |
| 510 method->form_.reset(FormFromAttributes(attrs)); |
| 511 method->event_.Signal(); |
| 512 } |
| 513 |
| 514 // static |
| 515 void GKRMethod::OnOperationGetInfo(GnomeKeyringResult result, |
| 516 GnomeKeyringItemInfo* info, |
| 517 gpointer data) { |
| 518 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 519 method->result_ = result; |
| 520 // |info| will be freed after this callback returns, so use it now. |
| 521 if (result == GNOME_KEYRING_RESULT_OK) { |
| 522 char* secret = gnome_keyring_item_info_get_secret(info); |
| 523 method->password_ = UTF8ToUTF16(secret); |
| 524 // gnome_keyring_item_info_get_secret() allocates and returns a new copy |
| 525 // of the secret, so we have to free it afterward. |
| 526 free(secret); |
| 527 } |
| 528 method->event_.Signal(); |
| 529 } |
| 530 #endif |
| 531 |
| 532 } // namespace |
| 533 |
| 534 // GKRMethod isn't reference counted, but it always outlasts runnable |
| 535 // methods against it because the caller waits for those methods to run. |
| 536 template<> |
| 537 struct RunnableMethodTraits<GKRMethod> { |
| 538 void RetainCallee(GKRMethod*) {} |
| 539 void ReleaseCallee(GKRMethod*) {} |
| 540 }; |
| 541 |
| 542 NativeBackendGnome::NativeBackendGnome() { |
| 543 } |
| 544 |
| 545 NativeBackendGnome::~NativeBackendGnome() { |
| 546 } |
| 547 |
| 548 bool NativeBackendGnome::Init() { |
| 549 return LoadGnomeKeyring() && gnome_keyring_is_available(); |
| 550 } |
| 551 |
| 552 bool NativeBackendGnome::AddLogin(const PasswordForm& form) { |
| 553 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
| 554 GKRMethod method; |
| 555 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 556 NewRunnableMethod(&method, |
| 557 &GKRMethod::AddLogin, |
| 558 form)); |
| 559 GnomeKeyringResult result = method.WaitResult(); |
245 if (result != GNOME_KEYRING_RESULT_OK) { | 560 if (result != GNOME_KEYRING_RESULT_OK) { |
246 LOG(ERROR) << "Keyring save failed: " | 561 LOG(ERROR) << "Keyring save failed: " |
247 << gnome_keyring_result_to_message(result); | 562 << gnome_keyring_result_to_message(result); |
248 return false; | 563 return false; |
249 } | 564 } |
250 return true; | 565 return true; |
251 } | 566 } |
252 | 567 |
253 bool NativeBackendGnome::UpdateLogin(const PasswordForm& form) { | 568 bool NativeBackendGnome::UpdateLogin(const PasswordForm& form) { |
254 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by | 569 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by |
255 // origin_url, username_element, username_value, password_element, and | 570 // origin_url, username_element, username_value, password_element, and |
256 // signon_realm. We then compare the result to the updated form. If they | 571 // signon_realm. We then compare the result to the updated form. If they |
257 // differ in any of the action, password_value, ssl_valid, or preferred | 572 // differ in any of the action, password_value, ssl_valid, or preferred |
258 // fields, then we add a new login with those fields updated and only delete | 573 // fields, then we add a new login with those fields updated and only delete |
259 // the original on success. | 574 // the original on success. |
260 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 575 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
261 GList* found = NULL; | 576 GKRMethod method; |
262 // Search gnome keyring for matching passwords. | 577 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
263 GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( | 578 NewRunnableMethod(&method, |
264 GNOME_KEYRING_ITEM_GENERIC_SECRET, | 579 &GKRMethod::UpdateLoginSearch, |
265 &found, | 580 form)); |
266 "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | 581 PasswordFormList forms; |
267 form.origin.spec().c_str(), | 582 GnomeKeyringResult result = method.WaitResult(&forms); |
268 "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
269 UTF16ToUTF8(form.username_element).c_str(), | |
270 "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
271 UTF16ToUTF8(form.username_value).c_str(), | |
272 "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
273 UTF16ToUTF8(form.password_element).c_str(), | |
274 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
275 form.signon_realm.c_str(), | |
276 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
277 GNOME_KEYRING_APPLICATION_CHROME, | |
278 NULL); | |
279 if (result != GNOME_KEYRING_RESULT_OK) { | 583 if (result != GNOME_KEYRING_RESULT_OK) { |
280 LOG(ERROR) << "Keyring find failed: " | 584 LOG(ERROR) << "Keyring find failed: " |
281 << gnome_keyring_result_to_message(result); | 585 << gnome_keyring_result_to_message(result); |
282 return false; | 586 return false; |
283 } | 587 } |
284 bool ok = true; | 588 bool ok = true; |
285 PasswordFormList forms; | |
286 ConvertFormList(found, &forms); | |
287 for (size_t i = 0; i < forms.size(); ++i) { | 589 for (size_t i = 0; i < forms.size(); ++i) { |
288 if (forms[i]->action != form.action || | 590 if (forms[i]->action != form.action || |
289 forms[i]->password_value != form.password_value || | 591 forms[i]->password_value != form.password_value || |
290 forms[i]->ssl_valid != form.ssl_valid || | 592 forms[i]->ssl_valid != form.ssl_valid || |
291 forms[i]->preferred != form.preferred) { | 593 forms[i]->preferred != form.preferred) { |
292 PasswordForm updated = *forms[i]; | 594 PasswordForm updated = *forms[i]; |
293 updated.action = form.action; | 595 updated.action = form.action; |
294 updated.password_value = form.password_value; | 596 updated.password_value = form.password_value; |
295 updated.ssl_valid = form.ssl_valid; | 597 updated.ssl_valid = form.ssl_valid; |
296 updated.preferred = form.preferred; | 598 updated.preferred = form.preferred; |
297 if (AddLogin(updated)) | 599 if (AddLogin(updated)) |
298 RemoveLogin(*forms[i]); | 600 RemoveLogin(*forms[i]); |
299 else | 601 else |
300 ok = false; | 602 ok = false; |
301 } | 603 } |
302 delete forms[i]; | 604 delete forms[i]; |
303 } | 605 } |
304 return ok; | 606 return ok; |
305 } | 607 } |
306 | 608 |
307 bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) { | 609 bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) { |
308 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 610 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
309 // We find forms using the same fields as LoginDatabase::RemoveLogin(). | 611 GKRMethod method; |
310 GnomeKeyringResult result = gnome_keyring_delete_password_sync( | 612 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
311 &kGnomeSchema, | 613 NewRunnableMethod(&method, |
312 "origin_url", form.origin.spec().c_str(), | 614 &GKRMethod::RemoveLogin, |
313 "action_url", form.action.spec().c_str(), | 615 form)); |
314 "username_element", UTF16ToUTF8(form.username_element).c_str(), | 616 GnomeKeyringResult result = method.WaitResult(); |
315 "username_value", UTF16ToUTF8(form.username_value).c_str(), | |
316 "password_element", UTF16ToUTF8(form.password_element).c_str(), | |
317 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), | |
318 "signon_realm", form.signon_realm.c_str(), | |
319 NULL); | |
320 if (result != GNOME_KEYRING_RESULT_OK) { | 617 if (result != GNOME_KEYRING_RESULT_OK) { |
321 LOG(ERROR) << "Keyring delete failed: " | 618 LOG(ERROR) << "Keyring delete failed: " |
322 << gnome_keyring_result_to_message(result); | 619 << gnome_keyring_result_to_message(result); |
323 return false; | 620 return false; |
324 } | 621 } |
325 return true; | 622 return true; |
326 } | 623 } |
327 | 624 |
328 bool NativeBackendGnome::RemoveLoginsCreatedBetween( | 625 bool NativeBackendGnome::RemoveLoginsCreatedBetween( |
329 const base::Time& delete_begin, | 626 const base::Time& delete_begin, |
(...skipping 13 matching lines...) Expand all Loading... |
343 ok = false; | 640 ok = false; |
344 } | 641 } |
345 delete forms[i]; | 642 delete forms[i]; |
346 } | 643 } |
347 return ok; | 644 return ok; |
348 } | 645 } |
349 | 646 |
350 bool NativeBackendGnome::GetLogins(const PasswordForm& form, | 647 bool NativeBackendGnome::GetLogins(const PasswordForm& form, |
351 PasswordFormList* forms) { | 648 PasswordFormList* forms) { |
352 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 649 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
353 GList* found = NULL; | 650 GKRMethod method; |
354 // Search gnome keyring for matching passwords. | 651 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
355 GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( | 652 NewRunnableMethod(&method, |
356 GNOME_KEYRING_ITEM_GENERIC_SECRET, | 653 &GKRMethod::GetLogins, |
357 &found, | 654 form)); |
358 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | 655 GnomeKeyringResult result = method.WaitResult(forms); |
359 form.signon_realm.c_str(), | |
360 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
361 GNOME_KEYRING_APPLICATION_CHROME, | |
362 NULL); | |
363 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | 656 if (result == GNOME_KEYRING_RESULT_NO_MATCH) |
364 return true; | 657 return true; |
365 if (result != GNOME_KEYRING_RESULT_OK) { | 658 if (result != GNOME_KEYRING_RESULT_OK) { |
366 LOG(ERROR) << "Keyring find failed: " | 659 LOG(ERROR) << "Keyring find failed: " |
367 << gnome_keyring_result_to_message(result); | 660 << gnome_keyring_result_to_message(result); |
368 return false; | 661 return false; |
369 } | 662 } |
370 ConvertFormList(found, forms); | |
371 return true; | 663 return true; |
372 } | 664 } |
373 | 665 |
374 bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin, | 666 bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin, |
375 const base::Time& get_end, | 667 const base::Time& get_end, |
376 PasswordFormList* forms) { | 668 PasswordFormList* forms) { |
377 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 669 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
378 // We could walk the list and add items as we find them, but it is much | 670 // We could walk the list and add items as we find them, but it is much |
379 // easier to build the list and then filter the results. | 671 // easier to build the list and then filter the results. |
380 PasswordFormList all_forms; | 672 PasswordFormList all_forms; |
(...skipping 20 matching lines...) Expand all Loading... |
401 bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) { | 693 bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) { |
402 return GetLoginsList(forms, false); | 694 return GetLoginsList(forms, false); |
403 } | 695 } |
404 | 696 |
405 bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms, | 697 bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms, |
406 bool autofillable) { | 698 bool autofillable) { |
407 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); | 699 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
408 | 700 |
409 uint32_t blacklisted_by_user = !autofillable; | 701 uint32_t blacklisted_by_user = !autofillable; |
410 | 702 |
411 #if !defined(GNOME_KEYRING_WORKAROUND_MEMORY_CORRUPTION) | 703 #if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
412 GList* found = NULL; | 704 GKRMethod method; |
413 // Search gnome keyring for matching passwords. | 705 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
414 GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( | 706 NewRunnableMethod(&method, |
415 GNOME_KEYRING_ITEM_GENERIC_SECRET, | 707 &GKRMethod::GetLoginsList, |
416 &found, | 708 blacklisted_by_user)); |
417 "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32, | 709 GnomeKeyringResult result = method.WaitResult(forms); |
418 blacklisted_by_user, | |
419 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
420 GNOME_KEYRING_APPLICATION_CHROME, | |
421 NULL); | |
422 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | 710 if (result == GNOME_KEYRING_RESULT_NO_MATCH) |
423 return true; | 711 return true; |
424 if (result != GNOME_KEYRING_RESULT_OK) { | 712 if (result != GNOME_KEYRING_RESULT_OK) { |
425 LOG(ERROR) << "Keyring find failed: " | 713 LOG(ERROR) << "Keyring find failed: " |
426 << gnome_keyring_result_to_message(result); | 714 << gnome_keyring_result_to_message(result); |
427 return false; | 715 return false; |
428 } | 716 } |
429 ConvertFormList(found, forms); | |
430 return true; | 717 return true; |
431 #else | 718 #else |
432 PasswordFormList all_forms; | 719 PasswordFormList all_forms; |
433 if (!GetAllLogins(&all_forms)) | 720 if (!GetAllLogins(&all_forms)) |
434 return false; | 721 return false; |
435 // Now manually filter the result for the values we care about. | 722 // Now manually filter the results for the values we care about. |
436 for (size_t i = 0; i < all_forms.size(); ++i) { | 723 for (size_t i = 0; i < all_forms.size(); ++i) { |
437 if (all_forms[i]->blacklisted_by_user == blacklisted_by_user) | 724 if (all_forms[i]->blacklisted_by_user == blacklisted_by_user) |
438 forms->push_back(all_forms[i]); | 725 forms->push_back(all_forms[i]); |
439 else | 726 else |
440 delete all_forms[i]; | 727 delete all_forms[i]; |
441 } | 728 } |
442 return true; | 729 return true; |
443 #endif | 730 #endif |
444 } | 731 } |
445 | 732 |
446 bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) { | 733 bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) { |
447 // Older versions of GNOME Keyring have bugs that prevent them from | 734 GKRMethod method; |
448 // working correctly with the find_itemsv API. (In particular, the | 735 #if !defined(GNOME_KEYRING_WORK_AROUND_MEMORY_CORRUPTION) |
449 // non-pageable memory allocator is rather busted.) There is no | 736 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
450 // official way to check the version, nor could we figure out any | 737 NewRunnableMethod(&method, |
451 // reasonable unofficial way to do it. So we work around it by | 738 &GKRMethod::GetAllLogins)); |
452 // using a much slower API. | 739 GnomeKeyringResult result = method.WaitResult(forms); |
453 | |
454 #if !defined(GNOME_KEYRING_WORKAROUND_MEMORY_CORRUPTION) | |
455 GList* found = NULL; | |
456 // We need to search for something, otherwise we get no results - so | |
457 // we search for the fixed application string. | |
458 GnomeKeyringResult result = gnome_keyring_find_itemsv_sync( | |
459 GNOME_KEYRING_ITEM_GENERIC_SECRET, | |
460 &found, | |
461 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
462 GNOME_KEYRING_APPLICATION_CHROME, | |
463 NULL); | |
464 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | 740 if (result == GNOME_KEYRING_RESULT_NO_MATCH) |
465 return true; | 741 return true; |
466 if (result != GNOME_KEYRING_RESULT_OK) { | 742 if (result != GNOME_KEYRING_RESULT_OK) { |
467 LOG(ERROR) << "Keyring find failed: " | 743 LOG(ERROR) << "Keyring find failed: " |
468 << gnome_keyring_result_to_message(result); | 744 << gnome_keyring_result_to_message(result); |
469 return false; | 745 return false; |
470 } | 746 } |
471 ConvertFormList(found, forms); | |
472 return true; | 747 return true; |
473 #else | 748 #else |
474 GList* ids = NULL; | 749 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
475 GnomeKeyringResult result = gnome_keyring_list_item_ids_sync(NULL, &ids); | 750 NewRunnableMethod(&method, |
| 751 &GKRMethod::GetItemIds)); |
| 752 std::vector<guint> item_ids; |
| 753 GnomeKeyringResult result = method.WaitResult(&item_ids); |
476 if (result != GNOME_KEYRING_RESULT_OK) { | 754 if (result != GNOME_KEYRING_RESULT_OK) { |
477 LOG(ERROR) << "Keyring itemid list failed: " | 755 LOG(ERROR) << "Keyring itemid list failed: " |
478 << gnome_keyring_result_to_message(result); | 756 << gnome_keyring_result_to_message(result); |
479 return false; | 757 return false; |
480 } | 758 } |
481 | 759 |
482 for (GList* i = ids; i; i = i->next) { | 760 // We can parallelize getting the item attributes. |
483 int id = GPOINTER_TO_INT(i->data); | 761 GKRMethod* methods = new GKRMethod[item_ids.size()]; |
484 GnomeKeyringAttributeList* attrs = NULL; | 762 for (size_t i = 0; i < item_ids.size(); ++i) { |
485 result = gnome_keyring_item_get_attributes_sync(NULL, id, &attrs); | 763 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 764 NewRunnableMethod(&methods[i], |
| 765 &GKRMethod::GetItemAttrs, |
| 766 item_ids[i])); |
| 767 } |
| 768 |
| 769 bool success = true; |
| 770 |
| 771 // We can also parallelize getting the item info (i.e. passwords). |
| 772 PasswordFormList all_forms; |
| 773 all_forms.resize(item_ids.size()); |
| 774 for (size_t i = 0; i < item_ids.size(); ++i) { |
| 775 result = methods[i].WaitResult(&all_forms[i]); |
486 if (result != GNOME_KEYRING_RESULT_OK) { | 776 if (result != GNOME_KEYRING_RESULT_OK) { |
487 LOG(ERROR) << "Keyring get item attributes failed:" | 777 LOG(ERROR) << "Keyring get item attributes failed:" |
488 << gnome_keyring_result_to_message(result); | 778 << gnome_keyring_result_to_message(result); |
489 gnome_keyring_attribute_list_free(attrs); | 779 // We explicitly do not break out here. We must wait on all the other |
490 break; | 780 // methods first, and we may have already posted new methods. So, we just |
| 781 // note the failure and continue. |
| 782 success = false; |
491 } | 783 } |
492 | 784 if (all_forms[i]) { |
493 PasswordForm* form = FormFromAttributes(attrs); | 785 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
494 gnome_keyring_attribute_list_free(attrs); | 786 NewRunnableMethod(&methods[i], |
495 | 787 &GKRMethod::GetItemInfo, |
496 if (form) { | 788 item_ids[i])); |
497 GnomeKeyringItemInfo* info = NULL; | |
498 result = gnome_keyring_item_get_info_sync(NULL, id, &info); | |
499 if (result != GNOME_KEYRING_RESULT_OK) { | |
500 delete form; | |
501 break; | |
502 } | |
503 form->password_value = UTF8ToUTF16( | |
504 gnome_keyring_item_info_get_secret(info)); | |
505 | |
506 gnome_keyring_item_info_free(info); | |
507 forms->push_back(form); | |
508 } | 789 } |
509 } | 790 } |
510 g_list_free(ids); | |
511 | 791 |
512 return result == GNOME_KEYRING_RESULT_OK; | 792 // Now just wait for all the passwords to come in. |
| 793 for (size_t i = 0; i < item_ids.size(); ++i) { |
| 794 if (!all_forms[i]) |
| 795 continue; |
| 796 result = methods[i].WaitResult(&all_forms[i]->password_value); |
| 797 if (result != GNOME_KEYRING_RESULT_OK) { |
| 798 LOG(ERROR) << "Keyring get item info failed:" |
| 799 << gnome_keyring_result_to_message(result); |
| 800 delete all_forms[i]; |
| 801 all_forms[i] = NULL; |
| 802 // We explicitly do not break out here (see above). |
| 803 success = false; |
| 804 } |
| 805 } |
| 806 |
| 807 delete[] methods; |
| 808 |
| 809 if (success) { |
| 810 // If we succeeded, output all the forms. |
| 811 for (size_t i = 0; i < item_ids.size(); ++i) { |
| 812 if (all_forms[i]) |
| 813 forms->push_back(all_forms[i]); |
| 814 } |
| 815 } else { |
| 816 // Otherwise, free them. |
| 817 for (size_t i = 0; i < item_ids.size(); ++i) |
| 818 delete all_forms[i]; |
| 819 } |
| 820 |
| 821 return success; |
513 #endif | 822 #endif |
514 } | 823 } |
515 | |
516 void NativeBackendGnome::ConvertFormList(GList* found, | |
517 PasswordFormList* forms) { | |
518 GList* element = g_list_first(found); | |
519 while (element != NULL) { | |
520 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); | |
521 GnomeKeyringAttributeList* attrs = data->attributes; | |
522 | |
523 PasswordForm* form = FormFromAttributes(attrs); | |
524 form->password_value = UTF8ToUTF16(data->secret); | |
525 forms->push_back(form); | |
526 | |
527 element = g_list_next(element); | |
528 } | |
529 gnome_keyring_found_list_free(found); | |
530 } | |
OLD | NEW |