cherry pick pr-512 changes
[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         sk_void_free(ret->meth_data);
43         OPENSSL_free(ret);
44         return NULL;
45     }
46
47     if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
48         DSO_free(ret);
49         ret = NULL;
50     }
51
52     return ret;
53 }
54
55 DSO *DSO_new(void)
56 {
57     return DSO_new_method(NULL);
58 }
59
60 int DSO_free(DSO *dso)
61 {
62     int i;
63
64     if (dso == NULL)
65         return (1);
66
67     if (CRYPTO_atomic_add(&dso->references, -1, &i, dso->lock) <= 0)
68         return 0;
69
70     REF_PRINT_COUNT("DSO", dso);
71     if (i > 0)
72         return 1;
73     REF_ASSERT_ISNT(i < 0);
74
75     if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
76         DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
77         return 0;
78     }
79
80     if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
81         DSOerr(DSO_F_DSO_FREE, DSO_R_FINISH_FAILED);
82         return 0;
83     }
84
85     sk_void_free(dso->meth_data);
86     OPENSSL_free(dso->filename);
87     OPENSSL_free(dso->loaded_filename);
88     CRYPTO_THREAD_lock_free(dso->lock);
89     OPENSSL_free(dso);
90     return 1;
91 }
92
93 int DSO_flags(DSO *dso)
94 {
95     return ((dso == NULL) ? 0 : dso->flags);
96 }
97
98 int DSO_up_ref(DSO *dso)
99 {
100     int i;
101
102     if (dso == NULL) {
103         DSOerr(DSO_F_DSO_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
104         return 0;
105     }
106
107     if (CRYPTO_atomic_add(&dso->references, 1, &i, dso->lock) <= 0)
108         return 0;
109
110     REF_PRINT_COUNT("DSO", r);
111     REF_ASSERT_ISNT(i < 2);
112     return ((i > 1) ? 1 : 0);
113 }
114
115 DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
116 {
117     DSO *ret;
118     int allocated = 0;
119
120     if (dso == NULL) {
121         ret = DSO_new_method(meth);
122         if (ret == NULL) {
123             DSOerr(DSO_F_DSO_LOAD, ERR_R_MALLOC_FAILURE);
124             goto err;
125         }
126         allocated = 1;
127         /* Pass the provided flags to the new DSO object */
128         if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
129             DSOerr(DSO_F_DSO_LOAD, DSO_R_CTRL_FAILED);
130             goto err;
131         }
132     } else
133         ret = dso;
134     /* Don't load if we're currently already loaded */
135     if (ret->filename != NULL) {
136         DSOerr(DSO_F_DSO_LOAD, DSO_R_DSO_ALREADY_LOADED);
137         goto err;
138     }
139     /*
140      * filename can only be NULL if we were passed a dso that already has one
141      * set.
142      */
143     if (filename != NULL)
144         if (!DSO_set_filename(ret, filename)) {
145             DSOerr(DSO_F_DSO_LOAD, DSO_R_SET_FILENAME_FAILED);
146             goto err;
147         }
148     filename = ret->filename;
149     if (filename == NULL) {
150         DSOerr(DSO_F_DSO_LOAD, DSO_R_NO_FILENAME);
151         goto err;
152     }
153     if (ret->meth->dso_load == NULL) {
154         DSOerr(DSO_F_DSO_LOAD, DSO_R_UNSUPPORTED);
155         goto err;
156     }
157     if (!ret->meth->dso_load(ret)) {
158         DSOerr(DSO_F_DSO_LOAD, DSO_R_LOAD_FAILED);
159         goto err;
160     }
161     /* Load succeeded */
162     return (ret);
163  err:
164     if (allocated)
165         DSO_free(ret);
166     return (NULL);
167 }
168
169 DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
170 {
171     DSO_FUNC_TYPE ret = NULL;
172
173     if ((dso == NULL) || (symname == NULL)) {
174         DSOerr(DSO_F_DSO_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
175         return (NULL);
176     }
177     if (dso->meth->dso_bind_func == NULL) {
178         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_UNSUPPORTED);
179         return (NULL);
180     }
181     if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
182         DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_SYM_FAILURE);
183         return (NULL);
184     }
185     /* Success */
186     return (ret);
187 }
188
189 /*
190  * I don't really like these *_ctrl functions very much to be perfectly
191  * honest. For one thing, I think I have to return a negative value for any
192  * error because possible DSO_ctrl() commands may return values such as
193  * "size"s that can legitimately be zero (making the standard
194  * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
195  * times. I'd prefer "output" values to be passed by reference and the return
196  * value as success/failure like usual ... but we conform when we must... :-)
197  */
198 long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
199 {
200     if (dso == NULL) {
201         DSOerr(DSO_F_DSO_CTRL, ERR_R_PASSED_NULL_PARAMETER);
202         return (-1);
203     }
204     /*
205      * We should intercept certain generic commands and only pass control to
206      * the method-specific ctrl() function if it's something we don't handle.
207      */
208     switch (cmd) {
209     case DSO_CTRL_GET_FLAGS:
210         return dso->flags;
211     case DSO_CTRL_SET_FLAGS:
212         dso->flags = (int)larg;
213         return (0);
214     case DSO_CTRL_OR_FLAGS:
215         dso->flags |= (int)larg;
216         return (0);
217     default:
218         break;
219     }
220     if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
221         DSOerr(DSO_F_DSO_CTRL, DSO_R_UNSUPPORTED);
222         return (-1);
223     }
224     return (dso->meth->dso_ctrl(dso, cmd, larg, parg));
225 }
226
227 const char *DSO_get_filename(DSO *dso)
228 {
229     if (dso == NULL) {
230         DSOerr(DSO_F_DSO_GET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
231         return (NULL);
232     }
233     return (dso->filename);
234 }
235
236 int DSO_set_filename(DSO *dso, const char *filename)
237 {
238     char *copied;
239
240     if ((dso == NULL) || (filename == NULL)) {
241         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
242         return (0);
243     }
244     if (dso->loaded_filename) {
245         DSOerr(DSO_F_DSO_SET_FILENAME, DSO_R_DSO_ALREADY_LOADED);
246         return (0);
247     }
248     /* We'll duplicate filename */
249     copied = OPENSSL_strdup(filename);
250     if (copied == NULL) {
251         DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_MALLOC_FAILURE);
252         return (0);
253     }
254     OPENSSL_free(dso->filename);
255     dso->filename = copied;
256     return (1);
257 }
258
259 char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
260 {
261     char *result = NULL;
262
263     if (dso == NULL || filespec1 == NULL) {
264         DSOerr(DSO_F_DSO_MERGE, ERR_R_PASSED_NULL_PARAMETER);
265         return (NULL);
266     }
267     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
268         if (dso->merger != NULL)
269             result = dso->merger(dso, filespec1, filespec2);
270         else if (dso->meth->dso_merger != NULL)
271             result = dso->meth->dso_merger(dso, filespec1, filespec2);
272     }
273     return (result);
274 }
275
276 char *DSO_convert_filename(DSO *dso, const char *filename)
277 {
278     char *result = NULL;
279
280     if (dso == NULL) {
281         DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
282         return (NULL);
283     }
284     if (filename == NULL)
285         filename = dso->filename;
286     if (filename == NULL) {
287         DSOerr(DSO_F_DSO_CONVERT_FILENAME, DSO_R_NO_FILENAME);
288         return (NULL);
289     }
290     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
291         if (dso->name_converter != NULL)
292             result = dso->name_converter(dso, filename);
293         else if (dso->meth->dso_name_converter != NULL)
294             result = dso->meth->dso_name_converter(dso, filename);
295     }
296     if (result == NULL) {
297         result = OPENSSL_strdup(filename);
298         if (result == NULL) {
299             DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_MALLOC_FAILURE);
300             return (NULL);
301         }
302     }
303     return (result);
304 }
305
306 void *DSO_global_lookup(const char *name)
307 {
308     DSO_METHOD *meth = default_DSO_meth;
309     if (meth == NULL)
310         meth = DSO_METHOD_openssl();
311     if (meth->globallookup == NULL) {
312         DSOerr(DSO_F_DSO_GLOBAL_LOOKUP, DSO_R_UNSUPPORTED);
313         return NULL;
314     }
315     return (*meth->globallookup) (name);
316 }