Make DSO opaque.
[openssl.git] / crypto / dso / dso_lib.c
1 /*
2  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
3  * 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000 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 #include "dso_locl.h"
60
61 static DSO_METHOD *default_DSO_meth = NULL;
62
63 DSO *DSO_new(void)
64 {
65     return (DSO_new_method(NULL));
66 }
67
68 void DSO_set_default_method(DSO_METHOD *meth)
69 {
70     default_DSO_meth = meth;
71 }
72
73 DSO_METHOD *DSO_get_default_method(void)
74 {
75     return (default_DSO_meth);
76 }
77
78 DSO_METHOD *DSO_get_method(DSO *dso)
79 {
80     return (dso->meth);
81 }
82
83 DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth)
84 {
85     DSO_METHOD *mtmp;
86     mtmp = dso->meth;
87     dso->meth = meth;
88     return (mtmp);
89 }
90
91 DSO *DSO_new_method(DSO_METHOD *meth)
92 {
93     DSO *ret;
94
95     if (default_DSO_meth == NULL) {
96         /*
97          * We default to DSO_METH_openssl() which in turn defaults to
98          * stealing the "best available" method. Will fallback to
99          * DSO_METH_null() in the worst case.
100          */
101         default_DSO_meth = DSO_METHOD_openssl();
102     }
103     ret = OPENSSL_zalloc(sizeof(*ret));
104     if (ret == NULL) {
105         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
106         return (NULL);
107     }
108     ret->meth_data = sk_void_new_null();
109     if (ret->meth_data == NULL) {
110         /* sk_new doesn't generate any errors so we do */
111         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
112         OPENSSL_free(ret);
113         return (NULL);
114     }
115     if (meth == NULL)
116         ret->meth = default_DSO_meth;
117     else
118         ret->meth = meth;
119     ret->references = 1;
120
121     ret->lock = CRYPTO_THREAD_lock_new();
122     if (ret->lock == NULL) {
123         sk_void_free(ret->meth_data);
124         OPENSSL_free(ret);
125         return NULL;
126     }
127
128     if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
129         DSO_free(ret);
130         ret = NULL;
131     }
132
133     return ret;
134 }
135
136 int DSO_free(DSO *dso)
137 {
138     int i;
139
140     if (dso == NULL)
141         return (1);
142
143     if (CRYPTO_atomic_add(&dso->references, -1, &i, dso->lock) <= 0)
144         return 0;
145
146     REF_PRINT_COUNT("DSO", dso);
147     if (i > 0)
148         return 1;
149     REF_ASSERT_ISNT(i < 0);
150
151     if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
152         DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
153         return 0;
154     }
155
156     if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
157         DSOerr(DSO_F_DSO_FREE, DSO_R_FINISH_FAILED);
158         return 0;
159     }
160
161     sk_void_free(dso->meth_data);
162     OPENSSL_free(dso->filename);
163     OPENSSL_free(dso->loaded_filename);
164     CRYPTO_THREAD_lock_free(dso->lock);
165     OPENSSL_free(dso);
166     return 1;
167 }
168
169 int DSO_flags(DSO *dso)
170 {
171     return ((dso == NULL) ? 0 : dso->flags);
172 }
173
174 int DSO_up_ref(DSO *dso)
175 {
176     int i;
177
178     if (dso == NULL) {
179         DSOerr(DSO_F_DSO_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
180         return 0;
181     }
182
183     if (CRYPTO_atomic_add(&dso->references, 1, &i, dso->lock) <= 0)
184         return 0;
185
186     REF_PRINT_COUNT("DSO", r);
187     REF_ASSERT_ISNT(i < 2);
188     return ((i > 1) ? 1 : 0);
189 }
190
191 DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
192 {
193     DSO *ret;
194     int allocated = 0;
195
196     if (dso == NULL) {
197         ret = DSO_new_method(meth);
198         if (ret == NULL) {
199             DSOerr(DSO_F_DSO_LOAD, ERR_R_MALLOC_FAILURE);
200             goto err;
201         }
202         allocated = 1;
203         /* Pass the provided flags to the new DSO object */
204         if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
205             DSOerr(DSO_F_DSO_LOAD, DSO_R_CTRL_FAILED);
206             goto err;
207         }
208     } else
209         ret = dso;
210     /* Don't load if we're currently already loaded */
211     if (ret->filename != NULL) {
212         DSOerr(DSO_F_DSO_LOAD, DSO_R_DSO_ALREADY_LOADED);
213         goto err;
214     }
215     /*
216      * filename can only be NULL if we were passed a dso that already has one
217      * set.
218      */
219     if (filename != NULL)
220         if (!DSO_set_filename(ret, filename)) {
221             DSOerr(DSO_F_DSO_LOAD, DSO_R_SET_FILENAME_FAILED);
222             goto err;
223         }
224     filename = ret->filename;
225     if (filename == NULL) {
226         DSOerr(DSO_F_DSO_LOAD, DSO_R_NO_FILENAME);
227         goto err;
228     }
229     if (ret->meth->dso_load == NULL) {
230         DSOerr(DSO_F_DSO_LOAD, DSO_R_UNSUPPORTED);
231         goto err;
232     }
233     if (!ret->meth->dso_load(ret)) {
234         DSOerr(DSO_F_DSO_LOAD, DSO_R_LOAD_FAILED);
235         goto err;
236     }
237     /* Load succeeded */
238     return (ret);
239  err:
240     if (allocated)
241         DSO_free(ret);
242     return (NULL);
243 }
244
245 void *DSO_bind_var(DSO *dso, const char *symname)
246 {
247     void *ret = NULL;
248
249     if ((dso == NULL) || (symname == NULL)) {
250         DSOerr(DSO_F_DSO_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
251         return (NULL);
252     }
253     if (dso->meth->dso_bind_var == NULL) {
254         DSOerr(DSO_F_DSO_BIND_VAR, DSO_R_UNSUPPORTED);
255         return (NULL);
256     }
257     if ((ret = dso->meth->dso_bind_var(dso, symname)) == NULL) {
258         DSOerr(DSO_F_DSO_BIND_VAR, DSO_R_SYM_FAILURE);
259         return (NULL);
260     }
261     /* Success */
262     return (ret);
263 }
264
265 DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
266 {
267     DSO_FUNC_TYPE ret = NULL;
268
269     if ((dso == NULL) || (symname == NULL)) {
270         DSOerr(DSO_F_DSO_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
271         return (NULL);
272     }
273     if (dso->meth->dso_bind_func == NULL) {
274         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_UNSUPPORTED);
275         return (NULL);
276     }
277     if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
278         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_SYM_FAILURE);
279         return (NULL);
280     }
281     /* Success */
282     return (ret);
283 }
284
285 /*
286  * I don't really like these *_ctrl functions very much to be perfectly
287  * honest. For one thing, I think I have to return a negative value for any
288  * error because possible DSO_ctrl() commands may return values such as
289  * "size"s that can legitimately be zero (making the standard
290  * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
291  * times. I'd prefer "output" values to be passed by reference and the return
292  * value as success/failure like usual ... but we conform when we must... :-)
293  */
294 long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
295 {
296     if (dso == NULL) {
297         DSOerr(DSO_F_DSO_CTRL, ERR_R_PASSED_NULL_PARAMETER);
298         return (-1);
299     }
300     /*
301      * We should intercept certain generic commands and only pass control to
302      * the method-specific ctrl() function if it's something we don't handle.
303      */
304     switch (cmd) {
305     case DSO_CTRL_GET_FLAGS:
306         return dso->flags;
307     case DSO_CTRL_SET_FLAGS:
308         dso->flags = (int)larg;
309         return (0);
310     case DSO_CTRL_OR_FLAGS:
311         dso->flags |= (int)larg;
312         return (0);
313     default:
314         break;
315     }
316     if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
317         DSOerr(DSO_F_DSO_CTRL, DSO_R_UNSUPPORTED);
318         return (-1);
319     }
320     return (dso->meth->dso_ctrl(dso, cmd, larg, parg));
321 }
322
323 int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb,
324                            DSO_NAME_CONVERTER_FUNC *oldcb)
325 {
326     if (dso == NULL) {
327         DSOerr(DSO_F_DSO_SET_NAME_CONVERTER, ERR_R_PASSED_NULL_PARAMETER);
328         return (0);
329     }
330     if (oldcb)
331         *oldcb = dso->name_converter;
332     dso->name_converter = cb;
333     return (1);
334 }
335
336 const char *DSO_get_filename(DSO *dso)
337 {
338     if (dso == NULL) {
339         DSOerr(DSO_F_DSO_GET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
340         return (NULL);
341     }
342     return (dso->filename);
343 }
344
345 int DSO_set_filename(DSO *dso, const char *filename)
346 {
347     char *copied;
348
349     if ((dso == NULL) || (filename == NULL)) {
350         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
351         return (0);
352     }
353     if (dso->loaded_filename) {
354         DSOerr(DSO_F_DSO_SET_FILENAME, DSO_R_DSO_ALREADY_LOADED);
355         return (0);
356     }
357     /* We'll duplicate filename */
358     copied = OPENSSL_strdup(filename);
359     if (copied == NULL) {
360         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_MALLOC_FAILURE);
361         return (0);
362     }
363     OPENSSL_free(dso->filename);
364     dso->filename = copied;
365     return (1);
366 }
367
368 char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
369 {
370     char *result = NULL;
371
372     if (dso == NULL || filespec1 == NULL) {
373         DSOerr(DSO_F_DSO_MERGE, ERR_R_PASSED_NULL_PARAMETER);
374         return (NULL);
375     }
376     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
377         if (dso->merger != NULL)
378             result = dso->merger(dso, filespec1, filespec2);
379         else if (dso->meth->dso_merger != NULL)
380             result = dso->meth->dso_merger(dso, filespec1, filespec2);
381     }
382     return (result);
383 }
384
385 char *DSO_convert_filename(DSO *dso, const char *filename)
386 {
387     char *result = NULL;
388
389     if (dso == NULL) {
390         DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
391         return (NULL);
392     }
393     if (filename == NULL)
394         filename = dso->filename;
395     if (filename == NULL) {
396         DSOerr(DSO_F_DSO_CONVERT_FILENAME, DSO_R_NO_FILENAME);
397         return (NULL);
398     }
399     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
400         if (dso->name_converter != NULL)
401             result = dso->name_converter(dso, filename);
402         else if (dso->meth->dso_name_converter != NULL)
403             result = dso->meth->dso_name_converter(dso, filename);
404     }
405     if (result == NULL) {
406         result = OPENSSL_strdup(filename);
407         if (result == NULL) {
408             DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_MALLOC_FAILURE);
409             return (NULL);
410         }
411     }
412     return (result);
413 }
414
415 const char *DSO_get_loaded_filename(DSO *dso)
416 {
417     if (dso == NULL) {
418         DSOerr(DSO_F_DSO_GET_LOADED_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
419         return (NULL);
420     }
421     return (dso->loaded_filename);
422 }
423
424 int DSO_pathbyaddr(void *addr, char *path, int sz)
425 {
426     DSO_METHOD *meth = default_DSO_meth;
427     if (meth == NULL)
428         meth = DSO_METHOD_openssl();
429     if (meth->pathbyaddr == NULL) {
430         DSOerr(DSO_F_DSO_PATHBYADDR, DSO_R_UNSUPPORTED);
431         return -1;
432     }
433     return (*meth->pathbyaddr) (addr, path, sz);
434 }
435
436 void *DSO_global_lookup(const char *name)
437 {
438     DSO_METHOD *meth = default_DSO_meth;
439     if (meth == NULL)
440         meth = DSO_METHOD_openssl();
441     if (meth->globallookup == NULL) {
442         DSOerr(DSO_F_DSO_GLOBAL_LOOKUP, DSO_R_UNSUPPORTED);
443         return NULL;
444     }
445     return (*meth->globallookup) (name);
446 }