The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
decode.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library 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 GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; 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: 9be87d70b467a35b339f1667545bb4b2f0808e01 $
19  *
20  * Because what we need is yet *ANOTHER* serialisation scheme.
21  *
22  * @file protocols/internal/decode.c
23  * @brief Functions to decode data in our internal structure.
24  *
25  * @copyright 2020 The FreeRADIUS server project
26  * @copyright 2020 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
27  */
28 
29 #include <freeradius-devel/internal/internal.h>
30 #include <freeradius-devel/io/pair.h>
31 #include <freeradius-devel/io/test_point.h>
32 #include <freeradius-devel/util/proto.h>
33 #include <freeradius-devel/util/types.h>
34 
35 static ssize_t internal_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da,
36  fr_dbuff_t *dbuff, void *decode_ctx);
37 
38 /** Decodes the value of an attribute, potentially producing a pair (added to the cursor)
39  *
40  */
41 static ssize_t internal_decode_pair_value(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da,
42  fr_dbuff_t *dbuff,
43  bool tainted, UNUSED void *decode_ctx)
44 {
45  fr_pair_t *vp;
46  ssize_t slen;
47  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
48 
49  vp = fr_pair_afrom_da(ctx, parent_da);
50  if (!vp) return PAIR_DECODE_OOM;
51 
52  /*
53  * Zero length is fine here
54  */
55  slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
56  &work_dbuff, fr_dbuff_len(&work_dbuff), tainted);
57  if (slen < 0) {
58  talloc_free(vp);
59  return slen;
60  }
62 
63  return fr_dbuff_set(dbuff, &work_dbuff);
64 }
65 
66 /** Decode a group
67  *
68  */
69 static ssize_t internal_decode_structural(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da,
70  fr_dbuff_t *dbuff, void *decode_ctx)
71 {
72  fr_pair_t *vp;
73  ssize_t slen;
74  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
75 
76  FR_PROTO_TRACE("Decoding group - %s", parent_da->name);
77 
78  vp = fr_pair_afrom_da(ctx, parent_da);
79  if (!vp) return PAIR_DECODE_OOM;
80 
81  /*
82  * Decode all the children of this group
83  */
84  while (fr_dbuff_extend(&work_dbuff)) {
86  "Decoding child");
87 
88  slen = internal_decode_pair(vp, &vp->vp_group, parent_da, &work_dbuff, decode_ctx);
89  if (slen <= 0) {
90  talloc_free(vp);
91  return slen;
92  }
93  }
95 
96  return fr_dbuff_set(dbuff, &work_dbuff);
97 }
98 
99 static ssize_t internal_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent_da,
100  fr_dbuff_t *dbuff, void *decode_ctx)
101 {
102  ssize_t slen = 0;
103  fr_dict_attr_t const *da;
104  uint8_t enc_byte = 0, ext_byte = 0, type_field_size, len_field_size;
105  fr_dbuff_marker_t len_field, enc_field, ext_field;
106  uint64_t len = 0, type = 0;
107  size_t remaining, needed;
108  bool tainted, extended, unknown = false, internal = false;
109  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
110 
111  /*
112  * The first byte of each attribute describes the encoding format.
113  *
114  * tlen (type field len) - Describes how many byte(s) were used to encode the type.
115  * llen (length field len) - Describes how many byte(s) were used to encode the length.
116  * t (tainted) - This attribute was tainted when it was encoded,
117  * so should be marked tainted now.
118  * e (extended) - Process the next byte as an extension of the encoding
119  * field (allows for future extensions).
120  *
121  * 0 1 2 3
122  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1kk
123  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124  * |tlen |llen |t|e| Type (min) | Length (min) | value...
125  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126  *
127  */
128  remaining = fr_dbuff_extend_lowat(NULL, &work_dbuff, 3);
129  if (remaining < 3) {
130  fr_strerror_printf("%s: Insufficient data. Need %zu additional byte(s)",
131  __FUNCTION__, 3 - remaining);
132  return -fr_dbuff_len(&work_dbuff);
133  }
134 
135  fr_dbuff_marker(&enc_field, &work_dbuff);
136  fr_dbuff_marker(&ext_field, &work_dbuff); /* Placed here to make static analysis happy */
137  FR_DBUFF_OUT_RETURN(&enc_byte, &work_dbuff);
138  type_field_size = ((enc_byte & FR_INTERNAL_MASK_TYPE) >> 5) + 1; /* bits 0-2 */
139  len_field_size = ((enc_byte & FR_INTERNAL_MASK_LEN) >> 2) + 1; /* bits 3-5 */
140 
141  tainted = (enc_byte & FR_INTERNAL_FLAG_TAINTED) != 0; /* bit 6 */
142  extended = (enc_byte & FR_INTERNAL_FLAG_EXTENDED) != 0; /* bit 7 */
143 
144  /* Processed first encoding byte */
145 
146  needed = type_field_size + len_field_size + extended;
147  remaining = fr_dbuff_extend_lowat(NULL, &work_dbuff, needed);
148  if (remaining < needed) {
149  fr_strerror_printf("%s: Encoding byte invalid, fields overrun input data. "
150  "%zu byte(s) remaining, need %zu byte(s)",
151  __FUNCTION__, remaining, needed);
152  return 0;
153  }
154 
155  /*
156  * The second (optional) extension byte carries more flag information from the attribute.
157  *
158  * u (unknown attribute) - When this pair was converted from network to internal
159  * format, it was found to be badly formatted, or not
160  * match an existing dictionary definition.
161  * A new unknown DA should be allocated for this attribute
162  * and it should be treated as raw octets.
163  * i (internal attribute) - Resolve this attribute in the internal dictionary.
164  * - (currently unused) - Unused flag.
165  * e (extended) - Encoding definitions continue to a third byte.
166  *
167  * 0 1
168  * 0 1 2 3 4 5 6 7 8 9 0
169  * +-+-+-+-+-+-+-+-+-+-+
170  * |u|i|-|-|-|-|-|e|
171  * +-+-+-+-+-+-+-+-+-+-+
172  *
173  */
174  if (extended) {
175  fr_dbuff_set(&ext_field, &work_dbuff);
176  FR_DBUFF_OUT_RETURN(&ext_byte, &work_dbuff);
177  unknown = (ext_byte & FR_INTERNAL_FLAG_UNKNOWN) != 0;
178  internal = (ext_byte & FR_INTERNAL_FLAG_INTERNAL) != 0;
179  if (ext_byte & FR_INTERNAL_FLAG_EXTENDED) {
180  fr_strerror_printf("%s: Third extension byte not in use", __FUNCTION__);
182  }
183  }
184 
185  FR_DBUFF_OUT_UINT64V_RETURN(&type, &work_dbuff, type_field_size);
186 
187  /*
188  * This is the length of the start *after* the flags and
189  * type/length fields.
190  */
191  fr_dbuff_marker(&len_field, &work_dbuff);
192  FR_DBUFF_OUT_UINT64V_RETURN(&len, &work_dbuff, len_field_size);
193 
194  remaining = fr_dbuff_extend_lowat(NULL, &work_dbuff, len);
195  if (remaining < len) {
196  fr_strerror_printf("%s: Length field value overruns input data. "
197  "%zu byte(s) remaining, need %zu byte(s)",
198  __FUNCTION__, remaining, (size_t) len);
199  return -(fr_dbuff_current(&len_field) - fr_dbuff_start(&work_dbuff));
200  }
201 
202  /*
203  * Internal flag is only set on the outer attribute
204  * so it's fine to swap the parent_da.
205  */
206  if (internal) {
207  if (!parent_da->flags.is_root && !(parent_da->type == FR_TYPE_GROUP)) {
208  fr_strerror_printf("%s: Internal flag can only be set on top level attribute", __FUNCTION__);
210  }
211  parent_da = fr_dict_root(fr_dict_internal());
212  }
213 
214  if (unknown || parent_da->flags.is_unknown) {
215  unknown:
216  FR_PROTO_TRACE("Unknown attribute %" PRIu64, type);
217  da = fr_dict_unknown_attr_afrom_num(ctx, parent_da, type);
218  if (!da) return PAIR_DECODE_FATAL_ERROR;
219  } else {
220  da = fr_dict_attr_child_by_num(parent_da, type);
221  if (!da) {
222  unknown = true; /* Be kind, someone may have messed with the dictionaries */
223  goto unknown;
224  }
225  }
226 
227  FR_PROTO_TRACE("decode context changed %s -> %s", da->parent->name, da->name);
228 
229  /*
230  * Set the end of our dbuff to match the length
231  * of the attribute.
232  */
233  fr_dbuff_set_end(&work_dbuff, fr_dbuff_current(&work_dbuff) + len);
234 
235  switch (da->type) {
236  /*
237  * Structural types
238  *
239  * STRUCTs are encoded as TLVs, because the struct
240  * packing only applies to the original protocol, and not
241  * to our internal encoding.
242  */
243  case FR_TYPE_STRUCTURAL:
244  if (fr_type_is_vsa(da->type)) {
245  if (unlikely(unknown)) {
246  fr_strerror_printf("%s: %s can't be marked as unknown", __FUNCTION__,
247  fr_type_to_str(da->type));
248  fr_dbuff_set(&work_dbuff, &ext_field);
249  error:
250  if (unknown) fr_dict_unknown_free(&da);
251  return fr_pair_decode_slen(slen, fr_dbuff_start(&work_dbuff), fr_dbuff_current(&work_dbuff));
252  }
253  }
254  slen = internal_decode_structural(ctx, out, da, &work_dbuff, decode_ctx);
255  if (slen <= 0) goto error;
256  break;
257 
258  default:
259  /*
260  * It's ok for this function to return 0
261  * we can have zero length strings.
262  */
263  slen = internal_decode_pair_value(ctx, out, da, &work_dbuff, tainted, decode_ctx);
264  if (slen < 0) goto error;
265  }
266 
267  return fr_dbuff_set(dbuff, &work_dbuff);
268 }
269 
270 /** Create a single fr_pair_t and all its nesting
271  *
272  */
274  uint8_t const *data, size_t data_len, void *decode_ctx)
275 {
276  return fr_internal_decode_pair_dbuff(ctx, list, parent, &FR_DBUFF_TMP(data, data_len), decode_ctx);
277 }
278 
280  fr_dbuff_t *dbuff, void *decode_ctx)
281 {
282  fr_pair_list_t tmp;
283  ssize_t slen;
284  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
285 
286  fr_pair_list_init(&tmp);
287 
288  slen = internal_decode_pair(ctx, &tmp, parent, &work_dbuff, decode_ctx);
289  if (slen <= 0) {
290  fr_pair_list_free(&tmp);
291  return slen;
292  }
293 
294  fr_pair_list_append(out, &tmp);
295 
296  return fr_dbuff_set(dbuff, &work_dbuff);
297 }
298 
299 /** Retrieve all pairs from the dbuff
300  *
301  * @param ctx to create new pairs in
302  * @param out list to append pairs to
303  * @param parent attribute within which which to decode
304  * @param dbuff to parse
305  * @param decode_ctx to pass to decoder function
306  * @return
307  * - bytes of dbuff consumed
308  * - < 0 on error
309  */
311  fr_dbuff_t *dbuff, void *decode_ctx)
312 {
313  ssize_t ret, len = 0;
314 
315  while (fr_dbuff_remaining(dbuff)) {
316  ret = fr_internal_decode_pair_dbuff(ctx, out, parent, dbuff, decode_ctx);
317  if (ret < 0) return ret;
318  if (ret == 0) break;
319  len += ret;
320  }
321 
322  return len;
323 }
324 
325 /*
326  * Test points
327  */
330  .test_ctx = NULL,
332 };
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition: dbuff.h:762
#define FR_DBUFF_OUT_UINT64V_RETURN(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
Definition: dbuff.h:1834
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
Definition: dbuff.h:771
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition: dbuff.h:81
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition: dbuff.h:906
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:893
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition: dbuff.h:655
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition: dbuff.h:700
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition: dbuff.h:738
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition: dbuff.h:1187
#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data.
Definition: dbuff.h:1797
#define fr_dbuff_set_end(_dst, _end)
Set a new 'end' position in a dbuff or marker.
Definition: dbuff.h:1046
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4204
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
#define FR_INTERNAL_FLAG_INTERNAL
Definition: internal.h:33
#define FR_INTERNAL_MASK_TYPE
Definition: internal.h:24
#define FR_INTERNAL_FLAG_EXTENDED
Definition: internal.h:26
#define FR_INTERNAL_MASK_LEN
Definition: internal.h:25
#define FR_INTERNAL_FLAG_UNKNOWN
Definition: internal.h:32
#define FR_INTERNAL_FLAG_TAINTED
Definition: internal.h:27
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
Definition: pair.h:46
#define PAIR_DECODE_FATAL_ERROR
Fatal error - Failed decoding the packet.
Definition: pair.h:50
static ssize_t fr_pair_decode_slen(ssize_t slen, uint8_t const *start, uint8_t const *p)
Return the correct adjusted slen for errors.
Definition: pair.h:58
talloc_free(reap)
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
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_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
ssize_t fr_internal_decode_list_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *dbuff, void *decode_ctx)
Retrieve all pairs from the dbuff.
Definition: decode.c:310
static ssize_t internal_decode_pair_value(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da, fr_dbuff_t *dbuff, bool tainted, UNUSED void *decode_ctx)
Decodes the value of an attribute, potentially producing a pair (added to the cursor)
Definition: decode.c:41
ssize_t fr_internal_decode_pair_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *dbuff, void *decode_ctx)
Definition: decode.c:279
ssize_t fr_internal_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Create a single fr_pair_t and all its nesting.
Definition: decode.c:273
fr_test_point_pair_decode_t internal_tp_decode_pair
Definition: decode.c:329
static ssize_t internal_decode_structural(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da, fr_dbuff_t *dbuff, void *decode_ctx)
Decode a group.
Definition: decode.c:69
static ssize_t internal_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da, fr_dbuff_t *dbuff, void *decode_ctx)
Definition: decode.c:99
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:84
Entry point for pair decoders.
Definition: test_point.h:83
static fr_slen_t head
Definition: xlat.h:408
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
Definition: pair_inline.c:182
static fr_slen_t parent
Definition: pair.h:844
#define FR_PROTO_TRACE(_fmt,...)
Definition: proto.h:40
#define FR_PROTO_HEX_MARKER(_data, _data_len, _slen, _fmt,...)
Definition: proto.h:42
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_vsa(_x)
Definition: types.h:353
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition: value.c:1709
return fr_dbuff_set(dbuff, &our_dbuff)
static fr_slen_t data
Definition: value.h:1259
static size_t char ** out
Definition: value.h:984