Home | History | Annotate | Download | only in dso
      1 /* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */
      2 /* Written by Geoff Thorpe (geoff (at) 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 (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 <string.h>
     61 #include "cryptlib.h"
     62 #include <openssl/dso.h>
     63 
     64 #if !defined(DSO_WIN32)
     65 DSO_METHOD *DSO_METHOD_win32(void)
     66 	{
     67 	return NULL;
     68 	}
     69 #else
     70 
     71 #ifdef _WIN32_WCE
     72 # if _WIN32_WCE < 300
     73 static FARPROC GetProcAddressA(HMODULE hModule,LPCSTR lpProcName)
     74 	{
     75 	WCHAR lpProcNameW[64];
     76 	int i;
     77 
     78 	for (i=0;lpProcName[i] && i<64;i++)
     79 		lpProcNameW[i] = (WCHAR)lpProcName[i];
     80 	if (i==64) return NULL;
     81 	lpProcNameW[i] = 0;
     82 
     83 	return GetProcAddressW(hModule,lpProcNameW);
     84 	}
     85 # endif
     86 # undef GetProcAddress
     87 # define GetProcAddress GetProcAddressA
     88 
     89 static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName)
     90 	{
     91 	WCHAR *fnamw;
     92 	size_t len_0=strlen(lpLibFileName)+1,i;
     93 
     94 #ifdef _MSC_VER
     95 	fnamw = (WCHAR *)_alloca (len_0*sizeof(WCHAR));
     96 #else
     97 	fnamw = (WCHAR *)alloca (len_0*sizeof(WCHAR));
     98 #endif
     99 	if (fnamw == NULL) return NULL;
    100 
    101 #if defined(_WIN32_WCE) && _WIN32_WCE>=101
    102 	if (!MultiByteToWideChar(CP_ACP,0,lpLibFileName,len_0,fnamw,len_0))
    103 #endif
    104 		for (i=0;i<len_0;i++) fnamw[i]=(WCHAR)lpLibFileName[i];
    105 
    106 	return LoadLibraryW(fnamw);
    107 	}
    108 #endif
    109 
    110 /* Part of the hack in "win32_load" ... */
    111 #define DSO_MAX_TRANSLATED_SIZE 256
    112 
    113 static int win32_load(DSO *dso);
    114 static int win32_unload(DSO *dso);
    115 static void *win32_bind_var(DSO *dso, const char *symname);
    116 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
    117 #if 0
    118 static int win32_unbind_var(DSO *dso, char *symname, void *symptr);
    119 static int win32_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
    120 static int win32_init(DSO *dso);
    121 static int win32_finish(DSO *dso);
    122 static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
    123 #endif
    124 static char *win32_name_converter(DSO *dso, const char *filename);
    125 static char *win32_merger(DSO *dso, const char *filespec1,
    126 	const char *filespec2);
    127 
    128 static const char *openssl_strnchr(const char *string, int c, size_t len);
    129 
    130 static DSO_METHOD dso_meth_win32 = {
    131 	"OpenSSL 'win32' shared library method",
    132 	win32_load,
    133 	win32_unload,
    134 	win32_bind_var,
    135 	win32_bind_func,
    136 /* For now, "unbind" doesn't exist */
    137 #if 0
    138 	NULL, /* unbind_var */
    139 	NULL, /* unbind_func */
    140 #endif
    141 	NULL, /* ctrl */
    142 	win32_name_converter,
    143 	win32_merger,
    144 	NULL, /* init */
    145 	NULL  /* finish */
    146 	};
    147 
    148 DSO_METHOD *DSO_METHOD_win32(void)
    149 	{
    150 	return(&dso_meth_win32);
    151 	}
    152 
    153 /* For this DSO_METHOD, our meth_data STACK will contain;
    154  * (i) a pointer to the handle (HINSTANCE) returned from
    155  *     LoadLibrary(), and copied.
    156  */
    157 
    158 static int win32_load(DSO *dso)
    159 	{
    160 	HINSTANCE h = NULL, *p = NULL;
    161 	/* See applicable comments from dso_dl.c */
    162 	char *filename = DSO_convert_filename(dso, NULL);
    163 
    164 	if(filename == NULL)
    165 		{
    166 		DSOerr(DSO_F_WIN32_LOAD,DSO_R_NO_FILENAME);
    167 		goto err;
    168 		}
    169 	h = LoadLibraryA(filename);
    170 	if(h == NULL)
    171 		{
    172 		DSOerr(DSO_F_WIN32_LOAD,DSO_R_LOAD_FAILED);
    173 		ERR_add_error_data(3, "filename(", filename, ")");
    174 		goto err;
    175 		}
    176 	p = (HINSTANCE *)OPENSSL_malloc(sizeof(HINSTANCE));
    177 	if(p == NULL)
    178 		{
    179 		DSOerr(DSO_F_WIN32_LOAD,ERR_R_MALLOC_FAILURE);
    180 		goto err;
    181 		}
    182 	*p = h;
    183 	if(!sk_push(dso->meth_data, (char *)p))
    184 		{
    185 		DSOerr(DSO_F_WIN32_LOAD,DSO_R_STACK_ERROR);
    186 		goto err;
    187 		}
    188 	/* Success */
    189 	dso->loaded_filename = filename;
    190 	return(1);
    191 err:
    192 	/* Cleanup !*/
    193 	if(filename != NULL)
    194 		OPENSSL_free(filename);
    195 	if(p != NULL)
    196 		OPENSSL_free(p);
    197 	if(h != NULL)
    198 		FreeLibrary(h);
    199 	return(0);
    200 	}
    201 
    202 static int win32_unload(DSO *dso)
    203 	{
    204 	HINSTANCE *p;
    205 	if(dso == NULL)
    206 		{
    207 		DSOerr(DSO_F_WIN32_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
    208 		return(0);
    209 		}
    210 	if(sk_num(dso->meth_data) < 1)
    211 		return(1);
    212 	p = (HINSTANCE *)sk_pop(dso->meth_data);
    213 	if(p == NULL)
    214 		{
    215 		DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_NULL_HANDLE);
    216 		return(0);
    217 		}
    218 	if(!FreeLibrary(*p))
    219 		{
    220 		DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_UNLOAD_FAILED);
    221 		/* We should push the value back onto the stack in
    222 		 * case of a retry. */
    223 		sk_push(dso->meth_data, (char *)p);
    224 		return(0);
    225 		}
    226 	/* Cleanup */
    227 	OPENSSL_free(p);
    228 	return(1);
    229 	}
    230 
    231 /* Using GetProcAddress for variables? TODO: Check this out in
    232  * the Win32 API docs, there's probably a variant for variables. */
    233 static void *win32_bind_var(DSO *dso, const char *symname)
    234 	{
    235 	HINSTANCE *ptr;
    236 	void *sym;
    237 
    238 	if((dso == NULL) || (symname == NULL))
    239 		{
    240 		DSOerr(DSO_F_WIN32_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
    241 		return(NULL);
    242 		}
    243 	if(sk_num(dso->meth_data) < 1)
    244 		{
    245 		DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_STACK_ERROR);
    246 		return(NULL);
    247 		}
    248 	ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
    249 	if(ptr == NULL)
    250 		{
    251 		DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_NULL_HANDLE);
    252 		return(NULL);
    253 		}
    254 	sym = GetProcAddress(*ptr, symname);
    255 	if(sym == NULL)
    256 		{
    257 		DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_SYM_FAILURE);
    258 		ERR_add_error_data(3, "symname(", symname, ")");
    259 		return(NULL);
    260 		}
    261 	return(sym);
    262 	}
    263 
    264 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
    265 	{
    266 	HINSTANCE *ptr;
    267 	void *sym;
    268 
    269 	if((dso == NULL) || (symname == NULL))
    270 		{
    271 		DSOerr(DSO_F_WIN32_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
    272 		return(NULL);
    273 		}
    274 	if(sk_num(dso->meth_data) < 1)
    275 		{
    276 		DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_STACK_ERROR);
    277 		return(NULL);
    278 		}
    279 	ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
    280 	if(ptr == NULL)
    281 		{
    282 		DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_NULL_HANDLE);
    283 		return(NULL);
    284 		}
    285 	sym = GetProcAddress(*ptr, symname);
    286 	if(sym == NULL)
    287 		{
    288 		DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_SYM_FAILURE);
    289 		ERR_add_error_data(3, "symname(", symname, ")");
    290 		return(NULL);
    291 		}
    292 	return((DSO_FUNC_TYPE)sym);
    293 	}
    294 
    295 struct file_st
    296 	{
    297 	const char *node; int nodelen;
    298 	const char *device; int devicelen;
    299 	const char *predir; int predirlen;
    300 	const char *dir; int dirlen;
    301 	const char *file; int filelen;
    302 	};
    303 
    304 static struct file_st *win32_splitter(DSO *dso, const char *filename,
    305 	int assume_last_is_dir)
    306 	{
    307 	struct file_st *result = NULL;
    308 	enum { IN_NODE, IN_DEVICE, IN_FILE } position;
    309 	const char *start = filename;
    310 	char last;
    311 
    312 	if (!filename)
    313 		{
    314 		DSOerr(DSO_F_WIN32_SPLITTER,DSO_R_NO_FILENAME);
    315 		/*goto err;*/
    316 		return(NULL);
    317 		}
    318 
    319 	result = OPENSSL_malloc(sizeof(struct file_st));
    320 	if(result == NULL)
    321 		{
    322 		DSOerr(DSO_F_WIN32_SPLITTER,
    323 			ERR_R_MALLOC_FAILURE);
    324 		return(NULL);
    325 		}
    326 
    327 	memset(result, 0, sizeof(struct file_st));
    328 	position = IN_DEVICE;
    329 
    330 	if((filename[0] == '\\' && filename[1] == '\\')
    331 		|| (filename[0] == '/' && filename[1] == '/'))
    332 		{
    333 		position = IN_NODE;
    334 		filename += 2;
    335 		start = filename;
    336 		result->node = start;
    337 		}
    338 
    339 	do
    340 		{
    341 		last = filename[0];
    342 		switch(last)
    343 			{
    344 		case ':':
    345 			if(position != IN_DEVICE)
    346 				{
    347 				DSOerr(DSO_F_WIN32_SPLITTER,
    348 					DSO_R_INCORRECT_FILE_SYNTAX);
    349 				/*goto err;*/
    350 				OPENSSL_free(result);
    351 				return(NULL);
    352 				}
    353 			result->device = start;
    354 			result->devicelen = filename - start;
    355 			position = IN_FILE;
    356 			start = ++filename;
    357 			result->dir = start;
    358 			break;
    359 		case '\\':
    360 		case '/':
    361 			if(position == IN_NODE)
    362 				{
    363 				result->nodelen = filename - start;
    364 				position = IN_FILE;
    365 				start = ++filename;
    366 				result->dir = start;
    367 				}
    368 			else if(position == IN_DEVICE)
    369 				{
    370 				position = IN_FILE;
    371 				filename++;
    372 				result->dir = start;
    373 				result->dirlen = filename - start;
    374 				start = filename;
    375 				}
    376 			else
    377 				{
    378 				filename++;
    379 				result->dirlen += filename - start;
    380 				start = filename;
    381 				}
    382 			break;
    383 		case '\0':
    384 			if(position == IN_NODE)
    385 				{
    386 				result->nodelen = filename - start;
    387 				}
    388 			else
    389 				{
    390 				if(filename - start > 0)
    391 					{
    392 					if (assume_last_is_dir)
    393 						{
    394 						if (position == IN_DEVICE)
    395 							{
    396 							result->dir = start;
    397 							result->dirlen = 0;
    398 							}
    399 						result->dirlen +=
    400 							filename - start;
    401 						}
    402 					else
    403 						{
    404 						result->file = start;
    405 						result->filelen =
    406 							filename - start;
    407 						}
    408 					}
    409 				}
    410 			break;
    411 		default:
    412 			filename++;
    413 			break;
    414 			}
    415 		}
    416 	while(last);
    417 
    418 	if(!result->nodelen) result->node = NULL;
    419 	if(!result->devicelen) result->device = NULL;
    420 	if(!result->dirlen) result->dir = NULL;
    421 	if(!result->filelen) result->file = NULL;
    422 
    423 	return(result);
    424 	}
    425 
    426 static char *win32_joiner(DSO *dso, const struct file_st *file_split)
    427 	{
    428 	int len = 0, offset = 0;
    429 	char *result = NULL;
    430 	const char *start;
    431 
    432 	if(!file_split)
    433 		{
    434 		DSOerr(DSO_F_WIN32_JOINER,
    435 				ERR_R_PASSED_NULL_PARAMETER);
    436 		return(NULL);
    437 		}
    438 	if(file_split->node)
    439 		{
    440 		len += 2 + file_split->nodelen;	/* 2 for starting \\ */
    441 		if(file_split->predir || file_split->dir || file_split->file)
    442 			len++;	/* 1 for ending \ */
    443 		}
    444 	else if(file_split->device)
    445 		{
    446 		len += file_split->devicelen + 1; /* 1 for ending : */
    447 		}
    448 	len += file_split->predirlen;
    449 	if(file_split->predir && (file_split->dir || file_split->file))
    450 		{
    451 		len++;	/* 1 for ending \ */
    452 		}
    453 	len += file_split->dirlen;
    454 	if(file_split->dir && file_split->file)
    455 		{
    456 		len++;	/* 1 for ending \ */
    457 		}
    458 	len += file_split->filelen;
    459 
    460 	if(!len)
    461 		{
    462 		DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
    463 		return(NULL);
    464 		}
    465 
    466 	result = OPENSSL_malloc(len + 1);
    467 	if (!result)
    468 		{
    469 		DSOerr(DSO_F_WIN32_JOINER,
    470 			ERR_R_MALLOC_FAILURE);
    471 		return(NULL);
    472 		}
    473 
    474 	if(file_split->node)
    475 		{
    476 		strcpy(&result[offset], "\\\\"); offset += 2;
    477 		strncpy(&result[offset], file_split->node,
    478 			file_split->nodelen); offset += file_split->nodelen;
    479 		if(file_split->predir || file_split->dir || file_split->file)
    480 			{
    481 			result[offset] = '\\'; offset++;
    482 			}
    483 		}
    484 	else if(file_split->device)
    485 		{
    486 		strncpy(&result[offset], file_split->device,
    487 			file_split->devicelen); offset += file_split->devicelen;
    488 		result[offset] = ':'; offset++;
    489 		}
    490 	start = file_split->predir;
    491 	while(file_split->predirlen > (start - file_split->predir))
    492 		{
    493 		const char *end = openssl_strnchr(start, '/',
    494 			file_split->predirlen - (start - file_split->predir));
    495 		if(!end)
    496 			end = start
    497 				+ file_split->predirlen
    498 				- (start - file_split->predir);
    499 		strncpy(&result[offset], start,
    500 			end - start); offset += end - start;
    501 		result[offset] = '\\'; offset++;
    502 		start = end + 1;
    503 		}
    504 #if 0 /* Not needed, since the directory converter above already appeneded
    505 	 a backslash */
    506 	if(file_split->predir && (file_split->dir || file_split->file))
    507 		{
    508 		result[offset] = '\\'; offset++;
    509 		}
    510 #endif
    511 	start = file_split->dir;
    512 	while(file_split->dirlen > (start - file_split->dir))
    513 		{
    514 		const char *end = openssl_strnchr(start, '/',
    515 			file_split->dirlen - (start - file_split->dir));
    516 		if(!end)
    517 			end = start
    518 				+ file_split->dirlen
    519 				- (start - file_split->dir);
    520 		strncpy(&result[offset], start,
    521 			end - start); offset += end - start;
    522 		result[offset] = '\\'; offset++;
    523 		start = end + 1;
    524 		}
    525 #if 0 /* Not needed, since the directory converter above already appeneded
    526 	 a backslash */
    527 	if(file_split->dir && file_split->file)
    528 		{
    529 		result[offset] = '\\'; offset++;
    530 		}
    531 #endif
    532 	strncpy(&result[offset], file_split->file,
    533 		file_split->filelen); offset += file_split->filelen;
    534 	result[offset] = '\0';
    535 	return(result);
    536 	}
    537 
    538 static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2)
    539 	{
    540 	char *merged = NULL;
    541 	struct file_st *filespec1_split = NULL;
    542 	struct file_st *filespec2_split = NULL;
    543 
    544 	if(!filespec1 && !filespec2)
    545 		{
    546 		DSOerr(DSO_F_WIN32_MERGER,
    547 				ERR_R_PASSED_NULL_PARAMETER);
    548 		return(NULL);
    549 		}
    550 	if (!filespec2)
    551 		{
    552 		merged = OPENSSL_malloc(strlen(filespec1) + 1);
    553 		if(!merged)
    554 			{
    555 			DSOerr(DSO_F_WIN32_MERGER,
    556 				ERR_R_MALLOC_FAILURE);
    557 			return(NULL);
    558 			}
    559 		strcpy(merged, filespec1);
    560 		}
    561 	else if (!filespec1)
    562 		{
    563 		merged = OPENSSL_malloc(strlen(filespec2) + 1);
    564 		if(!merged)
    565 			{
    566 			DSOerr(DSO_F_WIN32_MERGER,
    567 				ERR_R_MALLOC_FAILURE);
    568 			return(NULL);
    569 			}
    570 		strcpy(merged, filespec2);
    571 		}
    572 	else
    573 		{
    574 		filespec1_split = win32_splitter(dso, filespec1, 0);
    575 		if (!filespec1_split)
    576 			{
    577 			DSOerr(DSO_F_WIN32_MERGER,
    578 				ERR_R_MALLOC_FAILURE);
    579 			return(NULL);
    580 			}
    581 		filespec2_split = win32_splitter(dso, filespec2, 1);
    582 		if (!filespec2_split)
    583 			{
    584 			DSOerr(DSO_F_WIN32_MERGER,
    585 				ERR_R_MALLOC_FAILURE);
    586 			OPENSSL_free(filespec1_split);
    587 			return(NULL);
    588 			}
    589 
    590 		/* Fill in into filespec1_split */
    591 		if (!filespec1_split->node && !filespec1_split->device)
    592 			{
    593 			filespec1_split->node = filespec2_split->node;
    594 			filespec1_split->nodelen = filespec2_split->nodelen;
    595 			filespec1_split->device = filespec2_split->device;
    596 			filespec1_split->devicelen = filespec2_split->devicelen;
    597 			}
    598 		if (!filespec1_split->dir)
    599 			{
    600 			filespec1_split->dir = filespec2_split->dir;
    601 			filespec1_split->dirlen = filespec2_split->dirlen;
    602 			}
    603 		else if (filespec1_split->dir[0] != '\\'
    604 			&& filespec1_split->dir[0] != '/')
    605 			{
    606 			filespec1_split->predir = filespec2_split->dir;
    607 			filespec1_split->predirlen = filespec2_split->dirlen;
    608 			}
    609 		if (!filespec1_split->file)
    610 			{
    611 			filespec1_split->file = filespec2_split->file;
    612 			filespec1_split->filelen = filespec2_split->filelen;
    613 			}
    614 
    615 		merged = win32_joiner(dso, filespec1_split);
    616 		}
    617 	OPENSSL_free(filespec1_split);
    618 	OPENSSL_free(filespec2_split);
    619 	return(merged);
    620 	}
    621 
    622 static char *win32_name_converter(DSO *dso, const char *filename)
    623 	{
    624 	char *translated;
    625 	int len, transform;
    626 
    627 	len = strlen(filename);
    628 	transform = ((strstr(filename, "/") == NULL) &&
    629 			(strstr(filename, "\\") == NULL) &&
    630 			(strstr(filename, ":") == NULL));
    631 	if(transform)
    632 		/* We will convert this to "%s.dll" */
    633 		translated = OPENSSL_malloc(len + 5);
    634 	else
    635 		/* We will simply duplicate filename */
    636 		translated = OPENSSL_malloc(len + 1);
    637 	if(translated == NULL)
    638 		{
    639 		DSOerr(DSO_F_WIN32_NAME_CONVERTER,
    640 				DSO_R_NAME_TRANSLATION_FAILED);
    641 		return(NULL);
    642 		}
    643 	if(transform)
    644 		sprintf(translated, "%s.dll", filename);
    645 	else
    646 		sprintf(translated, "%s", filename);
    647 	return(translated);
    648 	}
    649 
    650 static const char *openssl_strnchr(const char *string, int c, size_t len)
    651 	{
    652 	size_t i;
    653 	const char *p;
    654 	for (i = 0, p = string; i < len && *p; i++, p++)
    655 		{
    656 		if (*p == c)
    657 			return p;
    658 		}
    659 	return NULL;
    660 	}
    661 
    662 
    663 #endif /* OPENSSL_SYS_WIN32 */
    664