Home | History | Annotate | Download | only in dso
      1 /* dso_dl.c -*- mode:C; c-file-style: "eay" -*- */
      2 /* Written by Richard Levitte (richard (at) levitte.org) 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 (at) 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 (at) cryptsoft.com).  This product includes software written by Tim
     55  * Hudson (tjh (at) cryptsoft.com).
     56  *
     57  */
     58 
     59 #include <stdio.h>
     60 #include "cryptlib.h"
     61 #include <openssl/dso.h>
     62 
     63 #ifndef DSO_DL
     64 DSO_METHOD *DSO_METHOD_dl(void)
     65        {
     66        return NULL;
     67        }
     68 #else
     69 
     70 #include <dl.h>
     71 
     72 /* Part of the hack in "dl_load" ... */
     73 #define DSO_MAX_TRANSLATED_SIZE 256
     74 
     75 static int dl_load(DSO *dso);
     76 static int dl_unload(DSO *dso);
     77 static void *dl_bind_var(DSO *dso, const char *symname);
     78 static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname);
     79 #if 0
     80 static int dl_unbind_var(DSO *dso, char *symname, void *symptr);
     81 static int dl_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
     82 static int dl_init(DSO *dso);
     83 static int dl_finish(DSO *dso);
     84 static int dl_ctrl(DSO *dso, int cmd, long larg, void *parg);
     85 #endif
     86 static char *dl_name_converter(DSO *dso, const char *filename);
     87 static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2);
     88 static int dl_pathbyaddr(void *addr,char *path,int sz);
     89 static void *dl_globallookup(const char *name);
     90 
     91 static DSO_METHOD dso_meth_dl = {
     92 	"OpenSSL 'dl' shared library method",
     93 	dl_load,
     94 	dl_unload,
     95 	dl_bind_var,
     96 	dl_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 	dl_name_converter,
    104 	dl_merger,
    105 	NULL, /* init */
    106 	NULL, /* finish */
    107 	dl_pathbyaddr,
    108 	dl_globallookup
    109 	};
    110 
    111 DSO_METHOD *DSO_METHOD_dl(void)
    112 	{
    113 	return(&dso_meth_dl);
    114 	}
    115 
    116 /* For this DSO_METHOD, our meth_data STACK will contain;
    117  * (i) the handle (shl_t) returned from shl_load().
    118  * NB: I checked on HPUX11 and shl_t is itself a pointer
    119  * type so the cast is safe.
    120  */
    121 
    122 static int dl_load(DSO *dso)
    123 	{
    124 	shl_t ptr = NULL;
    125 	/* We don't do any fancy retries or anything, just take the method's
    126 	 * (or DSO's if it has the callback set) best translation of the
    127 	 * platform-independant filename and try once with that. */
    128 	char *filename= DSO_convert_filename(dso, NULL);
    129 
    130 	if(filename == NULL)
    131 		{
    132 		DSOerr(DSO_F_DL_LOAD,DSO_R_NO_FILENAME);
    133 		goto err;
    134 		}
    135 	ptr = shl_load(filename, BIND_IMMEDIATE |
    136 		(dso->flags&DSO_FLAG_NO_NAME_TRANSLATION?0:DYNAMIC_PATH), 0L);
    137 	if(ptr == NULL)
    138 		{
    139 		DSOerr(DSO_F_DL_LOAD,DSO_R_LOAD_FAILED);
    140 		ERR_add_error_data(4, "filename(", filename, "): ",
    141 			strerror(errno));
    142 		goto err;
    143 		}
    144 	if(!sk_push(dso->meth_data, (char *)ptr))
    145 		{
    146 		DSOerr(DSO_F_DL_LOAD,DSO_R_STACK_ERROR);
    147 		goto err;
    148 		}
    149 	/* Success, stick the converted filename we've loaded under into the DSO
    150 	 * (it also serves as the indicator that we are currently loaded). */
    151 	dso->loaded_filename = filename;
    152 	return(1);
    153 err:
    154 	/* Cleanup! */
    155 	if(filename != NULL)
    156 		OPENSSL_free(filename);
    157 	if(ptr != NULL)
    158 		shl_unload(ptr);
    159 	return(0);
    160 	}
    161 
    162 static int dl_unload(DSO *dso)
    163 	{
    164 	shl_t ptr;
    165 	if(dso == NULL)
    166 		{
    167 		DSOerr(DSO_F_DL_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
    168 		return(0);
    169 		}
    170 	if(sk_num(dso->meth_data) < 1)
    171 		return(1);
    172 	/* Is this statement legal? */
    173 	ptr = (shl_t)sk_pop(dso->meth_data);
    174 	if(ptr == NULL)
    175 		{
    176 		DSOerr(DSO_F_DL_UNLOAD,DSO_R_NULL_HANDLE);
    177 		/* Should push the value back onto the stack in
    178 		 * case of a retry. */
    179 		sk_push(dso->meth_data, (char *)ptr);
    180 		return(0);
    181 		}
    182 	shl_unload(ptr);
    183 	return(1);
    184 	}
    185 
    186 static void *dl_bind_var(DSO *dso, const char *symname)
    187 	{
    188 	shl_t ptr;
    189 	void *sym;
    190 
    191 	if((dso == NULL) || (symname == NULL))
    192 		{
    193 		DSOerr(DSO_F_DL_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
    194 		return(NULL);
    195 		}
    196 	if(sk_num(dso->meth_data) < 1)
    197 		{
    198 		DSOerr(DSO_F_DL_BIND_VAR,DSO_R_STACK_ERROR);
    199 		return(NULL);
    200 		}
    201 	ptr = (shl_t)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
    202 	if(ptr == NULL)
    203 		{
    204 		DSOerr(DSO_F_DL_BIND_VAR,DSO_R_NULL_HANDLE);
    205 		return(NULL);
    206 		}
    207 	if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0)
    208 		{
    209 		DSOerr(DSO_F_DL_BIND_VAR,DSO_R_SYM_FAILURE);
    210 		ERR_add_error_data(4, "symname(", symname, "): ",
    211 			strerror(errno));
    212 		return(NULL);
    213 		}
    214 	return(sym);
    215 	}
    216 
    217 static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname)
    218 	{
    219 	shl_t ptr;
    220 	void *sym;
    221 
    222 	if((dso == NULL) || (symname == NULL))
    223 		{
    224 		DSOerr(DSO_F_DL_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
    225 		return(NULL);
    226 		}
    227 	if(sk_num(dso->meth_data) < 1)
    228 		{
    229 		DSOerr(DSO_F_DL_BIND_FUNC,DSO_R_STACK_ERROR);
    230 		return(NULL);
    231 		}
    232 	ptr = (shl_t)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
    233 	if(ptr == NULL)
    234 		{
    235 		DSOerr(DSO_F_DL_BIND_FUNC,DSO_R_NULL_HANDLE);
    236 		return(NULL);
    237 		}
    238 	if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0)
    239 		{
    240 		DSOerr(DSO_F_DL_BIND_FUNC,DSO_R_SYM_FAILURE);
    241 		ERR_add_error_data(4, "symname(", symname, "): ",
    242 			strerror(errno));
    243 		return(NULL);
    244 		}
    245 	return((DSO_FUNC_TYPE)sym);
    246 	}
    247 
    248 static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2)
    249 	{
    250 	char *merged;
    251 
    252 	if(!filespec1 && !filespec2)
    253 		{
    254 		DSOerr(DSO_F_DL_MERGER,
    255 				ERR_R_PASSED_NULL_PARAMETER);
    256 		return(NULL);
    257 		}
    258 	/* If the first file specification is a rooted path, it rules.
    259 	   same goes if the second file specification is missing. */
    260 	if (!filespec2 || filespec1[0] == '/')
    261 		{
    262 		merged = OPENSSL_malloc(strlen(filespec1) + 1);
    263 		if(!merged)
    264 			{
    265 			DSOerr(DSO_F_DL_MERGER,
    266 				ERR_R_MALLOC_FAILURE);
    267 			return(NULL);
    268 			}
    269 		strcpy(merged, filespec1);
    270 		}
    271 	/* If the first file specification is missing, the second one rules. */
    272 	else if (!filespec1)
    273 		{
    274 		merged = OPENSSL_malloc(strlen(filespec2) + 1);
    275 		if(!merged)
    276 			{
    277 			DSOerr(DSO_F_DL_MERGER,
    278 				ERR_R_MALLOC_FAILURE);
    279 			return(NULL);
    280 			}
    281 		strcpy(merged, filespec2);
    282 		}
    283 	else
    284 		/* This part isn't as trivial as it looks.  It assumes that
    285 		   the second file specification really is a directory, and
    286 		   makes no checks whatsoever.  Therefore, the result becomes
    287 		   the concatenation of filespec2 followed by a slash followed
    288 		   by filespec1. */
    289 		{
    290 		int spec2len, len;
    291 
    292 		spec2len = (filespec2 ? strlen(filespec2) : 0);
    293 		len = spec2len + (filespec1 ? strlen(filespec1) : 0);
    294 
    295 		if(filespec2 && filespec2[spec2len - 1] == '/')
    296 			{
    297 			spec2len--;
    298 			len--;
    299 			}
    300 		merged = OPENSSL_malloc(len + 2);
    301 		if(!merged)
    302 			{
    303 			DSOerr(DSO_F_DL_MERGER,
    304 				ERR_R_MALLOC_FAILURE);
    305 			return(NULL);
    306 			}
    307 		strcpy(merged, filespec2);
    308 		merged[spec2len] = '/';
    309 		strcpy(&merged[spec2len + 1], filespec1);
    310 		}
    311 	return(merged);
    312 	}
    313 
    314 /* This function is identical to the one in dso_dlfcn.c, but as it is highly
    315  * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at the
    316  * same time, there's no great duplicating the code. Figuring out an elegant
    317  * way to share one copy of the code would be more difficult and would not
    318  * leave the implementations independant. */
    319 #if defined(__hpux)
    320 static const char extension[] = ".sl";
    321 #else
    322 static const char extension[] = ".so";
    323 #endif
    324 static char *dl_name_converter(DSO *dso, const char *filename)
    325 	{
    326 	char *translated;
    327 	int len, rsize, transform;
    328 
    329 	len = strlen(filename);
    330 	rsize = len + 1;
    331 	transform = (strstr(filename, "/") == NULL);
    332 		{
    333 		/* We will convert this to "%s.s?" or "lib%s.s?" */
    334 		rsize += strlen(extension);/* The length of ".s?" */
    335 		if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
    336 			rsize += 3; /* The length of "lib" */
    337 		}
    338 	translated = OPENSSL_malloc(rsize);
    339 	if(translated == NULL)
    340 		{
    341 		DSOerr(DSO_F_DL_NAME_CONVERTER,
    342 				DSO_R_NAME_TRANSLATION_FAILED);
    343 		return(NULL);
    344 		}
    345 	if(transform)
    346 		{
    347 		if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
    348 			sprintf(translated, "lib%s%s", filename, extension);
    349 		else
    350 			sprintf(translated, "%s%s", filename, extension);
    351 		}
    352 	else
    353 		sprintf(translated, "%s", filename);
    354 	return(translated);
    355 	}
    356 
    357 static int dl_pathbyaddr(void *addr,char *path,int sz)
    358 	{
    359 	struct shl_descriptor inf;
    360 	int i,len;
    361 
    362 	if (addr == NULL)
    363 		{
    364 		union	{ int(*f)(void*,char*,int); void *p; } t =
    365 			{ dl_pathbyaddr };
    366 		addr = t.p;
    367 		}
    368 
    369 	for (i=-1;shl_get_r(i,&inf)==0;i++)
    370 		{
    371 		if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) ||
    372 		    ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend))
    373 			{
    374 			len = (int)strlen(inf.filename);
    375 			if (sz <= 0) return len+1;
    376 			if (len >= sz) len=sz-1;
    377 			memcpy(path,inf.filename,len);
    378 			path[len++] = 0;
    379 			return len;
    380 			}
    381 		}
    382 
    383 	return -1;
    384 	}
    385 
    386 static void *dl_globallookup(const char *name)
    387 	{
    388 	void *ret;
    389 	shl_t h = NULL;
    390 
    391 	return shl_findsym(&h,name,TYPE_UNDEFINED,&ret) ? NULL : ret;
    392 	}
    393 #endif /* DSO_DL */
    394