Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/libfreerdp/common/addin.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Addin 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 <freerdp/config.h>
21
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include <winpr/crt.h>
27
#include <winpr/path.h>
28
#include <winpr/string.h>
29
#include <winpr/library.h>
30
31
#include <freerdp/addin.h>
32
#include <freerdp/build-config.h>
33
34
#include <freerdp/log.h>
35
#define TAG FREERDP_TAG("addin")
36
37
static INLINE BOOL is_path_required(LPCSTR path, size_t len)
38
0
{
39
0
  if (!path || (len <= 1))
40
0
    return FALSE;
41
42
0
  if (strcmp(path, ".") == 0)
43
0
    return FALSE;
44
45
0
  return TRUE;
46
0
}
47
48
LPSTR freerdp_get_library_install_path(void)
49
0
{
50
0
  LPSTR pszPath;
51
0
  size_t cchPath;
52
0
  size_t cchLibraryPath;
53
0
  size_t cchInstallPrefix;
54
0
  BOOL needLibPath, needInstallPath;
55
0
  LPCSTR pszLibraryPath = FREERDP_LIBRARY_PATH;
56
0
  LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
57
0
  cchLibraryPath = strlen(pszLibraryPath) + 1;
58
0
  cchInstallPrefix = strlen(pszInstallPrefix) + 1;
59
0
  cchPath = cchInstallPrefix + cchLibraryPath;
60
0
  needInstallPath = is_path_required(pszInstallPrefix, cchInstallPrefix);
61
0
  needLibPath = is_path_required(pszLibraryPath, cchLibraryPath);
62
63
0
  if (!needInstallPath && !needLibPath)
64
0
    return NULL;
65
66
0
  pszPath = (LPSTR)malloc(cchPath + 1);
67
68
0
  if (!pszPath)
69
0
    return NULL;
70
71
0
  if (needInstallPath)
72
0
  {
73
0
    CopyMemory(pszPath, pszInstallPrefix, cchInstallPrefix);
74
0
    pszPath[cchInstallPrefix] = '\0';
75
0
  }
76
77
0
  if (needLibPath)
78
0
  {
79
0
    if (FAILED(NativePathCchAppendA(pszPath, cchPath + 1, pszLibraryPath)))
80
0
    {
81
0
      free(pszPath);
82
0
      return NULL;
83
0
    }
84
0
  }
85
86
0
  return pszPath;
87
0
}
88
89
LPSTR freerdp_get_dynamic_addin_install_path(void)
90
0
{
91
#if defined(WITH_ADD_PLUGIN_TO_RPATH)
92
  return NULL;
93
#else
94
0
  LPSTR pszPath;
95
0
  size_t cchPath;
96
0
  size_t cchAddinPath;
97
0
  size_t cchInstallPrefix;
98
0
  BOOL needLibPath, needInstallPath;
99
0
  LPCSTR pszAddinPath = FREERDP_ADDIN_PATH;
100
0
  LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
101
0
  cchAddinPath = strlen(pszAddinPath) + 1;
102
0
  cchInstallPrefix = strlen(pszInstallPrefix) + 1;
103
0
  cchPath = cchInstallPrefix + cchAddinPath;
104
0
  needInstallPath = is_path_required(pszInstallPrefix, cchInstallPrefix);
105
0
  needLibPath = is_path_required(pszAddinPath, cchAddinPath);
106
107
0
  WLog_DBG(TAG,
108
0
           "freerdp_get_dynamic_addin_install_path <- pszInstallPrefix: %s, pszAddinPath: %s",
109
0
           pszInstallPrefix, pszAddinPath);
110
111
0
  if (!needInstallPath && !needLibPath)
112
0
    return NULL;
113
114
0
  pszPath = (LPSTR)calloc(cchPath + 1, sizeof(CHAR));
115
116
0
  if (!pszPath)
117
0
    return NULL;
118
119
0
  if (needInstallPath)
120
0
  {
121
0
    CopyMemory(pszPath, pszInstallPrefix, cchInstallPrefix);
122
0
    pszPath[cchInstallPrefix] = '\0';
123
0
  }
124
125
0
  if (needLibPath)
126
0
  {
127
0
    if (FAILED(NativePathCchAppendA(pszPath, cchPath + 1, pszAddinPath)))
128
0
    {
129
0
      free(pszPath);
130
0
      return NULL;
131
0
    }
132
0
  }
133
134
0
  WLog_DBG(TAG, "freerdp_get_dynamic_addin_install_path -> pszPath: %s", pszPath);
135
136
0
  return pszPath;
137
0
#endif
138
0
}
139
140
PVIRTUALCHANNELENTRY freerdp_load_dynamic_addin(LPCSTR pszFileName, LPCSTR pszPath,
141
                                                LPCSTR pszEntryName)
