]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/dso/dso_dlfcn.c
Always build library object files with shared library cflags
[thirdparty/openssl.git] / crypto / dso / dso_dlfcn.c
CommitLineData
0f113f3e
MC
1/*
2 * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
3 * 2000.
8f4fac7f
GT
4 */
5/* ====================================================================
6 * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
0f113f3e 13 * notice, this list of conditions and the following disclaimer.
8f4fac7f
GT
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgment:
22 * "This product includes software developed by the OpenSSL Project
23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 * endorse or promote products derived from this software without
27 * prior written permission. For written permission, please contact
28 * licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 * nor may "OpenSSL" appear in their names without prior written
32 * permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 * acknowledgment:
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 * This product includes cryptographic software written by Eric Young
54 * (eay@cryptsoft.com). This product includes software written by Tim
55 * Hudson (tjh@cryptsoft.com).
56 *
57 */
58
0f113f3e
MC
59/*
60 * We need to do this early, because stdio.h includes the header files that
61 * handle _GNU_SOURCE and other similar macros. Defining it later is simply
62 * too late, because those headers are protected from re- inclusion.
63 */
c1844095 64#ifndef _GNU_SOURCE
0f113f3e 65# define _GNU_SOURCE /* make sure dladdr is declared */
3ecbd099
RL
66#endif
67
8f4fac7f 68#include <stdio.h>
b39fc560 69#include "internal/cryptlib.h"
8f4fac7f 70#include <openssl/dso.h>
e987f9f2 71#include "internal/dso_conf.h"
8f4fac7f
GT
72
73#ifndef DSO_DLFCN
74DSO_METHOD *DSO_METHOD_dlfcn(void)
0f113f3e
MC
75{
76 return NULL;
77}
8f4fac7f
GT
78#else
79
0f113f3e
MC
80# ifdef HAVE_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__) || \
73133962 87 defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
afb41913 88 (defined(__osf__) && !defined(RTLD_NEXT)) || \
7a4ec19a 89 (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
0f113f3e
MC
90 defined(__ANDROID__)
91# undef HAVE_DLINFO
92# endif
73133962 93# endif
8f4fac7f 94
b9e63915 95/* Part of the hack in "dlfcn_load" ... */
0f113f3e 96# define DSO_MAX_TRANSLATED_SIZE 256
b9e63915 97
51c8dc37 98static int dlfcn_load(DSO *dso);
8f4fac7f 99static int dlfcn_unload(DSO *dso);
e9a68cfb
GT
100static void *dlfcn_bind_var(DSO *dso, const char *symname);
101static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
51c8dc37 102static char *dlfcn_name_converter(DSO *dso, const char *filename);
cbecb3ac 103static char *dlfcn_merger(DSO *dso, const char *filespec1,
0f113f3e
MC
104 const char *filespec2);
105static int dlfcn_pathbyaddr(void *addr, char *path, int sz);
c6cb42e4 106static void *dlfcn_globallookup(const char *name);
8f4fac7f
GT
107
108static DSO_METHOD dso_meth_dlfcn = {
0f113f3e
MC
109 "OpenSSL 'dlfcn' shared library method",
110 dlfcn_load,
111 dlfcn_unload,
112 dlfcn_bind_var,
113 dlfcn_bind_func,
0f113f3e
MC
114 NULL, /* ctrl */
115 dlfcn_name_converter,
116 dlfcn_merger,
117 NULL, /* init */
118 NULL, /* finish */
119 dlfcn_pathbyaddr,
120 dlfcn_globallookup
121};
8f4fac7f
GT
122
123DSO_METHOD *DSO_METHOD_dlfcn(void)
0f113f3e
MC
124{
125 return (&dso_meth_dlfcn);
126}
127
128/*
129 * Prior to using the dlopen() function, we should decide on the flag we
130 * send. There's a few different ways of doing this and it's a messy
131 * venn-diagram to match up which platforms support what. So as we don't have
132 * autoconf yet, I'm implementing a hack that could be hacked further
133 * relatively easily to deal with cases as we find them. Initially this is to
134 * cope with OpenBSD.
135 */
136# if defined(__OpenBSD__) || defined(__NetBSD__)
137# ifdef DL_LAZY
138# define DLOPEN_FLAG DL_LAZY
139# else
140# ifdef RTLD_NOW
141# define DLOPEN_FLAG RTLD_NOW
142# else
143# define DLOPEN_FLAG 0
144# endif
145# endif
146# else
147# define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */
148# endif
1a797ac6 149
0f113f3e
MC
150/*
151 * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
152 * (void*) returned from dlopen().
8f4fac7f
GT
153 */
154
51c8dc37 155static int dlfcn_load(DSO *dso)
0f113f3e
MC
156{
157 void *ptr = NULL;
158 /* See applicable comments in dso_dl.c */
159 char *filename = DSO_convert_filename(dso, NULL);
160 int flags = DLOPEN_FLAG;
161
162 if (filename == NULL) {
163 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_NO_FILENAME);
164 goto err;
165 }
166# ifdef RTLD_GLOBAL
167 if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
168 flags |= RTLD_GLOBAL;
169# endif
170 ptr = dlopen(filename, flags);
171 if (ptr == NULL) {
172 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_LOAD_FAILED);
173 ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
174 goto err;
175 }
176 if (!sk_void_push(dso->meth_data, (char *)ptr)) {
177 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_STACK_ERROR);
178 goto err;
179 }
180 /* Success */
181 dso->loaded_filename = filename;
182 return (1);
183 err:
184 /* Cleanup! */
b548a1f1 185 OPENSSL_free(filename);
0f113f3e
MC
186 if (ptr != NULL)
187 dlclose(ptr);
188 return (0);
51c8dc37 189}
8f4fac7f
GT
190
191static int dlfcn_unload(DSO *dso)
0f113f3e
MC
192{
193 void *ptr;
194 if (dso == NULL) {
195 DSOerr(DSO_F_DLFCN_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
196 return (0);
197 }
198 if (sk_void_num(dso->meth_data) < 1)
199 return (1);
200 ptr = sk_void_pop(dso->meth_data);
201 if (ptr == NULL) {
202 DSOerr(DSO_F_DLFCN_UNLOAD, DSO_R_NULL_HANDLE);
203 /*
204 * Should push the value back onto the stack in case of a retry.
205 */
206 sk_void_push(dso->meth_data, ptr);
207 return (0);
208 }
209 /* For now I'm not aware of any errors associated with dlclose() */
210 dlclose(ptr);
211 return (1);
212}
8f4fac7f 213
e9a68cfb 214static void *dlfcn_bind_var(DSO *dso, const char *symname)
0f113f3e
MC
215{
216 void *ptr, *sym;
217
218 if ((dso == NULL) || (symname == NULL)) {
219 DSOerr(DSO_F_DLFCN_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
220 return (NULL);
221 }
222 if (sk_void_num(dso->meth_data) < 1) {
223 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_STACK_ERROR);
224 return (NULL);
225 }
226 ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
227 if (ptr == NULL) {
228 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_NULL_HANDLE);
229 return (NULL);
230 }
231 sym = dlsym(ptr, symname);
232 if (sym == NULL) {
233 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_SYM_FAILURE);
234 ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
235 return (NULL);
236 }
237 return (sym);
238}
e9a68cfb
GT
239
240static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
0f113f3e
MC
241{
242 void *ptr;
243 union {
244 DSO_FUNC_TYPE sym;
245 void *dlret;
246 } u;
247
248 if ((dso == NULL) || (symname == NULL)) {
249 DSOerr(DSO_F_DLFCN_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
250 return (NULL);
251 }
252 if (sk_void_num(dso->meth_data) < 1) {
253 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_STACK_ERROR);
254 return (NULL);
255 }
256 ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
257 if (ptr == NULL) {
258 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_NULL_HANDLE);
259 return (NULL);
260 }
261 u.dlret = dlsym(ptr, symname);
262 if (u.dlret == NULL) {
263 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_SYM_FAILURE);
264 ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
265 return (NULL);
266 }
267 return u.sym;
268}
8f4fac7f 269
cbecb3ac 270static char *dlfcn_merger(DSO *dso, const char *filespec1,
0f113f3e
MC
271 const char *filespec2)
272{
273 char *merged;
274
275 if (!filespec1 && !filespec2) {
276 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_PASSED_NULL_PARAMETER);
277 return (NULL);
278 }
279 /*
280 * If the first file specification is a rooted path, it rules. same goes
281 * if the second file specification is missing.
282 */
283 if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) {
a89c9a0d 284 merged = OPENSSL_strdup(filespec1);
90945fa3 285 if (merged == NULL) {
0f113f3e
MC
286 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
287 return (NULL);
288 }
0f113f3e
MC
289 }
290 /*
291 * If the first file specification is missing, the second one rules.
292 */
293 else if (!filespec1) {
a89c9a0d 294 merged = OPENSSL_strdup(filespec2);
90945fa3 295 if (merged == NULL) {
0f113f3e
MC
296 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
297 return (NULL);
298 }
b7573c59 299 } else {
0f113f3e
MC
300 /*
301 * This part isn't as trivial as it looks. It assumes that the
302 * second file specification really is a directory, and makes no
303 * checks whatsoever. Therefore, the result becomes the
304 * concatenation of filespec2 followed by a slash followed by
305 * filespec1.
306 */
0f113f3e
MC
307 int spec2len, len;
308
309 spec2len = strlen(filespec2);
b7573c59 310 len = spec2len + strlen(filespec1);
0f113f3e 311
b7573c59 312 if (spec2len && filespec2[spec2len - 1] == '/') {
0f113f3e
MC
313 spec2len--;
314 len--;
315 }
316 merged = OPENSSL_malloc(len + 2);
90945fa3 317 if (merged == NULL) {
0f113f3e
MC
318 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
319 return (NULL);
320 }
321 strcpy(merged, filespec2);
322 merged[spec2len] = '/';
323 strcpy(&merged[spec2len + 1], filespec1);
324 }
325 return (merged);
326}
4a620922 327
51c8dc37 328static char *dlfcn_name_converter(DSO *dso, const char *filename)
0f113f3e
MC
329{
330 char *translated;
331 int len, rsize, transform;
332
333 len = strlen(filename);
334 rsize = len + 1;
335 transform = (strstr(filename, "/") == NULL);
336 if (transform) {
337 /* We will convert this to "%s.so" or "lib%s.so" etc */
e987f9f2 338 rsize += strlen(DSO_EXTENSION); /* The length of ".so" */
0f113f3e
MC
339 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
340 rsize += 3; /* The length of "lib" */
341 }
342 translated = OPENSSL_malloc(rsize);
343 if (translated == NULL) {
344 DSOerr(DSO_F_DLFCN_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
345 return (NULL);
346 }
347 if (transform) {
348 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
e987f9f2 349 sprintf(translated, "lib%s" DSO_EXTENSION, filename);
0f113f3e 350 else
e987f9f2 351 sprintf(translated, "%s" DSO_EXTENSION, filename);
0f113f3e
MC
352 } else
353 sprintf(translated, "%s", filename);
354 return (translated);
355}
356
357# ifdef __sgi
23a22b4c 358/*-
7ed87653
AP
359This is a quote from IRIX manual for dladdr(3c):
360
361 <dlfcn.h> does not contain a prototype for dladdr or definition of
362 Dl_info. The #include <dlfcn.h> in the SYNOPSIS line is traditional,
363 but contains no dladdr prototype and no IRIX library contains an
364 implementation. Write your own declaration based on the code below.
365
366 The following code is dependent on internal interfaces that are not
367 part of the IRIX compatibility guarantee; however, there is no future
368 intention to change this interface, so on a practical level, the code
369 below is safe to use on IRIX.
c8e1edaa 370*/
0f113f3e
MC
371# include <rld_interface.h>
372# ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
373# define _RLD_INTERFACE_DLFCN_H_DLADDR
7ed87653 374typedef struct Dl_info {
0f113f3e
MC
375 const char *dli_fname;
376 void *dli_fbase;
377 const char *dli_sname;
378 void *dli_saddr;
379 int dli_version;
380 int dli_reserved1;
381 long dli_reserved[4];
7ed87653 382} Dl_info;
0f113f3e 383# else
7ed87653 384typedef struct Dl_info Dl_info;
0f113f3e
MC
385# endif
386# define _RLD_DLADDR 14
7ed87653
AP
387
388static int dladdr(void *address, Dl_info *dl)
389{
0f113f3e
MC
390 void *v;
391 v = _rld_new_interface(_RLD_DLADDR, address, dl);
392 return (int)v;
393}
394# endif /* __sgi */
395
396static int dlfcn_pathbyaddr(void *addr, char *path, int sz)
397{
398# ifdef HAVE_DLINFO
399 Dl_info dli;
400 int len;
401
402 if (addr == NULL) {
403 union {
404 int (*f) (void *, char *, int);
405 void *p;
406 } t = {
407 dlfcn_pathbyaddr
408 };
409 addr = t.p;
410 }
411
412 if (dladdr(addr, &dli)) {
413 len = (int)strlen(dli.dli_fname);
414 if (sz <= 0)
415 return len + 1;
416 if (len >= sz)
417 len = sz - 1;
418 memcpy(path, dli.dli_fname, len);
419 path[len++] = 0;
420 return len;
421 }
422
423 ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
424# endif
425 return -1;
7ed87653 426}
68b64fb6 427
c6cb42e4 428static void *dlfcn_globallookup(const char *name)
0f113f3e
MC
429{
430 void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
431
432 if (handle) {
433 ret = dlsym(handle, name);
434 dlclose(handle);
435 }
436
437 return ret;
438}
439#endif /* DSO_DLFCN */