/src/openssl/crypto/dso/dso_lib.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
15 | 0 | DSO *ret; |
16 | |
|
17 | 0 | ret = OPENSSL_zalloc(sizeof(*ret)); |
18 | 0 | if (ret == NULL) |
19 | 0 | return NULL; |
20 | 0 | ret->meth_data = sk_void_new_null(); |
21 | 0 | if (ret->meth_data == NULL) { |
22 | | /* sk_new doesn't generate any errors so we do */ |
23 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_CRYPTO_LIB); |
24 | 0 | OPENSSL_free(ret); |
25 | 0 | return NULL; |
26 | 0 | } |
27 | 0 | ret->meth = DSO_METHOD_openssl(); |
28 | 0 | if (!CRYPTO_NEW_REF(&ret->references, 1)) { |
29 | 0 | sk_void_free(ret->meth_data); |
30 | 0 | OPENSSL_free(ret); |
31 | 0 | return NULL; |
32 | 0 | } |
33 | | |
34 | 0 | if ((ret->meth->init != NULL) && !ret->meth->init(ret)) { |
35 | 0 | DSO_free(ret); |
36 | 0 | ret = NULL; |
37 | 0 | } |
38 | |
|
39 | 0 | return ret; |
40 | 0 | } |
41 | | |
42 | | DSO *DSO_new(void) |
43 | 0 | { |
44 | 0 | return DSO_new_method(NULL); |
45 | 0 | } |
46 | | |
47 | | int DSO_free(DSO *dso) |
48 | 2 | { |
49 | 2 | int i; |
50 | | |
51 | 2 | if (dso == NULL) |
52 | 2 | return 1; |
53 | | |
54 | 0 | if (CRYPTO_DOWN_REF(&dso->references, &i) <= 0) |
55 | 0 | return 0; |
56 | | |
57 | 0 | REF_PRINT_COUNT("DSO", dso); |
58 | 0 | if (i > 0) |
59 | 0 | return 1; |
60 | 0 | REF_ASSERT_ISNT(i < 0); |
61 | |
|
62 | 0 | if ((dso->flags & DSO_FLAG_NO_UNLOAD_ON_FREE) == 0) { |
63 | 0 | if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) { |
64 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNLOAD_FAILED); |
65 | 0 | return 0; |
66 | 0 | } |
67 | 0 | } |
68 | | |
69 | 0 | if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) { |
70 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_FINISH_FAILED); |
71 | 0 | return 0; |
72 | 0 | } |
73 | | |
74 | 0 | sk_void_free(dso->meth_data); |
75 | 0 | OPENSSL_free(dso->filename); |
76 | 0 | OPENSSL_free(dso->loaded_filename); |
77 | 0 | CRYPTO_FREE_REF(&dso->references); |
78 | 0 | OPENSSL_free(dso); |
79 | 0 | return 1; |
80 | 0 | } |
81 | | |
82 | | int DSO_flags(DSO *dso) |
83 | 0 | { |
84 | 0 | return ((dso == NULL) ? 0 : dso->flags); |
85 | 0 | } |
86 | | |
87 | | int DSO_up_ref(DSO *dso) |
88 | 0 | { |
89 | 0 | int i; |
90 | |
|
91 | 0 | if (dso == NULL) { |
92 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
93 | 0 | return 0; |
94 | 0 | } |
95 | | |
96 | 0 | if (CRYPTO_UP_REF(&dso->references, &i) <= 0) |
97 | 0 | return 0; |
98 | | |
99 | 0 | REF_PRINT_COUNT("DSO", dso); |
100 | 0 | REF_ASSERT_ISNT(i < 2); |
101 | 0 | return ((i > 1) ? 1 : 0); |
102 | 0 | } |
103 | | |
104 | | DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags) |
105 | 0 | { |
106 | 0 | DSO *ret; |
107 | 0 | int allocated = 0; |
108 | |
|
109 | 0 | if (dso == NULL) { |
110 | 0 | ret = DSO_new_method(meth); |
111 | 0 | if (ret == NULL) { |
112 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_DSO_LIB); |
113 | 0 | goto err; |
114 | 0 | } |
115 | 0 | allocated = 1; |
116 | | /* Pass the provided flags to the new DSO object */ |
117 | 0 | if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) { |
118 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_CTRL_FAILED); |
119 | 0 | goto err; |
120 | 0 | } |
121 | 0 | } else |
122 | 0 | ret = dso; |
123 | | /* Don't load if we're currently already loaded */ |
124 | 0 | if (ret->filename != NULL) { |
125 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED); |
126 | 0 | goto err; |
127 | 0 | } |
128 | | /* |
129 | | * filename can only be NULL if we were passed a dso that already has one |
130 | | * set. |
131 | | */ |
132 | 0 | if (filename != NULL) |
133 | 0 | if (!DSO_set_filename(ret, filename)) { |
134 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_SET_FILENAME_FAILED); |
135 | 0 | goto err; |
136 | 0 | } |
137 | 0 | filename = ret->filename; |
138 | 0 | if (filename == NULL) { |
139 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); |
140 | 0 | goto err; |
141 | 0 | } |
142 | 0 | if (ret->meth->dso_load == NULL) { |
143 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
144 | 0 | goto err; |
145 | 0 | } |
146 | 0 | if (!ret->meth->dso_load(ret)) { |
147 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_LOAD_FAILED); |
148 | 0 | goto err; |
149 | 0 | } |
150 | | /* Load succeeded */ |
151 | 0 | return ret; |
152 | 0 | err: |
153 | 0 | if (allocated) |
154 | 0 | DSO_free(ret); |
155 | 0 | return NULL; |
156 | 0 | } |
157 | | |
158 | | DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname) |
159 | 0 | { |
160 | 0 | DSO_FUNC_TYPE ret = NULL; |
161 | |
|
162 | 0 | if ((dso == NULL) || (symname == NULL)) { |
163 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
164 | 0 | return NULL; |
165 | 0 | } |
166 | 0 | if (dso->meth->dso_bind_func == NULL) { |
167 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
168 | 0 | return NULL; |
169 | 0 | } |
170 | 0 | if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) { |
171 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_SYM_FAILURE); |
172 | 0 | return NULL; |
173 | 0 | } |
174 | | /* Success */ |
175 | 0 | return ret; |
176 | 0 | } |
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 | 0 | { |
189 | 0 | if (dso == NULL) { |
190 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
191 | 0 | return -1; |
192 | 0 | } |
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 | 0 | switch (cmd) { |
198 | 0 | case DSO_CTRL_GET_FLAGS: |
199 | 0 | return dso->flags; |
200 | 0 | case DSO_CTRL_SET_FLAGS: |
201 | 0 | dso->flags = (int)larg; |
202 | 0 | return 0; |
203 | 0 | case DSO_CTRL_OR_FLAGS: |
204 | 0 | dso->flags |= (int)larg; |
205 | 0 | return 0; |
206 | 0 | default: |
207 | 0 | break; |
208 | 0 | } |
209 | 0 | if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) { |
210 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
211 | 0 | return -1; |
212 | 0 | } |
213 | 0 | return dso->meth->dso_ctrl(dso, cmd, larg, parg); |
214 | 0 | } |
215 | | |
216 | | const char *DSO_get_filename(DSO *dso) |
217 | 0 | { |
218 | 0 | if (dso == NULL) { |
219 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
220 | 0 | return NULL; |
221 | 0 | } |
222 | 0 | return dso->filename; |
223 | 0 | } |
224 | | |
225 | | int DSO_set_filename(DSO *dso, const char *filename) |
226 | 0 | { |
227 | 0 | char *copied; |
228 | |
|
229 | 0 | if ((dso == NULL) || (filename == NULL)) { |
230 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
231 | 0 | return 0; |
232 | 0 | } |
233 | 0 | if (dso->loaded_filename) { |
234 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED); |
235 | 0 | return 0; |
236 | 0 | } |
237 | | /* We'll duplicate filename */ |
238 | 0 | copied = OPENSSL_strdup(filename); |
239 | 0 | if (copied == NULL) |
240 | 0 | return 0; |
241 | 0 | OPENSSL_free(dso->filename); |
242 | 0 | dso->filename = copied; |
243 | 0 | return 1; |
244 | 0 | } |
245 | | |
246 | | char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2) |
247 | 0 | { |
248 | 0 | char *result = NULL; |
249 | |
|
250 | 0 | if (dso == NULL || filespec1 == NULL) { |
251 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
252 | 0 | return NULL; |
253 | 0 | } |
254 | 0 | if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) { |
255 | 0 | if (dso->merger != NULL) |
256 | 0 | result = dso->merger(dso, filespec1, filespec2); |
257 | 0 | else if (dso->meth->dso_merger != NULL) |
258 | 0 | result = dso->meth->dso_merger(dso, filespec1, filespec2); |
259 | 0 | } |
260 | 0 | return result; |
261 | 0 | } |
262 | | |
263 | | char *DSO_convert_filename(DSO *dso, const char *filename) |
264 | 0 | { |
265 | 0 | char *result = NULL; |
266 | |
|
267 | 0 | if (dso == NULL) { |
268 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
269 | 0 | return NULL; |
270 | 0 | } |
271 | 0 | if (filename == NULL) |
272 | 0 | filename = dso->filename; |
273 | 0 | if (filename == NULL) { |
274 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); |
275 | 0 | return NULL; |
276 | 0 | } |
277 | 0 | if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) { |
278 | 0 | if (dso->name_converter != NULL) |
279 | 0 | result = dso->name_converter(dso, filename); |
280 | 0 | else if (dso->meth->dso_name_converter != NULL) |
281 | 0 | result = dso->meth->dso_name_converter(dso, filename); |
282 | 0 | } |
283 | 0 | if (result == NULL) { |
284 | 0 | result = OPENSSL_strdup(filename); |
285 | 0 | if (result == NULL) |
286 | 0 | return NULL; |
287 | 0 | } |
288 | 0 | return result; |
289 | 0 | } |
290 | | |
291 | | int DSO_pathbyaddr(void *addr, char *path, int sz) |
292 | 0 | { |
293 | 0 | DSO_METHOD *meth = DSO_METHOD_openssl(); |
294 | |
|
295 | 0 | if (meth->pathbyaddr == NULL) { |
296 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
297 | 0 | return -1; |
298 | 0 | } |
299 | 0 | return (*meth->pathbyaddr) (addr, path, sz); |
300 | 0 | } |
301 | | |
302 | | DSO *DSO_dsobyaddr(void *addr, int flags) |
303 | 0 | { |
304 | 0 | DSO *ret = NULL; |
305 | 0 | char *filename = NULL; |
306 | 0 | int len = DSO_pathbyaddr(addr, NULL, 0); |
307 | |
|
308 | 0 | if (len < 0) |
309 | 0 | return NULL; |
310 | | |
311 | 0 | filename = OPENSSL_malloc(len); |
312 | 0 | if (filename != NULL |
313 | 0 | && DSO_pathbyaddr(addr, filename, len) == len) |
314 | 0 | ret = DSO_load(NULL, filename, NULL, flags); |
315 | |
|
316 | 0 | OPENSSL_free(filename); |
317 | 0 | return ret; |
318 | 0 | } |
319 | | |
320 | | void *DSO_global_lookup(const char *name) |
321 | 0 | { |
322 | 0 | DSO_METHOD *meth = DSO_METHOD_openssl(); |
323 | |
|
324 | 0 | if (meth->globallookup == NULL) { |
325 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
326 | 0 | return NULL; |
327 | 0 | } |
328 | 0 | return (*meth->globallookup) (name); |
329 | 0 | } |