424 lines
8.9 KiB
C
424 lines
8.9 KiB
C
/**
|
|
* WinPR: Windows Portable Runtime
|
|
* Library Loader
|
|
*
|
|
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <winpr/config.h>
|
|
|
|
#include <winpr/crt.h>
|
|
#include <winpr/platform.h>
|
|
|
|
#include <winpr/library.h>
|
|
|
|
#include "../log.h"
|
|
#define TAG WINPR_TAG("library")
|
|
|
|
/**
|
|
* api-ms-win-core-libraryloader-l1-1-1.dll:
|
|
*
|
|
* AddDllDirectory
|
|
* RemoveDllDirectory
|
|
* SetDefaultDllDirectories
|
|
* DisableThreadLibraryCalls
|
|
* EnumResourceLanguagesExA
|
|
* EnumResourceLanguagesExW
|
|
* EnumResourceNamesExA
|
|
* EnumResourceNamesExW
|
|
* EnumResourceTypesExA
|
|
* EnumResourceTypesExW
|
|
* FindResourceExW
|
|
* FindStringOrdinal
|
|
* FreeLibrary
|
|
* FreeLibraryAndExitThread
|
|
* FreeResource
|
|
* GetModuleFileNameA
|
|
* GetModuleFileNameW
|
|
* GetModuleHandleA
|
|
* GetModuleHandleExA
|
|
* GetModuleHandleExW
|
|
* GetModuleHandleW
|
|
* GetProcAddress
|
|
* LoadLibraryExA
|
|
* LoadLibraryExW
|
|
* LoadResource
|
|
* LoadStringA
|
|
* LoadStringW
|
|
* LockResource
|
|
* QueryOptionalDelayLoadedAPI
|
|
* SizeofResource
|
|
*/
|
|
|
|
#if !defined(_WIN32) || defined(_UWP)
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <dlfcn.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef __MACOSX__
|
|
#include <mach-o/dyld.h>
|
|
#endif
|
|
|
|
#if defined(__FreeBSD__)
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
|
|
#endif
|
|
|
|
DLL_DIRECTORY_COOKIE AddDllDirectory(WINPR_ATTR_UNUSED PCWSTR NewDirectory)
|
|
{
|
|
/* TODO: Implement */
|
|
WLog_ERR(TAG, "not implemented");
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return nullptr;
|
|
}
|
|
|
|
BOOL RemoveDllDirectory(WINPR_ATTR_UNUSED DLL_DIRECTORY_COOKIE Cookie)
|
|
{
|
|
/* TODO: Implement */
|
|
WLog_ERR(TAG, "not implemented");
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL SetDefaultDllDirectories(WINPR_ATTR_UNUSED DWORD DirectoryFlags)
|
|
{
|
|
/* TODO: Implement */
|
|
WLog_ERR(TAG, "not implemented");
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
HMODULE LoadLibraryA(LPCSTR lpLibFileName)
|
|
{
|
|
if (!lpLibFileName)
|
|
return nullptr;
|
|
|
|
#if defined(_UWP)
|
|
int status;
|
|
HMODULE hModule = nullptr;
|
|
WCHAR* filenameW = nullptr;
|
|
|
|
filenameW = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
|
|
if (filenameW)
|
|
return nullptr;
|
|
|
|
hModule = LoadLibraryW(filenameW);
|
|
free(filenameW);
|
|
return hModule;
|
|
#else
|
|
HMODULE library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY);
|
|
|
|
if (!library)
|
|
{
|
|
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
|
const char* err = dlerror();
|
|
WLog_ERR(TAG, "failed with %s", err);
|
|
return nullptr;
|
|
}
|
|
|
|
return library;
|
|
#endif
|
|
}
|
|
|
|
HMODULE LoadLibraryW(LPCWSTR lpLibFileName)
|
|
{
|
|
#if defined(_UWP)
|
|
return LoadPackagedLibrary(lpLibFileName, 0);
|
|
#else
|
|
char* name = nullptr;
|
|
|
|
if (lpLibFileName)
|
|
name = ConvertWCharToUtf8Alloc(lpLibFileName, nullptr);
|
|
|
|
HMODULE module = LoadLibraryA(name);
|
|
free(name);
|
|
return module;
|
|
#endif
|
|
}
|
|
|
|
HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
|
|
{
|
|
if (dwFlags != 0)
|
|
WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
|
|
|
|
if (hFile)
|
|
WLog_WARN(TAG, "does not support hFile != nullptr");
|
|
|
|
return LoadLibraryA(lpLibFileName);
|
|
}
|
|
|
|
HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
|
|
{
|
|
if (dwFlags != 0)
|
|
WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
|
|
|
|
if (hFile)
|
|
WLog_WARN(TAG, "does not support hFile != nullptr");
|
|
|
|
return LoadLibraryW(lpLibFileName);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if !defined(_WIN32) && !defined(__CYGWIN__)
|
|
|
|
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
|
|
{
|
|
FARPROC proc = nullptr;
|
|
proc = dlsym(hModule, lpProcName);
|
|
|
|
if (proc == nullptr)
|
|
{
|
|
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
|
WLog_ERR(TAG, "GetProcAddress: could not find procedure %s: %s", lpProcName, dlerror());
|
|
return (FARPROC) nullptr;
|
|
}
|
|
|
|
return proc;
|
|
}
|
|
|
|
BOOL FreeLibrary(HMODULE hLibModule)
|
|
{
|
|
int status = 0;
|
|
status = dlclose(hLibModule);
|
|
|
|
return (status == 0);
|
|
}
|
|
|
|
HMODULE GetModuleHandleA(LPCSTR lpModuleName)
|
|
{
|
|
return dlopen(lpModuleName, RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
|
|
}
|
|
|
|
HMODULE GetModuleHandleW(LPCWSTR lpModuleName)
|
|
{
|
|
char* name = nullptr;
|
|
if (lpModuleName)
|
|
name = ConvertWCharToUtf8Alloc(lpModuleName, nullptr);
|
|
HANDLE hdl = GetModuleHandleA(name);
|
|
free(name);
|
|
return hdl;
|
|
}
|
|
|
|
/**
|
|
* GetModuleFileName:
|
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms683197/
|
|
*
|
|
* Finding current executable's path without /proc/self/exe:
|
|
* http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
|
|
*/
|
|
|
|
DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize)
|
|
{
|
|
DWORD status = 0;
|
|
if (!lpFilename)
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
char* name = calloc(nSize, sizeof(char));
|
|
if (!name)
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
status = GetModuleFileNameA(hModule, name, nSize);
|
|
|
|
if ((status > INT_MAX) || (nSize > INT_MAX))
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
status = 0;
|
|
}
|
|
|
|
if (status > 0)
|
|
{
|
|
if (ConvertUtf8NToWChar(name, status, lpFilename, nSize) < 0)
|
|
{
|
|
free(name);
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
free(name);
|
|
return status;
|
|
}
|
|
|
|
#if defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__)
|
|
static DWORD module_from_proc(const char* proc, LPSTR lpFilename, DWORD nSize)
|
|
{
|
|
char buffer[8192] = WINPR_C_ARRAY_INIT;
|
|
ssize_t status = readlink(proc, buffer, ARRAYSIZE(buffer) - 1);
|
|
|
|
if ((status < 0) || ((size_t)status >= ARRAYSIZE(buffer)))
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
const size_t length = strnlen(buffer, ARRAYSIZE(buffer));
|
|
|
|
if (length < nSize)
|
|
{
|
|
CopyMemory(lpFilename, buffer, length);
|
|
lpFilename[length] = '\0';
|
|
return (DWORD)length;
|
|
}
|
|
|
|
CopyMemory(lpFilename, buffer, nSize - 1);
|
|
lpFilename[nSize - 1] = '\0';
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return nSize;
|
|
}
|
|
#endif
|
|
|
|
DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
|
|
{
|
|
if (hModule)
|
|
{
|
|
WLog_ERR(TAG, "is not implemented");
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(__linux__)
|
|
return module_from_proc("/proc/self/exe", lpFilename, nSize);
|
|
#elif defined(__FreeBSD__)
|
|
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
size_t cb = nSize;
|
|
|
|
{
|
|
const int rc = sysctl(mib, ARRAYSIZE(mib), nullptr, &cb, nullptr, 0);
|
|
if (rc != 0)
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
char* fullname = calloc(cb + 1, sizeof(char));
|
|
if (!fullname)
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
{
|
|
size_t cb2 = cb;
|
|
const int rc = sysctl(mib, ARRAYSIZE(mib), fullname, &cb2, nullptr, 0);
|
|
if ((rc != 0) || (cb2 != cb))
|
|
{
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
free(fullname);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (nSize > 0)
|
|
{
|
|
strncpy(lpFilename, fullname, nSize - 1);
|
|
lpFilename[nSize - 1] = '\0';
|
|
}
|
|
free(fullname);
|
|
|
|
if (nSize < cb)
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return (DWORD)MIN(nSize, cb);
|
|
#elif defined(__NetBSD__)
|
|
return module_from_proc("/proc/curproc/exe", lpFilename, nSize);
|
|
#elif defined(__DragonFly__)
|
|
return module_from_proc("/proc/curproc/file", lpFilename, nSize);
|
|
#elif defined(__MACOSX__)
|
|
char path[4096] = WINPR_C_ARRAY_INIT;
|
|
char buffer[4096] = WINPR_C_ARRAY_INIT;
|
|
uint32_t size = sizeof(path);
|
|
const int status = _NSGetExecutablePath(path, &size);
|
|
|
|
if (status != 0)
|
|
{
|
|
/* path too small */
|
|
SetLastError(ERROR_INTERNAL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* _NSGetExecutablePath may not return the canonical path,
|
|
* so use realpath to find the absolute, canonical path.
|
|
*/
|
|
realpath(path, buffer);
|
|
const size_t length = strnlen(buffer, sizeof(buffer));
|
|
|
|
if (length < nSize)
|
|
{
|
|
CopyMemory(lpFilename, buffer, length);
|
|
lpFilename[length] = '\0';
|
|
return (DWORD)length;
|
|
}
|
|
|
|
CopyMemory(lpFilename, buffer, nSize - 1);
|
|
lpFilename[nSize - 1] = '\0';
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return nSize;
|
|
#else
|
|
WLog_ERR(TAG, "is not implemented");
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
HMODULE LoadLibraryX(LPCSTR lpLibFileName)
|
|
{
|
|
#if defined(_WIN32)
|
|
HMODULE hm = nullptr;
|
|
WCHAR* wstr = nullptr;
|
|
|
|
if (lpLibFileName)
|
|
wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
|
|
|
|
hm = LoadLibraryW(wstr);
|
|
free(wstr);
|
|
return hm;
|
|
#else
|
|
return LoadLibraryA(lpLibFileName);
|
|
#endif
|
|
}
|
|
|
|
HMODULE LoadLibraryExX(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
|
|
{
|
|
if (!lpLibFileName)
|
|
return nullptr;
|
|
#if defined(_WIN32)
|
|
HMODULE hm = nullptr;
|
|
WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
|
|
if (wstr)
|
|
hm = LoadLibraryExW(wstr, hFile, dwFlags);
|
|
free(wstr);
|
|
return hm;
|
|
#else
|
|
return LoadLibraryExA(lpLibFileName, hFile, dwFlags);
|
|
#endif
|
|
}
|