1/* module.c - Module management for libgcrypt. 2 * Copyright (C) 2003, 2008 Free Software Foundation, Inc. 3 * 4 * This file is part of Libgcrypt. 5 * 6 * Libgcrypt is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser general Public License as 8 * published by the Free Software Foundation; either version 2.1 of 9 * the License, or (at your option) any later version. 10 * 11 * Libgcrypt is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include <config.h> 21#include <errno.h> 22#include "g10lib.h" 23 24/* Please match these numbers with the allocated algorithm 25 numbers. */ 26#define MODULE_ID_MIN 600 27#define MODULE_ID_LAST 65500 28#define MODULE_ID_USER GCRY_MODULE_ID_USER 29#define MODULE_ID_USER_LAST GCRY_MODULE_ID_USER_LAST 30 31#if MODULE_ID_MIN >= MODULE_ID_USER 32#error Need to implement a different search strategy 33#endif 34 35/* Internal function. Generate a new, unique module ID for a module 36 that should be inserted into the module chain starting at 37 MODULES. */ 38static gcry_err_code_t 39_gcry_module_id_new (gcry_module_t modules, unsigned int *id_new) 40{ 41 unsigned int mod_id; 42 gcry_err_code_t err = GPG_ERR_NO_ERROR; 43 gcry_module_t module; 44 45 /* Search for unused ID. */ 46 for (mod_id = MODULE_ID_MIN; mod_id < MODULE_ID_LAST; mod_id++) 47 { 48 if (mod_id == MODULE_ID_USER) 49 { 50 mod_id = MODULE_ID_USER_LAST; 51 continue; 52 } 53 54 /* Search for a module with the current ID. */ 55 for (module = modules; module; module = module->next) 56 if (mod_id == module->mod_id) 57 break; 58 59 if (! module) 60 /* None found -> the ID is available for use. */ 61 break; 62 } 63 64 if (mod_id < MODULE_ID_LAST) 65 /* Done. */ 66 *id_new = mod_id; 67 else 68 /* No free ID found. */ 69 err = GPG_ERR_INTERNAL; 70 71 return err; 72} 73 74/* Add a module specification to the list ENTRIES. The new module has 75 it's use-counter set to one. */ 76gcry_err_code_t 77_gcry_module_add (gcry_module_t *entries, unsigned int mod_id, 78 void *spec, void *extraspec, gcry_module_t *module) 79{ 80 gcry_err_code_t err = 0; 81 gcry_module_t entry; 82 83 if (! mod_id) 84 err = _gcry_module_id_new (*entries, &mod_id); 85 86 if (! err) 87 { 88 entry = gcry_malloc (sizeof (struct gcry_module)); 89 if (! entry) 90 err = gpg_err_code_from_errno (errno); 91 } 92 93 if (! err) 94 { 95 /* Fill new module entry. */ 96 entry->flags = 0; 97 entry->counter = 1; 98 entry->spec = spec; 99 entry->extraspec = extraspec; 100 entry->mod_id = mod_id; 101 102 /* Link it into the list. */ 103 entry->next = *entries; 104 entry->prevp = entries; 105 if (*entries) 106 (*entries)->prevp = &entry->next; 107 *entries = entry; 108 109 /* And give it to the caller. */ 110 if (module) 111 *module = entry; 112 } 113 return err; 114} 115 116/* Internal function. Unlink CIPHER_ENTRY from the list of registered 117 ciphers and destroy it. */ 118static void 119_gcry_module_drop (gcry_module_t entry) 120{ 121 *entry->prevp = entry->next; 122 if (entry->next) 123 entry->next->prevp = entry->prevp; 124 125 gcry_free (entry); 126} 127 128/* Lookup a module specification by it's ID. After a successful 129 lookup, the module has it's resource counter incremented. */ 130gcry_module_t 131_gcry_module_lookup_id (gcry_module_t entries, unsigned int mod_id) 132{ 133 gcry_module_t entry; 134 135 for (entry = entries; entry; entry = entry->next) 136 if (entry->mod_id == mod_id) 137 { 138 entry->counter++; 139 break; 140 } 141 142 return entry; 143} 144 145/* Lookup a module specification. After a successful lookup, the 146 module has it's resource counter incremented. FUNC is a function 147 provided by the caller, which is responsible for identifying the 148 wanted module. */ 149gcry_module_t 150_gcry_module_lookup (gcry_module_t entries, void *data, 151 gcry_module_lookup_t func) 152{ 153 gcry_module_t entry; 154 155 for (entry = entries; entry; entry = entry->next) 156 if ((*func) (entry->spec, data)) 157 { 158 entry->counter++; 159 break; 160 } 161 162 return entry; 163} 164 165/* Release a module. In case the use-counter reaches zero, destroy 166 the module. Passing MODULE as NULL is a dummy operation (similar 167 to free()). */ 168void 169_gcry_module_release (gcry_module_t module) 170{ 171 if (module && ! --module->counter) 172 _gcry_module_drop (module); 173} 174 175/* Add a reference to a module. */ 176void 177_gcry_module_use (gcry_module_t module) 178{ 179 ++module->counter; 180} 181 182/* If LIST is zero, write the number of modules identified by MODULES 183 to LIST_LENGTH and return. If LIST is non-zero, the first 184 *LIST_LENGTH algorithm IDs are stored in LIST, which must be of 185 according size. In case there are less cipher modules than 186 *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ 187gcry_err_code_t 188_gcry_module_list (gcry_module_t modules, 189 int *list, int *list_length) 190{ 191 gcry_err_code_t err = GPG_ERR_NO_ERROR; 192 gcry_module_t module; 193 int length, i; 194 195 for (module = modules, length = 0; module; module = module->next, length++); 196 197 if (list) 198 { 199 if (length > *list_length) 200 length = *list_length; 201 202 for (module = modules, i = 0; i < length; module = module->next, i++) 203 list[i] = module->mod_id; 204 205 if (length < *list_length) 206 *list_length = length; 207 } 208 else 209 *list_length = length; 210 211 return err; 212} 213