1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * X.224 Transport Protocol Data Units (TPDUs)
4 *
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <winpr/print.h>
26
27 #include <freerdp/log.h>
28
29 #include "tpdu.h"
30
31 #define TAG FREERDP_TAG("core")
32
33 /**
34 * TPDUs are defined in:
35 *
36 * http://www.itu.int/rec/T-REC-X.224-199511-I/
37 * X.224: Information technology - Open Systems Interconnection - Protocol for providing the
38 * connection-mode transport service
39 *
40 * RDP uses only TPDUs of class 0, the "simple class" defined in section 8 of X.224
41 *
42 * TPDU Header
43 * ____________________ byte
44 * | |
45 * | LI | 1
46 * |____________________|
47 * | |
48 * | Code | 2
49 * |____________________|
50 * | |
51 * | | 3
52 * |_______DST-REF______|
53 * | |
54 * | | 4
55 * |____________________|
56 * | |
57 * | | 5
58 * |_______SRC-REF______|
59 * | |
60 * | | 6
61 * |____________________|
62 * | |
63 * | Class | 7
64 * |____________________|
65 * | ... |
66 */
67
68 static void tpdu_write_header(wStream* s, UINT16 length, BYTE code);
69
70 /**
71 * Read TPDU header.
72 * @param s stream
73 * @param code variable pointer to receive TPDU code
74 * @return TPDU length indicator (LI)
75 */
76
tpdu_read_header(wStream * s,BYTE * code,BYTE * li,UINT16 tpktlength)77 BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li, UINT16 tpktlength)
78 {
79 if (Stream_GetRemainingLength(s) < 3)
80 return FALSE;
81
82 Stream_Read_UINT8(s, *li); /* LI */
83 Stream_Read_UINT8(s, *code); /* Code */
84
85 if (*li + 4 > tpktlength)
86 {
87 WLog_ERR(TAG, "tpdu length %" PRIu8 " > tpkt header length %" PRIu16, *li, tpktlength);
88 return FALSE;
89 }
90
91 if (*code == X224_TPDU_DATA)
92 {
93 /* EOT (1 byte) */
94 Stream_Seek(s, 1);
95 }
96 else
97 {
98 /* DST-REF (2 bytes) */
99 /* SRC-REF (2 bytes) */
100 /* Class 0 (1 byte) */
101 return Stream_SafeSeek(s, 5);
102 }
103
104 return TRUE;
105 }
106
107 /**
108 * Write TDPU header.
109 * @param s stream
110 * @param length length
111 * @param code TPDU code
112 */
113
tpdu_write_header(wStream * s,UINT16 length,BYTE code)114 void tpdu_write_header(wStream* s, UINT16 length, BYTE code)
115 {
116 Stream_Write_UINT8(s, length); /* LI */
117 Stream_Write_UINT8(s, code); /* code */
118
119 if (code == X224_TPDU_DATA)
120 {
121 Stream_Write_UINT8(s, 0x80); /* EOT */
122 }
123 else
124 {
125 Stream_Write_UINT16(s, 0); /* DST-REF */
126 Stream_Write_UINT16(s, 0); /* SRC-REF */
127 Stream_Write_UINT8(s, 0); /* Class 0 */
128 }
129 }
130
131 /**
132 * Read Connection Request TPDU
133 * @param s stream
134 * @return length indicator (LI)
135 */
136
tpdu_read_connection_request(wStream * s,BYTE * li,UINT16 tpktlength)137 BOOL tpdu_read_connection_request(wStream* s, BYTE* li, UINT16 tpktlength)
138 {
139 BYTE code;
140
141 if (!tpdu_read_header(s, &code, li, tpktlength))
142 return FALSE;
143
144 if (code != X224_TPDU_CONNECTION_REQUEST)
145 {
146 WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST");
147 return FALSE;
148 }
149
150 return TRUE;
151 }
152
153 /**
154 * Write Connection Request TPDU.
155 * @param s stream
156 * @param length TPDU length
157 */
158
tpdu_write_connection_request(wStream * s,UINT16 length)159 void tpdu_write_connection_request(wStream* s, UINT16 length)
160 {
161 tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
162 }
163
164 /**
165 * Read Connection Confirm TPDU.
166 * @param s stream
167 * @return length indicator (LI)
168 */
169
tpdu_read_connection_confirm(wStream * s,BYTE * li,UINT16 tpktlength)170 BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li, UINT16 tpktlength)
171 {
172 BYTE code;
173 size_t position;
174 size_t bytes_read = 0;
175
176 /* save the position to determine the number of bytes read */
177 position = Stream_GetPosition(s);
178
179 if (!tpdu_read_header(s, &code, li, tpktlength))
180 return FALSE;
181
182 if (code != X224_TPDU_CONNECTION_CONFIRM)
183 {
184 WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM");
185 return FALSE;
186 }
187 /*
188 * To ensure that there are enough bytes remaining for processing
189 * check against the length indicator (li). Already read bytes need
190 * to be taken into account.
191 * The -1 is because li was read but isn't included in the TPDU size.
192 * For reference see ITU-T Rec. X.224 - 13.2.1
193 */
194 bytes_read = (Stream_GetPosition(s) - position) - 1;
195
196 return (Stream_GetRemainingLength(s) >= (size_t)(*li - bytes_read));
197 }
198
199 /**
200 * Write Connection Confirm TPDU.
201 * @param s stream
202 * @param length TPDU length
203 */
204
tpdu_write_connection_confirm(wStream * s,UINT16 length)205 void tpdu_write_connection_confirm(wStream* s, UINT16 length)
206 {
207 tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
208 }
209
210 /**
211 * Write Disconnect Request TPDU.
212 * @param s stream
213 * @param length TPDU length
214 */
215
tpdu_write_disconnect_request(wStream * s,UINT16 length)216 void tpdu_write_disconnect_request(wStream* s, UINT16 length)
217 {
218 tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
219 }
220
221 /**
222 * Write Data TPDU.
223 * @param s stream
224 */
225
tpdu_write_data(wStream * s)226 void tpdu_write_data(wStream* s)
227 {
228 tpdu_write_header(s, 2, X224_TPDU_DATA);
229 }
230
231 /**
232 * Read Data TPDU.
233 * @param s stream
234 */
235
tpdu_read_data(wStream * s,UINT16 * LI,UINT16 tpktlength)236 BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
237 {
238 BYTE code;
239 BYTE li;
240
241 if (!tpdu_read_header(s, &code, &li, tpktlength))
242 return FALSE;
243
244 if (code != X224_TPDU_DATA)
245 return FALSE;
246
247 *LI = li;
248
249 return TRUE;
250 }
251