Coverage Report

Created: 2025-07-11 06:46

/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
64.6k
{
77
64.6k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
78
2.39k
    return FALSE;
79
80
62.2k
  Stream_Read_UINT8(s, *li);   /* LI */
81
62.2k
  Stream_Read_UINT8(s, *code); /* Code */
82
83
62.2k
  if (*li + 4 > tpktlength)
84
54.3k
  {
85
54.3k
    WLog_ERR(TAG, "tpdu length %" PRIu8 " > tpkt header length %" PRIu16, *li, tpktlength);
86
54.3k
    return FALSE;
87
54.3k
  }
88
89
7.91k
  if (*code == X224_TPDU_DATA)
90
7.28k
  {
91
    /* EOT (1 byte) */
92
7.28k
    Stream_Seek(s, 1);
93
7.28k
  }
94
622
  else
95
622
  {
96
    /* DST-REF (2 bytes) */
97
    /* SRC-REF (2 bytes) */
98
    /* Class 0 (1 byte) */
99
622
    if (!Stream_SafeSeek(s, 5))
100
52
    {
101
52
      WLog_WARN(TAG, "tpdu invalid data, got %" PRIuz ", require at least 5 more",
102
52
                Stream_GetRemainingLength(s));
103
52
      return FALSE;
104
52
    }
105
622
  }
106
107
7.85k
  return TRUE;
108
7.91k
}
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.06k
{
119
3.06k
  if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 3))
120
0
    return FALSE;
121
122
3.06k
  WINPR_ASSERT(length <= UINT8_MAX);
123
3.06k
  Stream_Write_UINT8(s, (UINT8)length); /* LI */
124
3.06k
  Stream_Write_UINT8(s, code);   /* code */
125
126
3.06k
  if (code == X224_TPDU_DATA)
127
3.06k
  {
128
3.06k
    Stream_Write_UINT8(s, 0x80); /* EOT */
129
3.06k
  }
130
0
  else
131
0
  {
132
0
    if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 5))
133
0
      return FALSE;
134
0
    Stream_Write_UINT16(s, 0); /* DST-REF */
135
0
    Stream_Write_UINT16(s, 0); /* SRC-REF */
136
0
    Stream_Write_UINT8(s, 0);  /* Class 0 */
137
0
  }
138
3.06k
  return TRUE;
139
3.06k
}
140
141
/**
142
 * Read Connection Request TPDU
143
 * @param s stream
144
 * @return length indicator (LI)
145
 */
146
147
BOOL tpdu_read_connection_request(wStream* s, BYTE* li, UINT16 tpktlength)
148
0
{
149
0
  BYTE code = 0;
150
151
0
  if (!tpdu_read_header(s, &code, li, tpktlength))
152
0
    return FALSE;
153
154
0
  if (code != X224_TPDU_CONNECTION_REQUEST)
155
0
  {
156
0
    WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_REQUEST");
157
0
    return FALSE;
158
0
  }
159
160
0
  return TRUE;
161
0
}
162
163
/**
164
 * Write Connection Request TPDU.
165
 * @param s stream
166
 * @param length TPDU length
167
 */
168
169
BOOL tpdu_write_connection_request(wStream* s, UINT16 length)
170
0
{
171
0
  return tpdu_write_header(s, length, X224_TPDU_CONNECTION_REQUEST);
172
0
}
173
174
/**
175
 * Read Connection Confirm TPDU.
176
 * @param s stream
177
 * @return length indicator (LI)
178
 */
179
180
BOOL tpdu_read_connection_confirm(wStream* s, BYTE* li, UINT16 tpktlength)
181
0
{
182
0
  BYTE code = 0;
183
0
  size_t position = 0;
184
0
  size_t bytes_read = 0;
185
186
  /* save the position to determine the number of bytes read */
187
0
  position = Stream_GetPosition(s);
188
189
0
  if (!tpdu_read_header(s, &code, li, tpktlength))
190
0
    return FALSE;
191
192
0
  if (code != X224_TPDU_CONNECTION_CONFIRM)
193
0
  {
194
0
    WLog_ERR(TAG, "Error: expected X224_TPDU_CONNECTION_CONFIRM");
195
0
    return FALSE;
196
0
  }
197
  /*
198
   * To ensure that there are enough bytes remaining for processing
199
   * check against the length indicator (li). Already read bytes need
200
   * to be taken into account.
201
   * The -1 is because li was read but isn't included in the TPDU size.
202
   * For reference see ITU-T Rec. X.224 - 13.2.1
203
   */
204
0
  bytes_read = (Stream_GetPosition(s) - position) - 1;
205
206
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)(*li - bytes_read)))
207
0
    return FALSE;
208
0
  return TRUE;
209
0
}
210
211
/**
212
 * Write Connection Confirm TPDU.
213
 * @param s stream
214
 * @param length TPDU length
215
 */
216
217
BOOL tpdu_write_connection_confirm(wStream* s, UINT16 length)
218
0
{
219
0
  return tpdu_write_header(s, length, X224_TPDU_CONNECTION_CONFIRM);
220
0
}
221
222
/**
223
 * Write Disconnect Request TPDU.
224
 * @param s stream
225
 * @param length TPDU length
226
 */
227
228
BOOL tpdu_write_disconnect_request(wStream* s, UINT16 length)
229
0
{
230
0
  return tpdu_write_header(s, length, X224_TPDU_DISCONNECT_REQUEST);
231
0
}
232
233
/**
234
 * Write Data TPDU.
235
 * @param s stream
236
 */
237
238
BOOL tpdu_write_data(wStream* s)
239
3.06k
{
240
3.06k
  return tpdu_write_header(s, 2, X224_TPDU_DATA);
241
3.06k
}
242
243
/**
244
 * Read Data TPDU.
245
 * @param s stream
246
 */
247
248
BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
249
34.2k
{
250
34.2k
  BYTE code = 0;
251
34.2k
  BYTE li = 0;
252
253
34.2k
  if (!tpdu_read_header(s, &code, &li, tpktlength))
254
27.8k
    return FALSE;
255
256
6.34k
  if (code != X224_TPDU_DATA)
257
216
  {
258
216
    WLog_ERR(TAG, "tpdu got code 0x%02" PRIx8 " expected X224_TPDU_DATA [0x%02x]", code,
259
216
             X224_TPDU_DATA);
260
216
    return FALSE;
261
216
  }
262
263
6.12k
  *LI = li;
264
265
6.12k
  return TRUE;
266
6.34k
}
267
268
const char* tpdu_type_to_string(int type)
269
234
{
270
234
  switch (type)
271
234
  {
272
1
    case X224_TPDU_CONNECTION_REQUEST:
273
1
      return "X224_TPDU_CONNECTION_REQUEST";
274
6
    case X224_TPDU_CONNECTION_CONFIRM:
275
6
      return "X224_TPDU_CONNECTION_CONFIRM";
276
0
    case X224_TPDU_DISCONNECT_REQUEST:
277
0
      return "X224_TPDU_DISCONNECT_REQUEST";
278
117
    case X224_TPDU_DATA:
279
117
      return "X224_TPDU_DATA";
280
1
    case X224_TPDU_ERROR:
281
1
      return "X224_TPDU_ERROR";
282
109
    default:
283
109
      return "X224_TPDU_UNKNOWN";
284
234
  }
285
234
}