Chromium Code Reviews| 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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 form->avatar_url = GURL(string_attr_map["avatar_url"]); | 155 form->avatar_url = GURL(string_attr_map["avatar_url"]); |
| 156 form->federation_url = GURL(string_attr_map["federation_url"]); | 156 form->federation_url = GURL(string_attr_map["federation_url"]); |
| 157 form->skip_zero_click = uint_attr_map["skip_zero_click"]; | 157 form->skip_zero_click = uint_attr_map["skip_zero_click"]; |
| 158 form->generation_upload_status = | 158 form->generation_upload_status = |
| 159 static_cast<PasswordForm::GenerationUploadStatus>( | 159 static_cast<PasswordForm::GenerationUploadStatus>( |
| 160 uint_attr_map["generation_upload_status"]); | 160 uint_attr_map["generation_upload_status"]); |
| 161 | 161 |
| 162 return form.Pass(); | 162 return form.Pass(); |
| 163 } | 163 } |
| 164 | 164 |
| 165 // Parse all the results from the given GList into a | 165 // Returns all the results from |found|. If not NULL, |lookup_form| is used to |
|
engedy
2015/02/25 15:17:48
Phrasing suggestion: Converts native credentials i
vabr (Chromium)
2015/03/09 10:56:18
Done.
engedy
2015/03/09 13:33:17
I am not sure, but the original comment mentioned
| |
| 166 // ScopedVector<autofill::PasswordForm>, and free the GList. PasswordForms are | 166 // filter out results -- only credentials with signon realms passing the PSL |
| 167 // allocated on the heap, and should be deleted by the consumer. If not NULL, | 167 // matching against |lookup_form->signon_realm| will be kept. PSL matched |
| 168 // |lookup_form| is used to filter out results -- only credentials with signon | 168 // results get their signon_realm, origin, and action rewritten to those of |
| 169 // realms passing the PSL matching against |lookup_form->signon_realm| will be | 169 // |lookup_form_|, with the original signon_realm saved into the result's |
| 170 // kept. PSL matched results get their signon_realm, origin, and action | 170 // original_signon_realm data member. |
| 171 // rewritten to those of |lookup_form_|, with the original signon_realm saved | 171 ScopedVector<autofill::PasswordForm> ConvertFormList( |
| 172 // into the result's original_signon_realm data member. | 172 GList* found, |
| 173 void ConvertFormList(GList* found, | 173 const PasswordForm* lookup_form) { |
| 174 const PasswordForm* lookup_form, | 174 ScopedVector<autofill::PasswordForm> forms; |
| 175 ScopedVector<autofill::PasswordForm>* forms) { | |
| 176 password_manager::PSLDomainMatchMetric psl_domain_match_metric = | 175 password_manager::PSLDomainMatchMetric psl_domain_match_metric = |
| 177 password_manager::PSL_DOMAIN_MATCH_NONE; | 176 password_manager::PSL_DOMAIN_MATCH_NONE; |
| 178 for (GList* element = g_list_first(found); element; | 177 for (GList* element = g_list_first(found); element; |
| 179 element = g_list_next(element)) { | 178 element = g_list_next(element)) { |
| 180 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); | 179 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); |
| 181 GnomeKeyringAttributeList* attrs = data->attributes; | 180 GnomeKeyringAttributeList* attrs = data->attributes; |
| 182 | 181 |
| 183 scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); | 182 scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); |
| 184 if (form) { | 183 if (form) { |
| 185 if (lookup_form && form->signon_realm != lookup_form->signon_realm) { | 184 if (lookup_form && form->signon_realm != lookup_form->signon_realm) { |
| 186 // This is not an exact match, we try PSL matching. | 185 // This is not an exact match, we try PSL matching. |
| 187 if (lookup_form->scheme != PasswordForm::SCHEME_HTML || | 186 if (lookup_form->scheme != PasswordForm::SCHEME_HTML || |
| 188 form->scheme != PasswordForm::SCHEME_HTML || | 187 form->scheme != PasswordForm::SCHEME_HTML || |
| 189 !(password_manager::IsPublicSuffixDomainMatch( | 188 !(password_manager::IsPublicSuffixDomainMatch( |
| 190 lookup_form->signon_realm, form->signon_realm))) { | 189 lookup_form->signon_realm, form->signon_realm))) { |
| 191 continue; | 190 continue; |
| 192 } | 191 } |
| 193 psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; | 192 psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; |
| 194 form->original_signon_realm = form->signon_realm; | 193 form->original_signon_realm = form->signon_realm; |
| 195 form->signon_realm = lookup_form->signon_realm; | 194 form->signon_realm = lookup_form->signon_realm; |
| 196 form->origin = lookup_form->origin; | 195 form->origin = lookup_form->origin; |
| 197 form->action = lookup_form->action; | 196 form->action = lookup_form->action; |
| 198 } | 197 } |
| 199 if (data->secret) { | 198 if (data->secret) { |
| 200 form->password_value = UTF8ToUTF16(data->secret); | 199 form->password_value = UTF8ToUTF16(data->secret); |
| 201 } else { | 200 } else { |
| 202 LOG(WARNING) << "Unable to access password from list element!"; | 201 LOG(WARNING) << "Unable to access password from list element!"; |
| 203 } | 202 } |
| 204 forms->push_back(form.release()); | 203 forms.push_back(form.release()); |
| 205 } else { | 204 } else { |
| 206 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; | 205 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; |
| 207 } | 206 } |
| 208 } | 207 } |
| 209 if (lookup_form) { | 208 if (lookup_form) { |
| 210 const GURL signon_realm(lookup_form->signon_realm); | 209 const GURL signon_realm(lookup_form->signon_realm); |
| 211 std::string registered_domain = | 210 std::string registered_domain = |
| 212 password_manager::GetRegistryControlledDomain(signon_realm); | 211 password_manager::GetRegistryControlledDomain(signon_realm); |
| 213 UMA_HISTOGRAM_ENUMERATION( | 212 UMA_HISTOGRAM_ENUMERATION( |
| 214 "PasswordManager.PslDomainMatchTriggering", | 213 "PasswordManager.PslDomainMatchTriggering", |
| 215 password_manager::ShouldPSLDomainMatchingApply(registered_domain) | 214 password_manager::ShouldPSLDomainMatchingApply(registered_domain) |
| 216 ? psl_domain_match_metric | 215 ? psl_domain_match_metric |
| 217 : password_manager::PSL_DOMAIN_MATCH_NOT_USED, | 216 : password_manager::PSL_DOMAIN_MATCH_NOT_USED, |
| 218 password_manager::PSL_DOMAIN_MATCH_COUNT); | 217 password_manager::PSL_DOMAIN_MATCH_COUNT); |
| 219 } | 218 } |
| 219 return forms.Pass(); | |
| 220 } | 220 } |
| 221 | 221 |
| 222 // Schema is analagous to the fields in PasswordForm. | 222 // Schema is analagous to the fields in PasswordForm. |
| 223 // TODO(gcasto): Adding 'form_data' would be nice, but we would need to | 223 // TODO(gcasto): Adding 'form_data' would be nice, but we would need to |
| 224 // serialize in a way that is guaranteed to not have any embedded NULLs. Pickle | 224 // serialize in a way that is guaranteed to not have any embedded NULLs. Pickle |
| 225 // doesn't make this guarantee, so we just don't serialize this field. Since | 225 // doesn't make this guarantee, so we just don't serialize this field. Since |
| 226 // it's only used to crowd source data collection it doesn't matter that much | 226 // it's only used to crowd source data collection it doesn't matter that much |
| 227 // if it's not available on this platform. | 227 // if it's not available on this platform. |
| 228 const GnomeKeyringPasswordSchema kGnomeSchema = { | 228 const GnomeKeyringPasswordSchema kGnomeSchema = { |
| 229 GNOME_KEYRING_ITEM_GENERIC_SECRET, { | 229 GNOME_KEYRING_ITEM_GENERIC_SECRET, { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 280 void UpdateLoginSearch(const PasswordForm& form, const char* app_string); | 280 void UpdateLoginSearch(const PasswordForm& form, const char* app_string); |
| 281 void RemoveLogin(const PasswordForm& form, const char* app_string); | 281 void RemoveLogin(const PasswordForm& form, const char* app_string); |
| 282 void GetLogins(const PasswordForm& form, const char* app_string); | 282 void GetLogins(const PasswordForm& form, const char* app_string); |
| 283 void GetLoginsList(uint32_t blacklisted_by_user, const char* app_string); | 283 void GetLoginsList(uint32_t blacklisted_by_user, const char* app_string); |
| 284 void GetAllLogins(const char* app_string); | 284 void GetAllLogins(const char* app_string); |
| 285 | 285 |
| 286 // Use after AddLogin, RemoveLogin. | 286 // Use after AddLogin, RemoveLogin. |
| 287 GnomeKeyringResult WaitResult(); | 287 GnomeKeyringResult WaitResult(); |
| 288 | 288 |
| 289 // Use after AddLoginSearch, UpdateLoginSearch, GetLogins, GetLoginsList, | 289 // Use after AddLoginSearch, UpdateLoginSearch, GetLogins, GetLoginsList, |
| 290 // GetAllLogins. | 290 // GetAllLogins. Replaces the content of |forms| with found logins. |
| 291 GnomeKeyringResult WaitResult(ScopedVector<autofill::PasswordForm>* forms); | 291 GnomeKeyringResult WaitResult(ScopedVector<autofill::PasswordForm>* forms); |
| 292 | 292 |
| 293 private: | 293 private: |
| 294 struct GnomeKeyringAttributeListFreeDeleter { | 294 struct GnomeKeyringAttributeListFreeDeleter { |
| 295 inline void operator()(void* list) const { | 295 inline void operator()(void* list) const { |
| 296 gnome_keyring_attribute_list_free( | 296 gnome_keyring_attribute_list_free( |
| 297 static_cast<GnomeKeyringAttributeList*>(list)); | 297 static_cast<GnomeKeyringAttributeList*>(list)); |
| 298 } | 298 } |
| 299 }; | 299 }; |
| 300 | 300 |
| 301 typedef scoped_ptr<GnomeKeyringAttributeList, | 301 typedef scoped_ptr<GnomeKeyringAttributeList, |
| 302 GnomeKeyringAttributeListFreeDeleter> ScopedAttributeList; | 302 GnomeKeyringAttributeListFreeDeleter> ScopedAttributeList; |
| 303 | 303 |
| 304 // Helper methods to abbreviate Gnome Keyring long API names. | 304 // Helper methods to abbreviate Gnome Keyring long API names. |
| 305 static void AppendString(ScopedAttributeList* list, | 305 static void AppendString(ScopedAttributeList* list, |
| 306 const char* name, | 306 const char* name, |
| 307 const char* value); | 307 const char* value); |
| 308 static void AppendString(ScopedAttributeList* list, | 308 static void AppendString(ScopedAttributeList* list, |
| 309 const char* name, | 309 const char* name, |
| 310 const std::string& value); | 310 const std::string& value); |
| 311 static void AppendUint32(ScopedAttributeList* list, | 311 static void AppendUint32(ScopedAttributeList* list, |
| 312 const char* name, | 312 const char* name, |
| 313 guint32 value); | 313 guint32 value); |
| 314 | 314 |
| 315 // All these callbacks are called on UI thread. | 315 // All these callbacks are called on UI thread. |
| 316 static void OnOperationDone(GnomeKeyringResult result, gpointer data); | 316 static void OnOperationDone(GnomeKeyringResult result, gpointer data); |
| 317 | 317 |
| 318 // This is marked as static, but acts on the GKRMethod instance pointed to by | |
|
engedy
2015/02/25 15:17:47
Phrasing suggestion: s/GKRMethod instance pointed
vabr (Chromium)
2015/03/09 10:56:18
Done.
| |
| 319 // |data|. Saves the result to |result_|. If the result is OK, overwrites | |
|
engedy
2015/02/25 15:17:47
Nit: |result|.
vabr (Chromium)
2015/03/09 10:56:18
Done.
| |
| 320 // |forms_| with the found credentials. Clears |forms_| otherwise. | |
| 318 static void OnOperationGetList(GnomeKeyringResult result, GList* list, | 321 static void OnOperationGetList(GnomeKeyringResult result, GList* list, |
| 319 gpointer data); | 322 gpointer data); |
| 320 | 323 |
| 321 base::WaitableEvent event_; | 324 base::WaitableEvent event_; |
| 322 GnomeKeyringResult result_; | 325 GnomeKeyringResult result_; |
| 323 ScopedVector<autofill::PasswordForm> forms_; | 326 ScopedVector<autofill::PasswordForm> forms_; |
| 324 // If the credential search is specified by a single form and needs to use PSL | 327 // If the credential search is specified by a single form and needs to use PSL |
| 325 // matching, then the specifying form is stored in |lookup_form_|. If PSL | 328 // matching, then the specifying form is stored in |lookup_form_|. If PSL |
| 326 // matching is used to find a result, then the results signon realm, origin | 329 // matching is used to find a result, then the results signon realm, origin |
| 327 // and action are stored are replaced by those of |lookup_form_|. | 330 // and action are stored are replaced by those of |lookup_form_|. |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 GnomeKeyringResult GKRMethod::WaitResult() { | 481 GnomeKeyringResult GKRMethod::WaitResult() { |
| 479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 480 event_.Wait(); | 483 event_.Wait(); |
| 481 return result_; | 484 return result_; |
| 482 } | 485 } |
| 483 | 486 |
| 484 GnomeKeyringResult GKRMethod::WaitResult( | 487 GnomeKeyringResult GKRMethod::WaitResult( |
| 485 ScopedVector<autofill::PasswordForm>* forms) { | 488 ScopedVector<autofill::PasswordForm>* forms) { |
| 486 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 487 event_.Wait(); | 490 event_.Wait(); |
| 488 if (forms->empty()) { | 491 forms->swap(forms_); |
|
vabr (Chromium)
2015/02/24 18:06:21
https://codereview.chromium.org/7712024 introduced
| |
| 489 // Normal case. Avoid extra allocation by swapping. | |
| 490 forms->swap(forms_); | |
| 491 } else { | |
| 492 // Rare case. Append forms_ to *forms. | |
| 493 forms->insert(forms->end(), forms_.begin(), forms_.end()); | |
| 494 forms_.weak_clear(); | |
| 495 } | |
| 496 return result_; | 492 return result_; |
| 497 } | 493 } |
| 498 | 494 |
| 499 // static | 495 // static |
| 500 void GKRMethod::AppendString(GKRMethod::ScopedAttributeList* list, | 496 void GKRMethod::AppendString(GKRMethod::ScopedAttributeList* list, |
| 501 const char* name, | 497 const char* name, |
| 502 const char* value) { | 498 const char* value) { |
| 503 gnome_keyring_attribute_list_append_string(list->get(), name, value); | 499 gnome_keyring_attribute_list_append_string(list->get(), name, value); |
| 504 } | 500 } |
| 505 | 501 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 524 method->event_.Signal(); | 520 method->event_.Signal(); |
| 525 } | 521 } |
| 526 | 522 |
| 527 // static | 523 // static |
| 528 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, | 524 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, |
| 529 gpointer data) { | 525 gpointer data) { |
| 530 GKRMethod* method = static_cast<GKRMethod*>(data); | 526 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 531 method->result_ = result; | 527 method->result_ = result; |
| 532 method->forms_.clear(); | 528 method->forms_.clear(); |
| 533 // |list| will be freed after this callback returns, so convert it now. | 529 // |list| will be freed after this callback returns, so convert it now. |
| 534 ConvertFormList(list, method->lookup_form_.get(), &method->forms_); | 530 if (result == GNOME_KEYRING_RESULT_OK) |
| 531 method->forms_ = ConvertFormList(list, method->lookup_form_.get()); | |
| 535 method->lookup_form_.reset(); | 532 method->lookup_form_.reset(); |
| 536 method->event_.Signal(); | 533 method->event_.Signal(); |
| 537 } | 534 } |
| 538 | 535 |
| 539 } // namespace | 536 } // namespace |
| 540 | 537 |
| 541 NativeBackendGnome::NativeBackendGnome(LocalProfileId id) | 538 NativeBackendGnome::NativeBackendGnome(LocalProfileId id) |
| 542 : profile_id_(id) { | 539 : profile_id_(id) { |
| 543 app_string_ = GetProfileSpecificAppString(); | 540 app_string_ = GetProfileSpecificAppString(); |
| 544 } | 541 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 710 | 707 |
| 711 bool NativeBackendGnome::GetBlacklistLogins( | 708 bool NativeBackendGnome::GetBlacklistLogins( |
| 712 ScopedVector<autofill::PasswordForm>* forms) { | 709 ScopedVector<autofill::PasswordForm>* forms) { |
| 713 return GetLoginsList(false, forms); | 710 return GetLoginsList(false, forms); |
| 714 } | 711 } |
| 715 | 712 |
| 716 bool NativeBackendGnome::GetLoginsList( | 713 bool NativeBackendGnome::GetLoginsList( |
| 717 bool autofillable, | 714 bool autofillable, |
| 718 ScopedVector<autofill::PasswordForm>* forms) { | 715 ScopedVector<autofill::PasswordForm>* forms) { |
| 719 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 717 forms->clear(); | |
|
engedy
2015/02/25 15:17:48
I think this is not needed, WaitResult will always
vabr (Chromium)
2015/03/09 10:56:18
Done.
| |
| 720 | 718 |
| 721 uint32_t blacklisted_by_user = !autofillable; | 719 uint32_t blacklisted_by_user = !autofillable; |
| 722 | 720 |
| 723 GKRMethod method; | 721 GKRMethod method; |
| 724 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 722 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 725 base::Bind(&GKRMethod::GetLoginsList, | 723 base::Bind(&GKRMethod::GetLoginsList, |
| 726 base::Unretained(&method), | 724 base::Unretained(&method), |
| 727 blacklisted_by_user, app_string_.c_str())); | 725 blacklisted_by_user, app_string_.c_str())); |
| 728 GnomeKeyringResult result = method.WaitResult(forms); | 726 GnomeKeyringResult result = method.WaitResult(forms); |
| 729 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | 727 if (result == GNOME_KEYRING_RESULT_NO_MATCH) |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 753 } | 751 } |
| 754 return true; | 752 return true; |
| 755 } | 753 } |
| 756 | 754 |
| 757 bool NativeBackendGnome::GetLoginsBetween( | 755 bool NativeBackendGnome::GetLoginsBetween( |
| 758 base::Time get_begin, | 756 base::Time get_begin, |
| 759 base::Time get_end, | 757 base::Time get_end, |
| 760 TimestampToCompare date_to_compare, | 758 TimestampToCompare date_to_compare, |
| 761 ScopedVector<autofill::PasswordForm>* forms) { | 759 ScopedVector<autofill::PasswordForm>* forms) { |
| 762 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 760 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 763 // We could walk the list and add items as we find them, but it is much | 761 // We could walk the list and add items as we find them, but it is much |
|
engedy
2015/02/25 15:17:48
Need to clear |forms| here.
vabr (Chromium)
2015/03/09 10:56:18
Done.
| |
| 764 // easier to build the list and then filter the results. | 762 // easier to build the list and then filter the results. |
| 765 ScopedVector<autofill::PasswordForm> all_forms; | 763 ScopedVector<autofill::PasswordForm> all_forms; |
| 766 if (!GetAllLogins(&all_forms)) | 764 if (!GetAllLogins(&all_forms)) |
| 767 return false; | 765 return false; |
| 768 | 766 |
| 769 base::Time autofill::PasswordForm::*date_member = | 767 base::Time autofill::PasswordForm::*date_member = |
| 770 date_to_compare == CREATION_TIMESTAMP | 768 date_to_compare == CREATION_TIMESTAMP |
| 771 ? &autofill::PasswordForm::date_created | 769 ? &autofill::PasswordForm::date_created |
| 772 : &autofill::PasswordForm::date_synced; | 770 : &autofill::PasswordForm::date_synced; |
| 773 for (auto& saved_form : all_forms) { | 771 for (auto& saved_form : all_forms) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 806 } | 804 } |
| 807 return ok; | 805 return ok; |
| 808 } | 806 } |
| 809 | 807 |
| 810 std::string NativeBackendGnome::GetProfileSpecificAppString() const { | 808 std::string NativeBackendGnome::GetProfileSpecificAppString() const { |
| 811 // Originally, the application string was always just "chrome" and used only | 809 // Originally, the application string was always just "chrome" and used only |
| 812 // so that we had *something* to search for since GNOME Keyring won't search | 810 // so that we had *something* to search for since GNOME Keyring won't search |
| 813 // for nothing. Now we use it to distinguish passwords for different profiles. | 811 // for nothing. Now we use it to distinguish passwords for different profiles. |
| 814 return base::StringPrintf("%s-%d", kGnomeKeyringAppString, profile_id_); | 812 return base::StringPrintf("%s-%d", kGnomeKeyringAppString, profile_id_); |
| 815 } | 813 } |
| OLD | NEW |