52816dfb9d9812b618677acfe856f86346e1a8d3
[openssl.git] / crypto / dso / dso_lib.c
1 /*
2  * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "dso_locl.h"
11
12 static DSO_METHOD *default_DSO_meth = NULL;
13
14 static DSO *DSO_new_method(DSO_METHOD *meth)
15 {
16     DSO *ret;
17
18     if (default_DSO_meth == NULL) {
19         /*
20          * We default to DSO_METH_openssl() which in turn defaults to
21          * stealing the "best available" method. Will fallback to
22          * DSO_METH_null() in the worst case.
23          */
24         default_DSO_meth = DSO_METHOD_openssl();
25     }
26     ret = OPENSSL_zalloc(sizeof(*ret));
27     if (ret == NULL) {
28         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
29         return (NULL);
30     }
31     ret->meth_data = sk_void_new_null();
32     if (ret->meth_data == NULL) {
33         /* sk_new doesn't generate any errors so we do */
34         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
35         OPENSSL_free(ret);
36         return (NULL);
37     }
38     ret->meth = default_DSO_meth;
39     ret->references = 1;
40     ret->lock = CRYPTO_THREAD_lock_new();
41     if (ret->lock == NULL) {
42         DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
43         sk_void_free(ret->meth_data);
44         OPENSSL_free(ret);
45         return NULL;
46     }
47
48     if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
49         DSO_free(ret);
50         ret = NULL;
51     }
52
53     return ret;
54 }
55
56 DSO *DSO_new(void)
57 {
58     return DSO_new_method(NULL);
59 }
60
61 int DSO_free(DSO *dso)
62 {
63     int i;
64
65     if (dso == NULL)
66         return (1);
67
68     if (CRYPTO_atomic_add(&dso->references, -1, &i, dso->lock) <= 0)
69         return 0;
70
71     REF_PRINT_COUNT("DSO", dso);
72     if (i > 0)
73         return 1;
74     REF_ASSERT_ISNT(i < 0);
75
76     if ((dso->flags & DSO_FLAG_NO_UNLOAD_ON_FREE) == 0) {
77         if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
78             DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
79             return 0;
80         }
81     }
82
83     if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
84         DSOerr(DSO_F_DSO_FREE, DSO_R_FINISH_FAILED);
85         return 0;
86     }
87
88     sk_void_free(dso->meth_data);
89     OPENSSL_free(dso->filename);
90     OPENSSL_free(dso->loaded_filename);
91     CRYPTO_THREAD_lock_free(dso->lock);
92     OPENSSL_free(dso);
93     return 1;
94 }
95
96 int DSO_flags(DSO *dso)
97 {
98     return ((dso == NULL) ? 0 : dso->flags);
99 }
100
101 int DSO_up_ref(DSO *dso)
102 {
103     int i;
104
105     if (dso == NULL) {
106         DSOerr(DSO_F_DSO_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
107         return 0;
108     }
109
110     if (CRYPTO_atomic_add(&dso->references, 1, &i, dso->lock) <= 0)
111         return 0;
112
113     REF_PRINT_COUNT("DSO", r);
114     REF_ASSERT_ISNT(i < 2);
115     return ((i > 1) ? 1 : 0);
116 }
117
118 DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
119 {
120     DSO *ret;
121     int allocated = 0;
122
123     if (dso == NULL) {
124         ret = DSO_new_method(meth);
125         if (ret == NULL) {
126             DSOerr(DSO_F_DSO_LOAD, ERR_R_MALLOC_FAILURE);
127             goto err;
128         }
129         allocated = 1;
130         /* Pass the provided flags to the new DSO object */
131         if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
132             DSOerr(DSO_F_DSO_LOAD, DSO_R_CTRL_FAILED);
133             goto err;
134         }
135     } else
136         ret = dso;
137     /* Don't load if we're currently already loaded */
138     if (ret->filename != NULL) {
139         DSOerr(DSO_F_DSO_LOAD, DSO_R_DSO_ALREADY_LOADED);
140         goto err;
141     }
142     /*
143      * filename can only be NULL if we were passed a dso that already has one
144      * set.
145      */
146     if (filename != NULL)
147         if (!DSO_set_filename(ret, filename)) {
148             DSOerr(DSO_F_DSO_LOAD, DSO_R_SET_FILENAME_FAILED);
149             goto err;
150         }
151     filename = ret->filename;
152     if (filename == NULL) {
153         DSOerr(DSO_F_DSO_LOAD, DSO_R_NO_FILENAME);
154         goto err;
155     }
156     if (ret->meth->dso_load == NULL) {
157         DSOerr(DSO_F_DSO_LOAD, DSO_R_UNSUPPORTED);
158         goto err;
159     }
160     if (!ret->meth->dso_load(ret)) {
161         DSOerr(DSO_F_DSO_LOAD, DSO_R_LOAD_FAILED);
162         goto err;
163     }
164     /* Load succeeded */
165     return (ret);
166  err:
167     if (allocated)
168         DSO_free(ret);
169     return (NULL);
170 }
171
172 DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
173 {
174     DSO_FUNC_TYPE ret = NULL;
175
176     if ((dso == NULL) || (symname == NULL)) {
177         DSOerr(DSO_F_DSO_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
178         return (NULL);
179     }
180     if (dso->meth->dso_bind_func == NULL) {
181         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_UNSUPPORTED);
182         return (NULL);
183     }
184     if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
185         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_SYM_FAILURE);
186         return (NULL);
187     }
188     /* Success */
189     return (ret);
190 }
191
192 /*
193  * I don't really like these *_ctrl functions very much to be perfectly
194  * honest. For one thing, I think I have to return a negative value for any
195  * error because possible DSO_ctrl() commands may return values such as
196  * "size"s that can legitimately be zero (making the standard
197  * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
198  * times. I'd prefer "output" values to be passed by reference and the return
199  * value as success/failure like usual ... but we conform when we must... :-)
200  */
201 long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
202 {
203     if (dso == NULL) {
204         DSOerr(DSO_F_DSO_CTRL, ERR_R_PASSED_NULL_PARAMETER);
205         return (-1);
206     }
207     /*
208      * We should intercept certain generic commands and only pass control to
209      * the method-specific ctrl() function if it's something we don't handle.
210      */
211     switch (cmd) {
212     case DSO_CTRL_GET_FLAGS:
213         return dso->flags;
214     case DSO_CTRL_SET_FLAGS:
215         dso->flags = (int)larg;
216         return (0);
217     case DSO_CTRL_OR_FLAGS:
218         dso->flags |= (int)larg;
219         return (0);
220     default:
221         break;
222     }
223     if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
224         DSOerr(DSO_F_DSO_CTRL, DSO_R_UNSUPPORTED);
225         return (-1);
226     }
227     return (dso->meth->dso_ctrl(dso, cmd, larg, parg));
228 }
229
230 const char *DSO_get_filename(DSO *dso)
231 {
232     if (dso == NULL) {
233         DSOerr(DSO_F_DSO_GET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
234         return (NULL);
235     }
236     return (dso->filename);
237 }
238
239 int DSO_set_filename(DSO *dso, const char *filename)
240 {
241     char *copied;
242
243     if ((dso == NULL) || (filename == NULL)) {
244         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
245         return (0);
246     }
247     if (dso->loaded_filename) {
248         DSOerr(DSO_F_DSO_SET_FILENAME, DSO_R_DSO_ALREADY_LOADED);
249         return (0);
250     }
251     /* We'll duplicate filename */
252     copied = OPENSSL_strdup(filename);
253     if (copied == NULL) {
254         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_MALLOC_FAILURE);
255         return (0);
256     }
257     OPENSSL_free(dso->filename);
258     dso->filename = copied;
259     return (1);
260 }
261
262 char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
263 {
264     char *result = NULL;
265
266     if (dso == NULL || filespec1 == NULL) {
267         DSOerr(DSO_F_DSO_MERGE, ERR_R_PASSED_NULL_PARAMETER);
268         return (NULL);
269     }
270     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
271         if (dso->merger != NULL)
272             result = dso->merger(dso, filespec1, filespec2);
273         else if (dso->meth->dso_merger != NULL)
274             result = dso->meth->dso_merger(dso, filespec1, filespec2);
275     }
276     return (result);
277 }
278
279 char *DSO_convert_filename(DSO *dso, const char *filename)
280 {
281     char *result = NULL;
282
283     if (dso == NULL) {
284         DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
285         return (NULL);
286     }
287     if (filename == NULL)
288         filename = dso->filename;
289     if (filename == NULL) {
290         DSOerr(DSO_F_DSO_CONVERT_FILENAME, DSO_R_NO_FILENAME);
291         return (NULL);
292     }
293     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
294         if (dso->name_converter != NULL)
295             result = dso->name_converter(dso, filename);
296         else if (dso->meth->dso_name_converter != NULL)
297             result = dso->meth->dso_name_converter(dso, filename);
298     }
299     if (result == NULL) {
300         result = OPENSSL_strdup(filename);
301         if (result == NULL) {
302             DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_MALLOC_FAILURE);
303             return (NULL);
304         }
305     }
306     return (result);
307 }
308
309 int DSO_pathbyaddr(void *addr, char *path, int sz)
310 {
311     DSO_METHOD *meth = default_DSO_meth;
312     if (meth == NULL)
313         meth = DSO_METHOD_openssl();
314     if (meth->pathbyaddr == NULL) {
315         DSOerr(DSO_F_DSO_PATHBYADDR, DSO_R_UNSUPPORTED);
316         return -1;
317     }
318     return (*meth->pathbyaddr) (addr, path, sz);
319 }
320
321 DSO *DSO_dsobyaddr(void *addr, int flags)
322 {
323     DSO *ret = NULL;
324     char *filename = NULL;
325     int len = DSO_pathbyaddr(addr, NULL, 0);
326
327     filename = OPENSSL_malloc(len);
328     if (filename != NULL
329             && DSO_pathbyaddr(addr, filename, len) == len)
330         ret = DSO_load(NULL, filename, NULL, flags);
331
332     OPENSSL_free(filename);
333     return ret;
334 }
335
336 void *DSO_global_lookup(const char *name)
337 {
338     DSO_METHOD *meth = default_DSO_meth;
339     if (meth == NULL)
340         meth = DSO_METHOD_openssl();
341     if (meth->globallookup == NULL) {
342         DSOerr(DSO_F_DSO_GLOBAL_LOOKUP, DSO_R_UNSUPPORTED);
343         return NULL;
344     }
345     return (*meth->globallookup) (name);
346 }