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