Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/winpr/libwinpr/library/library.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Library Loader
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
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
30
/**
31
 * api-ms-win-core-libraryloader-l1-1-1.dll:
32
 *
33
 * AddDllDirectory
34
 * RemoveDllDirectory
35
 * SetDefaultDllDirectories
36
 * DisableThreadLibraryCalls
37
 * EnumResourceLanguagesExA
38
 * EnumResourceLanguagesExW
39
 * EnumResourceNamesExA
40
 * EnumResourceNamesExW
41
 * EnumResourceTypesExA
42
 * EnumResourceTypesExW
43
 * FindResourceExW
44
 * FindStringOrdinal
45
 * FreeLibrary
46
 * FreeLibraryAndExitThread
47
 * FreeResource
48
 * GetModuleFileNameA
49
 * GetModuleFileNameW
50
 * GetModuleHandleA
51
 * GetModuleHandleExA
52
 * GetModuleHandleExW
53
 * GetModuleHandleW
54
 * GetProcAddress
55
 * LoadLibraryExA
56
 * LoadLibraryExW
57
 * LoadResource
58
 * LoadStringA
59
 * LoadStringW
60
 * LockResource
61
 * QueryOptionalDelayLoadedAPI
62
 * SizeofResource
63
 */
64
65
#if !defined(_WIN32) || 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
#endif
85
86
DLL_DIRECTORY_COOKIE AddDllDirectory(WINPR_ATTR_UNUSED PCWSTR NewDirectory)
87
0
{
88
  /* TODO: Implement */
89
0
  WLog_ERR(TAG, "not implemented");
90
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
91
0
  return NULL;
92
0
}
93
94
BOOL RemoveDllDirectory(WINPR_ATTR_UNUSED DLL_DIRECTORY_COOKIE Cookie)
95
0
{
96
  /* TODO: Implement */
97
0
  WLog_ERR(TAG, "not implemented");
98
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
99
0
  return FALSE;
100
0
}
101
102
BOOL SetDefaultDllDirectories(WINPR_ATTR_UNUSED DWORD DirectoryFlags)
103
0
{
104
  /* TODO: Implement */
105
0
  WLog_ERR(TAG, "not implemented");
106
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
107
0
  return FALSE;
108
0
}
109
110
HMODULE LoadLibraryA(LPCSTR lpLibFileName)
111
0
{
112
#if defined(_UWP)
113
  int status;
114
  HMODULE hModule = NULL;
115
  WCHAR* filenameW = NULL;
116
117
  if (!lpLibFileName)
118
    return NULL;
119
120
  filenameW = ConvertUtf8ToWCharAlloc(lpLibFileName, NULL);
121
  if (filenameW)
122
    return NULL;
123
124
  hModule = LoadLibraryW(filenameW);
125
  free(filenameW);
126
  return hModule;
127
#else
128
0
  HMODULE library = NULL;
129
0
  library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY);
130
131
0
  if (!library)
132
0
  {
133
    // NOLINTNEXTLINE(concurrency-mt-unsafe)
134
0
    const char* err = dlerror();
135
0
    WLog_ERR(TAG, "failed with %s", err);
136
0
    return NULL;
137
0
  }
138
139
0
  return library;
