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