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