Step 11c of move of engines: Time to make the changes to support
[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 <openssl/crypto.h>
65 #include "cryptlib.h"
66 #include "eng_int.h"
67 #include <openssl/engine.h>
68
69 /* The linked-list of pointers to engine types. engine_list_head
70  * incorporates an implicit structural reference but engine_list_tail
71  * does not - the latter is a computational niceity and only points
72  * to something that is already pointed to by its predecessor in the
73  * list (or engine_list_head itself). In the same way, the use of the
74  * "prev" pointer in each ENGINE is to save excessive list iteration,
75  * it doesn't correspond to an extra structural reference. Hence,
76  * engine_list_head, and each non-null "next" pointer account for
77  * the list itself assuming exactly 1 structural reference on each
78  * list member. */
79 static ENGINE *engine_list_head = NULL;
80 static ENGINE *engine_list_tail = NULL;
81
82 /* This cleanup function is only needed internally. If it should be called, we
83  * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */
84
85 static void engine_list_cleanup(void)
86         {
87         ENGINE *iterator = engine_list_head;
88
89         while(iterator != NULL)
90                 {
91                 ENGINE_remove(iterator);
92                 iterator = engine_list_head;
93                 }
94         return;
95         }
96
97 /* These static functions starting with a lower case "engine_" always
98  * take place when CRYPTO_LOCK_ENGINE has been locked up. */
99 static int engine_list_add(ENGINE *e)
100         {
101         int conflict = 0;
102         ENGINE *iterator = NULL;
103
104         if(e == NULL)
105                 {
106                 ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
107                         ERR_R_PASSED_NULL_PARAMETER);
108                 return 0;
109                 }
110         iterator = engine_list_head;
111         while(iterator && !conflict)
112                 {
113                 conflict = (strcmp(iterator->id, e->id) == 0);
114                 iterator = iterator->next;
115                 }
116         if(conflict)
117                 {
118                 ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
119                         ENGINE_R_CONFLICTING_ENGINE_ID);
120                 return 0;
121                 }
122         if(engine_list_head == NULL)
123                 {
124                 /* We are adding to an empty list. */
125                 if(engine_list_tail)
126                         {
127                         ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
128                                 ENGINE_R_INTERNAL_LIST_ERROR);
129                         return 0;
130                         }
131                 engine_list_head = e;
132                 e->prev = NULL;
133                 /* The first time the list allocates, we should register the
134                  * cleanup. */
135                 engine_cleanup_add_last(engine_list_cleanup);
136                 }
137         else
138                 {
139                 /* We are adding to the tail of an existing list. */
140                 if((engine_list_tail == NULL) ||
141                                 (engine_list_tail->next != NULL))
142                         {
143                         ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
144                                 ENGINE_R_INTERNAL_LIST_ERROR);
145                         return 0;
146                         }
147                 engine_list_tail->next = e;
148                 e->prev = engine_list_tail;
149                 }
150         /* Having the engine in the list assumes a structural
151          * reference. */
152         e->struct_ref++;
153         engine_ref_debug(e, 0, 1)
154         /* However it came to be, e is the last item in the list. */
155         engine_list_tail = e;
156         e->next = NULL;
157         return 1;
158         }
159
160 static int engine_list_remove(ENGINE *e)
161         {
162         ENGINE *iterator;
163
164         if(e == NULL)
165                 {
166                 ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
167                         ERR_R_PASSED_NULL_PARAMETER);
168                 return 0;
169                 }
170         /* We need to check that e is in our linked list! */
171         iterator = engine_list_head;
172         while(iterator && (iterator != e))
173                 iterator = iterator->next;
174         if(iterator == NULL)
175                 {
176                 ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
177                         ENGINE_R_ENGINE_IS_NOT_IN_LIST);
178                 return 0;
179                 }
180         /* un-link e from the chain. */
181         if(e->next)
182                 e->next->prev = e->prev;
183         if(e->prev)
184                 e->prev->next = e->next;
185         /* Correct our head/tail if necessary. */
186         if(engine_list_head == e)
187                 engine_list_head = e->next;
188         if(engine_list_tail == e)
189                 engine_list_tail = e->prev;
190         engine_free_util(e, 0);
191         return 1;
192         }
193
194 /* Get the first/last "ENGINE" type available. */
195 ENGINE *ENGINE_get_first(void)
196         {
197         ENGINE *ret;
198
199         CRYPTO_r_lock(CRYPTO_LOCK_ENGINE);
200         ret = engine_list_head;
201         if(ret)
202                 {
203                 ret->struct_ref++;
204                 engine_ref_debug(ret, 0, 1)
205                 }
206         CRYPTO_r_unlock(CRYPTO_LOCK_ENGINE);
207         return ret;
208         }
209
210 ENGINE *ENGINE_get_last(void)
211         {
212         ENGINE *ret;
213
214         CRYPTO_r_lock(CRYPTO_LOCK_ENGINE);
215                 ret = engine_list_tail;
216         if(ret)
217                 {
218                 ret->struct_ref++;
219                 engine_ref_debug(ret, 0, 1)
220                 }
221         CRYPTO_r_unlock(CRYPTO_LOCK_ENGINE);
222         return ret;
223         }
224
225 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
226 ENGINE *ENGINE_get_next(ENGINE *e)
227         {
228         ENGINE *ret = NULL;
229         if(e == NULL)
230                 {
231                 ENGINEerr(ENGINE_F_ENGINE_GET_NEXT,
232                         ERR_R_PASSED_NULL_PARAMETER);
233                 return 0;
234                 }
235         CRYPTO_r_lock(CRYPTO_LOCK_ENGINE);
236         ret = e->next;
237         if(ret)
238                 {
239                 /* Return a valid structural refernce to the next ENGINE */
240                 ret->struct_ref++;
241                 engine_ref_debug(ret, 0, 1)
242                 }
243         CRYPTO_r_unlock(CRYPTO_LOCK_ENGINE);
244         /* Release the structural reference to the previous ENGINE */
245         ENGINE_free(e);
246         return ret;
247         }
248
249 ENGINE *ENGINE_get_prev(ENGINE *e)
250         {
251         ENGINE *ret = NULL;
252         if(e == NULL)
253                 {
254                 ENGINEerr(ENGINE_F_ENGINE_GET_PREV,
255                         ERR_R_PASSED_NULL_PARAMETER);
256                 return 0;
257                 }
258         CRYPTO_r_lock(CRYPTO_LOCK_ENGINE);
259         ret = e->prev;
260         if(ret)
261                 {
262                 /* Return a valid structural reference to the next ENGINE */
263                 ret->struct_ref++;
264                 engine_ref_debug(ret, 0, 1)
265                 }
266         CRYPTO_r_unlock(CRYPTO_LOCK_ENGINE);
267         /* Release the structural reference to the previous ENGINE */
268         ENGINE_free(e);
269         return ret;
270         }
271
272 /* Add another "ENGINE" type into the list. */
273 int ENGINE_add(ENGINE *e)
274         {
275         int to_return = 1;
276         if(e == NULL)
277                 {
278                 ENGINEerr(ENGINE_F_ENGINE_ADD,
279                         ERR_R_PASSED_NULL_PARAMETER);
280                 return 0;
281                 }
282         if((e->id == NULL) || (e->name == NULL))
283                 {
284                 ENGINEerr(ENGINE_F_ENGINE_ADD,
285                         ENGINE_R_ID_OR_NAME_MISSING);
286                 }
287         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
288         if(!engine_list_add(e))
289                 {
290                 ENGINEerr(ENGINE_F_ENGINE_ADD,
291                         ENGINE_R_INTERNAL_LIST_ERROR);
292                 to_return = 0;
293                 }
294         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
295         return to_return;
296         }
297
298 /* Remove an existing "ENGINE" type from the array. */
299 int ENGINE_remove(ENGINE *e)
300         {
301         int to_return = 1;
302         if(e == NULL)
303                 {
304                 ENGINEerr(ENGINE_F_ENGINE_REMOVE,
305                         ERR_R_PASSED_NULL_PARAMETER);
306                 return 0;
307                 }
308         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
309         if(!engine_list_remove(e))
310                 {
311                 ENGINEerr(ENGINE_F_ENGINE_REMOVE,
312                         ENGINE_R_INTERNAL_LIST_ERROR);
313                 to_return = 0;
314                 }
315         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
316         return to_return;
317         }
318
319 static void engine_cpy(ENGINE *dest, const ENGINE *src)
320         {
321         dest->id = src->id;
322         dest->name = src->name;
323 #ifndef OPENSSL_NO_RSA
324         dest->rsa_meth = src->rsa_meth;
325 #endif
326 #ifndef OPENSSL_NO_DSA
327         dest->dsa_meth = src->dsa_meth;
328 #endif
329 #ifndef OPENSSL_NO_DH
330         dest->dh_meth = src->dh_meth;
331 #endif
332 #ifndef OPENSSL_NO_ECDH
333         dest->ecdh_meth = src->ecdh_meth;
334 #endif
335 #ifndef OPENSSL_NO_ECDSA
336         dest->ecdsa_meth = src->ecdsa_meth;
337 #endif
338         dest->rand_meth = src->rand_meth;
339         dest->ciphers = src->ciphers;
340         dest->digests = src->digests;
341         dest->destroy = src->destroy;
342         dest->init = src->init;
343         dest->finish = src->finish;
344         dest->ctrl = src->ctrl;
345         dest->load_privkey = src->load_privkey;
346         dest->load_pubkey = src->load_pubkey;
347         dest->cmd_defns = src->cmd_defns;
348         dest->flags = src->flags;
349         }
350
351 ENGINE *ENGINE_by_id(const char *id)
352         {
353         ENGINE *iterator;
354         char *load_dir = NULL;
355         if(id == NULL)
356                 {
357                 ENGINEerr(ENGINE_F_ENGINE_BY_ID,
358                         ERR_R_PASSED_NULL_PARAMETER);
359                 return NULL;
360                 }
361         CRYPTO_r_lock(CRYPTO_LOCK_ENGINE);
362         iterator = engine_list_head;
363         while(iterator && (strcmp(id, iterator->id) != 0))
364                 iterator = iterator->next;
365         if(iterator)
366                 {
367                 /* We need to return a structural reference. If this is an
368                  * ENGINE type that returns copies, make a duplicate - otherwise
369                  * increment the existing ENGINE's reference count. */
370                 if(iterator->flags & ENGINE_FLAGS_BY_ID_COPY)
371                         {
372                         ENGINE *cp = ENGINE_new();
373                         if(!cp)
374                                 iterator = NULL;
375                         else
376                                 {
377                                 engine_cpy(cp, iterator);
378                                 iterator = cp;
379                                 }
380                         }
381                 else
382                         {
383                         iterator->struct_ref++;
384                         engine_ref_debug(iterator, 0, 1)
385                         }
386                 }
387         CRYPTO_r_unlock(CRYPTO_LOCK_ENGINE);
388 #if 0
389         if(iterator == NULL)
390                 {
391                 ENGINEerr(ENGINE_F_ENGINE_BY_ID,
392                         ENGINE_R_NO_SUCH_ENGINE);
393                 ERR_add_error_data(2, "id=", id);
394                 }
395         return iterator;
396 #else
397         /* EEK! Experimental code starts */
398         if(iterator) return iterator;
399 #ifdef OPENSSL_SYS_VMS
400         if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = "SSLROOT:[ENGINES]";
401 #else
402         if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = OPENSSLDIR "/engines";
403 #endif
404         iterator = ENGINE_by_id("dynamic");
405         if(!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
406                         !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
407                         !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
408                                 load_dir, 0) ||
409                         !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
410                 goto notfound;
411         return iterator;
412 notfound:
413         ENGINEerr(ENGINE_F_ENGINE_BY_ID,ENGINE_R_NO_SUCH_ENGINE);
414         ERR_add_error_data(2, "id=", id);
415         return NULL;
416         /* EEK! Experimental code ends */
417 #endif
418         }