FreeRDP
pf_channel.c
1 
18 #include <winpr/assert.h>
19 #include <winpr/cast.h>
20 
21 #include <freerdp/freerdp.h>
22 #include <freerdp/server/proxy/proxy_log.h>
23 
24 #include "proxy_modules.h"
25 #include "pf_channel.h"
26 
27 #define TAG PROXY_TAG("channel")
28 
30 struct _ChannelStateTracker
31 {
32  pServerStaticChannelContext* channel;
33  ChannelTrackerMode mode;
34  wStream* currentPacket;
35  size_t currentPacketReceived;
36  size_t currentPacketSize;
37  size_t currentPacketFragments;
38 
39  ChannelTrackerPeekFn peekFn;
40  void* trackerData;
41  proxyData* pdata;
42 };
43 
44 static BOOL channelTracker_resetCurrentPacket(ChannelStateTracker* tracker)
45 {
46  WINPR_ASSERT(tracker);
47 
48  BOOL create = TRUE;
49  if (tracker->currentPacket)
50  {
51  const size_t cap = Stream_Capacity(tracker->currentPacket);
52  if (cap < 1ULL * 1000ULL * 1000ULL)
53  create = FALSE;
54  else
55  Stream_Free(tracker->currentPacket, TRUE);
56  }
57 
58  if (create)
59  tracker->currentPacket = Stream_New(NULL, 10ULL * 1024ULL);
60  if (!tracker->currentPacket)
61  return FALSE;
62  Stream_SetPosition(tracker->currentPacket, 0);
63  return TRUE;
64 }
65 
66 ChannelStateTracker* channelTracker_new(pServerStaticChannelContext* channel,
67  ChannelTrackerPeekFn fn, void* data)
68 {
69  ChannelStateTracker* ret = calloc(1, sizeof(ChannelStateTracker));
70  if (!ret)
71  return ret;
72 
73  WINPR_ASSERT(fn);
74 
75  ret->channel = channel;
76  ret->peekFn = fn;
77 
78  if (!channelTracker_setCustomData(ret, data))
79  goto fail;
80 
81  if (!channelTracker_resetCurrentPacket(ret))
82  goto fail;
83 
84  return ret;
85 
86 fail:
87  WINPR_PRAGMA_DIAG_PUSH
88  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
89  channelTracker_free(ret);
90  WINPR_PRAGMA_DIAG_POP
91  return NULL;
92 }
93 
94 PfChannelResult channelTracker_update(ChannelStateTracker* tracker, const BYTE* xdata, size_t xsize,
95  UINT32 flags, size_t totalSize)
96 {
97  PfChannelResult result = PF_CHANNEL_RESULT_ERROR;
98  BOOL firstPacket = (flags & CHANNEL_FLAG_FIRST) != 0;
99  BOOL lastPacket = (flags & CHANNEL_FLAG_LAST) != 0;
100 
101  WINPR_ASSERT(tracker);
102 
103  WLog_VRB(TAG, "channelTracker_update(%s): sz=%" PRIuz " first=%d last=%d",
104  tracker->channel->channel_name, xsize, firstPacket, lastPacket);
105  if (flags & CHANNEL_FLAG_FIRST)
106  {
107  if (!channelTracker_resetCurrentPacket(tracker))
108  return FALSE;
109  channelTracker_setCurrentPacketSize(tracker, totalSize);
110  tracker->currentPacketReceived = 0;
111  tracker->currentPacketFragments = 0;
112  }
113 
114  {
115  const size_t currentPacketSize = channelTracker_getCurrentPacketSize(tracker);
116  if (tracker->currentPacketReceived + xsize > currentPacketSize)
117  WLog_INFO(TAG, "cumulated size is bigger (%" PRIuz ") than total size (%" PRIuz ")",
118  tracker->currentPacketReceived + xsize, currentPacketSize);
119  }
120 
121  tracker->currentPacketReceived += xsize;
122  tracker->currentPacketFragments++;
123 
124  switch (channelTracker_getMode(tracker))
125  {
126  case CHANNEL_TRACKER_PEEK:
127  {
128  wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
129  if (!Stream_EnsureRemainingCapacity(currentPacket, xsize))
130  return PF_CHANNEL_RESULT_ERROR;
131 
132  Stream_Write(currentPacket, xdata, xsize);
133 
134  WINPR_ASSERT(tracker->peekFn);
135  result = tracker->peekFn(tracker, firstPacket, lastPacket);
136  }
137  break;
138  case CHANNEL_TRACKER_PASS:
139  result = PF_CHANNEL_RESULT_PASS;
140  break;
141  case CHANNEL_TRACKER_DROP:
142  result = PF_CHANNEL_RESULT_DROP;
143  break;
144  default:
145  break;
146  }
147 
148  if (lastPacket)
149  {
150  const size_t currentPacketSize = channelTracker_getCurrentPacketSize(tracker);
151  channelTracker_setMode(tracker, CHANNEL_TRACKER_PEEK);
152 
153  if (tracker->currentPacketReceived != currentPacketSize)
154  WLog_INFO(TAG, "cumulated size(%" PRIuz ") does not match total size (%" PRIuz ")",
155  tracker->currentPacketReceived, currentPacketSize);
156  }
157 
158  return result;
159 }
160 
161 void channelTracker_free(ChannelStateTracker* t)
162 {
163  if (!t)
164  return;
165 
166  Stream_Free(t->currentPacket, TRUE);
167  free(t);
168 }
169 
176 PfChannelResult channelTracker_flushCurrent(ChannelStateTracker* t, BOOL first, BOOL last,
177  BOOL toBack)
178 {
179  proxyData* pdata = NULL;
180  pServerContext* ps = NULL;
181  pServerStaticChannelContext* channel = NULL;
182  UINT32 flags = CHANNEL_FLAG_FIRST;
183  BOOL r = 0;
184  const char* direction = toBack ? "F->B" : "B->F";
185  const size_t currentPacketSize = channelTracker_getCurrentPacketSize(t);
186  wStream* currentPacket = channelTracker_getCurrentPacket(t);
187 
188  WINPR_ASSERT(t);
189 
190  WLog_VRB(TAG, "channelTracker_flushCurrent(%s): %s sz=%" PRIuz " first=%d last=%d",
191  t->channel->channel_name, direction, Stream_GetPosition(currentPacket), first, last);
192 
193  if (first)
194  return PF_CHANNEL_RESULT_PASS;
195 
196  pdata = t->pdata;
197  channel = t->channel;
198  if (last)
199  flags |= CHANNEL_FLAG_LAST;
200 
201  if (toBack)
202  {
203  proxyChannelDataEventInfo ev = { 0 };
204 
205  ev.channel_id = WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id);
206  ev.channel_name = channel->channel_name;
207  ev.data = Stream_Buffer(currentPacket);
208  ev.data_len = Stream_GetPosition(currentPacket);
209  ev.flags = flags;
210  ev.total_size = currentPacketSize;
211 
212  if (!pdata->pc->sendChannelData)
213  return PF_CHANNEL_RESULT_ERROR;
214 
215  return pdata->pc->sendChannelData(pdata->pc, &ev) ? PF_CHANNEL_RESULT_DROP
216  : PF_CHANNEL_RESULT_ERROR;
217  }
218 
219  ps = pdata->ps;
220  r = ps->context.peer->SendChannelPacket(
221  ps->context.peer, WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id),
222  currentPacketSize, flags, Stream_Buffer(currentPacket), Stream_GetPosition(currentPacket));
223 
224  return r ? PF_CHANNEL_RESULT_DROP : PF_CHANNEL_RESULT_ERROR;
225 }
226 
227 static PfChannelResult pf_channel_generic_back_data(proxyData* pdata,
228  const pServerStaticChannelContext* channel,
229  const BYTE* xdata, size_t xsize, UINT32 flags,
230  size_t totalSize)
231 {
232  proxyChannelDataEventInfo ev = { 0 };
233 
234  WINPR_ASSERT(pdata);
235  WINPR_ASSERT(channel);
236 
237  switch (channel->channelMode)
238  {
239  case PF_UTILS_CHANNEL_PASSTHROUGH:
240  ev.channel_id = WINPR_ASSERTING_INT_CAST(UINT16, channel->back_channel_id);
241  ev.channel_name = channel->channel_name;
242  ev.data = xdata;
243  ev.data_len = xsize;
244  ev.flags = flags;
245  ev.total_size = totalSize;
246 
247  if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA,
248  pdata, &ev))
249  return PF_CHANNEL_RESULT_DROP; /* Silently drop */
250 
251  return PF_CHANNEL_RESULT_PASS;
252 
253  case PF_UTILS_CHANNEL_INTERCEPT:
254  /* TODO */
255  case PF_UTILS_CHANNEL_BLOCK:
256  default:
257  return PF_CHANNEL_RESULT_DROP;
258  }
259 }
260 
261 static PfChannelResult pf_channel_generic_front_data(proxyData* pdata,
262  const pServerStaticChannelContext* channel,
263  const BYTE* xdata, size_t xsize, UINT32 flags,
264  size_t totalSize)
265 {
266  proxyChannelDataEventInfo ev = { 0 };
267 
268  WINPR_ASSERT(pdata);
269  WINPR_ASSERT(channel);
270 
271  switch (channel->channelMode)
272  {
273  case PF_UTILS_CHANNEL_PASSTHROUGH:
274  ev.channel_id = WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id);
275  ev.channel_name = channel->channel_name;
276  ev.data = xdata;
277  ev.data_len = xsize;
278  ev.flags = flags;
279  ev.total_size = totalSize;
280 
281  if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA,
282  pdata, &ev))
283  return PF_CHANNEL_RESULT_DROP; /* Silently drop */
284 
285  return PF_CHANNEL_RESULT_PASS;
286 
287  case PF_UTILS_CHANNEL_INTERCEPT:
288  /* TODO */
289  case PF_UTILS_CHANNEL_BLOCK:
290  default:
291  return PF_CHANNEL_RESULT_DROP;
292  }
293 }
294 
295 BOOL pf_channel_setup_generic(pServerStaticChannelContext* channel)
296 {
297  WINPR_ASSERT(channel);
298  channel->onBackData = pf_channel_generic_back_data;
299  channel->onFrontData = pf_channel_generic_front_data;
300  return TRUE;
301 }
302 
303 BOOL channelTracker_setMode(ChannelStateTracker* tracker, ChannelTrackerMode mode)
304 {
305  WINPR_ASSERT(tracker);
306  tracker->mode = mode;
307  return TRUE;
308 }
309 
310 ChannelTrackerMode channelTracker_getMode(ChannelStateTracker* tracker)
311 {
312  WINPR_ASSERT(tracker);
313  return tracker->mode;
314 }
315 
316 BOOL channelTracker_setPData(ChannelStateTracker* tracker, proxyData* pdata)
317 {
318  WINPR_ASSERT(tracker);
319  tracker->pdata = pdata;
320  return TRUE;
321 }
322 
323 proxyData* channelTracker_getPData(ChannelStateTracker* tracker)
324 {
325  WINPR_ASSERT(tracker);
326  return tracker->pdata;
327 }
328 
329 wStream* channelTracker_getCurrentPacket(ChannelStateTracker* tracker)
330 {
331  WINPR_ASSERT(tracker);
332  return tracker->currentPacket;
333 }
334 
335 BOOL channelTracker_setCustomData(ChannelStateTracker* tracker, void* data)
336 {
337  WINPR_ASSERT(tracker);
338  tracker->trackerData = data;
339  return TRUE;
340 }
341 
342 void* channelTracker_getCustomData(ChannelStateTracker* tracker)
343 {
344  WINPR_ASSERT(tracker);
345  return tracker->trackerData;
346 }
347 
348 size_t channelTracker_getCurrentPacketSize(ChannelStateTracker* tracker)
349 {
350  WINPR_ASSERT(tracker);
351  return tracker->currentPacketSize;
352 }
353 
354 BOOL channelTracker_setCurrentPacketSize(ChannelStateTracker* tracker, size_t size)
355 {
356  WINPR_ASSERT(tracker);
357  tracker->currentPacketSize = size;
358  return TRUE;
359 }