]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/dso/dso_dlfcn.c
Remove /* foo.c */ comments
[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
GT
70#include <openssl/dso.h>
71
72#ifndef DSO_DLFCN
73DSO_METHOD *DSO_METHOD_dlfcn(void)
0f113f3e
MC
74{
75 return NULL;
76}
8f4fac7f
GT
77#else
78
0f113f3e
MC
79# ifdef HAVE_DLFCN_H
80# ifdef __osf__
81# define __EXTENSIONS__
82# endif
83# include <dlfcn.h>
84# define HAVE_DLINFO 1
85# if defined(_AIX) || defined(__CYGWIN__) || \
73133962 86 defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
afb41913 87 (defined(__osf__) && !defined(RTLD_NEXT)) || \
7a4ec19a 88 (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
0f113f3e
MC
89 defined(__ANDROID__)
90# undef HAVE_DLINFO
91# endif
73133962 92# endif
8f4fac7f 93
b9e63915 94/* Part of the hack in "dlfcn_load" ... */
0f113f3e 95# define DSO_MAX_TRANSLATED_SIZE 256
b9e63915 96
51c8dc37 97static int dlfcn_load(DSO *dso);
8f4fac7f 98static int dlfcn_unload(DSO *dso);
e9a68cfb
GT
99static void *dlfcn_bind_var(DSO *dso, const char *symname);
100static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
51c8dc37 101static char *dlfcn_name_converter(DSO *dso, const char *filename);
cbecb3ac 102static char *dlfcn_merger(DSO *dso, const char *filespec1,
0f113f3e
MC
103 const char *filespec2);
104static int dlfcn_pathbyaddr(void *addr, char *path, int sz);
c6cb42e4 105static void *dlfcn_globallookup(const char *name);
8f4fac7f
GT
106
107static DSO_METHOD dso_meth_dlfcn = {
0f113f3e
MC
108 "OpenSSL 'dlfcn' shared library method",
109 dlfcn_load,
110 dlfcn_unload,
111 dlfcn_bind_var,
112 dlfcn_bind_func,
0f113f3e
MC
113 NULL, /* ctrl */
114 dlfcn_name_converter,
115 dlfcn_merger,
116 NULL, /* init */
117 NULL, /* finish */
118 dlfcn_pathbyaddr,
119 dlfcn_globallookup
120};
8f4fac7f
GT
121
122DSO_METHOD *DSO_METHOD_dlfcn(void)
0f113f3e
MC
123{
124 return (&dso_meth_dlfcn);
125}
126
127/*
128 * Prior to using the dlopen() function, we should decide on the flag we
129 * send. There's a few different ways of doing this and it's a messy
130 * venn-diagram to match up which platforms support what. So as we don't have
131 * autoconf yet, I'm implementing a hack that could be hacked further
132 * relatively easily to deal with cases as we find them. Initially this is to
133 * cope with OpenBSD.
134 */
135# if defined(__OpenBSD__) || defined(__NetBSD__)
136# ifdef DL_LAZY
137# define DLOPEN_FLAG DL_LAZY
138# else
139# ifdef RTLD_NOW
140# define DLOPEN_FLAG RTLD_NOW
141# else
142# define DLOPEN_FLAG 0
143# endif
144# endif
145# else
146# define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */
147# endif
1a797ac6 148
0f113f3e
MC
149/*
150 * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
151 * (void*) returned from dlopen().
8f4fac7f
GT
152 */
153
51c8dc37 154static int dlfcn_load(DSO *dso)
0f113f3e
MC
155{
156 void *ptr = NULL;
157 /* See applicable comments in dso_dl.c */
158 char *filename = DSO_convert_filename(dso, NULL);
159 int flags = DLOPEN_FLAG;
160
161 if (filename == NULL) {
162 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_NO_FILENAME);
163 goto err;
164 }
165# ifdef RTLD_GLOBAL
166 if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
167 flags |= RTLD_GLOBAL;
168# endif
169 ptr = dlopen(filename, flags);
170 if (ptr == NULL) {
171 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_LOAD_FAILED);
172 ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
173 goto err;
174 }
175 if (!sk_void_push(dso->meth_data, (char *)ptr)) {
176 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_STACK_ERROR);
177 goto err;
178 }
179 /* Success */
180 dso->loaded_filename = filename;
181 return (1);
182 err:
183 /* Cleanup! */
b548a1f1 184 OPENSSL_free(filename);
0f113f3e
MC
185 if (ptr != NULL)
186 dlclose(ptr);
187 return (0);
51c8dc37 188}
8f4fac7f
GT
189
190static int dlfcn_unload(DSO *dso)
0f113f3e
MC
191{
192 void *ptr;
193 if (dso == NULL) {
194 DSOerr(DSO_F_DLFCN_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
195 return (0);
196 }
197 if (sk_void_num(dso->meth_data) < 1)
198 return (1);
199 ptr = sk_void_pop(dso->meth_data);
200 if (ptr == NULL) {
201 DSOerr(DSO_F_DLFCN_UNLOAD, DSO_R_NULL_HANDLE);
202 /*
203 * Should push the value back onto the stack in case of a retry.
204 */
205 sk_void_push(dso->meth_data, ptr);
206 return (0);
207 }
208 /* For now I'm not aware of any errors associated with dlclose() */
209 dlclose(ptr);
210 return (1);
211}
8f4fac7f 212
e9a68cfb 213static void *dlfcn_bind_var(DSO *dso, const char *symname)
0f113f3e
MC
214{
215 void *ptr, *sym;
216
217 if ((dso == NULL) || (symname == NULL)) {
218 DSOerr(DSO_F_DLFCN_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
219 return (NULL);
220 }
221 if (sk_void_num(dso->meth_data) < 1) {
222 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_STACK_ERROR);
223 return (NULL);
224 }
225 ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
226 if (ptr == NULL) {
227 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_NULL_HANDLE);
228 return (NULL);
229 }
230 sym = dlsym(ptr, symname);
231 if (sym == NULL) {
232 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_SYM_FAILURE);
233 ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
234 return (NULL);
235 }
236 return (sym);
237}
e9a68cfb
GT
238
239static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
0f113f3e
MC
240{
241 void *ptr;
242 union {
243 DSO_FUNC_TYPE sym;
244 void *dlret;
245 } u;
246
247 if ((dso == NULL) || (symname == NULL)) {
248 DSOerr(DSO_F_DLFCN_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
249 return (NULL);
250 }
251 if (sk_void_num(dso->meth_data) < 1) {
252 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_STACK_ERROR);
253 return (NULL);
254 }
255 ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
256 if (ptr == NULL) {
257 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_NULL_HANDLE);
258 return (NULL);
259 }
260 u.dlret = dlsym(ptr, symname);
261 if (u.dlret == NULL) {
262 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_SYM_FAILURE);
263 ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
264 return (NULL);
265 }
266 return u.sym;
267}
8f4fac7f 268
cbecb3ac 269static char *dlfcn_merger(DSO *dso, const char *filespec1,
0f113f3e
MC
270 const char *filespec2)
271{
272 char *merged;
273
274 if (!filespec1 && !filespec2) {
275 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_PASSED_NULL_PARAMETER);
276 return (NULL);
277 }
278 /*
279 * If the first file specification is a rooted path, it rules. same goes
280 * if the second file specification is missing.
281 */
282 if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) {
283 merged = OPENSSL_malloc(strlen(filespec1) + 1);
90945fa3 284 if (merged == NULL) {
0f113f3e
MC
285 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
286 return (NULL);
287 }
288 strcpy(merged, filespec1);
289 }
290 /*
291 * If the first file specification is missing, the second one rules.
292 */
293 else if (!filespec1) {
294 merged = OPENSSL_malloc(strlen(filespec2) + 1);
90945fa3 295 if (merged == NULL) {
0f113f3e
MC
296 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
297 return (NULL);
298 }
299 strcpy(merged, filespec2);
b7573c59 300 } else {
0f113f3e
MC
301 /*
302 * This part isn't as trivial as it looks. It assumes that the
303 * second file specification really is a directory, and makes no
304 * checks whatsoever. Therefore, the result becomes the
305 * concatenation of filespec2 followed by a slash followed by
306 * filespec1.
307 */
0f113f3e
MC
308 int spec2len, len;
309
310 spec2len = strlen(filespec2);
b7573c59 311 len = spec2len + strlen(filespec1);
0f113f3e 312
b7573c59 313 if (spec2len && filespec2[spec2len - 1] == '/') {
0f113f3e
MC
314 spec2len--;
315 len--;
316 }
317 merged = OPENSSL_malloc(len + 2);
90945fa3 318 if (merged == NULL) {
0f113f3e
MC
319 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
320 return (NULL);
321 }
322 strcpy(merged, filespec2);
323 merged[spec2len] = '/';
324 strcpy(&merged[spec2len + 1], filespec1);
325 }
326 return (merged);
327}
4a620922 328
0f113f3e
MC
329# ifdef OPENSSL_SYS_MACOSX
330# define DSO_ext ".dylib"
331# define DSO_extlen 6
332# else
333# define DSO_ext ".so"
334# define DSO_extlen 3
335# endif
4a620922 336
51c8dc37 337static char *dlfcn_name_converter(DSO *dso, const char *filename)
0f113f3e
MC
338{
339 char *translated;
340 int len, rsize, transform;
341
342 len = strlen(filename);
343 rsize = len + 1;
344 transform = (strstr(filename, "/") == NULL);
345 if (transform) {
346 /* We will convert this to "%s.so" or "lib%s.so" etc */
347 rsize += DSO_extlen; /* The length of ".so" */
348 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
349 rsize += 3; /* The length of "lib" */
350 }
351 translated = OPENSSL_malloc(rsize);
352 if (translated == NULL) {
353 DSOerr(DSO_F_DLFCN_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
354 return (NULL);
355 }
356 if (transform) {
357 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
358 sprintf(translated, "lib%s" DSO_ext, filename);
359 else
360 sprintf(translated, "%s" DSO_ext, filename);
361 } else
362 sprintf(translated, "%s", filename);
363 return (translated);
364}
365
366# ifdef __sgi
23a22b4c 367/*-
7ed87653
AP
368This is a quote from IRIX manual for dladdr(3c):
369
370 <dlfcn.h> does not contain a prototype for dladdr or definition of
371 Dl_info. The #include <dlfcn.h> in the SYNOPSIS line is traditional,
372 but contains no dladdr prototype and no IRIX library contains an
373 implementation. Write your own declaration based on the code below.
374
375 The following code is dependent on internal interfaces that are not
376 part of the IRIX compatibility guarantee; however, there is no future
377 intention to change this interface, so on a practical level, the code
378 below is safe to use on IRIX.
c8e1edaa 379*/
0f113f3e
MC
380# include <rld_interface.h>
381# ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
382# define _RLD_INTERFACE_DLFCN_H_DLADDR
7ed87653 383typedef struct Dl_info {
0f113f3e
MC
384 const char *dli_fname;
385 void *dli_fbase;
386 const char *dli_sname;
387 void *dli_saddr;
388 int dli_version;
389 int dli_reserved1;
390 long dli_reserved[4];
7ed87653 391} Dl_info;
0f113f3e 392# else
7ed87653 393typedef struct Dl_info Dl_info;
0f113f3e
MC
394# endif
395# define _RLD_DLADDR 14
7ed87653
AP
396
397static int dladdr(void *address, Dl_info *dl)
398{
0f113f3e
MC
399 void *v;
400 v = _rld_new_interface(_RLD_DLADDR, address, dl);
401 return (int)v;
402}
403# endif /* __sgi */
404
405static int dlfcn_pathbyaddr(void *addr, char *path, int sz)
406{
407# ifdef HAVE_DLINFO
408 Dl_info dli;
409 int len;
410
411 if (addr == NULL) {
412 union {
413 int (*f) (void *, char *, int);
414 void *p;
415 } t = {
416 dlfcn_pathbyaddr
417 };
418 addr = t.p;
419 }
420
421 if (dladdr(addr, &dli)) {
422 len = (int)strlen(dli.dli_fname);
423 if (sz <= 0)
424 return len + 1;
425 if (len >= sz)
426 len = sz - 1;
427 memcpy(path, dli.dli_fname, len);
428 path[len++] = 0;
429 return len;
430 }
431
432 ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
433# endif
434 return -1;
7ed87653 435}
68b64fb6 436
c6cb42e4 437static void *dlfcn_globallookup(const char *name)
0f113f3e
MC
438{
439 void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
440
441 if (handle) {
442 ret = dlsym(handle, name);
443 dlclose(handle);
444 }
445
446 return ret;
447}
448#endif /* DSO_DLFCN */