diff options
Diffstat (limited to 'src/lib/libcrypto/dso/dso_dlfcn.c')
-rw-r--r-- | src/lib/libcrypto/dso/dso_dlfcn.c | 157 |
1 files changed, 135 insertions, 22 deletions
diff --git a/src/lib/libcrypto/dso/dso_dlfcn.c b/src/lib/libcrypto/dso/dso_dlfcn.c index 656cd496f8..5dceaf7b00 100644 --- a/src/lib/libcrypto/dso/dso_dlfcn.c +++ b/src/lib/libcrypto/dso/dso_dlfcn.c | |||
@@ -56,6 +56,16 @@ | |||
56 | * | 56 | * |
57 | */ | 57 | */ |
58 | 58 | ||
59 | /* We need to do this early, because stdio.h includes the header files | ||
60 | that handle _GNU_SOURCE and other similar macros. Defining it later | ||
61 | is simply too late, because those headers are protected from re- | ||
62 | inclusion. */ | ||
63 | #ifdef __linux | ||
64 | # ifndef _GNU_SOURCE | ||
65 | # define _GNU_SOURCE /* make sure dladdr is declared */ | ||
66 | # endif | ||
67 | #endif | ||
68 | |||
59 | #include <stdio.h> | 69 | #include <stdio.h> |
60 | #include "cryptlib.h" | 70 | #include "cryptlib.h" |
61 | #include <openssl/dso.h> | 71 | #include <openssl/dso.h> |
@@ -68,7 +78,16 @@ DSO_METHOD *DSO_METHOD_dlfcn(void) | |||
68 | #else | 78 | #else |
69 | 79 | ||
70 | #ifdef HAVE_DLFCN_H | 80 | #ifdef HAVE_DLFCN_H |
71 | #include <dlfcn.h> | 81 | # ifdef __osf__ |
82 | # define __EXTENSIONS__ | ||
83 | # endif | ||
84 | # include <dlfcn.h> | ||
85 | # define HAVE_DLINFO 1 | ||
86 | # if defined(_AIX) || defined(__CYGWIN__) || \ | ||
87 | defined(__SCO_VERSION__) || defined(_SCO_ELF) || \ | ||
88 | (defined(__OpenBSD__) && !defined(RTLD_SELF)) | ||
89 | # undef HAVE_DLINFO | ||
90 | # endif | ||
72 | #endif | 91 | #endif |
73 | 92 | ||
74 | /* Part of the hack in "dlfcn_load" ... */ | 93 | /* Part of the hack in "dlfcn_load" ... */ |
@@ -87,6 +106,8 @@ static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg); | |||
87 | static char *dlfcn_name_converter(DSO *dso, const char *filename); | 106 | static char *dlfcn_name_converter(DSO *dso, const char *filename); |
88 | static char *dlfcn_merger(DSO *dso, const char *filespec1, | 107 | static char *dlfcn_merger(DSO *dso, const char *filespec1, |
89 | const char *filespec2); | 108 | const char *filespec2); |
109 | static int dlfcn_pathbyaddr(void *addr,char *path,int sz); | ||
110 | static void *dlfcn_globallookup(const char *name); | ||
90 | 111 | ||
91 | static DSO_METHOD dso_meth_dlfcn = { | 112 | static DSO_METHOD dso_meth_dlfcn = { |
92 | "OpenSSL 'dlfcn' shared library method", | 113 | "OpenSSL 'dlfcn' shared library method", |
@@ -103,7 +124,9 @@ static DSO_METHOD dso_meth_dlfcn = { | |||
103 | dlfcn_name_converter, | 124 | dlfcn_name_converter, |
104 | dlfcn_merger, | 125 | dlfcn_merger, |
105 | NULL, /* init */ | 126 | NULL, /* init */ |
106 | NULL /* finish */ | 127 | NULL, /* finish */ |
128 | dlfcn_pathbyaddr, | ||
129 | dlfcn_globallookup | ||
107 | }; | 130 | }; |
108 | 131 | ||
109 | DSO_METHOD *DSO_METHOD_dlfcn(void) | 132 | DSO_METHOD *DSO_METHOD_dlfcn(void) |
@@ -163,7 +186,7 @@ static int dlfcn_load(DSO *dso) | |||
163 | ERR_add_error_data(4, "filename(", filename, "): ", dlerror()); | 186 | ERR_add_error_data(4, "filename(", filename, "): ", dlerror()); |
164 | goto err; | 187 | goto err; |
165 | } | 188 | } |
166 | if(!sk_push(dso->meth_data, (char *)ptr)) | 189 | if(!sk_void_push(dso->meth_data, (char *)ptr)) |
167 | { | 190 | { |
168 | DSOerr(DSO_F_DLFCN_LOAD,DSO_R_STACK_ERROR); | 191 | DSOerr(DSO_F_DLFCN_LOAD,DSO_R_STACK_ERROR); |
169 | goto err; | 192 | goto err; |
@@ -188,15 +211,15 @@ static int dlfcn_unload(DSO *dso) | |||
188 | DSOerr(DSO_F_DLFCN_UNLOAD,ERR_R_PASSED_NULL_PARAMETER); | 211 | DSOerr(DSO_F_DLFCN_UNLOAD,ERR_R_PASSED_NULL_PARAMETER); |
189 | return(0); | 212 | return(0); |
190 | } | 213 | } |
191 | if(sk_num(dso->meth_data) < 1) | 214 | if(sk_void_num(dso->meth_data) < 1) |
192 | return(1); | 215 | return(1); |
193 | ptr = (void *)sk_pop(dso->meth_data); | 216 | ptr = sk_void_pop(dso->meth_data); |
194 | if(ptr == NULL) | 217 | if(ptr == NULL) |
195 | { | 218 | { |
196 | DSOerr(DSO_F_DLFCN_UNLOAD,DSO_R_NULL_HANDLE); | 219 | DSOerr(DSO_F_DLFCN_UNLOAD,DSO_R_NULL_HANDLE); |
197 | /* Should push the value back onto the stack in | 220 | /* Should push the value back onto the stack in |
198 | * case of a retry. */ | 221 | * case of a retry. */ |
199 | sk_push(dso->meth_data, (char *)ptr); | 222 | sk_void_push(dso->meth_data, ptr); |
200 | return(0); | 223 | return(0); |
201 | } | 224 | } |
202 | /* For now I'm not aware of any errors associated with dlclose() */ | 225 | /* For now I'm not aware of any errors associated with dlclose() */ |
@@ -213,12 +236,12 @@ static void *dlfcn_bind_var(DSO *dso, const char *symname) | |||
213 | DSOerr(DSO_F_DLFCN_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER); | 236 | DSOerr(DSO_F_DLFCN_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER); |
214 | return(NULL); | 237 | return(NULL); |
215 | } | 238 | } |
216 | if(sk_num(dso->meth_data) < 1) | 239 | if(sk_void_num(dso->meth_data) < 1) |
217 | { | 240 | { |
218 | DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_STACK_ERROR); | 241 | DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_STACK_ERROR); |
219 | return(NULL); | 242 | return(NULL); |
220 | } | 243 | } |
221 | ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); | 244 | ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1); |
222 | if(ptr == NULL) | 245 | if(ptr == NULL) |
223 | { | 246 | { |
224 | DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_NULL_HANDLE); | 247 | DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_NULL_HANDLE); |
@@ -237,32 +260,35 @@ static void *dlfcn_bind_var(DSO *dso, const char *symname) | |||
237 | static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) | 260 | static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) |
238 | { | 261 | { |
239 | void *ptr; | 262 | void *ptr; |
240 | DSO_FUNC_TYPE sym, *tsym = &sym; | 263 | union { |
264 | DSO_FUNC_TYPE sym; | ||
265 | void *dlret; | ||
266 | } u; | ||
241 | 267 | ||
242 | if((dso == NULL) || (symname == NULL)) | 268 | if((dso == NULL) || (symname == NULL)) |
243 | { | 269 | { |
244 | DSOerr(DSO_F_DLFCN_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER); | 270 | DSOerr(DSO_F_DLFCN_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER); |
245 | return(NULL); | 271 | return(NULL); |
246 | } | 272 | } |
247 | if(sk_num(dso->meth_data) < 1) | 273 | if(sk_void_num(dso->meth_data) < 1) |
248 | { | 274 | { |
249 | DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_STACK_ERROR); | 275 | DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_STACK_ERROR); |
250 | return(NULL); | 276 | return(NULL); |
251 | } | 277 | } |
252 | ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); | 278 | ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1); |
253 | if(ptr == NULL) | 279 | if(ptr == NULL) |
254 | { | 280 | { |
255 | DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_NULL_HANDLE); | 281 | DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_NULL_HANDLE); |
256 | return(NULL); | 282 | return(NULL); |
257 | } | 283 | } |
258 | *(void **)(tsym) = dlsym(ptr, symname); | 284 | u.dlret = dlsym(ptr, symname); |
259 | if(sym == NULL) | 285 | if(u.dlret == NULL) |
260 | { | 286 | { |
261 | DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_SYM_FAILURE); | 287 | DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_SYM_FAILURE); |
262 | ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); | 288 | ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); |
263 | return(NULL); | 289 | return(NULL); |
264 | } | 290 | } |
265 | return(sym); | 291 | return u.sym; |
266 | } | 292 | } |
267 | 293 | ||
268 | static char *dlfcn_merger(DSO *dso, const char *filespec1, | 294 | static char *dlfcn_merger(DSO *dso, const char *filespec1, |
@@ -279,14 +305,13 @@ static char *dlfcn_merger(DSO *dso, const char *filespec1, | |||
279 | } | 305 | } |
280 | /* If the first file specification is a rooted path, it rules. | 306 | /* If the first file specification is a rooted path, it rules. |
281 | same goes if the second file specification is missing. */ | 307 | same goes if the second file specification is missing. */ |
282 | if (!filespec2 || filespec1[0] == '/') | 308 | if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) |
283 | { | 309 | { |
284 | len = strlen(filespec1) + 1; | 310 | len = strlen(filespec1) + 1; |
285 | merged = OPENSSL_malloc(len); | 311 | merged = OPENSSL_malloc(len); |
286 | if(!merged) | 312 | if(!merged) |
287 | { | 313 | { |
288 | DSOerr(DSO_F_DLFCN_MERGER, | 314 | DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE); |
289 | ERR_R_MALLOC_FAILURE); | ||
290 | return(NULL); | 315 | return(NULL); |
291 | } | 316 | } |
292 | strlcpy(merged, filespec1, len); | 317 | strlcpy(merged, filespec1, len); |
@@ -313,7 +338,7 @@ static char *dlfcn_merger(DSO *dso, const char *filespec1, | |||
313 | { | 338 | { |
314 | int spec2len, len; | 339 | int spec2len, len; |
315 | 340 | ||
316 | spec2len = (filespec2 ? strlen(filespec2) : 0); | 341 | spec2len = strlen(filespec2); |
317 | len = spec2len + (filespec1 ? strlen(filespec1) : 0); | 342 | len = spec2len + (filespec1 ? strlen(filespec1) : 0); |
318 | 343 | ||
319 | if(filespec2 && filespec2[spec2len - 1] == '/') | 344 | if(filespec2 && filespec2[spec2len - 1] == '/') |
@@ -335,6 +360,15 @@ static char *dlfcn_merger(DSO *dso, const char *filespec1, | |||
335 | return(merged); | 360 | return(merged); |
336 | } | 361 | } |
337 | 362 | ||
363 | #ifdef OPENSSL_SYS_MACOSX | ||
364 | #define DSO_ext ".dylib" | ||
365 | #define DSO_extlen 6 | ||
366 | #else | ||
367 | #define DSO_ext ".so" | ||
368 | #define DSO_extlen 3 | ||
369 | #endif | ||
370 | |||
371 | |||
338 | static char *dlfcn_name_converter(DSO *dso, const char *filename) | 372 | static char *dlfcn_name_converter(DSO *dso, const char *filename) |
339 | { | 373 | { |
340 | char *translated; | 374 | char *translated; |
@@ -345,8 +379,8 @@ static char *dlfcn_name_converter(DSO *dso, const char *filename) | |||
345 | transform = (strstr(filename, "/") == NULL); | 379 | transform = (strstr(filename, "/") == NULL); |
346 | if(transform) | 380 | if(transform) |
347 | { | 381 | { |
348 | /* We will convert this to "%s.so" or "lib%s.so" */ | 382 | /* We will convert this to "%s.so" or "lib%s.so" etc */ |
349 | rsize += 3; /* The length of ".so" */ | 383 | rsize += DSO_extlen; /* The length of ".so" */ |
350 | if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) | 384 | if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) |
351 | rsize += 3; /* The length of "lib" */ | 385 | rsize += 3; /* The length of "lib" */ |
352 | } | 386 | } |
@@ -360,13 +394,92 @@ static char *dlfcn_name_converter(DSO *dso, const char *filename) | |||
360 | if(transform) | 394 | if(transform) |
361 | { | 395 | { |
362 | if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) | 396 | if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) |
363 | snprintf(translated, rsize, "lib%s.so", filename); | 397 | snprintf(translated, rsize, "lib%s" DSO_ext, filename); |
364 | else | 398 | else |
365 | snprintf(translated, rsize, "%s.so", filename); | 399 | snprintf(translated, rsize, "%s" DSO_ext, filename); |
366 | } | 400 | } |
367 | else | 401 | else |
368 | snprintf(translated, rsize, "%s", filename); | 402 | snprintf(translated, rsize, "%s", filename); |
369 | return(translated); | 403 | return(translated); |
370 | } | 404 | } |
371 | 405 | ||
406 | #if defined(__sgi) && !defined(__OpenBSD__) | ||
407 | /* | ||
408 | This is a quote from IRIX manual for dladdr(3c): | ||
409 | |||
410 | <dlfcn.h> does not contain a prototype for dladdr or definition of | ||
411 | Dl_info. The #include <dlfcn.h> in the SYNOPSIS line is traditional, | ||
412 | but contains no dladdr prototype and no IRIX library contains an | ||
413 | implementation. Write your own declaration based on the code below. | ||
414 | |||
415 | The following code is dependent on internal interfaces that are not | ||
416 | part of the IRIX compatibility guarantee; however, there is no future | ||
417 | intention to change this interface, so on a practical level, the code | ||
418 | below is safe to use on IRIX. | ||
419 | */ | ||
420 | #include <rld_interface.h> | ||
421 | #ifndef _RLD_INTERFACE_DLFCN_H_DLADDR | ||
422 | #define _RLD_INTERFACE_DLFCN_H_DLADDR | ||
423 | typedef struct Dl_info { | ||
424 | const char * dli_fname; | ||
425 | void * dli_fbase; | ||
426 | const char * dli_sname; | ||
427 | void * dli_saddr; | ||
428 | int dli_version; | ||
429 | int dli_reserved1; | ||
430 | long dli_reserved[4]; | ||
431 | } Dl_info; | ||
432 | #else | ||
433 | typedef struct Dl_info Dl_info; | ||
434 | #endif | ||
435 | #define _RLD_DLADDR 14 | ||
436 | |||
437 | static int dladdr(void *address, Dl_info *dl) | ||
438 | { | ||
439 | void *v; | ||
440 | v = _rld_new_interface(_RLD_DLADDR,address,dl); | ||
441 | return (int)v; | ||
442 | } | ||
443 | #endif /* __sgi */ | ||
444 | |||
445 | static int dlfcn_pathbyaddr(void *addr,char *path,int sz) | ||
446 | { | ||
447 | #ifdef HAVE_DLINFO | ||
448 | Dl_info dli; | ||
449 | int len; | ||
450 | |||
451 | if (addr == NULL) | ||
452 | { | ||
453 | union { int(*f)(void*,char*,int); void *p; } t = | ||
454 | { dlfcn_pathbyaddr }; | ||
455 | addr = t.p; | ||
456 | } | ||
457 | |||
458 | if (dladdr(addr,&dli)) | ||
459 | { | ||
460 | len = (int)strlen(dli.dli_fname); | ||
461 | if (sz <= 0) return len+1; | ||
462 | if (len >= sz) len=sz-1; | ||
463 | memcpy(path,dli.dli_fname,len); | ||
464 | path[len++]=0; | ||
465 | return len; | ||
466 | } | ||
467 | |||
468 | ERR_add_error_data(4, "dlfcn_pathbyaddr(): ", dlerror()); | ||
469 | #endif | ||
470 | return -1; | ||
471 | } | ||
472 | |||
473 | static void *dlfcn_globallookup(const char *name) | ||
474 | { | ||
475 | void *ret = NULL,*handle = dlopen(NULL,RTLD_LAZY); | ||
476 | |||
477 | if (handle) | ||
478 | { | ||
479 | ret = dlsym(handle,name); | ||
480 | dlclose(handle); | ||
481 | } | ||
482 | |||
483 | return ret; | ||
484 | } | ||
372 | #endif /* DSO_DLFCN */ | 485 | #endif /* DSO_DLFCN */ |