140
0
#endif
141
0
}
142
143
HMODULE LoadLibraryW(LPCWSTR lpLibFileName)
144
0
{
145
0
  if (!lpLibFileName)
146
0
    return NULL;
147
#if defined(_UWP)
148
  return LoadPackagedLibrary(lpLibFileName, 0);
149
#else
150
0
  HMODULE module = NULL;
151
0
  char* name = ConvertWCharToUtf8Alloc(lpLibFileName, NULL);
152
0
  if (!name)
153
0
    return NULL;
154
155
0
  module = LoadLibraryA(name);
156
0
  free(name);
157
0
  return module;
158
0
#endif
159
0
}
160
161
HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
162
0
{
163
0
  if (dwFlags != 0)
164
0
    WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
165
166
0
  if (hFile)
167
0
    WLog_WARN(TAG, "does not support hFile != NULL");
168
169
0
  return LoadLibraryA(lpLibFileName);
170
0
}
171
172
HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
173
0
{
174
0
  if (dwFlags != 0)
175
0
    WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
176
177
0
  if (hFile)
178
0
    WLog_WARN(TAG, "does not support hFile != NULL");
179
180
0
  return LoadLibraryW(lpLibFileName);
181
0
}
182
183
#endif
184
185
#if !defined(_WIN32) && !defined(__CYGWIN__)
186
187
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
188
0
{
189
0
  FARPROC proc = NULL;
190
0
  proc = dlsym(hModule, lpProcName);
191
192
0
  if (proc == NULL)
193
0
  {
194
    // NOLINTNEXTLINE(concurrency-mt-unsafe)
195
0
    WLog_ERR(TAG, "GetProcAddress: could not find procedure %s: %s", lpProcName, dlerror());
196
0
    return (FARPROC)NULL;
197
0
  }
198
199
0
  return proc;
200
0
}
201
202
BOOL FreeLibrary(HMODULE hLibModule)
203
0
{
204
0
  int status = 0;
205
0
  status = dlclose(hLibModule);
206
207
0
  if (status != 0)
208
0
    return FALSE;
209
210
0
  return TRUE;
211
0
}
212
213
HMODULE GetModuleHandleA(WINPR_ATTR_UNUSED LPCSTR lpModuleName)
214
0
{
215
  /* TODO: Implement */
216
0
  WLog_ERR(TAG, "not implemented");
217
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
218
0
  return NULL;
219
0
}
220
221
HMODULE GetModuleHandleW(WINPR_ATTR_UNUSED LPCWSTR lpModuleName)
222
0
{
223
  /* TODO: Implement */
224
0
  WLog_ERR(TAG, "not implemented");
225
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
226
0
  return NULL;
227
0
}
228
229
/**
230
 * GetModuleFileName:
231
 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms683197/
232
 *
233
 * Finding current executable's path without /proc/self/exe:
234
 * http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
235
 */
