OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/password_manager/native_backend_gnome_x.h" | 5 #include "chrome/browser/password_manager/native_backend_gnome_x.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <gnome-keyring.h> | 8 #include <gnome-keyring.h> |
9 | 9 |
10 #include <map> | 10 #include <map> |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"]; | 136 form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"]; |
137 form->type = static_cast<PasswordForm::Type>(uint_attr_map["type"]); | 137 form->type = static_cast<PasswordForm::Type>(uint_attr_map["type"]); |
138 form->times_used = uint_attr_map["times_used"]; | 138 form->times_used = uint_attr_map["times_used"]; |
139 form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]); | 139 form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]); |
140 | 140 |
141 return form.Pass(); | 141 return form.Pass(); |
142 } | 142 } |
143 | 143 |
144 // Parse all the results from the given GList into a PasswordFormList, and free | 144 // Parse all the results from the given GList into a PasswordFormList, and free |
145 // the GList. PasswordForms are allocated on the heap, and should be deleted by | 145 // the GList. PasswordForms are allocated on the heap, and should be deleted by |
146 // the consumer. If not empty, |filter_by_signon_realm| is used to filter out | 146 // the consumer. If not NULL, |lookup_form| is used to filter out results -- |
147 // results -- only credentials with signon realms passing the PSL matching | 147 // only credentials with signon realms passing the PSL matching (done by |
148 // (done by |helper|) against |filter_by_signon_realm| will be kept. | 148 // |helper|) against |lookup_form->signon_realm| will be kept. PSL matched |
| 149 // results get their signon_realm, origin, and action rewritten to those of |
| 150 // |lookup_form_|, with the original signon_realm saved into the result's |
| 151 // original_signon_realm data member. |
149 void ConvertFormList(GList* found, | 152 void ConvertFormList(GList* found, |
150 const std::string& filter_by_signon_realm, | 153 const PasswordForm* lookup_form, |
151 const PSLMatchingHelper& helper, | 154 const PSLMatchingHelper& helper, |
152 NativeBackendGnome::PasswordFormList* forms) { | 155 NativeBackendGnome::PasswordFormList* forms) { |
153 PSLMatchingHelper::PSLDomainMatchMetric psl_domain_match_metric = | 156 PSLMatchingHelper::PSLDomainMatchMetric psl_domain_match_metric = |
154 PSLMatchingHelper::PSL_DOMAIN_MATCH_NONE; | 157 PSLMatchingHelper::PSL_DOMAIN_MATCH_NONE; |
155 for (GList* element = g_list_first(found); element != NULL; | 158 for (GList* element = g_list_first(found); element != NULL; |
156 element = g_list_next(element)) { | 159 element = g_list_next(element)) { |
157 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); | 160 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); |
158 GnomeKeyringAttributeList* attrs = data->attributes; | 161 GnomeKeyringAttributeList* attrs = data->attributes; |
159 | 162 |
160 scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); | 163 scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); |
161 if (form) { | 164 if (form) { |
162 if (!filter_by_signon_realm.empty() && | 165 if (lookup_form && form->signon_realm != lookup_form->signon_realm) { |
163 form->signon_realm != filter_by_signon_realm) { | |
164 // This is not an exact match, we try PSL matching. | 166 // This is not an exact match, we try PSL matching. |
165 if (!(PSLMatchingHelper::IsPublicSuffixDomainMatch( | 167 if (!(PSLMatchingHelper::IsPublicSuffixDomainMatch( |
166 filter_by_signon_realm, form->signon_realm))) { | 168 lookup_form->signon_realm, form->signon_realm))) { |
167 continue; | 169 continue; |
168 } | 170 } |
169 psl_domain_match_metric = PSLMatchingHelper::PSL_DOMAIN_MATCH_FOUND; | 171 psl_domain_match_metric = PSLMatchingHelper::PSL_DOMAIN_MATCH_FOUND; |
170 form->original_signon_realm = form->signon_realm; | 172 form->original_signon_realm = form->signon_realm; |
| 173 form->signon_realm = lookup_form->signon_realm; |
| 174 form->origin = lookup_form->origin; |
| 175 form->action = lookup_form->action; |
171 } | 176 } |
172 if (data->secret) { | 177 if (data->secret) { |
173 form->password_value = UTF8ToUTF16(data->secret); | 178 form->password_value = UTF8ToUTF16(data->secret); |
174 } else { | 179 } else { |
175 LOG(WARNING) << "Unable to access password from list element!"; | 180 LOG(WARNING) << "Unable to access password from list element!"; |
176 } | 181 } |
177 forms->push_back(form.release()); | 182 forms->push_back(form.release()); |
178 } else { | 183 } else { |
179 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; | 184 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; |
180 } | 185 } |
181 } | 186 } |
182 if (!filter_by_signon_realm.empty()) { | 187 if (lookup_form) { |
183 UMA_HISTOGRAM_ENUMERATION( | 188 UMA_HISTOGRAM_ENUMERATION( |
184 "PasswordManager.PslDomainMatchTriggering", | 189 "PasswordManager.PslDomainMatchTriggering", |
185 helper.IsMatchingEnabled() | 190 helper.IsMatchingEnabled() |
186 ? psl_domain_match_metric | 191 ? psl_domain_match_metric |
187 : PSLMatchingHelper::PSL_DOMAIN_MATCH_DISABLED, | 192 : PSLMatchingHelper::PSL_DOMAIN_MATCH_DISABLED, |
188 PSLMatchingHelper::PSL_DOMAIN_MATCH_COUNT); | 193 PSLMatchingHelper::PSL_DOMAIN_MATCH_COUNT); |
189 } | 194 } |
190 } | 195 } |
191 | 196 |
192 // Schema is analagous to the fields in PasswordForm. | 197 // Schema is analagous to the fields in PasswordForm. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 | 285 |
281 // All these callbacks are called on UI thread. | 286 // All these callbacks are called on UI thread. |
282 static void OnOperationDone(GnomeKeyringResult result, gpointer data); | 287 static void OnOperationDone(GnomeKeyringResult result, gpointer data); |
283 | 288 |
284 static void OnOperationGetList(GnomeKeyringResult result, GList* list, | 289 static void OnOperationGetList(GnomeKeyringResult result, GList* list, |
285 gpointer data); | 290 gpointer data); |
286 | 291 |
287 base::WaitableEvent event_; | 292 base::WaitableEvent event_; |
288 GnomeKeyringResult result_; | 293 GnomeKeyringResult result_; |
289 NativeBackendGnome::PasswordFormList forms_; | 294 NativeBackendGnome::PasswordFormList forms_; |
290 // Two additional arguments to OnOperationGetList: | 295 // If the credential search is specified by a single form and needs to use PSL |
291 // If the credential search is related to a particular form, | 296 // matching, then the specifying form is stored in |lookup_form_|. If PSL |
292 // |original_signon_realm_| contains the signon realm of that form. It is used | 297 // matching is used to find a result, then the results signon realm, origin |
293 // to filter the relevant results out of all the found ones. | 298 // and action are stored are replaced by those of |lookup_form_|. |
294 std::string original_signon_realm_; | 299 // Additionally, |lookup_form_->signon_realm| is also used to narrow down the |
| 300 // found logins to those which indeed PSL-match the look-up. And finally, |
| 301 // |lookup_form_| set to NULL means that PSL matching is not required. |
| 302 scoped_ptr<PasswordForm> lookup_form_; |
295 const PSLMatchingHelper helper_; | 303 const PSLMatchingHelper helper_; |
296 }; | 304 }; |
297 | 305 |
298 void GKRMethod::AddLogin(const PasswordForm& form, const char* app_string) { | 306 void GKRMethod::AddLogin(const PasswordForm& form, const char* app_string) { |
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
300 time_t date_created = form.date_created.ToTimeT(); | 308 time_t date_created = form.date_created.ToTimeT(); |
301 // If we are asked to save a password with 0 date, use the current time. | 309 // If we are asked to save a password with 0 date, use the current time. |
302 // We don't want to actually save passwords as though on January 1, 1970. | 310 // We don't want to actually save passwords as though on January 1, 1970. |
303 if (!date_created) | 311 if (!date_created) |
304 date_created = time(NULL); | 312 date_created = time(NULL); |
(...skipping 19 matching lines...) Expand all Loading... |
324 "type", form.type, | 332 "type", form.type, |
325 "times_used", form.times_used, | 333 "times_used", form.times_used, |
326 "scheme", form.scheme, | 334 "scheme", form.scheme, |
327 "application", app_string, | 335 "application", app_string, |
328 NULL); | 336 NULL); |
329 } | 337 } |
330 | 338 |
331 void GKRMethod::AddLoginSearch(const PasswordForm& form, | 339 void GKRMethod::AddLoginSearch(const PasswordForm& form, |
332 const char* app_string) { | 340 const char* app_string) { |
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
334 original_signon_realm_ = form.signon_realm; | 342 lookup_form_.reset(NULL); |
335 // Search GNOME Keyring for matching passwords to update. | 343 // Search GNOME Keyring for matching passwords to update. |
336 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); | 344 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); |
337 AppendString(&attrs, "origin_url", form.origin.spec()); | 345 AppendString(&attrs, "origin_url", form.origin.spec()); |
338 AppendString(&attrs, "username_element", UTF16ToUTF8(form.username_element)); | 346 AppendString(&attrs, "username_element", UTF16ToUTF8(form.username_element)); |
339 AppendString(&attrs, "username_value", UTF16ToUTF8(form.username_value)); | 347 AppendString(&attrs, "username_value", UTF16ToUTF8(form.username_value)); |
340 AppendString(&attrs, "password_element", UTF16ToUTF8(form.password_element)); | 348 AppendString(&attrs, "password_element", UTF16ToUTF8(form.password_element)); |
341 AppendString(&attrs, "submit_element", UTF16ToUTF8(form.submit_element)); | 349 AppendString(&attrs, "submit_element", UTF16ToUTF8(form.submit_element)); |
342 AppendString(&attrs, "signon_realm", form.signon_realm); | 350 AppendString(&attrs, "signon_realm", form.signon_realm); |
343 AppendString(&attrs, "application", app_string); | 351 AppendString(&attrs, "application", app_string); |
344 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, | 352 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, |
345 attrs.get(), | 353 attrs.get(), |
346 OnOperationGetList, | 354 OnOperationGetList, |
347 /*data=*/this, | 355 /*data=*/this, |
348 /*destroy_data=*/NULL); | 356 /*destroy_data=*/NULL); |
349 } | 357 } |
350 | 358 |
351 void GKRMethod::UpdateLoginSearch(const PasswordForm& form, | 359 void GKRMethod::UpdateLoginSearch(const PasswordForm& form, |
352 const char* app_string) { | 360 const char* app_string) { |
353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
354 original_signon_realm_ = form.signon_realm; | 362 lookup_form_.reset(NULL); |
355 // Search GNOME Keyring for matching passwords to update. | 363 // Search GNOME Keyring for matching passwords to update. |
356 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); | 364 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); |
357 AppendString(&attrs, "origin_url", form.origin.spec()); | 365 AppendString(&attrs, "origin_url", form.origin.spec()); |
358 AppendString(&attrs, "username_element", UTF16ToUTF8(form.username_element)); | 366 AppendString(&attrs, "username_element", UTF16ToUTF8(form.username_element)); |
359 AppendString(&attrs, "username_value", UTF16ToUTF8(form.username_value)); | 367 AppendString(&attrs, "username_value", UTF16ToUTF8(form.username_value)); |
360 AppendString(&attrs, "password_element", UTF16ToUTF8(form.password_element)); | 368 AppendString(&attrs, "password_element", UTF16ToUTF8(form.password_element)); |
361 AppendString(&attrs, "signon_realm", form.signon_realm); | 369 AppendString(&attrs, "signon_realm", form.signon_realm); |
362 AppendString(&attrs, "application", app_string); | 370 AppendString(&attrs, "application", app_string); |
363 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, | 371 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, |
364 attrs.get(), | 372 attrs.get(), |
(...skipping 16 matching lines...) Expand all Loading... |
381 "username_value", UTF16ToUTF8(form.username_value).c_str(), | 389 "username_value", UTF16ToUTF8(form.username_value).c_str(), |
382 "password_element", UTF16ToUTF8(form.password_element).c_str(), | 390 "password_element", UTF16ToUTF8(form.password_element).c_str(), |
383 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), | 391 "submit_element", UTF16ToUTF8(form.submit_element).c_str(), |
384 "signon_realm", form.signon_realm.c_str(), | 392 "signon_realm", form.signon_realm.c_str(), |
385 "application", app_string, | 393 "application", app_string, |
386 NULL); | 394 NULL); |
387 } | 395 } |
388 | 396 |
389 void GKRMethod::GetLogins(const PasswordForm& form, const char* app_string) { | 397 void GKRMethod::GetLogins(const PasswordForm& form, const char* app_string) { |
390 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
391 original_signon_realm_ = form.signon_realm; | 399 lookup_form_.reset(new PasswordForm(form)); |
392 // Search GNOME Keyring for matching passwords. | 400 // Search GNOME Keyring for matching passwords. |
393 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); | 401 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); |
394 if (!helper_.ShouldPSLDomainMatchingApply( | 402 if (!helper_.ShouldPSLDomainMatchingApply( |
395 PSLMatchingHelper::GetRegistryControlledDomain( | 403 PSLMatchingHelper::GetRegistryControlledDomain( |
396 GURL(form.signon_realm)))) { | 404 GURL(form.signon_realm)))) { |
397 AppendString(&attrs, "signon_realm", form.signon_realm); | 405 AppendString(&attrs, "signon_realm", form.signon_realm); |
398 } | 406 } |
399 AppendString(&attrs, "application", app_string); | 407 AppendString(&attrs, "application", app_string); |
400 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, | 408 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, |
401 attrs.get(), | 409 attrs.get(), |
402 OnOperationGetList, | 410 OnOperationGetList, |
403 /*data=*/this, | 411 /*data=*/this, |
404 /*destroy_data=*/NULL); | 412 /*destroy_data=*/NULL); |
405 } | 413 } |
406 | 414 |
407 void GKRMethod::GetLoginsList(uint32_t blacklisted_by_user, | 415 void GKRMethod::GetLoginsList(uint32_t blacklisted_by_user, |
408 const char* app_string) { | 416 const char* app_string) { |
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
410 original_signon_realm_.clear(); | 418 lookup_form_.reset(NULL); |
411 // Search GNOME Keyring for matching passwords. | 419 // Search GNOME Keyring for matching passwords. |
412 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); | 420 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); |
413 AppendUint32(&attrs, "blacklisted_by_user", blacklisted_by_user); | 421 AppendUint32(&attrs, "blacklisted_by_user", blacklisted_by_user); |
414 AppendString(&attrs, "application", app_string); | 422 AppendString(&attrs, "application", app_string); |
415 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, | 423 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, |
416 attrs.get(), | 424 attrs.get(), |
417 OnOperationGetList, | 425 OnOperationGetList, |
418 /*data=*/this, | 426 /*data=*/this, |
419 /*destroy_data=*/NULL); | 427 /*destroy_data=*/NULL); |
420 } | 428 } |
421 | 429 |
422 void GKRMethod::GetAllLogins(const char* app_string) { | 430 void GKRMethod::GetAllLogins(const char* app_string) { |
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
424 original_signon_realm_.clear(); | 432 lookup_form_.reset(NULL); |
425 // We need to search for something, otherwise we get no results - so | 433 // We need to search for something, otherwise we get no results - so |
426 // we search for the fixed application string. | 434 // we search for the fixed application string. |
427 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); | 435 ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); |
428 AppendString(&attrs, "application", app_string); | 436 AppendString(&attrs, "application", app_string); |
429 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, | 437 gnome_keyring_find_items(GNOME_KEYRING_ITEM_GENERIC_SECRET, |
430 attrs.get(), | 438 attrs.get(), |
431 OnOperationGetList, | 439 OnOperationGetList, |
432 /*data=*/this, | 440 /*data=*/this, |
433 /*destroy_data=*/NULL); | 441 /*destroy_data=*/NULL); |
434 } | 442 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 } | 490 } |
483 | 491 |
484 // static | 492 // static |
485 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, | 493 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, |
486 gpointer data) { | 494 gpointer data) { |
487 GKRMethod* method = static_cast<GKRMethod*>(data); | 495 GKRMethod* method = static_cast<GKRMethod*>(data); |
488 method->result_ = result; | 496 method->result_ = result; |
489 method->forms_.clear(); | 497 method->forms_.clear(); |
490 // |list| will be freed after this callback returns, so convert it now. | 498 // |list| will be freed after this callback returns, so convert it now. |
491 ConvertFormList( | 499 ConvertFormList( |
492 list, method->original_signon_realm_, method->helper_, &method->forms_); | 500 list, method->lookup_form_.get(), method->helper_, &method->forms_); |
493 method->original_signon_realm_.clear(); | 501 method->lookup_form_.reset(NULL); |
494 method->event_.Signal(); | 502 method->event_.Signal(); |
495 } | 503 } |
496 | 504 |
497 } // namespace | 505 } // namespace |
498 | 506 |
499 NativeBackendGnome::NativeBackendGnome(LocalProfileId id) | 507 NativeBackendGnome::NativeBackendGnome(LocalProfileId id) |
500 : profile_id_(id) { | 508 : profile_id_(id) { |
501 app_string_ = GetProfileSpecificAppString(); | 509 app_string_ = GetProfileSpecificAppString(); |
502 } | 510 } |
503 | 511 |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 } | 736 } |
729 return true; | 737 return true; |
730 } | 738 } |
731 | 739 |
732 std::string NativeBackendGnome::GetProfileSpecificAppString() const { | 740 std::string NativeBackendGnome::GetProfileSpecificAppString() const { |
733 // Originally, the application string was always just "chrome" and used only | 741 // Originally, the application string was always just "chrome" and used only |
734 // so that we had *something* to search for since GNOME Keyring won't search | 742 // so that we had *something* to search for since GNOME Keyring won't search |
735 // for nothing. Now we use it to distinguish passwords for different profiles. | 743 // for nothing. Now we use it to distinguish passwords for different profiles. |
736 return base::StringPrintf("%s-%d", kGnomeKeyringAppString, profile_id_); | 744 return base::StringPrintf("%s-%d", kGnomeKeyringAppString, profile_id_); |
737 } | 745 } |
OLD | NEW |