The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 106a0161b95d8eda0f0ec116748046c932ff947e $
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  */
26 RCSID("$Id: 106a0161b95d8eda0f0ec116748046c932ff947e $")
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  */
74 int 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 || blksize > FR_TFTP_BLOCK_MAX_SIZE) {
182  fr_strerror_printf("Invalid Block-Size %ld value", blksize);
183  goto error;
184  }
185 
186  vp->vp_uint16 = (uint16_t)blksize;
188  }
189 
190  break;
191 
192  case FR_OPCODE_VALUE_ACKNOWLEDGEMENT:
193  case FR_OPCODE_VALUE_DATA:
194  /**
195  * 2 bytes 2 bytes
196  * ---------------------
197  * | Opcode | Block # |
198  * ---------------------
199  * Figure 5-3: ACK packet
200  */
201 
203  if (!vp) goto error;
204 
205  vp->vp_uint16 = fr_nbo_to_uint16(p);
206 
208 
209  /*
210  * From that point...
211  *
212  * 2 bytes 2 bytes n bytes
213  * ----------------------------------
214  * | Opcode | Block # | Data |
215  * ----------------------------------
216  * Figure 5-2: DATA packet
217  */
218  if (opcode != FR_OPCODE_VALUE_DATA) goto done;
219 
220  if ((p + 2) >= end) goto error_malformed;
221 
222  p += 2;
223 
225  if (!vp) goto error;
226 
227  fr_pair_value_memdup(vp, p, (end - p), true);
229 
230  break;
231 
232  case FR_OPCODE_VALUE_ERROR:
233  /**
234  * 2 bytes 2 bytes string 1 byte
235  * -----------------------------------------
236  * | Opcode | ErrorCode | ErrMsg | 0 |
237  * -----------------------------------------
238  *
239  * Figure 5-4: ERROR packet
240  */
241 
242  if ((p + 2) >= end) goto error_malformed;
243 
245  if (!vp) goto error;
246 
247  vp->vp_uint16 = fr_nbo_to_uint16(p);
248 
250 
251  p += 2; /* <ErrorCode> */
252  q = memchr(p, '\0', (end - p));
253  if (!q || q[0] != '\0') goto error_malformed;
254 
256  if (!vp) goto error;
257 
258  fr_pair_value_bstrndup(vp, (char const *)p, (q - p), true);
260 
261  break;
262 
263  default:
264  fr_strerror_printf("Invalid TFTP opcode %#04x", opcode);
265  goto error;
266  }
267 
268 done:
269  return data_len;
270 }
271 
272 /**
273  * Used as the decoder ctx.
274  */
275 typedef struct {
276  int nothing;
277 } fr_tftp_ctx_t;
278 
279 /*
280  * Test points for protocol decode
281  */
283  uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
284 {
285  return fr_tftp_decode(ctx, out, data, data_len);
286 }
287 
288 static int _decode_test_ctx(UNUSED fr_tftp_ctx_t *proto_ctx)
289 {
291 
292  return 0;
293 }
294 
295 static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
296 {
297  fr_tftp_ctx_t *test_ctx;
298 
299  if (fr_tftp_global_init() < 0) return -1;
300 
301  test_ctx = talloc_zero(ctx, fr_tftp_ctx_t);
302  if (!test_ctx) return -1;
303 
304  talloc_set_destructor(test_ctx, _decode_test_ctx);
305 
306  *out = test_ctx;
307 
308  return 0;
309 }
310 
314  .func = fr_tftp_decode_proto
315 };
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
unsigned short uint16_t
Definition: merged_model.c:31
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
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:137
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:278
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:2978
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:1340
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:2781
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:312
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:282
static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
Definition: decode.c:295
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:288
int nothing
Definition: decode.c:276
Used as the decoder ctx.
Definition: decode.c:275
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:66
Entry point for protocol decoders.
Definition: test_point.h:65
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_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static fr_slen_t data
Definition: value.h:1259
static size_t char ** out
Definition: value.h:984