142
0
{
143
0
  LPSTR pszAddinInstallPath = freerdp_get_dynamic_addin_install_path();
144
0
  PVIRTUALCHANNELENTRY entry = NULL;
145
0
  BOOL bHasExt = TRUE;
146
0
  PCSTR pszExt;
147
0
  size_t cchExt = 0;
148
0
  HINSTANCE library = NULL;
149
0
  size_t cchFileName;
150
0
  size_t cchFilePath;
151
0
  LPSTR pszAddinFile = NULL;
152
0
  LPSTR pszFilePath = NULL;
153
0
  LPSTR pszRelativeFilePath = NULL;
154
0
  size_t cchAddinFile;
155
0
  size_t cchAddinInstallPath;
156
157
0
  if (!pszFileName || !pszEntryName)
158
0
    goto fail;
159
160
0
  WLog_DBG(TAG, "freerdp_load_dynamic_addin <- pszFileName: %s, pszPath: %s, pszEntryName: %s",
161
0
           pszFileName, pszPath, pszEntryName);
162
163
0
  cchFileName = strlen(pszFileName);
164
165
  /* Get file name with prefix and extension */
166
0
  if (FAILED(PathCchFindExtensionA(pszFileName, cchFileName + 1, &pszExt)))
167
0
  {
168
0
    pszExt = PathGetSharedLibraryExtensionA(PATH_SHARED_LIB_EXT_WITH_DOT);
169
0
    cchExt = strlen(pszExt);
170
0
    bHasExt = FALSE;
171
0
  }
172
173
0
  if (bHasExt)
174
0
  {
175
0
    pszAddinFile = _strdup(pszFileName);
176
177
0
    if (!pszAddinFile)
178
0
      goto fail;
179
0
  }
180
0
  else
181
0
  {
182
0
    cchAddinFile = cchFileName + cchExt + 2 + sizeof(FREERDP_SHARED_LIBRARY_PREFIX);
183
0
    pszAddinFile = (LPSTR)malloc(cchAddinFile + 1);
184
185
0
    if (!pszAddinFile)
186
0
      goto fail;
187
188
0
    sprintf_s(pszAddinFile, cchAddinFile, FREERDP_SHARED_LIBRARY_PREFIX "%s%s", pszFileName,
189
0
              pszExt);
190
0
  }
191
192
0
  cchAddinFile = strlen(pszAddinFile);
193
194
  /* If a path is provided prefix the library name with it. */
195
0
  if (pszPath)
196
0
  {
197
0
    size_t relPathLen = strlen(pszPath) + cchAddinFile + 1;
198
0
    pszRelativeFilePath = calloc(relPathLen, sizeof(CHAR));
199
200
0
    if (!pszRelativeFilePath)
201
0
      goto fail;
202
203
0
    sprintf_s(pszRelativeFilePath, relPathLen, "%s", pszPath);
204
0
    const HRESULT hr = NativePathCchAppendA(pszRelativeFilePath, relPathLen, pszAddinFile);
205
0
    if (FAILED(hr))
206
0
      goto fail;
207
0
  }
208
0
  else
209
0
    pszRelativeFilePath = _strdup(pszAddinFile);
210
211
0
  if (!pszRelativeFilePath)
212
0
    goto fail;
213
214
  /* If a system prefix path is provided try these locations too. */
215
0
  if (pszAddinInstallPath)
216
0
  {
217
0
    cchAddinInstallPath = strlen(pszAddinInstallPath);
218
0
    cchFilePath = cchAddinInstallPath + cchFileName + 32;
219
0
    pszFilePath = (LPSTR)malloc(cchFilePath + 1);
220
221
0
    if (!pszFilePath)
222
0
      goto fail;
223
224
0
    CopyMemory(pszFilePath, pszAddinInstallPath, cchAddinInstallPath);
225
0
    pszFilePath[cchAddinInstallPath] = '\0';
226
0
    const HRESULT hr =
227
0
        NativePathCchAppendA((LPSTR)pszFilePath, cchFilePath + 1, pszRelativeFilePath);
228
0
    if (FAILED(hr))
229
0
      goto fail;
230
0
  }
231
0
  else
232
0
    pszFilePath = _strdup(pszRelativeFilePath);
233
234
0
  library = LoadLibraryX(pszFilePath);
235
236
0
  if (!library)
237
0
    goto fail;
238
239
0
  entry = (PVIRTUALCHANNELENTRY)GetProcAddress(library, pszEntryName);
240
0
fail:
241
0
  free(pszRelativeFilePath);
242
0
  free(pszAddinFile);
243
0
  free(pszFilePath);
244
0
  free(pszAddinInstallPath);
245
246
0
  if (!entry && library)
247
0
    FreeLibrary(library);
248
249
0
  return entry;
250
0
}
251
252
PVIRTUALCHANNELENTRY freerdp_load_dynamic_channel_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
253
                                                              LPCSTR pszType, DWORD dwFlags)
