FreeRDP
Loading...
Searching...
No Matches
library.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23#include <winpr/platform.h>
24
25#include <winpr/library.h>
26
27#include "../log.h"
28#define TAG WINPR_TAG("library")
29
65#if (!defined(_WIN32) && !defined(__CYGWIN__)) || defined(_UWP)
66
67#ifndef _WIN32
68
69#include <dlfcn.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <unistd.h>
73#include <sys/types.h>
74#include <sys/stat.h>
75
76#ifdef __MACOSX__
77#include <mach-o/dyld.h>
78#endif
79
80#if defined(__FreeBSD__)
81#include <sys/sysctl.h>
82#endif
83
84#if defined(__OpenBSD__)
85#include <errno.h>
86#endif
87
88#endif
89
90DLL_DIRECTORY_COOKIE AddDllDirectory(WINPR_ATTR_UNUSED PCWSTR NewDirectory)
91{
92 /* TODO: Implement */
93 WLog_ERR(TAG, "not implemented");
94 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
95 return nullptr;
96}
97
98BOOL RemoveDllDirectory(WINPR_ATTR_UNUSED DLL_DIRECTORY_COOKIE Cookie)
99{
100 /* TODO: Implement */
101 WLog_ERR(TAG, "not implemented");
102 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
103 return FALSE;
104}
105
106BOOL SetDefaultDllDirectories(WINPR_ATTR_UNUSED DWORD DirectoryFlags)
107{
108 /* TODO: Implement */
109 WLog_ERR(TAG, "not implemented");
110 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
111 return FALSE;
112}
113
114HMODULE LoadLibraryA(LPCSTR lpLibFileName)
115{
116 if (!lpLibFileName)
117 return nullptr;
118
119#if defined(_UWP)
120 int status;
121 HMODULE hModule = nullptr;
122 WCHAR* filenameW = nullptr;
123
124 filenameW = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
125 if (filenameW)
126 return nullptr;
127
128 hModule = LoadLibraryW(filenameW);
129 free(filenameW);
130 return hModule;
131#else
132 HMODULE library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY);
133
134 if (!library)
135 {
136 // NOLINTNEXTLINE(concurrency-mt-unsafe)
137 const char* err = dlerror();
138 WLog_VRB(TAG, "failed with %s", err);
139 return nullptr;
140 }
141
142 return library;
143#endif
144}
145
146HMODULE LoadLibraryW(LPCWSTR lpLibFileName)
147{
148#if defined(_UWP)
149 return LoadPackagedLibrary(lpLibFileName, 0);
150#else
151 char* name = nullptr;
152
153 if (lpLibFileName)
154 name = ConvertWCharToUtf8Alloc(lpLibFileName, nullptr);
155
156 HMODULE module = LoadLibraryA(name);
157 free(name);
158 return module;
159#endif
160}
161
162HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
163{
164 if (dwFlags != 0)
165 WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
166
167 if (hFile)
168 WLog_WARN(TAG, "does not support hFile != nullptr");
169
170 return LoadLibraryA(lpLibFileName);
171}
172
173HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
174{
175 if (dwFlags != 0)
176 WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
177
178 if (hFile)
179 WLog_WARN(TAG, "does not support hFile != nullptr");
180
181 return LoadLibraryW(lpLibFileName);
182}
183
184#endif
185
186#if !defined(_WIN32) && !defined(__CYGWIN__)
187
188FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
189{
190 FARPROC proc = nullptr;
191 proc = dlsym(hModule, lpProcName);
192
193 if (proc == nullptr)
194 {
195 // NOLINTNEXTLINE(concurrency-mt-unsafe)
196 WLog_ERR(TAG, "GetProcAddress: could not find procedure %s: %s", lpProcName, dlerror());
197 return (FARPROC) nullptr;
198 }
199
200 return proc;
201}
202
203BOOL FreeLibrary(HMODULE hLibModule)
204{
205 int status = 0;
206 status = dlclose(hLibModule);
207
208 return (status == 0);
209}
210
211HMODULE GetModuleHandleA(LPCSTR lpModuleName)
212{
213 return dlopen(lpModuleName, RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
214}
215
216HMODULE GetModuleHandleW(LPCWSTR lpModuleName)
217{
218 char* name = nullptr;
219 if (lpModuleName)
220 name = ConvertWCharToUtf8Alloc(lpModuleName, nullptr);
221 HANDLE hdl = GetModuleHandleA(name);
222 free(name);
223 return hdl;
224}
225
234DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize)
235{
236 DWORD status = 0;
237 if (!lpFilename)
238 {
239 SetLastError(ERROR_INTERNAL_ERROR);
240 return 0;
241 }
242
243 char* name = calloc(nSize, sizeof(char));
244 if (!name)
245 {
246 SetLastError(ERROR_INTERNAL_ERROR);
247 return 0;
248 }
249 status = GetModuleFileNameA(hModule, name, nSize);
250
251 if ((status > INT_MAX) || (nSize > INT_MAX))
252 {
253 SetLastError(ERROR_INTERNAL_ERROR);
254 status = 0;
255 }
256
257 if (status > 0)
258 {
259 if (ConvertUtf8NToWChar(name, status, lpFilename, nSize) < 0)
260 {
261 free(name);
262 SetLastError(ERROR_INTERNAL_ERROR);
263 return 0;
264 }
265 }
266
267 free(name);
268 return status;
269}
270
271#if defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__)
272static DWORD module_from_proc(const char* proc, LPSTR lpFilename, DWORD nSize)
273{
274 char buffer[8192] = WINPR_C_ARRAY_INIT;
275 ssize_t status = readlink(proc, buffer, ARRAYSIZE(buffer) - 1);
276
277 if ((status < 0) || ((size_t)status >= ARRAYSIZE(buffer)))
278 {
279 SetLastError(ERROR_INTERNAL_ERROR);
280 return 0;
281 }
282
283 const size_t length = strnlen(buffer, ARRAYSIZE(buffer));
284
285 if (length < nSize)
286 {
287 CopyMemory(lpFilename, buffer, length);
288 lpFilename[length] = '\0';
289 return (DWORD)length;
290 }
291
292 CopyMemory(lpFilename, buffer, nSize - 1);
293 lpFilename[nSize - 1] = '\0';
294 SetLastError(ERROR_INSUFFICIENT_BUFFER);
295 return nSize;
296}
297#endif
298
299#if defined(__FreeBSD__)
300WINPR_ATTR_NODISCARD
301static DWORD freebsd_get_module_file_name(char* lpFilename, uint32_t nSize)
302{
303 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
304 size_t cb = nSize;
305
306 {
307 const int rc = sysctl(mib, ARRAYSIZE(mib), nullptr, &cb, nullptr, 0);
308 if (rc != 0)
309 {
310 SetLastError(ERROR_INTERNAL_ERROR);
311 return 0;
312 }
313 }
314
315 char* fullname = calloc(cb + 1, sizeof(char));
316 if (!fullname)
317 {
318 SetLastError(ERROR_INTERNAL_ERROR);
319 return 0;
320 }
321
322 {
323 size_t cb2 = cb;
324 const int rc = sysctl(mib, ARRAYSIZE(mib), fullname, &cb2, nullptr, 0);
325 if ((rc != 0) || (cb2 != cb))
326 {
327 SetLastError(ERROR_INTERNAL_ERROR);
328 free(fullname);
329 return 0;
330 }
331 }
332
333 if (nSize > 0)
334 {
335 strncpy(lpFilename, fullname, nSize - 1);
336 lpFilename[nSize - 1] = '\0';
337 }
338 free(fullname);
339
340 if (nSize < cb)
341 SetLastError(ERROR_INSUFFICIENT_BUFFER);
342
343 return (DWORD)MIN(nSize, cb);
344}
345#endif
346
347#if defined(__MACOSX__)
348WINPR_ATTR_NODISCARD
349static uint32_t get_required_size(void)
350{
351 char buffer[1] = WINPR_C_ARRAY_INIT;
352 uint32_t size = sizeof(buffer);
353 if (_NSGetExecutablePath(buffer, &size) == 0)
354 return sizeof(buffer);
355 return size;
356}
357
358WINPR_ATTR_NODISCARD
359static DWORD mac_get_module_file_name(char* lpFilename, uint32_t nSize)
360{
361 const uint32_t required = get_required_size();
362 if (required == 0)
363 return 0;
364
365 if (required < nSize)
366 {
367 uint32_t size = nSize;
368 if (_NSGetExecutablePath(lpFilename, &size) == 0)
369 return (DWORD)strnlen(lpFilename, nSize);
370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
371 return nSize;
372 }
373
374 char* buffer = calloc(1ull + required, sizeof(char));
375 if (!buffer)
376 {
377 SetLastError(ERROR_OUTOFMEMORY);
378 return 0;
379 }
380
381 uint32_t size = required;
382 const int status = _NSGetExecutablePath(buffer, &size);
383
384 if (status != 0)
385 {
386 /* path too small */
387 SetLastError(ERROR_INSUFFICIENT_BUFFER);
388 free(buffer);
389 return size;
390 }
391
392 /*
393 * _NSGetExecutablePath may not return the canonical path,
394 * so use realpath to find the absolute, canonical path.
395 */
396 char* real = realpath(buffer, nullptr);
397 free(buffer);
398 if (!real)
399 {
400 SetLastError(ERROR_OUTOFMEMORY);
401 return 0;
402 }
403 const size_t length = strlen(real);
404 if (length < nSize)
405 {
406 strncpy(lpFilename, real, length + 1);
407 free(real);
408 return (DWORD)strnlen(lpFilename, nSize);
409 }
410
411 strncpy(lpFilename, real, nSize - 1);
412 free(real);
413 lpFilename[nSize - 1] = '\0';
414 SetLastError(ERROR_INSUFFICIENT_BUFFER);
415 return nSize;
416}
417#endif
418
419#if defined(__OpenBSD__)
420WINPR_ATTR_NODISCARD
421static DWORD openbsd_get_module_file_name(char* lpFilename, uint32_t nSize)
422{
423#ifdef WITH_GETEXECPATH
424 size_t size = nSize + 1ull;
425 char* path = calloc(1, size);
426
427 if (path == nullptr)
428 {
429 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
430 return 0;
431 }
432
433 while (getexecpath(path, size) != 0)
434 {
435 if (errno != ERANGE)
436 {
437 free(path);
438 SetLastError(ERROR_INTERNAL_ERROR);
439 return 0;
440 }
441
442 size += PATH_MAX;
443
444 char* tmp = realloc(path, size);
445
446 if (tmp == nullptr)
447 {
448 free(path);
449 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
450 return 0;
451 }
452
453 path = tmp;
454 }
455
456 const size_t length = strnlen(path, size);
457
458 memset(lpFilename, 0, nSize);
459 memcpy(lpFilename, path, MIN(length, nSize));
460
461 free(path);
462
463 if (length >= nSize)
464 {
465 SetLastError(ERROR_INSUFFICIENT_BUFFER);
466 return nSize;
467 }
468
469 return WINPR_ASSERTING_INT_CAST(DWORD, length);
470#else
471 WLog_ERR(TAG, "is not implemented");
472 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
473 return 0;
474#endif
475}
476#endif
477
478DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
479{
480 if (hModule)
481 {
482 WLog_ERR(TAG, "is not implemented");
483 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
484 return 0;
485 }
486
487#if defined(__linux__)
488 return module_from_proc("/proc/self/exe", lpFilename, nSize);
489#elif defined(__FreeBSD__)
490 return freebsd_get_module_file_name(lpFilename, nSize);
491#elif defined(__NetBSD__)
492 return module_from_proc("/proc/curproc/exe", lpFilename, nSize);
493#elif defined(__DragonFly__)
494 return module_from_proc("/proc/curproc/file", lpFilename, nSize);
495#elif defined(__MACOSX__)
496 return mac_get_module_file_name(lpFilename, nSize);
497#elif defined(__OpenBSD__)
498 return openbsd_get_module_file_name(lpFilename, nSize);
499#else
500 WLog_ERR(TAG, "is not implemented");
501 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
502 return 0;
503#endif
504}
505
506#endif
507
508HMODULE LoadLibraryX(LPCSTR lpLibFileName)
509{
510#if defined(_WIN32)
511 HMODULE hm = nullptr;
512 WCHAR* wstr = nullptr;
513
514 if (lpLibFileName)
515 wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
516
517 hm = LoadLibraryW(wstr);
518 free(wstr);
519 return hm;
520#else
521 return LoadLibraryA(lpLibFileName);
522#endif
523}
524
525HMODULE LoadLibraryExX(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
526{
527 if (!lpLibFileName)
528 return nullptr;
529#if defined(_WIN32)
530 HMODULE hm = nullptr;
531 WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
532 if (wstr)
533 hm = LoadLibraryExW(wstr, hFile, dwFlags);
534 free(wstr);
535 return hm;
536#else
537 return LoadLibraryExA(lpLibFileName, hFile, dwFlags);
538#endif
539}