Coverage Report

Created: 2025-07-01 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
0
{
77
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
78
0
    return FALSE;
79
80
0
  Stream_Read_UINT8(s, *li);   /* LI */
81
0
  Stream_Read_UINT8(s, *code); /* Code */
82
83
0
  if (*li + 4 > tpktlength)
84
0
  {
85
0
    WLog_ERR(TAG, "tpdu length %" PRIu8 " > tpkt header length %" PRIu16, *li, tpktlength);
86
0
    return FALSE;
87
0
  }
88
89
0
  if (*code == X224_TPDU_DATA)
90
0
  {
91
    /* EOT (1 byte) */
92
0
    Stream_Seek(s, 1);
93
0
  }
94
0
  else
95
0
  {
96
    /* DST-REF (2 bytes) */
97
    /* SRC-REF (2 bytes) */
98
    /* Class 0 (1 byte) */
99
0
    if (!Stream_SafeSeek(s, 5))
100
0
    {
101
0
      WLog_WARN(TAG, "tpdu invalid data, got %" PRIuz ", require at least 5 more",
102
0
                Stream_GetRemainingLength(s));
103
0
      return FALSE;
104
0
    }
105
0
  }
106
107
0
  return TRUE;
108
0
}
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
0
{
119
0
  if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 3))
120
0
    return FALSE;
121
122
0
  WINPR_ASSERT(length <= UINT8_MAX);
123
0
  Stream_Write_UINT8(s, (UINT8)length); /* LI */
124
0
  Stream_Write_UINT8(s, code);   /* code */
125
126
0
  if (code == X224_TPDU_DATA)
127
0
  {
128
0
    Stream_Write_UINT8(s, 0x80); /* EOT */
129
0
  }
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
0
  return TRUE;
139
0
}
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
0
{
240
0
  return tpdu_write_header(s, 2, X224_TPDU_DATA);
241
0
}
242
243
/**
244
 * Read Data TPDU.
245
 * @param s stream
246
 */
247
248
BOOL tpdu_read_data(wStream* s, UINT16* LI, UINT16 tpktlength)
249
0
{
250
0
  BYTE code = 0;
251
0
  BYTE li = 0;
252
253
0
  if (!tpdu_read_header(s, &code, &li, tpktlength))
254
0
    return FALSE;
255
256
0
  if (code != X224_TPDU_DATA)
257
0
  {
258
0
    WLog_ERR(TAG, "tpdu got code 0x%02" PRIx8 " expected X224_TPDU_DATA [0x%02x]", code,
259
0
             X224_TPDU_DATA);
260
0
    return FALSE;
261
0
  }
262
263
0
  *LI = li;
264
265
0
  return TRUE;
266
0
}
267
268
const char* tpdu_type_to_string(int type)
269
0
{
270
0
  switch (type)
271
0
  {
272
0
    case X224_TPDU_CONNECTION_REQUEST:
273
0
      return "X224_TPDU_CONNECTION_REQUEST";
274
0
    case X224_TPDU_CONNECTION_CONFIRM:
275
0
      return "X224_TPDU_CONNECTION_CONFIRM";
276
0
    case X224_TPDU_DISCONNECT_REQUEST:
277
0
      return "X224_TPDU_DISCONNECT_REQUEST";
278
0
    case X224_TPDU_DATA:
279
0
      return "X224_TPDU_DATA";
280
0
    case X224_TPDU_ERROR:
281
0
      return "X224_TPDU_ERROR";
282
0
    default:
283
0
      return "X224_TPDU_UNKNOWN";
284
0
  }
285
0
}