summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2021-11-30 11:48:37 +0100
committerMilan Crha <mcrha@redhat.com>2021-11-30 11:48:37 +0100
commit7268a4111e8242c0d2fc8e5ad8b33190a468ca30 (patch)
tree130d8d007952e010fd83c6e836a4d700bcb7516b
parentd0bcf3822c3eb271ce7112bbf0f82e2f545d31df (diff)
downloadlibsecret-62-flatpak-libsecret-fails-to-read-credentials-saved-by-other-process.tar.gz
secret-file-collection: Check for file changes and reload when needed62-flatpak-libsecret-fails-to-read-credentials-saved-by-other-process
When some other process changes the underlying file, the collection should reload its in-memory content, to reflect the changes. Closes https://gitlab.gnome.org/GNOME/libsecret/-/issues/62
-rw-r--r--libsecret/secret-file-collection.c228
1 files changed, 155 insertions, 73 deletions
diff --git a/libsecret/secret-file-collection.c b/libsecret/secret-file-collection.c
index 62847b9..1819e83 100644
--- a/libsecret/secret-file-collection.c
+++ b/libsecret/secret-file-collection.c
@@ -54,6 +54,7 @@ struct _SecretFileCollection
guint64 usage_count;
GBytes *key;
GVariant *items;
+ guint64 file_last_modified;
};
static void secret_file_collection_async_initable_iface (GAsyncInitableIface *iface);
@@ -68,6 +69,22 @@ enum {
PROP_PASSWORD
};
+static guint64
+get_file_last_modified (SecretFileCollection *self)
+{
+ GFileInfo *info;
+ guint64 res;
+
+ info = g_file_query_info (self->file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ if (info == NULL)
+ return 0;
+
+ res = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ g_object_unref (info);
+
+ return res;
+}
+
static gboolean
do_derive_key (SecretFileCollection *self)
{
@@ -296,17 +313,13 @@ secret_file_collection_class_init (SecretFileCollectionClass *klass)
egg_libgcrypt_initialize ();
}
-static void
-on_load_contents (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+static gboolean
+load_contents (SecretFileCollection *self,
+ gchar *contents, /* takes ownership */
+ gsize length,
+ GError **error)
{
- GFile *file = G_FILE (source_object);
- GTask *task = G_TASK (user_data);
- SecretFileCollection *self = g_task_get_source_object (task);
- gchar *contents;
gchar *p;
- gsize length;
GVariant *variant;
GVariant *salt_array;
guint32 salt_size;
@@ -315,70 +328,25 @@ on_load_contents (GObject *source_object,
guint64 usage_count;
gconstpointer data;
gsize n_data;
- GError *error = NULL;
- gboolean ret;
-
- ret = g_file_load_contents_finish (file, result,
- &contents, &length,
- &self->etag,
- &error);
-
- if (!ret) {
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
- GVariantBuilder builder;
- guint8 salt[SALT_SIZE];
-
- g_clear_error (&error);
-
- gcry_create_nonce (salt, sizeof(salt));
- self->salt = g_bytes_new (salt, sizeof(salt));
- self->iteration_count = ITERATION_COUNT;
- self->modified = g_date_time_new_now_utc ();
- self->usage_count = 0;
-
- if (!do_derive_key (self)) {
- g_task_return_new_error (task,
- SECRET_ERROR,
- SECRET_ERROR_PROTOCOL,
- "couldn't derive key");
- g_object_unref (task);
- return;
- }
-
- g_variant_builder_init (&builder,
- G_VARIANT_TYPE ("a(a{say}ay)"));
- self->items = g_variant_builder_end (&builder);
- g_variant_ref_sink (self->items);
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
p = contents;
if (length < KEYRING_FILE_HEADER_LEN ||
memcmp (p, KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN) != 0) {
- g_task_return_new_error (task,
- SECRET_ERROR,
- SECRET_ERROR_INVALID_FILE_FORMAT,
- "file header mismatch");
- g_object_unref (task);
- return;
+ g_set_error_literal (error,
+ SECRET_ERROR,
+ SECRET_ERROR_INVALID_FILE_FORMAT,
+ "file header mismatch");
+ return FALSE;
}
p += KEYRING_FILE_HEADER_LEN;
length -= KEYRING_FILE_HEADER_LEN;
if (length < 2 || *p != MAJOR_VERSION || *(p + 1) != MINOR_VERSION) {
- g_task_return_new_error (task,
- SECRET_ERROR,
- SECRET_ERROR_INVALID_FILE_FORMAT,
- "version mismatch");
- g_object_unref (task);
- return;
+ g_set_error_literal (error,
+ SECRET_ERROR,
+ SECRET_ERROR_INVALID_FILE_FORMAT,
+ "version mismatch");
+ return FALSE;
}
p += 2;
length -= 2;
@@ -407,19 +375,125 @@ on_load_contents (GObject *source_object,
g_assert (n_data == salt_size);
self->salt = g_bytes_new (data, n_data);
+
+ g_variant_unref (salt_array);
+ g_variant_unref (variant);
+
if (!do_derive_key (self)) {
- g_task_return_new_error (task,
- SECRET_ERROR,
- SECRET_ERROR_PROTOCOL,
- "couldn't derive key");
- goto out;
+ g_set_error_literal (error,
+ SECRET_ERROR,
+ SECRET_ERROR_PROTOCOL,
+ "couldn't derive key");
+ return FALSE;
}
- g_task_return_boolean (task, TRUE);
+ return TRUE;
+}
+
+static gboolean
+init_empty_file (SecretFileCollection *self,
+ GError **error)
+{
+ GVariantBuilder builder;
+ guint8 salt[SALT_SIZE];
+
+ gcry_create_nonce (salt, sizeof(salt));
+ self->salt = g_bytes_new (salt, sizeof(salt));
+ self->iteration_count = ITERATION_COUNT;
+ self->modified = g_date_time_new_now_utc ();
+ self->usage_count = 0;
+
+ if (!do_derive_key (self)) {
+ g_set_error_literal (error,
+ SECRET_ERROR,
+ SECRET_ERROR_PROTOCOL,
+ "couldn't derive key");
+ return FALSE;
+ }
+
+ g_variant_builder_init (&builder,
+ G_VARIANT_TYPE ("a(a{say}ay)"));
+ self->items = g_variant_builder_end (&builder);
+ g_variant_ref_sink (self->items);
+
+ return TRUE;
+}
+
+static void
+ensure_up_to_date (SecretFileCollection *self)
+{
+ guint64 last_modified;
+
+ last_modified = get_file_last_modified (self);
+ if (last_modified != self->file_last_modified) {
+ gchar *contents = NULL;
+ gsize length = 0;
+ gboolean success;
+ GError *error = NULL;
+
+ self->file_last_modified = last_modified;
+ g_clear_pointer (&self->etag, g_free);
+
+ success = g_file_load_contents (self->file, NULL, &contents, &length, &self->etag, &error);
+
+ if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ g_clear_error (&error);
+
+ success = init_empty_file (self, &error);
+ }
+
+ if (success)
+ success = load_contents (self, contents, length, &error);
+
+ if (!success)
+ g_debug ("Failed to load file contents: %s", error ? error->message : "Unknown error");
+
+ g_clear_error (&error);
+ }
+}
+
+static void
+on_load_contents (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file = G_FILE (source_object);
+ GTask *task = G_TASK (user_data);
+ SecretFileCollection *self = g_task_get_source_object (task);
+ gchar *contents;
+ gsize length;
+ GError *error = NULL;
+ gboolean ret;
+
+ self->file_last_modified = get_file_last_modified (self);
+
+ ret = g_file_load_contents_finish (file, result,
+ &contents, &length,
+ &self->etag,
+ &error);
+
+ if (!ret) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ g_clear_error (&error);
+
+ if (init_empty_file (self, &error)) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ret = load_contents (self, contents, length, &error);
+ if (ret)
+ g_task_return_boolean (task, ret);
+ else
+ g_task_return_error (task, error);
- out:
- g_variant_unref (salt_array);
- g_variant_unref (variant);
g_object_unref (task);
}
@@ -546,6 +620,8 @@ secret_file_collection_replace (SecretFileCollection *self,
GDateTime *created = NULL;
GDateTime *modified;
+ ensure_up_to_date (self);
+
hashed_attributes = hash_attributes (self, attributes);
if (!hashed_attributes) {
g_set_error (error,
@@ -657,6 +733,8 @@ secret_file_collection_search (SecretFileCollection *self,
GVariant *child;
GList *result = NULL;
+ ensure_up_to_date (self);
+
g_variant_iter_init (&iter, self->items);
while ((child = g_variant_iter_next_value (&iter)) != NULL) {
GVariant *hashed_attributes;
@@ -750,6 +828,8 @@ secret_file_collection_clear (SecretFileCollection *self,
GVariant *child;
gboolean removed = FALSE;
+ ensure_up_to_date (self);
+
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(a{say}ay)"));
g_variant_iter_init (&items, self->items);
while ((child = g_variant_iter_next_value (&items)) != NULL) {
@@ -791,6 +871,8 @@ on_replace_contents (GObject *source_object,
return;
}
+ self->file_last_modified = get_file_last_modified (self);
+
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}