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

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

Issue 113871: Revert the password manager refactoring -- it failed reliability tests. (Closed)
Patch Set: Created 11 years, 6 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
OLDNEW
(Empty)
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/password_manager/password_store_kwallet.h"
6
7 #include <sstream>
8
9 #include "base/logging.h"
10 #include "base/md5.h"
11 #include "base/pickle.h"
12 #include "base/string_util.h"
13 #include "base/task.h"
14
15 using std::string;
16 using std::vector;
17
18 const char* PasswordStoreKWallet::kAppId = "Chrome";
19 const char* PasswordStoreKWallet::kKWalletFolder = "Chrome Form Data";
20
21 const char* PasswordStoreKWallet::kKWalletServiceName = "org.kde.kwalletd";
22 const char* PasswordStoreKWallet::kKWalletPath = "/modules/kwalletd";
23 const char* PasswordStoreKWallet::kKWalletInterface = "org.kde.KWallet";
24 const char* PasswordStoreKWallet::kKLauncherServiceName = "org.kde.klauncher";
25 const char* PasswordStoreKWallet::kKLauncherPath = "/KLauncher";
26 const char* PasswordStoreKWallet::kKLauncherInterface = "org.kde.KLauncher";
27
28 PasswordStoreKWallet::PasswordStoreKWallet()
29 : error_(NULL),
30 connection_(NULL),
31 proxy_(NULL) {
32 }
33
34 PasswordStoreKWallet::~PasswordStoreKWallet() {
35 if (proxy_) {
36 g_object_unref(proxy_);
37 }
38 }
39
40 bool PasswordStoreKWallet::Init() {
41 thread_.reset(new base::Thread("Chrome_KeyringThread"));
42
43 if (!thread_->Start()) {
44 thread_.reset(NULL);
45 return false;
46 }
47
48 // Initialize threading in dbus-glib - it should be fine for
49 // dbus_g_thread_init to be called multiple times.
50 if (!g_thread_supported())
51 g_thread_init(NULL);
52 dbus_g_thread_init();
53
54 // Get a connection to the session bus.
55 connection_ = dbus_g_bus_get(DBUS_BUS_SESSION, &error_);
56 if (CheckError())
57 return false;
58
59 if (!StartKWalletd()) return false;
60 if (!InitWallet()) return false;
61
62 return true;
63 }
64
65 bool PasswordStoreKWallet::StartKWalletd() {
66 // Sadly kwalletd doesn't use DBUS activation, so we have to make a call to
67 // klauncher to start it.
68 DBusGProxy* klauncher_proxy =
69 dbus_g_proxy_new_for_name(connection_, kKLauncherServiceName,
70 kKLauncherPath, kKLauncherInterface);
71
72 char* empty_string_list = NULL;
73 int ret = 1;
74 char* error = NULL;
75 dbus_g_proxy_call(klauncher_proxy, "start_service_by_desktop_name", &error_,
76 G_TYPE_STRING, "kwalletd", // serviceName
77 G_TYPE_STRV, &empty_string_list, // urls
78 G_TYPE_STRV, &empty_string_list, // envs
79 G_TYPE_STRING, "", // startup_id
80 G_TYPE_BOOLEAN, (gboolean) false, // blind
81 G_TYPE_INVALID,
82 G_TYPE_INT, &ret, // result
83 G_TYPE_STRING, NULL, // dubsName
84 G_TYPE_STRING, &error, // error
85 G_TYPE_INT, NULL, // pid
86 G_TYPE_INVALID);
87
88 if (error && *error) {
89 LOG(ERROR) << "Error launching kwalletd: " << error;
90 ret = 1; // Make sure we return false after freeing.
91 }
92
93 g_free(error);
94 g_object_unref(klauncher_proxy);
95
96 if (CheckError() || ret != 0)
97 return false;
98 return true;
99 }
100
101 bool PasswordStoreKWallet::InitWallet() {
102 // Make a proxy to KWallet.
103 proxy_ = dbus_g_proxy_new_for_name(connection_, kKWalletServiceName,
104 kKWalletPath, kKWalletInterface);
105
106 // Check KWallet is enabled.
107 gboolean is_enabled = false;
108 dbus_g_proxy_call(proxy_, "isEnabled", &error_,
109 G_TYPE_INVALID,
110 G_TYPE_BOOLEAN, &is_enabled,
111 G_TYPE_INVALID);
112 if (CheckError() || !is_enabled)
113 return false;
114
115 // Get the wallet name.
116 char* wallet_name = NULL;
117 dbus_g_proxy_call(proxy_, "networkWallet", &error_,
118 G_TYPE_INVALID,
119 G_TYPE_STRING, &wallet_name,
120 G_TYPE_INVALID);
121 if (CheckError() || !wallet_name)
122 return false;
123
124 wallet_name_.assign(wallet_name);
125 g_free(wallet_name);
126
127 return true;
128 }
129
130 void PasswordStoreKWallet::AddLoginImpl(const PasswordForm& form) {
131 AutoLock l(kwallet_lock_);
132 int wallet_handle = WalletHandle();
133 if (wallet_handle == kInvalidKWalletHandle)
134 return;
135
136 PasswordFormList forms;
137 GetLoginsList(&forms, form, wallet_handle);
138
139 forms.push_back(const_cast<PasswordForm*>(&form));
140
141 SetLoginsList(forms, form, wallet_handle);
142 }
143
144 void PasswordStoreKWallet::UpdateLoginImpl(const PasswordForm& form) {
145 AutoLock l(kwallet_lock_);
146 int wallet_handle = WalletHandle();
147 if (wallet_handle == kInvalidKWalletHandle)
148 return;
149
150 PasswordFormList forms;
151 GetLoginsList(&forms, form, wallet_handle);
152
153 for (uint i = 0; i < forms.size(); ++i) {
154 if (CompareForms(form, *forms[i])) {
155 forms.erase(forms.begin() + i);
156 forms.insert(forms.begin() + i, const_cast<PasswordForm*>(&form));
157 }
158 }
159
160 SetLoginsList(forms, form, wallet_handle);
161 }
162
163 void PasswordStoreKWallet::RemoveLoginImpl(const PasswordForm& form) {
164 AutoLock l(kwallet_lock_);
165 int wallet_handle = WalletHandle();
166 if (wallet_handle == kInvalidKWalletHandle)
167 return;
168
169 PasswordFormList forms;
170 GetLoginsList(&forms, form, wallet_handle);
171
172 for (uint i = 0; i < forms.size(); ++i) {
173 if (CompareForms(form, *forms[i])) {
174 forms.erase(forms.begin() + i);
175 --i;
176 }
177 }
178
179 if (forms.empty()) {
180 // No items left? Remove the entry from the wallet.
181 int ret = 0;
182 dbus_g_proxy_call(proxy_, "removeEntry", &error_,
183 G_TYPE_INT, wallet_handle, // handle
184 G_TYPE_STRING, kKWalletFolder, // folder
185 G_TYPE_STRING, form.signon_realm.c_str(), // key
186 G_TYPE_STRING, kAppId, // appid
187 G_TYPE_INVALID,
188 G_TYPE_INT, &ret,
189 G_TYPE_INVALID);
190 CheckError();
191 if (ret)
192 LOG(ERROR) << "Bad return code " << ret << " from kwallet removeEntry";
193 } else {
194 // Otherwise update the entry in the wallet.
195 SetLoginsList(forms, form, wallet_handle);
196 }
197 }
198
199 void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request) {
200 PasswordFormList forms;
201
202 AutoLock l(kwallet_lock_);
203 int wallet_handle = WalletHandle();
204 if (wallet_handle != kInvalidKWalletHandle)
205 GetLoginsList(&forms, request->form, wallet_handle);
206
207 NotifyConsumer(request, forms);
208 }
209
210 void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms,
211 const PasswordForm& key,
212 int wallet_handle) {
213 // Is there an entry in the wallet?
214 gboolean has_entry = false;
215 dbus_g_proxy_call(proxy_, "hasEntry", &error_,
216 G_TYPE_INT, wallet_handle, // handle
217 G_TYPE_STRING, kKWalletFolder, // folder
218 G_TYPE_STRING, key.signon_realm.c_str(), // key
219 G_TYPE_STRING, kAppId, // appid
220 G_TYPE_INVALID,
221 G_TYPE_BOOLEAN, &has_entry,
222 G_TYPE_INVALID);
223
224 if (CheckError() || !has_entry)
225 return;
226
227 GArray* byte_array = NULL;
228 dbus_g_proxy_call(proxy_, "readEntry", &error_,
229 G_TYPE_INT, wallet_handle, // handle
230 G_TYPE_STRING, kKWalletFolder, // folder
231 G_TYPE_STRING, key.signon_realm.c_str(), // key
232 G_TYPE_STRING, kAppId, // appid
233 G_TYPE_INVALID,
234 DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
235 G_TYPE_INVALID);
236
237 if (CheckError() || !byte_array || !byte_array->len)
238 return;
239
240 Pickle pickle(byte_array->data, byte_array->len);
241 DeserializeValue(key, pickle, forms);
242 }
243
244 void PasswordStoreKWallet::SetLoginsList(const PasswordFormList& forms,
245 const PasswordForm& key,
246 int wallet_handle) {
247 Pickle value;
248 SerializeValue(forms, &value);
249
250 // Convert the pickled bytes to a GByteArray.
251 GArray* byte_array = g_array_sized_new(false, false, sizeof(char),
252 value.size());
253 g_array_append_vals(byte_array, value.data(), value.size());
254
255 // Make the call.
256 int ret = 0;
257 dbus_g_proxy_call(proxy_, "writeEntry", &error_,
258 G_TYPE_INT, wallet_handle, // handle
259 G_TYPE_STRING, kKWalletFolder, // folder
260 G_TYPE_STRING, key.signon_realm.c_str(), // key
261 DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value
262 G_TYPE_STRING, kAppId, // appid
263 G_TYPE_INVALID,
264 G_TYPE_INT, &ret,
265 G_TYPE_INVALID);
266 g_array_free(byte_array, true);
267
268 CheckError();
269 if (ret)
270 LOG(ERROR) << "Bad return code " << ret << " from kwallet writeEntry";
271 }
272
273 bool PasswordStoreKWallet::CompareForms(const PasswordForm& a,
274 const PasswordForm& b) {
275 return a.origin == b.origin &&
276 a.password_element == b.password_element &&
277 a.signon_realm == b.signon_realm &&
278 a.submit_element == b.submit_element &&
279 a.username_element == b.username_element &&
280 a.username_value == b.username_value;
281 }
282
283 void PasswordStoreKWallet::SerializeValue(const PasswordFormList& forms,
284 Pickle* pickle) {
285 pickle->WriteInt(forms.size());
286 for (PasswordFormList::const_iterator it = forms.begin() ;
287 it != forms.end() ; ++it) {
288 const PasswordForm* form = *it;
289 pickle->WriteInt(form->scheme);
290 pickle->WriteString(form->origin.spec());
291 pickle->WriteString(form->action.spec());
292 pickle->WriteWString(form->username_element);
293 pickle->WriteWString(form->username_value);
294 pickle->WriteWString(form->password_element);
295 pickle->WriteWString(form->password_value);
296 pickle->WriteWString(form->submit_element);
297 pickle->WriteBool(form->ssl_valid);
298 pickle->WriteBool(form->preferred);
299 pickle->WriteBool(form->blacklisted_by_user);
300 }
301 }
302
303 void PasswordStoreKWallet::DeserializeValue(const PasswordForm& key,
304 const Pickle& pickle,
305 PasswordFormList* forms) {
306 void* iter = NULL;
307
308 int count = 0;
309 pickle.ReadInt(&iter, &count);
310
311 for (int i = 0; i < count; ++i) {
312 PasswordForm* form = new PasswordForm();
313 form->signon_realm.assign(key.signon_realm);
314
315 pickle.ReadInt(&iter, reinterpret_cast<int*>(&form->scheme));
316 ReadGURL(pickle, &iter, &form->origin);
317 ReadGURL(pickle, &iter, &form->action);
318 pickle.ReadWString(&iter, &form->username_element);
319 pickle.ReadWString(&iter, &form->username_value);
320 pickle.ReadWString(&iter, &form->password_element);
321 pickle.ReadWString(&iter, &form->password_value);
322 pickle.ReadWString(&iter, &form->submit_element);
323 pickle.ReadBool(&iter, &form->ssl_valid);
324 pickle.ReadBool(&iter, &form->preferred);
325 pickle.ReadBool(&iter, &form->blacklisted_by_user);
326 forms->push_back(form);
327 }
328 }
329
330 void PasswordStoreKWallet::ReadGURL(const Pickle& pickle, void** iter,
331 GURL* url) {
332 string url_string;
333 pickle.ReadString(iter, &url_string);
334 *url = GURL(url_string);
335 }
336
337 bool PasswordStoreKWallet::CheckError() {
338 if (error_) {
339 LOG(ERROR) << "Failed to complete KWallet call: " << error_->message;
340 g_error_free(error_);
341 error_ = NULL;
342 return true;
343 }
344 return false;
345 }
346
347 int PasswordStoreKWallet::WalletHandle() {
348 // Open the wallet.
349 int handle = kInvalidKWalletHandle;
350 dbus_g_proxy_call(proxy_, "open", &error_,
351 G_TYPE_STRING, wallet_name_.c_str(), // wallet
352 G_TYPE_INT64, 0LL, // wid
353 G_TYPE_STRING, kAppId, // appid
354 G_TYPE_INVALID,
355 G_TYPE_INT, &handle,
356 G_TYPE_INVALID);
357 if (CheckError() || handle == kInvalidKWalletHandle)
358 return kInvalidKWalletHandle;
359
360 // Check if our folder exists.
361 gboolean has_folder = false;
362 dbus_g_proxy_call(proxy_, "hasFolder", &error_,
363 G_TYPE_INT, handle, // handle
364 G_TYPE_STRING, kKWalletFolder, // folder
365 G_TYPE_STRING, kAppId, // appid
366 G_TYPE_INVALID,
367 G_TYPE_BOOLEAN, &has_folder,
368 G_TYPE_INVALID);
369 if (CheckError())
370 return kInvalidKWalletHandle;
371
372 // Create it if it didn't.
373 if (!has_folder) {
374 gboolean success = false;
375 dbus_g_proxy_call(proxy_, "createFolder", &error_,
376 G_TYPE_INT, handle, // handle
377 G_TYPE_STRING, kKWalletFolder, // folder
378 G_TYPE_STRING, kAppId, // appid
379 G_TYPE_INVALID,
380 G_TYPE_BOOLEAN, &success,
381 G_TYPE_INVALID);
382 if (CheckError() || !success)
383 return kInvalidKWalletHandle;
384 }
385
386 return handle;
387 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698