/* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */ /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL * project 2000. */ /* ==================================================================== * Copyright (c) 2000 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * licensing@OpenSSL.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include #include #include "cryptlib.h" #include #if !defined(DSO_WIN32) DSO_METHOD *DSO_METHOD_win32(void) { return NULL; } #else #ifdef _WIN32_WCE # if _WIN32_WCE < 300 static FARPROC GetProcAddressA(HMODULE hModule,LPCSTR lpProcName) { WCHAR lpProcNameW[64]; int i; for (i=0;lpProcName[i] && i<64;i++) lpProcNameW[i] = (WCHAR)lpProcName[i]; if (i==64) return NULL; lpProcNameW[i] = 0; return GetProcAddressW(hModule,lpProcNameW); } # endif # undef GetProcAddress # define GetProcAddress GetProcAddressA static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName) { WCHAR *fnamw; size_t len_0=strlen(lpLibFileName)+1,i; #ifdef _MSC_VER fnamw = (WCHAR *)_alloca (len_0*sizeof(WCHAR)); #else fnamw = (WCHAR *)alloca (len_0*sizeof(WCHAR)); #endif if (fnamw == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } #if defined(_WIN32_WCE) && _WIN32_WCE>=101 if (!MultiByteToWideChar(CP_ACP,0,lpLibFileName,len_0,fnamw,len_0)) #endif for (i=0;imeth_data, p)) { DSOerr(DSO_F_WIN32_LOAD,DSO_R_STACK_ERROR); goto err; } /* Success */ dso->loaded_filename = filename; return(1); err: /* Cleanup !*/ if(filename != NULL) OPENSSL_free(filename); if(p != NULL) OPENSSL_free(p); if(h != NULL) FreeLibrary(h); return(0); } static int win32_unload(DSO *dso) { HINSTANCE *p; if(dso == NULL) { DSOerr(DSO_F_WIN32_UNLOAD,ERR_R_PASSED_NULL_PARAMETER); return(0); } if(sk_void_num(dso->meth_data) < 1) return(1); p = sk_void_pop(dso->meth_data); if(p == NULL) { DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_NULL_HANDLE); return(0); } if(!FreeLibrary(*p)) { DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_UNLOAD_FAILED); /* We should push the value back onto the stack in * case of a retry. */ sk_void_push(dso->meth_data, p); return(0); } /* Cleanup */ OPENSSL_free(p); return(1); } /* Using GetProcAddress for variables? TODO: Check this out in * the Win32 API docs, there's probably a variant for variables. */ static void *win32_bind_var(DSO *dso, const char *symname) { HINSTANCE *ptr; void *sym; if((dso == NULL) || (symname == NULL)) { DSOerr(DSO_F_WIN32_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER); return(NULL); } if(sk_void_num(dso->meth_data) < 1) { DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_STACK_ERROR); return(NULL); } ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1); if(ptr == NULL) { DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_NULL_HANDLE); return(NULL); } sym = GetProcAddress(*ptr, symname); if(sym == NULL) { DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_SYM_FAILURE); ERR_add_error_data(3, "symname(", symname, ")"); return(NULL); } return(sym); } static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname) { HINSTANCE *ptr; void *sym; if((dso == NULL) || (symname == NULL)) { DSOerr(DSO_F_WIN32_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER); return(NULL); } if(sk_void_num(dso->meth_data) < 1) { DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_STACK_ERROR); return(NULL); } ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1); if(ptr == NULL) { DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_NULL_HANDLE); return(NULL); } sym = GetProcAddress(*ptr, symname); if(sym == NULL) { DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_SYM_FAILURE); ERR_add_error_data(3, "symname(", symname, ")"); return(NULL); } return((DSO_FUNC_TYPE)sym); } struct file_st { const char *node; int nodelen; const char *device; int devicelen; const char *predir; int predirlen; const char *dir; int dirlen; const char *file; int filelen; }; static struct file_st *win32_splitter(DSO *dso, const char *filename, int assume_last_is_dir) { struct file_st *result = NULL; enum { IN_NODE, IN_DEVICE, IN_FILE } position; const char *start = filename; char last; if (!filename) { DSOerr(DSO_F_WIN32_SPLITTER,DSO_R_NO_FILENAME); /*goto err;*/ return(NULL); } result = OPENSSL_malloc(sizeof(struct file_st)); if(result == NULL) { DSOerr(DSO_F_WIN32_SPLITTER, ERR_R_MALLOC_FAILURE); return(NULL); } memset(result, 0, sizeof(struct file_st)); position = IN_DEVICE; if((filename[0] == '\\' && filename[1] == '\\') || (filename[0] == '/' && filename[1] == '/')) { position = IN_NODE; filename += 2; start = filename; result->node = start; } do { last = filename[0]; switch(last) { case ':': if(position != IN_DEVICE) { DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_INCORRECT_FILE_SYNTAX); /*goto err;*/ OPENSSL_free(result); return(NULL); } result->device = start; result->devicelen = (int)(filename - start); position = IN_FILE; start = ++filename; result->dir = start; break; case '\\': case '/': if(position == IN_NODE) { result->nodelen = (int)(filename - start); position = IN_FILE; start = ++filename; result->dir = start; } else if(position == IN_DEVICE) { position = IN_FILE; filename++; result->dir = start; result->dirlen = (int)(filename - start); start = filename; } else { filename++; result->dirlen += (int)(filename - start); start = filename; } break; case '\0': if(position == IN_NODE) { result->nodelen = (int)(filename - start); } else { if(filename - start > 0) { if (assume_last_is_dir) { if (position == IN_DEVICE) { result->dir = start; result->dirlen = 0; } result->dirlen += (int)(filename - start); } else { result->file = start; result->filelen = (int)(filename - start); } } } break; default: filename++; break; } } while(last); if(!result->nodelen) result->node = NULL; if(!result->devicelen) result->device = NULL; if(!result->dirlen) result->dir = NULL; if(!result->filelen) result->file = NULL; return(result); } static char *win32_joiner(DSO *dso, const struct file_st *file_split) { int len = 0, offset = 0; char *result = NULL; const char *start; if(!file_split) { DSOerr(DSO_F_WIN32_JOINER, ERR_R_PASSED_NULL_PARAMETER); return(NULL); } if(file_split->node) { len += 2 + file_split->nodelen; /* 2 for starting \\ */ if(file_split->predir || file_split->dir || file_split->file) len++; /* 1 for ending \ */ } else if(file_split->device) { len += file_split->devicelen + 1; /* 1 for ending : */ } len += file_split->predirlen; if(file_split->predir && (file_split->dir || file_split->file)) { len++; /* 1 for ending \ */ } len += file_split->dirlen; if(file_split->dir && file_split->file) { len++; /* 1 for ending \ */ } len += file_split->filelen; if(!len) { DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE); return(NULL); } result = OPENSSL_malloc(len + 1); if (!result) { DSOerr(DSO_F_WIN32_JOINER, ERR_R_MALLOC_FAILURE); return(NULL); } if(file_split->node) { strcpy(&result[offset], "\\\\"); offset += 2; strncpy(&result[offset], file_split->node, file_split->nodelen); offset += file_split->nodelen; if(file_split->predir || file_split->dir || file_split->file) { result[offset] = '\\'; offset++; } } else if(file_split->device) { strncpy(&result[offset], file_split->device, file_split->devicelen); offset += file_split->devicelen; result[offset] = ':'; offset++; } start = file_split->predir; while(file_split->predirlen > (start - file_split->predir)) { const char *end = openssl_strnchr(start, '/', file_split->predirlen - (start - file_split->predir)); if(!end) end = start + file_split->predirlen - (start - file_split->predir); strncpy(&result[offset], start, end - start); offset += (int)(end - start); result[offset] = '\\'; offset++; start = end + 1; } #if 0 /* Not needed, since the directory converter above already appeneded a backslash */ if(file_split->predir && (file_split->dir || file_split->file)) { result[offset] = '\\'; offset++; } #endif start = file_split->dir; while(file_split->dirlen > (start - file_split->dir)) { const char *end = openssl_strnchr(start, '/', file_split->dirlen - (start - file_split->dir)); if(!end) end = start + file_split->dirlen - (start - file_split->dir); strncpy(&result[offset], start, end - start); offset += (int)(end - start); result[offset] = '\\'; offset++; start = end + 1; } #if 0 /* Not needed, since the directory converter above already appeneded a backslash */ if(file_split->dir && file_split->file) { result[offset] = '\\'; offset++; } #endif strncpy(&result[offset], file_split->file, file_split->filelen); offset += file_split->filelen; result[offset] = '\0'; return(result); } static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2) { char *merged = NULL; struct file_st *filespec1_split = NULL; struct file_st *filespec2_split = NULL; if(!filespec1 && !filespec2) { DSOerr(DSO_F_WIN32_MERGER, ERR_R_PASSED_NULL_PARAMETER); return(NULL); } if (!filespec2) { merged = OPENSSL_malloc(strlen(filespec1) + 1); if(!merged) { DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE); return(NULL); } strcpy(merged, filespec1); } else if (!filespec1) { merged = OPENSSL_malloc(strlen(filespec2) + 1); if(!merged) { DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE); return(NULL); } strcpy(merged, filespec2); } else { filespec1_split = win32_splitter(dso, filespec1, 0); if (!filespec1_split) { DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE); return(NULL); } filespec2_split = win32_splitter(dso, filespec2, 1); if (!filespec2_split) { DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE); OPENSSL_free(filespec1_split); return(NULL); } /* Fill in into filespec1_split */ if (!filespec1_split->node && !filespec1_split->device) { filespec1_split->node = filespec2_split->node; filespec1_split->nodelen = filespec2_split->nodelen; filespec1_split->device = filespec2_split->device; filespec1_split->devicelen = filespec2_split->devicelen; } if (!filespec1_split->dir) { filespec1_split->dir = filespec2_split->dir; filespec1_split->dirlen = filespec2_split->dirlen; } else if (filespec1_split->dir[0] != '\\' && filespec1_split->dir[0] != '/') { filespec1_split->predir = filespec2_split->dir; filespec1_split->predirlen = filespec2_split->dirlen; } if (!filespec1_split->file) { filespec1_split->file = filespec2_split->file; filespec1_split->filelen = filespec2_split->filelen; } merged = win32_joiner(dso, filespec1_split); } OPENSSL_free(filespec1_split); OPENSSL_free(filespec2_split); return(merged); } static char *win32_name_converter(DSO *dso, const char *filename) { char *translated; int len, transform; len = strlen(filename); transform = ((strstr(filename, "/") == NULL) && (strstr(filename, "\\") == NULL) && (strstr(filename, ":") == NULL)); if(transform) /* We will convert this to "%s.dll" */ translated = OPENSSL_malloc(len + 5); else /* We will simply duplicate filename */ translated = OPENSSL_malloc(len + 1); if(translated == NULL) { DSOerr(DSO_F_WIN32_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED); return(NULL); } if(transform) sprintf(translated, "%s.dll", filename); else sprintf(translated, "%s", filename); return(translated); } static const char *openssl_strnchr(const char *string, int c, size_t len) { size_t i; const char *p; for (i = 0, p = string; i < len && *p; i++, p++) { if (*p == c) return p; } return NULL; } #include #ifdef _WIN32_WCE # define DLLNAME "TOOLHELP.DLL" #else # ifdef MODULEENTRY32 # undef MODULEENTRY32 /* unmask the ASCII version! */ # endif # define DLLNAME "KERNEL32.DLL" #endif typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD); typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE); typedef BOOL (WINAPI *MODULE32)(HANDLE, MODULEENTRY32 *); static int win32_pathbyaddr(void *addr,char *path,int sz) { HMODULE dll; HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; CREATETOOLHELP32SNAPSHOT create_snap; CLOSETOOLHELP32SNAPSHOT close_snap; MODULE32 module_first, module_next; int len; if (addr == NULL) { union { int(*f)(void*,char*,int); void *p; } t = { win32_pathbyaddr }; addr = t.p; } dll = LoadLibrary(TEXT(DLLNAME)); if (dll == NULL) { DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_UNSUPPORTED); return -1; } create_snap = (CREATETOOLHELP32SNAPSHOT) GetProcAddress(dll,"CreateToolhelp32Snapshot"); if (create_snap == NULL) { FreeLibrary(dll); DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_UNSUPPORTED); return -1; } /* We take the rest for granted... */ #ifdef _WIN32_WCE close_snap = (CLOSETOOLHELP32SNAPSHOT) GetProcAddress(dll,"CloseToolhelp32Snapshot"); #else close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle; #endif module_first = (MODULE32)GetProcAddress(dll,"Module32First"); module_next = (MODULE32)GetProcAddress(dll,"Module32Next"); hModuleSnap = (*create_snap)(TH32CS_SNAPMODULE,0); if( hModuleSnap == INVALID_HANDLE_VALUE ) { FreeLibrary(dll); DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_UNSUPPORTED); return -1; } me32.dwSize = sizeof(me32); if(!(*module_first)(hModuleSnap,&me32)) { (*close_snap)(hModuleSnap); FreeLibrary(dll); DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_FAILURE); return -1; } do { if ((BYTE *)addr >= me32.modBaseAddr && (BYTE *)addr < me32.modBaseAddr+me32.modBaseSize) { (*close_snap)(hModuleSnap); FreeLibrary(dll); #ifdef _WIN32_WCE # if _WIN32_WCE >= 101 return WideCharToMultiByte(CP_ACP,0,me32.szExePath,-1, path,sz,NULL,NULL); # else len = (int)wcslen(me32.szExePath); if (sz <= 0) return len+1; if (len >= sz) len=sz-1; for(i=0;i= sz) len=sz-1; memcpy(path,me32.szExePath,len); path[len++] = 0; return len; #endif } } while((*module_next)(hModuleSnap, &me32)); (*close_snap)(hModuleSnap); FreeLibrary(dll); return 0; } static void *win32_globallookup(const char *name) { HMODULE dll; HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; CREATETOOLHELP32SNAPSHOT create_snap; CLOSETOOLHELP32SNAPSHOT close_snap; MODULE32 module_first, module_next; FARPROC ret=NULL; dll = LoadLibrary(TEXT(DLLNAME)); if (dll == NULL) { DSOerr(DSO_F_WIN32_GLOBALLOOKUP,DSO_R_UNSUPPORTED); return NULL; } create_snap = (CREATETOOLHELP32SNAPSHOT) GetProcAddress(dll,"CreateToolhelp32Snapshot"); if (create_snap == NULL) { FreeLibrary(dll); DSOerr(DSO_F_WIN32_GLOBALLOOKUP,DSO_R_UNSUPPORTED); return NULL; } /* We take the rest for granted... */ #ifdef _WIN32_WCE close_snap = (CLOSETOOLHELP32SNAPSHOT) GetProcAddress(dll,"CloseToolhelp32Snapshot"); #else close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle; #endif module_first = (MODULE32)GetProcAddress(dll,"Module32First"); module_next = (MODULE32)GetProcAddress(dll,"Module32Next"); hModuleSnap = (*create_snap)(TH32CS_SNAPMODULE,0); if( hModuleSnap == INVALID_HANDLE_VALUE ) { FreeLibrary(dll); DSOerr(DSO_F_WIN32_GLOBALLOOKUP,DSO_R_UNSUPPORTED); return NULL; } me32.dwSize = sizeof(me32); if (!(*module_first)(hModuleSnap,&me32)) { (*close_snap)(hModuleSnap); FreeLibrary(dll); return NULL; } do { if ((ret = GetProcAddress(me32.hModule,name))) { (*close_snap)(hModuleSnap); FreeLibrary(dll); return ret; } } while((*module_next)(hModuleSnap,&me32)); (*close_snap)(hModuleSnap); FreeLibrary(dll); return NULL; } #endif /* DSO_WIN32 */