236
237
DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize)
238
0
{
239
0
  DWORD status = 0;
240
0
  if (!lpFilename)
241
0
  {
242
0
    SetLastError(ERROR_INTERNAL_ERROR);
243
0
    return 0;
244
0
  }
245
246
0
  char* name = calloc(nSize, sizeof(char));
247
0
  if (!name)
248
0
  {
249
0
    SetLastError(ERROR_INTERNAL_ERROR);
250
0
    return 0;
251
0
  }
252
0
  status = GetModuleFileNameA(hModule, name, nSize);
253
254
0
  if ((status > INT_MAX) || (nSize > INT_MAX))
255
0
  {
256
0
    SetLastError(ERROR_INTERNAL_ERROR);
257
0
    status = 0;
258
0
  }
259
260
0
  if (status > 0)
261
0
  {
262
0
    if (ConvertUtf8NToWChar(name, status, lpFilename, nSize) < 0)
263
0
    {
264
0
      free(name);
265
0
      SetLastError(ERROR_INTERNAL_ERROR);
266
0
      return 0;
267
0
    }
268
0
  }
269
270
0
  free(name);
271
0
  return status;
272
0
}
273
274
#if defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__)
275
static DWORD module_from_proc(const char* proc, LPSTR lpFilename, DWORD nSize)
276
0
{
277
0
  char buffer[8192] = { 0 };
278
0
  ssize_t status = readlink(proc, buffer, ARRAYSIZE(buffer) - 1);
279
280
0
  if ((status < 0) || ((size_t)status >= ARRAYSIZE(buffer)))
281
0
  {
282
0
    SetLastError(ERROR_INTERNAL_ERROR);
283
0
    return 0;
284
0
  }
285
286
0
  const size_t length = strnlen(buffer, ARRAYSIZE(buffer));
287
288
0
  if (length < nSize)
289
0
  {
290
0
    CopyMemory(lpFilename, buffer, length);
291
0
    lpFilename[length] = '\0';
292
0
    return (DWORD)length;
293
0
  }
294
295
0
  CopyMemory(lpFilename, buffer, nSize - 1);
296
0
  lpFilename[nSize - 1] = '\0';
297
0
  SetLastError(ERROR_INSUFFICIENT_BUFFER);
298
0
  return nSize;
299
0
}
300
#endif
301
302
DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
303
0
{
304
0
  if (hModule)
305
0
  {
306
0
    WLog_ERR(TAG, "is not implemented");
307
0
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
308
0
    return 0;
309
0
  }
310
311
0
#if defined(__linux__)
312
0
  return module_from_proc("/proc/self/exe", lpFilename, nSize);
313
#elif defined(__FreeBSD__)
314
  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
315
  size_t cb = nSize;
316
317
  {
318
    const int rc = sysctl(mib, ARRAYSIZE(mib), NULL, &cb, NULL, 0);
319
    if (rc != 0)
320
    {
321
      SetLastError(ERROR_INTERNAL_ERROR);
322
      return 0;
323
    }
324
  }
325
326
  char* fullname = calloc(cb + 1, sizeof(char));
327
  if (!fullname)
328
  {
329
    SetLastError(ERROR_INTERNAL_ERROR);
330
    return 0;
331
  }
332
333
  {
334
    size_t cb2 = cb;
335
    const int rc = sysctl(mib, ARRAYSIZE(mib), fullname, &cb2, NULL, 0);
336
    if ((rc != 0) || (cb2 != cb))
337
    {
338
      SetLastError(ERROR_INTERNAL_ERROR);
339
      free(fullname);
340
      return 0;
341
    }
342
  }
343
344
  if (nSize > 0)
345
  {
346
    strncpy(lpFilename, fullname, nSize - 1);
347
    lpFilename[nSize - 1] = '\0';
348
  }
349
  free(fullname);
350
351
  if (nSize < cb)
352
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
353
354
  return (DWORD)MIN(nSize, cb);
355
#elif defined(__NetBSD__)
356
  return module_from_proc("/proc/curproc/exe", lpFilename, nSize);
357
#elif defined(__DragonFly__)
358
  return module_from_proc("/proc/curproc/file", lpFilename, nSize);
359
#elif defined(__MACOSX__)
360
  char path[4096] = { 0 };
361
  char buffer[4096] = { 0 };
362
  uint32_t size = sizeof(path);
363
  const int status = _NSGetExecutablePath(path, &size);
364
365
  if (status != 0)
366
  {
367
    /* path too small */
368
    SetLastError(ERROR_INTERNAL_ERROR);
369
    return 0;
370
  }
371
372
  /*
373
   * _NSGetExecutablePath may not return the canonical path,
374
   * so use realpath to find the absolute, canonical path.
375
   */
376
  realpath(path, buffer);
377
  const size_t length = strnlen(buffer, sizeof(buffer));
378
379
  if (length < nSize)
380
  {
381
    CopyMemory(lpFilename, buffer, length);
382
    lpFilename[length] = '\0';
383
    return (DWORD)length;
384
  }
385
386
  CopyMemory(lpFilename, buffer, nSize - 1);
387
  lpFilename[nSize - 1] = '\0';
388
  SetLastError(ERROR_INSUFFICIENT_BUFFER);
389
  return nSize;
390
#else
391
  WLog_ERR(TAG, "is not implemented");
392
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
393
  return 0;
394
#endif
395
0
}
396
397
#endif
398
399
HMODULE LoadLibraryX(LPCSTR lpLibFileName)
400
0
{
401
0
  if (!lpLibFileName)
402
0
    return NULL;
403
404
#if defined(_WIN32)
405
  HMODULE hm = NULL;
406
  WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, NULL);
407
408
  if (wstr)
409
    hm = LoadLibraryW(wstr);
410
  free(wstr);
411
  return hm;
412
#else
413
0
  return LoadLibraryA(lpLibFileName);
414
0
#endif
415
0
}
416
417
HMODULE LoadLibraryExX(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
418
0
{
419
0
  if (!lpLibFileName)
420
0
    return NULL;
421
#if defined(_WIN32)
422
  HMODULE hm = NULL;
423
  WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, NULL);
424
  if (wstr)
425
    hm = LoadLibraryExW(wstr, hFile, dwFlags);
426
  free(wstr);
427
  return hm;
428
#else
429
0
  return LoadLibraryExA(lpLibFileName, hFile, dwFlags);
430
0
#endif
431
0
}