Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/core/tpdu.c
Line
Count
Source (jump to first uncovered line)
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
#include <freerdp/config.h>
21
22
#include <stdio.h>
23
#include <winpr/print.h>
24
25
#include <freerdp/log.h>
26
27
#include "tpdu.h"
28
29
#define TAG FREERDP_TAG("core")
30
31
/**
32
 * TPDUs are defined in:
33
 *
34
 * http://www.itu.int/rec/T-REC-X.224-199511-I/
35
 * X.224: Information technology - Open Systems Interconnection - Protocol for providing the
36
 * connection-mode transport service
37
 *
38
 * RDP uses only TPDUs of class 0, the "simple class" defined in section 8 of X.224
39
 *
40
 *       TPDU Header
41
 *  ____________________   byte
42
 * |                    |
43
 * |         LI         |   1
44
 * |____________________|
45
 * |                    |
46
 * |        Code        |   2
47
 * |____________________|
48
 * |                    |
49
 * |                    |   3
50
 * |_______DST-REF______|
51
 * |                    |
52
 * |                    |   4
53
 * |____________________|
54
 * |                    |
55
 * |                    |   5
56
 * |_______SRC-REF______|
57
 * |                    |
58
 * |                    |   6
59
 * |____________________|
60
 * |                    |
61
 * |        Class       |   7
62
 * |____________________|
63
 * |         ...        |
64
 */
65
66
static BOOL tpdu_write_header(wStream* s, UINT16 length, BYTE code);
67
68
/**
69
 * Read TPDU header.
70
 * @param s stream
71
 * @param code variable pointer to receive TPDU code
72
 * @return TPDU length indicator (LI)
73
 */
74
75
BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li, UINT16 tpktlength)
76
62.8k
{
77
62.8k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
78
2.61k
    return FALSE;
79
80
60.2k
  Stream_Read_UINT8(s, *li);   /* LI */
81
60.2k
  Stream_Read_UINT8(s, *code); /* Code */
82
83
60.2k
  if (*li + 4 > tpktlength)
84
55.7k
  {
85
55.7k
    WLog_ERR(TAG, "tpdu length %" PRIu8 " > tpkt header length %" PRIu16, *li, tpktlength);
86
55.7k
    return FALSE;
87
55.7k
  }
88
89
4.52k
  if (*code == X224_TPDU_DATA)
90
2.78k
  {
91
    /* EOT (1 byte) */
92
2.78k
    Stream_Seek(s, 1);
93
2.78k
  }
94
1.74k
  else
95
1.74k
  {
96
    /* DST-REF (2 bytes) */
97
    /* SRC-REF (2 bytes) */
98
    /* Class 0 (1 byte) */
99
1.74k
    if (!Stream_SafeSeek(s, 5))
100
61
    {
101
61
      WLog_WARN(TAG, "tpdu invalid data, got %" PRIuz ", require at least 5 more",
102
61
                Stream_GetRemainingLength(s));
103
61
      return FALSE;
104
61
    }
105
1.74k
  }
106
107
4.46k
  return TRUE;
108
4.52k
}
109
110
/**
111
 * Write TDPU header.
112
 * @param s stream
113
 * @param length length
114
 * @param code TPDU code
115
 */
116
117
BOOL tpdu_write_header(wStream* s, UINT16 length, BYTE code)
118
3.12k
{
119
3.12k
  if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 3))
120
0
    return FALSE;
121
122
3.12k
  Stream_Write_UINT8(s, length); /* LI */
123
3.12k
  Stream_Write_UINT8(s, code);   /* code */
124
125
3.12k
  if (code == X224_TPDU_DATA)
126
3.12k
  {
127
3.12k
    Stream_Write_UINT8(s, 0x80); /* EOT */
128
3.12k
  }
129
0
  else
130
0
  {
131
0
    if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 5))
132
0
      return FALSE;
133
0
    Stream_Write_UINT16(s, 0); /* DST-REF */
134
0
    Stream_Write_UINT16(s, 0); /* SRC-REF */
135
0
    Stream_Write_UINT8(s, 0);  /* Class 0 */
136
0
  }
137
3.12k
  return TRUE;
138
3.12k
}
139
140
/**
141
 * Read Connection Request TPDU
142
 * @param s stream
143
 * @return length indicator (LI)
144
 */
