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