1/* dso_win32.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 <string.h> 61#include "cryptlib.h" 62#include <openssl/dso.h> 63 64#if !defined(DSO_WIN32) 65DSO_METHOD *DSO_METHOD_win32(void) 66 { 67 return NULL; 68 } 69#else 70 71#ifdef _WIN32_WCE 72# if _WIN32_WCE < 300 73static 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 89static 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 113static int win32_load(DSO *dso); 114static int win32_unload(DSO *dso); 115static void *win32_bind_var(DSO *dso, const char *symname); 116static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname); 117#if 0 118static int win32_unbind_var(DSO *dso, char *symname, void *symptr); 119static int win32_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr); 120static int win32_init(DSO *dso); 121static int win32_finish(DSO *dso); 122static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg); 123#endif 124static char *win32_name_converter(DSO *dso, const char *filename); 125static char *win32_merger(DSO *dso, const char *filespec1, 126 const char *filespec2); 127 128static const char *openssl_strnchr(const char *string, int c, size_t len); 129 130static 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 148DSO_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 158static 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); 191err: 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 202static 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. */ 233static 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 264static 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 295struct 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 304static 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 311 if (!filename) 312 { 313 DSOerr(DSO_F_WIN32_SPLITTER,DSO_R_NO_FILENAME); 314 /*goto err;*/ 315 return(NULL); 316 } 317 318 result = OPENSSL_malloc(sizeof(struct file_st)); 319 if(result == NULL) 320 { 321 DSOerr(DSO_F_WIN32_SPLITTER, 322 ERR_R_MALLOC_FAILURE); 323 return(NULL); 324 } 325 326 memset(result, 0, sizeof(struct file_st)); 327 position = IN_DEVICE; 328 329 if(filename[0] == '\\' && filename[1] == '\\' 330 || filename[0] == '/' && filename[1] == '/') 331 { 332 position = IN_NODE; 333 filename += 2; 334 start = filename; 335 result->node = start; 336 } 337 338 do 339 { 340 switch(filename[0]) 341 { 342 case ':': 343 if(position != IN_DEVICE) 344 { 345 DSOerr(DSO_F_WIN32_SPLITTER, 346 DSO_R_INCORRECT_FILE_SYNTAX); 347 /*goto err;*/ 348 return(NULL); 349 } 350 result->device = start; 351 result->devicelen = filename - start; 352 position = IN_FILE; 353 start = ++filename; 354 result->dir = start; 355 break; 356 case '\\': 357 case '/': 358 if(position == IN_NODE) 359 { 360 result->nodelen = filename - start; 361 position = IN_FILE; 362 start = ++filename; 363 result->dir = start; 364 } 365 else 366 { 367 filename++; 368 result->dirlen += filename - start; 369 } 370 break; 371 case '\0': 372 if(position == IN_NODE) 373 { 374 result->nodelen = filename - start; 375 } 376 else 377 { 378 if(filename - start > 0) 379 { 380 if (assume_last_is_dir) 381 { 382 result->devicelen += filename - start; 383 } 384 else 385 { 386 result->file = start; 387 result->filelen = filename - start; 388 } 389 } 390 } 391 break; 392 default: 393 filename++; 394 break; 395 } 396 } 397 while(*filename); 398 399 if(!result->nodelen) result->node = NULL; 400 if(!result->devicelen) result->device = NULL; 401 if(!result->dirlen) result->dir = NULL; 402 if(!result->filelen) result->file = NULL; 403 404 return(result); 405 } 406 407static char *win32_joiner(DSO *dso, const struct file_st *file_split) 408 { 409 int len = 0, offset = 0; 410 char *result = NULL; 411 const char *start; 412 413 if(!file_split) 414 { 415 DSOerr(DSO_F_WIN32_JOINER, 416 ERR_R_PASSED_NULL_PARAMETER); 417 return(NULL); 418 } 419 if(file_split->node) 420 { 421 len += 2 + file_split->nodelen; /* 2 for starting \\ */ 422 if(file_split->predir || file_split->dir || file_split->file) 423 len++; /* 1 for ending \ */ 424 } 425 else if(file_split->device) 426 { 427 len += file_split->devicelen + 1; /* 1 for ending : */ 428 } 429 len += file_split->predirlen; 430 if(file_split->predir && (file_split->dir || file_split->file)) 431 { 432 len++; /* 1 for ending \ */ 433 } 434 len += file_split->dirlen; 435 if(file_split->dir && file_split->file) 436 { 437 len++; /* 1 for ending \ */ 438 } 439 len += file_split->filelen; 440 441 if(!len) 442 { 443 DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE); 444 return(NULL); 445 } 446 447 result = OPENSSL_malloc(len + 1); 448 if (!result) 449 { 450 DSOerr(DSO_F_WIN32_JOINER, 451 ERR_R_MALLOC_FAILURE); 452 return(NULL); 453 } 454 455 if(file_split->node) 456 { 457 strcpy(&result[offset], "\\\\"); offset += 2; 458 strncpy(&result[offset], file_split->node, 459 file_split->nodelen); offset += file_split->nodelen; 460 if(file_split->predir || file_split->dir || file_split->file) 461 { 462 result[offset] = '\\'; offset++; 463 } 464 } 465 else if(file_split->device) 466 { 467 strncpy(&result[offset], file_split->device, 468 file_split->devicelen); offset += file_split->devicelen; 469 result[offset] = ':'; offset++; 470 } 471 start = file_split->predir; 472 while(file_split->predirlen > (start - file_split->predir)) 473 { 474 const char *end = openssl_strnchr(start, '/', 475 file_split->predirlen - (start - file_split->predir)); 476 if(!end) 477 end = start 478 + file_split->predirlen 479 - (start - file_split->predir); 480 strncpy(&result[offset], start, 481 end - start); offset += end - start; 482 result[offset] = '\\'; offset++; 483 start = end + 1; 484 } 485 if(file_split->predir && (file_split->dir || file_split->file)) 486 { 487 result[offset] = '\\'; offset++; 488 } 489 start = file_split->dir; 490 while(file_split->dirlen > (start - file_split->dir)) 491 { 492 const char *end = openssl_strnchr(start, '/', 493 file_split->dirlen - (start - file_split->dir)); 494 if(!end) 495 end = start 496 + file_split->dirlen 497 - (start - file_split->dir); 498 strncpy(&result[offset], start, 499 end - start); offset += end - start; 500 result[offset] = '\\'; offset++; 501 start = end + 1; 502 } 503 if(file_split->dir && file_split->file) 504 { 505 result[offset] = '\\'; offset++; 506 } 507 strncpy(&result[offset], file_split->file, 508 file_split->filelen); offset += file_split->filelen; 509 result[offset] = '\0'; 510 return(result); 511 } 512 513static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2) 514 { 515 char *merged = NULL; 516 struct file_st *filespec1_split = NULL; 517 struct file_st *filespec2_split = NULL; 518 519 if(!filespec1 && !filespec2) 520 { 521 DSOerr(DSO_F_WIN32_MERGER, 522 ERR_R_PASSED_NULL_PARAMETER); 523 return(NULL); 524 } 525 if (!filespec2) 526 { 527 merged = OPENSSL_malloc(strlen(filespec1) + 1); 528 if(!merged) 529 { 530 DSOerr(DSO_F_WIN32_MERGER, 531 ERR_R_MALLOC_FAILURE); 532 return(NULL); 533 } 534 strcpy(merged, filespec1); 535 } 536 else if (!filespec1) 537 { 538 merged = OPENSSL_malloc(strlen(filespec2) + 1); 539 if(!merged) 540 { 541 DSOerr(DSO_F_WIN32_MERGER, 542 ERR_R_MALLOC_FAILURE); 543 return(NULL); 544 } 545 strcpy(merged, filespec2); 546 } 547 else 548 { 549 filespec1_split = win32_splitter(dso, filespec1, 1); 550 if (!filespec1_split) 551 { 552 DSOerr(DSO_F_WIN32_MERGER, 553 ERR_R_MALLOC_FAILURE); 554 return(NULL); 555 } 556 filespec2_split = win32_splitter(dso, filespec2, 0); 557 if (!filespec1_split) 558 { 559 DSOerr(DSO_F_WIN32_MERGER, 560 ERR_R_MALLOC_FAILURE); 561 OPENSSL_free(filespec1_split); 562 return(NULL); 563 } 564 565 /* Fill in into filespec1_split */ 566 if (!filespec1_split->node && !filespec1_split->device) 567 { 568 filespec1_split->node = filespec2_split->node; 569 filespec1_split->nodelen = filespec2_split->nodelen; 570 filespec1_split->device = filespec2_split->device; 571 filespec1_split->devicelen = filespec2_split->devicelen; 572 } 573 if (!filespec1_split->dir) 574 { 575 filespec1_split->dir = filespec2_split->dir; 576 filespec1_split->dirlen = filespec2_split->dirlen; 577 } 578 else if (filespec1_split->dir[0] != '\\' 579 && filespec1_split->dir[0] != '/') 580 { 581 filespec1_split->predir = filespec2_split->dir; 582 filespec1_split->predirlen = filespec2_split->dirlen; 583 } 584 if (!filespec1_split->file) 585 { 586 filespec1_split->file = filespec2_split->file; 587 filespec1_split->filelen = filespec2_split->filelen; 588 } 589 590 merged = win32_joiner(dso, filespec1_split); 591 } 592 return(merged); 593 } 594 595static char *win32_name_converter(DSO *dso, const char *filename) 596 { 597 char *translated; 598 int len, transform; 599 600 len = strlen(filename); 601 transform = ((strstr(filename, "/") == NULL) && 602 (strstr(filename, "\\") == NULL) && 603 (strstr(filename, ":") == NULL)); 604 if(transform) 605 /* We will convert this to "%s.dll" */ 606 translated = OPENSSL_malloc(len + 5); 607 else 608 /* We will simply duplicate filename */ 609 translated = OPENSSL_malloc(len + 1); 610 if(translated == NULL) 611 { 612 DSOerr(DSO_F_WIN32_NAME_CONVERTER, 613 DSO_R_NAME_TRANSLATION_FAILED); 614 return(NULL); 615 } 616 if(transform) 617 sprintf(translated, "%s.dll", filename); 618 else 619 sprintf(translated, "%s", filename); 620 return(translated); 621 } 622 623static const char *openssl_strnchr(const char *string, int c, size_t len) 624 { 625 size_t i; 626 const char *p; 627 for (i = 0, p = string; i < len && *p; i++, p++) 628 { 629 if (*p == c) 630 return p; 631 } 632 return NULL; 633 } 634 635 636#endif /* OPENSSL_SYS_WIN32 */ 637