oops, reinstate correct prototype
[openssl.git] / crypto / engine / eng_list.c
1 /* crypto/engine/eng_list.c */
2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 /* ====================================================================
59  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60  * ECDH support in OpenSSL originally developed by 
61  * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
62  */
63
64 #include "eng_int.h"
65
66 /* The linked-list of pointers to engine types. engine_list_head
67  * incorporates an implicit structural reference but engine_list_tail
68  * does not - the latter is a computational niceity and only points
69  * to something that is already pointed to by its predecessor in the
70  * list (or engine_list_head itself). In the same way, the use of the
71  * "prev" pointer in each ENGINE is to save excessive list iteration,
72  * it doesn't correspond to an extra structural reference. Hence,
73  * engine_list_head, and each non-null "next" pointer account for
74  * the list itself assuming exactly 1 structural reference on each
75  * list member. */
76 static ENGINE *engine_list_head = NULL;
77 static ENGINE *engine_list_tail = NULL;
78
79 /* This cleanup function is only needed internally. If it should be called, we
80  * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */
81
82 static void engine_list_cleanup(void)
83         {
84         ENGINE *iterator = engine_list_head;
85
86         while(iterator != NULL)
87                 {
88                 ENGINE_remove(iterator);
89                 iterator = engine_list_head;
90                 }
91         return;
92         }
93
94 /* These static functions starting with a lower case "engine_" always
95  * take place when CRYPTO_LOCK_ENGINE has been locked up. */
96 static int engine_list_add(ENGINE *e)
97         {
98         int conflict = 0;
99         ENGINE *iterator = NULL;
100
101         if(e == NULL)
102                 {
103                 ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
104                         ERR_R_PASSED_NULL_PARAMETER);
105                 return 0;
106                 }
107         iterator = engine_list_head;
108         while(iterator && !conflict)
109                 {
110                 conflict = (strcmp(iterator->id, e->id) == 0);
111                 iterator = iterator->next;
112                 }
113         if(conflict)
114                 {
115                 ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
116                         ENGINE_R_CONFLICTING_ENGINE_ID);
117                 return 0;
118                 }
119         if(engine_list_head == NULL)
120                 {
121                 /* We are adding to an empty list. */
122                 if(engine_list_tail)
123                         {
124                         ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
125                                 ENGINE_R_INTERNAL_LIST_ERROR);
126                         return 0;
127                         }
128                 engine_list_head = e;
129                 e->prev = NULL;
130                 /* The first time the list allocates, we should register the
131                  * cleanup. */
132                 engine_cleanup_add_last(engine_list_cleanup);
133                 }
134         else
135                 {
136                 /* We are adding to the tail of an existing list. */
137                 if((engine_list_tail == NULL) ||
138                                 (engine_list_tail->next != NULL))
139                         {
140                         ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
141                                 ENGINE_R_INTERNAL_LIST_ERROR);
142                         return 0;
143                         }
144                 engine_list_tail->next = e;
145                 e->prev = engine_list_tail;
146                 }
147         /* Having the engine in the list assumes a structural
148          * reference. */
149         e->struct_ref++;
150         engine_ref_debug(e, 0, 1)
151         /* However it came to be, e is the last item in the list. */
152         engine_list_tail = e;
153         e->next = NULL;
154         return 1;
155         }
156
157 static int engine_list_remove(ENGINE *e)
158         {
159         ENGINE *iterator;
160
161         if(e == NULL)
162                 {
163                 ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
164                         ERR_R_PASSED_NULL_PARAMETER);
165                 return 0;
166                 }
167         /* We need to check that e is in our linked list! */
168         iterator = engine_list_head;
169         while(iterator && (iterator != e))
170                 iterator = iterator->next;
171         if(iterator == NULL)
172                 {
173                 ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
174                         ENGINE_R_ENGINE_IS_NOT_IN_LIST);
175                 return 0;
176                 }
177         /* un-link e from the chain. */
178         if(e->next)
179                 e->next->prev = e->prev;
180         if(e->prev)
181                 e->prev->next = e->next;
182         /* Correct our head/tail if necessary. */
183         if(engine_list_head == e)
184                 engine_list_head = e->next;
185         if(engine_list_tail == e)
186                 engine_list_tail = e->prev;
187         engine_free_util(e, 0);
188         return 1;
189         }
190
191 /* Get the first/last "ENGINE" type available. */
192 ENGINE *ENGINE_get_first(void)
193         {
194         ENGINE *ret;
195
196         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
197         ret = engine_list_head;
198         if(ret)
199                 {
200                 ret->struct_ref++;
201                 engine_ref_debug(ret, 0, 1)
202                 }
203         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
204         return ret;
205         }
206
207 ENGINE *ENGINE_get_last(void)
208         {
209         ENGINE *ret;
210
211         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
212         ret = engine_list_tail;
213         if(ret)
214                 {
215                 ret->struct_ref++;
216                 engine_ref_debug(ret, 0, 1)
217                 }
218         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
219         return ret;
220         }
221
222 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
223 ENGINE *ENGINE_get_next(ENGINE *e)
224         {
225         ENGINE *ret = NULL;
226         if(e == NULL)
227                 {
228                 ENGINEerr(ENGINE_F_ENGINE_GET_NEXT,
229                         ERR_R_PASSED_NULL_PARAMETER);
230                 return 0;
231                 }
232         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
233         ret = e->next;
234         if(ret)
235                 {
236                 /* Return a valid structural refernce to the next ENGINE */
237                 ret->struct_ref++;
238                 engine_ref_debug(ret, 0, 1)
239                 }
240         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
241         /* Release the structural reference to the previous ENGINE */
242         ENGINE_free(e);
243         return ret;
244         }
245
246 ENGINE *ENGINE_get_prev(ENGINE *e)
247         {
248         ENGINE *ret = NULL;
249         if(e == NULL)
250                 {
251                 ENGINEerr(ENGINE_F_ENGINE_GET_PREV,
252                         ERR_R_PASSED_NULL_PARAMETER);
253                 return 0;
254                 }
255         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
256         ret = e->prev;
257         if(ret)
258                 {
259                 /* Return a valid structural reference to the next ENGINE */
260                 ret->struct_ref++;
261                 engine_ref_debug(ret, 0, 1)
262                 }
263         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
264         /* Release the structural reference to the previous ENGINE */
265         ENGINE_free(e);
266         return ret;
267         }
268
269 /* Add another "ENGINE" type into the list. */
270 int ENGINE_add(ENGINE *e)
271         {
272         int to_return = 1;
273         if(e == NULL)
274                 {
275                 ENGINEerr(ENGINE_F_ENGINE_ADD,
276                         ERR_R_PASSED_NULL_PARAMETER);
277                 return 0;
278                 }
279         if((e->id == NULL) || (e->name == NULL))
280                 {
281                 ENGINEerr(ENGINE_F_ENGINE_ADD,
282                         ENGINE_R_ID_OR_NAME_MISSING);
283                 }
284         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
285         if(!engine_list_add(e))
286                 {
287                 ENGINEerr(ENGINE_F_ENGINE_ADD,
288                         ENGINE_R_INTERNAL_LIST_ERROR);
289                 to_return = 0;
290                 }
291         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
292         return to_return;
293         }
294
295 /* Remove an existing "ENGINE" type from the array. */
296 int ENGINE_remove(ENGINE *e)
297         {
298         int to_return = 1;
299         if(e == NULL)
300                 {
301                 ENGINEerr(ENGINE_F_ENGINE_REMOVE,
302                         ERR_R_PASSED_NULL_PARAMETER);
303                 return 0;
304                 }
305         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
306         if(!engine_list_remove(e))
307                 {
308                 ENGINEerr(ENGINE_F_ENGINE_REMOVE,
309                         ENGINE_R_INTERNAL_LIST_ERROR);
310                 to_return = 0;
311                 }
312         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
313         return to_return;
314         }
315
316 static void engine_cpy(ENGINE *dest, const ENGINE *src)
317         {
318         dest->id = src->id;
319         dest->name = src->name;
320 #ifndef OPENSSL_NO_RSA
321         dest->rsa_meth = src->rsa_meth;
322 #endif
323 #ifndef OPENSSL_NO_DSA
324         dest->dsa_meth = src->dsa_meth;
325 #endif
326 #ifndef OPENSSL_NO_DH
327         dest->dh_meth = src->dh_meth;
328 #endif
329 #ifndef OPENSSL_NO_ECDH
330         dest->ecdh_meth = src->ecdh_meth;
331 #endif
332 #ifndef OPENSSL_NO_ECDSA
333         dest->ecdsa_meth = src->ecdsa_meth;
334 #endif
335         dest->rand_meth = src->rand_meth;
336         dest->store_meth = src->store_meth;
337         dest->ciphers = src->ciphers;
338         dest->digests = src->digests;
339         dest->pkey_meths = src->pkey_meths;
340         dest->destroy = src->destroy;
341         dest->init = src->init;
342         dest->finish = src->finish;
343         dest->ctrl = src->ctrl;
344         dest->load_privkey = src->load_privkey;
345         dest->load_pubkey = src->load_pubkey;
346         dest->cmd_defns = src->cmd_defns;
347         dest->flags = src->flags;
348         }
349
350 ENGINE *ENGINE_by_id(const char *id)
351         {
352         ENGINE *iterator;
353         char *load_dir = NULL;
354         if(id == NULL)
355                 {
356                 ENGINEerr(ENGINE_F_ENGINE_BY_ID,
357                         ERR_R_PASSED_NULL_PARAMETER);
358                 return NULL;
359                 }
360         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
361         iterator = engine_list_head;
362         while(iterator && (strcmp(id, iterator->id) != 0))
363                 iterator = iterator->next;
364         if(iterator)
365                 {
366                 /* We need to return a structural reference. If this is an
367                  * ENGINE type that returns copies, make a duplicate - otherwise
368                  * increment the existing ENGINE's reference count. */
369                 if(iterator->flags & ENGINE_FLAGS_BY_ID_COPY)
370                         {
371                         ENGINE *cp = ENGINE_new();
372                         if(!cp)
373                                 iterator = NULL;
374                         else
375                                 {
376                                 engine_cpy(cp, iterator);
377                                 iterator = cp;
378                                 }
379                         }
380                 else
381                         {
382                         iterator->struct_ref++;
383                         engine_ref_debug(iterator, 0, 1)
384                         }
385                 }
386         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
387 #if 0
388         if(iterator == NULL)
389                 {
390                 ENGINEerr(ENGINE_F_ENGINE_BY_ID,
391                         ENGINE_R_NO_SUCH_ENGINE);
392                 ERR_add_error_data(2, "id=", id);
393                 }
394         return iterator;
395 #else
396         /* EEK! Experimental code starts */
397         if(iterator) return iterator;
398         /* Prevent infinite recusrion if we're looking for the dynamic engine. */
399         if (strcmp(id, "dynamic"))
400                 {
401 #ifdef OPENSSL_SYS_VMS
402                 if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = "SSLROOT:[ENGINES]";
403 #else
404                 if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = ENGINESDIR;
405 #endif
406                 iterator = ENGINE_by_id("dynamic");
407                 if(!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
408                                 !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
409                                 !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
410                                         load_dir, 0) ||
411                                 !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
412                                 goto notfound;
413                 return iterator;
414                 }
415 notfound:
416         ENGINEerr(ENGINE_F_ENGINE_BY_ID,ENGINE_R_NO_SUCH_ENGINE);
417         ERR_add_error_data(2, "id=", id);
418         return NULL;
419         /* EEK! Experimental code ends */
420 #endif
421         }
422
423 int ENGINE_up_ref(ENGINE *e)
424         {
425         if (e == NULL)
426                 {
427                 ENGINEerr(ENGINE_F_ENGINE_UP_REF,ERR_R_PASSED_NULL_PARAMETER);
428                 return 0;
429                 }
430         CRYPTO_add(&e->struct_ref,1,CRYPTO_LOCK_ENGINE);
431         return 1;
432         }