/src/FreeRDP/libfreerdp/core/channels.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Virtual Channels |
4 | | * |
5 | | * Copyright 2011 Vic Lee |
6 | | * Copyright 2015 Copyright 2015 Thincast Technologies GmbH |
7 | | * |
8 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | | * you may not use this file except in compliance with the License. |
10 | | * You may obtain a copy of the License at |
11 | | * |
12 | | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | | * |
14 | | * Unless required by applicable law or agreed to in writing, software |
15 | | * distributed under the License is distributed on an "AS IS" BASIS, |
16 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | | * See the License for the specific language governing permissions and |
18 | | * limitations under the License. |
19 | | */ |
20 | | |
21 | | #include <freerdp/config.h> |
22 | | |
23 | | #include "settings.h" |
24 | | |
25 | | #include <stdio.h> |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | |
29 | | #include <winpr/crt.h> |
30 | | #include <winpr/assert.h> |
31 | | #include <winpr/stream.h> |
32 | | #include <winpr/wtsapi.h> |
33 | | |
34 | | #include <freerdp/freerdp.h> |
35 | | #include <freerdp/constants.h> |
36 | | |
37 | | #include <freerdp/log.h> |
38 | | #include <freerdp/svc.h> |
39 | | #include <freerdp/peer.h> |
40 | | #include <freerdp/addin.h> |
41 | | |
42 | | #include <freerdp/client/channels.h> |
43 | | #include <freerdp/client/drdynvc.h> |
44 | | #include <freerdp/channels/channels.h> |
45 | | |
46 | | #include "rdp.h" |
47 | | #include "client.h" |
48 | | #include "server.h" |
49 | | #include "channels.h" |
50 | | |
51 | | #define TAG FREERDP_TAG("core.channels") |
52 | | |
53 | | BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_t size) |
54 | 0 | { |
55 | 0 | size_t left = 0; |
56 | 0 | UINT32 flags = 0; |
57 | 0 | size_t chunkSize = 0; |
58 | 0 | rdpMcs* mcs = NULL; |
59 | 0 | const rdpMcsChannel* channel = NULL; |
60 | |
|
61 | 0 | WINPR_ASSERT(rdp); |
62 | 0 | WINPR_ASSERT(data || (size == 0)); |
63 | | |
64 | 0 | mcs = rdp->mcs; |
65 | 0 | WINPR_ASSERT(mcs); |
66 | 0 | for (UINT32 i = 0; i < mcs->channelCount; i++) |
67 | 0 | { |
68 | 0 | const rdpMcsChannel* cur = &mcs->channels[i]; |
69 | 0 | if (cur->ChannelId == channelId) |
70 | 0 | { |
71 | 0 | channel = cur; |
72 | 0 | break; |
73 | 0 | } |
74 | 0 | } |
75 | |
|
76 | 0 | if (!channel) |
77 | 0 | { |
78 | 0 | WLog_ERR(TAG, "freerdp_channel_send: unknown channelId %" PRIu16 "", channelId); |
79 | 0 | return FALSE; |
80 | 0 | } |
81 | | |
82 | 0 | flags = CHANNEL_FLAG_FIRST; |
83 | 0 | left = size; |
84 | |
|
85 | 0 | while (left > 0) |
86 | 0 | { |
87 | 0 | if (left > rdp->settings->VCChunkSize) |
88 | 0 | { |
89 | 0 | chunkSize = rdp->settings->VCChunkSize; |
90 | 0 | } |
91 | 0 | else |
92 | 0 | { |
93 | 0 | chunkSize = left; |
94 | 0 | flags |= CHANNEL_FLAG_LAST; |
95 | 0 | } |
96 | |
|
97 | 0 | if (!rdp->settings->ServerMode && (channel->options & CHANNEL_OPTION_SHOW_PROTOCOL)) |
98 | 0 | { |
99 | 0 | flags |= CHANNEL_FLAG_SHOW_PROTOCOL; |
100 | 0 | } |
101 | |
|
102 | 0 | if (!freerdp_channel_send_packet(rdp, channelId, size, flags, data, chunkSize)) |
103 | 0 | return FALSE; |
104 | | |
105 | 0 | data += chunkSize; |
106 | 0 | left -= chunkSize; |
107 | 0 | flags = 0; |
108 | 0 | } |
109 | | |
110 | 0 | return TRUE; |
111 | 0 | } |
112 | | |
113 | | BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength) |
114 | 0 | { |
115 | 0 | BOOL rc = FALSE; |
116 | 0 | UINT32 length = 0; |
117 | 0 | UINT32 flags = 0; |
118 | 0 | size_t chunkLength = 0; |
119 | |
|
120 | 0 | WINPR_ASSERT(instance); |
121 | | |
122 | 0 | if (packetLength < 8) |
123 | 0 | { |
124 | 0 | WLog_ERR(TAG, "Header length %" PRIdz " bytes promised, none available", packetLength); |
125 | 0 | return FALSE; |
126 | 0 | } |
127 | 0 | packetLength -= 8; |
128 | |
|
129 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) |
130 | 0 | return FALSE; |
131 | | |
132 | | /* [MS-RDPBCGR] 3.1.5.2.2 Processing of Virtual Channel PDU |
133 | | * chunked data. Length is the total size of the combined data, |
134 | | * chunkLength is the actual data received. |
135 | | * check chunkLength against packetLength, which is the TPKT header size. |
136 | | */ |
137 | 0 | Stream_Read_UINT32(s, length); |
138 | 0 | Stream_Read_UINT32(s, flags); |
139 | 0 | chunkLength = Stream_GetRemainingLength(s); |
140 | 0 | if (packetLength != chunkLength) |
141 | 0 | { |
142 | 0 | WLog_ERR(TAG, "Header length %" PRIdz " != actual length %" PRIdz, packetLength, |
143 | 0 | chunkLength); |
144 | 0 | return FALSE; |
145 | 0 | } |
146 | | |
147 | 0 | IFCALLRET(instance->ReceiveChannelData, rc, instance, channelId, Stream_Pointer(s), chunkLength, |
148 | 0 | flags, length); |
149 | 0 | if (!rc) |
150 | 0 | { |
151 | 0 | WLog_WARN(TAG, "ReceiveChannelData returned %d", rc); |
152 | 0 | return FALSE; |
153 | 0 | } |
154 | | |
155 | 0 | return Stream_SafeSeek(s, chunkLength); |
156 | 0 | } |
157 | | |
158 | | BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId) |
159 | 0 | { |
160 | 0 | UINT32 length = 0; |
161 | 0 | UINT32 flags = 0; |
162 | |
|
163 | 0 | WINPR_ASSERT(client); |
164 | 0 | WINPR_ASSERT(s); |
165 | | |
166 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) |
167 | 0 | return FALSE; |
168 | | |
169 | 0 | Stream_Read_UINT32(s, length); |
170 | 0 | Stream_Read_UINT32(s, flags); |
171 | 0 | const size_t chunkLength = Stream_GetRemainingLength(s); |
172 | 0 | if (chunkLength > UINT32_MAX) |
173 | 0 | return FALSE; |
174 | | |
175 | 0 | if (client->VirtualChannelRead) |
176 | 0 | { |
177 | 0 | int rc = 0; |
178 | 0 | BOOL found = FALSE; |
179 | 0 | HANDLE hChannel = 0; |
180 | 0 | rdpContext* context = client->context; |
181 | 0 | rdpMcs* mcs = context->rdp->mcs; |
182 | |
|
183 | 0 | for (UINT32 index = 0; index < mcs->channelCount; index++) |
184 | 0 | { |
185 | 0 | const rdpMcsChannel* mcsChannel = &(mcs->channels[index]); |
186 | |
|
187 | 0 | if (mcsChannel->ChannelId == channelId) |
188 | 0 | { |
189 | 0 | hChannel = (HANDLE)mcsChannel->handle; |
190 | 0 | found = TRUE; |
191 | 0 | break; |
192 | 0 | } |
193 | 0 | } |
194 | |
|
195 | 0 | if (!found) |
196 | 0 | return FALSE; |
197 | | |
198 | 0 | rc = client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), (UINT32)chunkLength); |
199 | 0 | if (rc < 0) |
200 | 0 | return FALSE; |
201 | 0 | } |
202 | 0 | else if (client->ReceiveChannelData) |
203 | 0 | { |
204 | 0 | BOOL rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s), |
205 | 0 | (UINT32)chunkLength, flags, length); |
206 | 0 | if (!rc) |
207 | 0 | return FALSE; |
208 | 0 | } |
209 | 0 | if (!Stream_SafeSeek(s, chunkLength)) |
210 | 0 | { |
211 | 0 | WLog_WARN(TAG, "Short PDU, need %" PRIuz " bytes, got %" PRIuz, chunkLength, |
212 | 0 | Stream_GetRemainingLength(s)); |
213 | 0 | return FALSE; |
214 | 0 | } |
215 | 0 | return TRUE; |
216 | 0 | } |
217 | | |
218 | | static const WtsApiFunctionTable FreeRDP_WtsApiFunctionTable = { |
219 | | 0, /* dwVersion */ |
220 | | 0, /* dwFlags */ |
221 | | |
222 | | FreeRDP_WTSStopRemoteControlSession, /* StopRemoteControlSession */ |
223 | | FreeRDP_WTSStartRemoteControlSessionW, /* StartRemoteControlSessionW */ |
224 | | FreeRDP_WTSStartRemoteControlSessionA, /* StartRemoteControlSessionA */ |
225 | | FreeRDP_WTSConnectSessionW, /* ConnectSessionW */ |
226 | | FreeRDP_WTSConnectSessionA, /* ConnectSessionA */ |
227 | | FreeRDP_WTSEnumerateServersW, /* EnumerateServersW */ |
228 | | FreeRDP_WTSEnumerateServersA, /* EnumerateServersA */ |
229 | | FreeRDP_WTSOpenServerW, /* OpenServerW */ |
230 | | FreeRDP_WTSOpenServerA, /* OpenServerA */ |
231 | | FreeRDP_WTSOpenServerExW, /* OpenServerExW */ |
232 | | FreeRDP_WTSOpenServerExA, /* OpenServerExA */ |
233 | | FreeRDP_WTSCloseServer, /* CloseServer */ |
234 | | FreeRDP_WTSEnumerateSessionsW, /* EnumerateSessionsW */ |
235 | | FreeRDP_WTSEnumerateSessionsA, /* EnumerateSessionsA */ |
236 | | FreeRDP_WTSEnumerateSessionsExW, /* EnumerateSessionsExW */ |
237 | | FreeRDP_WTSEnumerateSessionsExA, /* EnumerateSessionsExA */ |
238 | | FreeRDP_WTSEnumerateProcessesW, /* EnumerateProcessesW */ |
239 | | FreeRDP_WTSEnumerateProcessesA, /* EnumerateProcessesA */ |
240 | | FreeRDP_WTSTerminateProcess, /* TerminateProcess */ |
241 | | FreeRDP_WTSQuerySessionInformationW, /* QuerySessionInformationW */ |
242 | | FreeRDP_WTSQuerySessionInformationA, /* QuerySessionInformationA */ |
243 | | FreeRDP_WTSQueryUserConfigW, /* QueryUserConfigW */ |
244 | | FreeRDP_WTSQueryUserConfigA, /* QueryUserConfigA */ |
245 | | FreeRDP_WTSSetUserConfigW, /* SetUserConfigW */ |
246 | | FreeRDP_WTSSetUserConfigA, /* SetUserConfigA */ |
247 | | FreeRDP_WTSSendMessageW, /* SendMessageW */ |
248 | | FreeRDP_WTSSendMessageA, /* SendMessageA */ |
249 | | FreeRDP_WTSDisconnectSession, /* DisconnectSession */ |
250 | | FreeRDP_WTSLogoffSession, /* LogoffSession */ |
251 | | FreeRDP_WTSShutdownSystem, /* ShutdownSystem */ |
252 | | FreeRDP_WTSWaitSystemEvent, /* WaitSystemEvent */ |
253 | | FreeRDP_WTSVirtualChannelOpen, /* VirtualChannelOpen */ |
254 | | FreeRDP_WTSVirtualChannelOpenEx, /* VirtualChannelOpenEx */ |
255 | | FreeRDP_WTSVirtualChannelClose, /* VirtualChannelClose */ |
256 | | FreeRDP_WTSVirtualChannelRead, /* VirtualChannelRead */ |
257 | | FreeRDP_WTSVirtualChannelWrite, /* VirtualChannelWrite */ |
258 | | FreeRDP_WTSVirtualChannelPurgeInput, /* VirtualChannelPurgeInput */ |
259 | | FreeRDP_WTSVirtualChannelPurgeOutput, /* VirtualChannelPurgeOutput */ |
260 | | FreeRDP_WTSVirtualChannelQuery, /* VirtualChannelQuery */ |
261 | | FreeRDP_WTSFreeMemory, /* FreeMemory */ |
262 | | FreeRDP_WTSRegisterSessionNotification, /* RegisterSessionNotification */ |
263 | | FreeRDP_WTSUnRegisterSessionNotification, /* UnRegisterSessionNotification */ |
264 | | FreeRDP_WTSRegisterSessionNotificationEx, /* RegisterSessionNotificationEx */ |
265 | | FreeRDP_WTSUnRegisterSessionNotificationEx, /* UnRegisterSessionNotificationEx */ |
266 | | FreeRDP_WTSQueryUserToken, /* QueryUserToken */ |
267 | | FreeRDP_WTSFreeMemoryExW, /* FreeMemoryExW */ |
268 | | FreeRDP_WTSFreeMemoryExA, /* FreeMemoryExA */ |
269 | | FreeRDP_WTSEnumerateProcessesExW, /* EnumerateProcessesExW */ |
270 | | FreeRDP_WTSEnumerateProcessesExA, /* EnumerateProcessesExA */ |
271 | | FreeRDP_WTSEnumerateListenersW, /* EnumerateListenersW */ |
272 | | FreeRDP_WTSEnumerateListenersA, /* EnumerateListenersA */ |
273 | | FreeRDP_WTSQueryListenerConfigW, /* QueryListenerConfigW */ |
274 | | FreeRDP_WTSQueryListenerConfigA, /* QueryListenerConfigA */ |
275 | | FreeRDP_WTSCreateListenerW, /* CreateListenerW */ |
276 | | FreeRDP_WTSCreateListenerA, /* CreateListenerA */ |
277 | | FreeRDP_WTSSetListenerSecurityW, /* SetListenerSecurityW */ |
278 | | FreeRDP_WTSSetListenerSecurityA, /* SetListenerSecurityA */ |
279 | | FreeRDP_WTSGetListenerSecurityW, /* GetListenerSecurityW */ |
280 | | FreeRDP_WTSGetListenerSecurityA, /* GetListenerSecurityA */ |
281 | | FreeRDP_WTSEnableChildSessions, /* EnableChildSessions */ |
282 | | FreeRDP_WTSIsChildSessionsEnabled, /* IsChildSessionsEnabled */ |
283 | | FreeRDP_WTSGetChildSessionId, /* GetChildSessionId */ |
284 | | FreeRDP_WTSGetActiveConsoleSessionId, /* GetActiveConsoleSessionId */ |
285 | | FreeRDP_WTSLogonUser, |
286 | | FreeRDP_WTSLogoffUser, |
287 | | FreeRDP_WTSStartRemoteControlSessionExW, |
288 | | FreeRDP_WTSStartRemoteControlSessionExA |
289 | | }; |
290 | | |
291 | | const WtsApiFunctionTable* FreeRDP_InitWtsApi(void) |
292 | 0 | { |
293 | 0 | return &FreeRDP_WtsApiFunctionTable; |
294 | 0 | } |
295 | | |
296 | | BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags, |
297 | | const BYTE* data, size_t chunkSize) |
298 | 0 | { |
299 | 0 | if (totalSize > UINT32_MAX) |
300 | 0 | return FALSE; |
301 | | |
302 | 0 | UINT16 sec_flags = 0; |
303 | 0 | wStream* s = rdp_send_stream_init(rdp, &sec_flags); |
304 | |
|
305 | 0 | if (!s) |
306 | 0 | return FALSE; |
307 | | |
308 | 0 | if (!Stream_EnsureRemainingCapacity(s, chunkSize + 8)) |
309 | 0 | { |
310 | 0 | Stream_Release(s); |
311 | 0 | return FALSE; |
312 | 0 | } |
313 | | |
314 | 0 | Stream_Write_UINT32(s, (UINT32)totalSize); |
315 | 0 | Stream_Write_UINT32(s, flags); |
316 | | |
317 | 0 | Stream_Write(s, data, chunkSize); |
318 | | |
319 | | /* WLog_DBG(TAG, "sending data (flags=0x%x size=%d)", flags, size); */ |
320 | 0 | return rdp_send(rdp, s, channelId, sec_flags); |
321 | 0 | } |