12544b3a1610ec0ad609ef3c7d346fa0723a8e89
[openssl.git] / crypto / dso / dso_lib.c
1 /* dso_lib.c -*- mode:C; c-file-style: "eay" -*- */
2 /*
3  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
4  * 2000.
5  */
6 /* ====================================================================
7  * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. All advertising materials mentioning features or use of this
22  *    software must display the following acknowledgment:
23  *    "This product includes software developed by the OpenSSL Project
24  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25  *
26  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27  *    endorse or promote products derived from this software without
28  *    prior written permission. For written permission, please contact
29  *    licensing@OpenSSL.org.
30  *
31  * 5. Products derived from this software may not be called "OpenSSL"
32  *    nor may "OpenSSL" appear in their names without prior written
33  *    permission of the OpenSSL Project.
34  *
35  * 6. Redistributions of any form whatsoever must retain the following
36  *    acknowledgment:
37  *    "This product includes software developed by the OpenSSL Project
38  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This product includes cryptographic software written by Eric Young
55  * (eay@cryptsoft.com).  This product includes software written by Tim
56  * Hudson (tjh@cryptsoft.com).
57  *
58  */
59
60 #include <stdio.h>
61 #include <openssl/crypto.h>
62 #include "internal/cryptlib.h"
63 #include <openssl/dso.h>
64
65 static DSO_METHOD *default_DSO_meth = NULL;
66
67 DSO *DSO_new(void)
68 {
69     return (DSO_new_method(NULL));
70 }
71
72 void DSO_set_default_method(DSO_METHOD *meth)
73 {
74     default_DSO_meth = meth;
75 }
76
77 DSO_METHOD *DSO_get_default_method(void)
78 {
79     return (default_DSO_meth);
80 }
81
82 DSO_METHOD *DSO_get_method(DSO *dso)
83 {
84     return (dso->meth);
85 }
86
87 DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth)
88 {
89     DSO_METHOD *mtmp;
90     mtmp = dso->meth;
91     dso->meth = meth;
92     return (mtmp);
93 }
94
95 DSO *DSO_new_method(DSO_METHOD *meth)
96 {
97     DSO *ret;
98
99     if (default_DSO_meth == NULL) {
100         /*
101          * We default to DSO_METH_openssl() which in turn defaults to
102          * stealing the "best available" method. Will fallback to
103          * DSO_METH_null() in the worst case.
104          */
105         default_DSO_meth = DSO_METHOD_openssl();
106     }
107     ret = OPENSSL_malloc(sizeof(*ret));
108     if (ret == NULL) {
109         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
110         return (NULL);
111     }
112     memset(ret, 0, sizeof(*ret));
113     ret->meth_data = sk_void_new_null();
114     if (ret->meth_data == NULL) {
115         /* sk_new doesn't generate any errors so we do */
116         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
117         OPENSSL_free(ret);
118         return (NULL);
119     }
120     if (meth == NULL)
121         ret->meth = default_DSO_meth;
122     else
123         ret->meth = meth;
124     ret->references = 1;
125     if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
126         OPENSSL_free(ret);
127         ret = NULL;
128     }
129     return (ret);
130 }
131
132 int DSO_free(DSO *dso)
133 {
134     int i;
135
136     if (dso == NULL)
137         return (1);
138
139     i = CRYPTO_add(&dso->references, -1, CRYPTO_LOCK_DSO);
140 #ifdef REF_PRINT
141     REF_PRINT("DSO", dso);
142 #endif
143     if (i > 0)
144         return (1);
145 #ifdef REF_CHECK
146     if (i < 0) {
147         fprintf(stderr, "DSO_free, bad reference count\n");
148         abort();
149     }
150 #endif
151
152     if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
153         DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
154         return (0);
155     }
156
157     if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
158         DSOerr(DSO_F_DSO_FREE, DSO_R_FINISH_FAILED);
159         return (0);
160     }
161
162     sk_void_free(dso->meth_data);
163     OPENSSL_free(dso->filename);
164     OPENSSL_free(dso->loaded_filename);
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     if (dso == NULL) {
177         DSOerr(DSO_F_DSO_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
178         return (0);
179     }
180
181     CRYPTO_add(&dso->references, 1, CRYPTO_LOCK_DSO);
182     return (1);
183 }
184
185 DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
186 {
187     DSO *ret;
188     int allocated = 0;
189
190     if (dso == NULL) {
191         ret = DSO_new_method(meth);
192         if (ret == NULL) {
193             DSOerr(DSO_F_DSO_LOAD, ERR_R_MALLOC_FAILURE);
194             goto err;
195         }
196         allocated = 1;
197         /* Pass the provided flags to the new DSO object */
198         if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
199             DSOerr(DSO_F_DSO_LOAD, DSO_R_CTRL_FAILED);
200             goto err;
201         }
202     } else
203         ret = dso;
204     /* Don't load if we're currently already loaded */
205     if (ret->filename != NULL) {
206         DSOerr(DSO_F_DSO_LOAD, DSO_R_DSO_ALREADY_LOADED);
207         goto err;
208     }
209     /*
210      * filename can only be NULL if we were passed a dso that already has one
211      * set.
212      */
213     if (filename != NULL)
214         if (!DSO_set_filename(ret, filename)) {
215             DSOerr(DSO_F_DSO_LOAD, DSO_R_SET_FILENAME_FAILED);
216             goto err;
217         }
218     filename = ret->filename;
219     if (filename == NULL) {
220         DSOerr(DSO_F_DSO_LOAD, DSO_R_NO_FILENAME);
221         goto err;
222     }
223     if (ret->meth->dso_load == NULL) {
224         DSOerr(DSO_F_DSO_LOAD, DSO_R_UNSUPPORTED);
225         goto err;
226     }
227     if (!ret->meth->dso_load(ret)) {
228         DSOerr(DSO_F_DSO_LOAD, DSO_R_LOAD_FAILED);
229         goto err;
230     }
231     /* Load succeeded */
232     return (ret);
233  err:
234     if (allocated)
235         DSO_free(ret);
236     return (NULL);
237 }
238
239 void *DSO_bind_var(DSO *dso, const char *symname)
240 {
241     void *ret = NULL;
242
243     if ((dso == NULL) || (symname == NULL)) {
244         DSOerr(DSO_F_DSO_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
245         return (NULL);
246     }
247     if (dso->meth->dso_bind_var == NULL) {
248         DSOerr(DSO_F_DSO_BIND_VAR, DSO_R_UNSUPPORTED);
249         return (NULL);
250     }
251     if ((ret = dso->meth->dso_bind_var(dso, symname)) == NULL) {
252         DSOerr(DSO_F_DSO_BIND_VAR, DSO_R_SYM_FAILURE);
253         return (NULL);
254     }
255     /* Success */
256     return (ret);
257 }
258
259 DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
260 {
261     DSO_FUNC_TYPE ret = NULL;
262
263     if ((dso == NULL) || (symname == NULL)) {
264         DSOerr(DSO_F_DSO_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
265         return (NULL);
266     }
267     if (dso->meth->dso_bind_func == NULL) {
268         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_UNSUPPORTED);
269         return (NULL);
270     }
271     if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
272         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_SYM_FAILURE);
273         return (NULL);
274     }
275     /* Success */
276     return (ret);
277 }
278
279 /*
280  * I don't really like these *_ctrl functions very much to be perfectly
281  * honest. For one thing, I think I have to return a negative value for any
282  * error because possible DSO_ctrl() commands may return values such as
283  * "size"s that can legitimately be zero (making the standard
284  * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
285  * times. I'd prefer "output" values to be passed by reference and the return
286  * value as success/failure like usual ... but we conform when we must... :-)
287  */
288 long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
289 {
290     if (dso == NULL) {
291         DSOerr(DSO_F_DSO_CTRL, ERR_R_PASSED_NULL_PARAMETER);
292         return (-1);
293     }
294     /*
295      * We should intercept certain generic commands and only pass control to
296      * the method-specific ctrl() function if it's something we don't handle.
297      */
298     switch (cmd) {
299     case DSO_CTRL_GET_FLAGS:
300         return dso->flags;
301     case DSO_CTRL_SET_FLAGS:
302         dso->flags = (int)larg;
303         return (0);
304     case DSO_CTRL_OR_FLAGS:
305         dso->flags |= (int)larg;
306         return (0);
307     default:
308         break;
309     }
310     if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
311         DSOerr(DSO_F_DSO_CTRL, DSO_R_UNSUPPORTED);
312         return (-1);
313     }
314     return (dso->meth->dso_ctrl(dso, cmd, larg, parg));
315 }
316
317 int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb,
318                            DSO_NAME_CONVERTER_FUNC *oldcb)
319 {
320     if (dso == NULL) {
321         DSOerr(DSO_F_DSO_SET_NAME_CONVERTER, ERR_R_PASSED_NULL_PARAMETER);
322         return (0);
323     }
324     if (oldcb)
325         *oldcb = dso->name_converter;
326     dso->name_converter = cb;
327     return (1);
328 }
329
330 const char *DSO_get_filename(DSO *dso)
331 {
332     if (dso == NULL) {
333         DSOerr(DSO_F_DSO_GET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
334         return (NULL);
335     }
336     return (dso->filename);
337 }
338
339 int DSO_set_filename(DSO *dso, const char *filename)
340 {
341     char *copied;
342
343     if ((dso == NULL) || (filename == NULL)) {
344         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
345         return (0);
346     }
347     if (dso->loaded_filename) {
348         DSOerr(DSO_F_DSO_SET_FILENAME, DSO_R_DSO_ALREADY_LOADED);
349         return (0);
350     }
351     /* We'll duplicate filename */
352     copied = OPENSSL_malloc(strlen(filename) + 1);
353     if (copied == NULL) {
354         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_MALLOC_FAILURE);
355         return (0);
356     }
357     BUF_strlcpy(copied, filename, strlen(filename) + 1);
358     OPENSSL_free(dso->filename);
359     dso->filename = copied;
360     return (1);
361 }
362
363 char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
364 {
365     char *result = NULL;
366
367     if (dso == NULL || filespec1 == NULL) {
368         DSOerr(DSO_F_DSO_MERGE, ERR_R_PASSED_NULL_PARAMETER);
369         return (NULL);
370     }
371     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
372         if (dso->merger != NULL)
373             result = dso->merger(dso, filespec1, filespec2);
374         else if (dso->meth->dso_merger != NULL)
375             result = dso->meth->dso_merger(dso, filespec1, filespec2);
376     }
377     return (result);
378 }
379
380 char *DSO_convert_filename(DSO *dso, const char *filename)
381 {
382     char *result = NULL;
383
384     if (dso == NULL) {
385         DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
386         return (NULL);
387     }
388     if (filename == NULL)
389         filename = dso->filename;
390     if (filename == NULL) {
391         DSOerr(DSO_F_DSO_CONVERT_FILENAME, DSO_R_NO_FILENAME);
392         return (NULL);
393     }
394     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
395         if (dso->name_converter != NULL)
396             result = dso->name_converter(dso, filename);
397         else if (dso->meth->dso_name_converter != NULL)
398             result = dso->meth->dso_name_converter(dso, filename);
399     }
400     if (result == NULL) {
401         result = OPENSSL_malloc(strlen(filename) + 1);
402         if (result == NULL) {
403             DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_MALLOC_FAILURE);
404             return (NULL);
405         }
406         BUF_strlcpy(result, filename, strlen(filename) + 1);
407     }
408     return (result);
409 }
410
411 const char *DSO_get_loaded_filename(DSO *dso)
412 {
413     if (dso == NULL) {
414         DSOerr(DSO_F_DSO_GET_LOADED_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
415         return (NULL);
416     }
417     return (dso->loaded_filename);
418 }
419
420 int DSO_pathbyaddr(void *addr, char *path, int sz)
421 {
422     DSO_METHOD *meth = default_DSO_meth;
423     if (meth == NULL)
424         meth = DSO_METHOD_openssl();
425     if (meth->pathbyaddr == NULL) {
426         DSOerr(DSO_F_DSO_PATHBYADDR, DSO_R_UNSUPPORTED);
427         return -1;
428     }
429     return (*meth->pathbyaddr) (addr, path, sz);
430 }
431
432 void *DSO_global_lookup(const char *name)
433 {
434     DSO_METHOD *meth = default_DSO_meth;
435     if (meth == NULL)
436         meth = DSO_METHOD_openssl();
437     if (meth->globallookup == NULL) {
438         DSOerr(DSO_F_DSO_GLOBAL_LOOKUP, DSO_R_UNSUPPORTED);
439         return NULL;
440     }
441     return (*meth->globallookup) (name);
442 }