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

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: everything works 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/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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698