xref: /freebsd/crypto/openssl/crypto/dso/dso_dl.c (revision f05cddf9)
1 /* dso_dl.c -*- mode:C; c-file-style: "eay" -*- */
2 /* Written by Richard Levitte (richard@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@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_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