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

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
« no previous file with comments | « chrome/browser/password_manager/native_backend_kwallet_x.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // This destructor is called on the thread that is destroying the Profile
49 g_object_unref(proxy_); 50 // containing the PasswordStore that owns this NativeBackend. Generally that
51 // won't be the DB thread; it will be the UI thread. So we post a message to
52 // shut it down on the DB thread, and it will be destructed afterward when the
53 // scoped_refptr<dbus::Bus> goes out of scope. The NativeBackend will be
54 // destroyed before that occurs, but that's OK.
55 if (session_bus_.get()) {
56 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
57 NewRunnableMethod(
58 session_bus_.get(),
59 &dbus::Bus::ShutdownAndBlock));
60 }
50 } 61 }
51 62
52 bool NativeBackendKWallet::Init() { 63 bool NativeBackendKWallet::Init() {
53 // Get a connection to the session bus. 64 // We must synchronously do a few DBus calls to figure out if initialization
54 connection_ = dbus_g_bus_get(DBUS_BUS_SESSION, &error_); 65 // succeeds, but later, we'll want to do most work on the DB thread. So we
55 if (CheckError()) 66 // have to do the initialization on the DB thread here too, and wait for it.
67 scoped_refptr<dbus::Bus> optional_bus; // Will construct its own.
68 bool success = false;
69 base::WaitableEvent event(false, false);
70 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
71 NewRunnableMethod(
72 this, &NativeBackendKWallet::InitWithBus,
73 optional_bus, &event, &success));
74 event.Wait();
75 return success;
76 }
77
78 // NativeBackendKWallet isn't reference counted, but the one place we post a
79 // message to it (in InitWithBus below) waits for the task to run. So we can
80 // disable needing reference counting safely here.
81 template<>
82 struct RunnableMethodTraits<NativeBackendKWallet> {
83 void RetainCallee(NativeBackendKWallet*) {}
84 void ReleaseCallee(NativeBackendKWallet*) {}
85 };
86
87 void NativeBackendKWallet::InitWithBus(scoped_refptr<dbus::Bus> optional_bus,
88 base::WaitableEvent* event,
89 bool* success) {
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
91 DCHECK(!session_bus_.get());
92 if (optional_bus.get()) {
93 // The optional_bus parameter is given when this method is called in tests.
94 session_bus_ = optional_bus;
95 } else {
96 // Get a (real) connection to the session bus.
97 dbus::Bus::Options options;
98 options.bus_type = dbus::Bus::SESSION;
99 options.connection_type = dbus::Bus::PRIVATE;
100 session_bus_ = new dbus::Bus(options);
101 }
102 kwallet_proxy_ =
103 session_bus_->GetObjectProxy(kKWalletServiceName, kKWalletPath);
104 // kwalletd may not be running. If it fails to initialize, try to start it
105 // and then try to initialize it again. (Note the short-circuit evaluation.)
106 *success = (InitWallet() || (StartKWalletd() && InitWallet()));
107 if (event)
108 event->Signal();
109 }
110
111 bool NativeBackendKWallet::StartKWalletd() {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
113 // Sadly kwalletd doesn't use DBus activation, so we have to make a call to
114 // klauncher to start it.
115 dbus::ObjectProxy* klauncher =
116 session_bus_->GetObjectProxy(kKLauncherServiceName, kKLauncherPath);
117
118 dbus::MethodCall method_call(kKLauncherInterface,
119 "start_service_by_desktop_name");
120 dbus::MessageWriter builder(&method_call);
121 dbus::MessageWriter empty(&method_call);
122 builder.AppendString("kwalletd"); // serviceName
123 builder.OpenArray("s", &empty); // urls
124 builder.CloseContainer(&empty);
125 builder.OpenArray("s", &empty); // envs
126 builder.CloseContainer(&empty);
127 builder.AppendString(""); // startup_id
128 builder.AppendBool(false); // blind
129 scoped_ptr<dbus::Response> response(
130 klauncher->CallMethodAndBlock(
131 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
132 if (!response.get()) {
133 LOG(ERROR) << "Error contacting klauncher to start kwalletd";
56 return false; 134 return false;
57 135 }
58 if (!InitWallet()) { 136 dbus::MessageReader reader(response.get());
59 // kwalletd may not be running. Try to start it and try again. 137 int32_t ret = -1;
60 if (!StartKWalletd() || !InitWallet()) 138 std::string dbus_name;
61 return false; 139 std::string error;
140 int32_t pid = -1;
141 if (!reader.PopInt32(&ret) || !reader.PopString(&dbus_name) ||
142 !reader.PopString(&error) || !reader.PopInt32(&pid)) {
143 LOG(ERROR) << "Error reading response from klauncher to start kwalletd: "
144 << response->ToString();
145 return false;
146 }
147 if (!error.empty() || ret) {
148 LOG(ERROR) << "Error launching kwalletd: error '" << error << "' "
149 << " (code " << ret << ")";
150 return false;
62 } 151 }
63 152
64 return true; 153 return true;
65 } 154 }
66 155
67 bool NativeBackendKWallet::StartKWalletd() { 156 bool NativeBackendKWallet::InitWallet() {
68 // Sadly kwalletd doesn't use DBUS activation, so we have to make a call to 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
69 // klauncher to start it. 158 {
70 DBusGProxy* klauncher_proxy = 159 // Check that KWallet is enabled.
71 dbus_g_proxy_new_for_name(connection_, kKLauncherServiceName, 160 dbus::MethodCall method_call(kKWalletInterface, "isEnabled");
72 kKLauncherPath, kKLauncherInterface); 161 scoped_ptr<dbus::Response> response(
73 162 kwallet_proxy_->CallMethodAndBlock(
74 char* empty_string_list = NULL; 163 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
75 int ret = 1; 164 if (!response.get()) {
76 char* error = NULL; 165 LOG(ERROR) << "Error contacting kwalletd (isEnabled)";
77 dbus_g_proxy_call(klauncher_proxy, "start_service_by_desktop_name", &error_, 166 return false;
78 G_TYPE_STRING, "kwalletd", // serviceName 167 }
79 G_TYPE_STRV, &empty_string_list, // urls 168 dbus::MessageReader reader(response.get());
80 G_TYPE_STRV, &empty_string_list, // envs 169 bool enabled = false;
81 G_TYPE_STRING, "", // startup_id 170 if (!reader.PopBool(&enabled)) {
82 G_TYPE_BOOLEAN, (gboolean) false, // blind 171 LOG(ERROR) << "Error reading response from kwalletd (isEnabled): "
83 G_TYPE_INVALID, 172 << response->ToString();
84 G_TYPE_INT, &ret, // result 173 return false;
85 G_TYPE_STRING, NULL, // dubsName 174 }
86 G_TYPE_STRING, &error, // error 175 // Not enabled? Don't use KWallet. But also don't warn here.
87 G_TYPE_INT, NULL, // pid 176 if (!enabled) {
88 G_TYPE_INVALID); 177 VLOG(1) << "kwalletd reports that KWallet is not enabled.";
89 178 return false;
90 if (error && *error) { 179 }
91 LOG(ERROR) << "Error launching kwalletd: " << error;
92 ret = 1; // Make sure we return false after freeing.
93 } 180 }
94 181
95 g_free(error); 182 {
96 g_object_unref(klauncher_proxy); 183 // Get the wallet name.
97 184 dbus::MethodCall method_call(kKWalletInterface, "networkWallet");
98 if (CheckError() || ret != 0) 185 scoped_ptr<dbus::Response> response(
99 return false; 186 kwallet_proxy_->CallMethodAndBlock(
100 return true; 187 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
101 } 188 if (!response.get()) {
102 189 LOG(ERROR) << "Error contacting kwalletd (networkWallet)";
103 bool NativeBackendKWallet::InitWallet() { 190 return false;
104 // Make a proxy to KWallet. 191 }
105 proxy_ = dbus_g_proxy_new_for_name(connection_, kKWalletServiceName, 192 dbus::MessageReader reader(response.get());
106 kKWalletPath, kKWalletInterface); 193 if (!reader.PopString(&wallet_name_)) {
107 194 LOG(ERROR) << "Error reading response from kwalletd (networkWallet): "
108 // Check KWallet is enabled. 195 << response->ToString();
109 gboolean is_enabled = false; 196 return false;
110 dbus_g_proxy_call(proxy_, "isEnabled", &error_, 197 }
111 G_TYPE_INVALID, 198 }
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 199
129 return true; 200 return true;
130 } 201 }
131 202
132 bool NativeBackendKWallet::AddLogin(const PasswordForm& form) { 203 bool NativeBackendKWallet::AddLogin(const PasswordForm& form) {
133 int wallet_handle = WalletHandle(); 204 int wallet_handle = WalletHandle();
134 if (wallet_handle == kInvalidKWalletHandle) 205 if (wallet_handle == kInvalidKWalletHandle)
135 return false; 206 return false;
136 207
137 PasswordFormList forms; 208 PasswordFormList forms;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 } 273 }
203 274
204 bool NativeBackendKWallet::RemoveLoginsCreatedBetween( 275 bool NativeBackendKWallet::RemoveLoginsCreatedBetween(
205 const base::Time& delete_begin, 276 const base::Time& delete_begin,
206 const base::Time& delete_end) { 277 const base::Time& delete_end) {
207 int wallet_handle = WalletHandle(); 278 int wallet_handle = WalletHandle();
208 if (wallet_handle == kInvalidKWalletHandle) 279 if (wallet_handle == kInvalidKWalletHandle)
209 return false; 280 return false;
210 281
211 // We could probably also use readEntryList here. 282 // We could probably also use readEntryList here.
212 char** realm_list = NULL; 283 std::vector<std::string> realm_list;
213 dbus_g_proxy_call(proxy_, "entryList", &error_, 284 {
214 G_TYPE_INT, wallet_handle, // handle 285 dbus::MethodCall method_call(kKWalletInterface, "entryList");
215 G_TYPE_STRING, folder_name_.c_str(), // folder 286 dbus::MessageWriter builder(&method_call);
216 G_TYPE_STRING, app_name_.c_str(), // appid 287 builder.AppendInt32(wallet_handle); // handle
217 G_TYPE_INVALID, 288 builder.AppendString(folder_name_); // folder
218 G_TYPE_STRV, &realm_list, 289 builder.AppendString(app_name_); // appid
219 G_TYPE_INVALID); 290 scoped_ptr<dbus::Response> response(
220 if (CheckError()) 291 kwallet_proxy_->CallMethodAndBlock(
221 return false; 292 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
293 if (!response.get()) {
294 LOG(ERROR) << "Error contacting kwalletd (entryList)";
295 return false;
296 }
297 dbus::MessageReader reader(response.get());
298 dbus::MessageReader array(response.get());
299 if (!reader.PopArray(&array)) {
300 LOG(ERROR) << "Error reading response from kwalletd (entryList): "
301 << response->ToString();
302 return false;
303 }
304 while (array.HasMoreData()) {
305 std::string realm;
306 if (!array.PopString(&realm)) {
307 LOG(ERROR) << "Error reading response from kwalletd (entryList): "
308 << response->ToString();
309 return false;
310 }
311 realm_list.push_back(realm);
312 }
313 }
222 314
223 bool ok = true; 315 bool ok = true;
224 for (char** realm = realm_list; *realm; ++realm) { 316 for (size_t i = 0; i < realm_list.size(); ++i) {
225 GArray* byte_array = NULL; 317 const std::string& signon_realm = realm_list[i];
226 dbus_g_proxy_call(proxy_, "readEntry", &error_, 318 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
227 G_TYPE_INT, wallet_handle, // handle 319 dbus::MessageWriter builder(&method_call);
228 G_TYPE_STRING, folder_name_.c_str(), // folder 320 builder.AppendInt32(wallet_handle); // handle
229 G_TYPE_STRING, *realm, // key 321 builder.AppendString(folder_name_); // folder
230 G_TYPE_STRING, app_name_.c_str(), // appid 322 builder.AppendString(signon_realm); // key
231 G_TYPE_INVALID, 323 builder.AppendString(app_name_); // appid
232 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, 324 scoped_ptr<dbus::Response> response(
233 G_TYPE_INVALID); 325 kwallet_proxy_->CallMethodAndBlock(
234 326 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
235 if (CheckError() || !byte_array || 327 if (!response.get()) {
236 !CheckSerializedValue(byte_array, *realm)) { 328 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
237 continue; 329 continue;
238 } 330 }
331 dbus::MessageReader reader(response.get());
332 uint8_t* bytes = NULL;
333 size_t length = 0;
334 if (!reader.PopArrayOfBytes(&bytes, &length)) {
335 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
336 << response->ToString();
337 continue;
338 }
339 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
340 continue;
239 341
240 string signon_realm(*realm); 342 // Can't we all just agree on whether bytes are signed or not? Please?
241 Pickle pickle(byte_array->data, byte_array->len); 343 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
242 PasswordFormList all_forms; 344 PasswordFormList all_forms;
243 DeserializeValue(signon_realm, pickle, &all_forms); 345 DeserializeValue(signon_realm, pickle, &all_forms);
244 g_array_free(byte_array, true);
245 346
246 PasswordFormList kept_forms; 347 PasswordFormList kept_forms;
247 kept_forms.reserve(all_forms.size()); 348 kept_forms.reserve(all_forms.size());
248 for (size_t i = 0; i < all_forms.size(); ++i) { 349 for (size_t i = 0; i < all_forms.size(); ++i) {
249 if (delete_begin <= all_forms[i]->date_created && 350 if (delete_begin <= all_forms[i]->date_created &&
250 (delete_end.is_null() || all_forms[i]->date_created < delete_end)) { 351 (delete_end.is_null() || all_forms[i]->date_created < delete_end)) {
251 delete all_forms[i]; 352 delete all_forms[i];
252 } else { 353 } else {
253 kept_forms.push_back(all_forms[i]); 354 kept_forms.push_back(all_forms[i]);
254 } 355 }
255 } 356 }
256 357
257 if (!SetLoginsList(kept_forms, signon_realm, wallet_handle)) 358 if (!SetLoginsList(kept_forms, signon_realm, wallet_handle))
258 ok = false; 359 ok = false;
259 STLDeleteElements(&kept_forms); 360 STLDeleteElements(&kept_forms);
260 } 361 }
261 g_strfreev(realm_list);
262 return ok; 362 return ok;
263 } 363 }
264 364
265 bool NativeBackendKWallet::GetLogins(const PasswordForm& form, 365 bool NativeBackendKWallet::GetLogins(const PasswordForm& form,
266 PasswordFormList* forms) { 366 PasswordFormList* forms) {
267 int wallet_handle = WalletHandle(); 367 int wallet_handle = WalletHandle();
268 if (wallet_handle == kInvalidKWalletHandle) 368 if (wallet_handle == kInvalidKWalletHandle)
269 return false; 369 return false;
270 return GetLoginsList(forms, form.signon_realm, wallet_handle); 370 return GetLoginsList(forms, form.signon_realm, wallet_handle);
271 } 371 }
(...skipping 15 matching lines...) Expand all
287 } 387 }
288 388
289 bool NativeBackendKWallet::GetBlacklistLogins(PasswordFormList* forms) { 389 bool NativeBackendKWallet::GetBlacklistLogins(PasswordFormList* forms) {
290 int wallet_handle = WalletHandle(); 390 int wallet_handle = WalletHandle();
291 if (wallet_handle == kInvalidKWalletHandle) 391 if (wallet_handle == kInvalidKWalletHandle)
292 return false; 392 return false;
293 return GetLoginsList(forms, false, wallet_handle); 393 return GetLoginsList(forms, false, wallet_handle);
294 } 394 }
295 395
296 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms, 396 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms,
297 const string& signon_realm, 397 const std::string& signon_realm,
298 int wallet_handle) { 398 int wallet_handle) {
299 // Is there an entry in the wallet? 399 // Is there an entry in the wallet?
300 gboolean has_entry = false; 400 {
301 dbus_g_proxy_call(proxy_, "hasEntry", &error_, 401 dbus::MethodCall method_call(kKWalletInterface, "hasEntry");
302 G_TYPE_INT, wallet_handle, // handle 402 dbus::MessageWriter builder(&method_call);
303 G_TYPE_STRING, folder_name_.c_str(), // folder 403 builder.AppendInt32(wallet_handle); // handle
304 G_TYPE_STRING, signon_realm.c_str(), // key 404 builder.AppendString(folder_name_); // folder
305 G_TYPE_STRING, app_name_.c_str(), // appid 405 builder.AppendString(signon_realm); // key
306 G_TYPE_INVALID, 406 builder.AppendString(app_name_); // appid
307 G_TYPE_BOOLEAN, &has_entry, 407 scoped_ptr<dbus::Response> response(
308 G_TYPE_INVALID); 408 kwallet_proxy_->CallMethodAndBlock(
309 409 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
310 if (CheckError()) 410 if (!response.get()) {
311 return false; 411 LOG(ERROR) << "Error contacting kwalletd (hasEntry)";
312 if (!has_entry) { 412 return false;
313 // This is not an error. There just isn't a matching entry. 413 }
314 return true; 414 dbus::MessageReader reader(response.get());
415 bool has_entry = false;
416 if (!reader.PopBool(&has_entry)) {
417 LOG(ERROR) << "Error reading response from kwalletd (hasEntry): "
418 << response->ToString();
419 return false;
420 }
421 if (!has_entry) {
422 // This is not an error. There just isn't a matching entry.
423 return true;
424 }
315 } 425 }
316 426
317 GArray* byte_array = NULL; 427 {
318 dbus_g_proxy_call(proxy_, "readEntry", &error_, 428 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
319 G_TYPE_INT, wallet_handle, // handle 429 dbus::MessageWriter builder(&method_call);
320 G_TYPE_STRING, folder_name_.c_str(), // folder 430 builder.AppendInt32(wallet_handle); // handle
321 G_TYPE_STRING, signon_realm.c_str(), // key 431 builder.AppendString(folder_name_); // folder
322 G_TYPE_STRING, app_name_.c_str(), // appid 432 builder.AppendString(signon_realm); // key
323 G_TYPE_INVALID, 433 builder.AppendString(app_name_); // appid
324 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, 434 scoped_ptr<dbus::Response> response(
325 G_TYPE_INVALID); 435 kwallet_proxy_->CallMethodAndBlock(
436 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
437 if (!response.get()) {
438 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
439 return false;
440 }
441 dbus::MessageReader reader(response.get());
442 uint8_t* bytes = NULL;
443 size_t length = 0;
444 if (!reader.PopArrayOfBytes(&bytes, &length)) {
445 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
446 << response->ToString();
447 return false;
448 }
449 if (!bytes)
450 return false;
451 if (!CheckSerializedValue(bytes, length, signon_realm)) {
452 // This is weird, but we choose not to call it an error. There is an
453 // invalid entry somehow, but by just ignoring it, we make it easier to
454 // repair without having to delete it using kwalletmanager (that is, by
455 // just saving a new password within this realm to overwrite it).
456 return true;
457 }
326 458
327 if (CheckError() || !byte_array) 459 // Can't we all just agree on whether bytes are signed or not? Please?
328 return false; 460 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
329 if (!CheckSerializedValue(byte_array, signon_realm.c_str())) { 461 PasswordFormList all_forms;
330 // This is weird, but we choose not to call it an error. There's an invalid 462 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 } 463 }
337 464
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; 465 return true;
343 } 466 }
344 467
345 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms, 468 bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms,
346 bool autofillable, 469 bool autofillable,
347 int wallet_handle) { 470 int wallet_handle) {
348 PasswordFormList all_forms; 471 PasswordFormList all_forms;
349 if (!GetAllLogins(&all_forms, wallet_handle)) 472 if (!GetAllLogins(&all_forms, wallet_handle))
350 return false; 473 return false;
351 474
(...skipping 27 matching lines...) Expand all
379 delete all_forms[i]; 502 delete all_forms[i];
380 } 503 }
381 } 504 }
382 505
383 return true; 506 return true;
384 } 507 }
385 508
386 bool NativeBackendKWallet::GetAllLogins(PasswordFormList* forms, 509 bool NativeBackendKWallet::GetAllLogins(PasswordFormList* forms,
387 int wallet_handle) { 510 int wallet_handle) {
388 // We could probably also use readEntryList here. 511 // We could probably also use readEntryList here.
389 char** realm_list = NULL; 512 std::vector<std::string> realm_list;
390 dbus_g_proxy_call(proxy_, "entryList", &error_, 513 {
391 G_TYPE_INT, wallet_handle, // handle 514 dbus::MethodCall method_call(kKWalletInterface, "entryList");
392 G_TYPE_STRING, folder_name_.c_str(), // folder 515 dbus::MessageWriter builder(&method_call);
393 G_TYPE_STRING, app_name_.c_str(), // appid 516 builder.AppendInt32(wallet_handle); // handle
394 G_TYPE_INVALID, 517 builder.AppendString(folder_name_); // folder
395 G_TYPE_STRV, &realm_list, 518 builder.AppendString(app_name_); // appid
396 G_TYPE_INVALID); 519 scoped_ptr<dbus::Response> response(
397 if (CheckError()) 520 kwallet_proxy_->CallMethodAndBlock(
398 return false; 521 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
522 if (!response.get()) {
523 LOG(ERROR) << "Error contacting kwalletd (entryList)";
524 return false;
525 }
526 dbus::MessageReader reader(response.get());
527 dbus::MessageReader array(response.get());
528 if (!reader.PopArray(&array)) {
529 LOG(ERROR) << "Error reading response from kwalletd (entryList): "
530 << response->ToString();
531 return false;
532 }
533 while (array.HasMoreData()) {
534 std::string realm;
535 if (!array.PopString(&realm)) {
536 LOG(ERROR) << "Error reading response from kwalletd (entryList): "
537 << response->ToString();
538 return false;
539 }
540 realm_list.push_back(realm);
541 }
542 }
399 543
400 for (char** realm = realm_list; *realm; ++realm) { 544 for (size_t i = 0; i < realm_list.size(); ++i) {
401 GArray* byte_array = NULL; 545 const std::string& signon_realm = realm_list[i];
402 dbus_g_proxy_call(proxy_, "readEntry", &error_, 546 dbus::MethodCall method_call(kKWalletInterface, "readEntry");
403 G_TYPE_INT, wallet_handle, // handle 547 dbus::MessageWriter builder(&method_call);
404 G_TYPE_STRING, folder_name_.c_str(), // folder 548 builder.AppendInt32(wallet_handle); // handle
405 G_TYPE_STRING, *realm, // key 549 builder.AppendString(folder_name_); // folder
406 G_TYPE_STRING, app_name_.c_str(), // appid 550 builder.AppendString(signon_realm); // key
407 G_TYPE_INVALID, 551 builder.AppendString(app_name_); // appid
408 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array, 552 scoped_ptr<dbus::Response> response(
409 G_TYPE_INVALID); 553 kwallet_proxy_->CallMethodAndBlock(
410 554 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
411 if (CheckError() || !byte_array || 555 if (!response.get()) {
412 !CheckSerializedValue(byte_array, *realm)) { 556 LOG(ERROR) << "Error contacting kwalletd (readEntry)";
413 continue; 557 continue;
414 } 558 }
559 dbus::MessageReader reader(response.get());
560 uint8_t* bytes = NULL;
561 size_t length = 0;
562 if (!reader.PopArrayOfBytes(&bytes, &length)) {
563 LOG(ERROR) << "Error reading response from kwalletd (readEntry): "
564 << response->ToString();
565 continue;
566 }
567 if (!bytes || !CheckSerializedValue(bytes, length, signon_realm))
568 continue;
415 569
416 Pickle pickle(byte_array->data, byte_array->len); 570 // Can't we all just agree on whether bytes are signed or not? Please?
417 DeserializeValue(*realm, pickle, forms); 571 Pickle pickle(reinterpret_cast<const char*>(bytes), length);
418 g_array_free(byte_array, true); 572 PasswordFormList all_forms;
573 DeserializeValue(signon_realm, pickle, forms);
419 } 574 }
420 g_strfreev(realm_list);
421 return true; 575 return true;
422 } 576 }
423 577
424 bool NativeBackendKWallet::SetLoginsList(const PasswordFormList& forms, 578 bool NativeBackendKWallet::SetLoginsList(const PasswordFormList& forms,
425 const string& signon_realm, 579 const std::string& signon_realm,
426 int wallet_handle) { 580 int wallet_handle) {
427 if (forms.empty()) { 581 if (forms.empty()) {
428 // No items left? Remove the entry from the wallet. 582 // No items left? Remove the entry from the wallet.
583 dbus::MethodCall method_call(kKWalletInterface, "removeEntry");
584 dbus::MessageWriter builder(&method_call);
585 builder.AppendInt32(wallet_handle); // handle
586 builder.AppendString(folder_name_); // folder
587 builder.AppendString(signon_realm); // key
588 builder.AppendString(app_name_); // appid
589 scoped_ptr<dbus::Response> response(
590 kwallet_proxy_->CallMethodAndBlock(
591 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
592 if (!response.get()) {
593 LOG(ERROR) << "Error contacting kwalletd (removeEntry)";
594 return kInvalidKWalletHandle;
595 }
596 dbus::MessageReader reader(response.get());
429 int ret = 0; 597 int ret = 0;
430 dbus_g_proxy_call(proxy_, "removeEntry", &error_, 598 if (!reader.PopInt32(&ret)) {
431 G_TYPE_INT, wallet_handle, // handle 599 LOG(ERROR) << "Error reading response from kwalletd (removeEntry): "
432 G_TYPE_STRING, folder_name_.c_str(), // folder 600 << response->ToString();
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; 601 return false;
602 }
440 if (ret != 0) 603 if (ret != 0)
441 LOG(ERROR) << "Bad return code " << ret << " from KWallet removeEntry"; 604 LOG(ERROR) << "Bad return code " << ret << " from KWallet removeEntry";
442 return ret == 0; 605 return ret == 0;
443 } 606 }
444 607
445 Pickle value; 608 Pickle value;
446 SerializeValue(forms, &value); 609 SerializeValue(forms, &value);
447 610
448 // Convert the pickled bytes to a GByteArray. 611 dbus::MethodCall method_call(kKWalletInterface, "writeEntry");
449 GArray* byte_array = g_array_sized_new(false, false, sizeof(char), 612 dbus::MessageWriter builder(&method_call);
450 value.size()); 613 builder.AppendInt32(wallet_handle); // handle
451 g_array_append_vals(byte_array, value.data(), value.size()); 614 builder.AppendString(folder_name_); // folder
452 615 builder.AppendString(signon_realm); // key
453 // Make the call. 616 builder.AppendArrayOfBytes(static_cast<const uint8_t*>(value.data()),
617 value.size()); // value
618 builder.AppendString(app_name_); // appid
619 scoped_ptr<dbus::Response> response(
620 kwallet_proxy_->CallMethodAndBlock(
621 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
622 if (!response.get()) {
623 LOG(ERROR) << "Error contacting kwalletd (writeEntry)";
624 return kInvalidKWalletHandle;
625 }
626 dbus::MessageReader reader(response.get());
454 int ret = 0; 627 int ret = 0;
455 dbus_g_proxy_call(proxy_, "writeEntry", &error_, 628 if (!reader.PopInt32(&ret)) {
456 G_TYPE_INT, wallet_handle, // handle 629 LOG(ERROR) << "Error reading response from kwalletd (writeEntry): "
457 G_TYPE_STRING, folder_name_.c_str(), // folder 630 << response->ToString();
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; 631 return false;
632 }
468 if (ret != 0) 633 if (ret != 0)
469 LOG(ERROR) << "Bad return code " << ret << " from KWallet writeEntry"; 634 LOG(ERROR) << "Bad return code " << ret << " from KWallet writeEntry";
470 return ret == 0; 635 return ret == 0;
471 } 636 }
472 637
473 bool NativeBackendKWallet::CompareForms(const PasswordForm& a, 638 bool NativeBackendKWallet::CompareForms(const PasswordForm& a,
474 const PasswordForm& b, 639 const PasswordForm& b,
475 bool update_check) { 640 bool update_check) {
476 // An update check doesn't care about the submit element. 641 // An update check doesn't care about the submit element.
477 if (!update_check && a.submit_element != b.submit_element) 642 if (!update_check && a.submit_element != b.submit_element)
(...skipping 20 matching lines...) Expand all
498 pickle->WriteString16(form->password_element); 663 pickle->WriteString16(form->password_element);
499 pickle->WriteString16(form->password_value); 664 pickle->WriteString16(form->password_value);
500 pickle->WriteString16(form->submit_element); 665 pickle->WriteString16(form->submit_element);
501 pickle->WriteBool(form->ssl_valid); 666 pickle->WriteBool(form->ssl_valid);
502 pickle->WriteBool(form->preferred); 667 pickle->WriteBool(form->preferred);
503 pickle->WriteBool(form->blacklisted_by_user); 668 pickle->WriteBool(form->blacklisted_by_user);
504 pickle->WriteInt64(form->date_created.ToTimeT()); 669 pickle->WriteInt64(form->date_created.ToTimeT());
505 } 670 }
506 } 671 }
507 672
508 bool NativeBackendKWallet::CheckSerializedValue(const GArray* byte_array, 673 bool NativeBackendKWallet::CheckSerializedValue(const uint8_t* byte_array,
509 const char* realm) { 674 size_t length,
675 const std::string& realm) {
510 const Pickle::Header* header = 676 const Pickle::Header* header =
511 reinterpret_cast<const Pickle::Header*>(byte_array->data); 677 reinterpret_cast<const Pickle::Header*>(byte_array);
512 if (byte_array->len < sizeof(*header) || 678 if (length < sizeof(*header) ||
513 header->payload_size > byte_array->len - sizeof(*header)) { 679 header->payload_size > length - sizeof(*header)) {
514 LOG(WARNING) << "Invalid KWallet entry detected (realm: " << realm << ")"; 680 LOG(WARNING) << "Invalid KWallet entry detected (realm: " << realm << ")";
515 return false; 681 return false;
516 } 682 }
517 return true; 683 return true;
518 } 684 }
519 685
520 void NativeBackendKWallet::DeserializeValue(const string& signon_realm, 686 void NativeBackendKWallet::DeserializeValue(const std::string& signon_realm,
521 const Pickle& pickle, 687 const Pickle& pickle,
522 PasswordFormList* forms) { 688 PasswordFormList* forms) {
523 void* iter = NULL; 689 void* iter = NULL;
524 690
525 int version = -1; 691 int version = -1;
526 if (!pickle.ReadInt(&iter, &version) || version != kPickleVersion) { 692 if (!pickle.ReadInt(&iter, &version) || version != kPickleVersion) {
527 // This is the only version so far, so anything else is an error. 693 // This is the only version so far, so anything else is an error.
528 LOG(ERROR) << "Failed to deserialize KWallet entry " 694 LOG(ERROR) << "Failed to deserialize KWallet entry "
529 << "(realm: " << signon_realm << ")"; 695 << "(realm: " << signon_realm << ")";
530 return; 696 return;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 break; 738 break;
573 } 739 }
574 form->scheme = static_cast<PasswordForm::Scheme>(scheme); 740 form->scheme = static_cast<PasswordForm::Scheme>(scheme);
575 form->date_created = base::Time::FromTimeT(date_created); 741 form->date_created = base::Time::FromTimeT(date_created);
576 forms->push_back(form.release()); 742 forms->push_back(form.release());
577 } 743 }
578 } 744 }
579 745
580 bool NativeBackendKWallet::ReadGURL(const Pickle& pickle, void** iter, 746 bool NativeBackendKWallet::ReadGURL(const Pickle& pickle, void** iter,
581 GURL* url) { 747 GURL* url) {
582 string url_string; 748 std::string url_string;
583 if (!pickle.ReadString(iter, &url_string)) { 749 if (!pickle.ReadString(iter, &url_string)) {
584 LOG(ERROR) << "Failed to deserialize URL"; 750 LOG(ERROR) << "Failed to deserialize URL";
585 *url = GURL(); 751 *url = GURL();
586 return false; 752 return false;
587 } 753 }
588 *url = GURL(url_string); 754 *url = GURL(url_string);
589 return true; 755 return true;
590 } 756 }
591 757
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() { 758 int NativeBackendKWallet::WalletHandle() {
603 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 759 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
760
604 // Open the wallet. 761 // Open the wallet.
605 // TODO(mdm): Are we leaking these handles? Find out. 762 // TODO(mdm): Are we leaking these handles? Find out.
606 int handle = kInvalidKWalletHandle; 763 int32_t handle = kInvalidKWalletHandle;
607 dbus_g_proxy_call(proxy_, "open", &error_, 764 {
608 G_TYPE_STRING, wallet_name_.c_str(), // wallet 765 dbus::MethodCall method_call(kKWalletInterface, "open");
609 G_TYPE_INT64, 0LL, // wid 766 dbus::MessageWriter builder(&method_call);
610 G_TYPE_STRING, app_name_.c_str(), // appid 767 builder.AppendString(wallet_name_); // wallet
611 G_TYPE_INVALID, 768 builder.AppendInt64(0); // wid
612 G_TYPE_INT, &handle, 769 builder.AppendString(app_name_); // appid
613 G_TYPE_INVALID); 770 scoped_ptr<dbus::Response> response(
614 if (CheckError() || handle == kInvalidKWalletHandle) 771 kwallet_proxy_->CallMethodAndBlock(
615 return kInvalidKWalletHandle; 772 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
773 if (!response.get()) {
774 LOG(ERROR) << "Error contacting kwalletd (open)";
775 return kInvalidKWalletHandle;
776 }
777 dbus::MessageReader reader(response.get());
778 if (!reader.PopInt32(&handle)) {
779 LOG(ERROR) << "Error reading response from kwalletd (open): "
780 << response->ToString();
781 return kInvalidKWalletHandle;
782 }
783 if (handle == kInvalidKWalletHandle) {
784 LOG(ERROR) << "Error obtaining KWallet handle";
785 return kInvalidKWalletHandle;
786 }
787 }
616 788
617 // Check if our folder exists. 789 // Check if our folder exists.
618 gboolean has_folder = false; 790 bool has_folder = false;
619 dbus_g_proxy_call(proxy_, "hasFolder", &error_, 791 {
620 G_TYPE_INT, handle, // handle 792 dbus::MethodCall method_call(kKWalletInterface, "hasFolder");
621 G_TYPE_STRING, folder_name_.c_str(), // folder 793 dbus::MessageWriter builder(&method_call);
622 G_TYPE_STRING, app_name_.c_str(), // appid 794 builder.AppendInt32(handle); // handle
623 G_TYPE_INVALID, 795 builder.AppendString(folder_name_); // folder
624 G_TYPE_BOOLEAN, &has_folder, 796 builder.AppendString(app_name_); // appid
625 G_TYPE_INVALID); 797 scoped_ptr<dbus::Response> response(
626 if (CheckError()) 798 kwallet_proxy_->CallMethodAndBlock(
627 return kInvalidKWalletHandle; 799 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
800 if (!response.get()) {
801 LOG(ERROR) << "Error contacting kwalletd (hasFolder)";
802 return kInvalidKWalletHandle;
803 }
804 dbus::MessageReader reader(response.get());
805 if (!reader.PopBool(&has_folder)) {
806 LOG(ERROR) << "Error reading response from kwalletd (hasFolder): "
807 << response->ToString();
808 return kInvalidKWalletHandle;
809 }
810 }
628 811
629 // Create it if it didn't. 812 // Create it if it didn't.
630 if (!has_folder) { 813 if (!has_folder) {
631 gboolean success = false; 814 dbus::MethodCall method_call(kKWalletInterface, "createFolder");
632 dbus_g_proxy_call(proxy_, "createFolder", &error_, 815 dbus::MessageWriter builder(&method_call);
633 G_TYPE_INT, handle, // handle 816 builder.AppendInt32(handle); // handle
634 G_TYPE_STRING, folder_name_.c_str(), // folder 817 builder.AppendString(folder_name_); // folder
635 G_TYPE_STRING, app_name_.c_str(), // appid 818 builder.AppendString(app_name_); // appid
636 G_TYPE_INVALID, 819 scoped_ptr<dbus::Response> response(
637 G_TYPE_BOOLEAN, &success, 820 kwallet_proxy_->CallMethodAndBlock(
638 G_TYPE_INVALID); 821 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
639 if (CheckError() || !success) 822 if (!response.get()) {
823 LOG(ERROR) << "Error contacting kwalletd (createFolder)";
640 return kInvalidKWalletHandle; 824 return kInvalidKWalletHandle;
825 }
826 dbus::MessageReader reader(response.get());
827 bool success = false;
828 if (!reader.PopBool(&success)) {
829 LOG(ERROR) << "Error reading response from kwalletd (createFolder): "
830 << response->ToString();
831 return kInvalidKWalletHandle;
832 }
833 if (!success) {
834 LOG(ERROR) << "Error creating KWallet folder";
835 return kInvalidKWalletHandle;
836 }
641 } 837 }
642 838
643 // Successful initialization. Try migration if necessary. 839 // Successful initialization. Try migration if necessary.
644 if (!migrate_tried_) 840 if (!migrate_tried_)
645 MigrateToProfileSpecificLogins(); 841 MigrateToProfileSpecificLogins();
646 842
647 return handle; 843 return handle;
648 } 844 }
649 845
650 std::string NativeBackendKWallet::GetProfileSpecificFolderName() const { 846 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, 889 // 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 890 // so we must leave it alone. After a few releases, we'll add code to
695 // delete them, and eventually remove this migration code. 891 // delete them, and eventually remove this migration code.
696 // TODO(mdm): follow through with the plan above. 892 // TODO(mdm): follow through with the plan above.
697 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_); 893 PasswordStoreX::SetPasswordsUseLocalProfileId(prefs_);
698 } else { 894 } else {
699 // We failed to migrate for some reason. Use the old folder name. 895 // We failed to migrate for some reason. Use the old folder name.
700 folder_name_ = kKWalletFolder; 896 folder_name_ = kKWalletFolder;
701 } 897 }
702 } 898 }
OLDNEW
« no previous file with comments | « chrome/browser/password_manager/native_backend_kwallet_x.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698