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  const ENCOMSP_ORDER_HEADER* header)
88 {
90  UINT error = CHANNEL_RC_OK;
91 
92  const size_t pos = Stream_GetPosition(s);
93  if (pos < ENCOMSP_ORDER_HEADER_SIZE)
94  return ERROR_INVALID_PARAMETER;
95 
96  const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
97  CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
98 
99  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
100  return ERROR_INVALID_DATA;
101 
102  Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
103  Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
104  const size_t end = Stream_GetPosition(s);
105 
106  if ((beg + header->Length) < end)
107  {
108  WLog_ERR(TAG, "Not enough data!");
109  return ERROR_INVALID_DATA;
110  }
111 
112  if ((beg + header->Length) > end)
113  {
114  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)((beg + header->Length) - end)))
115  return ERROR_INVALID_DATA;
116 
117  Stream_SetPosition(s, (beg + header->Length));
118  }
119 
120  IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
121 
122  if (error)
123  WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
124  error);
125 
126  return error;
127 }
128 
134 static UINT encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s)
135 {
136  UINT error = CHANNEL_RC_OK;
137  ENCOMSP_ORDER_HEADER header;
138 
139  while (Stream_GetRemainingLength(s) > 0)
140  {
141  if ((error = encomsp_read_header(s, &header)))
142  {
143  WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
144  return error;
145  }
146 
147  WLog_INFO(TAG, "EncomspReceive: Type: %" PRIu16 " Length: %" PRIu16 "", header.Type,
148  header.Length);
149 
150  switch (header.Type)
151  {
152  case ODTYPE_PARTICIPANT_CTRL_CHANGED:
153  if ((error =
154  encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
155  {
156  WLog_ERR(TAG,
157  "encomsp_recv_change_participant_control_level_pdu failed with error "
158  "%" PRIu32 "!",
159  error);
160  return error;
161  }
162 
163  break;
164 
165  default:
166  WLog_ERR(TAG, "header.Type unknown %" PRIu16 "!", header.Type);
167  return ERROR_INVALID_DATA;
168  }
169  }
170 
171  return error;
172 }
173 
174 static DWORD WINAPI encomsp_server_thread(LPVOID arg)
175 {
176  wStream* s = NULL;
177  DWORD nCount = 0;
178  void* buffer = NULL;
179  HANDLE events[8];
180  HANDLE ChannelEvent = NULL;
181  DWORD BytesReturned = 0;
182  ENCOMSP_ORDER_HEADER* header = NULL;
183  EncomspServerContext* context = NULL;
184  UINT error = CHANNEL_RC_OK;
185  DWORD status = 0;
186  context = (EncomspServerContext*)arg;
187 
188  buffer = NULL;
189  BytesReturned = 0;
190  ChannelEvent = NULL;
191  s = Stream_New(NULL, 4096);
192 
193  if (!s)
194  {
195  WLog_ERR(TAG, "Stream_New failed!");
196  error = CHANNEL_RC_NO_MEMORY;
197  goto out;
198  }
199 
200  if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
201  &BytesReturned) == TRUE)
202  {
203  if (BytesReturned == sizeof(HANDLE))
204  ChannelEvent = *(HANDLE*)buffer;
205 
206  WTSFreeMemory(buffer);
207  }
208 
209  nCount = 0;
210  events[nCount++] = ChannelEvent;
211  events[nCount++] = context->priv->StopEvent;
212 
213  while (1)
214  {
215  status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
216 
217  if (status == WAIT_FAILED)
218  {
219  error = GetLastError();
220  WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
221  break;
222  }
223 
224  status = WaitForSingleObject(context->priv->StopEvent, 0);
225 
226  if (status == WAIT_FAILED)
227  {
228  error = GetLastError();
229  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
230  break;
231  }
232 
233  if (status == WAIT_OBJECT_0)
234  {
235  break;
236  }
237 
238  if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned))
239  {
240  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
241  error = ERROR_INTERNAL_ERROR;
242  break;
243  }
244 
245  if (BytesReturned < 1)
246  continue;
247 
248  if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
249  {
250  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
251  error = CHANNEL_RC_NO_MEMORY;
252  break;
253  }
254 
255  const size_t cap = Stream_Capacity(s);
256  if ((cap > UINT32_MAX) ||
257  !WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char),
258  (ULONG)cap, &BytesReturned))
259  {
260  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
261  error = ERROR_INTERNAL_ERROR;
262  break;
263  }
264 
265  if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
266  {
267  header = Stream_BufferAs(s, ENCOMSP_ORDER_HEADER);
268 
269  if (header->Length >= Stream_GetPosition(s))
270  {
271  Stream_SealLength(s);
272  Stream_SetPosition(s, 0);
273 
274  if ((error = encomsp_server_receive_pdu(context, s)))
275  {
276  WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %" PRIu32 "!",
277  error);
278  break;
279  }
280 
281  Stream_SetPosition(s, 0);
282  }
283  }
284  }
285 
286  Stream_Free(s, TRUE);
287 out:
288 
289  if (error && context->rdpcontext)
290  setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error");
291 
292  ExitThread(error);
293  return error;
294 }
295 
301 static UINT encomsp_server_start(EncomspServerContext* context)
302 {
303  context->priv->ChannelHandle =
304  WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, ENCOMSP_SVC_CHANNEL_NAME);
305 
306  if (!context->priv->ChannelHandle)
307  return CHANNEL_RC_BAD_CHANNEL;
308 
309  if (!(context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
310  {
311  WLog_ERR(TAG, "CreateEvent failed!");
312  return ERROR_INTERNAL_ERROR;
313  }
314 
315  if (!(context->priv->Thread =
316  CreateThread(NULL, 0, encomsp_server_thread, (void*)context, 0, NULL)))
317  {
318  WLog_ERR(TAG, "CreateThread failed!");
319  (void)CloseHandle(context->priv->StopEvent);
320  context->priv->StopEvent = NULL;
321  return ERROR_INTERNAL_ERROR;
322  }
323 
324  return CHANNEL_RC_OK;
325 }
326 
332 static UINT encomsp_server_stop(EncomspServerContext* context)
333 {
334  UINT error = CHANNEL_RC_OK;
335  (void)SetEvent(context->priv->StopEvent);
336 
337  if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
338  {
339  error = GetLastError();
340  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
341  return error;
342  }
343 
344  (void)CloseHandle(context->priv->Thread);
345  (void)CloseHandle(context->priv->StopEvent);
346  return error;
347 }
348 
349 EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
350 {
351  EncomspServerContext* context = NULL;
352  context = (EncomspServerContext*)calloc(1, sizeof(EncomspServerContext));
353 
354  if (context)
355  {
356  context->vcm = vcm;
357  context->Start = encomsp_server_start;
358  context->Stop = encomsp_server_stop;
359  context->priv = (EncomspServerPrivate*)calloc(1, sizeof(EncomspServerPrivate));
360 
361  if (!context->priv)
362  {
363  WLog_ERR(TAG, "calloc failed!");
364  free(context);
365  return NULL;
366  }
367  }
368 
369  return context;
370 }
371 
372 void encomsp_server_context_free(EncomspServerContext* context)
373 {
374  if (context)
375  {
376  if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
377  (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
378 
379  free(context->priv);
380  free(context);
381  }
382 }