/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gck-modules.c - the GObject PKCS#11 wrapper library Copyright (C) 2010, Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, see . Author: Stef Walter */ #include "config.h" #include "gck.h" #include "gck-private.h" #include "gck/gck-marshal.h" #include #define P11_KIT_FUTURE_UNSTABLE_API 1 #include #include #include /* * GckModule lists: * * These functions are useful for dealing with lists of modules, and performing * operations on all of them. */ typedef struct { GckArguments base; GList *results; GError *error; } InitializeRegistered; static CK_RV perform_initialize_registered (InitializeRegistered *args) { GckModule *module; CK_FUNCTION_LIST_PTR *modules, *funcs; modules = p11_kit_modules_load_and_initialize (0); if (modules == NULL) { g_set_error (&args->error, GCK_ERROR, (int)GCK_ERROR_MODULE_PROBLEM, _("Couldn’t initialize registered PKCS#11 modules: %s"), p11_kit_message ()); return GCK_ERROR_MODULE_PROBLEM; } for (funcs = modules; *funcs; ++funcs) { module = _gck_module_new_initialized (*funcs); args->results = g_list_prepend (args->results, module); } free (modules); return CKR_OK; } static void free_initialize_registered (InitializeRegistered *args) { g_clear_error (&args->error); g_clear_list (&args->results, g_object_unref); g_free (args); } /** * gck_modules_initialize_registered: * @cancellable: (nullable): optional cancellation object * @error: (out) (optional): location to place an error on failure * * Load and initialize all the registered modules. * * Returns: (transfer full) (element-type Gck.Module): A newly allocated list * of #GckModule objects. */ GList* gck_modules_initialize_registered (GCancellable *cancellable, GError **error) { InitializeRegistered args = { GCK_ARGUMENTS_INIT, 0, }; if (!_gck_call_sync (NULL, perform_initialize_registered, NULL, &args, cancellable, error)) { if (args.error) { g_clear_error (error); g_propagate_error (error, args.error); args.error = NULL; } } g_clear_error (&args.error); return args.results; } /** * gck_modules_initialize_registered_async: * @cancellable: optional cancellation object * @callback: a callback which will be called when the operation completes * @user_data: data to pass to the callback * * Load and initialize all the registered modules asynchronously. */ void gck_modules_initialize_registered_async (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GckCall *call; call = _gck_call_async_prep (NULL, perform_initialize_registered, NULL, sizeof (InitializeRegistered), free_initialize_registered); _gck_call_async_ready_go (call, NULL, cancellable, callback, user_data); } /** * gck_modules_initialize_registered_finish: * @result: the asynchronous result * @error: location to place an error on failure * * Finishes the asynchronous operation to initialize the registered * PKCS#11 modules. * * Returns: (transfer full) (element-type Gck.Module): a list of newly * initialized #GckModule objects */ GList * gck_modules_initialize_registered_finish (GAsyncResult *result, GError **error) { GList *modules = NULL; InitializeRegistered *args; args = _gck_call_async_result_arguments (result, InitializeRegistered); if (_gck_call_basic_finish (result, error)) { modules = args->results; args->results = NULL; } else { /* A custom error from perform_initialize */ if (args->error) { g_clear_error (error); g_propagate_error (error, args->error); args->error = NULL; } } return modules; } /** * gck_modules_get_slots: * @modules: (element-type Gck.Module): The modules * @token_present: Whether to only list slots with token present * * Get a list of slots for across all of the modules. * * Returns: (transfer full) (element-type Gck.Slot): A list of #GckSlot * objects. */ GList* gck_modules_get_slots (GList *modules, gboolean token_present) { GList *result = NULL; GList *m; for (m = modules; m; m = g_list_next (m)) { result = g_list_concat (result, gck_module_get_slots (m->data, token_present)); } return result; } /** * gck_modules_enumerate_objects: * @modules: (element-type Gck.Module): The modules * @attrs: attributes that the objects must have, or empty for all objects * @session_options: Options from GckSessionOptions * * Setup an enumerator for listing matching objects on the modules. * * This call will not block but will return an enumerator immediately. * * Return value: (transfer full): A new enumerator, which should be released * with g_object_unref(). **/ GckEnumerator* gck_modules_enumerate_objects (GList *modules, GckAttributes *attrs, GckSessionOptions session_options) { GckUriData *uri_data; g_return_val_if_fail (attrs, NULL); uri_data = gck_uri_data_new (); uri_data->attributes = gck_attributes_ref (attrs); return _gck_enumerator_new_for_modules (modules, session_options, uri_data); } static GList * tokens_for_uri (GList *modules, const gchar *uri, gboolean only_one, GError **error) { GckTokenInfo *token_info; GList *results = NULL; GckUriData *uri_data; GckModuleInfo *module_info; GList *slots; GList *m, *s; gboolean matched; GckUriFlags flags; flags = GCK_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE | GCK_URI_FOR_MODULE_WITH_VERSION; uri_data = gck_uri_data_parse (uri, flags, error); if (uri_data == NULL) return NULL; if (!uri_data->any_unrecognized) { for (m = modules; m != NULL; m = g_list_next (m)) { if (only_one && results) break; if (uri_data->module_info) { module_info = gck_module_get_info (m->data); matched = _gck_module_info_match (uri_data->module_info, module_info); gck_module_info_free (module_info); if (!matched) continue; } slots = gck_module_get_slots (m->data, TRUE); for (s = slots; s != NULL; s = g_list_next (s)) { if (only_one && results) break; if (!uri_data->token_info) { results = g_list_prepend (results, g_object_ref (s->data)); } else { token_info = gck_slot_get_token_info (s->data); if (token_info && _gck_token_info_match (uri_data->token_info, token_info)) results = g_list_prepend (results, g_object_ref (s->data)); gck_token_info_free (token_info); } } g_clear_list (&slots, g_object_unref); } } gck_uri_data_free (uri_data); return results; } /** * gck_modules_token_for_uri: * @modules: (element-type Gck.Module): The modules * @uri: The URI that the token must match * @error: A location to raise an error on failure * * Lookup a token that matches the URI. * * Returns: (transfer full): A newly allocated #GckSlot or %NULL if no such * token was found. */ GckSlot* gck_modules_token_for_uri (GList *modules, const gchar *uri, GError **error) { GList *results; GckSlot *slot = NULL; g_return_val_if_fail (uri != NULL, NULL); results = tokens_for_uri (modules, uri, TRUE, error); if (results) slot = g_object_ref (results->data); g_clear_list (&results, g_object_unref); return slot; } /** * gck_modules_tokens_for_uri: * @modules: (element-type Gck.Module): The modules * @uri: The URI that the token must match * @error: A location to raise an error on failure * * Lookup a token that matches the URI. * * Returns: (transfer full) (element-type Gck.Slot): A list of newly allocated * #GckSlot objects. */ GList * gck_modules_tokens_for_uri (GList *modules, const gchar *uri, GError **error) { g_return_val_if_fail (uri != NULL, NULL); return tokens_for_uri (modules, uri, FALSE, error); } /** * gck_modules_object_for_uri: * @modules: (element-type Gck.Module): The modules * @uri: The URI the objects must match * @session_options: Options from GckSessionOptions * @error: A location to raise an error on failure. * * Find an object that matches a URI. * * This call can block. Use [func@modules_enumerate_uri] for a non-blocking * version. * * Returns: (transfer full) (nullable): A new #GckObject which should be released with * g_object_unref(), or %NULL if no matching object was found. */ GckObject* gck_modules_object_for_uri (GList *modules, const gchar *uri, GckSessionOptions session_options, GError **error) { GckEnumerator *en; GckObject *result; g_return_val_if_fail (uri != NULL, NULL); g_return_val_if_fail (!error || !*error, NULL); en = gck_modules_enumerate_uri (modules, uri, session_options, error); if (en == NULL) return NULL; result = gck_enumerator_next (en, NULL, error); g_object_unref (en); return result; } /** * gck_modules_objects_for_uri: * @modules: (element-type Gck.Module): The modules * @uri: The URI the objects must match * @session_options: Options from GckSessionOptions * @error: A location to raise an error on failure. * * Find objects that match a URI. * * This call can block. Use [func@modules_enumerate_uri] for a non-blocking * version. * * Returns: (transfer full) (element-type Gck.Object): A (possibly empty) list * of `Gck.Object`s. */ GList* gck_modules_objects_for_uri (GList *modules, const gchar *uri, GckSessionOptions session_options, GError **error) { GckEnumerator *en; GList *results; g_return_val_if_fail (uri != NULL, NULL); g_return_val_if_fail (!error || !*error, NULL); en = gck_modules_enumerate_uri (modules, uri, session_options, error); if (en == NULL) return NULL; results = gck_enumerator_next_n (en, -1, NULL, error); g_object_unref (en); return results; } /** * gck_modules_enumerate_uri: * @modules: (element-type Gck.Module): The modules * @uri: The URI that the enumerator will match * @session_options: Options from GckSessionOptions * @error: A location to raise an error on failure. * * Enumerate objects that match a URI. * * This call will not block. Use the [class@Enumerator] functions in order to * get at the actual objects that match. * * Returns: (transfer full): A new #GckEnumerator, or %NULL if an error occurs. */ GckEnumerator* gck_modules_enumerate_uri (GList *modules, const gchar *uri, GckSessionOptions session_options, GError **error) { GckUriData *uri_data; g_return_val_if_fail (uri != NULL, NULL); uri_data = gck_uri_data_parse (uri, GCK_URI_FOR_ANY, error); if (uri_data == NULL) return NULL; /* Takes ownership of uri_info */ return _gck_enumerator_new_for_modules (modules, session_options, uri_data); }