| Index: chrome/browser/password_manager/native_backend_gnome_x.cc
|
| diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
|
| index dbf617bc215819bb91f2fb2be9bcdb805836ea0f..124ae40bb8055255ecc5d30b132b3c3ccd2c5c41 100644
|
| --- a/chrome/browser/password_manager/native_backend_gnome_x.cc
|
| +++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
|
| @@ -4,13 +4,12 @@
|
|
|
| #include "chrome/browser/password_manager/native_backend_gnome_x.h"
|
|
|
| -#if defined(DLOPEN_GNOME_KEYRING)
|
| -#include <dlfcn.h>
|
| -#endif
|
| -
|
| #include <map>
|
| #include <string>
|
|
|
| +#include <dbus/dbus-glib.h>
|
| +#include <dlfcn.h>
|
| +
|
| #include "base/logging.h"
|
| #include "base/string_util.h"
|
| #include "base/time.h"
|
| @@ -19,6 +18,8 @@
|
|
|
| using webkit_glue::PasswordForm;
|
|
|
| +namespace {
|
| +
|
| /* Many of the gnome_keyring_* functions use variable arguments, which makes
|
| * them difficult if not impossible to wrap in C. Therefore, we want the
|
| * actual uses below to either call the functions directly (if we are linking
|
| @@ -33,53 +34,43 @@ using webkit_glue::PasswordForm;
|
|
|
| #if defined(DLOPEN_GNOME_KEYRING)
|
|
|
| -namespace {
|
| -
|
| -gboolean (*wrap_gnome_keyring_is_available)();
|
| -GnomeKeyringResult (*wrap_gnome_keyring_store_password_sync)( // NOLINT
|
| - const GnomeKeyringPasswordSchema* schema, const gchar* keyring,
|
| - const gchar* display_name, const gchar* password, ...);
|
| -GnomeKeyringResult (*wrap_gnome_keyring_delete_password_sync)( // NOLINT
|
| - const GnomeKeyringPasswordSchema* schema, ...);
|
| -GnomeKeyringResult (*wrap_gnome_keyring_find_itemsv_sync)( // NOLINT
|
| - GnomeKeyringItemType type, GList** found, ...);
|
| -const gchar* (*wrap_gnome_keyring_result_to_message)(GnomeKeyringResult res);
|
| -void (*wrap_gnome_keyring_found_list_free)(GList* found_list);
|
| -
|
| -/* Cause the compiler to complain if the types of the above function pointers
|
| - * do not correspond to the types of the actual gnome_keyring_* functions. */
|
| -#define GNOME_KEYRING_VERIFY_TYPE(name) \
|
| - typeof(&gnome_keyring_##name) name = wrap_gnome_keyring_##name; name = name
|
| -
|
| -inline void VerifyGnomeKeyringTypes() {
|
| - GNOME_KEYRING_VERIFY_TYPE(is_available);
|
| - GNOME_KEYRING_VERIFY_TYPE(store_password_sync);
|
| - GNOME_KEYRING_VERIFY_TYPE(delete_password_sync);
|
| - GNOME_KEYRING_VERIFY_TYPE(find_itemsv_sync);
|
| - GNOME_KEYRING_VERIFY_TYPE(result_to_message);
|
| - GNOME_KEYRING_VERIFY_TYPE(found_list_free);
|
| -}
|
| -#undef GNOME_KEYRING_VERIFY_TYPE
|
| -
|
| -/* Make it easy to initialize the function pointers above with a loop below. */
|
| +// Call a given parameter with the name of each func we use from
|
| +// gnome keyring.
|
| +#define GNOME_KEYRING_FOR_EACH_FUNC(F) \
|
| + F(is_available) \
|
| + F(store_password_sync) \
|
| + F(delete_password_sync) \
|
| + F(find_itemsv_sync) \
|
| + F(result_to_message) \
|
| + F(found_list_free) \
|
| + F(list_item_ids_sync) \
|
| + F(item_get_attributes_sync) \
|
| + F(attribute_list_free) \
|
| + F(item_get_info_sync) \
|
| + F(item_info_get_secret) \
|
| + F(item_info_free)
|
| +
|
| +#define GNOME_KEYRING_DECLARE_TYPE(name) \
|
| + typeof(&gnome_keyring_##name) wrap_gnome_keyring_##name;
|
| +GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DECLARE_TYPE)
|
| +#undef GNOME_KEYRING_DECLARE_TYPE
|
| +
|
| +// Make it easy to initialize the function pointers above with a loop below.
|
| #define GNOME_KEYRING_FUNCTION(name) \
|
| - {#name, reinterpret_cast<void**>(&wrap_##name)}
|
| + {"gnome_keyring_"#name, reinterpret_cast<void**>(&wrap_gnome_keyring_##name)},
|
| const struct {
|
| const char* name;
|
| void** pointer;
|
| } gnome_keyring_functions[] = {
|
| - GNOME_KEYRING_FUNCTION(gnome_keyring_is_available),
|
| - GNOME_KEYRING_FUNCTION(gnome_keyring_store_password_sync),
|
| - GNOME_KEYRING_FUNCTION(gnome_keyring_delete_password_sync),
|
| - GNOME_KEYRING_FUNCTION(gnome_keyring_find_itemsv_sync),
|
| - GNOME_KEYRING_FUNCTION(gnome_keyring_result_to_message),
|
| - GNOME_KEYRING_FUNCTION(gnome_keyring_found_list_free),
|
| - {NULL, NULL}
|
| + GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION)
|
| + {NULL, NULL}
|
| };
|
| #undef GNOME_KEYRING_FUNCTION
|
|
|
| -/* Allow application code below to use the normal function names, but actually
|
| - * end up using the function pointers above instead. */
|
| +#undef GNOME_KEYRING_FOR_EACH_FUNC
|
| +
|
| +// Allow application code below to use the normal function names, but actually
|
| +// end up using the function pointers above instead.
|
| #define gnome_keyring_is_available \
|
| wrap_gnome_keyring_is_available
|
| #define gnome_keyring_store_password_sync \
|
| @@ -92,20 +83,18 @@ const struct {
|
| wrap_gnome_keyring_result_to_message
|
| #define gnome_keyring_found_list_free \
|
| wrap_gnome_keyring_found_list_free
|
| -
|
| -// Older versions of GNOME Keyring have bugs that prevent them from working
|
| -// correctly with this code. (In particular, the non-pageable memory allocator
|
| -// is rather busted.) There is no official way to check the version, but newer
|
| -// versions provide several symbols that older versions did not. It would be
|
| -// best if we could check for a new official API, but the only new symbols are
|
| -// "private" symbols. Still, it is probable that they will not change, and it's
|
| -// the best we can do for now. (And eventually we won't care about the older
|
| -// versions anyway so we can remove this version check some day.)
|
| -bool GnomeKeyringVersionOK(void* handle) {
|
| - dlerror();
|
| - dlsym(handle, "gnome_keyring_socket_connect_daemon");
|
| - return !dlerror();
|
| -}
|
| +#define gnome_keyring_list_item_ids_sync \
|
| + wrap_gnome_keyring_list_item_ids_sync
|
| +#define gnome_keyring_item_get_attributes_sync \
|
| + wrap_gnome_keyring_item_get_attributes_sync
|
| +#define gnome_keyring_attribute_list_free \
|
| + wrap_gnome_keyring_attribute_list_free
|
| +#define gnome_keyring_item_get_info_sync \
|
| + wrap_gnome_keyring_item_get_info_sync
|
| +#define gnome_keyring_item_info_get_secret \
|
| + wrap_gnome_keyring_item_info_get_secret
|
| +#define gnome_keyring_item_info_free \
|
| + wrap_gnome_keyring_item_info_free
|
|
|
| /* Load the library and initialize the function pointers. */
|
| bool LoadGnomeKeyring() {
|
| @@ -117,13 +106,6 @@ bool LoadGnomeKeyring() {
|
| LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror();
|
| return false;
|
| }
|
| - if (!GnomeKeyringVersionOK(handle)) {
|
| - // GNOME Keyring is too old. Only info, not a warning, as this can happen
|
| - // on older systems without the user actually asking for it explicitly.
|
| - LOG(INFO) << "libgnome-keyring.so.0 is too old!";
|
| - dlclose(handle);
|
| - return false;
|
| - }
|
| for (size_t i = 0; gnome_keyring_functions[i].name; ++i) {
|
| dlerror();
|
| *gnome_keyring_functions[i].pointer =
|
| @@ -140,24 +122,73 @@ bool LoadGnomeKeyring() {
|
| return true;
|
| }
|
|
|
| -} // namespace
|
| +// Older versions of GNOME Keyring have bugs that prevent them from
|
| +// working correctly with the find_itemsv API. (In particular, the
|
| +// non-pageable memory allocator is rather busted.) There is no
|
| +// official way to check the version, nor could we figure out any
|
| +// reasonable unofficial way to do it. So we work around it by using
|
| +// a much slower API.
|
| +#define GNOME_KEYRING_WORKAROUND_MEMORY_CORRUPTION
|
|
|
| #else // !defined(DLOPEN_GNOME_KEYRING)
|
|
|
| -namespace {
|
| -
|
| bool LoadGnomeKeyring() {
|
| - // We don't do the hacky version check here. When linking directly, we assume
|
| - // that whoever is compiling this code has checked that the version is OK.
|
| + // We don't need to do anything here. When linking directly, we
|
| + // assume that whoever is compiling this code has checked that the
|
| + // version is OK.
|
| return true;
|
| }
|
|
|
| -} // namespace
|
| -
|
| #endif // !defined(DLOPEN_GNOME_KEYRING)
|
|
|
| #define GNOME_KEYRING_APPLICATION_CHROME "chrome"
|
|
|
| +// Convert the attributes of a given keyring entry into a new
|
| +// PasswordForm. Note: does *not* get the actual password, as that is
|
| +// not a key attribute! Returns NULL if the attributes are for the
|
| +// wrong application.
|
| +PasswordForm* FormFromAttributes(GnomeKeyringAttributeList* attrs) {
|
| + // Read the string and int attributes into the appropriate map.
|
| + std::map<std::string, std::string> string_attr_map;
|
| + std::map<std::string, uint32_t> uint_attr_map;
|
| + for (guint i = 0; i < attrs->len; ++i) {
|
| + GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i);
|
| + if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
|
| + if (std::string(attr.name) == "application" &&
|
| + std::string(attr.value.string) != GNOME_KEYRING_APPLICATION_CHROME) {
|
| + // This is not a password we care about.
|
| + return NULL;
|
| + }
|
| + string_attr_map[attr.name] = attr.value.string;
|
| + } else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) {
|
| + uint_attr_map[attr.name] = attr.value.integer;
|
| + }
|
| + }
|
| +
|
| + PasswordForm* form = new PasswordForm();
|
| + form->origin = GURL(string_attr_map["origin_url"]);
|
| + form->action = GURL(string_attr_map["action_url"]);
|
| + form->username_element = UTF8ToUTF16(string_attr_map["username_element"]);
|
| + form->username_value = UTF8ToUTF16(string_attr_map["username_value"]);
|
| + form->password_element = UTF8ToUTF16(string_attr_map["password_element"]);
|
| + form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]);
|
| + form->signon_realm = string_attr_map["signon_realm"];
|
| + form->ssl_valid = uint_attr_map["ssl_valid"];
|
| + form->preferred = uint_attr_map["preferred"];
|
| + int64 date_created = 0;
|
| + bool date_ok = StringToInt64(string_attr_map["date_created"],
|
| + &date_created);
|
| + DCHECK(date_ok);
|
| + DCHECK_NE(date_created, 0);
|
| + form->date_created = base::Time::FromTimeT(date_created);
|
| + form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"];
|
| + form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]);
|
| +
|
| + return form;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| // Schema is analagous to the fields in PasswordForm.
|
| const GnomeKeyringPasswordSchema NativeBackendGnome::kGnomeSchema = {
|
| GNOME_KEYRING_ITEM_GENERIC_SECRET, {
|
| @@ -374,8 +405,11 @@ bool NativeBackendGnome::GetBlacklistLogins(PasswordFormList* forms) {
|
| bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms,
|
| bool autofillable) {
|
| DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
|
| - GList* found = NULL;
|
| +
|
| uint32_t blacklisted_by_user = !autofillable;
|
| +
|
| +#if !defined(GNOME_KEYRING_WORKAROUND_MEMORY_CORRUPTION)
|
| + GList* found = NULL;
|
| // Search gnome keyring for matching passwords.
|
| GnomeKeyringResult result = gnome_keyring_find_itemsv_sync(
|
| GNOME_KEYRING_ITEM_GENERIC_SECRET,
|
| @@ -394,12 +428,33 @@ bool NativeBackendGnome::GetLoginsList(PasswordFormList* forms,
|
| }
|
| ConvertFormList(found, forms);
|
| return true;
|
| +#else
|
| + PasswordFormList all_forms;
|
| + if (!GetAllLogins(&all_forms))
|
| + return false;
|
| + // Now manually filter the result for the values we care about.
|
| + for (size_t i = 0; i < all_forms.size(); ++i) {
|
| + if (all_forms[i]->blacklisted_by_user == blacklisted_by_user)
|
| + forms->push_back(all_forms[i]);
|
| + else
|
| + delete all_forms[i];
|
| + }
|
| + return true;
|
| +#endif
|
| }
|
|
|
| bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) {
|
| + // Older versions of GNOME Keyring have bugs that prevent them from
|
| + // working correctly with the find_itemsv API. (In particular, the
|
| + // non-pageable memory allocator is rather busted.) There is no
|
| + // official way to check the version, nor could we figure out any
|
| + // reasonable unofficial way to do it. So we work around it by
|
| + // using a much slower API.
|
| +
|
| +#if !defined(GNOME_KEYRING_WORKAROUND_MEMORY_CORRUPTION)
|
| GList* found = NULL;
|
| - // We need to search for something, otherwise we get no results - so we search
|
| - // for the fixed application string.
|
| + // We need to search for something, otherwise we get no results - so
|
| + // we search for the fixed application string.
|
| GnomeKeyringResult result = gnome_keyring_find_itemsv_sync(
|
| GNOME_KEYRING_ITEM_GENERIC_SECRET,
|
| &found,
|
| @@ -415,6 +470,47 @@ bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) {
|
| }
|
| ConvertFormList(found, forms);
|
| return true;
|
| +#else
|
| + GList* ids = NULL;
|
| + GnomeKeyringResult result = gnome_keyring_list_item_ids_sync(NULL, &ids);
|
| + if (result != GNOME_KEYRING_RESULT_OK) {
|
| + LOG(ERROR) << "Keyring itemid list failed: "
|
| + << gnome_keyring_result_to_message(result);
|
| + return false;
|
| + }
|
| +
|
| + for (GList* i = ids; i; i = i->next) {
|
| + int id = GPOINTER_TO_INT(i->data);
|
| + GnomeKeyringAttributeList* attrs = NULL;
|
| + result = gnome_keyring_item_get_attributes_sync(NULL, id, &attrs);
|
| + if (result != GNOME_KEYRING_RESULT_OK) {
|
| + LOG(ERROR) << "Keyring get item attributes failed:"
|
| + << gnome_keyring_result_to_message(result);
|
| + gnome_keyring_attribute_list_free(attrs);
|
| + break;
|
| + }
|
| +
|
| + PasswordForm* form = FormFromAttributes(attrs);
|
| + gnome_keyring_attribute_list_free(attrs);
|
| +
|
| + if (form) {
|
| + GnomeKeyringItemInfo* info = NULL;
|
| + result = gnome_keyring_item_get_info_sync(NULL, id, &info);
|
| + if (result != GNOME_KEYRING_RESULT_OK) {
|
| + delete form;
|
| + break;
|
| + }
|
| + form->password_value = UTF8ToUTF16(
|
| + gnome_keyring_item_info_get_secret(info));
|
| +
|
| + gnome_keyring_item_info_free(info);
|
| + forms->push_back(form);
|
| + }
|
| + }
|
| + g_list_free(ids);
|
| +
|
| + return result == GNOME_KEYRING_RESULT_OK;
|
| +#endif
|
| }
|
|
|
| void NativeBackendGnome::ConvertFormList(GList* found,
|
| @@ -422,40 +518,10 @@ void NativeBackendGnome::ConvertFormList(GList* found,
|
| GList* element = g_list_first(found);
|
| while (element != NULL) {
|
| GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data);
|
| -
|
| GnomeKeyringAttributeList* attrs = data->attributes;
|
| - // Read the string and int attributes into the appropriate map.
|
| - std::map<std::string, std::string> string_attr_map;
|
| - std::map<std::string, uint32_t> uint_attr_map;
|
| - for (guint i = 0; i < attrs->len; ++i) {
|
| - GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i);
|
| - if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
|
| - string_attr_map[attr.name] = attr.value.string;
|
| - } else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) {
|
| - uint_attr_map[attr.name] = attr.value.integer;
|
| - }
|
| - }
|
|
|
| - PasswordForm* form = new PasswordForm();
|
| - form->origin = GURL(string_attr_map["origin_url"]);
|
| - form->action = GURL(string_attr_map["action_url"]);
|
| - form->username_element = UTF8ToUTF16(string_attr_map["username_element"]);
|
| - form->username_value = UTF8ToUTF16(string_attr_map["username_value"]);
|
| - form->password_element = UTF8ToUTF16(string_attr_map["password_element"]);
|
| + PasswordForm* form = FormFromAttributes(attrs);
|
| form->password_value = UTF8ToUTF16(data->secret);
|
| - form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]);
|
| - form->signon_realm = string_attr_map["signon_realm"];
|
| - form->ssl_valid = uint_attr_map["ssl_valid"];
|
| - form->preferred = uint_attr_map["preferred"];
|
| - int64 date_created = 0;
|
| - bool date_ok = StringToInt64(string_attr_map["date_created"],
|
| - &date_created);
|
| - DCHECK(date_ok);
|
| - DCHECK_NE(date_created, 0);
|
| - form->date_created = base::Time::FromTimeT(date_created);
|
| - form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"];
|
| - form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]);
|
| -
|
| forms->push_back(form);
|
|
|
| element = g_list_next(element);
|
|
|