diff --git a/configure.ac b/configure.ac index 7cc3ef7984..55000e3ae5 100644 --- a/configure.ac +++ b/configure.ac @@ -1106,6 +1106,13 @@ then PKG_CHECK_MODULES(GNOME_KEYRING, gnome-keyring-1 >= "0.6", [AC_DEFINE(HAVE_GNOME_KEYRING,1,[System has gnome-keyring 0.6 or better])], [AC_DEFINE(HAVE_NO_KEYRING,1,[System has no suitable keyring service])]) + + PKG_CHECK_MODULES(LIBSECRET, libsecret-1 >= "0.18", + [AC_DEFINE(HAVE_LIBSECRET,1,[System has libsecret 0.18 or better])], + [AC_DEFINE(HAVE_NO_LIBSECRET,1,[System has no suitable libsecret service])]) + AC_SUBST(LIBSECRET_CFLAGS) + AC_SUBST(LIBSECRET_LIBS) + ;; esac ### ---------------------------------------------------------------------- diff --git a/src/gnome-utils/Makefile.am b/src/gnome-utils/Makefile.am index b973a6bb8f..739ff2506a 100644 --- a/src/gnome-utils/Makefile.am +++ b/src/gnome-utils/Makefile.am @@ -17,6 +17,7 @@ AM_CPPFLAGS = \ ${GLIB_CFLAGS} \ ${GTK_CFLAGS} \ ${GNOME_KEYRING_CFLAGS} \ + ${LIBSECRET_CFLAGS} \ ${GUILE_CFLAGS} \ ${QOF_CFLAGS} \ ${LIBGDA_CFLAGS} \ @@ -204,6 +205,7 @@ libgncmod_gnome_utils_la_LIBADD = \ ${top_builddir}/src/libqof/qof/libgnc-qof.la \ ${GTK_LIBS} \ ${GNOME_KEYRING_LIBS} \ + ${LIBSECRET_LIBS} \ ${GUILE_LIBS} \ ${GLIB_LIBS} \ ${DB_LIBS} \ diff --git a/src/gnome-utils/gnc-keyring.c b/src/gnome-utils/gnc-keyring.c index 75a4d27d88..9a1e16f2a2 100644 --- a/src/gnome-utils/gnc-keyring.c +++ b/src/gnome-utils/gnc-keyring.c @@ -26,7 +26,12 @@ #include "qof.h" #include "gnc-ui.h" #include "gnc-keyring.h" -#ifdef HAVE_GNOME_KEYRING +#ifdef HAVE_LIBSECRET +#include +#endif +#if HAVE_GNOME_KEYRING +#define GNOME_KEYRING_DEPRECATED +#define GNOME_KEYRING_DEPRECATED_FOR(x) #include #endif #ifdef HAVE_OSX_KEYCHAIN @@ -38,6 +43,27 @@ /* This static indicates the debugging module that this .o belongs to. */ G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_GUI; +#ifdef HAVE_LIBSECRET +const SecretSchema* gnucash_get_secret_schema(void) G_GNUC_CONST; +const SecretSchema* gnucash_get_secret_schema(void) +{ + static const SecretSchema secret_schema = { + "org.gnucash.password", SECRET_SCHEMA_NONE, + { + { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "server", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER }, + { "user", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "NULL", 0 }, + } + }; + + return &secret_schema; +} + +#define SECRET_SCHEMA_GNUCASH gnucash_get_secret_schema() +#endif + void gnc_keyring_set_password (const gchar *access_method, const gchar *server, guint32 port, @@ -45,8 +71,29 @@ void gnc_keyring_set_password (const gchar *access_method, const gchar *user, const gchar* password) { +#ifdef HAVE_LIBSECRET + GError* error = NULL; + gchar* label = NULL; + + label = g_strdup_printf("GnuCash password for %s://%s@%s", access_method, user, server); -#ifdef HAVE_GNOME_KEYRING + secret_password_store_sync (SECRET_SCHEMA_GNUCASH, SECRET_COLLECTION_DEFAULT, + label, password, NULL, &error, + "protocol", access_method, + "server", server, + "port", port, + "user", user, + NULL); + + g_free(label); + + if (error != NULL) + { + PWARN ("libsecret error: %s", error->message); + PWARN ("The user will be prompted for a password again next time."); + g_error_free(error); + } +#elif HAVE_GNOME_KEYRING GnomeKeyringResult gkr_result; guint32 item_id = 0; @@ -105,7 +152,11 @@ gboolean gnc_keyring_get_password ( GtkWidget *parent, gchar **password) { gboolean password_found = FALSE; -#ifdef HAVE_GNOME_KEYRING +#ifdef HAVE_LIBSECRET + GError* error = NULL; + char* libsecret_password; +#endif +#if HAVE_GNOME_KEYRING GnomeKeyringResult gkr_result; GList *found_list = NULL; GnomeKeyringNetworkPasswordData *found; @@ -121,25 +172,57 @@ gboolean gnc_keyring_get_password ( GtkWidget *parent, *password = NULL; -#ifdef HAVE_GNOME_KEYRING - gkr_result = gnome_keyring_find_network_password_sync - ( *user, NULL, server, service, - access_method, NULL, port, &found_list ); +#ifdef HAVE_LIBSECRET + libsecret_password = secret_password_lookup_sync (SECRET_SCHEMA_GNUCASH, NULL, &error, + "protocol", access_method, + "server", server, + "port", port, + "user", *user, + NULL); - if (gkr_result == GNOME_KEYRING_RESULT_OK) - { - found = (GnomeKeyringNetworkPasswordData *) found_list->data; - if (found->password) - *password = g_strdup(found->password); + if (libsecret_password == NULL) { + if (error != NULL) { + PWARN ("libsecret access failed: %s.", error->message); + g_error_free(error); + } + } else { password_found = TRUE; + *password = g_strdup (libsecret_password); + secret_password_free (libsecret_password); } - else - PWARN ("Gnome-keyring access failed: %s.", - gnome_keyring_result_to_message(gkr_result)); +#endif /* HAVE_LIBSECRET */ + +#if HAVE_GNOME_KEYRING + if (password_found == FALSE) { + gkr_result = gnome_keyring_find_network_password_sync + ( *user, NULL, server, service, + access_method, NULL, port, &found_list ); - gnome_keyring_network_password_list_free(found_list); + if (gkr_result == GNOME_KEYRING_RESULT_OK) + { + found = (GnomeKeyringNetworkPasswordData *) found_list->data; + if (found->password) + *password = g_strdup(found->password); + password_found = TRUE; + } + else + PWARN ("Gnome-keyring access failed: %s.", + gnome_keyring_result_to_message(gkr_result)); + + gnome_keyring_network_password_list_free(found_list); + } #endif /* HAVE_GNOME_KEYRING */ +#if defined(HAVE_LIBSECRET) && defined(HAVE_GNOME_KEYRING) + /* If we were not able to retrieve the password with libsecret and the new + * schema and libgnome-keyring was successful to retrieve the password using + * the old schema, we immediatly store it in the new schema. + */ + if (libsecret_password == NULL && password_found == TRUE) { + gnc_keyring_set_password(access_method, server, port, service, *user, *password); + } +#endif /* HAVE_LIBSECRET && HAVE_GNOME_KEYRING */ + #ifdef HAVE_OSX_KEYCHAIN /* mysql and postgres aren't valid protocols on Mac OS X. * So we use the security domain parameter to allow us to