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