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