Coverage Report

Created: 2026-10-15 06:31

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