blob: c70a44c08a25376a5bcb7a3d302495bdade4edd5 [file] [log] [blame]
/* module.c - Module management for libgcrypt.
* Copyright (C) 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt 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.
*
* Libgcrypt 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <errno.h>
#include "g10lib.h"
/* Please match these numbers with the allocated algorithm
numbers. */
#define MODULE_ID_MIN 600
#define MODULE_ID_LAST 65500
#define MODULE_ID_USER GCRY_MODULE_ID_USER
#define MODULE_ID_USER_LAST GCRY_MODULE_ID_USER_LAST
#if MODULE_ID_MIN >= MODULE_ID_USER
#error Need to implement a different search strategy
#endif
/* Internal function. Generate a new, unique module ID for a module
that should be inserted into the module chain starting at
MODULES. */
static gcry_err_code_t
_gcry_module_id_new (gcry_module_t modules, unsigned int *id_new)
{
unsigned int mod_id;
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_module_t module;
/* Search for unused ID. */
for (mod_id = MODULE_ID_MIN; mod_id < MODULE_ID_LAST; mod_id++)
{
if (mod_id == MODULE_ID_USER)
{
mod_id = MODULE_ID_USER_LAST;
continue;
}
/* Search for a module with the current ID. */
for (module = modules; module; module = module->next)
if (mod_id == module->mod_id)
break;
if (! module)
/* None found -> the ID is available for use. */
break;
}
if (mod_id < MODULE_ID_LAST)
/* Done. */
*id_new = mod_id;
else
/* No free ID found. */
err = GPG_ERR_INTERNAL;
return err;
}
/* Add a module specification to the list ENTRIES. The new module has
it's use-counter set to one. */
gcry_err_code_t
_gcry_module_add (gcry_module_t *entries, unsigned int mod_id,
void *spec, void *extraspec, gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t entry;
if (! mod_id)
err = _gcry_module_id_new (*entries, &mod_id);
if (! err)
{
entry = gcry_malloc (sizeof (struct gcry_module));
if (! entry)
err = gpg_err_code_from_errno (errno);
}
if (! err)
{
/* Fill new module entry. */
entry->flags = 0;
entry->counter = 1;
entry->spec = spec;
entry->extraspec = extraspec;
entry->mod_id = mod_id;
/* Link it into the list. */
entry->next = *entries;
entry->prevp = entries;
if (*entries)
(*entries)->prevp = &entry->next;
*entries = entry;
/* And give it to the caller. */
if (module)
*module = entry;
}
return err;
}
/* Internal function. Unlink CIPHER_ENTRY from the list of registered
ciphers and destroy it. */
static void
_gcry_module_drop (gcry_module_t entry)
{
*entry->prevp = entry->next;
if (entry->next)
entry->next->prevp = entry->prevp;
gcry_free (entry);
}
/* Lookup a module specification by it's ID. After a successfull
lookup, the module has it's resource counter incremented. */
gcry_module_t
_gcry_module_lookup_id (gcry_module_t entries, unsigned int mod_id)
{
gcry_module_t entry;
for (entry = entries; entry; entry = entry->next)
if (entry->mod_id == mod_id)
{
entry->counter++;
break;
}
return entry;
}
/* Lookup a module specification. After a successfull lookup, the
module has it's resource counter incremented. FUNC is a function
provided by the caller, which is responsible for identifying the
wanted module. */
gcry_module_t
_gcry_module_lookup (gcry_module_t entries, void *data,
gcry_module_lookup_t func)
{
gcry_module_t entry;
for (entry = entries; entry; entry = entry->next)
if ((*func) (entry->spec, data))
{
entry->counter++;
break;
}
return entry;
}
/* Release a module. In case the use-counter reaches zero, destroy
the module. Passing MODULE as NULL is a dummy operation (similar
to free()). */
void
_gcry_module_release (gcry_module_t module)
{
if (module && ! --module->counter)
_gcry_module_drop (module);
}
/* Add a reference to a module. */
void
_gcry_module_use (gcry_module_t module)
{
++module->counter;
}
/* If LIST is zero, write the number of modules identified by MODULES
to LIST_LENGTH and return. If LIST is non-zero, the first
*LIST_LENGTH algorithm IDs are stored in LIST, which must be of
according size. In case there are less cipher modules than
*LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */
gcry_err_code_t
_gcry_module_list (gcry_module_t modules,
int *list, int *list_length)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_module_t module;
int length, i;
for (module = modules, length = 0; module; module = module->next, length++);
if (list)
{
if (length > *list_length)
length = *list_length;
for (module = modules, i = 0; i < length; module = module->next, i++)
list[i] = module->mod_id;
if (length < *list_length)
*list_length = length;
}
else
*list_length = length;
return err;
}