OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <dlfcn.h> | |
8 #include <gnome-keyring.h> | 7 #include <gnome-keyring.h> |
9 | 8 |
10 #include <map> | |
11 #include <string> | 9 #include <string> |
12 #include <vector> | |
13 | 10 |
14 #include "base/logging.h" | 11 #include "base/logging.h" |
15 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
16 #include "base/string_piece.h" | |
17 #include "base/string_util.h" | |
18 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
19 #include "base/synchronization/waitable_event.h" | 14 #include "chrome/browser/password_manager/proxy/chrome_keyring_proxy_client.h" |
20 #include "base/time.h" | |
21 #include "base/utf_string_conversions.h" | |
22 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
23 | 16 |
24 using webkit_glue::PasswordForm; | 17 using webkit_glue::PasswordForm; |
25 | 18 |
26 #define GNOME_KEYRING_DEFINE_POINTER(name) \ | 19 const char NativeBackendGnome::kGnomeKeyringAppString[] = "chrome"; |
27 typeof(&::gnome_keyring_##name) GnomeKeyringLoader::gnome_keyring_##name; | |
28 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DEFINE_POINTER) | |
29 #undef GNOME_KEYRING_DEFINE_POINTER | |
30 | |
31 bool GnomeKeyringLoader::keyring_loaded = false; | |
32 | |
33 #if defined(DLOPEN_GNOME_KEYRING) | |
34 | |
35 #define GNOME_KEYRING_FUNCTION_INFO(name) \ | |
36 {"gnome_keyring_"#name, reinterpret_cast<void**>(&gnome_keyring_##name)}, | |
37 const GnomeKeyringLoader::FunctionInfo GnomeKeyringLoader::functions[] = { | |
38 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION_INFO) | |
39 {NULL, NULL} | |
40 }; | |
41 #undef GNOME_KEYRING_FUNCTION_INFO | |
42 | |
43 /* Load the library and initialize the function pointers. */ | |
44 bool GnomeKeyringLoader::LoadGnomeKeyring() { | |
45 if (keyring_loaded) | |
46 return true; | |
47 | |
48 void* handle = dlopen("libgnome-keyring.so.0", RTLD_NOW | RTLD_GLOBAL); | |
49 if (!handle) { | |
50 // We wanted to use GNOME Keyring, but we couldn't load it. Warn, because | |
51 // either the user asked for this, or we autodetected it incorrectly. (Or | |
52 // the system has broken libraries, which is also good to warn about.) | |
53 LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror(); | |
54 return false; | |
55 } | |
56 | |
57 for (size_t i = 0; functions[i].name; ++i) { | |
58 dlerror(); | |
59 *functions[i].pointer = dlsym(handle, functions[i].name); | |
60 const char* error = dlerror(); | |
61 if (error) { | |
62 LOG(ERROR) << "Unable to load symbol " | |
63 << functions[i].name << ": " << error; | |
64 dlclose(handle); | |
65 return false; | |
66 } | |
67 } | |
68 | |
69 keyring_loaded = true; | |
70 // We leak the library handle. That's OK: this function is called only once. | |
71 return true; | |
72 } | |
73 | |
74 #else // defined(DLOPEN_GNOME_KEYRING) | |
75 | |
76 bool GnomeKeyringLoader::LoadGnomeKeyring() { | |
77 if (keyring_loaded) | |
78 return true; | |
79 #define GNOME_KEYRING_ASSIGN_POINTER(name) \ | |
80 gnome_keyring_##name = &::gnome_keyring_##name; | |
81 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_ASSIGN_POINTER) | |
82 #undef GNOME_KEYRING_ASSIGN_POINTER | |
83 keyring_loaded = true; | |
84 return true; | |
85 } | |
86 | |
87 #endif // defined(DLOPEN_GNOME_KEYRING) | |
88 | |
89 namespace { | |
90 | |
91 const char kGnomeKeyringAppString[] = "chrome"; | |
92 | |
93 // Convert the attributes of a given keyring entry into a new PasswordForm. | |
94 // Note: does *not* get the actual password, as that is not a key attribute! | |
95 // Returns NULL if the attributes are for the wrong application. | |
96 PasswordForm* FormFromAttributes(GnomeKeyringAttributeList* attrs) { | |
97 // Read the string and int attributes into the appropriate map. | |
98 std::map<std::string, std::string> string_attr_map; | |
99 std::map<std::string, uint32_t> uint_attr_map; | |
100 for (guint i = 0; i < attrs->len; ++i) { | |
101 GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i); | |
102 if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) | |
103 string_attr_map[attr.name] = attr.value.string; | |
104 else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) | |
105 uint_attr_map[attr.name] = attr.value.integer; | |
106 } | |
107 // Check to make sure this is a password we care about. | |
108 const std::string& app_value = string_attr_map["application"]; | |
109 if (!base::StringPiece(app_value).starts_with(kGnomeKeyringAppString)) | |
110 return NULL; | |
111 | |
112 PasswordForm* form = new PasswordForm(); | |
113 form->origin = GURL(string_attr_map["origin_url"]); | |
114 form->action = GURL(string_attr_map["action_url"]); | |
115 form->username_element = UTF8ToUTF16(string_attr_map["username_element"]); | |
116 form->username_value = UTF8ToUTF16(string_attr_map["username_value"]); | |
117 form->password_element = UTF8ToUTF16(string_attr_map["password_element"]); | |
118 form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]); | |
119 form->signon_realm = string_attr_map["signon_realm"]; | |
120 form->ssl_valid = uint_attr_map["ssl_valid"]; | |
121 form->preferred = uint_attr_map["preferred"]; | |
122 int64 date_created = 0; | |
123 bool date_ok = base::StringToInt64(string_attr_map["date_created"], | |
124 &date_created); | |
125 DCHECK(date_ok); | |
126 form->date_created = base::Time::FromTimeT(date_created); | |
127 form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"]; | |
128 form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]); | |
129 | |
130 return form; | |
131 } | |
132 | |
133 // Parse all the results from the given GList into a PasswordFormList, and free | |
134 // the GList. PasswordForms are allocated on the heap, and should be deleted by | |
135 // the consumer. | |
136 void ConvertFormList(GList* found, | |
137 NativeBackendGnome::PasswordFormList* forms) { | |
138 GList* element = g_list_first(found); | |
139 while (element != NULL) { | |
140 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); | |
141 GnomeKeyringAttributeList* attrs = data->attributes; | |
142 | |
143 PasswordForm* form = FormFromAttributes(attrs); | |
144 if (form) { | |
145 if (data->secret) { | |
146 form->password_value = UTF8ToUTF16(data->secret); | |
147 } else { | |
148 LOG(WARNING) << "Unable to access password from list element!"; | |
149 } | |
150 forms->push_back(form); | |
151 } else { | |
152 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; | |
153 } | |
154 | |
155 element = g_list_next(element); | |
156 } | |
157 } | |
158 | |
159 // Schema is analagous to the fields in PasswordForm. | |
160 const GnomeKeyringPasswordSchema kGnomeSchema = { | |
161 GNOME_KEYRING_ITEM_GENERIC_SECRET, { | |
162 { "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
163 { "action_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
164 { "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
165 { "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
166 { "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
167 { "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
168 { "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
169 { "ssl_valid", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | |
170 { "preferred", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | |
171 { "date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
172 { "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | |
173 { "scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 }, | |
174 // This field is always "chrome" so that we can search for it. | |
175 { "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, | |
176 { NULL } | |
177 } | |
178 }; | |
179 | 20 |
180 // Sadly, PasswordStore goes to great lengths to switch from the originally | 21 // Sadly, PasswordStore goes to great lengths to switch from the originally |
181 // calling thread to the DB thread, and to provide an asynchronous API to | 22 // calling thread to the DB thread, and to provide an asynchronous API to |
182 // callers while using a synchronous (virtual) API provided by subclasses like | 23 // callers while using a synchronous (virtual) API provided by subclasses like |
183 // PasswordStoreX -- but GNOME Keyring really wants to be on the GLib main | 24 // PasswordStoreX -- but GNOME Keyring really wants to be on the GLib main |
184 // thread, which is the UI thread to us. So we end up having to switch threads | 25 // thread, which is the UI thread to us. We used to send a message to the UI |
185 // again, possibly back to the very same thread (in case the UI thread is the | 26 // thread and then wait for it, but that could cause deadlocks with password |
186 // caller, e.g. in the password management UI), and *block* the DB thread | 27 // sync which blocks the UI thread (!) for some operations. To avoid this, we |
187 // waiting for a response from the UI thread to provide the synchronous API | 28 // start a small proxy process with its own GLib main thread and talk to that. |
188 // PasswordStore expects of us. (It will then in turn switch back to the | 29 // We end up having to use the file thread for this, because the DB thread is |
189 // original caller to send the asynchronous reply to the original request.) | 30 // not a MessageLoopForIO and we need one of those to watch file descriptors. |
190 | |
191 // This class represents a call to a GNOME Keyring method. A RunnableMethod | |
192 // should be posted to the UI thread to call one of its action methods, and then | |
193 // a WaitResult() method should be called to wait for the result. Each instance | |
194 // supports only one outstanding method at a time, though multiple instances may | |
195 // be used in parallel. | |
196 class GKRMethod : public GnomeKeyringLoader { | |
197 public: | |
198 typedef NativeBackendGnome::PasswordFormList PasswordFormList; | |
199 | |
200 GKRMethod() : event_(false, false), result_(GNOME_KEYRING_RESULT_CANCELLED) {} | |
201 | |
202 // Action methods. These call gnome_keyring_* functions. Call from UI thread. | |
203 // See GetProfileSpecificAppString() for more information on the app string. | |
204 void AddLogin(const PasswordForm& form, const char* app_string); | |
205 void AddLoginSearch(const PasswordForm& form, const char* app_string); | |
206 void UpdateLoginSearch(const PasswordForm& form, const char* app_string); | |
207 void RemoveLogin(const PasswordForm& form, const char* app_string); | |
208 void GetLogins(const PasswordForm& form, const char* app_string); | |
209 void GetLoginsList(uint32_t blacklisted_by_user, const char* app_string); | |
210 void GetAllLogins(const char* app_string); | |
211 | |
212 // Use after AddLogin, RemoveLogin. | |
213 GnomeKeyringResult WaitResult(); | |
214 | |
215 // Use after AddLoginSearch, UpdateLoginSearch, GetLogins, GetLoginsList, | |
216 // GetAllLogins. | |
217 GnomeKeyringResult WaitResult(PasswordFormList* forms); | |
218 | |
219 private: | |
220 // All these callbacks are called on UI thread. | |
221 static void OnOperationDone(GnomeKeyringResult result, gpointer data); | |
222 | |
223 static void OnOperationGetList(GnomeKeyringResult result, GList* list, | |
224 gpointer data); | |
225 | |
226 base::WaitableEvent event_; | |
227 GnomeKeyringResult result_; | |
228 NativeBackendGnome::PasswordFormList forms_; | |
229 }; | |
230 | |
231 void GKRMethod::AddLogin(const PasswordForm& form, const char* app_string) { | |
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
233 time_t date_created = form.date_created.ToTimeT(); | |
234 // If we are asked to save a password with 0 date, use the current time. | |
235 // We don't want to actually save passwords as though on January 1, 1970. | |
236 if (!date_created) | |
237 date_created = time(NULL); | |
238 gnome_keyring_store_password( | |
239 &kGnomeSchema, | |
240 NULL, // Default keyring. | |
241 form.origin.spec().c_str(), // Display name. | |
242 UTF16ToUTF8(form.password_value).c_str(), | |
243 OnOperationDone, | |
244 this, // data | |
245 NULL, // destroy_data | |
246 "origin_url", form.origin.spec().c_str(), | |
247 "action_url", form.action.spec().c_str(), | |
248 "username_element", UTF16ToUTF8(form.username_element).c_str(), | |
249 "username_value", UTF16ToUTF8(form.username_value).c_str(), | |
250 "password_element", UTF16ToUTF8(form.password_element).c_str(), | |
251 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), | |
252 "signon_realm", form.signon_realm.c_str(), | |
253 "ssl_valid", form.ssl_valid, | |
254 "preferred", form.preferred, | |
255 "date_created", base::Int64ToString(date_created).c_str(), | |
256 "blacklisted_by_user", form.blacklisted_by_user, | |
257 "scheme", form.scheme, | |
258 "application", app_string, | |
259 NULL); | |
260 } | |
261 | |
262 void GKRMethod::AddLoginSearch(const PasswordForm& form, | |
263 const char* app_string) { | |
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
265 // Search GNOME Keyring for matching passwords to update. | |
266 gnome_keyring_find_itemsv( | |
267 GNOME_KEYRING_ITEM_GENERIC_SECRET, | |
268 OnOperationGetList, | |
269 this, // data | |
270 NULL, // destroy_data | |
271 "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
272 form.origin.spec().c_str(), | |
273 "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
274 UTF16ToUTF8(form.username_element).c_str(), | |
275 "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
276 UTF16ToUTF8(form.username_value).c_str(), | |
277 "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
278 UTF16ToUTF8(form.password_element).c_str(), | |
279 "submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
280 UTF16ToUTF8(form.submit_element).c_str(), | |
281 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
282 form.signon_realm.c_str(), | |
283 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
284 app_string, | |
285 NULL); | |
286 } | |
287 | |
288 void GKRMethod::UpdateLoginSearch(const PasswordForm& form, | |
289 const char* app_string) { | |
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
291 // Search GNOME Keyring for matching passwords to update. | |
292 gnome_keyring_find_itemsv( | |
293 GNOME_KEYRING_ITEM_GENERIC_SECRET, | |
294 OnOperationGetList, | |
295 this, // data | |
296 NULL, // destroy_data | |
297 "origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
298 form.origin.spec().c_str(), | |
299 "username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
300 UTF16ToUTF8(form.username_element).c_str(), | |
301 "username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
302 UTF16ToUTF8(form.username_value).c_str(), | |
303 "password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
304 UTF16ToUTF8(form.password_element).c_str(), | |
305 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
306 form.signon_realm.c_str(), | |
307 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
308 app_string, | |
309 NULL); | |
310 } | |
311 | |
312 void GKRMethod::RemoveLogin(const PasswordForm& form, const char* app_string) { | |
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
314 // We find forms using the same fields as LoginDatabase::RemoveLogin(). | |
315 gnome_keyring_delete_password( | |
316 &kGnomeSchema, | |
317 OnOperationDone, | |
318 this, // data | |
319 NULL, // destroy_data | |
320 "origin_url", form.origin.spec().c_str(), | |
321 "action_url", form.action.spec().c_str(), | |
322 "username_element", UTF16ToUTF8(form.username_element).c_str(), | |
323 "username_value", UTF16ToUTF8(form.username_value).c_str(), | |
324 "password_element", UTF16ToUTF8(form.password_element).c_str(), | |
325 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), | |
326 "signon_realm", form.signon_realm.c_str(), | |
327 "application", app_string, | |
328 NULL); | |
329 } | |
330 | |
331 void GKRMethod::GetLogins(const PasswordForm& form, const char* app_string) { | |
332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
333 // Search GNOME Keyring for matching passwords. | |
334 gnome_keyring_find_itemsv( | |
335 GNOME_KEYRING_ITEM_GENERIC_SECRET, | |
336 OnOperationGetList, | |
337 this, // data | |
338 NULL, // destroy_data | |
339 "signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
340 form.signon_realm.c_str(), | |
341 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
342 app_string, | |
343 NULL); | |
344 } | |
345 | |
346 void GKRMethod::GetLoginsList(uint32_t blacklisted_by_user, | |
347 const char* app_string) { | |
348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
349 // Search GNOME Keyring for matching passwords. | |
350 gnome_keyring_find_itemsv( | |
351 GNOME_KEYRING_ITEM_GENERIC_SECRET, | |
352 OnOperationGetList, | |
353 this, // data | |
354 NULL, // destroy_data | |
355 "blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32, | |
356 blacklisted_by_user, | |
357 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
358 app_string, | |
359 NULL); | |
360 } | |
361 | |
362 void GKRMethod::GetAllLogins(const char* app_string) { | |
363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
364 // We need to search for something, otherwise we get no results - so | |
365 // we search for the fixed application string. | |
366 gnome_keyring_find_itemsv( | |
367 GNOME_KEYRING_ITEM_GENERIC_SECRET, | |
368 OnOperationGetList, | |
369 this, // data | |
370 NULL, // destroy_data | |
371 "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING, | |
372 app_string, | |
373 NULL); | |
374 } | |
375 | |
376 GnomeKeyringResult GKRMethod::WaitResult() { | |
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
378 event_.Wait(); | |
379 return result_; | |
380 } | |
381 | |
382 GnomeKeyringResult GKRMethod::WaitResult(PasswordFormList* forms) { | |
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
384 event_.Wait(); | |
385 if (forms->empty()) { | |
386 // Normal case. Avoid extra allocation by swapping. | |
387 forms->swap(forms_); | |
388 } else { | |
389 // Rare case. Append forms_ to *forms. | |
390 forms->insert(forms->end(), forms_.begin(), forms_.end()); | |
391 forms_.clear(); | |
392 } | |
393 return result_; | |
394 } | |
395 | |
396 // static | |
397 void GKRMethod::OnOperationDone(GnomeKeyringResult result, gpointer data) { | |
398 GKRMethod* method = static_cast<GKRMethod*>(data); | |
399 method->result_ = result; | |
400 method->event_.Signal(); | |
401 } | |
402 | |
403 // static | |
404 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, | |
405 gpointer data) { | |
406 GKRMethod* method = static_cast<GKRMethod*>(data); | |
407 method->result_ = result; | |
408 method->forms_.clear(); | |
409 // |list| will be freed after this callback returns, so convert it now. | |
410 ConvertFormList(list, &method->forms_); | |
411 method->event_.Signal(); | |
412 } | |
413 | |
414 } // namespace | |
415 | 31 |
416 NativeBackendGnome::NativeBackendGnome(LocalProfileId id, PrefService* prefs) | 32 NativeBackendGnome::NativeBackendGnome(LocalProfileId id, PrefService* prefs) |
417 : profile_id_(id), prefs_(prefs) { | 33 : profile_id_(id), prefs_(prefs) { |
418 if (PasswordStoreX::PasswordsUseLocalProfileId(prefs)) { | 34 if (PasswordStoreX::PasswordsUseLocalProfileId(prefs)) { |
419 app_string_ = GetProfileSpecificAppString(); | 35 app_string_ = GetProfileSpecificAppString(); |
420 // We already did the migration previously. Don't try again. | 36 // We already did the migration previously. Don't try again. |
421 migrate_tried_ = true; | 37 migrate_tried_ = true; |
422 } else { | 38 } else { |
423 app_string_ = kGnomeKeyringAppString; | 39 app_string_ = kGnomeKeyringAppString; |
424 migrate_tried_ = false; | 40 migrate_tried_ = false; |
425 } | 41 } |
426 } | 42 } |
427 | 43 |
428 NativeBackendGnome::~NativeBackendGnome() { | 44 NativeBackendGnome::~NativeBackendGnome() { |
429 } | 45 } |
430 | 46 |
431 bool NativeBackendGnome::Init() { | 47 bool NativeBackendGnome::Init() { |
432 return LoadGnomeKeyring() && gnome_keyring_is_available(); | 48 // We don't need to determine with absolute certainty that we can use GNOME |
49 // Keyring here. PasswordStoreX is conservative and will back off if the first | |
50 // attempt to use it fails. Since that will conveniently occur on the DB | |
51 // thread, where we need to finish initialization by watching the IPC file | |
52 // descriptor, we merely start the proxy here and claim success if that works. | |
53 DCHECK(!proxy_client_.get()); | |
54 scoped_ptr<ChromeKeyringProxyClient> client(new ChromeKeyringProxyClient); | |
vandebo (ex-Chrome)
2011/12/01 19:57:30
nit: a new scoped_ptr seems overkill. Could you j
| |
55 if (!client->Connect()) | |
56 return false; | |
57 proxy_client_.reset(client.release()); | |
58 return true; | |
59 } | |
60 | |
61 void NativeBackendGnome::InitForTesting(ChromeKeyringProxyClient* client) { | |
62 DCHECK(!proxy_client_.get()); | |
63 proxy_client_.reset(client); | |
433 } | 64 } |
434 | 65 |
435 bool NativeBackendGnome::RawAddLogin(const PasswordForm& form) { | 66 bool NativeBackendGnome::RawAddLogin(const PasswordForm& form) { |
436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
437 GKRMethod method; | 68 ChromeKeyringProxyClient::RequestContext context; |
438 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 69 proxy_client_->AddLogin(form, app_string_, &context); |
439 base::Bind(&GKRMethod::AddLogin, | 70 context.event.Wait(); |
440 base::Unretained(&method), | 71 if (context.result_code != GNOME_KEYRING_RESULT_OK) { |
441 form, app_string_.c_str())); | 72 LOG(ERROR) << "Keyring save failed: code " << context.result_code; |
442 GnomeKeyringResult result = method.WaitResult(); | |
443 if (result != GNOME_KEYRING_RESULT_OK) { | |
444 LOG(ERROR) << "Keyring save failed: " | |
445 << gnome_keyring_result_to_message(result); | |
446 return false; | 73 return false; |
447 } | 74 } |
448 // Successful write. Try migration if necessary. | 75 // Successful write. Try migration if necessary. |
449 if (!migrate_tried_) | 76 if (!migrate_tried_) |
450 MigrateToProfileSpecificLogins(); | 77 MigrateToProfileSpecificLogins(); |
451 return true; | 78 return true; |
452 } | 79 } |
453 | 80 |
454 bool NativeBackendGnome::AddLogin(const PasswordForm& form) { | 81 bool NativeBackendGnome::AddLogin(const PasswordForm& form) { |
455 // Based on LoginDatabase::AddLogin(), we search for an existing match based | 82 // Based on LoginDatabase::AddLogin(), we search for an existing match based |
456 // on origin_url, username_element, username_value, password_element, submit | 83 // on origin_url, username_element, username_value, password_element, submit |
457 // element, and signon_realm first, remove that, and then add the new entry. | 84 // element, and signon_realm first, remove that, and then add the new entry. |
458 // We'd add the new one first, and then delete the original, but then the | 85 // We'd add the new one first, and then delete the original, but then the |
459 // delete might actually delete the newly-added entry! | 86 // delete might actually delete the newly-added entry! |
460 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
461 GKRMethod method; | |
462 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
463 base::Bind(&GKRMethod::AddLoginSearch, | |
464 base::Unretained(&method), | |
465 form, app_string_.c_str())); | |
466 PasswordFormList forms; | 88 PasswordFormList forms; |
467 GnomeKeyringResult result = method.WaitResult(&forms); | 89 ChromeKeyringProxyClient::RequestContext context(&forms); |
468 if (result != GNOME_KEYRING_RESULT_OK && | 90 proxy_client_->AddLoginSearch(form, app_string_, &context); |
469 result != GNOME_KEYRING_RESULT_NO_MATCH) { | 91 context.event.Wait(); |
470 LOG(ERROR) << "Keyring find failed: " | 92 if (context.result_code != GNOME_KEYRING_RESULT_OK && |
471 << gnome_keyring_result_to_message(result); | 93 context.result_code != GNOME_KEYRING_RESULT_NO_MATCH) { |
94 LOG(ERROR) << "Keyring find failed: code " << context.result_code; | |
472 return false; | 95 return false; |
473 } | 96 } |
474 if (forms.size() > 0) { | 97 if (forms.size() > 0) { |
475 if (forms.size() > 1) { | 98 if (forms.size() > 1) { |
476 LOG(WARNING) << "Adding login when there are " << forms.size() | 99 LOG(WARNING) << "Adding login when there are " << forms.size() |
477 << " matching logins already! Will replace only the first."; | 100 << " matching logins already! Will replace only the first."; |
478 } | 101 } |
479 | 102 |
480 // We try migration before updating the existing logins, since otherwise | 103 // We try migration before updating the existing logins, since otherwise |
481 // we'd do it after making some but not all of the changes below. | 104 // we'd do it after making some but not all of the changes below. |
482 if (forms.size() > 0 && !migrate_tried_) | 105 if (forms.size() > 0 && !migrate_tried_) |
483 MigrateToProfileSpecificLogins(); | 106 MigrateToProfileSpecificLogins(); |
484 | 107 |
485 RemoveLogin(*forms[0]); | 108 RemoveLogin(*forms[0]); |
486 for (size_t i = 0; i < forms.size(); ++i) | 109 for (size_t i = 0; i < forms.size(); ++i) |
487 delete forms[i]; | 110 delete forms[i]; |
488 } | 111 } |
489 return RawAddLogin(form); | 112 return RawAddLogin(form); |
490 } | 113 } |
491 | 114 |
492 bool NativeBackendGnome::UpdateLogin(const PasswordForm& form) { | 115 bool NativeBackendGnome::UpdateLogin(const PasswordForm& form) { |
493 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by | 116 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by |
494 // origin_url, username_element, username_value, password_element, and | 117 // origin_url, username_element, username_value, password_element, and |
495 // signon_realm. We then compare the result to the updated form. If they | 118 // signon_realm. We then compare the result to the updated form. If they |
496 // differ in any of the action, password_value, ssl_valid, or preferred | 119 // differ in any of the action, password_value, ssl_valid, or preferred |
497 // fields, then we remove the original, and then add the new entry. We'd add | 120 // fields, then we remove the original, and then add the new entry. We'd add |
498 // the new one first, and then delete the original, but then the delete might | 121 // the new one first, and then delete the original, but then the delete might |
499 // actually delete the newly-added entry! | 122 // actually delete the newly-added entry! |
500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
501 GKRMethod method; | |
502 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
503 base::Bind(&GKRMethod::UpdateLoginSearch, | |
504 base::Unretained(&method), | |
505 form, app_string_.c_str())); | |
506 PasswordFormList forms; | 124 PasswordFormList forms; |
507 GnomeKeyringResult result = method.WaitResult(&forms); | 125 ChromeKeyringProxyClient::RequestContext context(&forms); |
508 if (result != GNOME_KEYRING_RESULT_OK) { | 126 proxy_client_->UpdateLoginSearch(form, app_string_, &context); |
509 LOG(ERROR) << "Keyring find failed: " | 127 context.event.Wait(); |
510 << gnome_keyring_result_to_message(result); | 128 if (context.result_code != GNOME_KEYRING_RESULT_OK) { |
129 LOG(ERROR) << "Keyring find failed: code " << context.result_code; | |
511 return false; | 130 return false; |
512 } | 131 } |
513 | 132 |
514 // We try migration before updating the existing logins, since otherwise | 133 // We try migration before updating the existing logins, since otherwise |
515 // we'd do it after making some but not all of the changes below. | 134 // we'd do it after making some but not all of the changes below. |
516 if (forms.size() > 0 && !migrate_tried_) | 135 if (forms.size() > 0 && !migrate_tried_) |
517 MigrateToProfileSpecificLogins(); | 136 MigrateToProfileSpecificLogins(); |
518 | 137 |
519 bool ok = true; | 138 bool ok = true; |
520 for (size_t i = 0; i < forms.size(); ++i) { | 139 for (size_t i = 0; i < forms.size(); ++i) { |
(...skipping 16 matching lines...) Expand all Loading... | |
537 if (!RawAddLogin(*forms[i])) | 156 if (!RawAddLogin(*forms[i])) |
538 ok = false; | 157 ok = false; |
539 } | 158 } |
540 delete forms[i]; | 159 delete forms[i]; |
541 } | 160 } |
542 return ok; | 161 return ok; |
543 } | 162 } |
544 | 163 |
545 bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) { | 164 bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) { |
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
547 GKRMethod method; | 166 ChromeKeyringProxyClient::RequestContext context; |
548 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 167 proxy_client_->RemoveLogin(form, app_string_, &context); |
549 base::Bind(&GKRMethod::RemoveLogin, | 168 context.event.Wait(); |
550 base::Unretained(&method), | 169 if (context.result_code != GNOME_KEYRING_RESULT_OK) { |
551 form, app_string_.c_str())); | |
552 GnomeKeyringResult result = method.WaitResult(); | |
553 if (result != GNOME_KEYRING_RESULT_OK) { | |
554 // Warning, not error, because this can sometimes happen due to the user | 170 // Warning, not error, because this can sometimes happen due to the user |
555 // racing with the daemon to delete the password a second time. | 171 // racing with the daemon to delete the password a second time. |
556 LOG(WARNING) << "Keyring delete failed: " | 172 LOG(WARNING) << "Keyring delete failed: code " << context.result_code; |
557 << gnome_keyring_result_to_message(result); | |
558 return false; | 173 return false; |
559 } | 174 } |
560 // Successful write. Try migration if necessary. Note that presumably if we've | 175 // Successful write. Try migration if necessary. Note that presumably if we've |
561 // been asked to delete a login, it's because we returned it previously; thus, | 176 // been asked to delete a login, it's because we returned it previously; thus, |
562 // this will probably never happen since we'd have already tried migration. | 177 // this will probably never happen since we'd have already tried migration. |
563 if (!migrate_tried_) | 178 if (!migrate_tried_) |
564 MigrateToProfileSpecificLogins(); | 179 MigrateToProfileSpecificLogins(); |
565 return true; | 180 return true; |
566 } | 181 } |
567 | 182 |
(...skipping 16 matching lines...) Expand all Loading... | |
584 ok = false; | 199 ok = false; |
585 } | 200 } |
586 delete forms[i]; | 201 delete forms[i]; |
587 } | 202 } |
588 return ok; | 203 return ok; |
589 } | 204 } |
590 | 205 |
591 bool NativeBackendGnome::GetLogins(const PasswordForm& form, | 206 bool NativeBackendGnome::GetLogins(const PasswordForm& form, |
592 PasswordFormList* forms) { | 207 PasswordFormList* forms) { |
593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
594 GKRMethod method; | 209 ChromeKeyringProxyClient::RequestContext context(forms); |
595 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 210 proxy_client_->GetLogins(form, app_string_, &context); |
596 base::Bind(&GKRMethod::GetLogins, | 211 context.event.Wait(); |
597 base::Unretained(&method), | 212 if (context.result_code == GNOME_KEYRING_RESULT_NO_MATCH) |
598 form, app_string_.c_str())); | |
599 GnomeKeyringResult result = method.WaitResult(forms); | |
600 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | |
601 return true; | 213 return true; |
602 if (result != GNOME_KEYRING_RESULT_OK) { | 214 if (context.result_code != GNOME_KEYRING_RESULT_OK) { |
603 LOG(ERROR) << "Keyring find failed: " | 215 LOG(ERROR) << "Keyring find failed: code " << context.result_code; |
604 << gnome_keyring_result_to_message(result); | |
605 return false; | 216 return false; |
606 } | 217 } |
607 // Successful read of actual data. Try migration if necessary. | 218 // Successful read of actual data. Try migration if necessary. |
608 if (!migrate_tried_) | 219 if (!migrate_tried_) |
609 MigrateToProfileSpecificLogins(); | 220 MigrateToProfileSpecificLogins(); |
610 return true; | 221 return true; |
611 } | 222 } |
612 | 223 |
613 bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin, | 224 bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin, |
614 const base::Time& get_end, | 225 const base::Time& get_end, |
(...skipping 26 matching lines...) Expand all Loading... | |
641 bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) { | 252 bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) { |
642 return GetLoginsList(forms, false); | 253 return GetLoginsList(forms, false); |
643 } | 254 } |
644 | 255 |
645 bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms, | 256 bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms, |
646 bool autofillable) { | 257 bool autofillable) { |
647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
648 | 259 |
649 uint32_t blacklisted_by_user = !autofillable; | 260 uint32_t blacklisted_by_user = !autofillable; |
650 | 261 |
651 GKRMethod method; | 262 ChromeKeyringProxyClient::RequestContext context(forms); |
652 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 263 proxy_client_->GetLoginsList(blacklisted_by_user, app_string_, &context); |
653 base::Bind(&GKRMethod::GetLoginsList, | 264 context.event.Wait(); |
654 base::Unretained(&method), | 265 if (context.result_code == GNOME_KEYRING_RESULT_NO_MATCH) |
655 blacklisted_by_user, app_string_.c_str())); | |
656 GnomeKeyringResult result = method.WaitResult(forms); | |
657 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | |
658 return true; | 266 return true; |
659 if (result != GNOME_KEYRING_RESULT_OK) { | 267 if (context.result_code != GNOME_KEYRING_RESULT_OK) { |
660 LOG(ERROR) << "Keyring find failed: " | 268 LOG(ERROR) << "Keyring find failed: code " << context.result_code; |
661 << gnome_keyring_result_to_message(result); | |
662 return false; | 269 return false; |
663 } | 270 } |
664 // Successful read of actual data. Try migration if necessary. | 271 // Successful read of actual data. Try migration if necessary. |
665 if (!migrate_tried_) | 272 if (!migrate_tried_) |
666 MigrateToProfileSpecificLogins(); | 273 MigrateToProfileSpecificLogins(); |
667 return true; | 274 return true; |
668 } | 275 } |
669 | 276 |
670 bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) { | 277 bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) { |
671 GKRMethod method; | 278 ChromeKeyringProxyClient::RequestContext context(forms); |
672 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 279 proxy_client_->GetAllLogins(app_string_, &context); |
673 base::Bind(&GKRMethod::GetAllLogins, | 280 context.event.Wait(); |
674 base::Unretained(&method), | 281 if (context.result_code == GNOME_KEYRING_RESULT_NO_MATCH) |
675 app_string_.c_str())); | |
676 GnomeKeyringResult result = method.WaitResult(forms); | |
677 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | |
678 return true; | 282 return true; |
679 if (result != GNOME_KEYRING_RESULT_OK) { | 283 if (context.result_code != GNOME_KEYRING_RESULT_OK) { |
680 LOG(ERROR) << "Keyring find failed: " | 284 LOG(ERROR) << "Keyring find failed: code " << context.result_code; |
681 << gnome_keyring_result_to_message(result); | |
682 return false; | 285 return false; |
683 } | 286 } |
684 // Successful read of actual data. Try migration if necessary. | 287 // Successful read of actual data. Try migration if necessary. |
685 if (!migrate_tried_) | 288 if (!migrate_tried_) |
686 MigrateToProfileSpecificLogins(); | 289 MigrateToProfileSpecificLogins(); |
687 return true; | 290 return true; |
688 } | 291 } |
689 | 292 |
690 std::string NativeBackendGnome::GetProfileSpecificAppString() const { | 293 std::string NativeBackendGnome::GetProfileSpecificAppString() const { |
691 // Originally, the application string was always just "chrome" and used only | 294 // Originally, the application string was always just "chrome" and used only |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
727 // Each other profile must be able to migrate the shared data as well, | 330 // Each other profile must be able to migrate the shared data as well, |
728 // so we must leave it alone. After a few releases, we'll add code to | 331 // so we must leave it alone. After a few releases, we'll add code to |
729 // delete them, and eventually remove this migration code. | 332 // delete them, and eventually remove this migration code. |
730 // TODO(mdm): follow through with the plan above. | 333 // TODO(mdm): follow through with the plan above. |
731 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_); | 334 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_); |
732 } else { | 335 } else { |
733 // We failed to migrate for some reason. Use the old app string. | 336 // We failed to migrate for some reason. Use the old app string. |
734 app_string_ = kGnomeKeyringAppString; | 337 app_string_ = kGnomeKeyringAppString; |
735 } | 338 } |
736 } | 339 } |
OLD | NEW |