Opacity.
[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_int()" 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 global_engine_lock 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_THREAD_run_once(&engine_lock_init, do_engine_lock_init);
188     CRYPTO_THREAD_write_lock(global_engine_lock);
189     ret = engine_list_head;
190     if (ret) {
191         ret->struct_ref++;
192         engine_ref_debug(ret, 0, 1);
193     }
194     CRYPTO_THREAD_unlock(global_engine_lock);
195     return ret;
196 }
197
198 ENGINE *ENGINE_get_last(void)
199 {
200     ENGINE *ret;
201
202     CRYPTO_THREAD_run_once(&engine_lock_init, do_engine_lock_init);
203     CRYPTO_THREAD_write_lock(global_engine_lock);
204     ret = engine_list_tail;
205     if (ret) {
206         ret->struct_ref++;
207         engine_ref_debug(ret, 0, 1);
208     }
209     CRYPTO_THREAD_unlock(global_engine_lock);
210     return ret;
211 }
212
213 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
214 ENGINE *ENGINE_get_next(ENGINE *e)
215 {
216     ENGINE *ret = NULL;
217     if (e == NULL) {
218         ENGINEerr(ENGINE_F_ENGINE_GET_NEXT, ERR_R_PASSED_NULL_PARAMETER);
219         return 0;
220     }
221     CRYPTO_THREAD_write_lock(global_engine_lock);
222     ret = e->next;
223     if (ret) {
224         /* Return a valid structural reference to the next ENGINE */
225         ret->struct_ref++;
226         engine_ref_debug(ret, 0, 1);
227     }
228     CRYPTO_THREAD_unlock(global_engine_lock);
229     /* Release the structural reference to the previous ENGINE */
230     ENGINE_free(e);
231     return ret;
232 }
233
234 ENGINE *ENGINE_get_prev(ENGINE *e)
235 {
236     ENGINE *ret = NULL;
237     if (e == NULL) {
238         ENGINEerr(ENGINE_F_ENGINE_GET_PREV, ERR_R_PASSED_NULL_PARAMETER);
239         return 0;
240     }
241     CRYPTO_THREAD_write_lock(global_engine_lock);
242     ret = e->prev;
243     if (ret) {
244         /* Return a valid structural reference to the next ENGINE */
245         ret->struct_ref++;
246         engine_ref_debug(ret, 0, 1);
247     }
248     CRYPTO_THREAD_unlock(global_engine_lock);
249     /* Release the structural reference to the previous ENGINE */
250     ENGINE_free(e);
251     return ret;
252 }
253
254 /* Add another "ENGINE" type into the list. */
255 int ENGINE_add(ENGINE *e)
256 {
257     int to_return = 1;
258     if (e == NULL) {
259         ENGINEerr(ENGINE_F_ENGINE_ADD, ERR_R_PASSED_NULL_PARAMETER);
260         return 0;
261     }
262     if ((e->id == NULL) || (e->name == NULL)) {
263         ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_ID_OR_NAME_MISSING);
264         return 0;
265     }
266     CRYPTO_THREAD_write_lock(global_engine_lock);
267     if (!engine_list_add(e)) {
268         ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_INTERNAL_LIST_ERROR);
269         to_return = 0;
270     }
271     CRYPTO_THREAD_unlock(global_engine_lock);
272     return to_return;
273 }
274
275 /* Remove an existing "ENGINE" type from the array. */
276 int ENGINE_remove(ENGINE *e)
277 {
278     int to_return = 1;
279     if (e == NULL) {
280         ENGINEerr(ENGINE_F_ENGINE_REMOVE, ERR_R_PASSED_NULL_PARAMETER);
281         return 0;
282     }
283     CRYPTO_THREAD_write_lock(global_engine_lock);
284     if (!engine_list_remove(e)) {
285         ENGINEerr(ENGINE_F_ENGINE_REMOVE, ENGINE_R_INTERNAL_LIST_ERROR);
286         to_return = 0;
287     }
288     CRYPTO_THREAD_unlock(global_engine_lock);
289     return to_return;
290 }
291
292 static void engine_cpy(ENGINE *dest, const ENGINE *src)
293 {
294     dest->id = src->id;
295     dest->name = src->name;
296 #ifndef OPENSSL_NO_RSA
297     dest->rsa_meth = src->rsa_meth;
298 #endif
299 #ifndef OPENSSL_NO_DSA
300     dest->dsa_meth = src->dsa_meth;
301 #endif
302 #ifndef OPENSSL_NO_DH
303     dest->dh_meth = src->dh_meth;
304 #endif
305 #ifndef OPENSSL_NO_EC
306     dest->ec_meth = src->ec_meth;
307 #endif
308     dest->rand_meth = src->rand_meth;
309     dest->ciphers = src->ciphers;
310     dest->digests = src->digests;
311     dest->pkey_meths = src->pkey_meths;
312     dest->destroy = src->destroy;
313     dest->init = src->init;
314     dest->finish = src->finish;
315     dest->ctrl = src->ctrl;
316     dest->load_privkey = src->load_privkey;
317     dest->load_pubkey = src->load_pubkey;
318     dest->cmd_defns = src->cmd_defns;
319     dest->flags = src->flags;
320 }
321
322 ENGINE *ENGINE_by_id(const char *id)
323 {
324     ENGINE *iterator;
325     char *load_dir = NULL;
326     if (id == NULL) {
327         ENGINEerr(ENGINE_F_ENGINE_BY_ID, ERR_R_PASSED_NULL_PARAMETER);
328         return NULL;
329     }
330     CRYPTO_THREAD_run_once(&engine_lock_init, do_engine_lock_init);
331     CRYPTO_THREAD_write_lock(global_engine_lock);
332     iterator = engine_list_head;
333     while (iterator && (strcmp(id, iterator->id) != 0))
334         iterator = iterator->next;
335     if (iterator != NULL) {
336         /*
337          * We need to return a structural reference. If this is an ENGINE
338          * type that returns copies, make a duplicate - otherwise increment
339          * the existing ENGINE's reference count.
340          */
341         if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
342             ENGINE *cp = ENGINE_new();
343             if (cp == NULL)
344                 iterator = NULL;
345             else {
346                 engine_cpy(cp, iterator);
347                 iterator = cp;
348             }
349         } else {
350             iterator->struct_ref++;
351             engine_ref_debug(iterator, 0, 1);
352         }
353     }
354     CRYPTO_THREAD_unlock(global_engine_lock);
355     if (iterator != NULL)
356         return iterator;
357     /*
358      * Prevent infinite recursion if we're looking for the dynamic engine.
359      */
360     if (strcmp(id, "dynamic")) {
361         if ((load_dir = getenv("OPENSSL_ENGINES")) == 0)
362             load_dir = ENGINESDIR;
363         iterator = ENGINE_by_id("dynamic");
364         if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
365             !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
366             !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
367                                     load_dir, 0) ||
368             !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
369             !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
370             goto notfound;
371         return iterator;
372     }
373  notfound:
374     ENGINE_free(iterator);
375     ENGINEerr(ENGINE_F_ENGINE_BY_ID, ENGINE_R_NO_SUCH_ENGINE);
376     ERR_add_error_data(2, "id=", id);
377     return NULL;
378     /* EEK! Experimental code ends */
379 }
380
381 int ENGINE_up_ref(ENGINE *e)
382 {
383     int i;
384     if (e == NULL) {
385         ENGINEerr(ENGINE_F_ENGINE_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
386         return 0;
387     }
388     CRYPTO_atomic_add(&e->struct_ref, 1, &i, global_engine_lock);
389     return 1;
390 }