1 /* 2 * Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include "internal/e_os.h" 11 #include "dso_local.h" 12 13 #if defined(DSO_WIN32) 14 15 # ifdef _WIN32_WCE 16 # if _WIN32_WCE < 300 17 static FARPROC GetProcAddressA(HMODULE hModule, LPCSTR lpProcName) 18 { 19 WCHAR lpProcNameW[64]; 20 int i; 21 22 for (i = 0; lpProcName[i] && i < 64; i++) 23 lpProcNameW[i] = (WCHAR)lpProcName[i]; 24 if (i == 64) 25 return NULL; 26 lpProcNameW[i] = 0; 27 28 return GetProcAddressW(hModule, lpProcNameW); 29 } 30 # endif 31 # undef GetProcAddress 32 # define GetProcAddress GetProcAddressA 33 34 static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName) 35 { 36 WCHAR *fnamw; 37 size_t len_0 = strlen(lpLibFileName) + 1, i; 38 39 # ifdef _MSC_VER 40 fnamw = (WCHAR *)_alloca(len_0 * sizeof(WCHAR)); 41 # else 42 fnamw = (WCHAR *)alloca(len_0 * sizeof(WCHAR)); 43 # endif 44 if (fnamw == NULL) { 45 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 46 return NULL; 47 } 48 # if defined(_WIN32_WCE) && _WIN32_WCE>=101 49 if (!MultiByteToWideChar(CP_ACP, 0, lpLibFileName, len_0, fnamw, len_0)) 50 # endif 51 for (i = 0; i < len_0; i++) 52 fnamw[i] = (WCHAR)lpLibFileName[i]; 53 54 return LoadLibraryW(fnamw); 55 } 56 # endif 57 58 /* Part of the hack in "win32_load" ... */ 59 # define DSO_MAX_TRANSLATED_SIZE 256 60 61 static int win32_load(DSO *dso); 62 static int win32_unload(DSO *dso); 63 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname); 64 static char *win32_name_converter(DSO *dso, const char *filename); 65 static char *win32_merger(DSO *dso, const char *filespec1, 66 const char *filespec2); 67 static int win32_pathbyaddr(void *addr, char *path, int sz); 68 static void *win32_globallookup(const char *name); 69 70 static const char *openssl_strnchr(const char *string, int c, size_t len); 71 72 static DSO_METHOD dso_meth_win32 = { 73 "OpenSSL 'win32' shared library method", 74 win32_load, 75 win32_unload, 76 win32_bind_func, 77 NULL, /* ctrl */ 78 win32_name_converter, 79 win32_merger, 80 NULL, /* init */ 81 NULL, /* finish */ 82 win32_pathbyaddr, /* pathbyaddr */ 83 win32_globallookup 84 }; 85 86 DSO_METHOD *DSO_METHOD_openssl(void) 87 { 88 return &dso_meth_win32; 89 } 90 91 /* 92 * For this DSO_METHOD, our meth_data STACK will contain; (i) a pointer to 93 * the handle (HINSTANCE) returned from LoadLibrary(), and copied. 94 */ 95 96 static int win32_load(DSO *dso) 97 { 98 HINSTANCE h = NULL, *p = NULL; 99 /* See applicable comments from dso_dl.c */ 100 char *filename = DSO_convert_filename(dso, NULL); 101 102 if (filename == NULL) { 103 ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); 104 goto err; 105 } 106 h = LoadLibraryA(filename); 107 if (h == NULL) { 108 ERR_raise_data(ERR_LIB_DSO, DSO_R_LOAD_FAILED, 109 "filename(%s)", filename); 110 goto err; 111 } 112 p = OPENSSL_malloc(sizeof(*p)); 113 if (p == NULL) 114 goto err; 115 *p = h; 116 if (!sk_void_push(dso->meth_data, p)) { 117 ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR); 118 goto err; 119 } 120 /* Success */ 121 dso->loaded_filename = filename; 122 return 1; 123 err: 124 /* Cleanup ! */ 125 OPENSSL_free(filename); 126 OPENSSL_free(p); 127 if (h != NULL) 128 FreeLibrary(h); 129 return 0; 130 } 131 132 static int win32_unload(DSO *dso) 133 { 134 HINSTANCE *p; 135 if (dso == NULL) { 136 ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); 137 return 0; 138 } 139 if (sk_void_num(dso->meth_data) < 1) 140 return 1; 141 p = sk_void_pop(dso->meth_data); 142 if (p == NULL) { 143 ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE); 144 return 0; 145 } 146 if (!FreeLibrary(*p)) { 147 ERR_raise(ERR_LIB_DSO, DSO_R_UNLOAD_FAILED); 148 /* 149 * We should push the value back onto the stack in case of a retry. 150 */ 151 sk_void_push(dso->meth_data, p); 152 return 0; 153 } 154 /* Cleanup */ 155 OPENSSL_free(p); 156 return 1; 157 } 158 159 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname) 160 { 161 HINSTANCE *ptr; 162 union { 163 void *p; 164 FARPROC f; 165 } sym; 166 167 if ((dso == NULL) || (symname == NULL)) { 168 ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); 169 return NULL; 170 } 171 if (sk_void_num(dso->meth_data) < 1) { 172 ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR); 173 return NULL; 174 } 175 ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1); 176 if (ptr == NULL) { 177 ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE); 178 return NULL; 179 } 180 sym.f = GetProcAddress(*ptr, symname); 181 if (sym.p == NULL) { 182 ERR_raise_data(ERR_LIB_DSO, DSO_R_SYM_FAILURE, "symname(%s)", symname); 183 return NULL; 184 } 185 return (DSO_FUNC_TYPE)sym.f; 186 } 187 188 struct file_st { 189 const char *node; 190 int nodelen; 191 const char *device; 192 int devicelen; 193 const char *predir; 194 int predirlen; 195 const char *dir; 196 int dirlen; 197 const char *file; 198 int filelen; 199 }; 200 201 static struct file_st *win32_splitter(DSO *dso, const char *filename, 202 int assume_last_is_dir) 203 { 204 struct file_st *result = NULL; 205 enum { IN_NODE, IN_DEVICE, IN_FILE } position; 206 const char *start = filename; 207 char last; 208 209 if (!filename) { 210 ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); 211 return NULL; 212 } 213 214 result = OPENSSL_zalloc(sizeof(*result)); 215 if (result == NULL) 216 return NULL; 217 218 position = IN_DEVICE; 219 220 if ((filename[0] == '\\' && filename[1] == '\\') 221 || (filename[0] == '/' && filename[1] == '/')) { 222 position = IN_NODE; 223 filename += 2; 224 start = filename; 225 result->node = start; 226 } 227 228 do { 229 last = filename[0]; 230 switch (last) { 231 case ':': 232 if (position != IN_DEVICE) { 233 ERR_raise(ERR_LIB_DSO, DSO_R_INCORRECT_FILE_SYNTAX); 234 OPENSSL_free(result); 235 return NULL; 236 } 237 result->device = start; 238 result->devicelen = (int)(filename - start); 239 position = IN_FILE; 240 start = ++filename; 241 result->dir = start; 242 break; 243 case '\\': 244 case '/': 245 if (position == IN_NODE) { 246 result->nodelen = (int)(filename - start); 247 position = IN_FILE; 248 start = ++filename; 249 result->dir = start; 250 } else if (position == IN_DEVICE) { 251 position = IN_FILE; 252 filename++; 253 result->dir = start; 254 result->dirlen = (int)(filename - start); 255 start = filename; 256 } else { 257 filename++; 258 result->dirlen += (int)(filename - start); 259 start = filename; 260 } 261 break; 262 case '\0': 263 if (position == IN_NODE) { 264 result->nodelen = (int)(filename - start); 265 } else { 266 if (filename - start > 0) { 267 if (assume_last_is_dir) { 268 if (position == IN_DEVICE) { 269 result->dir = start; 270 result->dirlen = 0; 271 } 272 result->dirlen += (int)(filename - start); 273 } else { 274 result->file = start; 275 result->filelen = (int)(filename - start); 276 } 277 } 278 } 279 break; 280 default: 281 filename++; 282 break; 283 } 284 } 285 while (last); 286 287 if (!result->nodelen) 288 result->node = NULL; 289 if (!result->devicelen) 290 result->device = NULL; 291 if (!result->dirlen) 292 result->dir = NULL; 293 if (!result->filelen) 294 result->file = NULL; 295 296 return result; 297 } 298 299 static char *win32_joiner(DSO *dso, const struct file_st *file_split) 300 { 301 int len = 0, offset = 0; 302 char *result = NULL; 303 const char *start; 304 305 if (!file_split) { 306 ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); 307 return NULL; 308 } 309 if (file_split->node) { 310 len += 2 + file_split->nodelen; /* 2 for starting \\ */ 311 if (file_split->predir || file_split->dir || file_split->file) 312 len++; /* 1 for ending \ */ 313 } else if (file_split->device) { 314 len += file_split->devicelen + 1; /* 1 for ending : */ 315 } 316 len += file_split->predirlen; 317 if (file_split->predir && (file_split->dir || file_split->file)) { 318 len++; /* 1 for ending \ */ 319 } 320 len += file_split->dirlen; 321 if (file_split->dir && file_split->file) { 322 len++; /* 1 for ending \ */ 323 } 324 len += file_split->filelen; 325 326 if (!len) { 327 ERR_raise(ERR_LIB_DSO, DSO_R_EMPTY_FILE_STRUCTURE); 328 return NULL; 329 } 330 331 result = OPENSSL_malloc(len + 1); 332 if (result == NULL) 333 return NULL; 334 335 if (file_split->node) { 336 strcpy(&result[offset], "\\\\"); 337 offset += 2; 338 strncpy(&result[offset], file_split->node, file_split->nodelen); 339 offset += file_split->nodelen; 340 if (file_split->predir || file_split->dir || file_split->file) { 341 result[offset] = '\\'; 342 offset++; 343 } 344 } else if (file_split->device) { 345 strncpy(&result[offset], file_split->device, file_split->devicelen); 346 offset += file_split->devicelen; 347 result[offset] = ':'; 348 offset++; 349 } 350 start = file_split->predir; 351 while (file_split->predirlen > (start - file_split->predir)) { 352 const char *end = openssl_strnchr(start, '/', 353 file_split->predirlen - (start - 354 file_split->predir)); 355 if (!end) 356 end = start 357 + file_split->predirlen - (start - file_split->predir); 358 strncpy(&result[offset], start, end - start); 359 offset += (int)(end - start); 360 result[offset] = '\\'; 361 offset++; 362 start = end + 1; 363 } 364 start = file_split->dir; 365 while (file_split->dirlen > (start - file_split->dir)) { 366 const char *end = openssl_strnchr(start, '/', 367 file_split->dirlen - (start - 368 file_split->dir)); 369 if (!end) 370 end = start + file_split->dirlen - (start - file_split->dir); 371 strncpy(&result[offset], start, end - start); 372 offset += (int)(end - start); 373 result[offset] = '\\'; 374 offset++; 375 start = end + 1; 376 } 377 strncpy(&result[offset], file_split->file, file_split->filelen); 378 offset += file_split->filelen; 379 result[offset] = '\0'; 380 return result; 381 } 382 383 static char *win32_merger(DSO *dso, const char *filespec1, 384 const char *filespec2) 385 { 386 char *merged = NULL; 387 struct file_st *filespec1_split = NULL; 388 struct file_st *filespec2_split = NULL; 389 390 if (!filespec1 && !filespec2) { 391 ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); 392 return NULL; 393 } 394 if (!filespec2) { 395 merged = OPENSSL_strdup(filespec1); 396 if (merged == NULL) 397 return NULL; 398 } else if (!filespec1) { 399 merged = OPENSSL_strdup(filespec2); 400 if (merged == NULL) 401 return NULL; 402 } else { 403 filespec1_split = win32_splitter(dso, filespec1, 0); 404 if (!filespec1_split) { 405 ERR_raise(ERR_LIB_DSO, ERR_R_DSO_LIB); 406 return NULL; 407 } 408 filespec2_split = win32_splitter(dso, filespec2, 1); 409 if (!filespec2_split) { 410 ERR_raise(ERR_LIB_DSO, ERR_R_DSO_LIB); 411 OPENSSL_free(filespec1_split); 412 return NULL; 413 } 414 415 /* Fill in into filespec1_split */ 416 if (!filespec1_split->node && !filespec1_split->device) { 417 filespec1_split->node = filespec2_split->node; 418 filespec1_split->nodelen = filespec2_split->nodelen; 419 filespec1_split->device = filespec2_split->device; 420 filespec1_split->devicelen = filespec2_split->devicelen; 421 } 422 if (!filespec1_split->dir) { 423 filespec1_split->dir = filespec2_split->dir; 424 filespec1_split->dirlen = filespec2_split->dirlen; 425 } else if (filespec1_split->dir[0] != '\\' 426 && filespec1_split->dir[0] != '/') { 427 filespec1_split->predir = filespec2_split->dir; 428 filespec1_split->predirlen = filespec2_split->dirlen; 429 } 430 if (!filespec1_split->file) { 431 filespec1_split->file = filespec2_split->file; 432 filespec1_split->filelen = filespec2_split->filelen; 433 } 434 435 merged = win32_joiner(dso, filespec1_split); 436 } 437 OPENSSL_free(filespec1_split); 438 OPENSSL_free(filespec2_split); 439 return merged; 440 } 441 442 static char *win32_name_converter(DSO *dso, const char *filename) 443 { 444 char *translated; 445 int len, transform; 446 447 transform = ((strstr(filename, "/") == NULL) && 448 (strstr(filename, "\\") == NULL) && 449 (strstr(filename, ":") == NULL)); 450 /* If transform != 0, then we convert to %s.dll, else just dupe filename */ 451 452 len = strlen(filename) + 1; 453 if (transform) 454 len += strlen(".dll"); 455 translated = OPENSSL_malloc(len); 456 if (translated == NULL) { 457 ERR_raise(ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED); 458 return NULL; 459 } 460 BIO_snprintf(translated, len, "%s%s", filename, transform ? ".dll" : ""); 461 return translated; 462 } 463 464 static const char *openssl_strnchr(const char *string, int c, size_t len) 465 { 466 size_t i; 467 const char *p; 468 for (i = 0, p = string; i < len && *p; i++, p++) { 469 if (*p == c) 470 return p; 471 } 472 return NULL; 473 } 474 475 # include <tlhelp32.h> 476 # ifdef _WIN32_WCE 477 # define DLLNAME "TOOLHELP.DLL" 478 # else 479 # ifdef MODULEENTRY32 480 # undef MODULEENTRY32 /* unmask the ASCII version! */ 481 # endif 482 # define DLLNAME "KERNEL32.DLL" 483 # endif 484 485 typedef HANDLE(WINAPI *CREATETOOLHELP32SNAPSHOT) (DWORD, DWORD); 486 typedef BOOL(WINAPI *CLOSETOOLHELP32SNAPSHOT) (HANDLE); 487 typedef BOOL(WINAPI *MODULE32) (HANDLE, MODULEENTRY32 *); 488 489 static int win32_pathbyaddr(void *addr, char *path, int sz) 490 { 491 HMODULE dll; 492 HANDLE hModuleSnap = INVALID_HANDLE_VALUE; 493 MODULEENTRY32 me32; 494 CREATETOOLHELP32SNAPSHOT create_snap; 495 CLOSETOOLHELP32SNAPSHOT close_snap; 496 MODULE32 module_first, module_next; 497 498 if (addr == NULL) { 499 union { 500 int (*f) (void *, char *, int); 501 void *p; 502 } t = { 503 win32_pathbyaddr 504 }; 505 addr = t.p; 506 } 507 508 dll = LoadLibrary(TEXT(DLLNAME)); 509 if (dll == NULL) { 510 ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); 511 return -1; 512 } 513 514 create_snap = (CREATETOOLHELP32SNAPSHOT) 515 GetProcAddress(dll, "CreateToolhelp32Snapshot"); 516 if (create_snap == NULL) { 517 FreeLibrary(dll); 518 ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); 519 return -1; 520 } 521 /* We take the rest for granted... */ 522 # ifdef _WIN32_WCE 523 close_snap = (CLOSETOOLHELP32SNAPSHOT) 524 GetProcAddress(dll, "CloseToolhelp32Snapshot"); 525 # else 526 close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle; 527 # endif 528 module_first = (MODULE32) GetProcAddress(dll, "Module32First"); 529 module_next = (MODULE32) GetProcAddress(dll, "Module32Next"); 530 531 /* 532 * Take a snapshot of current process which includes 533 * list of all involved modules. 534 */ 535 hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0); 536 if (hModuleSnap == INVALID_HANDLE_VALUE) { 537 FreeLibrary(dll); 538 ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); 539 return -1; 540 } 541 542 me32.dwSize = sizeof(me32); 543 544 if (!(*module_first) (hModuleSnap, &me32)) { 545 (*close_snap) (hModuleSnap); 546 FreeLibrary(dll); 547 ERR_raise(ERR_LIB_DSO, DSO_R_FAILURE); 548 return -1; 549 } 550 551 /* Enumerate the modules to find one which includes me. */ 552 do { 553 if ((size_t) addr >= (size_t) me32.modBaseAddr && 554 (size_t) addr < (size_t) (me32.modBaseAddr + me32.modBaseSize)) { 555 (*close_snap) (hModuleSnap); 556 FreeLibrary(dll); 557 # ifdef _WIN32_WCE 558 # if _WIN32_WCE >= 101 559 return WideCharToMultiByte(CP_ACP, 0, me32.szExePath, -1, 560 path, sz, NULL, NULL); 561 # else 562 { 563 int i, len = (int)wcslen(me32.szExePath); 564 if (sz <= 0) 565 return len + 1; 566 if (len >= sz) 567 len = sz - 1; 568 for (i = 0; i < len; i++) 569 path[i] = (char)me32.szExePath[i]; 570 path[len++] = '\0'; 571 return len; 572 } 573 # endif 574 # else 575 { 576 int len = (int)strlen(me32.szExePath); 577 if (sz <= 0) 578 return len + 1; 579 if (len >= sz) 580 len = sz - 1; 581 memcpy(path, me32.szExePath, len); 582 path[len++] = '\0'; 583 return len; 584 } 585 # endif 586 } 587 } while ((*module_next) (hModuleSnap, &me32)); 588 589 (*close_snap) (hModuleSnap); 590 FreeLibrary(dll); 591 return 0; 592 } 593 594 static void *win32_globallookup(const char *name) 595 { 596 HMODULE dll; 597 HANDLE hModuleSnap = INVALID_HANDLE_VALUE; 598 MODULEENTRY32 me32; 599 CREATETOOLHELP32SNAPSHOT create_snap; 600 CLOSETOOLHELP32SNAPSHOT close_snap; 601 MODULE32 module_first, module_next; 602 union { 603 void *p; 604 FARPROC f; 605 } ret = { NULL }; 606 607 dll = LoadLibrary(TEXT(DLLNAME)); 608 if (dll == NULL) { 609 ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); 610 return NULL; 611 } 612 613 create_snap = (CREATETOOLHELP32SNAPSHOT) 614 GetProcAddress(dll, "CreateToolhelp32Snapshot"); 615 if (create_snap == NULL) { 616 FreeLibrary(dll); 617 ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); 618 return NULL; 619 } 620 /* We take the rest for granted... */ 621 # ifdef _WIN32_WCE 622 close_snap = (CLOSETOOLHELP32SNAPSHOT) 623 GetProcAddress(dll, "CloseToolhelp32Snapshot"); 624 # else 625 close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle; 626 # endif 627 module_first = (MODULE32) GetProcAddress(dll, "Module32First"); 628 module_next = (MODULE32) GetProcAddress(dll, "Module32Next"); 629 630 hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0); 631 if (hModuleSnap == INVALID_HANDLE_VALUE) { 632 FreeLibrary(dll); 633 ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); 634 return NULL; 635 } 636 637 me32.dwSize = sizeof(me32); 638 639 if (!(*module_first) (hModuleSnap, &me32)) { 640 (*close_snap) (hModuleSnap); 641 FreeLibrary(dll); 642 return NULL; 643 } 644 645 do { 646 if ((ret.f = GetProcAddress(me32.hModule, name))) { 647 (*close_snap) (hModuleSnap); 648 FreeLibrary(dll); 649 return ret.p; 650 } 651 } while ((*module_next) (hModuleSnap, &me32)); 652 653 (*close_snap) (hModuleSnap); 654 FreeLibrary(dll); 655 return NULL; 656 } 657 #endif /* DSO_WIN32 */ 658