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 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 return(NULL); 351 } 352 result->device = start; 353 result->devicelen = filename - start; 354 position = IN_FILE; 355 start = ++filename; 356 result->dir = start; 357 break; 358 case '\\': 359 case '/': 360 if(position == IN_NODE) 361 { 362 result->nodelen = filename - start; 363 position = IN_FILE; 364 start = ++filename; 365 result->dir = start; 366 } 367 else if(position == IN_DEVICE) 368 { 369 position = IN_FILE; 370 filename++; 371 result->dir = start; 372 result->dirlen = filename - start; 373 start = filename; 374 } 375 else 376 { 377 filename++; 378 result->dirlen += filename - start; 379 start = filename; 380 } 381 break; 382 case '\0': 383 if(position == IN_NODE) 384 { 385 result->nodelen = filename - start; 386 } 387 else 388 { 389 if(filename - start > 0) 390 { 391 if (assume_last_is_dir) 392 { 393 if (position == IN_DEVICE) 394 { 395 result->dir = start; 396 result->dirlen = 0; 397 } 398 result->dirlen += 399 filename - start; 400 } 401 else 402 { 403 result->file = start; 404 result->filelen = 405 filename - start; 406 } 407 } 408 } 409 break; 410 default: 411 filename++; 412 break; 413 } 414 } 415 while(last); 416 417 if(!result->nodelen) result->node = NULL; 418 if(!result->devicelen) result->device = NULL; 419 if(!result->dirlen) result->dir = NULL; 420 if(!result->filelen) result->file = NULL; 421 422 return(result); 423 } 424 425static char *win32_joiner(DSO *dso, const struct file_st *file_split) 426 { 427 int len = 0, offset = 0; 428 char *result = NULL; 429 const char *start; 430 431 if(!file_split) 432 { 433 DSOerr(DSO_F_WIN32_JOINER, 434 ERR_R_PASSED_NULL_PARAMETER); 435 return(NULL); 436 } 437 if(file_split->node) 438 { 439 len += 2 + file_split->nodelen; /* 2 for starting \\ */ 440 if(file_split->predir || file_split->dir || file_split->file) 441 len++; /* 1 for ending \ */ 442 } 443 else if(file_split->device) 444 { 445 len += file_split->devicelen + 1; /* 1 for ending : */ 446 } 447 len += file_split->predirlen; 448 if(file_split->predir && (file_split->dir || file_split->file)) 449 { 450 len++; /* 1 for ending \ */ 451 } 452 len += file_split->dirlen; 453 if(file_split->dir && file_split->file) 454 { 455 len++; /* 1 for ending \ */ 456 } 457 len += file_split->filelen; 458 459 if(!len) 460 { 461 DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE); 462 return(NULL); 463 } 464 465 result = OPENSSL_malloc(len + 1); 466 if (!result) 467 { 468 DSOerr(DSO_F_WIN32_JOINER, 469 ERR_R_MALLOC_FAILURE); 470 return(NULL); 471 } 472 473 if(file_split->node) 474 { 475 strcpy(&result[offset], "\\\\"); offset += 2; 476 strncpy(&result[offset], file_split->node, 477 file_split->nodelen); offset += file_split->nodelen; 478 if(file_split->predir || file_split->dir || file_split->file) 479 { 480 result[offset] = '\\'; offset++; 481 } 482 } 483 else if(file_split->device) 484 { 485 strncpy(&result[offset], file_split->device, 486 file_split->devicelen); offset += file_split->devicelen; 487 result[offset] = ':'; offset++; 488 } 489 start = file_split->predir; 490 while(file_split->predirlen > (start - file_split->predir)) 491 { 492 const char *end = openssl_strnchr(start, '/', 493 file_split->predirlen - (start - file_split->predir)); 494 if(!end) 495 end = start 496 + file_split->predirlen 497 - (start - file_split->predir); 498 strncpy(&result[offset], start, 499 end - start); offset += end - start; 500 result[offset] = '\\'; offset++; 501 start = end + 1; 502 } 503#if 0 /* Not needed, since the directory converter above already appeneded 504 a backslash */ 505 if(file_split->predir && (file_split->dir || file_split->file)) 506 { 507 result[offset] = '\\'; offset++; 508 } 509#endif 510 start = file_split->dir; 511 while(file_split->dirlen > (start - file_split->dir)) 512 { 513 const char *end = openssl_strnchr(start, '/', 514 file_split->dirlen - (start - file_split->dir)); 515 if(!end) 516 end = start 517 + file_split->dirlen 518 - (start - file_split->dir); 519 strncpy(&result[offset], start, 520 end - start); offset += end - start; 521 result[offset] = '\\'; offset++; 522 start = end + 1; 523 } 524#if 0 /* Not needed, since the directory converter above already appeneded 525 a backslash */ 526 if(file_split->dir && file_split->file) 527 { 528 result[offset] = '\\'; offset++; 529 } 530#endif 531 strncpy(&result[offset], file_split->file, 532 file_split->filelen); offset += file_split->filelen; 533 result[offset] = '\0'; 534 return(result); 535 } 536 537static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2) 538 { 539 char *merged = NULL; 540 struct file_st *filespec1_split = NULL; 541 struct file_st *filespec2_split = NULL; 542 543 if(!filespec1 && !filespec2) 544 { 545 DSOerr(DSO_F_WIN32_MERGER, 546 ERR_R_PASSED_NULL_PARAMETER); 547 return(NULL); 548 } 549 if (!filespec2) 550 { 551 merged = OPENSSL_malloc(strlen(filespec1) + 1); 552 if(!merged) 553 { 554 DSOerr(DSO_F_WIN32_MERGER, 555 ERR_R_MALLOC_FAILURE); 556 return(NULL); 557 } 558 strcpy(merged, filespec1); 559 } 560 else if (!filespec1) 561 { 562 merged = OPENSSL_malloc(strlen(filespec2) + 1); 563 if(!merged) 564 { 565 DSOerr(DSO_F_WIN32_MERGER, 566 ERR_R_MALLOC_FAILURE); 567 return(NULL); 568 } 569 strcpy(merged, filespec2); 570 } 571 else 572 { 573 filespec1_split = win32_splitter(dso, filespec1, 0); 574 if (!filespec1_split) 575 { 576 DSOerr(DSO_F_WIN32_MERGER, 577 ERR_R_MALLOC_FAILURE); 578 return(NULL); 579 } 580 filespec2_split = win32_splitter(dso, filespec2, 1); 581 if (!filespec2_split) 582 { 583 DSOerr(DSO_F_WIN32_MERGER, 584 ERR_R_MALLOC_FAILURE); 585 OPENSSL_free(filespec1_split); 586 return(NULL); 587 } 588 589 /* Fill in into filespec1_split */ 590 if (!filespec1_split->node && !filespec1_split->device) 591 { 592 filespec1_split->node = filespec2_split->node; 593 filespec1_split->nodelen = filespec2_split->nodelen; 594 filespec1_split->device = filespec2_split->device; 595 filespec1_split->devicelen = filespec2_split->devicelen; 596 } 597 if (!filespec1_split->dir) 598 { 599 filespec1_split->dir = filespec2_split->dir; 600 filespec1_split->dirlen = filespec2_split->dirlen; 601 } 602 else if (filespec1_split->dir[0] != '\\' 603 && filespec1_split->dir[0] != '/') 604 { 605 filespec1_split->predir = filespec2_split->dir; 606 filespec1_split->predirlen = filespec2_split->dirlen; 607 } 608 if (!filespec1_split->file) 609 { 610 filespec1_split->file = filespec2_split->file; 611 filespec1_split->filelen = filespec2_split->filelen; 612 } 613 614 merged = win32_joiner(dso, filespec1_split); 615 } 616 return(merged); 617 } 618 619static char *win32_name_converter(DSO *dso, const char *filename) 620 { 621 char *translated; 622 int len, transform; 623 624 len = strlen(filename); 625 transform = ((strstr(filename, "/") == NULL) && 626 (strstr(filename, "\\") == NULL) && 627 (strstr(filename, ":") == NULL)); 628 if(transform) 629 /* We will convert this to "%s.dll" */ 630 translated = OPENSSL_malloc(len + 5); 631 else 632 /* We will simply duplicate filename */ 633 translated = OPENSSL_malloc(len + 1); 634 if(translated == NULL) 635 { 636 DSOerr(DSO_F_WIN32_NAME_CONVERTER, 637 DSO_R_NAME_TRANSLATION_FAILED); 638 return(NULL); 639 } 640 if(transform) 641 sprintf(translated, "%s.dll", filename); 642 else 643 sprintf(translated, "%s", filename); 644 return(translated); 645 } 646 647static const char *openssl_strnchr(const char *string, int c, size_t len) 648 { 649 size_t i; 650 const char *p; 651 for (i = 0, p = string; i < len && *p; i++, p++) 652 { 653 if (*p == c) 654 return p; 655 } 656 return NULL; 657 } 658 659 660#endif /* OPENSSL_SYS_WIN32 */ 661