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