summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2017-12-13 00:39:36 -0800
committerPatrick Ohly <patrick.ohly@intel.com>2018-01-03 10:39:50 +0100
commit3325aebbff42025cb9f25fb17c5255bad613cac1 (patch)
treed9a430ea81a0dc9460e32c19d0e75f4179b7e139
parent7b7660af6023683d843d7f106e24446c409a448b (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.cpp112
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;