/*
* gnome-keyring
*
* Copyright (C) 2008 Stefan Walter
*
* 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.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see .
*/
#include "config.h"
#include "gcr-internal.h"
#include "gcr-library.h"
#include "gcr-types.h"
#include "egg/egg-error.h"
#include "egg/egg-libgcrypt.h"
#include "egg/egg-secure-memory.h"
#include
#include
#include
#include
/**
* GCR_CHECK_VERSION:
* @major: the major version to check for
* @minor: the minor version to check for
* @micro: the micro version to check for
*
* Checks the version of the Gcr library that is being compiled
* against.
*
* ```
* #if !GCR_CHECK_VERSION (3, 0, 0)
* #warning Old Gcr version, disabling functionality
* #endif
* ```
*
* Returns: %TRUE if the version of the Gcr header files
* is the same as or newer than the passed-in version.
*/
/**
* GCR_MAJOR_VERSION:
*
* The major version number of the Gcr library.
*/
/**
* GCR_MINOR_VERSION:
*
* The minor version number of the Gcr library.
*/
/**
* GCR_MICRO_VERSION:
*
* The micro version number of the Gcr library.
*/
G_LOCK_DEFINE_STATIC (modules);
static GList *all_modules = NULL;
static gboolean initialized_modules = FALSE;
G_LOCK_DEFINE_STATIC (uris);
static gboolean initialized_uris = FALSE;
static gchar *trust_store_uri = NULL;
static gchar **trust_lookup_uris = NULL;
/* -----------------------------------------------------------------------------
* ERRORS
*/
GQuark
gcr_data_error_get_domain (void)
{
static GQuark domain = 0;
if (domain == 0)
domain = g_quark_from_static_string ("gcr-parser-error");
return domain;
}
/* -----------------------------------------------------------------------------
* INITIALIZATION
*/
void
_gcr_uninitialize_library (void)
{
G_LOCK (modules);
g_clear_list (&all_modules, g_object_unref);
initialized_modules = FALSE;
G_UNLOCK (modules);
G_LOCK (uris);
initialized_uris = FALSE;
g_free (trust_store_uri);
trust_store_uri = NULL;
g_strfreev (trust_lookup_uris);
trust_lookup_uris = NULL;
G_UNLOCK (uris);
}
void
_gcr_initialize_library (void)
{
static gint gcr_initialize = 0;
if (g_atomic_int_add (&gcr_initialize, 1) == 0)
return;
/* Initialize the libgcrypt library if needed */
egg_libgcrypt_initialize ();
g_debug ("initialized library");
}
static void
initialize_uris (void)
{
GPtrArray *uris;
GList *l;
gchar *uri;
gchar *debug;
if (initialized_uris)
return;
if (!initialized_modules) {
g_debug ("modules not initialized");
return;
}
G_LOCK (uris);
if (!initialized_uris) {
/* Ask for the global x-trust-store option */
trust_store_uri = p11_kit_config_option (NULL, "x-trust-store");
for (l = all_modules; !trust_store_uri && l != NULL; l = g_list_next (l)) {
trust_store_uri = p11_kit_config_option (gck_module_get_functions (l->data),
"x-trust-store");
}
uris = g_ptr_array_new ();
uri = p11_kit_config_option (NULL, "x-trust-lookup");
if (uri != NULL)
g_ptr_array_add (uris, uri);
for (l = all_modules; l != NULL; l = g_list_next (l)) {
uri = p11_kit_config_option (gck_module_get_functions (l->data),
"x-trust-lookup");
if (uri != NULL)
g_ptr_array_add (uris, uri);
}
g_ptr_array_add (uris, NULL);
trust_lookup_uris = (gchar**)g_ptr_array_free (uris, FALSE);
g_debug ("trust store uri is: %s", trust_store_uri);
debug = g_strjoinv (" ", trust_lookup_uris);
g_debug ("trust lookup uris are: %s", debug);
g_free (debug);
initialized_uris = TRUE;
}
G_UNLOCK (uris);
}
static void
on_initialize_registered (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
GError *error = NULL;
GList *results;
results = gck_modules_initialize_registered_finish (result, &error);
if (error != NULL) {
g_debug ("failed %s", error->message);
g_task_return_error (task, g_steal_pointer (&error));
g_clear_object (&task);
return;
}
G_LOCK (modules);
if (!initialized_modules) {
all_modules = g_list_concat (all_modules, results);
results = NULL;
initialized_modules = TRUE;
}
G_UNLOCK (modules);
g_clear_list (&results, g_object_unref);
g_debug ("completed initialize of registered modules");
g_task_return_boolean (task, TRUE);
g_clear_object (&task);
}
/**
* gcr_pkcs11_initialize_async:
* @cancellable: (nullable): optional cancellable used to cancel the operation
* @callback: callback which will be called when the operation completes
* @user_data: data passed to the callback
*
* Asynchronously initialize the registered PKCS#11 modules.
*/
void
gcr_pkcs11_initialize_async (GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, gcr_pkcs11_initialize_async);
if (initialized_modules) {
g_debug ("already initialized, no need to async");
g_task_return_boolean (task, TRUE);
} else {
gck_modules_initialize_registered_async (cancellable,
on_initialize_registered,
g_steal_pointer (&task));
g_debug ("starting initialize of registered modules");
}
g_clear_object (&task);
}
/**
* gcr_pkcs11_initialize_finish:
* @result: the asynchronous result
* @error: location to place an error on failure
*
* Complete the asynchronous operation to initialize the registered PKCS#11
* modules.
*
* Returns: whether the operation was successful or not.
*/
gboolean
gcr_pkcs11_initialize_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
/**
* gcr_pkcs11_initialize:
* @cancellable: optional cancellable used to cancel the operation
* @error: location to place an error on failure
*
* Asynchronously initialize the registered PKCS#11 modules.
*
* Returns: whether the operation was successful or not.
*/
gboolean
gcr_pkcs11_initialize (GCancellable *cancellable,
GError **error)
{
GList *results;
GError *err = NULL;
if (initialized_modules)
return TRUE;
results = gck_modules_initialize_registered (cancellable, &err);
if (err == NULL) {
g_debug ("registered module initialize succeeded: %d modules",
g_list_length (results));
G_LOCK (modules);
if (!initialized_modules) {
all_modules = g_list_concat (all_modules, results);
results = NULL;
initialized_modules = TRUE;
}
G_UNLOCK (modules);
} else {
g_debug ("registered module initialize failed: %s", err->message);
g_propagate_error (error, err);
}
g_clear_list (&results, g_object_unref);
return (err == NULL);
}
/**
* gcr_pkcs11_get_modules:
*
* List all the PKCS#11 modules that are used by the GCR library.
* Each module is a [class@Gck.Module] object.
*
* An empty list of modules will be returned if [func@pkcs11_set_modules],
* or [func@pkcs11_initialize] has not yet run.
*
* Returns: (transfer full) (element-type Gck.Module): a newly allocated list
* of #GckModule objects
*/
GList*
gcr_pkcs11_get_modules (void)
{
if (!initialized_modules)
g_debug ("pkcs11 not yet initialized");
else if (!all_modules)
g_debug ("no modules loaded");
return g_list_copy_deep (all_modules, (GCopyFunc) g_object_ref, NULL);
}
/**
* gcr_pkcs11_set_modules:
* @modules: (element-type Gck.Module): a list of PKCS#11 modules
*
* Set the list of PKCS#11 modules that are used by the GCR library.
* Each module in the list is a [class@Gck.Module] object.
*
* It is not normally necessary to call this function. The available
* PKCS#11 modules installed on the system are automatically loaded
* by the GCR library.
*/
void
gcr_pkcs11_set_modules (GList *modules)
{
for (GList *l = modules; l; l = g_list_next (l))
g_return_if_fail (GCK_IS_MODULE (l->data));
modules = g_list_copy_deep (modules, (GCopyFunc) g_object_ref, NULL);
g_clear_list (&all_modules, g_object_unref);
all_modules = modules;
initialized_modules = TRUE;
}
/**
* gcr_pkcs11_add_module:
* @module: a #GckModule
*
* Add a #GckModule to the list of PKCS#11 modules that are used by the
* GCR library.
*
* It is not normally necessary to call this function. The available
* PKCS#11 modules installed on the system are automatically loaded
* by the GCR library.
*/
void
gcr_pkcs11_add_module (GckModule *module)
{
g_return_if_fail (GCK_IS_MODULE (module));
all_modules = g_list_append (all_modules, g_object_ref (module));
}
/**
* gcr_pkcs11_add_module_from_file:
* @module_path: the full file path of the PKCS#11 module
* @unused: unused
* @error: a #GError or %NULL
*
* Initialize a PKCS#11 module and add it to the modules that are
* used by the GCR library. Note that is an error to initialize the same
* PKCS#11 module twice.
*
* It is not normally necessary to call this function. The available
* PKCS#11 modules installed on the system are automatically loaded
* by the GCR library.
*
* Returns: whether the module was sucessfully added.
*/
gboolean
gcr_pkcs11_add_module_from_file (const gchar *module_path, gpointer unused,
GError **error)
{
GckModule *module;
GError *err = NULL;
g_return_val_if_fail (module_path, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
module = gck_module_initialize (module_path, NULL, &err);
if (module == NULL) {
g_debug ("initializing module failed: %s: %s",
module_path, err->message);
g_propagate_error (error, err);
return FALSE;
}
gcr_pkcs11_add_module (module);
g_debug ("initialized and added module: %s", module_path);
g_object_unref (module);
return TRUE;
}
/**
* gcr_pkcs11_get_trust_store_slot:
*
* Selects an appropriate PKCS#11 slot to store trust assertions. The slot
* to use is normally configured automatically by the system.
*
* This will only return a valid result after the [func@pkcs11_initialize]
* method has been called.
*
* When done with the #GckSlot, use g_object_unref() to release it.
*
* Returns: (transfer full) (nullable): the #GckSlot to use for trust
* assertions, or null if not initialized or no appropriate
* trust store could be found.
*/
GckSlot *
gcr_pkcs11_get_trust_store_slot (void)
{
GckSlot *slot;
GError *error = NULL;
if (!initialized_modules)
return NULL;
initialize_uris ();
if (!trust_store_uri) {
g_warning ("no slot available for storing assertions");
return NULL;
}
slot = gck_modules_token_for_uri (all_modules, trust_store_uri, &error);
if (!slot) {
if (error) {
g_warning ("error finding slot to store trust assertions: %s: %s",
trust_store_uri, egg_error_message (error));
g_clear_error (&error);
} else {
g_debug ("no trust store slot found");
}
}
return slot;
}
/**
* gcr_pkcs11_get_trust_lookup_slots:
*
* List all the PKCS#11 slots that are used by the GCR library for lookup
* of trust assertions. Each slot is a [class@Gck.Slot] object.
*
* This will return an empty list if the [func@pkcs11_initialize] function has
* not yet been called.
*
* Returns: (transfer full) (element-type Gck.Slot): a list of #GckSlot
* objects to use for lookup of trust, or the empty list if not
* initialized or no appropriate trust stores could be found.
*/
GList*
gcr_pkcs11_get_trust_lookup_slots (void)
{
GList *results = NULL;
GError *error = NULL;
gchar **uri;
if (!initialized_modules)
return NULL;
initialize_uris ();
if (!trust_lookup_uris) {
g_warning ("no slots available for assertion lookup");
return NULL;
}
for (uri = trust_lookup_uris; uri && *uri; ++uri) {
results = g_list_concat (results, gck_modules_tokens_for_uri (all_modules, *uri, &error));
if (error != NULL) {
g_warning ("error finding slot for trust assertions: %s: %s",
*uri, egg_error_message (error));
g_clear_error (&error);
}
}
if (results == NULL)
g_debug ("no trust lookup slots found");
return results;
}
/**
* gcr_pkcs11_get_trust_store_uri:
*
* Get the PKCS#11 URI that is used to identify which slot to use for
* storing trust storage.
*
* Returns: (nullable): the uri which identifies trust storage slot
*/
const gchar*
gcr_pkcs11_get_trust_store_uri (void)
{
initialize_uris ();
return trust_store_uri;
}
/**
* gcr_pkcs11_set_trust_store_uri:
* @pkcs11_uri: (nullable): the uri which identifies trust storage slot
*
* Set the PKCS#11 URI that is used to identify which slot to use for
* storing trust assertions.
*
* It is not normally necessary to call this function. The relevant
* PKCS#11 slot is automatically configured by the GCR library.
*/
void
gcr_pkcs11_set_trust_store_uri (const gchar *pkcs11_uri)
{
G_LOCK (uris);
g_free (trust_store_uri);
trust_store_uri = g_strdup (pkcs11_uri);
initialized_uris = TRUE;
G_UNLOCK (uris);
}
/**
* gcr_pkcs11_get_trust_lookup_uris:
*
* Get the PKCS#11 URIs that are used to identify which slots to use for
* lookup trust assertions.
*
* Returns: (nullable) (transfer none): the uri which identifies trust storage slot
*/
const gchar **
gcr_pkcs11_get_trust_lookup_uris (void)
{
initialize_uris ();
return (const gchar **)trust_lookup_uris;
}
/**
* gcr_pkcs11_set_trust_lookup_uris:
* @pkcs11_uris: (nullable): the uris which identifies trust lookup slots
*
* Set the PKCS#11 URIs that are used to identify which slots to use for
* lookup of trust assertions.
*
* It is not normally necessary to call this function. The relevant
* PKCS#11 slots are automatically configured by the GCR library.
*/
void
gcr_pkcs11_set_trust_lookup_uris (const gchar **pkcs11_uris)
{
G_LOCK (uris);
g_strfreev (trust_lookup_uris);
trust_lookup_uris = g_strdupv ((gchar**)pkcs11_uris);
initialized_uris = TRUE;
G_UNLOCK (uris);
}