/* GSecret - GLib wrapper for Secret Service * * Copyright 2011 Collabora Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. */ #include "config.h" #include "gsecret-password.h" #include "gsecret-private.h" #include "gsecret-value.h" #include typedef struct { GAsyncResult *result; GMainContext *context; GMainLoop *loop; } SyncClosure; static SyncClosure * sync_closure_new (void) { SyncClosure *closure; closure = g_new0 (SyncClosure, 1); closure->context = g_main_context_new (); closure->loop = g_main_loop_new (closure->context, FALSE); return closure; } static void sync_closure_free (gpointer data) { SyncClosure *closure = data; g_clear_object (&closure->result); g_main_loop_unref (closure->loop); g_main_context_unref (closure->context); } static void on_sync_result (GObject *source, GAsyncResult *result, gpointer user_data) { SyncClosure *closure = user_data; closure->result = g_object_ref (result); g_main_loop_quit (closure->loop); } typedef struct { const GSecretSchema *schema; GHashTable *attributes; gchar *collection_path; gchar *label; GSecretValue *value; GCancellable *cancellable; gboolean created; } StoreClosure; static void store_closure_free (gpointer data) { StoreClosure *closure = data; g_hash_table_unref (closure->attributes); g_free (closure->collection_path); g_free (closure->label); gsecret_value_unref (closure->value); g_clear_object (&closure->cancellable); g_slice_free (StoreClosure, closure); } static void on_store_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; closure->created = gsecret_service_store_password_finish (GSECRET_SERVICE (source), result, &error); if (error != NULL) g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); g_object_unref (res); } static void on_store_connected (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GSecretService *service; GError *error = NULL; service = _gsecret_service_bare_connect_finish (result, &error); if (error == NULL) { gsecret_service_store_passwordv (service, closure->schema, closure->attributes, closure->collection_path, closure->label, closure->value, closure->cancellable, on_store_complete, g_object_ref (res)); g_object_unref (service); } else { g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); } g_object_unref (res); } void gsecret_password_store (const GSecretSchema *schema, const gchar *collection_path, const gchar *label, const gchar *password, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (collection_path != NULL); g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); gsecret_password_storev (schema, collection_path, label, password, attributes, cancellable, callback, user_data); g_hash_table_unref (attributes); } void gsecret_password_storev (const GSecretSchema *schema, const gchar *collection_path, const gchar *label, const gchar *password, GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *res; StoreClosure *closure; g_return_if_fail (schema != NULL); g_return_if_fail (collection_path != NULL); g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); res = g_simple_async_result_new (NULL, callback, user_data, gsecret_password_storev); closure = g_slice_new0 (StoreClosure); closure->schema = schema; closure->collection_path = g_strdup (collection_path); closure->label = g_strdup (label); closure->value = gsecret_value_new (password, -1, "text/plain"); closure->attributes = g_hash_table_ref (attributes); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free); _gsecret_service_bare_connect (NULL, TRUE, cancellable, on_store_connected, g_object_ref (res)); g_object_unref (res); } gboolean gsecret_password_store_finish (GAsyncResult *result, GError **error) { GSimpleAsyncResult *res; StoreClosure *closure; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, gsecret_password_storev), FALSE); res = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (res, error)) return FALSE; closure = g_simple_async_result_get_op_res_gpointer (res); return closure->created; } gboolean gsecret_password_store_sync (const GSecretSchema *schema, const gchar *collection_path, const gchar *label, const gchar *password, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; va_list va; gboolean ret; g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (password != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); va_start (va, error); attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); ret = gsecret_password_storev_sync (schema, collection_path, label, password, attributes, cancellable, error); g_hash_table_unref (attributes); return ret; } gboolean gsecret_password_storev_sync (const GSecretSchema *schema, const gchar *collection_path, const gchar *label, const gchar *password, GHashTable *attributes, GCancellable *cancellable, GError **error) { SyncClosure *closure; gboolean ret; g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (collection_path != NULL, FALSE); g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (password != NULL, FALSE); g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); closure = sync_closure_new (); g_main_context_push_thread_default (closure->context); gsecret_password_storev (schema, collection_path, label, password, attributes, cancellable, on_sync_result, closure); g_main_loop_run (closure->loop); ret = gsecret_password_store_finish (closure->result, error); g_main_context_pop_thread_default (closure->context); sync_closure_free (closure); return ret; } typedef struct { GCancellable *cancellable; GHashTable *attributes; GSecretValue *value; } LookupClosure; static void lookup_closure_free (gpointer data) { LookupClosure *closure = data; g_clear_object (&closure->cancellable); g_hash_table_unref (closure->attributes); if (closure->value) gsecret_value_unref (closure->value); g_slice_free (LookupClosure, closure); } void gsecret_password_lookup (const GSecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); gsecret_password_lookupv (attributes, cancellable, callback, user_data); g_hash_table_unref (attributes); } static void on_lookup_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; closure->value = gsecret_service_lookup_password_finish (GSECRET_SERVICE (source), result, &error); if (error != NULL) g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); g_object_unref (res); } static void on_lookup_connected (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GSecretService *service; GError *error = NULL; service = _gsecret_service_bare_connect_finish (result, &error); if (error != NULL) { g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); } else { gsecret_service_lookup_passwordv (service, closure->attributes, closure->cancellable, on_lookup_complete, g_object_ref (res)); g_object_unref (service); } g_object_unref (res); } void gsecret_password_lookupv (GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *res; LookupClosure *closure; g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); res = g_simple_async_result_new (NULL, callback, user_data, gsecret_password_lookupv); closure = g_slice_new0 (LookupClosure); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free); _gsecret_service_bare_connect (NULL, TRUE, cancellable, on_lookup_connected, g_object_ref (res)); g_object_unref (res); } gchar * gsecret_password_lookup_finish (GAsyncResult *result, GError **error) { GSimpleAsyncResult *res; LookupClosure *closure; const gchar *content_type; gchar *password = NULL; g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, gsecret_password_lookupv), NULL); res = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (res, error)) return NULL; closure = g_simple_async_result_get_op_res_gpointer (res); content_type = gsecret_value_get_content_type (closure->value); if (content_type && g_str_equal (content_type, "text/plain")) { password = _gsecret_value_unref_to_password (closure->value); closure->value = NULL; } return password; } gchar * gsecret_password_lookup_sync (const GSecretSchema *schema, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; gchar *password; va_list va; g_return_val_if_fail (schema != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); va_start (va, error); attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); password = gsecret_password_lookupv_sync (attributes, cancellable, error); g_hash_table_unref (attributes); return password; } gchar * gsecret_password_lookupv_sync (GHashTable *attributes, GCancellable *cancellable, GError **error) { SyncClosure *closure; gchar *password; g_return_val_if_fail (attributes != NULL, NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); closure = sync_closure_new (); g_main_context_push_thread_default (closure->context); gsecret_password_deletev (attributes, cancellable, on_sync_result, closure); g_main_loop_run (closure->loop); password = gsecret_password_lookup_finish (closure->result, error); g_main_context_pop_thread_default (closure->context); sync_closure_free (closure); return password; } typedef struct { GCancellable *cancellable; GHashTable *attributes; gboolean deleted; } DeleteClosure; static void delete_closure_free (gpointer data) { DeleteClosure *closure = data; g_clear_object (&closure->cancellable); g_hash_table_unref (closure->attributes); g_slice_free (DeleteClosure, closure); } void gsecret_password_delete (const GSecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); va_start (va, user_data); attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); gsecret_password_deletev (attributes, cancellable, callback, user_data); g_hash_table_unref (attributes); } static void on_delete_complete (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; closure->deleted = gsecret_service_delete_password_finish (GSECRET_SERVICE (source), result, &error); if (error != NULL) g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); g_object_unref (res); } static void on_delete_connect (GObject *source, GAsyncResult *result, gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GSecretService *service; GError *error = NULL; service = _gsecret_service_bare_connect_finish (result, &error); if (error == NULL) { gsecret_service_delete_passwordv (service, closure->attributes, closure->cancellable, on_delete_complete, g_object_ref (res)); g_object_unref (service); } else { g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); } g_object_unref (res); } void gsecret_password_deletev (GHashTable *attributes, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *res; DeleteClosure *closure; g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); res = g_simple_async_result_new (NULL, callback, user_data, gsecret_password_deletev); closure = g_slice_new0 (DeleteClosure); closure->attributes = g_hash_table_ref (attributes); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free); _gsecret_service_bare_connect (NULL, FALSE, cancellable, on_delete_connect, g_object_ref (res)); g_object_unref (res); } gboolean gsecret_password_delete_finish (GAsyncResult *result, GError **error) { DeleteClosure *closure; GSimpleAsyncResult *res; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, gsecret_password_deletev), FALSE); res = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (res, error)) return FALSE; closure = g_simple_async_result_get_op_res_gpointer (res); return closure->deleted; } gboolean gsecret_password_delete_sync (const GSecretSchema* schema, GCancellable *cancellable, GError **error, ...) { GHashTable *attributes; gboolean result; va_list va; g_return_val_if_fail (schema != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); va_start (va, error); attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); result = gsecret_password_deletev_sync (attributes, cancellable, error); g_hash_table_unref (attributes); return result; } gboolean gsecret_password_deletev_sync (GHashTable *attributes, GCancellable *cancellable, GError **error) { SyncClosure *closure; gboolean result; g_return_val_if_fail (attributes != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); closure = sync_closure_new (); g_main_context_push_thread_default (closure->context); gsecret_password_deletev (attributes, cancellable, on_sync_result, closure); g_main_loop_run (closure->loop); result = gsecret_password_delete_finish (closure->result, error); g_main_context_pop_thread_default (closure->context); sync_closure_free (closure); return result; } void gsecret_password_free (gpointer password) { if (password == NULL) return; egg_secure_strfree (password); }