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

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: merge Created 8 years, 11 months 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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::forms::PasswordForm; 19 using webkit::forms::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 // TODO(mdm): after a few more releases, remove the code which is now dead due 36 // TODO(mdm): after a few more releases, remove the code which is now dead due
420 // to the true || here, and simplify this code. We don't do it yet to make it 37 // to the true || here, and simplify this code. We don't do it yet to make it
421 // easier to revert if necessary. 38 // easier to revert if necessary.
422 if (true || PasswordStoreX::PasswordsUseLocalProfileId(prefs)) { 39 if (true || PasswordStoreX::PasswordsUseLocalProfileId(prefs)) {
423 app_string_ = GetProfileSpecificAppString(); 40 app_string_ = GetProfileSpecificAppString();
424 // We already did the migration previously. Don't try again. 41 // We already did the migration previously. Don't try again.
425 migrate_tried_ = true; 42 migrate_tried_ = true;
426 } else { 43 } else {
427 app_string_ = kGnomeKeyringAppString; 44 app_string_ = kGnomeKeyringAppString;
428 migrate_tried_ = false; 45 migrate_tried_ = false;
429 } 46 }
430 } 47 }
431 48
432 NativeBackendGnome::~NativeBackendGnome() { 49 NativeBackendGnome::~NativeBackendGnome() {
433 } 50 }
434 51
435 bool NativeBackendGnome::Init() { 52 bool NativeBackendGnome::Init() {
436 return LoadGnomeKeyring() && gnome_keyring_is_available(); 53 // We don't need to determine with absolute certainty that we can use GNOME
54 // Keyring here. PasswordStoreX is conservative and will back off if the first
55 // attempt to use it fails. Since that will conveniently occur on the DB
56 // thread, where we need to finish initialization by watching the IPC file
57 // descriptor, we merely start the proxy here and claim success if that works.
58 DCHECK(!proxy_client_.get());
59 scoped_ptr<KeyringProxyClient> client(new KeyringProxyClient);
60 if (!client->Connect())
61 return false;
62 proxy_client_.reset(client.release());
63 return true;
64 }
65
66 void NativeBackendGnome::InitForTesting(KeyringProxyClient* client) {
67 DCHECK(!proxy_client_.get());
68 proxy_client_.reset(client);
437 } 69 }
438 70
439 bool NativeBackendGnome::RawAddLogin(const PasswordForm& form) { 71 bool NativeBackendGnome::RawAddLogin(const PasswordForm& form) {
440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
441 GKRMethod method; 73 KeyringProxyClient::RequestContext context;
442 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 74 proxy_client_->AddLogin(form, app_string_, &context);
443 base::Bind(&GKRMethod::AddLogin, 75 context.event.Wait();
444 base::Unretained(&method), 76 if (context.result_code != GNOME_KEYRING_RESULT_OK) {
445 form, app_string_.c_str())); 77 LOG(ERROR) << "Keyring save failed: code " << context.result_code;
446 GnomeKeyringResult result = method.WaitResult();
447 if (result != GNOME_KEYRING_RESULT_OK) {
448 LOG(ERROR) << "Keyring save failed: "
449 << gnome_keyring_result_to_message(result);
450 return false; 78 return false;
451 } 79 }
452 // Successful write. Try migration if necessary. 80 // Successful write. Try migration if necessary.
453 if (!migrate_tried_) 81 if (!migrate_tried_)
454 MigrateToProfileSpecificLogins(); 82 MigrateToProfileSpecificLogins();
455 return true; 83 return true;
456 } 84 }
457 85
458 bool NativeBackendGnome::AddLogin(const PasswordForm& form) { 86 bool NativeBackendGnome::AddLogin(const PasswordForm& form) {
459 // Based on LoginDatabase::AddLogin(), we search for an existing match based 87 // Based on LoginDatabase::AddLogin(), we search for an existing match based
460 // on origin_url, username_element, username_value, password_element, submit 88 // on origin_url, username_element, username_value, password_element, submit
461 // element, and signon_realm first, remove that, and then add the new entry. 89 // element, and signon_realm first, remove that, and then add the new entry.
462 // We'd add the new one first, and then delete the original, but then the 90 // We'd add the new one first, and then delete the original, but then the
463 // delete might actually delete the newly-added entry! 91 // delete might actually delete the newly-added entry!
464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
465 GKRMethod method;
466 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
467 base::Bind(&GKRMethod::AddLoginSearch,
468 base::Unretained(&method),
469 form, app_string_.c_str()));
470 PasswordFormList forms; 93 PasswordFormList forms;
471 GnomeKeyringResult result = method.WaitResult(&forms); 94 KeyringProxyClient::RequestContext context(&forms);
472 if (result != GNOME_KEYRING_RESULT_OK && 95 proxy_client_->AddLoginSearch(form, app_string_, &context);
473 result != GNOME_KEYRING_RESULT_NO_MATCH) { 96 context.event.Wait();
474 LOG(ERROR) << "Keyring find failed: " 97 if (context.result_code != GNOME_KEYRING_RESULT_OK &&
475 << gnome_keyring_result_to_message(result); 98 context.result_code != GNOME_KEYRING_RESULT_NO_MATCH) {
99 LOG(ERROR) << "Keyring find failed: code " << context.result_code;
476 return false; 100 return false;
477 } 101 }
478 if (forms.size() > 0) { 102 if (forms.size() > 0) {
479 if (forms.size() > 1) { 103 if (forms.size() > 1) {
480 LOG(WARNING) << "Adding login when there are " << forms.size() 104 LOG(WARNING) << "Adding login when there are " << forms.size()
481 << " matching logins already! Will replace only the first."; 105 << " matching logins already! Will replace only the first.";
482 } 106 }
483 107
484 // We try migration before updating the existing logins, since otherwise 108 // We try migration before updating the existing logins, since otherwise
485 // we'd do it after making some but not all of the changes below. 109 // we'd do it after making some but not all of the changes below.
486 if (forms.size() > 0 && !migrate_tried_) 110 if (forms.size() > 0 && !migrate_tried_)
487 MigrateToProfileSpecificLogins(); 111 MigrateToProfileSpecificLogins();
488 112
489 RemoveLogin(*forms[0]); 113 RemoveLogin(*forms[0]);
490 for (size_t i = 0; i < forms.size(); ++i) 114 for (size_t i = 0; i < forms.size(); ++i)
491 delete forms[i]; 115 delete forms[i];
492 } 116 }
493 return RawAddLogin(form); 117 return RawAddLogin(form);
494 } 118 }
495 119
496 bool NativeBackendGnome::UpdateLogin(const PasswordForm& form) { 120 bool NativeBackendGnome::UpdateLogin(const PasswordForm& form) {
497 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by 121 // Based on LoginDatabase::UpdateLogin(), we search for forms to update by
498 // origin_url, username_element, username_value, password_element, and 122 // origin_url, username_element, username_value, password_element, and
499 // signon_realm. We then compare the result to the updated form. If they 123 // signon_realm. We then compare the result to the updated form. If they
500 // differ in any of the action, password_value, ssl_valid, or preferred 124 // differ in any of the action, password_value, ssl_valid, or preferred
501 // fields, then we remove the original, and then add the new entry. We'd add 125 // fields, then we remove the original, and then add the new entry. We'd add
502 // the new one first, and then delete the original, but then the delete might 126 // the new one first, and then delete the original, but then the delete might
503 // actually delete the newly-added entry! 127 // actually delete the newly-added entry!
504 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
505 GKRMethod method;
506 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
507 base::Bind(&GKRMethod::UpdateLoginSearch,
508 base::Unretained(&method),
509 form, app_string_.c_str()));
510 PasswordFormList forms; 129 PasswordFormList forms;
511 GnomeKeyringResult result = method.WaitResult(&forms); 130 KeyringProxyClient::RequestContext context(&forms);
512 if (result != GNOME_KEYRING_RESULT_OK) { 131 proxy_client_->UpdateLoginSearch(form, app_string_, &context);
513 LOG(ERROR) << "Keyring find failed: " 132 context.event.Wait();
514 << gnome_keyring_result_to_message(result); 133 if (context.result_code != GNOME_KEYRING_RESULT_OK) {
134 LOG(ERROR) << "Keyring find failed: code " << context.result_code;
515 return false; 135 return false;
516 } 136 }
517 137
518 // We try migration before updating the existing logins, since otherwise 138 // We try migration before updating the existing logins, since otherwise
519 // we'd do it after making some but not all of the changes below. 139 // we'd do it after making some but not all of the changes below.
520 if (forms.size() > 0 && !migrate_tried_) 140 if (forms.size() > 0 && !migrate_tried_)
521 MigrateToProfileSpecificLogins(); 141 MigrateToProfileSpecificLogins();
522 142
523 bool ok = true; 143 bool ok = true;
524 for (size_t i = 0; i < forms.size(); ++i) { 144 for (size_t i = 0; i < forms.size(); ++i) {
(...skipping 16 matching lines...) Expand all
541 if (!RawAddLogin(*forms[i])) 161 if (!RawAddLogin(*forms[i]))
542 ok = false; 162 ok = false;
543 } 163 }
544 delete forms[i]; 164 delete forms[i];
545 } 165 }
546 return ok; 166 return ok;
547 } 167 }
548 168
549 bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) { 169 bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) {
550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
551 GKRMethod method; 171 KeyringProxyClient::RequestContext context;
552 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 172 proxy_client_->RemoveLogin(form, app_string_, &context);
553 base::Bind(&GKRMethod::RemoveLogin, 173 context.event.Wait();
554 base::Unretained(&method), 174 if (context.result_code != GNOME_KEYRING_RESULT_OK) {
555 form, app_string_.c_str()));
556 GnomeKeyringResult result = method.WaitResult();
557 if (result != GNOME_KEYRING_RESULT_OK) {
558 // Warning, not error, because this can sometimes happen due to the user 175 // Warning, not error, because this can sometimes happen due to the user
559 // racing with the daemon to delete the password a second time. 176 // racing with the daemon to delete the password a second time.
560 LOG(WARNING) << "Keyring delete failed: " 177 LOG(WARNING) << "Keyring delete failed: code " << context.result_code;
561 << gnome_keyring_result_to_message(result);
562 return false; 178 return false;
563 } 179 }
564 // Successful write. Try migration if necessary. Note that presumably if we've 180 // Successful write. Try migration if necessary. Note that presumably if we've
565 // been asked to delete a login, it's because we returned it previously; thus, 181 // been asked to delete a login, it's because we returned it previously; thus,
566 // this will probably never happen since we'd have already tried migration. 182 // this will probably never happen since we'd have already tried migration.
567 if (!migrate_tried_) 183 if (!migrate_tried_)
568 MigrateToProfileSpecificLogins(); 184 MigrateToProfileSpecificLogins();
569 return true; 185 return true;
570 } 186 }
571 187
(...skipping 16 matching lines...) Expand all
588 ok = false; 204 ok = false;
589 } 205 }
590 delete forms[i]; 206 delete forms[i];
591 } 207 }
592 return ok; 208 return ok;
593 } 209 }
594 210
595 bool NativeBackendGnome::GetLogins(const PasswordForm& form, 211 bool NativeBackendGnome::GetLogins(const PasswordForm& form,
596 PasswordFormList* forms) { 212 PasswordFormList* forms) {
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
598 GKRMethod method; 214 KeyringProxyClient::RequestContext context(forms);
599 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 215 proxy_client_->GetLogins(form, app_string_, &context);
600 base::Bind(&GKRMethod::GetLogins, 216 context.event.Wait();
601 base::Unretained(&method), 217 if (context.result_code == GNOME_KEYRING_RESULT_NO_MATCH)
602 form, app_string_.c_str()));
603 GnomeKeyringResult result = method.WaitResult(forms);
604 if (result == GNOME_KEYRING_RESULT_NO_MATCH)
605 return true; 218 return true;
606 if (result != GNOME_KEYRING_RESULT_OK) { 219 if (context.result_code != GNOME_KEYRING_RESULT_OK) {
607 LOG(ERROR) << "Keyring find failed: " 220 LOG(ERROR) << "Keyring find failed: code " << context.result_code;
608 << gnome_keyring_result_to_message(result);
609 return false; 221 return false;
610 } 222 }
611 // Successful read of actual data. Try migration if necessary. 223 // Successful read of actual data. Try migration if necessary.
612 if (!migrate_tried_) 224 if (!migrate_tried_)
613 MigrateToProfileSpecificLogins(); 225 MigrateToProfileSpecificLogins();
614 return true; 226 return true;
615 } 227 }
616 228
617 bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin, 229 bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin,
618 const base::Time& get_end, 230 const base::Time& get_end,
(...skipping 26 matching lines...) Expand all
645 bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) { 257 bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) {
646 return GetLoginsList(forms, false); 258 return GetLoginsList(forms, false);
647 } 259 }
648 260
649 bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms, 261 bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms,
650 bool autofillable) { 262 bool autofillable) {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
652 264
653 uint32_t blacklisted_by_user = !autofillable; 265 uint32_t blacklisted_by_user = !autofillable;
654 266
655 GKRMethod method; 267 KeyringProxyClient::RequestContext context(forms);
656 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 268 proxy_client_->GetLoginsList(blacklisted_by_user, app_string_, &context);
657 base::Bind(&GKRMethod::GetLoginsList, 269 context.event.Wait();
658 base::Unretained(&method), 270 if (context.result_code == GNOME_KEYRING_RESULT_NO_MATCH)
659 blacklisted_by_user, app_string_.c_str()));
660 GnomeKeyringResult result = method.WaitResult(forms);
661 if (result == GNOME_KEYRING_RESULT_NO_MATCH)
662 return true; 271 return true;
663 if (result != GNOME_KEYRING_RESULT_OK) { 272 if (context.result_code != GNOME_KEYRING_RESULT_OK) {
664 LOG(ERROR) << "Keyring find failed: " 273 LOG(ERROR) << "Keyring find failed: code " << context.result_code;
665 << gnome_keyring_result_to_message(result);
666 return false; 274 return false;
667 } 275 }
668 // Successful read of actual data. Try migration if necessary. 276 // Successful read of actual data. Try migration if necessary.
669 if (!migrate_tried_) 277 if (!migrate_tried_)
670 MigrateToProfileSpecificLogins(); 278 MigrateToProfileSpecificLogins();
671 return true; 279 return true;
672 } 280 }
673 281
674 bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) { 282 bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) {
675 GKRMethod method; 283 KeyringProxyClient::RequestContext context(forms);
676 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 284 proxy_client_->GetAllLogins(app_string_, &context);
677 base::Bind(&GKRMethod::GetAllLogins, 285 context.event.Wait();
678 base::Unretained(&method), 286 if (context.result_code == GNOME_KEYRING_RESULT_NO_MATCH)
679 app_string_.c_str()));
680 GnomeKeyringResult result = method.WaitResult(forms);
681 if (result == GNOME_KEYRING_RESULT_NO_MATCH)
682 return true; 287 return true;
683 if (result != GNOME_KEYRING_RESULT_OK) { 288 if (context.result_code != GNOME_KEYRING_RESULT_OK) {
684 LOG(ERROR) << "Keyring find failed: " 289 LOG(ERROR) << "Keyring find failed: code " << context.result_code;
685 << gnome_keyring_result_to_message(result);
686 return false; 290 return false;
687 } 291 }
688 // Successful read of actual data. Try migration if necessary. 292 // Successful read of actual data. Try migration if necessary.
689 if (!migrate_tried_) 293 if (!migrate_tried_)
690 MigrateToProfileSpecificLogins(); 294 MigrateToProfileSpecificLogins();
691 return true; 295 return true;
692 } 296 }
693 297
694 std::string NativeBackendGnome::GetProfileSpecificAppString() const { 298 std::string NativeBackendGnome::GetProfileSpecificAppString() const {
695 // Originally, the application string was always just "chrome" and used only 299 // Originally, the application string was always just "chrome" and used only
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 // Each other profile must be able to migrate the shared data as well, 335 // Each other profile must be able to migrate the shared data as well,
732 // so we must leave it alone. After a few releases, we'll add code to 336 // so we must leave it alone. After a few releases, we'll add code to
733 // delete them, and eventually remove this migration code. 337 // delete them, and eventually remove this migration code.
734 // TODO(mdm): follow through with the plan above. 338 // TODO(mdm): follow through with the plan above.
735 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_); 339 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_);
736 } else { 340 } else {
737 // We failed to migrate for some reason. Use the old app string. 341 // We failed to migrate for some reason. Use the old app string.
738 app_string_ = kGnomeKeyringAppString; 342 app_string_ = kGnomeKeyringAppString;
739 } 343 }
740 } 344 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698