145
146
BOOL tpdu_read_connection_request(wStream* s, BYTE* li, UINT16 tpktlength)
147
0
{
148
0
  BYTE code = 0;
149
150
0
  if (!tpdu_read_header(s, &code, li, tpktlength))
151
0
    return FALSE;
152
153
0
  if (code != X224_TPDU_CONNECTION_REQUEST)
154
0
  {
155
0
    WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST");
156
0
    return FALSE;
157
0
  }
158
159
0
  return TRUE;
160
0
}
161
162
/**
163
 * Write Connection Request TPDU.
164
 * @param s stream
165
 * @param length TPDU length
166
 */
167
168
BOOL tpdu_write_connection_request(wStream* s, UINT16 length)
169
0
{
170
0
  return tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
171
0
}
172
173
/**
174
 * Read Connection Confirm TPDU.
175
 * @param s stream
176
 * @return length indicator (LI)
177
 */
178
179
BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li, UINT16 tpktlength)
180
0
{
181
0
  BYTE code = 0;
182
0
  size_t position = 0;
183
0
  size_t bytes_read = 0;
184
185
  /* save the position to determine the number of bytes read */
186
0
  position = Stream_GetPosition(s);
187
188
0
  if (!tpdu_read_header(s, &code, li, tpktlength))
189
0
    return FALSE;
190
191
0
  if (code != X224_TPDU_CONNECTION_CONFIRM)
192
0
  {
193
0
    WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM");
194
0
    return FALSE;
195
0
  }
196
  /*
197
   * To ensure that there are enough bytes remaining for processing
198
   * check against the length indicator (li). Already read bytes need
199
   * to be taken into account.
200
   * The -1 is because li was read but isn't included in the TPDU size.
201
   * For reference see ITU-T Rec. X.224 - 13.2.1
202
   */
203
0
  bytes_read = (Stream_GetPosition(s) - position) - 1;
204
205
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(*li - bytes_read)))
206
0
    return FALSE;
207
0
  return TRUE;
208
0
}
209
210
/**
211
 * Write Connection Confirm TPDU.
212
 * @param s stream
213
 * @param length TPDU length
214
 */
215
216
BOOL tpdu_write_connection_confirm(wStream* s, UINT16 length)
217
0
{
218
0
  return tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
219
0
}
220
221
/**
222
 * Write Disconnect Request TPDU.
223
 * @param s stream
224
 * @param length TPDU length
225
 */
226
227
BOOL tpdu_write_disconnect_request(wStream* s, UINT16 length)
228
0
{
229
0
  return tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
230
0
}
231
232
/**
233
 * Write Data TPDU.
234
 * @param s stream
235
 */
236
237
BOOL tpdu_write_data(wStream* s)
238
3.12k
{
239
3.12k
  return tpdu_write_header(s, 2, X224_TPDU_DATA);
240
3.12k
}
241
242
/**
243
 * Read Data TPDU.
244
 * @param s stream
245
 */
246
247
BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
248
28.7k
{
249
28.7k
  BYTE code = 0;
250
28.7k
  BYTE li = 0;
251
252
28.7k
  if (!tpdu_read_header(s, &code, &li, tpktlength))
253
26.2k
    return FALSE;
254
255
2.53k
  if (code != X224_TPDU_DATA)
256
648
  {
257
648
    WLog_ERR(TAG, "tpdu got code 0x%02" PRIx8 " expected X224_TPDU_DATA [0x%02x]", code,
258
648
             X224_TPDU_DATA);
259
648
    return FALSE;
260
648
  }
261
262
1.89k
  *LI = li;
263
264
1.89k
  return TRUE;
265
2.53k
}
266
267
const char* tpdu_type_to_string(int type)
268
298
{
269
298
  switch (type)
270
298
  {
271
10
    case X224_TPDU_CONNECTION_REQUEST:
272
10
      return "X224_TPDU_CONNECTION_REQUEST";
273
3
    case X224_TPDU_CONNECTION_CONFIRM:
274
3
      return "X224_TPDU_CONNECTION_CONFIRM";
275
0
    case X224_TPDU_DISCONNECT_REQUEST:
276
0
      return "X224_TPDU_DISCONNECT_REQUEST";
277
149
    case X224_TPDU_DATA:
278
149
      return "X224_TPDU_DATA";
279
1
    case X224_TPDU_ERROR:
280
1
      return "X224_TPDU_ERROR";
281
135
    default:
282
135
      return "X224_TPDU_UNKNOWN";
283
298
  }
284
298
}