2 * Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
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
11 #include "dso_local.h"
13 #if defined(DSO_WIN32)
17 static FARPROC
GetProcAddressA(HMODULE hModule
, LPCSTR lpProcName
)
19 WCHAR lpProcNameW
[64];
22 for (i
= 0; lpProcName
[i
] && i
< 64; i
++)
23 lpProcNameW
[i
] = (WCHAR
)lpProcName
[i
];
28 return GetProcAddressW(hModule
, lpProcNameW
);
31 # undef GetProcAddress
32 # define GetProcAddress GetProcAddressA
34 static HINSTANCE
LoadLibraryA(LPCSTR lpLibFileName
)
37 size_t len_0
= strlen(lpLibFileName
) + 1, i
;
40 fnamw
= (WCHAR
*)_alloca(len_0
* sizeof(WCHAR
));
42 fnamw
= (WCHAR
*)alloca(len_0
* sizeof(WCHAR
));
45 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
48 # if defined(_WIN32_WCE) && _WIN32_WCE>=101
49 if (!MultiByteToWideChar(CP_ACP
, 0, lpLibFileName
, len_0
, fnamw
, len_0
))
51 for (i
= 0; i
< len_0
; i
++)
52 fnamw
[i
] = (WCHAR
)lpLibFileName
[i
];
54 return LoadLibraryW(fnamw
);
58 /* Part of the hack in "win32_load" ... */
59 # define DSO_MAX_TRANSLATED_SIZE 256
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
);
70 static const char *openssl_strnchr(const char *string
, int c
, size_t len
);
74 static DSO_METHOD dso_meth_win32
= {
75 "OpenSSL 'win32' shared library method",
84 win32_pathbyaddr
, /* pathbyaddr */
88 DSO_METHOD
*DSO_METHOD_openssl(void)
90 return &dso_meth_win32
;
94 * For this DSO_METHOD, our meth_data STACK will contain; (i) a pointer to
95 * the handle (HINSTANCE) returned from LoadLibrary(), and copied.
98 static int win32_load(DSO
*dso
)
100 HINSTANCE h
= NULL
, *p
= NULL
;
101 /* See applicable comments from dso_dl.c */
102 char *filename
= DSO_convert_filename(dso
, NULL
);
104 if (filename
== NULL
) {
105 DSOerr(DSO_F_WIN32_LOAD
, DSO_R_NO_FILENAME
);
108 h
= LoadLibraryA(filename
);
110 DSOerr(DSO_F_WIN32_LOAD
, DSO_R_LOAD_FAILED
);
111 ERR_add_error_data(3, "filename(", filename
, ")");
114 p
= OPENSSL_malloc(sizeof(*p
));
116 DSOerr(DSO_F_WIN32_LOAD
, ERR_R_MALLOC_FAILURE
);
120 if (!sk_void_push(dso
->meth_data
, p
)) {
121 DSOerr(DSO_F_WIN32_LOAD
, DSO_R_STACK_ERROR
);
125 dso
->loaded_filename
= filename
;
129 OPENSSL_free(filename
);
136 static int win32_unload(DSO
*dso
)
140 DSOerr(DSO_F_WIN32_UNLOAD
, ERR_R_PASSED_NULL_PARAMETER
);
143 if (sk_void_num(dso
->meth_data
) < 1)
145 p
= sk_void_pop(dso
->meth_data
);
147 DSOerr(DSO_F_WIN32_UNLOAD
, DSO_R_NULL_HANDLE
);
150 if (!FreeLibrary(*p
)) {
151 DSOerr(DSO_F_WIN32_UNLOAD
, DSO_R_UNLOAD_FAILED
);
153 * We should push the value back onto the stack in case of a retry.
155 sk_void_push(dso
->meth_data
, p
);
163 static DSO_FUNC_TYPE
win32_bind_func(DSO
*dso
, const char *symname
)
171 if ((dso
== NULL
) || (symname
== NULL
)) {
172 DSOerr(DSO_F_WIN32_BIND_FUNC
, ERR_R_PASSED_NULL_PARAMETER
);
175 if (sk_void_num(dso
->meth_data
) < 1) {
176 DSOerr(DSO_F_WIN32_BIND_FUNC
, DSO_R_STACK_ERROR
);
179 ptr
= sk_void_value(dso
->meth_data
, sk_void_num(dso
->meth_data
) - 1);
181 DSOerr(DSO_F_WIN32_BIND_FUNC
, DSO_R_NULL_HANDLE
);
184 sym
.f
= GetProcAddress(*ptr
, symname
);
186 DSOerr(DSO_F_WIN32_BIND_FUNC
, DSO_R_SYM_FAILURE
);
187 ERR_add_error_data(3, "symname(", symname
, ")");
190 return (DSO_FUNC_TYPE
)sym
.f
;
206 static struct file_st
*win32_splitter(DSO
*dso
, const char *filename
,
207 int assume_last_is_dir
)
209 struct file_st
*result
= NULL
;
210 enum { IN_NODE
, IN_DEVICE
, IN_FILE
} position
;
211 const char *start
= filename
;
215 DSOerr(DSO_F_WIN32_SPLITTER
, DSO_R_NO_FILENAME
);
219 result
= OPENSSL_zalloc(sizeof(*result
));
220 if (result
== NULL
) {
221 DSOerr(DSO_F_WIN32_SPLITTER
, ERR_R_MALLOC_FAILURE
);
225 position
= IN_DEVICE
;
227 if ((filename
[0] == '\\' && filename
[1] == '\\')
228 || (filename
[0] == '/' && filename
[1] == '/')) {
232 result
->node
= start
;
239 if (position
!= IN_DEVICE
) {
240 DSOerr(DSO_F_WIN32_SPLITTER
, DSO_R_INCORRECT_FILE_SYNTAX
);
241 OPENSSL_free(result
);
244 result
->device
= start
;
245 result
->devicelen
= (int)(filename
- start
);
252 if (position
== IN_NODE
) {
253 result
->nodelen
= (int)(filename
- start
);
257 } else if (position
== IN_DEVICE
) {
261 result
->dirlen
= (int)(filename
- start
);
265 result
->dirlen
+= (int)(filename
- start
);
270 if (position
== IN_NODE
) {
271 result
->nodelen
= (int)(filename
- start
);
273 if (filename
- start
> 0) {
274 if (assume_last_is_dir
) {
275 if (position
== IN_DEVICE
) {
279 result
->dirlen
+= (int)(filename
- start
);
281 result
->file
= start
;
282 result
->filelen
= (int)(filename
- start
);
294 if (!result
->nodelen
)
296 if (!result
->devicelen
)
297 result
->device
= NULL
;
300 if (!result
->filelen
)
306 static char *win32_joiner(DSO
*dso
, const struct file_st
*file_split
)
308 int len
= 0, offset
= 0;
313 DSOerr(DSO_F_WIN32_JOINER
, ERR_R_PASSED_NULL_PARAMETER
);
316 if (file_split
->node
) {
317 len
+= 2 + file_split
->nodelen
; /* 2 for starting \\ */
318 if (file_split
->predir
|| file_split
->dir
|| file_split
->file
)
319 len
++; /* 1 for ending \ */
320 } else if (file_split
->device
) {
321 len
+= file_split
->devicelen
+ 1; /* 1 for ending : */
323 len
+= file_split
->predirlen
;
324 if (file_split
->predir
&& (file_split
->dir
|| file_split
->file
)) {
325 len
++; /* 1 for ending \ */
327 len
+= file_split
->dirlen
;
328 if (file_split
->dir
&& file_split
->file
) {
329 len
++; /* 1 for ending \ */
331 len
+= file_split
->filelen
;
334 DSOerr(DSO_F_WIN32_JOINER
, DSO_R_EMPTY_FILE_STRUCTURE
);
338 result
= OPENSSL_malloc(len
+ 1);
339 if (result
== NULL
) {
340 DSOerr(DSO_F_WIN32_JOINER
, ERR_R_MALLOC_FAILURE
);
344 if (file_split
->node
) {
345 strcpy(&result
[offset
], "\\\\");
347 strncpy(&result
[offset
], file_split
->node
, file_split
->nodelen
);
348 offset
+= file_split
->nodelen
;
349 if (file_split
->predir
|| file_split
->dir
|| file_split
->file
) {
350 result
[offset
] = '\\';
353 } else if (file_split
->device
) {
354 strncpy(&result
[offset
], file_split
->device
, file_split
->devicelen
);
355 offset
+= file_split
->devicelen
;
356 result
[offset
] = ':';
359 start
= file_split
->predir
;
360 while (file_split
->predirlen
> (start
- file_split
->predir
)) {
361 const char *end
= openssl_strnchr(start
, '/',
362 file_split
->predirlen
- (start
-
363 file_split
->predir
));
366 + file_split
->predirlen
- (start
- file_split
->predir
);
367 strncpy(&result
[offset
], start
, end
- start
);
368 offset
+= (int)(end
- start
);
369 result
[offset
] = '\\';
373 start
= file_split
->dir
;
374 while (file_split
->dirlen
> (start
- file_split
->dir
)) {
375 const char *end
= openssl_strnchr(start
, '/',
376 file_split
->dirlen
- (start
-
379 end
= start
+ file_split
->dirlen
- (start
- file_split
->dir
);
380 strncpy(&result
[offset
], start
, end
- start
);
381 offset
+= (int)(end
- start
);
382 result
[offset
] = '\\';
386 strncpy(&result
[offset
], file_split
->file
, file_split
->filelen
);
387 offset
+= file_split
->filelen
;
388 result
[offset
] = '\0';
392 static char *win32_merger(DSO
*dso
, const char *filespec1
,
393 const char *filespec2
)
396 struct file_st
*filespec1_split
= NULL
;
397 struct file_st
*filespec2_split
= NULL
;
399 if (!filespec1
&& !filespec2
) {
400 DSOerr(DSO_F_WIN32_MERGER
, ERR_R_PASSED_NULL_PARAMETER
);
404 merged
= OPENSSL_strdup(filespec1
);
405 if (merged
== NULL
) {
406 DSOerr(DSO_F_WIN32_MERGER
, ERR_R_MALLOC_FAILURE
);
409 } else if (!filespec1
) {
410 merged
= OPENSSL_strdup(filespec2
);
411 if (merged
== NULL
) {
412 DSOerr(DSO_F_WIN32_MERGER
, ERR_R_MALLOC_FAILURE
);
416 filespec1_split
= win32_splitter(dso
, filespec1
, 0);
417 if (!filespec1_split
) {
418 DSOerr(DSO_F_WIN32_MERGER
, ERR_R_MALLOC_FAILURE
);
421 filespec2_split
= win32_splitter(dso
, filespec2
, 1);
422 if (!filespec2_split
) {
423 DSOerr(DSO_F_WIN32_MERGER
, ERR_R_MALLOC_FAILURE
);
424 OPENSSL_free(filespec1_split
);
428 /* Fill in into filespec1_split */
429 if (!filespec1_split
->node
&& !filespec1_split
->device
) {
430 filespec1_split
->node
= filespec2_split
->node
;
431 filespec1_split
->nodelen
= filespec2_split
->nodelen
;
432 filespec1_split
->device
= filespec2_split
->device
;
433 filespec1_split
->devicelen
= filespec2_split
->devicelen
;
435 if (!filespec1_split
->dir
) {
436 filespec1_split
->dir
= filespec2_split
->dir
;
437 filespec1_split
->dirlen
= filespec2_split
->dirlen
;
438 } else if (filespec1_split
->dir
[0] != '\\'
439 && filespec1_split
->dir
[0] != '/') {
440 filespec1_split
->predir
= filespec2_split
->dir
;
441 filespec1_split
->predirlen
= filespec2_split
->dirlen
;
443 if (!filespec1_split
->file
) {
444 filespec1_split
->file
= filespec2_split
->file
;
445 filespec1_split
->filelen
= filespec2_split
->filelen
;
448 merged
= win32_joiner(dso
, filespec1_split
);
450 OPENSSL_free(filespec1_split
);
451 OPENSSL_free(filespec2_split
);
455 static char *win32_name_converter(DSO
*dso
, const char *filename
)
460 len
= strlen(filename
);
461 transform
= ((strstr(filename
, "/") == NULL
) &&
462 (strstr(filename
, "\\") == NULL
) &&
463 (strstr(filename
, ":") == NULL
));
465 /* We will convert this to "%s.dll" */
466 translated
= OPENSSL_malloc(len
+ 5);
468 /* We will simply duplicate filename */
469 translated
= OPENSSL_malloc(len
+ 1);
470 if (translated
== NULL
) {
471 DSOerr(DSO_F_WIN32_NAME_CONVERTER
, DSO_R_NAME_TRANSLATION_FAILED
);
475 sprintf(translated
, "%s.dll", filename
);
477 sprintf(translated
, "%s", filename
);
481 static const char *openssl_strnchr(const char *string
, int c
, size_t len
)
485 for (i
= 0, p
= string
; i
< len
&& *p
; i
++, p
++) {
492 # include <tlhelp32.h>
494 # define DLLNAME "TOOLHELP.DLL"
496 # ifdef MODULEENTRY32
497 # undef MODULEENTRY32 /* unmask the ASCII version! */
499 # define DLLNAME "KERNEL32.DLL"
502 typedef HANDLE(WINAPI
*CREATETOOLHELP32SNAPSHOT
) (DWORD
, DWORD
);
503 typedef BOOL(WINAPI
*CLOSETOOLHELP32SNAPSHOT
) (HANDLE
);
504 typedef BOOL(WINAPI
*MODULE32
) (HANDLE
, MODULEENTRY32
*);
506 static int win32_pathbyaddr(void *addr
, char *path
, int sz
)
509 HANDLE hModuleSnap
= INVALID_HANDLE_VALUE
;
511 CREATETOOLHELP32SNAPSHOT create_snap
;
512 CLOSETOOLHELP32SNAPSHOT close_snap
;
513 MODULE32 module_first
, module_next
;
517 int (*f
) (void *, char *, int);
525 dll
= LoadLibrary(TEXT(DLLNAME
));
527 DSOerr(DSO_F_WIN32_PATHBYADDR
, DSO_R_UNSUPPORTED
);
531 create_snap
= (CREATETOOLHELP32SNAPSHOT
)
532 GetProcAddress(dll
, "CreateToolhelp32Snapshot");
533 if (create_snap
== NULL
) {
535 DSOerr(DSO_F_WIN32_PATHBYADDR
, DSO_R_UNSUPPORTED
);
538 /* We take the rest for granted... */
540 close_snap
= (CLOSETOOLHELP32SNAPSHOT
)
541 GetProcAddress(dll
, "CloseToolhelp32Snapshot");
543 close_snap
= (CLOSETOOLHELP32SNAPSHOT
) CloseHandle
;
545 module_first
= (MODULE32
) GetProcAddress(dll
, "Module32First");
546 module_next
= (MODULE32
) GetProcAddress(dll
, "Module32Next");
549 * Take a snapshot of current process which includes
550 * list of all involved modules.
552 hModuleSnap
= (*create_snap
) (TH32CS_SNAPMODULE
, 0);
553 if (hModuleSnap
== INVALID_HANDLE_VALUE
) {
555 DSOerr(DSO_F_WIN32_PATHBYADDR
, DSO_R_UNSUPPORTED
);
559 me32
.dwSize
= sizeof(me32
);
561 if (!(*module_first
) (hModuleSnap
, &me32
)) {
562 (*close_snap
) (hModuleSnap
);
564 DSOerr(DSO_F_WIN32_PATHBYADDR
, DSO_R_FAILURE
);
568 /* Enumerate the modules to find one which includes me. */
570 if ((uintptr_t) addr
>= (uintptr_t) me32
.modBaseAddr
&&
571 (uintptr_t) addr
< (uintptr_t) (me32
.modBaseAddr
+ me32
.modBaseSize
)) {
572 (*close_snap
) (hModuleSnap
);
575 # if _WIN32_WCE >= 101
576 return WideCharToMultiByte(CP_ACP
, 0, me32
.szExePath
, -1,
577 path
, sz
, NULL
, NULL
);
580 int i
, len
= (int)wcslen(me32
.szExePath
);
585 for (i
= 0; i
< len
; i
++)
586 path
[i
] = (char)me32
.szExePath
[i
];
593 int len
= (int)strlen(me32
.szExePath
);
598 memcpy(path
, me32
.szExePath
, len
);
604 } while ((*module_next
) (hModuleSnap
, &me32
));
606 (*close_snap
) (hModuleSnap
);
611 static void *win32_globallookup(const char *name
)
614 HANDLE hModuleSnap
= INVALID_HANDLE_VALUE
;
616 CREATETOOLHELP32SNAPSHOT create_snap
;
617 CLOSETOOLHELP32SNAPSHOT close_snap
;
618 MODULE32 module_first
, module_next
;
624 dll
= LoadLibrary(TEXT(DLLNAME
));
626 DSOerr(DSO_F_WIN32_GLOBALLOOKUP
, DSO_R_UNSUPPORTED
);
630 create_snap
= (CREATETOOLHELP32SNAPSHOT
)
631 GetProcAddress(dll
, "CreateToolhelp32Snapshot");
632 if (create_snap
== NULL
) {
634 DSOerr(DSO_F_WIN32_GLOBALLOOKUP
, DSO_R_UNSUPPORTED
);
637 /* We take the rest for granted... */
639 close_snap
= (CLOSETOOLHELP32SNAPSHOT
)
640 GetProcAddress(dll
, "CloseToolhelp32Snapshot");
642 close_snap
= (CLOSETOOLHELP32SNAPSHOT
) CloseHandle
;
644 module_first
= (MODULE32
) GetProcAddress(dll
, "Module32First");
645 module_next
= (MODULE32
) GetProcAddress(dll
, "Module32Next");
647 hModuleSnap
= (*create_snap
) (TH32CS_SNAPMODULE
, 0);
648 if (hModuleSnap
== INVALID_HANDLE_VALUE
) {
650 DSOerr(DSO_F_WIN32_GLOBALLOOKUP
, DSO_R_UNSUPPORTED
);
654 me32
.dwSize
= sizeof(me32
);
656 if (!(*module_first
) (hModuleSnap
, &me32
)) {
657 (*close_snap
) (hModuleSnap
);
663 if ((ret
.f
= GetProcAddress(me32
.hModule
, name
))) {
664 (*close_snap
) (hModuleSnap
);
668 } while ((*module_next
) (hModuleSnap
, &me32
));
670 (*close_snap
) (hModuleSnap
);
674 #endif /* DSO_WIN32 */