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

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

Issue 7835021: Linux: use our spiffy new DBus client library for KWallet, instead of dbus-glib. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 3 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) 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_kwallet_x.h" 5 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
6 6
7 #include <sstream> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/pickle.h" 10 #include "base/pickle.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/synchronization/waitable_event.h"
13 #include "content/browser/browser_thread.h" 14 #include "content/browser/browser_thread.h"
15 #include "dbus/bus.h"
16 #include "dbus/message.h"
17 #include "dbus/object_proxy.h"
14 #include "grit/chromium_strings.h" 18 #include "grit/chromium_strings.h"
15 #include "ui/base/l10n/l10n_util.h" 19 #include "ui/base/l10n/l10n_util.h"
16 20
17 using std::string;
18 using std::vector;
19 using webkit_glue::PasswordForm; 21 using webkit_glue::PasswordForm;
20 22
21 // We could localize this string, but then changing your locale would cause 23 // We could localize this string, but then changing your locale would cause
22 // you to lose access to all your stored passwords. Maybe best not to do that. 24 // you to lose access to all your stored passwords. Maybe best not to do that.
23 const char NativeBackendKWallet::kKWalletFolder[] = "Chrome Form Data"; 25 const char NativeBackendKWallet::kKWalletFolder[] = "Chrome Form Data";
24 26
25 const char NativeBackendKWallet::kKWalletServiceName[] = "org.kde.kwalletd"; 27 const char NativeBackendKWallet::kKWalletServiceName[] = "org.kde.kwalletd";
26 const char NativeBackendKWallet::kKWalletPath[] = "/modules/kwalletd"; 28 const char NativeBackendKWallet::kKWalletPath[] = "/modules/kwalletd";
27 const char NativeBackendKWallet::kKWalletInterface[] = "org.kde.KWallet"; 29 const char NativeBackendKWallet::kKWalletInterface[] = "org.kde.KWallet";
28 const char NativeBackendKWallet::kKLauncherServiceName[] = "org.kde.klauncher"; 30 const char NativeBackendKWallet::kKLauncherServiceName[] = "org.kde.klauncher";
29 const char NativeBackendKWallet::kKLauncherPath[] = "/KLauncher"; 31 const char NativeBackendKWallet::kKLauncherPath[] = "/KLauncher";
30 const char NativeBackendKWallet::kKLauncherInterface[] = "org.kde.KLauncher"; 32 const char NativeBackendKWallet::kKLauncherInterface[] = "org.kde.KLauncher";
31 33
32 NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id, 34 NativeBackendKWallet::NativeBackendKWallet(LocalProfileId id,
33 PrefService* prefs) 35 PrefService* prefs)
34 : profile_id_(id), prefs_(prefs), 36 : profile_id_(id), prefs_(prefs),
35 error_(NULL), connection_(NULL), proxy_(NULL),
36 app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) { 37 app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) {
37 if (PasswordStoreX::PasswordsUseLocalProfileId(prefs)) { 38 if (PasswordStoreX::PasswordsUseLocalProfileId(prefs)) {
38 folder_name_ = GetProfileSpecificFolderName(); 39 folder_name_ = GetProfileSpecificFolderName();
39 // We already did the migration previously. Don't try again. 40 // We already did the migration previously. Don't try again.
40 migrate_tried_ = true; 41 migrate_tried_ = true;
41 } else { 42 } else {
42 folder_name_ = kKWalletFolder; 43 folder_name_ = kKWalletFolder;
43 migrate_tried_ = false; 44 migrate_tried_ = false;
44 } 45 }
45 } 46 }
46 47
47 NativeBackendKWallet::~NativeBackendKWallet() { 48 NativeBackendKWallet::~NativeBackendKWallet() {
48 if (proxy_) 49 if (session_bus_)
49 g_object_unref(proxy_); 50 session_bus_->ShutdownAndBlock();
satorux1 2011/09/06 20:42:40 This would crash with DCHECK() if D-Bus thread is
Mike Mammarella 2011/09/07 01:01:27 Ah, one of the perils of code you have never actua
50 } 51 }
51 52
52 bool NativeBackendKWallet::Init() { 53 bool NativeBackendKWallet::Init() {
53 // Get a connection to the session bus. 54 // Get a connection to the session bus.
54 connection_ = dbus_g_bus_get(DBUS_BUS_SESSION, &error_); 55 dbus::Bus::Options options;
55 if (CheckError()) 56 options.bus_type = dbus::Bus::SESSION;
56 return false; 57 options.connection_type = dbus::Bus::PRIVATE;
58 options.dbus_thread_message_loop_proxy =
59 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB);
satorux1 2011/09/06 20:42:40 Why do we use the DB thread? Could you add a comme
Mike Mammarella 2011/09/07 01:01:27 Hmm. Now that I think about it more, I think I can
60 return InitWithBus(new dbus::Bus(options));
61 }
57 62
63 // NativeBackendKWallet isn't reference counted, but the one place we post a
64 // message to it (in InitWithBus below) waits for the task to run. So we can
65 // disable needing reference counting safely here.
66 template<>
67 struct RunnableMethodTraits<NativeBackendKWallet> {
68 void RetainCallee(NativeBackendKWallet*) {}
69 void ReleaseCallee(NativeBackendKWallet*) {}
70 };
71
72 bool NativeBackendKWallet::InitWithBus(dbus::Bus* bus) {
73 DCHECK(!session_bus_);
74 session_bus_ = bus;
75 kwallet_proxy_ = bus->GetObjectProxy(kKWalletServiceName, kKWalletPath);
76
77 // We must synchronously do a few DBus calls to figure out if initialization
78 // succeeds, but later, we'll want to do most work on the DB thread. So we
79 // have to do the initialization on the DB thread here too, and wait for it.
80 bool success = false;
81 base::WaitableEvent event(false, false);
82 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
83 NewRunnableMethod(
84 this, &NativeBackendKWallet::InitOnDBThread,
85 &event, &success));
86 event.Wait();
87 return success;
88 }
89
90 void NativeBackendKWallet::InitOnDBThread(base::WaitableEvent* event,
91 bool* success) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
58 if (!InitWallet()) { 93 if (!InitWallet()) {
59 // kwalletd may not be running. Try to start it and try again. 94 // kwalletd may not be running. Try to start it and try again.
60 if (!StartKWalletd() || !InitWallet()) 95 if (!StartKWalletd() || !InitWallet())
61 return false; 96 return; // *success starts out false
97 }
98 *success = true;
99 }
100
101 bool NativeBackendKWallet::StartKWalletd() {
102 // Sadly kwalletd doesn't use DBus activation, so we have to make a call to
103 // klauncher to start it.
104 dbus::ObjectProxy* klauncher =
105 session_bus_->GetObjectProxy(kKLauncherServiceName, kKLauncherPath);
106
107 dbus::MethodCall method_call(kKLauncherInterface,
108 "start_service_by_desktop_name");
109 dbus::MessageWriter builder(&method_call);
110 dbus::MessageWriter empty(&method_call);
111 builder.AppendString("kwalletd"); // serviceName
112 builder.OpenArray("s", &empty); // urls
113 builder.CloseContainer(&empty);
114 builder.OpenArray("s", &empty); // envs
115 builder.CloseContainer(&empty);
116 builder.AppendString(""); // startup_id
117 builder.AppendBool(false); // blind
118 scoped_ptr<dbus::Response> response(
119 klauncher->CallMethodAndBlock(
120 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
121 if (!response.get()) {
122 LOG(ERROR) << "Error contacting klauncher to start kwalletd";
123 return false;
124 }
125 dbus::MessageReader reader(response.get());
126 int32_t ret = -1;
127 std::string dbusName;
satorux1 2011/09/06 20:42:40 dbus_name
Mike Mammarella 2011/09/07 01:01:27 Done. Huh. I wonder where this came from. I'm pret
128 std::string error;
129 int32_t pid = -1;
130 if (!reader.PopInt32(&ret) || !reader.PopString(&dbusName) ||
131 !reader.PopString(&error) || !reader.PopInt32(&pid)) {
132 LOG(ERROR) << "Error reading response from klauncher to start kwalletd";
satorux1 2011/09/06 20:42:40 You could add << response->ToString(). It'll make
Mike Mammarella 2011/09/07 01:01:27 Done.
133 return false;
134 }
135 if (!error.empty()) {
136 LOG(ERROR) << "Error launching kwalletd: " << error;
137 return false;
138 }
139 if (ret) {
140 LOG(ERROR) << "Error launching kwalletd: " << ret;
141 return false;
62 } 142 }
satorux1 2011/09/06 20:42:40 Maybe you could merge the two conditionals, by usi
Mike Mammarella 2011/09/07 01:01:27 Done.
63 143
64 return true; 144 return true;
65 } 145 }
66 146
67 bool NativeBackendKWallet::StartKWalletd() { 147 bool NativeBackendKWallet::InitWallet() {
68 // Sadly kwalletd doesn't use DBUS activation, so we have to make a call to 148 {
69 // klauncher to start it. 149 // Check that KWallet is enabled.
70 DBusGProxy* klauncher_proxy = 150 dbus::MethodCall method_call(kKWalletInterface, "isEnabled");
71 dbus_g_proxy_new_for_name(connection_, kKLauncherServiceName, 151 scoped_ptr<dbus::Response> response(
72 kKLauncherPath, kKLauncherInterface); 152 kwallet_proxy_->CallMethodAndBlock(
73 153 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
74 char* empty_string_list = NULL; 154 if (!response.get()) {
75 int ret = 1; 155 LOG(ERROR) << "Error contacting kwalletd (isEnabled)";
76 char* error = NULL; 156 return false;
77 dbus_g_proxy_call(klauncher_proxy, "start_service_by_desktop_name", &error_, 157 }
78 G_TYPE_STRING, "kwalletd", // serviceName 158 dbus::MessageReader reader(response.get());
79 G_TYPE_STRV, &empty_string_list, // urls 159 bool enabled = false;
80 G_TYPE_STRV, &empty_string_list, // envs 160 if (!reader.PopBool(&enabled)) {
81 G_TYPE_STRING, "", // startup_id 161 LOG(ERROR) << "Error reading response from kwalletd (isEnabled)";
satorux1 2011/09/06 20:42:40 Likewise, I'd recommend including response->ToStri
Mike Mammarella 2011/09/07 01:01:27 Done.
82 G_TYPE_BOOLEAN, (gboolean) false, // blind 162 return false;
83 G_TYPE_INVALID, 163 }
84 G_TYPE_INT, &ret, // result 164 // Not enabled? Don't use KWallet. But also don't warn here.
85 G_TYPE_STRING, NULL, // dubsName 165 if (!enabled)
86 G_TYPE_STRING, &error, // error 166 return false;
87 G_TYPE_INT, NULL, // pid
88 G_TYPE_INVALID);
89
90 if (error && *error) {
91 LOG(ERROR) << "Error launching kwalletd: " << error;
92 ret = 1; // Make sure we return false after freeing.
93 } 167 }
94 168
95 g_free(error); 169 {
96 g_object_unref(klauncher_proxy); 170 // Get the wallet name.
97 171 dbus::MethodCall method_call(kKWalletInterface, "networkWallet");
98 if (CheckError() || ret != 0) 172 scoped_ptr<dbus::Response> response(
99 return false; 173 kwallet_proxy_->CallMethodAndBlock(
100 return true; 174 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
101 } 175 if (!response.get()) {
102 176 LOG(ERROR) << "Error contacting kwalletd (networkWallet)";
103 bool NativeBackendKWallet::InitWallet() { 177 return false;
104 // Make a proxy to KWallet. 178 }
105 proxy_ = dbus_g_proxy_new_for_name(connection_, kKWalletServiceName, 179 dbus::MessageReader reader(response.get());
106 kKWalletPath, kKWalletInterface); 180 if (!reader.PopString(&wallet_name_)) {
107 181 LOG(ERROR) << "Error reading response from kwalletd (networkWallet)";
108 // Check KWallet is enabled. 182 return false;
109 gboolean is_enabled = false; 183 }
110 dbus_g_proxy_call(proxy_, "isEnabled", &error_, 184 }
111 G_TYPE_INVALID,
112 G_TYPE_BOOLEAN, &is_enabled,
113 G_TYPE_INVALID);
114 if (CheckError() || !is_enabled)
115 return false;
116
117 // Get the wallet name.
118 char* wallet_name = NULL;
119 dbus_g_proxy_call(proxy_, "networkWallet", &error_,
120 G_TYPE_INVALID,
121 G_TYPE_STRING, &wallet_name,
122 G_TYPE_INVALID);
123 if (CheckError() || !wallet_name)
124 return false;
125
126 wallet_name_.assign(wallet_name);
127 g_free(wallet_name);
128 185
129 return true; 186 return true;
130 } 187 }
131 188
132 bool NativeBackendKWallet::AddLogin(const PasswordForm& form) { 189 bool NativeBackendKWallet::AddLogin(const PasswordForm& form) {
133 int wallet_handle = WalletHandle(); 190 int wallet_handle = WalletHandle();
134 if (wallet_handle == kInvalidKWalletHandle) 191 if (wallet_handle == kInvalidKWalletHandle)
135 return false; 192 return false;
136 193
137 PasswordFormList forms; 194 PasswordFormList forms;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 return ok; 258 return ok;
202 } 259 }
203 260
204 bool NativeBackendKWallet::RemoveLoginsCreatedBetween( 261 bool NativeBackendKWallet::RemoveLoginsCreatedBetween(
205 const base::Time& delete_begin, 262 const base::Time& delete_begin,
206 const base::Time& delete_end) { 263 const base::Time& delete_end) {
207 int wallet_handle = WalletHandle(); 264 int wallet_handle = WalletHandle();
208 if (wallet_handle == kInvalidKWalletHandle) 265 if (wallet_handle == kInvalidKWalletHandle)
209 return false; 266 return false;
210 267
211 // We could probably also use readEntryList here. 268 // We could probably also use readEntryList here.
satorux1 2011/09/06 20:42:40 What's readEntryList? Is this comment still valid?
Mike Mammarella 2011/09/07 01:01:27 It's another possible method call in the KWallet i
212 char** realm_list = NULL; 269 std::vector<std::string> realm_list;
213 dbus_g_proxy_call(proxy_, "entryList", &error_, 270 {
214 G_TYPE_INT, wallet_handle, // handle 271 dbus::MethodCall method_call(kKWalletInterface, "entryList");
215 G_TYPE_STRING, folder_name_.c_str(), // folder 272 dbus::MessageWriter builder(&method_call);
216 G_TYPE_STRING, app_name_.c_str(), // appid 273 builder.AppendInt32(wallet_handle); // handle
217 G_TYPE_INVALID, 274 builder.AppendString(folder_name_); // folder
218 G_TYPE_STRV, &realm_list, 275 builder.AppendString(app_name_); // appid
219 G_TYPE_INVALID); 276 scoped_ptr<dbus::Response> response(
220 if (CheckError()) 277 kwallet_proxy_->CallMethodAndBlock(
221 return false; 278 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
279 if (!response.get()) {
280 LOG(ERROR) << "Error contacting kwalletd (entryList)";
281 return false;
282 }
283 dbus::MessageReader reader(response.get());
284 dbus::MessageReader array(response.get());
285 if (!reader.PopArray(&array)) {
286 LOG(ERROR) << "Error reading response from kwalletd (entryList)";
287 return false;
288 }
289 while (array.HasMoreData()) {
290 std::string realm;
291 if (!array.PopString(&realm)) {
292 LOG(ERROR) << "Error reading response from kwalletd (entryList)";
293 return false;
294 }
295 realm_list.push_back(realm);
296 }
297 }
222 298
223 bool ok = true; 299 bool ok = true;
224 for (char** realm = realm_list; *realm; ++realm) { 300 for (size_t i = 0; i < realm_list.size(); ++i) {
225 GArray* byte_array = NULL; 301 const std::string& signon_realm = realm_list[i];
226 dbus_g_proxy_call(proxy_, "readEntry", &error_, 302 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
227 G_TYPE_INT, wallet_handle, // handle 303 dbus::MessageWriter builder(&method_call);
228 G_TYPE_STRING, folder_name_.c_str(), // folder 304 builder.AppendInt32(wallet_handle); // handle
229 G_TYPE_STRING, *realm, // key 305 builder.AppendString(folder_name_); // folder
230 G_TYPE_STRING, app_name_.c_str(), // appid 306 builder.AppendString(signon_realm); // key
231 G_TYPE_INVALID, 307 builder.AppendString(app_name_); // appid
232 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, 308 scoped_ptr<dbus::Response> response(
233 G_TYPE_INVALID); 309 kwallet_proxy_->CallMethodAndBlock(
234 310 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
235 if (CheckError() || !byte_array || 311 if (!response.get()) {
236 !CheckSerializedValue(byte_array, *realm)) { 312 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
237 continue; 313 continue;
238 } 314 }
315 dbus::MessageReader reader(response.get());
316 uint8_t* bytes = NULL;
317 size_t length = 0;
318 if (!reader.PopArrayOfBytes(&bytes, &length)) {
319 LOG(ERROR) << "Error reading response from kwalletd (readEntry)";
320 continue;
321 }
322 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
323 continue;
239 324
240 string signon_realm(*realm); 325 // Can't we all just agree on whether bytes are signed or not? Please?
241 Pickle pickle(byte_array->data, byte_array->len); 326 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
242 PasswordFormList all_forms; 327 PasswordFormList all_forms;
243 DeserializeValue(signon_realm, pickle, &all_forms); 328 DeserializeValue(signon_realm, pickle, &all_forms);
244 g_array_free(byte_array, true);
245 329
246 PasswordFormList kept_forms; 330 PasswordFormList kept_forms;
247 kept_forms.reserve(all_forms.size()); 331 kept_forms.reserve(all_forms.size());
248 for (size_t i = 0; i < all_forms.size(); ++i) { 332 for (size_t i = 0; i < all_forms.size(); ++i) {
249 if (delete_begin <= all_forms[i]->date_created && 333 if (delete_begin <= all_forms[i]->date_created &&
250 (delete_end.is_null() || all_forms[i]->date_created < delete_end)) { 334 (delete_end.is_null() || all_forms[i]->date_created < delete_end)) {
251 delete all_forms[i]; 335 delete all_forms[i];
252 } else { 336 } else {
253 kept_forms.push_back(all_forms[i]); 337 kept_forms.push_back(all_forms[i]);
254 } 338 }
255 } 339 }
256 340
257 if (!SetLoginsList(kept_forms, signon_realm, wallet_handle)) 341 if (!SetLoginsList(kept_forms, signon_realm, wallet_handle))
258 ok = false; 342 ok = false;
259 STLDeleteElements(&kept_forms); 343 STLDeleteElements(&kept_forms);
260 } 344 }
261 g_strfreev(realm_list);
262 return ok; 345 return ok;
263 } 346 }
264 347
265 bool NativeBackendKWallet::GetLogins(const PasswordForm& form, 348 bool NativeBackendKWallet::GetLogins(const PasswordForm& form,
266 PasswordFormList* forms) { 349 PasswordFormList* forms) {
267 int wallet_handle = WalletHandle(); 350 int wallet_handle = WalletHandle();
268 if (wallet_handle == kInvalidKWalletHandle) 351 if (wallet_handle == kInvalidKWalletHandle)
269 return false; 352 return false;
270 return GetLoginsList(forms, form.signon_realm, wallet_handle); 353 return GetLoginsList(forms, form.signon_realm, wallet_handle);
271 } 354 }
(...skipping 15 matching lines...) Expand all
287 } 370 }
288 371
289 bool NativeBackendKWallet::GetBlacklistLogins(PasswordFormList* forms) { 372 bool NativeBackendKWallet::GetBlacklistLogins(PasswordFormList* forms) {
290 int wallet_handle = WalletHandle(); 373 int wallet_handle = WalletHandle();
291 if (wallet_handle == kInvalidKWalletHandle) 374 if (wallet_handle == kInvalidKWalletHandle)
292 return false; 375 return false;
293 return GetLoginsList(forms, false, wallet_handle); 376 return GetLoginsList(forms, false, wallet_handle);
294 } 377 }
295 378
296 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms, 379 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms,
297 const string& signon_realm, 380 const std::string& signon_realm,
298 int wallet_handle) { 381 int wallet_handle) {
299 // Is there an entry in the wallet? 382 // Is there an entry in the wallet?
300 gboolean has_entry = false; 383 {
301 dbus_g_proxy_call(proxy_, "hasEntry", &error_, 384 dbus::MethodCall method_call(kKWalletInterface, "hasEntry");
302 G_TYPE_INT, wallet_handle, // handle 385 dbus::MessageWriter builder(&method_call);
303 G_TYPE_STRING, folder_name_.c_str(), // folder 386 builder.AppendInt32(wallet_handle); // handle
304 G_TYPE_STRING, signon_realm.c_str(), // key 387 builder.AppendString(folder_name_); // folder
305 G_TYPE_STRING, app_name_.c_str(), // appid 388 builder.AppendString(signon_realm); // key
306 G_TYPE_INVALID, 389 builder.AppendString(app_name_); // appid
307 G_TYPE_BOOLEAN, &has_entry, 390 scoped_ptr<dbus::Response> response(
308 G_TYPE_INVALID); 391 kwallet_proxy_->CallMethodAndBlock(
309 392 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
310 if (CheckError()) 393 if (!response.get()) {
311 return false; 394 LOG(ERROR) << "Error contacting kwalletd (hasEntry)";
312 if (!has_entry) { 395 return false;
313 // This is not an error. There just isn't a matching entry. 396 }
314 return true; 397 dbus::MessageReader reader(response.get());
398 bool has_entry = false;
399 if (!reader.PopBool(&has_entry)) {
400 LOG(ERROR) << "Error reading response from kwalletd (hasEntry)";
401 return false;
402 }
403 if (!has_entry) {
404 // This is not an error. There just isn't a matching entry.
405 return true;
406 }
315 } 407 }
316 408
317 GArray* byte_array = NULL; 409 {
318 dbus_g_proxy_call(proxy_, "readEntry", &error_, 410 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
319 G_TYPE_INT, wallet_handle, // handle 411 dbus::MessageWriter builder(&method_call);
320 G_TYPE_STRING, folder_name_.c_str(), // folder 412 builder.AppendInt32(wallet_handle); // handle
321 G_TYPE_STRING, signon_realm.c_str(), // key 413 builder.AppendString(folder_name_); // folder
322 G_TYPE_STRING, app_name_.c_str(), // appid 414 builder.AppendString(signon_realm); // key
323 G_TYPE_INVALID, 415 builder.AppendString(app_name_); // appid
324 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, 416 scoped_ptr<dbus::Response> response(
325 G_TYPE_INVALID); 417 kwallet_proxy_->CallMethodAndBlock(
418 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
419 if (!response.get()) {
420 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
421 return false;
422 }
423 dbus::MessageReader reader(response.get());
424 uint8_t* bytes = NULL;
425 size_t length = 0;
426 if (!reader.PopArrayOfBytes(&bytes, &length)) {
427 LOG(ERROR) << "Error reading response from kwalletd (readEntry)";
428 return false;
429 }
430 if (!bytes)
431 return false;
432 if (!CheckSerializedValue(bytes, length, signon_realm)) {
433 // This is weird, but we choose not to call it an error. There is an
434 // invalid entry somehow, but by just ignoring it, we make it easier to
435 // repair without having to delete it using kwalletmanager (that is, by
436 // just saving a new password within this realm to overwrite it).
437 return true;
438 }
326 439
327 if (CheckError() || !byte_array) 440 // Can't we all just agree on whether bytes are signed or not? Please?
328 return false; 441 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
329 if (!CheckSerializedValue(byte_array, signon_realm.c_str())) { 442 PasswordFormList all_forms;
330 // This is weird, but we choose not to call it an error. There's an invalid 443 DeserializeValue(signon_realm, pickle, forms);
331 // entry somehow, but by pretending it just doesn't exist, we make it easier
332 // to repair without having to delete it using kwalletmanager (that is, by
333 // just saving a new password within this realm to overwrite it).
334 g_array_free(byte_array, true);
335 return true;
336 } 444 }
337 445
338 Pickle pickle(byte_array->data, byte_array->len);
339 DeserializeValue(signon_realm, pickle, forms);
340 g_array_free(byte_array, true);
341
342 return true; 446 return true;
343 } 447 }
344 448
345 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms, 449 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms,
346 bool autofillable, 450 bool autofillable,
347 int wallet_handle) { 451 int wallet_handle) {
348 PasswordFormList all_forms; 452 PasswordFormList all_forms;
349 if (!GetAllLogins(&all_forms, wallet_handle)) 453 if (!GetAllLogins(&all_forms, wallet_handle))
350 return false; 454 return false;
351 455
(...skipping 27 matching lines...) Expand all
379 delete all_forms[i]; 483 delete all_forms[i];
380 } 484 }
381 } 485 }
382 486
383 return true; 487 return true;
384 } 488 }
385 489
386 bool NativeBackendKWallet::GetAllLogins(PasswordFormList* forms, 490 bool NativeBackendKWallet::GetAllLogins(PasswordFormList* forms,
387 int wallet_handle) { 491 int wallet_handle) {
388 // We could probably also use readEntryList here. 492 // We could probably also use readEntryList here.
389 char** realm_list = NULL; 493 std::vector<std::string> realm_list;
390 dbus_g_proxy_call(proxy_, "entryList", &error_, 494 {
391 G_TYPE_INT, wallet_handle, // handle 495 dbus::MethodCall method_call(kKWalletInterface, "entryList");
392 G_TYPE_STRING, folder_name_.c_str(), // folder 496 dbus::MessageWriter builder(&method_call);
393 G_TYPE_STRING, app_name_.c_str(), // appid 497 builder.AppendInt32(wallet_handle); // handle
394 G_TYPE_INVALID, 498 builder.AppendString(folder_name_); // folder
395 G_TYPE_STRV, &realm_list, 499 builder.AppendString(app_name_); // appid
396 G_TYPE_INVALID); 500 scoped_ptr<dbus::Response> response(
397 if (CheckError()) 501 kwallet_proxy_->CallMethodAndBlock(
398 return false; 502 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
503 if (!response.get()) {
504 LOG(ERROR) << "Error contacting kwalletd (entryList)";
505 return false;
506 }
507 dbus::MessageReader reader(response.get());
508 dbus::MessageReader array(response.get());
509 if (!reader.PopArray(&array)) {
510 LOG(ERROR) << "Error reading response from kwalletd (entryList)";
511 return false;
512 }
513 while (array.HasMoreData()) {
514 std::string realm;
515 if (!array.PopString(&realm)) {
516 LOG(ERROR) << "Error reading response from kwalletd (entryList)";
517 return false;
518 }
519 realm_list.push_back(realm);
520 }
521 }
399 522
400 for (char** realm = realm_list; *realm; ++realm) { 523 for (size_t i = 0; i < realm_list.size(); ++i) {
401 GArray* byte_array = NULL; 524 const std::string& signon_realm = realm_list[i];
402 dbus_g_proxy_call(proxy_, "readEntry", &error_, 525 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
403 G_TYPE_INT, wallet_handle, // handle 526 dbus::MessageWriter builder(&method_call);
404 G_TYPE_STRING, folder_name_.c_str(), // folder 527 builder.AppendInt32(wallet_handle); // handle
405 G_TYPE_STRING, *realm, // key 528 builder.AppendString(folder_name_); // folder
406 G_TYPE_STRING, app_name_.c_str(), // appid 529 builder.AppendString(signon_realm); // key
407 G_TYPE_INVALID, 530 builder.AppendString(app_name_); // appid
408 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, 531 scoped_ptr<dbus::Response> response(
409 G_TYPE_INVALID); 532 kwallet_proxy_->CallMethodAndBlock(
410 533 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
411 if (CheckError() || !byte_array || 534 if (!response.get()) {
412 !CheckSerializedValue(byte_array, *realm)) { 535 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
413 continue; 536 continue;
414 } 537 }
538 dbus::MessageReader reader(response.get());
539 uint8_t* bytes = NULL;
540 size_t length = 0;
541 if (!reader.PopArrayOfBytes(&bytes, &length)) {
542 LOG(ERROR) << "Error reading response from kwalletd (readEntry)";
543 continue;
544 }
545 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
546 continue;
415 547
416 Pickle pickle(byte_array->data, byte_array->len); 548 // Can't we all just agree on whether bytes are signed or not? Please?
417 DeserializeValue(*realm, pickle, forms); 549 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
418 g_array_free(byte_array, true); 550 PasswordFormList all_forms;
551 DeserializeValue(signon_realm, pickle, forms);
419 } 552 }
420 g_strfreev(realm_list);
421 return true; 553 return true;
422 } 554 }
423 555
424 bool NativeBackendKWallet::SetLoginsList(const PasswordFormList& forms, 556 bool NativeBackendKWallet::SetLoginsList(const PasswordFormList& forms,
425 const string& signon_realm, 557 const std::string& signon_realm,
426 int wallet_handle) { 558 int wallet_handle) {
427 if (forms.empty()) { 559 if (forms.empty()) {
428 // No items left? Remove the entry from the wallet. 560 // No items left? Remove the entry from the wallet.
561 dbus::MethodCall method_call(kKWalletInterface, "removeEntry");
562 dbus::MessageWriter builder(&method_call);
563 builder.AppendInt32(wallet_handle); // handle
564 builder.AppendString(folder_name_); // folder
565 builder.AppendString(signon_realm); // key
566 builder.AppendString(app_name_); // appid
567 scoped_ptr<dbus::Response> response(
568 kwallet_proxy_->CallMethodAndBlock(
569 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
570 if (!response.get()) {
571 LOG(ERROR) << "Error contacting kwalletd (removeEntry)";
572 return kInvalidKWalletHandle;
573 }
574 dbus::MessageReader reader(response.get());
429 int ret = 0; 575 int ret = 0;
430 dbus_g_proxy_call(proxy_, "removeEntry", &error_, 576 if (!reader.PopInt32(&ret)) {
431 G_TYPE_INT, wallet_handle, // handle 577 LOG(ERROR) << "Error reading response from kwalletd (removeEntry)";
432 G_TYPE_STRING, folder_name_.c_str(), // folder
433 G_TYPE_STRING, signon_realm.c_str(), // key
434 G_TYPE_STRING, app_name_.c_str(), // appid
435 G_TYPE_INVALID,
436 G_TYPE_INT, &ret,
437 G_TYPE_INVALID);
438 if (CheckError())
439 return false; 578 return false;
579 }
440 if (ret != 0) 580 if (ret != 0)
441 LOG(ERROR) << "Bad return code " << ret << " from KWallet removeEntry"; 581 LOG(ERROR) << "Bad return code " << ret << " from KWallet removeEntry";
442 return ret == 0; 582 return ret == 0;
443 } 583 }
444 584
445 Pickle value; 585 Pickle value;
446 SerializeValue(forms, &value); 586 SerializeValue(forms, &value);
447 587
448 // Convert the pickled bytes to a GByteArray. 588 dbus::MethodCall method_call(kKWalletInterface, "writeEntry");
449 GArray* byte_array = g_array_sized_new(false, false, sizeof(char), 589 dbus::MessageWriter builder(&method_call);
450 value.size()); 590 builder.AppendInt32(wallet_handle); // handle
451 g_array_append_vals(byte_array, value.data(), value.size()); 591 builder.AppendString(folder_name_); // folder
452 592 builder.AppendString(signon_realm); // key
453 // Make the call. 593 builder.AppendArrayOfBytes(static_cast<const uint8_t*>(value.data()),
594 value.size()); // value
595 builder.AppendString(app_name_); // appid
596 scoped_ptr<dbus::Response> response(
597 kwallet_proxy_->CallMethodAndBlock(
598 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
599 if (!response.get()) {
600 LOG(ERROR) << "Error contacting kwalletd (writeEntry)";
601 return kInvalidKWalletHandle;
602 }
603 dbus::MessageReader reader(response.get());
454 int ret = 0; 604 int ret = 0;
455 dbus_g_proxy_call(proxy_, "writeEntry", &error_, 605 if (!reader.PopInt32(&ret)) {
456 G_TYPE_INT, wallet_handle, // handle 606 LOG(ERROR) << "Error reading response from kwalletd (writeEntry)";
457 G_TYPE_STRING, folder_name_.c_str(), // folder
458 G_TYPE_STRING, signon_realm.c_str(), // key
459 DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value
460 G_TYPE_STRING, app_name_.c_str(), // appid
461 G_TYPE_INVALID,
462 G_TYPE_INT, &ret,
463 G_TYPE_INVALID);
464 g_array_free(byte_array, true);
465
466 if (CheckError())
467 return false; 607 return false;
608 }
468 if (ret != 0) 609 if (ret != 0)
469 LOG(ERROR) << "Bad return code " << ret << " from KWallet writeEntry"; 610 LOG(ERROR) << "Bad return code " << ret << " from KWallet writeEntry";
470 return ret == 0; 611 return ret == 0;
471 } 612 }
472 613
473 bool NativeBackendKWallet::CompareForms(const PasswordForm& a, 614 bool NativeBackendKWallet::CompareForms(const PasswordForm& a,
474 const PasswordForm& b, 615 const PasswordForm& b,
475 bool update_check) { 616 bool update_check) {
476 // An update check doesn't care about the submit element. 617 // An update check doesn't care about the submit element.
477 if (!update_check && a.submit_element != b.submit_element) 618 if (!update_check && a.submit_element != b.submit_element)
(...skipping 20 matching lines...) Expand all
498 pickle->WriteString16(form->password_element); 639 pickle->WriteString16(form->password_element);
499 pickle->WriteString16(form->password_value); 640 pickle->WriteString16(form->password_value);
500 pickle->WriteString16(form->submit_element); 641 pickle->WriteString16(form->submit_element);
501 pickle->WriteBool(form->ssl_valid); 642 pickle->WriteBool(form->ssl_valid);
502 pickle->WriteBool(form->preferred); 643 pickle->WriteBool(form->preferred);
503 pickle->WriteBool(form->blacklisted_by_user); 644 pickle->WriteBool(form->blacklisted_by_user);
504 pickle->WriteInt64(form->date_created.ToTimeT()); 645 pickle->WriteInt64(form->date_created.ToTimeT());
505 } 646 }
506 } 647 }
507 648
508 bool NativeBackendKWallet::CheckSerializedValue(const GArray* byte_array, 649 bool NativeBackendKWallet::CheckSerializedValue(const uint8_t* byte_array,
509 const char* realm) { 650 size_t length,
651 const std::string& realm) {
510 const Pickle::Header* header = 652 const Pickle::Header* header =
511 reinterpret_cast<const Pickle::Header*>(byte_array->data); 653 reinterpret_cast<const Pickle::Header*>(byte_array);
512 if (byte_array->len < sizeof(*header) || 654 if (length < sizeof(*header) ||
513 header->payload_size > byte_array->len - sizeof(*header)) { 655 header->payload_size > length - sizeof(*header)) {
514 LOG(WARNING) << "Invalid KWallet entry detected (realm: " << realm << ")"; 656 LOG(WARNING) << "Invalid KWallet entry detected (realm: " << realm << ")";
515 return false; 657 return false;
516 } 658 }
517 return true; 659 return true;
518 } 660 }
519 661
520 void NativeBackendKWallet::DeserializeValue(const string& signon_realm, 662 void NativeBackendKWallet::DeserializeValue(const std::string& signon_realm,
521 const Pickle& pickle, 663 const Pickle& pickle,
522 PasswordFormList* forms) { 664 PasswordFormList* forms) {
523 void* iter = NULL; 665 void* iter = NULL;
524 666
525 int version = -1; 667 int version = -1;
526 if (!pickle.ReadInt(&iter, &version) || version != kPickleVersion) { 668 if (!pickle.ReadInt(&iter, &version) || version != kPickleVersion) {
527 // This is the only version so far, so anything else is an error. 669 // This is the only version so far, so anything else is an error.
528 LOG(ERROR) << "Failed to deserialize KWallet entry " 670 LOG(ERROR) << "Failed to deserialize KWallet entry "
529 << "(realm: " << signon_realm << ")"; 671 << "(realm: " << signon_realm << ")";
530 return; 672 return;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 break; 714 break;
573 } 715 }
574 form->scheme = static_cast<PasswordForm::Scheme>(scheme); 716 form->scheme = static_cast<PasswordForm::Scheme>(scheme);
575 form->date_created = base::Time::FromTimeT(date_created); 717 form->date_created = base::Time::FromTimeT(date_created);
576 forms->push_back(form.release()); 718 forms->push_back(form.release());
577 } 719 }
578 } 720 }
579 721
580 bool NativeBackendKWallet::ReadGURL(const Pickle& pickle, void** iter, 722 bool NativeBackendKWallet::ReadGURL(const Pickle& pickle, void** iter,
581 GURL* url) { 723 GURL* url) {
582 string url_string; 724 std::string url_string;
583 if (!pickle.ReadString(iter, &url_string)) { 725 if (!pickle.ReadString(iter, &url_string)) {
584 LOG(ERROR) << "Failed to deserialize URL"; 726 LOG(ERROR) << "Failed to deserialize URL";
585 *url = GURL(); 727 *url = GURL();
586 return false; 728 return false;
587 } 729 }
588 *url = GURL(url_string); 730 *url = GURL(url_string);
589 return true; 731 return true;
590 } 732 }
591 733
592 bool NativeBackendKWallet::CheckError() {
593 if (error_) {
594 LOG(ERROR) << "Failed to complete KWallet call: " << error_->message;
595 g_error_free(error_);
596 error_ = NULL;
597 return true;
598 }
599 return false;
600 }
601
602 int NativeBackendKWallet::WalletHandle() { 734 int NativeBackendKWallet::WalletHandle() {
603 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 735 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
736
604 // Open the wallet. 737 // Open the wallet.
605 // TODO(mdm): Are we leaking these handles? Find out. 738 // TODO(mdm): Are we leaking these handles? Find out.
606 int handle = kInvalidKWalletHandle; 739 int32_t handle = kInvalidKWalletHandle;
607 dbus_g_proxy_call(proxy_, "open", &error_, 740 {
608 G_TYPE_STRING, wallet_name_.c_str(), // wallet 741 dbus::MethodCall method_call(kKWalletInterface, "open");
609 G_TYPE_INT64, 0LL, // wid 742 dbus::MessageWriter builder(&method_call);
610 G_TYPE_STRING, app_name_.c_str(), // appid 743 builder.AppendString(wallet_name_); // wallet
611 G_TYPE_INVALID, 744 builder.AppendInt64(0); // wid
612 G_TYPE_INT, &handle, 745 builder.AppendString(app_name_); // appid
613 G_TYPE_INVALID); 746 scoped_ptr<dbus::Response> response(
614 if (CheckError() || handle == kInvalidKWalletHandle) 747 kwallet_proxy_->CallMethodAndBlock(
615 return kInvalidKWalletHandle; 748 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
749 if (!response.get()) {
750 LOG(ERROR) << "Error contacting kwalletd (open)";
751 return kInvalidKWalletHandle;
752 }
753 dbus::MessageReader reader(response.get());
754 if (!reader.PopInt32(&handle)) {
755 LOG(ERROR) << "Error reading response from kwalletd (open)";
756 return kInvalidKWalletHandle;
757 }
758 if (handle == kInvalidKWalletHandle) {
759 LOG(ERROR) << "Error obtaining KWallet handle";
760 return kInvalidKWalletHandle;
761 }
762 }
616 763
617 // Check if our folder exists. 764 // Check if our folder exists.
618 gboolean has_folder = false; 765 bool has_folder = false;
619 dbus_g_proxy_call(proxy_, "hasFolder", &error_, 766 {
620 G_TYPE_INT, handle, // handle 767 dbus::MethodCall method_call(kKWalletInterface, "hasFolder");
621 G_TYPE_STRING, folder_name_.c_str(), // folder 768 dbus::MessageWriter builder(&method_call);
622 G_TYPE_STRING, app_name_.c_str(), // appid 769 builder.AppendInt32(handle); // handle
623 G_TYPE_INVALID, 770 builder.AppendString(folder_name_); // folder
624 G_TYPE_BOOLEAN, &has_folder, 771 builder.AppendString(app_name_); // appid
625 G_TYPE_INVALID); 772 scoped_ptr<dbus::Response> response(
626 if (CheckError()) 773 kwallet_proxy_->CallMethodAndBlock(
627 return kInvalidKWalletHandle; 774 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
775 if (!response.get()) {
776 LOG(ERROR) << "Error contacting kwalletd (hasFolder)";
777 return kInvalidKWalletHandle;
778 }
779 dbus::MessageReader reader(response.get());
780 if (!reader.PopBool(&has_folder)) {
781 LOG(ERROR) << "Error reading response from kwalletd (hasFolder)";
782 return kInvalidKWalletHandle;
783 }
784 }
628 785
629 // Create it if it didn't. 786 // Create it if it didn't.
630 if (!has_folder) { 787 if (!has_folder) {
631 gboolean success = false; 788 dbus::MethodCall method_call(kKWalletInterface, "createFolder");
632 dbus_g_proxy_call(proxy_, "createFolder", &error_, 789 dbus::MessageWriter builder(&method_call);
633 G_TYPE_INT, handle, // handle 790 builder.AppendInt32(handle); // handle
634 G_TYPE_STRING, folder_name_.c_str(), // folder 791 builder.AppendString(folder_name_); // folder
635 G_TYPE_STRING, app_name_.c_str(), // appid 792 builder.AppendString(app_name_); // appid
636 G_TYPE_INVALID, 793 scoped_ptr<dbus::Response> response(
637 G_TYPE_BOOLEAN, &success, 794 kwallet_proxy_->CallMethodAndBlock(
638 G_TYPE_INVALID); 795 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
639 if (CheckError() || !success) 796 if (!response.get()) {
797 LOG(ERROR) << "Error contacting kwalletd (createFolder)";
640 return kInvalidKWalletHandle; 798 return kInvalidKWalletHandle;
799 }
800 dbus::MessageReader reader(response.get());
801 bool success = false;
802 if (!reader.PopBool(&success)) {
803 LOG(ERROR) << "Error reading response from kwalletd (createFolder)";
804 return kInvalidKWalletHandle;
805 }
806 if (!success) {
807 LOG(ERROR) << "Error creating KWallet folder";
808 return kInvalidKWalletHandle;
809 }
641 } 810 }
642 811
643 // Successful initialization. Try migration if necessary. 812 // Successful initialization. Try migration if necessary.
644 if (!migrate_tried_) 813 if (!migrate_tried_)
645 MigrateToProfileSpecificLogins(); 814 MigrateToProfileSpecificLogins();
646 815
647 return handle; 816 return handle;
648 } 817 }
649 818
650 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const { 819 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
693 // Each other profile must be able to migrate the shared data as well, 862 // Each other profile must be able to migrate the shared data as well,
694 // so we must leave it alone. After a few releases, we'll add code to 863 // so we must leave it alone. After a few releases, we'll add code to
695 // delete them, and eventually remove this migration code. 864 // delete them, and eventually remove this migration code.
696 // TODO(mdm): follow through with the plan above. 865 // TODO(mdm): follow through with the plan above.
697 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_); 866 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_);
698 } else { 867 } else {
699 // We failed to migrate for some reason. Use the old folder name. 868 // We failed to migrate for some reason. Use the old folder name.
700 folder_name_ = kKWalletFolder; 869 folder_name_ = kKWalletFolder;
701 } 870 }
702 } 871 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698