The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
decode.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 547fdc406d27861d7975d4b6e6738d0bf225a747 $
19 * @file src/protocols/tftp/decode.c
20 * @brief Functions to decode TFTP packets.
21 * @author Jorge Pereira <jpereira@freeradius.org>
22 *
23 * @copyright 2021 The FreeRADIUS server project.
24 * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
25 */
26RCSID("$Id: 547fdc406d27861d7975d4b6e6738d0bf225a747 $")
27
28#include <freeradius-devel/util/udp.h>
29
30#include <freeradius-devel/io/test_point.h>
31
32#include "tftp.h"
33#include "attrs.h"
34
35/*
36 * https://tools.ietf.org/html/rfc1350
37 *
38 * Order of Headers
39 *
40 * 2 bytes
41 * ----------------------------------------------------------
42 * | Local Medium | Internet | Datagram | TFTP Opcode |
43 * ----------------------------------------------------------
44 *
45 * TFTP Formats
46 *
47 * Type Op # Format without header
48 *
49 * 2 bytes string 1 byte string 1 byte
50 * -----------------------------------------------
51 * RRQ/ | 01/02 | Filename | 0 | Mode | 0 |
52 * WRQ -----------------------------------------------
53 * 2 bytes 2 bytes n bytes
54 * ---------------------------------
55 * DATA | 03 | Block # | Data |
56 * ---------------------------------
57 * 2 bytes 2 bytes
58 * -------------------
59 * ACK | 04 | Block # |
60 * --------------------
61 * 2 bytes 2 bytes string 1 byte
62 * ----------------------------------------
63 * ERROR | 05 | ErrorCode | ErrMsg | 0 |
64 * ----------------------------------------
65 *
66 * Initial Connection Protocol for reading a file
67 *
68 * 1. Host A sends a "RRQ" to host B with source= A's TID,
69 * destination= 69.
70 *
71 * 2. Host B sends a "DATA" (with block number= 1) to host A with
72 * source= B's TID, destination= A's TID.
73 */
74int fr_tftp_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
75{
76 uint8_t const *q, *p, *end;
77 uint16_t opcode;
78 fr_pair_t *vp = NULL;
79
80 if (data_len == 0) return -1;
81
82 if (data_len < FR_TFTP_HDR_LEN) {
83 fr_strerror_printf("TFTP packet is too small. (%zu < %d)", data_len, FR_TFTP_HDR_LEN);
84 error:
85 return -1;
86 }
87
88 p = data;
89 end = (data + data_len);
90
91 /* Opcode */
92 opcode = fr_nbo_to_uint16(p);
94 if (!vp) goto error;
95
96 vp->vp_uint16 = opcode;
98 p += 2;
99
100 switch (opcode) {
101 case FR_OPCODE_VALUE_READ_REQUEST:
102 case FR_OPCODE_VALUE_WRITE_REQUEST:
103 /*
104 * 2 bytes string 1 byte string 1 byte string 1 byte string 1 byte
105 * +------------------------------------------------------------------------------------+
106 * | Opcode | Filename | 0 | Mode | 0 | blksize | 0 | #blksize | 0 |
107 * +------------------------------------------------------------------------------------+
108 * Figure 5-1: RRQ/WRQ packet
109 */
110
111 /* first of all, here we should have always a '\0' */
112 if (*(end - 1) != '\0') goto error_malformed;
113
114 /* first character should be alpha numeric */
115 if (!isalnum(p[0])) {
116 fr_strerror_printf("Invalid Filename");
117 goto error;
118 }
119
120 /* <filename> */
121 q = memchr(p, '\0', (end - p));
122 if (!(q && q[0] == '\0')) {
123 error_malformed:
124 fr_strerror_printf("Packet contains malformed attribute");
125 return -1;
126 }
127
129 if (!vp) goto error;
130
131 fr_pair_value_bstrndup(vp, (char const *)p, (q - p), true);
133 p += (q - p) + 1 /* \0 */;
134
135 /* <mode> */
136 q = memchr(p, '\0', (end - p));
137 if (!(q && q[0] == '\0')) goto error_malformed;
138
140 if (!vp) goto error;
141
142 /* (netascii || ascii || octet) + \0 */
143 if ((q - p) == 5 && !memcmp(p, "octet", 5)) {
144 p += 5;
145 vp->vp_uint8 = FR_MODE_VALUE_OCTET;
146 } else if ((q - p) == 5 && !memcmp(p, "ascii", 5)) {
147 p += 5;
148 vp->vp_uint8 = FR_MODE_VALUE_ASCII;
149 } else if ((q - p) == 8 && !memcmp(p, "netascii", 8)) {
150 p += 8;
151 vp->vp_uint8 = FR_MODE_VALUE_ASCII;
152 } else {
153 fr_strerror_printf("Invalid Mode");
154 goto error;
155 }
156
158 p += 1 /* \0 */;
159
160 if (p >= end) goto done;
161
162 /*
163 * Once here, the next 'blksize' is optional.
164 * At least: | blksize | \0 | #blksize | \0 |
165 */
166 if ((end - p) < 10) goto error_malformed;
167
168 if (!memcmp(p, "blksize\0", 8)) {
169 char *p_end = NULL;
170 long blksize;
171
172 p += 8;
173
174 if (p >= end || (end - p) < 1 || (end - p) > 6) goto error_malformed;
175
177 if (!vp) goto error;
178
179 blksize = strtol((const char *)p, &p_end, 10);
180
181 if ((p == (const uint8_t *)p_end) ||
182 (blksize < FR_TFTP_BLOCK_MIN_SIZE) ||
183 (blksize > FR_TFTP_BLOCK_MAX_SIZE)) {
184 fr_strerror_printf("Invalid Block-Size %ld value", blksize);
185 goto error;
186 }
187
188 vp->vp_uint16 = (uint16_t)blksize;
190 }
191
192 break;
193
194 case FR_OPCODE_VALUE_ACKNOWLEDGEMENT:
195 case FR_OPCODE_VALUE_DATA:
196 /**
197 * 2 bytes 2 bytes
198 * ---------------------
199 * | Opcode | Block # |
200 * ---------------------
201 * Figure 5-3: ACK packet
202 */
203
205 if (!vp) goto error;
206
207 vp->vp_uint16 = fr_nbo_to_uint16(p);
208
210
211 /*
212 * From that point...
213 *
214 * 2 bytes 2 bytes n bytes
215 * ----------------------------------
216 * | Opcode | Block # | Data |
217 * ----------------------------------
218 * Figure 5-2: DATA packet
219 */
220 if (opcode != FR_OPCODE_VALUE_DATA) goto done;
221
222 if ((p + 2) > end) goto error_malformed;
223
224 p += 2;
225
227 if (!vp) goto error;
228
229 fr_pair_value_memdup(vp, p, (end - p), true);
231
232 break;
233
234 case FR_OPCODE_VALUE_ERROR:
235 /**
236 * 2 bytes 2 bytes string 1 byte
237 * -----------------------------------------
238 * | Opcode | ErrorCode | ErrMsg | 0 |
239 * -----------------------------------------
240 *
241 * Figure 5-4: ERROR packet
242 */
243
244 if ((p + 2) >= end) goto error_malformed;
245
247 if (!vp) goto error;
248
249 vp->vp_uint16 = fr_nbo_to_uint16(p);
250
252
253 p += 2; /* <ErrorCode> */
254 q = memchr(p, '\0', (end - p));
255 if (!q || q[0] != '\0') goto error_malformed;
256
258 if (!vp) goto error;
259
260 fr_pair_value_bstrndup(vp, (char const *)p, (q - p), true);
262
263 break;
264
265 default:
266 fr_strerror_printf("Invalid TFTP opcode %#04x", opcode);
267 goto error;
268 }
269
270done:
271 return data_len;
272}
273
274/**
275 * Used as the decoder ctx.
276 */
277typedef struct {
280
281/*
282 * Test points for protocol decode
283 */
285 uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
286{
287 return fr_tftp_decode(ctx, out, data, data_len);
288}
289
291{
293
294 return 0;
295}
296
297static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
298 UNUSED fr_dict_attr_t const *root_da)
299{
300 fr_tftp_ctx_t *test_ctx;
301
302 if (fr_tftp_global_init() < 0) return -1;
303
304 test_ctx = talloc_zero(ctx, fr_tftp_ctx_t);
305 if (!test_ctx) return -1;
306
307 talloc_set_destructor(test_ctx, _decode_test_ctx);
308
309 *out = test_ctx;
310
311 return 0;
312}
313
#define RCSID(id)
Definition build.h:488
#define UNUSED
Definition build.h:318
unsigned short uint16_t
long int ssize_t
unsigned char uint8_t
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2966
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1352
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:290
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition pair.c:2816
static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition decode.c:102
HIDDEN fr_dict_attr_t const * attr_tftp_error_code
Definition base.c:47
HIDDEN fr_dict_attr_t const * attr_tftp_filename
Definition base.c:49
HIDDEN fr_dict_attr_t const * attr_tftp_block_size
Definition base.c:45
HIDDEN fr_dict_attr_t const * attr_tftp_opcode
Definition base.c:50
HIDDEN fr_dict_attr_t const * attr_tftp_mode
Definition base.c:51
HIDDEN fr_dict_attr_t const * attr_tftp_data
Definition base.c:46
HIDDEN fr_dict_attr_t const * attr_tftp_block
Definition base.c:44
HIDDEN fr_dict_attr_t const * attr_tftp_error_message
Definition base.c:48
int fr_tftp_global_init(void)
Definition base.c:90
void fr_tftp_global_free(void)
Definition base.c:114
fr_test_point_proto_decode_t tftp_tp_decode_proto
Definition decode.c:315
static ssize_t fr_tftp_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
Definition decode.c:284
int fr_tftp_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
Definition decode.c:74
static int _decode_test_ctx(UNUSED fr_tftp_ctx_t *proto_ctx)
Definition decode.c:290
Used as the decoder ctx.
Definition decode.c:277
VQP attributes.
static bool done
Definition radclient.c:80
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:68
Entry point for protocol decoders.
Definition test_point.h:67
Functions to encode/decode TFTP packets.
#define FR_TFTP_BLOCK_MAX_SIZE
Definition tftp.h:73
#define FR_TFTP_HDR_LEN
Definition tftp.h:41
#define FR_TFTP_BLOCK_MIN_SIZE
Definition tftp.h:72
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030