dso_dlfcn.c revision 296465
1145171Sdas/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */ 2145171Sdas/* 3145171Sdas * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project 4145171Sdas * 2000. 5145171Sdas */ 6145171Sdas/* ==================================================================== 7145171Sdas * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 8145171Sdas * 9145171Sdas * Redistribution and use in source and binary forms, with or without 10145171Sdas * modification, are permitted provided that the following conditions 11145171Sdas * are met: 12145171Sdas * 13145171Sdas * 1. Redistributions of source code must retain the above copyright 14145171Sdas * notice, this list of conditions and the following disclaimer. 15145171Sdas * 16145171Sdas * 2. Redistributions in binary form must reproduce the above copyright 17145171Sdas * notice, this list of conditions and the following disclaimer in 18145171Sdas * the documentation and/or other materials provided with the 19145171Sdas * distribution. 20145171Sdas * 21145171Sdas * 3. All advertising materials mentioning features or use of this 22145171Sdas * software must display the following acknowledgment: 23145171Sdas * "This product includes software developed by the OpenSSL Project 24145171Sdas * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25145171Sdas * 26145171Sdas * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27192760Sattilio * endorse or promote products derived from this software without 28217108Skib * prior written permission. For written permission, please contact 29217108Skib * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This product includes cryptographic software written by Eric Young 55 * (eay@cryptsoft.com). This product includes software written by Tim 56 * Hudson (tjh@cryptsoft.com). 57 * 58 */ 59 60#include <stdio.h> 61#include "cryptlib.h" 62#include <openssl/dso.h> 63 64#ifndef DSO_DLFCN 65DSO_METHOD *DSO_METHOD_dlfcn(void) 66{ 67 return NULL; 68} 69#else 70 71# ifdef HAVE_DLFCN_H 72# include <dlfcn.h> 73# endif 74 75/* Part of the hack in "dlfcn_load" ... */ 76# define DSO_MAX_TRANSLATED_SIZE 256 77 78static int dlfcn_load(DSO *dso); 79static int dlfcn_unload(DSO *dso); 80static void *dlfcn_bind_var(DSO *dso, const char *symname); 81static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname); 82# if 0 83static int dlfcn_unbind(DSO *dso, char *symname, void *symptr); 84static int dlfcn_init(DSO *dso); 85static int dlfcn_finish(DSO *dso); 86static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg); 87# endif 88static char *dlfcn_name_converter(DSO *dso, const char *filename); 89static char *dlfcn_merger(DSO *dso, const char *filespec1, 90 const char *filespec2); 91 92static DSO_METHOD dso_meth_dlfcn = { 93 "OpenSSL 'dlfcn' shared library method", 94 dlfcn_load, 95 dlfcn_unload, 96 dlfcn_bind_var, 97 dlfcn_bind_func, 98/* For now, "unbind" doesn't exist */ 99# if 0 100 NULL, /* unbind_var */ 101 NULL, /* unbind_func */ 102# endif 103 NULL, /* ctrl */ 104 dlfcn_name_converter, 105 dlfcn_merger, 106 NULL, /* init */ 107 NULL /* finish */ 108}; 109 110DSO_METHOD *DSO_METHOD_dlfcn(void) 111{ 112 return (&dso_meth_dlfcn); 113} 114 115/* 116 * Prior to using the dlopen() function, we should decide on the flag we 117 * send. There's a few different ways of doing this and it's a messy 118 * venn-diagram to match up which platforms support what. So as we don't have 119 * autoconf yet, I'm implementing a hack that could be hacked further 120 * relatively easily to deal with cases as we find them. Initially this is to 121 * cope with OpenBSD. 122 */ 123# if defined(__OpenBSD__) || defined(__NetBSD__) 124# ifdef DL_LAZY 125# define DLOPEN_FLAG DL_LAZY 126# else 127# ifdef RTLD_NOW 128# define DLOPEN_FLAG RTLD_NOW 129# else 130# define DLOPEN_FLAG 0 131# endif 132# endif 133# else 134# ifdef OPENSSL_SYS_SUNOS 135# define DLOPEN_FLAG 1 136# else 137# define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */ 138# endif 139# endif 140 141/* 142 * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle 143 * (void*) returned from dlopen(). 144 */ 145 146static int dlfcn_load(DSO *dso) 147{ 148 void *ptr = NULL; 149 /* See applicable comments in dso_dl.c */ 150 char *filename = DSO_convert_filename(dso, NULL); 151 int flags = DLOPEN_FLAG; 152 153 if (filename == NULL) { 154 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_NO_FILENAME); 155 goto err; 156 } 157# ifdef RTLD_GLOBAL 158 if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS) 159 flags |= RTLD_GLOBAL; 160# endif 161 ptr = dlopen(filename, flags); 162 if (ptr == NULL) { 163 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_LOAD_FAILED); 164 ERR_add_error_data(4, "filename(", filename, "): ", dlerror()); 165 goto err; 166 } 167 if (!sk_push(dso->meth_data, (char *)ptr)) { 168 DSOerr(DSO_F_DLFCN_LOAD, DSO_R_STACK_ERROR); 169 goto err; 170 } 171 /* Success */ 172 dso->loaded_filename = filename; 173 return (1); 174 err: 175 /* Cleanup! */ 176 if (filename != NULL) 177 OPENSSL_free(filename); 178 if (ptr != NULL) 179 dlclose(ptr); 180 return (0); 181} 182 183static int dlfcn_unload(DSO *dso) 184{ 185 void *ptr; 186 if (dso == NULL) { 187 DSOerr(DSO_F_DLFCN_UNLOAD, ERR_R_PASSED_NULL_PARAMETER); 188 return (0); 189 } 190 if (sk_num(dso->meth_data) < 1) 191 return (1); 192 ptr = (void *)sk_pop(dso->meth_data); 193 if (ptr == NULL) { 194 DSOerr(DSO_F_DLFCN_UNLOAD, DSO_R_NULL_HANDLE); 195 /* 196 * Should push the value back onto the stack in case of a retry. 197 */ 198 sk_push(dso->meth_data, (char *)ptr); 199 return (0); 200 } 201 /* For now I'm not aware of any errors associated with dlclose() */ 202 dlclose(ptr); 203 return (1); 204} 205 206static void *dlfcn_bind_var(DSO *dso, const char *symname) 207{ 208 void *ptr, *sym; 209 210 if ((dso == NULL) || (symname == NULL)) { 211 DSOerr(DSO_F_DLFCN_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER); 212 return (NULL); 213 } 214 if (sk_num(dso->meth_data) < 1) { 215 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_STACK_ERROR); 216 return (NULL); 217 } 218 ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 219 if (ptr == NULL) { 220 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_NULL_HANDLE); 221 return (NULL); 222 } 223 sym = dlsym(ptr, symname); 224 if (sym == NULL) { 225 DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_SYM_FAILURE); 226 ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); 227 return (NULL); 228 } 229 return (sym); 230} 231 232static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) 233{ 234 void *ptr; 235 union { 236 DSO_FUNC_TYPE sym; 237 void *dlret; 238 } u; 239 240 if ((dso == NULL) || (symname == NULL)) { 241 DSOerr(DSO_F_DLFCN_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER); 242 return (NULL); 243 } 244 if (sk_num(dso->meth_data) < 1) { 245 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_STACK_ERROR); 246 return (NULL); 247 } 248 ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 249 if (ptr == NULL) { 250 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_NULL_HANDLE); 251 return (NULL); 252 } 253 u.dlret = dlsym(ptr, symname); 254 if (u.dlret == NULL) { 255 DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_SYM_FAILURE); 256 ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); 257 return (NULL); 258 } 259 return u.sym; 260} 261 262static char *dlfcn_merger(DSO *dso, const char *filespec1, 263 const char *filespec2) 264{ 265 char *merged; 266 267 if (!filespec1 && !filespec2) { 268 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_PASSED_NULL_PARAMETER); 269 return (NULL); 270 } 271 /* 272 * If the first file specification is a rooted path, it rules. same goes 273 * if the second file specification is missing. 274 */ 275 if (!filespec2 || filespec1[0] == '/') { 276 merged = OPENSSL_malloc(strlen(filespec1) + 1); 277 if (!merged) { 278 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE); 279 return (NULL); 280 } 281 strcpy(merged, filespec1); 282 } 283 /* 284 * If the first file specification is missing, the second one rules. 285 */ 286 else if (!filespec1) { 287 merged = OPENSSL_malloc(strlen(filespec2) + 1); 288 if (!merged) { 289 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE); 290 return (NULL); 291 } 292 strcpy(merged, filespec2); 293 } else 294 /* 295 * This part isn't as trivial as it looks. It assumes that the 296 * second file specification really is a directory, and makes no 297 * checks whatsoever. Therefore, the result becomes the 298 * concatenation of filespec2 followed by a slash followed by 299 * filespec1. 300 */ 301 { 302 int spec2len, len; 303 304 spec2len = (filespec2 ? strlen(filespec2) : 0); 305 len = spec2len + (filespec1 ? strlen(filespec1) : 0); 306 307 if (filespec2 && filespec2[spec2len - 1] == '/') { 308 spec2len--; 309 len--; 310 } 311 merged = OPENSSL_malloc(len + 2); 312 if (!merged) { 313 DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE); 314 return (NULL); 315 } 316 strcpy(merged, filespec2); 317 merged[spec2len] = '/'; 318 strcpy(&merged[spec2len + 1], filespec1); 319 } 320 return (merged); 321} 322 323# ifdef OPENSSL_SYS_MACOSX 324# define DSO_ext ".dylib" 325# define DSO_extlen 6 326# else 327# define DSO_ext ".so" 328# define DSO_extlen 3 329# endif 330 331static char *dlfcn_name_converter(DSO *dso, const char *filename) 332{ 333 char *translated; 334 int len, rsize, transform; 335 336 len = strlen(filename); 337 rsize = len + 1; 338 transform = (strstr(filename, "/") == NULL); 339 if (transform) { 340 /* We will convert this to "%s.so" or "lib%s.so" etc */ 341 rsize += DSO_extlen; /* The length of ".so" */ 342 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 343 rsize += 3; /* The length of "lib" */ 344 } 345 translated = OPENSSL_malloc(rsize); 346 if (translated == NULL) { 347 DSOerr(DSO_F_DLFCN_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED); 348 return (NULL); 349 } 350 if (transform) { 351 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 352 sprintf(translated, "lib%s" DSO_ext, filename); 353 else 354 sprintf(translated, "%s" DSO_ext, filename); 355 } else 356 sprintf(translated, "%s", filename); 357 return (translated); 358} 359 360#endif /* DSO_DLFCN */ 361