The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: 9d6324ea0a8d18a5d0426903c5db0d757d220739 $
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
35static 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 */
41static 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{
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;
52
53 /*
54 * Zero length is fine here
55 */
56 slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
57 &work_dbuff, fr_dbuff_len(&work_dbuff), tainted);
58 if (slen < 0) {
60 return slen;
61 }
63
64 return fr_dbuff_set(dbuff, &work_dbuff);
65}
66
67/** Decode a group
68 *
69 */
70static ssize_t internal_decode_structural(TALLOC_CTX *ctx, fr_pair_list_t *head, fr_dict_attr_t const *parent_da,
71 fr_dbuff_t *dbuff, void *decode_ctx)
72{
74 ssize_t slen;
75 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
76
77 FR_PROTO_TRACE("Decoding group - %s", parent_da->name);
78
79 vp = fr_pair_afrom_da(ctx, parent_da);
80 if (!vp) return PAIR_DECODE_OOM;
82
83 /*
84 * Decode all the children of this group
85 */
86 while (fr_dbuff_extend(&work_dbuff)) {
88 "Decoding child");
89
90 slen = internal_decode_pair(vp, &vp->vp_group, parent_da, &work_dbuff, decode_ctx);
91 if (slen <= 0) {
93 return slen;
94 }
95 }
97
98 return fr_dbuff_set(dbuff, &work_dbuff);
99}
100
101static ssize_t internal_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent_da,
102 fr_dbuff_t *dbuff, void *decode_ctx)
103{
104 ssize_t slen = 0;
105 fr_dict_attr_t const *da;
106 uint8_t enc_byte = 0, ext_byte = 0, type_field_size, len_field_size;
107 fr_dbuff_marker_t len_field, enc_field, ext_field;
108 uint64_t len = 0, type = 0;
109 size_t remaining, needed;
110 bool tainted, extended, unknown = false, internal = false;
111 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
112
113 /*
114 * The first byte of each attribute describes the encoding format.
115 *
116 * tlen (type field len) - Describes how many byte(s) were used to encode the type.
117 * llen (length field len) - Describes how many byte(s) were used to encode the length.
118 * t (tainted) - This attribute was tainted when it was encoded,
119 * so should be marked tainted now.
120 * e (extended) - Process the next byte as an extension of the encoding
121 * field (allows for future extensions).
122 *
123 * 0 1 2 3
124 * 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 1
125 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126 * |tlen |llen |t|e| Type (min) | Length (min) | value...
127 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128 *
129 */
130 remaining = fr_dbuff_extend_lowat(NULL, &work_dbuff, 3);
131 if (remaining < 3) {
132 fr_strerror_printf("%s: Insufficient data. Need %zu additional byte(s)",
133 __FUNCTION__, 3 - remaining);
134 return -fr_dbuff_len(&work_dbuff);
135 }
136
137 fr_dbuff_marker(&enc_field, &work_dbuff);
138 fr_dbuff_marker(&ext_field, &work_dbuff); /* Placed here to make static analysis happy */
139 FR_DBUFF_OUT_RETURN(&enc_byte, &work_dbuff);
140 type_field_size = ((enc_byte & FR_INTERNAL_MASK_TYPE) >> 5) + 1; /* bits 0-2 */
141 len_field_size = ((enc_byte & FR_INTERNAL_MASK_LEN) >> 2) + 1; /* bits 3-5 */
142
143 tainted = (enc_byte & FR_INTERNAL_FLAG_TAINTED) != 0; /* bit 6 */
144 extended = (enc_byte & FR_INTERNAL_FLAG_EXTENDED) != 0; /* bit 7 */
145
146 /* Processed first encoding byte */
147
148 needed = type_field_size + len_field_size + extended;
149 remaining = fr_dbuff_extend_lowat(NULL, &work_dbuff, needed);
150 if (remaining < needed) {
151 fr_strerror_printf("%s: Encoding byte invalid, fields overrun input data. "
152 "%zu byte(s) remaining, need %zu byte(s)",
153 __FUNCTION__, remaining, needed);
154 return 0;
155 }
156
157 /*
158 * The second (optional) extension byte carries more flag information from the attribute.
159 *
160 * u (unknown attribute) - When this pair was converted from network to internal
161 * format, it was found to be badly formatted, or not
162 * match an existing dictionary definition.
163 * A new unknown DA should be allocated for this attribute
164 * and it should be treated as raw octets.
165 * i (internal attribute) - Resolve this attribute in the internal dictionary.
166 * - (currently unused) - Unused flag.
167 * e (extended) - Encoding definitions continue to a third byte.
168 *
169 * 0 1
170 * 0 1 2 3 4 5 6 7 8 9 0
171 * +-+-+-+-+-+-+-+-+-+-+
172 * |u|i|-|-|-|-|-|e|
173 * +-+-+-+-+-+-+-+-+-+-+
174 *
175 */
176 if (extended) {
177 fr_dbuff_set(&ext_field, &work_dbuff);
178 FR_DBUFF_OUT_RETURN(&ext_byte, &work_dbuff);
179 unknown = (ext_byte & FR_INTERNAL_FLAG_UNKNOWN) != 0;
180 internal = (ext_byte & FR_INTERNAL_FLAG_INTERNAL) != 0;
181 if (ext_byte & FR_INTERNAL_FLAG_EXTENDED) {
182 fr_strerror_printf("%s: Third extension byte not in use", __FUNCTION__);
184 }
185 }
186
187 FR_DBUFF_OUT_UINT64V_RETURN(&type, &work_dbuff, type_field_size);
188
189 /*
190 * This is the length of the start *after* the flags and
191 * type/length fields.
192 */
193 fr_dbuff_marker(&len_field, &work_dbuff);
194 FR_DBUFF_OUT_UINT64V_RETURN(&len, &work_dbuff, len_field_size);
195
196 remaining = fr_dbuff_extend_lowat(NULL, &work_dbuff, len);
197 if (remaining < len) {
198 fr_strerror_printf("%s: Length field value overruns input data. "
199 "%zu byte(s) remaining, need %zu byte(s)",
200 __FUNCTION__, remaining, (size_t) len);
201 return -(fr_dbuff_current(&len_field) - fr_dbuff_start(&work_dbuff));
202 }
203
204 /*
205 * Internal flag is only set on the outer attribute
206 * so it's fine to swap the parent_da.
207 */
208 if (internal) {
209 if (!parent_da->flags.is_root && !(parent_da->type == FR_TYPE_GROUP)) {
210 fr_strerror_printf("%s: Internal flag can only be set on top level attribute", __FUNCTION__);
212 }
213 parent_da = fr_dict_root(fr_dict_internal());
214 }
215
216 if (unknown || parent_da->flags.is_unknown) {
217 unknown:
218 FR_PROTO_TRACE("Unknown attribute %" PRIu64, type);
219 da = fr_dict_attr_unknown_raw_afrom_num(ctx, parent_da, type);
220 if (!da) return PAIR_DECODE_FATAL_ERROR;
221 } else {
222 da = fr_dict_attr_child_by_num(parent_da, type);
223 if (!da) {
224 unknown = true; /* Be kind, someone may have messed with the dictionaries */
225 goto unknown;
226 }
227 }
228
229 FR_PROTO_TRACE("decode context changed %s -> %s", da->parent->name, da->name);
230
231 /*
232 * Set the end of our dbuff to match the length
233 * of the attribute.
234 */
235 fr_dbuff_set_end(&work_dbuff, fr_dbuff_current(&work_dbuff) + len);
236
237 switch (da->type) {
238 /*
239 * Structural types
240 *
241 * STRUCTs are encoded as TLVs, because the struct
242 * packing only applies to the original protocol, and not
243 * to our internal encoding.
244 */
246 if (fr_type_is_vsa(da->type)) {
247 if (unlikely(unknown)) {
248 fr_strerror_printf("%s: %s can't be marked as unknown", __FUNCTION__,
249 fr_type_to_str(da->type));
250 fr_dbuff_set(&work_dbuff, &ext_field);
251 error:
252 if (unknown) fr_dict_attr_unknown_free(&da);
253 return fr_pair_decode_slen(slen, fr_dbuff_start(&work_dbuff), fr_dbuff_current(&work_dbuff));
254 }
255 }
256 /*
257 * It's ok for this function to return 0
258 * we can have empty groups (i.e. groups
259 * with no children)
260 */
261 slen = internal_decode_structural(ctx, out, da, &work_dbuff, decode_ctx);
262 if (slen < 0) goto error;
263 break;
264
265 default:
266 /*
267 * It's ok for this function to return 0
268 * we can have zero length strings.
269 */
270 slen = internal_decode_pair_value(ctx, out, da, &work_dbuff, tainted, decode_ctx);
271 if (slen < 0) goto error;
272 }
273
274 return fr_dbuff_set(dbuff, &work_dbuff);
275}
276
277/** Create a single fr_pair_t and all its nesting
278 *
279 */
281 uint8_t const *data, size_t data_len, void *decode_ctx)
282{
283 return fr_internal_decode_pair_dbuff(ctx, list, parent, &FR_DBUFF_TMP(data, data_len), decode_ctx);
284}
285
287 fr_dbuff_t *dbuff, void *decode_ctx)
288{
289 fr_pair_list_t tmp;
290 ssize_t slen;
291 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
292
293 fr_pair_list_init(&tmp);
294
295 slen = internal_decode_pair(ctx, &tmp, parent, &work_dbuff, decode_ctx);
296 if (slen <= 0) {
297 fr_pair_list_free(&tmp);
298 return slen;
299 }
300
302
303 return fr_dbuff_set(dbuff, &work_dbuff);
304}
305
306/** Retrieve all pairs from the dbuff
307 *
308 * @param ctx to create new pairs in
309 * @param out list to append pairs to
310 * @param parent attribute within which which to decode
311 * @param dbuff to parse
312 * @param decode_ctx to pass to decoder function
313 * @return
314 * - bytes of dbuff consumed
315 * - < 0 on error
316 */
318 fr_dbuff_t *dbuff, void *decode_ctx)
319{
320 ssize_t ret, len = 0;
321
322 while (fr_dbuff_remaining(dbuff)) {
323 ret = fr_internal_decode_pair_dbuff(ctx, out, parent, dbuff, decode_ctx);
324 if (ret < 0) return ret;
325 if (ret == 0) break;
326 len += ret;
327 }
328
329 return len;
330}
331
332/*
333 * Test points
334 */
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#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:777
#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:1869
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
Definition dbuff.h:786
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:83
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:921
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1014
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:908
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:670
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition dbuff.h:715
#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:753
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:1203
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:232
#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:1829
#define fr_dbuff_set_end(_dst, _end)
Set a new 'end' position in a dbuff or marker.
Definition dbuff.h:1061
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:524
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:613
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2669
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4938
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:3597
#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:45
#define PAIR_DECODE_FATAL_ERROR
Fatal error - Failed decoding the packet.
Definition pair.h:49
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:57
talloc_free(reap)
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char uint8_t
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:1348
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:289
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:317
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:286
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:280
fr_test_point_pair_decode_t internal_tp_decode_pair
Definition decode.c:336
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:70
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:101
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:86
Entry point for pair decoders.
Definition test_point.h:85
static fr_slen_t head
Definition xlat.h:420
#define PAIR_ALLOCED(_x)
Definition pair.h:212
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
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.
static fr_slen_t parent
Definition pair.h:857
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:41
#define FR_PROTO_HEX_MARKER(_data, _data_len, _slen, _fmt,...)
Definition proto.h:43
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_type_is_vsa(_x)
Definition types.h:375
#define FR_TYPE_STRUCTURAL
Definition types.h:317
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
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:1914
static fr_slen_t data
Definition value.h:1328
static size_t char ** out
Definition value.h:1025