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 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 base::StringToInt64(string_attr_map["date_synced"], &date_synced); | 152 base::StringToInt64(string_attr_map["date_synced"], &date_synced); |
| 153 form->date_synced = base::Time::FromInternalValue(date_synced); | 153 form->date_synced = base::Time::FromInternalValue(date_synced); |
| 154 form->display_name = UTF8ToUTF16(string_attr_map["display_name"]); | 154 form->display_name = UTF8ToUTF16(string_attr_map["display_name"]); |
| 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 | 158 |
| 159 return form.Pass(); | 159 return form.Pass(); |
| 160 } | 160 } |
| 161 | 161 |
| 162 // Parse all the results from the given GList into a | 162 // Returns all the results from |found|. If not NULL, |lookup_form| is used to |
| 163 // ScopedVector<autofill::PasswordForm>, and free the GList. PasswordForms are | 163 // filter out results -- only credentials with signon realms passing the PSL |
| 164 // allocated on the heap, and should be deleted by the consumer. If not NULL, | 164 // matching against |lookup_form->signon_realm| will be kept. PSL matched |
| 165 // |lookup_form| is used to filter out results -- only credentials with signon | 165 // results get their signon_realm, origin, and action rewritten to those of |
| 166 // realms passing the PSL matching against |lookup_form->signon_realm| will be | 166 // |lookup_form_|, with the original signon_realm saved into the result's |
| 167 // kept. PSL matched results get their signon_realm, origin, and action | 167 // original_signon_realm data member. |
| 168 // rewritten to those of |lookup_form_|, with the original signon_realm saved | 168 ScopedVector<autofill::PasswordForm> ConvertFormList( |
| 169 // into the result's original_signon_realm data member. | 169 GList* found, |
| 170 void ConvertFormList(GList* found, | 170 const PasswordForm* lookup_form) { |
| 171 const PasswordForm* lookup_form, | 171 ScopedVector<autofill::PasswordForm> forms; |
| 172 ScopedVector<autofill::PasswordForm>* forms) { | |
| 173 password_manager::PSLDomainMatchMetric psl_domain_match_metric = | 172 password_manager::PSLDomainMatchMetric psl_domain_match_metric = |
| 174 password_manager::PSL_DOMAIN_MATCH_NONE; | 173 password_manager::PSL_DOMAIN_MATCH_NONE; |
| 175 for (GList* element = g_list_first(found); element != NULL; | 174 for (GList* element = g_list_first(found); element != NULL; |
| 176 element = g_list_next(element)) { | 175 element = g_list_next(element)) { |
| 177 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); | 176 GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); |
| 178 GnomeKeyringAttributeList* attrs = data->attributes; | 177 GnomeKeyringAttributeList* attrs = data->attributes; |
| 179 | 178 |
| 180 scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); | 179 scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); |
| 181 if (form) { | 180 if (form) { |
| 182 if (lookup_form && form->signon_realm != lookup_form->signon_realm) { | 181 if (lookup_form && form->signon_realm != lookup_form->signon_realm) { |
| 183 // This is not an exact match, we try PSL matching. | 182 // This is not an exact match, we try PSL matching. |
| 184 if (lookup_form->scheme != PasswordForm::SCHEME_HTML || | 183 if (lookup_form->scheme != PasswordForm::SCHEME_HTML || |
| 185 form->scheme != PasswordForm::SCHEME_HTML || | 184 form->scheme != PasswordForm::SCHEME_HTML || |
| 186 !(password_manager::IsPublicSuffixDomainMatch( | 185 !(password_manager::IsPublicSuffixDomainMatch( |
| 187 lookup_form->signon_realm, form->signon_realm))) { | 186 lookup_form->signon_realm, form->signon_realm))) { |
| 188 continue; | 187 continue; |
| 189 } | 188 } |
| 190 psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; | 189 psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; |
| 191 form->original_signon_realm = form->signon_realm; | 190 form->original_signon_realm = form->signon_realm; |
| 192 form->signon_realm = lookup_form->signon_realm; | 191 form->signon_realm = lookup_form->signon_realm; |
| 193 form->origin = lookup_form->origin; | 192 form->origin = lookup_form->origin; |
| 194 form->action = lookup_form->action; | 193 form->action = lookup_form->action; |
| 195 } | 194 } |
| 196 if (data->secret) { | 195 if (data->secret) { |
| 197 form->password_value = UTF8ToUTF16(data->secret); | 196 form->password_value = UTF8ToUTF16(data->secret); |
| 198 } else { | 197 } else { |
| 199 LOG(WARNING) << "Unable to access password from list element!"; | 198 LOG(WARNING) << "Unable to access password from list element!"; |
| 200 } | 199 } |
| 201 forms->push_back(form.release()); | 200 forms.push_back(form.release()); |
| 202 } else { | 201 } else { |
| 203 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; | 202 LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; |
| 204 } | 203 } |
| 205 } | 204 } |
| 206 if (lookup_form) { | 205 if (lookup_form) { |
| 207 const GURL signon_realm(lookup_form->signon_realm); | 206 const GURL signon_realm(lookup_form->signon_realm); |
| 208 std::string registered_domain = | 207 std::string registered_domain = |
| 209 password_manager::GetRegistryControlledDomain(signon_realm); | 208 password_manager::GetRegistryControlledDomain(signon_realm); |
| 210 UMA_HISTOGRAM_ENUMERATION( | 209 UMA_HISTOGRAM_ENUMERATION( |
| 211 "PasswordManager.PslDomainMatchTriggering", | 210 "PasswordManager.PslDomainMatchTriggering", |
| 212 password_manager::ShouldPSLDomainMatchingApply(registered_domain) | 211 password_manager::ShouldPSLDomainMatchingApply(registered_domain) |
| 213 ? psl_domain_match_metric | 212 ? psl_domain_match_metric |
| 214 : password_manager::PSL_DOMAIN_MATCH_NOT_USED, | 213 : password_manager::PSL_DOMAIN_MATCH_NOT_USED, |
| 215 password_manager::PSL_DOMAIN_MATCH_COUNT); | 214 password_manager::PSL_DOMAIN_MATCH_COUNT); |
| 216 } | 215 } |
| 216 return forms.Pass(); | |
| 217 } | 217 } |
| 218 | 218 |
| 219 // Schema is analagous to the fields in PasswordForm. | 219 // Schema is analagous to the fields in PasswordForm. |
| 220 // TODO(gcasto): Adding 'form_data' would be nice, but we would need to | 220 // TODO(gcasto): Adding 'form_data' would be nice, but we would need to |
| 221 // serialize in a way that is guaranteed to not have any embedded NULLs. Pickle | 221 // serialize in a way that is guaranteed to not have any embedded NULLs. Pickle |
| 222 // doesn't make this guarantee, so we just don't serialize this field. Since | 222 // doesn't make this guarantee, so we just don't serialize this field. Since |
| 223 // it's only used to crowd source data collection it doesn't matter that much | 223 // it's only used to crowd source data collection it doesn't matter that much |
| 224 // if it's not available on this platform. | 224 // if it's not available on this platform. |
| 225 const GnomeKeyringPasswordSchema kGnomeSchema = { | 225 const GnomeKeyringPasswordSchema kGnomeSchema = { |
| 226 GNOME_KEYRING_ITEM_GENERIC_SECRET, { | 226 GNOME_KEYRING_ITEM_GENERIC_SECRET, { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 void UpdateLoginSearch(const PasswordForm& form, const char* app_string); | 276 void UpdateLoginSearch(const PasswordForm& form, const char* app_string); |
| 277 void RemoveLogin(const PasswordForm& form, const char* app_string); | 277 void RemoveLogin(const PasswordForm& form, const char* app_string); |
| 278 void GetLogins(const PasswordForm& form, const char* app_string); | 278 void GetLogins(const PasswordForm& form, const char* app_string); |
| 279 void GetLoginsList(uint32_t blacklisted_by_user, const char* app_string); | 279 void GetLoginsList(uint32_t blacklisted_by_user, const char* app_string); |
| 280 void GetAllLogins(const char* app_string); | 280 void GetAllLogins(const char* app_string); |
| 281 | 281 |
| 282 // Use after AddLogin, RemoveLogin. | 282 // Use after AddLogin, RemoveLogin. |
| 283 GnomeKeyringResult WaitResult(); | 283 GnomeKeyringResult WaitResult(); |
| 284 | 284 |
| 285 // Use after AddLoginSearch, UpdateLoginSearch, GetLogins, GetLoginsList, | 285 // Use after AddLoginSearch, UpdateLoginSearch, GetLogins, GetLoginsList, |
| 286 // GetAllLogins. | 286 // GetAllLogins. Replaces the content of |forms| with found logins. |
| 287 GnomeKeyringResult WaitResult(ScopedVector<autofill::PasswordForm>* forms); | 287 GnomeKeyringResult WaitResult(ScopedVector<autofill::PasswordForm>* forms); |
| 288 | 288 |
| 289 private: | 289 private: |
| 290 struct GnomeKeyringAttributeListFreeDeleter { | 290 struct GnomeKeyringAttributeListFreeDeleter { |
| 291 inline void operator()(void* list) const { | 291 inline void operator()(void* list) const { |
| 292 gnome_keyring_attribute_list_free( | 292 gnome_keyring_attribute_list_free( |
| 293 static_cast<GnomeKeyringAttributeList*>(list)); | 293 static_cast<GnomeKeyringAttributeList*>(list)); |
| 294 } | 294 } |
| 295 }; | 295 }; |
| 296 | 296 |
| 297 typedef scoped_ptr<GnomeKeyringAttributeList, | 297 typedef scoped_ptr<GnomeKeyringAttributeList, |
| 298 GnomeKeyringAttributeListFreeDeleter> ScopedAttributeList; | 298 GnomeKeyringAttributeListFreeDeleter> ScopedAttributeList; |
| 299 | 299 |
| 300 // Helper methods to abbreviate Gnome Keyring long API names. | 300 // Helper methods to abbreviate Gnome Keyring long API names. |
| 301 static void AppendString(ScopedAttributeList* list, | 301 static void AppendString(ScopedAttributeList* list, |
| 302 const char* name, | 302 const char* name, |
| 303 const char* value); | 303 const char* value); |
| 304 static void AppendString(ScopedAttributeList* list, | 304 static void AppendString(ScopedAttributeList* list, |
| 305 const char* name, | 305 const char* name, |
| 306 const std::string& value); | 306 const std::string& value); |
| 307 static void AppendUint32(ScopedAttributeList* list, | 307 static void AppendUint32(ScopedAttributeList* list, |
| 308 const char* name, | 308 const char* name, |
| 309 guint32 value); | 309 guint32 value); |
| 310 | 310 |
| 311 // All these callbacks are called on UI thread. | 311 // All these callbacks are called on UI thread. |
| 312 static void OnOperationDone(GnomeKeyringResult result, gpointer data); | 312 static void OnOperationDone(GnomeKeyringResult result, gpointer data); |
| 313 | 313 |
| 314 // This is marked as static, but acts on the GKRMethod instance pointed to by | |
| 315 // |data|. Saves the result to |result_|. If the result is OK, overwrites | |
| 316 // |forms_| with the found credentials. Clears |forms_| otherwise. | |
| 314 static void OnOperationGetList(GnomeKeyringResult result, GList* list, | 317 static void OnOperationGetList(GnomeKeyringResult result, GList* list, |
| 315 gpointer data); | 318 gpointer data); |
| 316 | 319 |
| 317 base::WaitableEvent event_; | 320 base::WaitableEvent event_; |
| 318 GnomeKeyringResult result_; | 321 GnomeKeyringResult result_; |
| 319 ScopedVector<autofill::PasswordForm> forms_; | 322 ScopedVector<autofill::PasswordForm> forms_; |
| 320 // If the credential search is specified by a single form and needs to use PSL | 323 // If the credential search is specified by a single form and needs to use PSL |
| 321 // matching, then the specifying form is stored in |lookup_form_|. If PSL | 324 // matching, then the specifying form is stored in |lookup_form_|. If PSL |
| 322 // matching is used to find a result, then the results signon realm, origin | 325 // matching is used to find a result, then the results signon realm, origin |
| 323 // and action are stored are replaced by those of |lookup_form_|. | 326 // and action are stored are replaced by those of |lookup_form_|. |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 GnomeKeyringResult GKRMethod::WaitResult() { | 476 GnomeKeyringResult GKRMethod::WaitResult() { |
| 474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 475 event_.Wait(); | 478 event_.Wait(); |
| 476 return result_; | 479 return result_; |
| 477 } | 480 } |
| 478 | 481 |
| 479 GnomeKeyringResult GKRMethod::WaitResult( | 482 GnomeKeyringResult GKRMethod::WaitResult( |
| 480 ScopedVector<autofill::PasswordForm>* forms) { | 483 ScopedVector<autofill::PasswordForm>* forms) { |
| 481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 482 event_.Wait(); | 485 event_.Wait(); |
| 483 if (forms->empty()) { | 486 forms->swap(forms_); |
|
vabr (Chromium)
2015/02/11 17:19:14
https://codereview.chromium.org/7712024 introduced
| |
| 484 // Normal case. Avoid extra allocation by swapping. | |
| 485 forms->swap(forms_); | |
| 486 } else { | |
| 487 // Rare case. Append forms_ to *forms. | |
| 488 forms->insert(forms->end(), forms_.begin(), forms_.end()); | |
| 489 forms_.weak_clear(); | |
| 490 } | |
| 491 return result_; | 487 return result_; |
| 492 } | 488 } |
| 493 | 489 |
| 494 // static | 490 // static |
| 495 void GKRMethod::AppendString(GKRMethod::ScopedAttributeList* list, | 491 void GKRMethod::AppendString(GKRMethod::ScopedAttributeList* list, |
| 496 const char* name, | 492 const char* name, |
| 497 const char* value) { | 493 const char* value) { |
| 498 gnome_keyring_attribute_list_append_string(list->get(), name, value); | 494 gnome_keyring_attribute_list_append_string(list->get(), name, value); |
| 499 } | 495 } |
| 500 | 496 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 519 method->event_.Signal(); | 515 method->event_.Signal(); |
| 520 } | 516 } |
| 521 | 517 |
| 522 // static | 518 // static |
| 523 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, | 519 void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, |
| 524 gpointer data) { | 520 gpointer data) { |
| 525 GKRMethod* method = static_cast<GKRMethod*>(data); | 521 GKRMethod* method = static_cast<GKRMethod*>(data); |
| 526 method->result_ = result; | 522 method->result_ = result; |
| 527 method->forms_.clear(); | 523 method->forms_.clear(); |
| 528 // |list| will be freed after this callback returns, so convert it now. | 524 // |list| will be freed after this callback returns, so convert it now. |
| 529 ConvertFormList(list, method->lookup_form_.get(), &method->forms_); | 525 if (result == GNOME_KEYRING_RESULT_OK) |
| 526 method->forms_ = ConvertFormList(list, method->lookup_form_.get()); | |
| 530 method->lookup_form_.reset(NULL); | 527 method->lookup_form_.reset(NULL); |
| 531 method->event_.Signal(); | 528 method->event_.Signal(); |
| 532 } | 529 } |
| 533 | 530 |
| 534 } // namespace | 531 } // namespace |
| 535 | 532 |
| 536 NativeBackendGnome::NativeBackendGnome(LocalProfileId id) | 533 NativeBackendGnome::NativeBackendGnome(LocalProfileId id) |
| 537 : profile_id_(id) { | 534 : profile_id_(id) { |
| 538 app_string_ = GetProfileSpecificAppString(); | 535 app_string_ = GetProfileSpecificAppString(); |
| 539 } | 536 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 705 | 702 |
| 706 bool NativeBackendGnome::GetBlacklistLogins( | 703 bool NativeBackendGnome::GetBlacklistLogins( |
| 707 ScopedVector<autofill::PasswordForm>* forms) { | 704 ScopedVector<autofill::PasswordForm>* forms) { |
| 708 return GetLoginsList(false, forms); | 705 return GetLoginsList(false, forms); |
| 709 } | 706 } |
| 710 | 707 |
| 711 bool NativeBackendGnome::GetLoginsList( | 708 bool NativeBackendGnome::GetLoginsList( |
| 712 bool autofillable, | 709 bool autofillable, |
| 713 ScopedVector<autofill::PasswordForm>* forms) { | 710 ScopedVector<autofill::PasswordForm>* forms) { |
| 714 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 711 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| 712 forms->clear(); | |
| 715 | 713 |
| 716 uint32_t blacklisted_by_user = !autofillable; | 714 uint32_t blacklisted_by_user = !autofillable; |
| 717 | 715 |
| 718 GKRMethod method; | 716 GKRMethod method; |
| 719 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 717 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 720 base::Bind(&GKRMethod::GetLoginsList, | 718 base::Bind(&GKRMethod::GetLoginsList, |
| 721 base::Unretained(&method), | 719 base::Unretained(&method), |
| 722 blacklisted_by_user, app_string_.c_str())); | 720 blacklisted_by_user, app_string_.c_str())); |
| 723 GnomeKeyringResult result = method.WaitResult(forms); | 721 GnomeKeyringResult result = method.WaitResult(forms); |
| 724 if (result == GNOME_KEYRING_RESULT_NO_MATCH) | 722 if (result == GNOME_KEYRING_RESULT_NO_MATCH) |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 801 } | 799 } |
| 802 return ok; | 800 return ok; |
| 803 } | 801 } |
| 804 | 802 |
| 805 std::string NativeBackendGnome::GetProfileSpecificAppString() const { | 803 std::string NativeBackendGnome::GetProfileSpecificAppString() const { |
| 806 // Originally, the application string was always just "chrome" and used only | 804 // Originally, the application string was always just "chrome" and used only |
| 807 // so that we had *something* to search for since GNOME Keyring won't search | 805 // so that we had *something* to search for since GNOME Keyring won't search |
| 808 // for nothing. Now we use it to distinguish passwords for different profiles. | 806 // for nothing. Now we use it to distinguish passwords for different profiles. |
| 809 return base::StringPrintf("%s-%d", kGnomeKeyringAppString, profile_id_); | 807 return base::StringPrintf("%s-%d", kGnomeKeyringAppString, profile_id_); |
| 810 } | 808 } |
| OLD | NEW |