Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: chrome/browser/password_manager/native_backend_gnome_x.cc

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

Powered by Google App Engine
This is Rietveld 408576698