| 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 |