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