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