summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/dso/dso_dlfcn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/dso/dso_dlfcn.c')
-rw-r--r--src/lib/libcrypto/dso/dso_dlfcn.c157
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);
87static char *dlfcn_name_converter(DSO *dso, const char *filename); 106static char *dlfcn_name_converter(DSO *dso, const char *filename);
88static char *dlfcn_merger(DSO *dso, const char *filespec1, 107static char *dlfcn_merger(DSO *dso, const char *filespec1,
89 const char *filespec2); 108 const char *filespec2);
109static int dlfcn_pathbyaddr(void *addr,char *path,int sz);
110static void *dlfcn_globallookup(const char *name);
90 111
91static DSO_METHOD dso_meth_dlfcn = { 112static 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
109DSO_METHOD *DSO_METHOD_dlfcn(void) 132DSO_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)
237static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) 260static 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
268static char *dlfcn_merger(DSO *dso, const char *filespec1, 294static 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
338static char *dlfcn_name_converter(DSO *dso, const char *filename) 372static 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/*
408This 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
423typedef 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
433typedef struct Dl_info Dl_info;
434#endif
435#define _RLD_DLADDR 14
436
437static 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
445static 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
473static 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 */