254
0
{
255
0
  PVIRTUALCHANNELENTRY entry;
256
0
  LPSTR pszFileName;
257
0
  const size_t cchBaseFileName = sizeof(FREERDP_SHARED_LIBRARY_PREFIX) + 32;
258
0
  size_t nameLen = 0;
259
0
  size_t subsystemLen = 0;
260
0
  size_t typeLen = 0;
261
0
  size_t cchFileName = 0;
262
263
0
  if (pszName)
264
0
    nameLen = strnlen(pszName, MAX_PATH);
265
0
  if (pszSubsystem)
266
0
    subsystemLen = strnlen(pszSubsystem, MAX_PATH);
267
0
  if (pszType)
268
0
    typeLen = strnlen(pszType, MAX_PATH);
269
270
0
  if (pszName && pszSubsystem && pszType)
271
0
  {
272
0
    cchFileName = cchBaseFileName + nameLen + subsystemLen + typeLen;
273
0
    pszFileName = (LPSTR)malloc(cchFileName);
274
275
0
    if (!pszFileName)
276
0
      return NULL;
277
278
0
    sprintf_s(pszFileName, cchFileName, "%s-client-%s-%s", pszName, pszSubsystem, pszType);
279
0
  }
280
0
  else if (pszName && pszSubsystem)
281
0
  {
282
0
    cchFileName = cchBaseFileName + nameLen + subsystemLen;
283
0
    pszFileName = (LPSTR)malloc(cchFileName);
284
285
0
    if (!pszFileName)
286
0
      return NULL;
287
288
0
    sprintf_s(pszFileName, cchFileName, "%s-client-%s", pszName, pszSubsystem);
289
0
  }
290
0
  else if (pszName)
291
0
  {
292
0
    cchFileName = cchBaseFileName + nameLen;
293
0
    pszFileName = (LPSTR)malloc(cchFileName);
294
295
0
    if (!pszFileName)
296
0
      return NULL;
297
298
0
    sprintf_s(pszFileName, cchFileName, "%s-client", pszName);
299
0
  }
300
0
  else
301
0
  {
302
0
    return NULL;
303
0
  }
304
305
0
  {
306
0
    LPCSTR pszExtension = PathGetSharedLibraryExtensionA(0);
307
0
    LPCSTR pszPrefix = FREERDP_SHARED_LIBRARY_PREFIX;
308
0
    int rc = 0;
309
310
0
    if (pszPrefix)
311
0
      cchFileName += strnlen(pszPrefix, MAX_PATH);
312
0
    if (pszExtension)
313
0
      cchFileName += strnlen(pszExtension, MAX_PATH) + 1;
314
0
    LPSTR tmp = calloc(cchFileName, sizeof(CHAR));
315
0
    if (tmp)
316
0
      rc = sprintf_s(tmp, cchFileName, "%s%s.%s", pszPrefix, pszFileName, pszExtension);
317
318
0
    free(pszFileName);
319
0
    pszFileName = tmp;
320
0
    if (!pszFileName || (rc < 0))
321
0
    {
322
0
      free(pszFileName);
323
0
      return NULL;
324
0
    }
325
0
  }
326
327
0
  if (pszSubsystem)
328
0
  {
329
0
    LPSTR pszEntryName;
330
0
    size_t cchEntryName;
331
    /* subsystem add-in */
332
0
    cchEntryName = 64 + nameLen;
333
0
    pszEntryName = (LPSTR)malloc(cchEntryName + 1);
334
335
0
    if (!pszEntryName)
336
0
    {
337
0
      free(pszFileName);
338
0
      return NULL;
339
0
    }
340
341
0
    sprintf_s(pszEntryName, cchEntryName + 1, "freerdp_%s_client_subsystem_entry", pszName);
342
0
    entry = freerdp_load_dynamic_addin(pszFileName, NULL, pszEntryName);
343
0
    free(pszEntryName);
344
0
    free(pszFileName);
345
0
    return entry;
346
0
  }
347
348
  /* channel add-in */
349
350
0
  if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
351
0
  {
352
0
    if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
353
0
      entry = freerdp_load_dynamic_addin(pszFileName, NULL, "VirtualChannelEntryEx");
354
0
    else
355
0
      entry = freerdp_load_dynamic_addin(pszFileName, NULL, "VirtualChannelEntry");
356
0
  }
357
0
  else if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
358
0
    entry = freerdp_load_dynamic_addin(pszFileName, NULL, "DVCPluginEntry");
359
0
  else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
360
0
    entry = freerdp_load_dynamic_addin(pszFileName, NULL, "DeviceServiceEntry");
361
0
  else
362
0
    entry = freerdp_load_dynamic_addin(pszFileName, NULL, pszType);
363
364
0
  free(pszFileName);
365
0
  return entry;
366
0
}
367
368
static FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN freerdp_load_static_channel_addin_entry = NULL;
369
370
int freerdp_register_addin_provider(FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN provider, DWORD dwFlags)
371
0
{
372
0
  freerdp_load_static_channel_addin_entry = provider;
373
0
  return 0;
374
0
}
375
376
FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN freerdp_get_current_addin_provider(void)
377
0
{
378
0
  return freerdp_load_static_channel_addin_entry;
379
0
}
380
381
PVIRTUALCHANNELENTRY freerdp_load_channel_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
382
                                                      LPCSTR pszType, DWORD dwFlags)
383
0
{
384
0
  PVIRTUALCHANNELENTRY entry = NULL;
385
386
0
  if (freerdp_load_static_channel_addin_entry)
387
0
    entry = freerdp_load_static_channel_addin_entry(pszName, pszSubsystem, pszType, dwFlags);
388
389
0
  if (!entry)
390
0
    entry = freerdp_load_dynamic_channel_addin_entry(pszName, pszSubsystem, pszType, dwFlags);
391
392
0
  if (!entry)
393
0
    WLog_WARN(TAG, "Failed to load channel %s [%s]", pszName, pszSubsystem);
394
395
0
  return entry;
396
0
}