diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2017-12-13 00:39:36 -0800 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2018-01-03 10:39:50 +0100 |
commit | 3325aebbff42025cb9f25fb17c5255bad613cac1 (patch) | |
tree | d9a430ea81a0dc9460e32c19d0e75f4179b7e139 | |
parent | 7b7660af6023683d843d7f106e24446c409a448b (diff) |
GNOME: retry keyring operations
Sometimes GNOME keyring and libsecret fail to set up the right temporary keys
(https://bugzilla.gnome.org/show_bug.cgi?id=778357). This has been fixed
upstream, but still breaks with the distros used by the automated testing
occassionally.
Retrying the operations after disconnecting from the server is an attempt
to recover from this sporadic error.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
-rw-r--r-- | src/backends/gnome/GNOMEPlatform.cpp | 112 |
1 files changed, 82 insertions, 30 deletions
diff --git a/src/backends/gnome/GNOMEPlatform.cpp b/src/backends/gnome/GNOMEPlatform.cpp index 37f9811a..deff896f 100644 --- a/src/backends/gnome/GNOMEPlatform.cpp +++ b/src/backends/gnome/GNOMEPlatform.cpp @@ -95,6 +95,23 @@ public: } }; +/** + * Sometimes libsecret and GNOME Keyring fail to initialize + * the encryption: https://bugzilla.gnome.org/show_bug.cgi?id=778357 + * If that happens, then trying with a new SecretService instance + * may work. + * + * When libsecret detects that, we get a well-defined error. + * When GNOME Keyring detects it, the error is less obvious. + */ +static bool IsSharedSecretError(const GErrorCXX &gerror) +{ + bool result = gerror.matches(SECRET_ERROR, SECRET_ERROR_PROTOCOL) /* = "received an invalid or unencryptable secret" */ || + strstr(gerror->message, "The secret was transferred or encrypted in an invalid way"); + SE_LOG_DEBUG(NULL, "IsSharedSecretError: %d/%d/%s: %s", (int)gerror->domain, (int)gerror->code, gerror->message, result ? "yes" : "no"); + return result; +} + bool GNOMELoadPasswordSlot(const InitStateTri &keyring, const std::string &passwordName, const std::string &descr, @@ -106,24 +123,49 @@ bool GNOMELoadPasswordSlot(const InitStateTri &keyring, return false; } - GErrorCXX gerror; LibSecretHash hash(key); - PlainGStr result(secret_password_lookupv_sync(SECRET_SCHEMA_COMPAT_NETWORK, - hash, - NULL, - gerror)); - - // if find password stored in gnome keyring - if (gerror) { - gerror.throwError(SE_HERE, StringPrintf("looking up password '%s'", descr.c_str())); - } else if (result) { - SE_LOG_DEBUG(NULL, "%s: loaded password from GNOME keyring using %s", - key.description.c_str(), - key.toString().c_str()); - password = result; - } else { - SE_LOG_DEBUG(NULL, "password not in GNOME keyring using %s", - key.toString().c_str()); + for (int i = 0; ; i++ ) { + GErrorCXX gerror; + PlainGStr result(secret_password_lookupv_sync(SECRET_SCHEMA_COMPAT_NETWORK, + hash, + NULL, + gerror)); + + // if find password stored in gnome keyring + if (gerror) { + /* It is uncertain whether we end up here at all when such + an error occurs. Check just in case. */ + if (IsSharedSecretError(gerror) && + i < 3) { + SE_LOG_DEBUG(NULL, "disconnecting secret service: %u/%d = %s", gerror->domain, gerror->code, gerror->message); + secret_service_disconnect(); + } else { + gerror.throwError(SE_HERE, StringPrintf("looking up password '%s'", descr.c_str())); + } + } else if (result.get()) { + SE_LOG_DEBUG(NULL, "%s: loaded password from GNOME keyring using %s", + key.description.c_str(), + key.toString().c_str()); + password = result; + break; + } else { + /* + * There have been cases where "received an invalid or + * unencryptable secret" was printed to the console right + * before we end up here. Apparently the error doesn't + * get propagated properly to us. + * + * To cope with that, we try to disconnect and check again. + */ + if (i < 3) { + SE_LOG_DEBUG(NULL, "disconnecting secret service: password not found"); + secret_service_disconnect(); + } else { + SE_LOG_DEBUG(NULL, "password not in GNOME keyring using %s", + key.toString().c_str()); + break; + } + } } return true; @@ -149,7 +191,6 @@ bool GNOMESavePasswordSlot(const InitStateTri &keyring, key.toString().c_str())); } - GErrorCXX gerror; LibSecretHash hash(key); std::string label; if (!key.user.empty() && !key.server.empty()) { @@ -158,19 +199,30 @@ bool GNOMESavePasswordSlot(const InitStateTri &keyring, } else { label = passwordName; } - gboolean result = secret_password_storev_sync(SECRET_SCHEMA_COMPAT_NETWORK, - hash, - NULL, - label.c_str(), - password.c_str(), - NULL, - gerror); - if (!result) { - gerror.throwError(SE_HERE, StringPrintf("%s: saving password '%s' in GNOME keyring", - key.description.c_str(), - key.toString().c_str())); + for (int i = 0; ; i++) { + GErrorCXX gerror; + gboolean result = secret_password_storev_sync(SECRET_SCHEMA_COMPAT_NETWORK, + hash, + NULL, + label.c_str(), + password.c_str(), + NULL, + gerror); + if (result) { + SE_LOG_DEBUG(NULL, "saved password in GNOME keyring using %s", key.toString().c_str()); + break; + } + + if (IsSharedSecretError(gerror) && + i < 3) { + SE_LOG_DEBUG(NULL, "disconnecting secret service: %u/%d = %s", gerror->domain, gerror->code, gerror->message); + secret_service_disconnect(); + } else { + gerror.throwError(SE_HERE, StringPrintf("%s: saving password '%s' in GNOME keyring", + key.description.c_str(), + key.toString().c_str())); + } } - SE_LOG_DEBUG(NULL, "saved password in GNOME keyring using %s", key.toString().c_str()); // handled return true; |