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