1295016Sjkim/* dso_dl.c */ 2280304Sjkim/* 3280304Sjkim * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project 4280304Sjkim * 2000. 568651Skris */ 668651Skris/* ==================================================================== 768651Skris * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 868651Skris * 968651Skris * Redistribution and use in source and binary forms, with or without 1068651Skris * modification, are permitted provided that the following conditions 1168651Skris * are met: 1268651Skris * 1368651Skris * 1. Redistributions of source code must retain the above copyright 14280304Sjkim * notice, this list of conditions and the following disclaimer. 1568651Skris * 1668651Skris * 2. Redistributions in binary form must reproduce the above copyright 1768651Skris * notice, this list of conditions and the following disclaimer in 1868651Skris * the documentation and/or other materials provided with the 1968651Skris * distribution. 2068651Skris * 2168651Skris * 3. All advertising materials mentioning features or use of this 2268651Skris * software must display the following acknowledgment: 2368651Skris * "This product includes software developed by the OpenSSL Project 2468651Skris * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2568651Skris * 2668651Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2768651Skris * endorse or promote products derived from this software without 2868651Skris * prior written permission. For written permission, please contact 2968651Skris * licensing@OpenSSL.org. 3068651Skris * 3168651Skris * 5. Products derived from this software may not be called "OpenSSL" 3268651Skris * nor may "OpenSSL" appear in their names without prior written 3368651Skris * permission of the OpenSSL Project. 3468651Skris * 3568651Skris * 6. Redistributions of any form whatsoever must retain the following 3668651Skris * acknowledgment: 3768651Skris * "This product includes software developed by the OpenSSL Project 3868651Skris * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3968651Skris * 4068651Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4168651Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4268651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4368651Skris * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4468651Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4568651Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4668651Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4768651Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4968651Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5068651Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5168651Skris * OF THE POSSIBILITY OF SUCH DAMAGE. 5268651Skris * ==================================================================== 5368651Skris * 5468651Skris * This product includes cryptographic software written by Eric Young 5568651Skris * (eay@cryptsoft.com). This product includes software written by Tim 5668651Skris * Hudson (tjh@cryptsoft.com). 5768651Skris * 5868651Skris */ 5968651Skris 6068651Skris#include <stdio.h> 6168651Skris#include "cryptlib.h" 6268651Skris#include <openssl/dso.h> 6368651Skris 6468651Skris#ifndef DSO_DL 6568651SkrisDSO_METHOD *DSO_METHOD_dl(void) 66280304Sjkim{ 67280304Sjkim return NULL; 68280304Sjkim} 6968651Skris#else 7068651Skris 71280304Sjkim# include <dl.h> 7268651Skris 7368651Skris/* Part of the hack in "dl_load" ... */ 74280304Sjkim# define DSO_MAX_TRANSLATED_SIZE 256 7568651Skris 76109998Smarkmstatic int dl_load(DSO *dso); 7768651Skrisstatic int dl_unload(DSO *dso); 7868651Skrisstatic void *dl_bind_var(DSO *dso, const char *symname); 7968651Skrisstatic DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname); 80280304Sjkim# if 0 8168651Skrisstatic int dl_unbind_var(DSO *dso, char *symname, void *symptr); 8268651Skrisstatic int dl_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr); 8368651Skrisstatic int dl_init(DSO *dso); 8468651Skrisstatic int dl_finish(DSO *dso); 85109998Smarkmstatic int dl_ctrl(DSO *dso, int cmd, long larg, void *parg); 86280304Sjkim# endif 87109998Smarkmstatic char *dl_name_converter(DSO *dso, const char *filename); 88280304Sjkimstatic char *dl_merger(DSO *dso, const char *filespec1, 89280304Sjkim const char *filespec2); 90280304Sjkimstatic int dl_pathbyaddr(void *addr, char *path, int sz); 91238405Sjkimstatic void *dl_globallookup(const char *name); 9268651Skris 9368651Skrisstatic DSO_METHOD dso_meth_dl = { 94280304Sjkim "OpenSSL 'dl' shared library method", 95280304Sjkim dl_load, 96280304Sjkim dl_unload, 97280304Sjkim dl_bind_var, 98280304Sjkim dl_bind_func, 9968651Skris/* For now, "unbind" doesn't exist */ 100280304Sjkim# if 0 101280304Sjkim NULL, /* unbind_var */ 102280304Sjkim NULL, /* unbind_func */ 103280304Sjkim# endif 104280304Sjkim NULL, /* ctrl */ 105280304Sjkim dl_name_converter, 106280304Sjkim dl_merger, 107280304Sjkim NULL, /* init */ 108280304Sjkim NULL, /* finish */ 109280304Sjkim dl_pathbyaddr, 110280304Sjkim dl_globallookup 111280304Sjkim}; 11268651Skris 11368651SkrisDSO_METHOD *DSO_METHOD_dl(void) 114280304Sjkim{ 115280304Sjkim return (&dso_meth_dl); 116280304Sjkim} 11768651Skris 118280304Sjkim/* 119280304Sjkim * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle 120280304Sjkim * (shl_t) returned from shl_load(). NB: I checked on HPUX11 and shl_t is 121280304Sjkim * itself a pointer type so the cast is safe. 12268651Skris */ 12368651Skris 124109998Smarkmstatic int dl_load(DSO *dso) 125280304Sjkim{ 126280304Sjkim shl_t ptr = NULL; 127280304Sjkim /* 128280304Sjkim * We don't do any fancy retries or anything, just take the method's (or 129280304Sjkim * DSO's if it has the callback set) best translation of the 130280304Sjkim * platform-independant filename and try once with that. 131280304Sjkim */ 132280304Sjkim char *filename = DSO_convert_filename(dso, NULL); 13368651Skris 134280304Sjkim if (filename == NULL) { 135280304Sjkim DSOerr(DSO_F_DL_LOAD, DSO_R_NO_FILENAME); 136280304Sjkim goto err; 137280304Sjkim } 138280304Sjkim ptr = shl_load(filename, BIND_IMMEDIATE | 139280304Sjkim (dso->flags & DSO_FLAG_NO_NAME_TRANSLATION ? 0 : 140280304Sjkim DYNAMIC_PATH), 0L); 141280304Sjkim if (ptr == NULL) { 142280304Sjkim DSOerr(DSO_F_DL_LOAD, DSO_R_LOAD_FAILED); 143280304Sjkim ERR_add_error_data(4, "filename(", filename, "): ", strerror(errno)); 144280304Sjkim goto err; 145280304Sjkim } 146280304Sjkim if (!sk_push(dso->meth_data, (char *)ptr)) { 147280304Sjkim DSOerr(DSO_F_DL_LOAD, DSO_R_STACK_ERROR); 148280304Sjkim goto err; 149280304Sjkim } 150280304Sjkim /* 151280304Sjkim * Success, stick the converted filename we've loaded under into the DSO 152280304Sjkim * (it also serves as the indicator that we are currently loaded). 153280304Sjkim */ 154280304Sjkim dso->loaded_filename = filename; 155280304Sjkim return (1); 156280304Sjkim err: 157280304Sjkim /* Cleanup! */ 158280304Sjkim if (filename != NULL) 159280304Sjkim OPENSSL_free(filename); 160280304Sjkim if (ptr != NULL) 161280304Sjkim shl_unload(ptr); 162280304Sjkim return (0); 163280304Sjkim} 16468651Skris 16568651Skrisstatic int dl_unload(DSO *dso) 166280304Sjkim{ 167280304Sjkim shl_t ptr; 168280304Sjkim if (dso == NULL) { 169280304Sjkim DSOerr(DSO_F_DL_UNLOAD, ERR_R_PASSED_NULL_PARAMETER); 170280304Sjkim return (0); 171280304Sjkim } 172280304Sjkim if (sk_num(dso->meth_data) < 1) 173280304Sjkim return (1); 174280304Sjkim /* Is this statement legal? */ 175280304Sjkim ptr = (shl_t) sk_pop(dso->meth_data); 176280304Sjkim if (ptr == NULL) { 177280304Sjkim DSOerr(DSO_F_DL_UNLOAD, DSO_R_NULL_HANDLE); 178280304Sjkim /* 179280304Sjkim * Should push the value back onto the stack in case of a retry. 180280304Sjkim */ 181280304Sjkim sk_push(dso->meth_data, (char *)ptr); 182280304Sjkim return (0); 183280304Sjkim } 184280304Sjkim shl_unload(ptr); 185280304Sjkim return (1); 186280304Sjkim} 18768651Skris 18868651Skrisstatic void *dl_bind_var(DSO *dso, const char *symname) 189280304Sjkim{ 190280304Sjkim shl_t ptr; 191280304Sjkim void *sym; 19268651Skris 193280304Sjkim if ((dso == NULL) || (symname == NULL)) { 194280304Sjkim DSOerr(DSO_F_DL_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER); 195280304Sjkim return (NULL); 196280304Sjkim } 197280304Sjkim if (sk_num(dso->meth_data) < 1) { 198280304Sjkim DSOerr(DSO_F_DL_BIND_VAR, DSO_R_STACK_ERROR); 199280304Sjkim return (NULL); 200280304Sjkim } 201280304Sjkim ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 202280304Sjkim if (ptr == NULL) { 203280304Sjkim DSOerr(DSO_F_DL_BIND_VAR, DSO_R_NULL_HANDLE); 204280304Sjkim return (NULL); 205280304Sjkim } 206280304Sjkim if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) { 207280304Sjkim DSOerr(DSO_F_DL_BIND_VAR, DSO_R_SYM_FAILURE); 208280304Sjkim ERR_add_error_data(4, "symname(", symname, "): ", strerror(errno)); 209280304Sjkim return (NULL); 210280304Sjkim } 211280304Sjkim return (sym); 212280304Sjkim} 21368651Skris 21468651Skrisstatic DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname) 215280304Sjkim{ 216280304Sjkim shl_t ptr; 217280304Sjkim void *sym; 21868651Skris 219280304Sjkim if ((dso == NULL) || (symname == NULL)) { 220280304Sjkim DSOerr(DSO_F_DL_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER); 221280304Sjkim return (NULL); 222280304Sjkim } 223280304Sjkim if (sk_num(dso->meth_data) < 1) { 224280304Sjkim DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_STACK_ERROR); 225280304Sjkim return (NULL); 226280304Sjkim } 227280304Sjkim ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 228280304Sjkim if (ptr == NULL) { 229280304Sjkim DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_NULL_HANDLE); 230280304Sjkim return (NULL); 231280304Sjkim } 232280304Sjkim if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) { 233280304Sjkim DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_SYM_FAILURE); 234280304Sjkim ERR_add_error_data(4, "symname(", symname, "): ", strerror(errno)); 235280304Sjkim return (NULL); 236280304Sjkim } 237280304Sjkim return ((DSO_FUNC_TYPE)sym); 238280304Sjkim} 23968651Skris 240160814Ssimonstatic char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2) 241280304Sjkim{ 242280304Sjkim char *merged; 243160814Ssimon 244280304Sjkim if (!filespec1 && !filespec2) { 245280304Sjkim DSOerr(DSO_F_DL_MERGER, ERR_R_PASSED_NULL_PARAMETER); 246280304Sjkim return (NULL); 247280304Sjkim } 248280304Sjkim /* 249280304Sjkim * If the first file specification is a rooted path, it rules. same goes 250280304Sjkim * if the second file specification is missing. 251280304Sjkim */ 252280304Sjkim if (!filespec2 || filespec1[0] == '/') { 253280304Sjkim merged = OPENSSL_malloc(strlen(filespec1) + 1); 254280304Sjkim if (!merged) { 255280304Sjkim DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE); 256280304Sjkim return (NULL); 257280304Sjkim } 258280304Sjkim strcpy(merged, filespec1); 259280304Sjkim } 260280304Sjkim /* 261280304Sjkim * If the first file specification is missing, the second one rules. 262280304Sjkim */ 263280304Sjkim else if (!filespec1) { 264280304Sjkim merged = OPENSSL_malloc(strlen(filespec2) + 1); 265280304Sjkim if (!merged) { 266280304Sjkim DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE); 267280304Sjkim return (NULL); 268280304Sjkim } 269280304Sjkim strcpy(merged, filespec2); 270280304Sjkim } else 271280304Sjkim /* 272280304Sjkim * This part isn't as trivial as it looks. It assumes that the 273280304Sjkim * second file specification really is a directory, and makes no 274280304Sjkim * checks whatsoever. Therefore, the result becomes the 275280304Sjkim * concatenation of filespec2 followed by a slash followed by 276280304Sjkim * filespec1. 277280304Sjkim */ 278280304Sjkim { 279280304Sjkim int spec2len, len; 280160814Ssimon 281280304Sjkim spec2len = (filespec2 ? strlen(filespec2) : 0); 282280304Sjkim len = spec2len + (filespec1 ? strlen(filespec1) : 0); 283160814Ssimon 284280304Sjkim if (filespec2 && filespec2[spec2len - 1] == '/') { 285280304Sjkim spec2len--; 286280304Sjkim len--; 287280304Sjkim } 288280304Sjkim merged = OPENSSL_malloc(len + 2); 289280304Sjkim if (!merged) { 290280304Sjkim DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE); 291280304Sjkim return (NULL); 292280304Sjkim } 293280304Sjkim strcpy(merged, filespec2); 294280304Sjkim merged[spec2len] = '/'; 295280304Sjkim strcpy(&merged[spec2len + 1], filespec1); 296280304Sjkim } 297280304Sjkim return (merged); 298280304Sjkim} 299160814Ssimon 300280304Sjkim/* 301280304Sjkim * This function is identical to the one in dso_dlfcn.c, but as it is highly 302280304Sjkim * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at 303280304Sjkim * the same time, there's no great duplicating the code. Figuring out an 304280304Sjkim * elegant way to share one copy of the code would be more difficult and 305280304Sjkim * would not leave the implementations independant. 306280304Sjkim */ 307280304Sjkim# if defined(__hpux) 308109998Smarkmstatic const char extension[] = ".sl"; 309280304Sjkim# else 310109998Smarkmstatic const char extension[] = ".so"; 311280304Sjkim# endif 312109998Smarkmstatic char *dl_name_converter(DSO *dso, const char *filename) 313280304Sjkim{ 314280304Sjkim char *translated; 315280304Sjkim int len, rsize, transform; 316109998Smarkm 317280304Sjkim len = strlen(filename); 318280304Sjkim rsize = len + 1; 319280304Sjkim transform = (strstr(filename, "/") == NULL); 320280304Sjkim { 321280304Sjkim /* We will convert this to "%s.s?" or "lib%s.s?" */ 322280304Sjkim rsize += strlen(extension); /* The length of ".s?" */ 323280304Sjkim if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 324280304Sjkim rsize += 3; /* The length of "lib" */ 325280304Sjkim } 326280304Sjkim translated = OPENSSL_malloc(rsize); 327280304Sjkim if (translated == NULL) { 328280304Sjkim DSOerr(DSO_F_DL_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED); 329280304Sjkim return (NULL); 330280304Sjkim } 331280304Sjkim if (transform) { 332280304Sjkim if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 333280304Sjkim sprintf(translated, "lib%s%s", filename, extension); 334280304Sjkim else 335280304Sjkim sprintf(translated, "%s%s", filename, extension); 336280304Sjkim } else 337280304Sjkim sprintf(translated, "%s", filename); 338280304Sjkim return (translated); 339280304Sjkim} 34068651Skris 341280304Sjkimstatic int dl_pathbyaddr(void *addr, char *path, int sz) 342280304Sjkim{ 343280304Sjkim struct shl_descriptor inf; 344280304Sjkim int i, len; 345238405Sjkim 346280304Sjkim if (addr == NULL) { 347280304Sjkim union { 348280304Sjkim int (*f) (void *, char *, int); 349280304Sjkim void *p; 350280304Sjkim } t = { 351280304Sjkim dl_pathbyaddr 352280304Sjkim }; 353280304Sjkim addr = t.p; 354280304Sjkim } 355238405Sjkim 356280304Sjkim for (i = -1; shl_get_r(i, &inf) == 0; i++) { 357280304Sjkim if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) || 358280304Sjkim ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend)) { 359280304Sjkim len = (int)strlen(inf.filename); 360280304Sjkim if (sz <= 0) 361280304Sjkim return len + 1; 362280304Sjkim if (len >= sz) 363280304Sjkim len = sz - 1; 364280304Sjkim memcpy(path, inf.filename, len); 365280304Sjkim path[len++] = 0; 366280304Sjkim return len; 367280304Sjkim } 368280304Sjkim } 369238405Sjkim 370280304Sjkim return -1; 371280304Sjkim} 372238405Sjkim 373238405Sjkimstatic void *dl_globallookup(const char *name) 374280304Sjkim{ 375280304Sjkim void *ret; 376280304Sjkim shl_t h = NULL; 377238405Sjkim 378280304Sjkim return shl_findsym(&h, name, TYPE_UNDEFINED, &ret) ? NULL : ret; 379280304Sjkim} 380280304Sjkim#endif /* DSO_DL */ 381