FreeRDP
server/encomsp_main.c
1 
22 #include <freerdp/config.h>
23 
24 #include <winpr/crt.h>
25 #include <winpr/print.h>
26 #include <winpr/stream.h>
27 
28 #include <freerdp/freerdp.h>
29 #include <freerdp/channels/log.h>
30 
31 #include "encomsp_main.h"
32 
33 #define TAG CHANNELS_TAG("encomsp.server")
34 
40 static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
41 {
42  if (!Stream_CheckAndLogRequiredLength(TAG, s, ENCOMSP_ORDER_HEADER_SIZE))
43  return ERROR_INVALID_DATA;
44 
45  Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
46  Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
47  return CHANNEL_RC_OK;
48 }
49 
50 #if 0
51 
52 static int encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
53 {
54  Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */
55  Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */
56  return 1;
57 }
58 
59 static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str)
60 {
61  ZeroMemory(str, sizeof(ENCOMSP_UNICODE_STRING));
62 
63  if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
64  return -1;
65 
66  Stream_Read_UINT16(s, str->cchString); /* cchString (2 bytes) */
67 
68  if (str->cchString > 1024)
69  return -1;
70 
71  if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, str->cchString, sizeof(WCHAR)))
72  return -1;
73 
74  Stream_Read(s, &(str->wString), (str->cchString * 2)); /* String (variable) */
75  return 1;
76 }
77 
78 #endif
79 
85 static UINT encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context,
86  wStream* s,
87  ENCOMSP_ORDER_HEADER* header)
88 {
89  int beg = 0;
90  int end = 0;
92  UINT error = CHANNEL_RC_OK;
93  beg = ((int)Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
94  CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
95 
96  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
97  return ERROR_INVALID_DATA;
98 
99  Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
100  Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
101  end = (int)Stream_GetPosition(s);
102 
103  if ((beg + header->Length) < end)
104  {
105  WLog_ERR(TAG, "Not enough data!");
106  return ERROR_INVALID_DATA;
107  }
108 
109  if ((beg + header->Length) > end)
110  {
111  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)((beg + header->Length) - end)))
112  return ERROR_INVALID_DATA;
113 
114  Stream_SetPosition(s, (beg + header->Length));
115  }
116 
117  IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
118 
119  if (error)
120  WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
121  error);
122 
123  return error;
124 }
125 
131 static UINT encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s)
132 {
133  UINT error = CHANNEL_RC_OK;
134  ENCOMSP_ORDER_HEADER header;
135 
136  while (Stream_GetRemainingLength(s) > 0)
137  {
138  if ((error = encomsp_read_header(s, &header)))
139  {
140  WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
141  return error;
142  }
143 
144  WLog_INFO(TAG, "EncomspReceive: Type: %" PRIu16 " Length: %" PRIu16 "", header.Type,
145  header.Length);
146 
147  switch (header.Type)
148  {
149  case ODTYPE_PARTICIPANT_CTRL_CHANGED:
150  if ((error =
151  encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
152  {
153  WLog_ERR(TAG,
154  "encomsp_recv_change_participant_control_level_pdu failed with error "
155  "%" PRIu32 "!",
156  error);
157  return error;
158  }
159 
160  break;
161 
162  default:
163  WLog_ERR(TAG, "header.Type unknown %" PRIu16 "!", header.Type);
164  return ERROR_INVALID_DATA;
165  }
166  }
167 
168  return error;
169 }
170 
171 static DWORD WINAPI encomsp_server_thread(LPVOID arg)
172 {
173  wStream* s = NULL;
174  DWORD nCount = 0;
175  void* buffer = NULL;
176  HANDLE events[8];
177  HANDLE ChannelEvent = NULL;
178  DWORD BytesReturned = 0;
179  ENCOMSP_ORDER_HEADER* header = NULL;
180  EncomspServerContext* context = NULL;
181  UINT error = CHANNEL_RC_OK;
182  DWORD status = 0;
183  context = (EncomspServerContext*)arg;
184 
185  buffer = NULL;
186  BytesReturned = 0;
187  ChannelEvent = NULL;
188  s = Stream_New(NULL, 4096);
189 
190  if (!s)
191  {
192  WLog_ERR(TAG, "Stream_New failed!");
193  error = CHANNEL_RC_NO_MEMORY;
194  goto out;
195  }
196 
197  if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
198  &BytesReturned) == TRUE)
199  {
200  if (BytesReturned == sizeof(HANDLE))
201  CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
202 
203  WTSFreeMemory(buffer);
204  }
205 
206  nCount = 0;
207  events[nCount++] = ChannelEvent;
208  events[nCount++] = context->priv->StopEvent;
209 
210  while (1)
211  {
212  status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
213 
214  if (status == WAIT_FAILED)
215  {
216  error = GetLastError();
217  WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
218  break;
219  }
220 
221  status = WaitForSingleObject(context->priv->StopEvent, 0);
222 
223  if (status == WAIT_FAILED)
224  {
225  error = GetLastError();
226  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
227  break;
228  }
229 
230  if (status == WAIT_OBJECT_0)
231  {
232  break;
233  }
234 
235  if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned))
236  {
237  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
238  error = ERROR_INTERNAL_ERROR;
239  break;
240  }
241 
242  if (BytesReturned < 1)
243  continue;
244 
245  if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
246  {
247  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
248  error = CHANNEL_RC_NO_MEMORY;
249  break;
250  }
251 
252  const size_t cap = Stream_Capacity(s);
253  if ((cap > UINT32_MAX) ||
254  !WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char),
255  (ULONG)cap, &BytesReturned))
256  {
257  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
258  error = ERROR_INTERNAL_ERROR;
259  break;
260  }
261 
262  if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
263  {
264  header = Stream_BufferAs(s, ENCOMSP_ORDER_HEADER);
265 
266  if (header->Length >= Stream_GetPosition(s))
267  {
268  Stream_SealLength(s);
269  Stream_SetPosition(s, 0);
270 
271  if ((error = encomsp_server_receive_pdu(context, s)))
272  {
273  WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %" PRIu32 "!",
274  error);
275  break;
276  }
277 
278  Stream_SetPosition(s, 0);
279  }
280  }
281  }
282 
283  Stream_Free(s, TRUE);
284 out:
285 
286  if (error && context->rdpcontext)
287  setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error");
288 
289  ExitThread(error);
290  return error;
291 }
292 
298 static UINT encomsp_server_start(EncomspServerContext* context)
299 {
300  context->priv->ChannelHandle =
301  WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, ENCOMSP_SVC_CHANNEL_NAME);
302 
303  if (!context->priv->ChannelHandle)
304  return CHANNEL_RC_BAD_CHANNEL;
305 
306  if (!(context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
307  {
308  WLog_ERR(TAG, "CreateEvent failed!");
309  return ERROR_INTERNAL_ERROR;
310  }
311 
312  if (!(context->priv->Thread =
313  CreateThread(NULL, 0, encomsp_server_thread, (void*)context, 0, NULL)))
314  {
315  WLog_ERR(TAG, "CreateThread failed!");
316  (void)CloseHandle(context->priv->StopEvent);
317  context->priv->StopEvent = NULL;
318  return ERROR_INTERNAL_ERROR;
319  }
320 
321  return CHANNEL_RC_OK;
322 }
323 
329 static UINT encomsp_server_stop(EncomspServerContext* context)
330 {
331  UINT error = CHANNEL_RC_OK;
332  (void)SetEvent(context->priv->StopEvent);
333 
334  if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
335  {
336  error = GetLastError();
337  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
338  return error;
339  }
340 
341  (void)CloseHandle(context->priv->Thread);
342  (void)CloseHandle(context->priv->StopEvent);
343  return error;
344 }
345 
346 EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
347 {
348  EncomspServerContext* context = NULL;
349  context = (EncomspServerContext*)calloc(1, sizeof(EncomspServerContext));
350 
351  if (context)
352  {
353  context->vcm = vcm;
354  context->Start = encomsp_server_start;
355  context->Stop = encomsp_server_stop;
356  context->priv = (EncomspServerPrivate*)calloc(1, sizeof(EncomspServerPrivate));
357 
358  if (!context->priv)
359  {
360  WLog_ERR(TAG, "calloc failed!");
361  free(context);
362  return NULL;
363  }
364  }
365 
366  return context;
367 }
368 
369 void encomsp_server_context_free(EncomspServerContext* context)
370 {
371  if (context)
372  {
373  if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
374  (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
375 
376  free(context->priv);
377  free(context);
378  }
379 }