1 /* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */ 2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL 3 * project 2000. 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 13 * notice, this list of conditions and the following disclaimer. 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 59 #include <stdio.h> 60 #include "cryptlib.h" 61 #include <openssl/dso.h> 62 63 #ifndef DSO_DLFCN 64 DSO_METHOD *DSO_METHOD_dlfcn(void) 65 { 66 return NULL; 67 } 68 #else 69 70 #ifdef HAVE_DLFCN_H 71 #include <dlfcn.h> 72 #endif 73 74 /* Part of the hack in "dlfcn_load" ... */ 75 #define DSO_MAX_TRANSLATED_SIZE 256 76 77 static int dlfcn_load(DSO *dso); 78 static int dlfcn_unload(DSO *dso); 79 static void *dlfcn_bind_var(DSO *dso, const char *symname); 80 static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname); 81 #if 0 82 static int dlfcn_unbind(DSO *dso, char *symname, void *symptr); 83 static int dlfcn_init(DSO *dso); 84 static int dlfcn_finish(DSO *dso); 85 static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg); 86 #endif 87 static char *dlfcn_name_converter(DSO *dso, const char *filename); 88 static char *dlfcn_merger(DSO *dso, const char *filespec1, 89 const char *filespec2); 90 91 static DSO_METHOD dso_meth_dlfcn = { 92 "OpenSSL 'dlfcn' shared library method", 93 dlfcn_load, 94 dlfcn_unload, 95 dlfcn_bind_var, 96 dlfcn_bind_func, 97 /* For now, "unbind" doesn't exist */ 98 #if 0 99 NULL, /* unbind_var */ 100 NULL, /* unbind_func */ 101 #endif 102 NULL, /* ctrl */ 103 dlfcn_name_converter, 104 dlfcn_merger, 105 NULL, /* init */ 106 NULL /* finish */ 107 }; 108 109 DSO_METHOD *DSO_METHOD_dlfcn(void) 110 { 111 return(&dso_meth_dlfcn); 112 } 113 114 /* Prior to using the dlopen() function, we should decide on the flag 115 * we send. There's a few different ways of doing this and it's a 116 * messy venn-diagram to match up which platforms support what. So 117 * as we don't have autoconf yet, I'm implementing a hack that could 118 * be hacked further relatively easily to deal with cases as we find 119 * them. Initially this is to cope with OpenBSD. */ 120 #if defined(__OpenBSD__) || defined(__NetBSD__) 121 # ifdef DL_LAZY 122 # define DLOPEN_FLAG DL_LAZY 123 # else 124 # ifdef RTLD_NOW 125 # define DLOPEN_FLAG RTLD_NOW 126 # else 127 # define DLOPEN_FLAG 0 128 # endif 129 # endif 130 #else 131 # ifdef OPENSSL_SYS_SUNOS 132 # define DLOPEN_FLAG 1 133 # else 134 # define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */ 135 # endif 136 #endif 137 138 /* For this DSO_METHOD, our meth_data STACK will contain; 139 * (i) the handle (void*) returned from dlopen(). 140 */ 141 142 static int dlfcn_load(DSO *dso) 143 { 144 void *ptr = NULL; 145 /* See applicable comments in dso_dl.c */ 146 char *filename = DSO_convert_filename(dso, NULL); 147 int flags = DLOPEN_FLAG; 148 149 if(filename == NULL) 150 { 151 DSOerr(DSO_F_DLFCN_LOAD,DSO_R_NO_FILENAME); 152 goto err; 153 } 154 155 #ifdef RTLD_GLOBAL 156 if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS) 157 flags |= RTLD_GLOBAL; 158 #endif 159 ptr = dlopen(filename, flags); 160 if(ptr == NULL) 161 { 162 DSOerr(DSO_F_DLFCN_LOAD,DSO_R_LOAD_FAILED); 163 ERR_add_error_data(4, "filename(", filename, "): ", dlerror()); 164 goto err; 165 } 166 if(!sk_push(dso->meth_data, (char *)ptr)) 167 { 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 183 static int dlfcn_unload(DSO *dso) 184 { 185 void *ptr; 186 if(dso == NULL) 187 { 188 DSOerr(DSO_F_DLFCN_UNLOAD,ERR_R_PASSED_NULL_PARAMETER); 189 return(0); 190 } 191 if(sk_num(dso->meth_data) < 1) 192 return(1); 193 ptr = (void *)sk_pop(dso->meth_data); 194 if(ptr == NULL) 195 { 196 DSOerr(DSO_F_DLFCN_UNLOAD,DSO_R_NULL_HANDLE); 197 /* Should push the value back onto the stack in 198 * case of a retry. */ 199 sk_push(dso->meth_data, (char *)ptr); 200 return(0); 201 } 202 /* For now I'm not aware of any errors associated with dlclose() */ 203 dlclose(ptr); 204 return(1); 205 } 206 207 static void *dlfcn_bind_var(DSO *dso, const char *symname) 208 { 209 void *ptr, *sym; 210 211 if((dso == NULL) || (symname == NULL)) 212 { 213 DSOerr(DSO_F_DLFCN_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER); 214 return(NULL); 215 } 216 if(sk_num(dso->meth_data) < 1) 217 { 218 DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_STACK_ERROR); 219 return(NULL); 220 } 221 ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 222 if(ptr == NULL) 223 { 224 DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_NULL_HANDLE); 225 return(NULL); 226 } 227 sym = dlsym(ptr, symname); 228 if(sym == NULL) 229 { 230 DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_SYM_FAILURE); 231 ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); 232 return(NULL); 233 } 234 return(sym); 235 } 236 237 static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) 238 { 239 void *ptr; 240 union { 241 DSO_FUNC_TYPE sym; 242 void *dlret; 243 } u; 244 245 if((dso == NULL) || (symname == NULL)) 246 { 247 DSOerr(DSO_F_DLFCN_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER); 248 return(NULL); 249 } 250 if(sk_num(dso->meth_data) < 1) 251 { 252 DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_STACK_ERROR); 253 return(NULL); 254 } 255 ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 256 if(ptr == NULL) 257 { 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 { 264 DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_SYM_FAILURE); 265 ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); 266 return(NULL); 267 } 268 return u.sym; 269 } 270 271 static char *dlfcn_merger(DSO *dso, const char *filespec1, 272 const char *filespec2) 273 { 274 char *merged; 275 276 if(!filespec1 && !filespec2) 277 { 278 DSOerr(DSO_F_DLFCN_MERGER, 279 ERR_R_PASSED_NULL_PARAMETER); 280 return(NULL); 281 } 282 /* If the first file specification is a rooted path, it rules. 283 same goes if the second file specification is missing. */ 284 if (!filespec2 || filespec1[0] == '/') 285 { 286 merged = OPENSSL_malloc(strlen(filespec1) + 1); 287 if(!merged) 288 { 289 DSOerr(DSO_F_DLFCN_MERGER, 290 ERR_R_MALLOC_FAILURE); 291 return(NULL); 292 } 293 strcpy(merged, filespec1); 294 } 295 /* If the first file specification is missing, the second one rules. */ 296 else if (!filespec1) 297 { 298 merged = OPENSSL_malloc(strlen(filespec2) + 1); 299 if(!merged) 300 { 301 DSOerr(DSO_F_DLFCN_MERGER, 302 ERR_R_MALLOC_FAILURE); 303 return(NULL); 304 } 305 strcpy(merged, filespec2); 306 } 307 else 308 /* This part isn't as trivial as it looks. It assumes that 309 the second file specification really is a directory, and 310 makes no checks whatsoever. Therefore, the result becomes 311 the concatenation of filespec2 followed by a slash followed 312 by filespec1. */ 313 { 314 int spec2len, len; 315 316 spec2len = (filespec2 ? strlen(filespec2) : 0); 317 len = spec2len + (filespec1 ? strlen(filespec1) : 0); 318 319 if(filespec2 && filespec2[spec2len - 1] == '/') 320 { 321 spec2len--; 322 len--; 323 } 324 merged = OPENSSL_malloc(len + 2); 325 if(!merged) 326 { 327 DSOerr(DSO_F_DLFCN_MERGER, 328 ERR_R_MALLOC_FAILURE); 329 return(NULL); 330 } 331 strcpy(merged, filespec2); 332 merged[spec2len] = '/'; 333 strcpy(&merged[spec2len + 1], filespec1); 334 } 335 return(merged); 336 } 337 338 #ifdef OPENSSL_SYS_MACOSX 339 #define DSO_ext ".dylib" 340 #define DSO_extlen 6 341 #else 342 #define DSO_ext ".so" 343 #define DSO_extlen 3 344 #endif 345 346 347 static char *dlfcn_name_converter(DSO *dso, const char *filename) 348 { 349 char *translated; 350 int len, rsize, transform; 351 352 len = strlen(filename); 353 rsize = len + 1; 354 transform = (strstr(filename, "/") == NULL); 355 if(transform) 356 { 357 /* We will convert this to "%s.so" or "lib%s.so" etc */ 358 rsize += DSO_extlen; /* The length of ".so" */ 359 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 360 rsize += 3; /* The length of "lib" */ 361 } 362 translated = OPENSSL_malloc(rsize); 363 if(translated == NULL) 364 { 365 DSOerr(DSO_F_DLFCN_NAME_CONVERTER, 366 DSO_R_NAME_TRANSLATION_FAILED); 367 return(NULL); 368 } 369 if(transform) 370 { 371 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 372 sprintf(translated, "lib%s" DSO_ext, filename); 373 else 374 sprintf(translated, "%s" DSO_ext, filename); 375 } 376 else 377 sprintf(translated, "%s", filename); 378 return(translated); 379 } 380 381 #endif /* DSO_DLFCN */ 382