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