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: c70875a6d29fa55196fca148a04e28bef48c74ce $
19 *
20 * @file src/lib/util/decode.c
21 * @brief Generic functions for decoding protocols.
22 *
23 * @copyright 2022 Network RADIUS SAS (legal@networkradius.com)
24 */
25#include <freeradius-devel/io/test_point.h>
26#include <freeradius-devel/util/proto.h>
27#include <freeradius-devel/util/decode.h>
28
29/** Decode an array of values from the network
30 *
31 * @param[in] ctx context to alloc new attributes in.
32 * @param[out] out Where to write the decoded #fr_pair_t
33 * @param[in] parent dictionary entry, must have parent->flags.array set
34 * @param[in] data to parse.
35 * @param[in] data_len of data to parse.
36 * @param[in] decode_ctx passed to decode_value
37 * @param[in] decode_value function to decode one value.
38 * <0 on error - decode error, or OOM
39 * data_len on success
40 */
42 uint8_t const *data, size_t data_len,
43 void *decode_ctx, fr_pair_decode_value_t decode_value)
44{
45 uint8_t const *p = data, *end = p + data_len;
46 ssize_t slen;
47 fr_pair_list_t list;
48
49 fr_pair_list_init(&list);
50
51 FR_PROTO_HEX_DUMP(data, data_len, "fr_pair_array_from_network");
52
53 if (!fr_cond_assert_msg(parent->flags.array,
54 "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
55 __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
56
57 /*
58 * Catch stupidities.
59 */
60 if (data_len == 0) return data_len;
61
62 while (p < end) {
63 slen = decode_value(ctx, &list, parent, p, (end - p), decode_ctx);
64 if (slen <= 0) {
65 fr_pair_list_free(&list);
66 return slen - (p - data);
67 }
68
69 p += slen;
70 }
71
73 return data_len;
74}
75
76/** Create a "raw" pair from malformed network data
77 *
78 * @param[in] ctx context to alloc new attributes in.
79 * @param[out] out Where to write the decoded #fr_pair_t
80 * @param[in] da dictionary entry which it should be
81 * @param[in] data to parse.
82 * @param[in] data_len of data to parse.
83 * <0 on error - decode error, or OOM
84 * data_len on success
85 */
87 uint8_t const *data, size_t data_len)
88{
89 ssize_t slen;
91 fr_dict_attr_t *unknown;
92 fr_dict_attr_t const *child;
93
94#if defined(STATIC_ANALYZER) || !defined(NDEBUG)
95 if (!da->parent) return -1; /* stupid static analyzers */
96#endif
97
98 FR_PROTO_TRACE("Creating Raw attribute %s", da->name);
99 FR_PROTO_HEX_DUMP(data, data_len, "fr_pair_raw_from_network");
100
101 /*
102 * Build an unknown attr of the entire data.
103 */
104 unknown = fr_dict_attr_unknown_raw_afrom_da(ctx, da);
105 if (!unknown) return -1;
106
107 vp = fr_pair_afrom_da(ctx, unknown); /* makes a copy of 'unknown' */
108 child = unknown;
109 fr_dict_attr_unknown_free(&child); /* const issues */
110 if (!vp) return -1;
111
112 /*
113 * Don't bother getting data from the network if there's no data.
114 */
115 if (data_len > 0) {
116 slen = fr_value_box_from_network(vp, &vp->data, vp->da->type, vp->da,
117 &FR_DBUFF_TMP(data, data_len), data_len, true);
118 if (slen < 0) {
120 return slen;
121 }
122 }
123
124 /*
125 * Raw VPs are always tainted.
126 */
127 vp->vp_tainted = true;
129
130 return data_len;
131}
132
133
134/** Decode a list of pairs from the network
135 *
136 * @param[in] ctx context to alloc new attributes in.
137 * @param[out] out Where to write the decoded #fr_pair_t
138 * @param[in] parent dictionary entry, must have parent->flags.array set
139 * @param[in] data to parse.
140 * @param[in] data_len of data to parse.
141 * @param[in] decode_ctx passed to decode_tlv
142 * @param[in] decode_tlv function to decode one attribute / option / tlv
143 * @param[in] verify_tlvs simple function to see if the TLVs are even vaguely well-formed
144 * @param[in] nested whether or not we create nested VPs.
145 * <0 on error - decode error, or OOM
146 * data_len on success
147 *
148 * The decode_tlv function should return an error if the option is
149 * malformed. In that case, the entire list of pairs is thrown away,
150 * and a "raw" attribute is created which contains the entire
151 * data_len.
152 *
153 * If the value is malformed, then the decode_tlv function should call
154 * fr_pair_raw_from_network() on the value, and return a positive value.
155 */
157 fr_dict_attr_t const *parent,
158 uint8_t const *data, size_t const data_len,
159 void *decode_ctx, fr_pair_decode_value_t decode_tlv,
161 bool nested)
162{
163 uint8_t const *p, *end;
164 fr_pair_list_t tlvs, *list;
165 fr_pair_t *vp = NULL;
166 TALLOC_CTX *child_ctx;
167
168 FR_PROTO_HEX_DUMP(data, data_len, "fr_pair_tlvs_from_network");
169
170 switch (parent->type) {
171 case FR_TYPE_TLV:
172 case FR_TYPE_VENDOR:
173 case FR_TYPE_STRUCT:
174 break;
175
176 default:
177 fr_strerror_printf("Internal sanity check failed, attribute \"%s\" has unexpected data type '%s'",
178 parent->name, fr_type_to_str(parent->type));
180 }
181
182 /*
183 * Do a quick sanity check to see if the TLVs are at all OK.
184 */
185 if (verify_tlvs && !verify_tlvs(data, data_len)) return -1;
186
187 p = data;
188 end = data + data_len;
189
190 if (!nested) {
191 fr_pair_list_init(&tlvs);
192 list = &tlvs;
193 child_ctx = ctx;
194 } else {
195 vp = fr_pair_afrom_da(ctx, parent);
196 if (!vp) return PAIR_DECODE_OOM;
197 list = &vp->vp_group;
198 child_ctx = vp;
199 }
200
201 while (p < end) {
202 ssize_t slen;
203
204 slen = decode_tlv(child_ctx, list, parent, p, (end - p), decode_ctx);
205 if (slen <= 0) {
206 FR_PROTO_TRACE(" tlv decode failed at offset %zu - %s", (size_t) (p - data), fr_strerror());
207 fr_pair_list_free(list);
209
210 /*
211 * Don't decode it as raw. We don't know how the TLVs are structured, so the
212 * only da we have is the parent. The output has to in the parent with a child
213 * da. So if we create a raw attribute here, then we have the raw attribute of
214 * da==parent going into the parent, which is wrong.
215 */
217 }
218
219 p += slen;
220 }
221
222 if (!nested) {
223 fr_pair_list_append(out, &tlvs);
224 } else {
226 }
227
228 return data_len;
229}
230
231
232/** Decode a DNS label or a list of DNS labels from the network
233 *
234 * @param[in] ctx context to alloc new attributes in.
235 * @param[out] out Where to write the decoded #fr_pair_t
236 * @param[in] parent dictionary entry, must have parent->flags.array set
237 * @param[in] start of the DNS labels to decode
238 * @param[in] data to parse.
239 * @param[in] data_len of data to parse.
240 * @param[in] lb struct to help with decoding packets.
241 * @param[in] exact whether the labels should entirely fill the buffer.
242 * @return
243 * <0 on error - decode error, or OOM
244 * data_len on success
245 *
246 * DNS labels exist in many protocols, and we also have src/lib/dns.c, so we might
247 * as well put a common function here, too.
248 *
249 * This function assumes that the DNS label or labels take up all of the
250 * input. If they do not, then the decoded DNS labels are freed, and
251 * a raw attribute is returned instead.
252 */
254 fr_dict_attr_t const *parent, uint8_t const *start,
255 uint8_t const *data, size_t const data_len, fr_dns_labels_t *lb, bool exact)
256{
257 ssize_t slen;
258 size_t total, labels_len;
259 fr_pair_t *vp;
260 uint8_t const *next = data;
261 fr_pair_list_t tmp;
262
263 FR_PROTO_HEX_DUMP(data, data_len, "fr_pair_dns_labels_from_network");
264
265 fr_pair_list_init(&tmp);
266
267 /*
268 * This function handles both single-valued and array
269 * types. It's just easier that way.
270 */
271 if (!parent->flags.array) {
272 /*
273 * Decode starting at "NEXT", but allowing decodes from the start of the packet.
274 */
275 slen = fr_dns_label_uncompressed_length(start, data, data_len, &next, lb);
276 if (slen <= 0) {
277 FR_PROTO_TRACE("ERROR - uncompressed length failed");
278 goto raw;
279 }
280
281 labels_len = next - data; /* decode only what we've found */
282 } else {
283 /*
284 * Get the length of the entire set of labels, up
285 * to (and including) the final 0x00.
286 *
287 * If any of the labels point outside of this
288 * area, OR they are otherwise invalid, then that's an error.
289 */
290 slen = fr_dns_labels_network_verify(start, data, data_len, data, lb);
291 if (slen <= 0) {
292 FR_PROTO_TRACE("ERROR - network verify failed");
293 goto raw;
294 }
295
296 labels_len = slen;
297 }
298
299 /*
300 * The labels MUST fill the entire buffer.
301 */
302 if (exact && (labels_len != data_len)) {
303 FR_PROTO_TRACE("ERROR - labels_len %zu != data_len %zu", labels_len, data_len);
304 raw:
305 return fr_pair_raw_from_network(ctx, out, parent, data, data_len);
306 }
307
308 /*
309 * Loop over the input buffer, decoding the labels one by
310 * one.
311 *
312 * @todo - put the labels into a child cursor, and then
313 * merge them only if it succeeds. That doesn't seem to
314 * work for some reason, and I don't have time to debug
315 * it right now. So... let's leave it.
316 */
317 for (total = 0; total < labels_len; total += slen) {
318 vp = fr_pair_afrom_da(ctx, parent);
319 if (!vp) return PAIR_DECODE_OOM;
320
321 /*
322 * Having verified the input above, this next
323 * function should never fail unless there's a
324 * bug in the code.
325 */
326 slen = fr_dns_label_to_value_box(vp, &vp->data, data, labels_len, data + total, true, lb);
327 if (slen <= 0) {
328 FR_PROTO_TRACE("ERROR - failed decoding DNS label at with %zu error %zd", total, slen);
330 fr_pair_list_free(&tmp);
331 goto raw;
332 }
333
334 fr_pair_append(&tmp, vp);
335 }
336
338 return labels_len;
339}
340
341/** Generic decode value.
342 *
343 */
345 uint8_t const *data, size_t const data_len, UNUSED void *decode_ctx)
346{
347 fr_pair_t *vp;
348 ssize_t slen;
349
350 if (!fr_type_is_leaf(parent->type)) {
351 FR_PROTO_TRACE("Cannot use generic decoder for data type %s", fr_type_to_str(parent->type));
352 fr_strerror_printf("Cannot decode data type %s", fr_type_to_str(parent->type));
353 return -1;
354 }
355
356 vp = fr_pair_afrom_da(ctx, parent);
357 if (!vp) return PAIR_DECODE_OOM;
358
359 /*
360 * No protocol-specific data types here.
361 *
362 * If we can't decode this field, then the entire
363 * structure is treated as a raw blob.
364 */
365 slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
366 &FR_DBUFF_TMP(data, data_len), data_len, true);
367 if (slen <= 0) {
368 FR_PROTO_TRACE("failed decoding child VP %s", vp->da->name);
370 return fr_pair_raw_from_network(ctx, out, parent, data, data_len);
371 }
372
374
375 return slen;
376}
#define UNUSED
Definition build.h:317
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:524
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:148
bool(* fr_pair_tlvs_verify_t)(uint8_t const *data, size_t const data_len)
Definition decode.h:49
ssize_t(* fr_pair_decode_value_t)(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Decode a value from the network into an output fr_pair_list_t.
Definition decode.h:45
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition dict.h:633
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
ssize_t fr_dns_label_uncompressed_length(uint8_t const *packet, uint8_t const *buf, size_t buf_len, uint8_t const **next, fr_dns_labels_t *lb)
Get the uncompressed length of a DNS label in a network buffer.
Definition dns.c:881
ssize_t fr_dns_labels_network_verify(uint8_t const *packet, uint8_t const *buf, size_t buf_len, uint8_t const *start, fr_dns_labels_t *lb)
Verify that a network buffer contains valid DNS labels.
Definition dns.c:1134
ssize_t fr_dns_label_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *dst, uint8_t const *src, size_t len, uint8_t const *label, bool tainted, fr_dns_labels_t *lb)
Decode a fr_value_box_t from one DNS label.
Definition dns.c:1222
talloc_free(hp)
#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
ssize_t fr_pair_tlvs_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx, fr_pair_decode_value_t decode_tlv, fr_pair_tlvs_verify_t verify_tlvs, bool nested)
Decode a list of pairs from the network.
Definition decode.c:156
ssize_t fr_pair_dns_labels_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *start, uint8_t const *data, size_t const data_len, fr_dns_labels_t *lb, bool exact)
Decode a DNS label or a list of DNS labels from the network.
Definition decode.c:253
ssize_t fr_pair_decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, UNUSED void *decode_ctx)
Generic decode value.
Definition decode.c:344
ssize_t fr_pair_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da, uint8_t const *data, size_t data_len)
Create a "raw" pair from malformed network data.
Definition decode.c:86
ssize_t fr_pair_array_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value)
Decode an array of values from the network.
Definition decode.c:41
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
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:1350
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
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
static bool verify_tlvs(uint8_t const *data, size_t data_len)
Definition decode.c:41
#define decode_value
Definition decode.c:407
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
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:858
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:41
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_type_is_leaf(_x)
Definition types.h:394
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:1922
static fr_slen_t data
Definition value.h:1334
static size_t char ** out
Definition value.h:1024