/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 | 0 | size_t chunkLength = 0; |
163 | |
|
164 | 0 | WINPR_ASSERT(client); |
165 | 0 | WINPR_ASSERT(s); |
166 | | |
167 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) |
168 | 0 | return FALSE; |
169 | | |
170 | 0 | Stream_Read_UINT32(s, length); |
171 | 0 | Stream_Read_UINT32(s, flags); |
172 | 0 | chunkLength = Stream_GetRemainingLength(s); |
173 | |
|
174 | 0 | if (client->VirtualChannelRead) |
175 | 0 | { |
176 | 0 | int rc = 0; |
177 | 0 | BOOL found = FALSE; |
178 | 0 | HANDLE hChannel = 0; |
179 | 0 | rdpContext* context = client->context; |
180 | 0 | rdpMcs* mcs = context->rdp->mcs; |
181 | |
|
182 | 0 | for (UINT32 index = 0; index < mcs->channelCount; index++) |
183 | 0 | { |
184 | 0 | const rdpMcsChannel* mcsChannel = &(mcs->channels[index]); |
185 | |
|
186 | 0 | if (mcsChannel->ChannelId == channelId) |
187 | 0 | { |
188 | 0 | hChannel = (HANDLE)mcsChannel->handle; |
189 | 0 | found = TRUE; |
190 | 0 | break; |
191 | 0 | } |
192 | 0 | } |
193 | |
|
194 | 0 | if (!found) |
195 | 0 | return FALSE; |
196 | | |
197 | 0 | rc = client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), chunkLength); |
198 | 0 | if (rc < 0) |
199 | 0 | return FALSE; |
200 | 0 | } |
201 | 0 | else if (client->ReceiveChannelData) |
202 | 0 | { |
203 | 0 | BOOL rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s), chunkLength, |
204 | 0 | flags, length); |
205 | 0 | if (!rc) |
206 | 0 | return FALSE; |
207 | 0 | } |
208 | 0 | if (!Stream_SafeSeek(s, chunkLength)) |
209 | 0 | { |
210 | 0 | WLog_WARN(TAG, "Short PDU, need %" PRIuz " bytes, got %" PRIuz, chunkLength, |
211 | 0 | Stream_GetRemainingLength(s)); |
212 | 0 | return FALSE; |
213 | 0 | } |
214 | 0 | return TRUE; |
215 | 0 | } |
216 | | |
217 | | static const WtsApiFunctionTable FreeRDP_WtsApiFunctionTable = { |
218 | | 0, /* dwVersion */ |
219 | | 0, /* dwFlags */ |
220 | | |
221 | | FreeRDP_WTSStopRemoteControlSession, /* StopRemoteControlSession */ |
222 | | FreeRDP_WTSStartRemoteControlSessionW, /* StartRemoteControlSessionW */ |
223 | | FreeRDP_WTSStartRemoteControlSessionA, /* StartRemoteControlSessionA */ |
224 | | FreeRDP_WTSConnectSessionW, /* ConnectSessionW */ |
225 | | FreeRDP_WTSConnectSessionA, /* ConnectSessionA */ |
226 | | FreeRDP_WTSEnumerateServersW, /* EnumerateServersW */ |
227 | | FreeRDP_WTSEnumerateServersA, /* EnumerateServersA */ |
228 | | FreeRDP_WTSOpenServerW, /* OpenServerW */ |
229 | | FreeRDP_WTSOpenServerA, /* OpenServerA */ |
230 | | FreeRDP_WTSOpenServerExW, /* OpenServerExW */ |
231 | | FreeRDP_WTSOpenServerExA, /* OpenServerExA */ |
232 | | FreeRDP_WTSCloseServer, /* CloseServer */ |
233 | | FreeRDP_WTSEnumerateSessionsW, /* EnumerateSessionsW */ |
234 | | FreeRDP_WTSEnumerateSessionsA, /* EnumerateSessionsA */ |
235 | | FreeRDP_WTSEnumerateSessionsExW, /* EnumerateSessionsExW */ |
236 | | FreeRDP_WTSEnumerateSessionsExA, /* EnumerateSessionsExA */ |
237 | | FreeRDP_WTSEnumerateProcessesW, /* EnumerateProcessesW */ |
238 | | FreeRDP_WTSEnumerateProcessesA, /* EnumerateProcessesA */ |
239 | | FreeRDP_WTSTerminateProcess, /* TerminateProcess */ |
240 | | FreeRDP_WTSQuerySessionInformationW, /* QuerySessionInformationW */ |
241 | | FreeRDP_WTSQuerySessionInformationA, /* QuerySessionInformationA */ |
242 | | FreeRDP_WTSQueryUserConfigW, /* QueryUserConfigW */ |
243 | | FreeRDP_WTSQueryUserConfigA, /* QueryUserConfigA */ |
244 | | FreeRDP_WTSSetUserConfigW, /* SetUserConfigW */ |
245 | | FreeRDP_WTSSetUserConfigA, /* SetUserConfigA */ |
246 | | FreeRDP_WTSSendMessageW, /* SendMessageW */ |
247 | | FreeRDP_WTSSendMessageA, /* SendMessageA */ |
248 | | FreeRDP_WTSDisconnectSession, /* DisconnectSession */ |
249 | | FreeRDP_WTSLogoffSession, /* LogoffSession */ |
250 | | FreeRDP_WTSShutdownSystem, /* ShutdownSystem */ |
251 | | FreeRDP_WTSWaitSystemEvent, /* WaitSystemEvent */ |
252 | | FreeRDP_WTSVirtualChannelOpen, /* VirtualChannelOpen */ |
253 | | FreeRDP_WTSVirtualChannelOpenEx, /* VirtualChannelOpenEx */ |
254 | | FreeRDP_WTSVirtualChannelClose, /* VirtualChannelClose */ |
255 | | FreeRDP_WTSVirtualChannelRead, /* VirtualChannelRead */ |
256 | | FreeRDP_WTSVirtualChannelWrite, /* VirtualChannelWrite */ |
257 | | FreeRDP_WTSVirtualChannelPurgeInput, /* VirtualChannelPurgeInput */ |
258 | | FreeRDP_WTSVirtualChannelPurgeOutput, /* VirtualChannelPurgeOutput */ |
259 | | FreeRDP_WTSVirtualChannelQuery, /* VirtualChannelQuery */ |
260 | | FreeRDP_WTSFreeMemory, /* FreeMemory */ |
261 | | FreeRDP_WTSRegisterSessionNotification, /* RegisterSessionNotification */ |
262 | | FreeRDP_WTSUnRegisterSessionNotification, /* UnRegisterSessionNotification */ |
263 | | FreeRDP_WTSRegisterSessionNotificationEx, /* RegisterSessionNotificationEx */ |
264 | | FreeRDP_WTSUnRegisterSessionNotificationEx, /* UnRegisterSessionNotificationEx */ |
265 | | FreeRDP_WTSQueryUserToken, /* QueryUserToken */ |
266 | | FreeRDP_WTSFreeMemoryExW, /* FreeMemoryExW */ |
267 | | FreeRDP_WTSFreeMemoryExA, /* FreeMemoryExA */ |
268 | | FreeRDP_WTSEnumerateProcessesExW, /* EnumerateProcessesExW */ |
269 | | FreeRDP_WTSEnumerateProcessesExA, /* EnumerateProcessesExA */ |
270 | | FreeRDP_WTSEnumerateListenersW, /* EnumerateListenersW */ |
271 | | FreeRDP_WTSEnumerateListenersA, /* EnumerateListenersA */ |
272 | | FreeRDP_WTSQueryListenerConfigW, /* QueryListenerConfigW */ |
273 | | FreeRDP_WTSQueryListenerConfigA, /* QueryListenerConfigA */ |
274 | | FreeRDP_WTSCreateListenerW, /* CreateListenerW */ |
275 | | FreeRDP_WTSCreateListenerA, /* CreateListenerA */ |
276 | | FreeRDP_WTSSetListenerSecurityW, /* SetListenerSecurityW */ |
277 | | FreeRDP_WTSSetListenerSecurityA, /* SetListenerSecurityA */ |
278 | | FreeRDP_WTSGetListenerSecurityW, /* GetListenerSecurityW */ |
279 | | FreeRDP_WTSGetListenerSecurityA, /* GetListenerSecurityA */ |
280 | | FreeRDP_WTSEnableChildSessions, /* EnableChildSessions */ |
281 | | FreeRDP_WTSIsChildSessionsEnabled, /* IsChildSessionsEnabled */ |
282 | | FreeRDP_WTSGetChildSessionId, /* GetChildSessionId */ |
283 | | FreeRDP_WTSGetActiveConsoleSessionId, /* GetActiveConsoleSessionId */ |
284 | | FreeRDP_WTSLogonUser, |
285 | | FreeRDP_WTSLogoffUser, |
286 | | FreeRDP_WTSStartRemoteControlSessionExW, |
287 | | FreeRDP_WTSStartRemoteControlSessionExA |
288 | | }; |
289 | | |
290 | | const WtsApiFunctionTable* FreeRDP_InitWtsApi(void) |
291 | 0 | { |
292 | 0 | return &FreeRDP_WtsApiFunctionTable; |
293 | 0 | } |
294 | | |
295 | | BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags, |
296 | | const BYTE* data, size_t chunkSize) |
297 | 0 | { |
298 | 0 | wStream* s = rdp_send_stream_init(rdp); |
299 | |
|
300 | 0 | if (!s) |
301 | 0 | return FALSE; |
302 | | |
303 | 0 | Stream_Write_UINT32(s, totalSize); |
304 | 0 | Stream_Write_UINT32(s, flags); |
305 | |
|
306 | 0 | if (!Stream_EnsureCapacity(s, chunkSize)) |
307 | 0 | { |
308 | 0 | Stream_Release(s); |
309 | 0 | return FALSE; |
310 | 0 | } |
311 | | |
312 | 0 | Stream_Write(s, data, chunkSize); |
313 | | |
314 | | /* WLog_DBG(TAG, "sending data (flags=0x%x size=%d)", flags, size); */ |
315 | 0 | return rdp_send(rdp, s, channelId); |
316 | 0 | } |