| /* 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; |
| } |