1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - Virtual channels
4 Copyright 2003 Erik Forsberg <forsberg@cendio.se> for Cendio AB
5 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 2003-2008
6 Copyright 2016 Alexander Zakharov <uglym8@gmail.com>
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "rdesktop.h"
23
24 #define MAX_CHANNELS 6
25 #define CHANNEL_CHUNK_LENGTH 1600
26 #define CHANNEL_FLAG_FIRST 0x01
27 #define CHANNEL_FLAG_LAST 0x02
28 #define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
29
30 extern RDP_VERSION g_rdp_version;
31 extern RD_BOOL g_encryption;
32
33 uint32 vc_chunk_size = CHANNEL_CHUNK_LENGTH;
34
35 VCHANNEL g_channels[MAX_CHANNELS];
36 unsigned int g_num_channels;
37
38 /* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5
39 channels to MCS channels.
40
41 The format of TAG_SRV_CHANNELS seems to be
42
43 global_channel_no (uint16le)
44 number_of_other_channels (uint16le)
45 ..followed by uint16les for the other channels.
46 */
47
48 VCHANNEL *
channel_register(char * name,uint32 flags,void (* callback)(STREAM))49 channel_register(char *name, uint32 flags, void (*callback) (STREAM))
50 {
51 VCHANNEL *channel;
52
53 if (g_rdp_version < RDP_V5)
54 return NULL;
55
56 if (g_num_channels >= MAX_CHANNELS)
57 {
58 logger(Core, Error,
59 "channel_register(), channel table full, increase MAX_CHANNELS");
60 return NULL;
61 }
62
63 channel = &g_channels[g_num_channels];
64 channel->mcs_id = MCS_GLOBAL_CHANNEL + 1 + g_num_channels;
65 strncpy(channel->name, name, 8);
66 channel->flags = flags;
67 channel->process = callback;
68 g_num_channels++;
69 return channel;
70 }
71
72 STREAM
channel_init(VCHANNEL * channel,uint32 length)73 channel_init(VCHANNEL * channel, uint32 length)
74 {
75 UNUSED(channel);
76 STREAM s;
77
78 s = sec_init(g_encryption ? SEC_ENCRYPT : 0, length + 8);
79 s_push_layer(s, channel_hdr, 8);
80 return s;
81 }
82
83 static void
channel_send_chunk(STREAM s,VCHANNEL * channel,uint32 length)84 channel_send_chunk(STREAM s, VCHANNEL * channel, uint32 length)
85 {
86 uint32 flags;
87 uint32 thislength;
88 RD_BOOL inplace;
89 STREAM chunk;
90
91 /* Note: In the original clipboard implementation, this number was
92 1592, not 1600. However, I don't remember the reason and 1600 seems
93 to work so.. This applies only to *this* length, not the length of
94 continuation or ending packets. */
95
96 /* Actually, CHANNEL_CHUNK_LENGTH (default value is 1600 bytes) is described
97 in MS-RDPBCGR (s. 2.2.6, s.3.1.5.2.1) and can be set by server only
98 in the optional field VCChunkSize of VC Caps) */
99
100 thislength = MIN(s_remaining(s), vc_chunk_size);
101
102 flags = 0;
103 if (length == s_remaining(s))
104 {
105 flags |= CHANNEL_FLAG_FIRST;
106 }
107 if (s_remaining(s) == thislength)
108 {
109 flags |= CHANNEL_FLAG_LAST;
110 }
111 if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
112 {
113 flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
114 }
115
116 logger(Protocol, Debug, "channel_send_chunk(), sending %d bytes with flags 0x%x",
117 thislength, flags);
118
119 /* first fragment sent in-place */
120 inplace = False;
121 if ((flags & (CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST)) ==
122 (CHANNEL_FLAG_FIRST|CHANNEL_FLAG_LAST))
123 {
124 inplace = True;
125 }
126
127 if (inplace)
128 {
129 s_pop_layer(s, channel_hdr);
130 chunk = s;
131 }
132 else
133 {
134 chunk = sec_init(g_encryption ? SEC_ENCRYPT : 0, thislength + 8);
135 }
136
137 out_uint32_le(chunk, length);
138 out_uint32_le(chunk, flags);
139 if (!inplace)
140 {
141 out_uint8stream(chunk, s, thislength);
142 s_mark_end(chunk);
143 }
144 sec_send_to_channel(chunk, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
145
146 /* Sending modifies the current offset, so make it is marked as
147 fully completed. */
148 if (inplace)
149 {
150 in_uint8s(s, s_remaining(s));
151 }
152
153 if (!inplace)
154 {
155 s_free(chunk);
156 }
157 }
158
159 void
channel_send(STREAM s,VCHANNEL * channel)160 channel_send(STREAM s, VCHANNEL * channel)
161 {
162 uint32 length;
163
164 #ifdef WITH_SCARD
165 scard_lock(SCARD_LOCK_CHANNEL);
166 #endif
167
168 s_pop_layer(s, channel_hdr);
169 in_uint8s(s, 8);
170 length = s_remaining(s);
171
172 logger(Protocol, Debug, "channel_send(), channel = %d, length = %d", channel->mcs_id,
173 length);
174
175 while (!s_check_end(s))
176 {
177 channel_send_chunk(s, channel, length);
178 }
179
180 #ifdef WITH_SCARD
181 scard_unlock(SCARD_LOCK_CHANNEL);
182 #endif
183 }
184
185 void
channel_process(STREAM s,uint16 mcs_channel)186 channel_process(STREAM s, uint16 mcs_channel)
187 {
188 uint32 length, flags;
189 uint32 thislength;
190 VCHANNEL *channel = NULL;
191 unsigned int i;
192 STREAM in;
193
194 for (i = 0; i < g_num_channels; i++)
195 {
196 channel = &g_channels[i];
197 if (channel->mcs_id == mcs_channel)
198 break;
199 }
200
201 if (i >= g_num_channels)
202 return;
203
204 in_uint32_le(s, length);
205 in_uint32_le(s, flags);
206 if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST))
207 {
208 /* single fragment - pass straight up */
209 channel->process(s);
210 }
211 else
212 {
213 /* add fragment to defragmentation buffer */
214 in = &channel->in;
215 if (flags & CHANNEL_FLAG_FIRST)
216 {
217 s_realloc(in, length);
218 s_reset(in);
219 }
220
221 thislength = s_remaining(s);
222 out_uint8stream(in, s, thislength);
223
224 if (flags & CHANNEL_FLAG_LAST)
225 {
226 s_mark_end(in);
227 s_seek(in, 0);
228 channel->process(in);
229 }
230 }
231 }
232