FreeRDP
rdp2tcp_main.c
1 
20 #include <stdio.h>
21 #include <winpr/assert.h>
22 
23 #include <winpr/file.h>
24 #include <winpr/pipe.h>
25 #include <winpr/thread.h>
26 
27 #include <freerdp/freerdp.h>
28 #include <freerdp/svc.h>
29 #include <freerdp/channels/rdp2tcp.h>
30 
31 #include <freerdp/log.h>
32 #define TAG CLIENT_TAG(RDP2TCP_DVC_CHANNEL_NAME)
33 
34 typedef struct
35 {
36  HANDLE hStdOutputRead;
37  HANDLE hStdInputWrite;
38  HANDLE hProcess;
39  HANDLE copyThread;
40  HANDLE writeComplete;
41  DWORD openHandle;
42  void* initHandle;
43  CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints;
44  char buffer[16 * 1024];
45  char* commandline;
46 } Plugin;
47 
48 static int init_external_addin(Plugin* plugin)
49 {
50  SECURITY_ATTRIBUTES saAttr = { 0 };
51  STARTUPINFOA siStartInfo = { 0 }; /* Using ANSI type to match CreateProcessA */
52  PROCESS_INFORMATION procInfo = { 0 };
53 
54  WINPR_ASSERT(plugin);
55 
56  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
57  saAttr.bInheritHandle = TRUE;
58  saAttr.lpSecurityDescriptor = NULL;
59  siStartInfo.cb = sizeof(STARTUPINFO);
60  siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
61  siStartInfo.dwFlags = STARTF_USESTDHANDLES;
62 
63  // Create pipes
64  if (!CreatePipe(&plugin->hStdOutputRead, &siStartInfo.hStdOutput, &saAttr, 0))
65  {
66  WLog_ERR(TAG, "stdout CreatePipe");
67  return -1;
68  }
69 
70  if (!SetHandleInformation(plugin->hStdOutputRead, HANDLE_FLAG_INHERIT, 0))
71  {
72  WLog_ERR(TAG, "stdout SetHandleInformation");
73  return -1;
74  }
75 
76  if (!CreatePipe(&siStartInfo.hStdInput, &plugin->hStdInputWrite, &saAttr, 0))
77  {
78  WLog_ERR(TAG, "stdin CreatePipe");
79  return -1;
80  }
81 
82  if (!SetHandleInformation(plugin->hStdInputWrite, HANDLE_FLAG_INHERIT, 0))
83  {
84  WLog_ERR(TAG, "stdin SetHandleInformation");
85  return -1;
86  }
87 
88  // Execute plugin
89  plugin->commandline = _strdup(plugin->channelEntryPoints.pExtendedData);
90  if (!CreateProcessA(NULL,
91  plugin->commandline, // command line
92  NULL, // process security attributes
93  NULL, // primary thread security attributes
94  TRUE, // handles are inherited
95  0, // creation flags
96  NULL, // use parent's environment
97  NULL, // use parent's current directory
98  &siStartInfo, // STARTUPINFO pointer
99  &procInfo // receives PROCESS_INFORMATION
100  ))
101  {
102  WLog_ERR(TAG, "fork for addin");
103  return -1;
104  }
105 
106  plugin->hProcess = procInfo.hProcess;
107  (void)CloseHandle(procInfo.hThread);
108  (void)CloseHandle(siStartInfo.hStdOutput);
109  (void)CloseHandle(siStartInfo.hStdInput);
110  return 0;
111 }
112 
113 static DWORD WINAPI copyThread(void* data)
114 {
115  DWORD status = WAIT_OBJECT_0;
116  Plugin* plugin = (Plugin*)data;
117  size_t const bufsize = 16ULL * 1024ULL;
118 
119  WINPR_ASSERT(plugin);
120 
121  while (status == WAIT_OBJECT_0)
122  {
123 
124  HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
125  DWORD dwRead = 0;
126  char* buffer = calloc(bufsize, sizeof(char));
127 
128  if (!buffer)
129  {
130  (void)fprintf(stderr, "rdp2tcp copyThread: malloc failed\n");
131  goto fail;
132  }
133 
134  // if (!ReadFile(plugin->hStdOutputRead, plugin->buffer, sizeof plugin->buffer, &dwRead,
135  // NULL))
136  if (!ReadFile(plugin->hStdOutputRead, buffer, bufsize, &dwRead, NULL))
137  {
138  free(buffer);
139  goto fail;
140  }
141 
142  if (plugin->channelEntryPoints.pVirtualChannelWriteEx(
143  plugin->initHandle, plugin->openHandle, buffer, dwRead, buffer) != CHANNEL_RC_OK)
144  {
145  free(buffer);
146  (void)fprintf(stderr, "rdp2tcp copyThread failed %i\n", (int)dwRead);
147  goto fail;
148  }
149 
150  handles[0] = plugin->writeComplete;
151  handles[1] = freerdp_abort_event(plugin->channelEntryPoints.context);
152  status = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
153  if (status == WAIT_OBJECT_0)
154  (void)ResetEvent(plugin->writeComplete);
155  }
156 
157 fail:
158  ExitThread(0);
159  return 0;
160 }
161 
162 static void closeChannel(Plugin* plugin)
163 {
164  WINPR_ASSERT(plugin);
165  WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelCloseEx);
166  plugin->channelEntryPoints.pVirtualChannelCloseEx(plugin->initHandle, plugin->openHandle);
167 }
168 
169 static void dataReceived(Plugin* plugin, void* pData, UINT32 dataLength, UINT32 totalLength,
170  UINT32 dataFlags)
171 {
172  DWORD dwWritten = 0;
173 
174  WINPR_ASSERT(plugin);
175 
176  if (dataFlags & CHANNEL_FLAG_SUSPEND)
177  return;
178 
179  if (dataFlags & CHANNEL_FLAG_RESUME)
180  return;
181 
182  if (dataFlags & CHANNEL_FLAG_FIRST)
183  {
184  if (!WriteFile(plugin->hStdInputWrite, &totalLength, sizeof(totalLength), &dwWritten, NULL))
185  closeChannel(plugin);
186  }
187 
188  if (!WriteFile(plugin->hStdInputWrite, pData, dataLength, &dwWritten, NULL))
189  closeChannel(plugin);
190 }
191 
192 static void VCAPITYPE VirtualChannelOpenEventEx(LPVOID lpUserParam, DWORD openHandle, UINT event,
193  LPVOID pData, UINT32 dataLength, UINT32 totalLength,
194  UINT32 dataFlags)
195 {
196  Plugin* plugin = (Plugin*)lpUserParam;
197 
198  WINPR_ASSERT(plugin);
199  switch (event)
200  {
201  case CHANNEL_EVENT_DATA_RECEIVED:
202  dataReceived(plugin, pData, dataLength, totalLength, dataFlags);
203  break;
204 
205  case CHANNEL_EVENT_WRITE_CANCELLED:
206  free(pData);
207  break;
208  case CHANNEL_EVENT_WRITE_COMPLETE:
209  (void)SetEvent(plugin->writeComplete);
210  free(pData);
211  break;
212  default:
213  break;
214  }
215 }
216 
217 static void channel_terminated(Plugin* plugin)
218 {
219  if (!plugin)
220  return;
221 
222  if (plugin->copyThread)
223  (void)TerminateThread(plugin->copyThread, 0);
224  if (plugin->writeComplete)
225  (void)CloseHandle(plugin->writeComplete);
226 
227  (void)CloseHandle(plugin->hStdInputWrite);
228  (void)CloseHandle(plugin->hStdOutputRead);
229  TerminateProcess(plugin->hProcess, 0);
230  (void)CloseHandle(plugin->hProcess);
231  free(plugin->commandline);
232  free(plugin);
233 }
234 
235 static void channel_initialized(Plugin* plugin)
236 {
237  WINPR_ASSERT(plugin);
238  plugin->writeComplete = CreateEvent(NULL, TRUE, FALSE, NULL);
239  plugin->copyThread = CreateThread(NULL, 0, copyThread, plugin, 0, NULL);
240 }
241 
242 static VOID VCAPITYPE VirtualChannelInitEventEx(LPVOID lpUserParam, LPVOID pInitHandle, UINT event,
243  LPVOID pData, UINT dataLength)
244 {
245  Plugin* plugin = (Plugin*)lpUserParam;
246 
247  WINPR_ASSERT(plugin);
248 
249  switch (event)
250  {
251  case CHANNEL_EVENT_INITIALIZED:
252  channel_initialized(plugin);
253  break;
254 
255  case CHANNEL_EVENT_CONNECTED:
256  WINPR_ASSERT(plugin);
257  WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelOpenEx);
258  if (plugin->channelEntryPoints.pVirtualChannelOpenEx(
259  pInitHandle, &plugin->openHandle, RDP2TCP_DVC_CHANNEL_NAME,
260  VirtualChannelOpenEventEx) != CHANNEL_RC_OK)
261  return;
262 
263  break;
264 
265  case CHANNEL_EVENT_DISCONNECTED:
266  break;
267 
268  case CHANNEL_EVENT_TERMINATED:
269  channel_terminated(plugin);
270  break;
271  default:
272  break;
273  }
274 }
275 
276 #define VirtualChannelEntryEx rdp2tcp_VirtualChannelEntryEx
277 FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
278  PVOID pInitHandle))
279 {
280  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx =
281  (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
282  WINPR_ASSERT(pEntryPointsEx);
283  WINPR_ASSERT(pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX) &&
284  pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER);
285 
286  Plugin* plugin = (Plugin*)calloc(1, sizeof(Plugin));
287 
288  if (!plugin)
289  return FALSE;
290 
291  plugin->initHandle = pInitHandle;
292  plugin->channelEntryPoints = *pEntryPointsEx;
293 
294  if (init_external_addin(plugin) < 0)
295  {
296  free(plugin);
297  return FALSE;
298  }
299 
300  CHANNEL_DEF channelDef = { 0 };
301  strncpy(channelDef.name, RDP2TCP_DVC_CHANNEL_NAME, sizeof(channelDef.name));
302  channelDef.options =
303  CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
304 
305  if (pEntryPointsEx->pVirtualChannelInitEx(plugin, NULL, pInitHandle, &channelDef, 1,
306  VIRTUAL_CHANNEL_VERSION_WIN2000,
307  VirtualChannelInitEventEx) != CHANNEL_RC_OK)
308  return FALSE;
309 
310  return TRUE;
311 }
Definition: svc.h:61