2 * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
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
11 * We need to do this early, because stdio.h includes the header files that
12 * handle _GNU_SOURCE and other similar macros. Defining it later is simply
13 * too late, because those headers are protected from re- inclusion.
16 # define _GNU_SOURCE /* make sure dladdr is declared */
25 # define __EXTENSIONS__
28 # define HAVE_DLINFO 1
29 # if defined(_AIX) || defined(__CYGWIN__) || \
30 defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
31 (defined(__osf__) && !defined(RTLD_NEXT)) || \
32 (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
38 /* Part of the hack in "dlfcn_load" ... */
39 # define DSO_MAX_TRANSLATED_SIZE 256
41 static int dlfcn_load(DSO *dso);
42 static int dlfcn_unload(DSO *dso);
43 static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
44 static char *dlfcn_name_converter(DSO *dso, const char *filename);
45 static char *dlfcn_merger(DSO *dso, const char *filespec1,
46 const char *filespec2);
47 static void *dlfcn_globallookup(const char *name);
49 static DSO_METHOD dso_meth_dlfcn = {
50 "OpenSSL 'dlfcn' shared library method",
62 DSO_METHOD *DSO_METHOD_openssl(void)
64 return &dso_meth_dlfcn;
68 * Prior to using the dlopen() function, we should decide on the flag we
69 * send. There's a few different ways of doing this and it's a messy
70 * venn-diagram to match up which platforms support what. So as we don't have
71 * autoconf yet, I'm implementing a hack that could be hacked further
72 * relatively easily to deal with cases as we find them. Initially this is to
75 # if defined(__OpenBSD__) || defined(__NetBSD__)
77 # define DLOPEN_FLAG DL_LAZY
80 # define DLOPEN_FLAG RTLD_NOW
82 # define DLOPEN_FLAG 0
86 # define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */
90 * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
91 * (void*) returned from dlopen().
94 static int dlfcn_load(DSO *dso)
97 /* See applicable comments in dso_dl.c */
98 char *filename = DSO_convert_filename(dso, NULL);
99 int flags = DLOPEN_FLAG;
101 if (filename == NULL) {
102 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_NO_FILENAME);
106 if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
107 flags |= RTLD_GLOBAL;
109 ptr = dlopen(filename, flags);
111 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_LOAD_FAILED);
112 ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
115 if (!sk_void_push(dso->meth_data, (char *)ptr)) {
116 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_STACK_ERROR);
120 dso->loaded_filename = filename;
124 OPENSSL_free(filename);
130 static int dlfcn_unload(DSO *dso)
134 DSOerr(DSO_F_DLFCN_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
137 if (sk_void_num(dso->meth_data) < 1)
139 ptr = sk_void_pop(dso->meth_data);
141 DSOerr(DSO_F_DLFCN_UNLOAD, DSO_R_NULL_HANDLE);
143 * Should push the value back onto the stack in case of a retry.
145 sk_void_push(dso->meth_data, ptr);
148 /* For now I'm not aware of any errors associated with dlclose() */
153 static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
161 if ((dso == NULL) || (symname == NULL)) {
162 DSOerr(DSO_F_DLFCN_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
165 if (sk_void_num(dso->meth_data) < 1) {
166 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_STACK_ERROR);
169 ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
171 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_NULL_HANDLE);
174 u.dlret = dlsym(ptr, symname);
175 if (u.dlret == NULL) {
176 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_SYM_FAILURE);
177 ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
183 static char *dlfcn_merger(DSO *dso, const char *filespec1,
184 const char *filespec2)
188 if (!filespec1 && !filespec2) {
189 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_PASSED_NULL_PARAMETER);
193 * If the first file specification is a rooted path, it rules. same goes
194 * if the second file specification is missing.
196 if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) {
197 merged = OPENSSL_strdup(filespec1);
198 if (merged == NULL) {
199 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
204 * If the first file specification is missing, the second one rules.
206 else if (!filespec1) {
207 merged = OPENSSL_strdup(filespec2);
208 if (merged == NULL) {
209 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
214 * This part isn't as trivial as it looks. It assumes that the
215 * second file specification really is a directory, and makes no
216 * checks whatsoever. Therefore, the result becomes the
217 * concatenation of filespec2 followed by a slash followed by
222 spec2len = strlen(filespec2);
223 len = spec2len + strlen(filespec1);
225 if (spec2len && filespec2[spec2len - 1] == '/') {
229 merged = OPENSSL_malloc(len + 2);
230 if (merged == NULL) {
231 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
234 strcpy(merged, filespec2);
235 merged[spec2len] = '/';
236 strcpy(&merged[spec2len + 1], filespec1);
241 static char *dlfcn_name_converter(DSO *dso, const char *filename)
244 int len, rsize, transform;
246 len = strlen(filename);
248 transform = (strstr(filename, "/") == NULL);
250 /* We will convert this to "%s.so" or "lib%s.so" etc */
251 rsize += strlen(DSO_EXTENSION); /* The length of ".so" */
252 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
253 rsize += 3; /* The length of "lib" */
255 translated = OPENSSL_malloc(rsize);
256 if (translated == NULL) {
257 DSOerr(DSO_F_DLFCN_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
261 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
262 sprintf(translated, "lib%s" DSO_EXTENSION, filename);
264 sprintf(translated, "%s" DSO_EXTENSION, filename);
266 sprintf(translated, "%s", filename);
272 This is a quote from IRIX manual for dladdr(3c):
274 <dlfcn.h> does not contain a prototype for dladdr or definition of
275 Dl_info. The #include <dlfcn.h> in the SYNOPSIS line is traditional,
276 but contains no dladdr prototype and no IRIX library contains an
277 implementation. Write your own declaration based on the code below.
279 The following code is dependent on internal interfaces that are not
280 part of the IRIX compatibility guarantee; however, there is no future
281 intention to change this interface, so on a practical level, the code
282 below is safe to use on IRIX.
284 # include <rld_interface.h>
285 # ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
286 # define _RLD_INTERFACE_DLFCN_H_DLADDR
287 typedef struct Dl_info {
288 const char *dli_fname;
290 const char *dli_sname;
294 long dli_reserved[4];
297 typedef struct Dl_info Dl_info;
299 # define _RLD_DLADDR 14
301 static int dladdr(void *address, Dl_info *dl)
304 v = _rld_new_interface(_RLD_DLADDR, address, dl);
309 static void *dlfcn_globallookup(const char *name)
311 void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
314 ret = dlsym(handle, name);
320 #endif /* DSO_DLFCN */