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: a176efe387168fd3b765463963c19b8ad7fed905 $
19 *
20 * @file protocols/radius/decode.c
21 * @brief Functions to decode RADIUS attributes
22 *
23 * @copyright 2000-2003,2006-2015 The FreeRADIUS server project
24 */
25RCSID("$Id: a176efe387168fd3b765463963c19b8ad7fed905 $")
26
27#include <freeradius-devel/util/md5.h>
28#include <freeradius-devel/util/struct.h>
29#include <freeradius-devel/io/test_point.h>
30#include <freeradius-devel/protocol/radius/freeradius.internal.h>
31
32#include "attrs.h"
33
34/*
35 * For all of the concat/extended attributes.
36 */
37#include <freeradius-devel/protocol/radius/rfc2869.h>
38#include <freeradius-devel/protocol/radius/rfc5904.h>
39#include <freeradius-devel/protocol/radius/rfc6929.h>
40#include <freeradius-devel/protocol/radius/rfc7268.h>
41
42static bool memcpy_bounded(void * restrict dst, const void * restrict src, size_t n, const void * restrict end)
43{
44 size_t len;
45
46 if (!fr_cond_assert(n <= 65535)) {
47 return false;
48 }
49
50 if (!fr_cond_assert(src <= end)) {
51 return false;
52 }
53
54 if (n == 0) return true;
55
56 len = ((uint8_t const * restrict) end - (uint8_t const * restrict) src);
57 if (n > len) return false;
58
59 memcpy(dst, src, n);
60 return true;
61}
62
63
64/** Decode Tunnel-Password encrypted attributes
65 *
66 * Defined in RFC-2868, this uses a two char SALT along with the
67 * initial intermediate value, to differentiate it from the
68 * above.
69 */
70static ssize_t fr_radius_decode_tunnel_password(uint8_t passwd[static 256], size_t *pwlen, fr_radius_decode_ctx_t *packet_ctx)
71{
72 fr_md5_ctx_t *md5_ctx, *md5_ctx_old;
74 size_t i, n, encrypted_len, embedded_len;
75
76 encrypted_len = *pwlen;
77
78 /*
79 * We need at least a salt.
80 */
81 if (encrypted_len < 2) {
82 fr_strerror_const("Tunnel password is too short");
83 return -1;
84 }
85
86 /*
87 * There's a salt, but no password. Or, there's a salt
88 * and a 'data_len' octet. It's wrong, but at least we
89 * can figure out what it means: the password is empty.
90 *
91 * Note that this means we ignore the 'data_len' field,
92 * if the attribute length tells us that there's no
93 * more data. So the 'data_len' field may be wrong,
94 * but that's ok...
95 */
96 if (encrypted_len <= 3) {
97 passwd[0] = 0;
98 *pwlen = 0;
99 return 0;
100 }
101
102 encrypted_len -= 2; /* discount the salt */
103
104 md5_ctx = fr_md5_ctx_alloc_from_list();
105 md5_ctx_old = fr_md5_ctx_alloc_from_list();
106
107 fr_md5_update(md5_ctx, (uint8_t const *) packet_ctx->common->secret, packet_ctx->common->secret_length);
108 fr_md5_ctx_copy(md5_ctx_old, md5_ctx); /* save intermediate work */
109
110 /*
111 * Set up the initial key:
112 *
113 * b(1) = MD5(secret + vector + salt)
114 */
116 fr_md5_update(md5_ctx, passwd, 2);
117
118 embedded_len = 0;
119 for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
120 size_t base;
121 size_t block_len = AUTH_PASS_LEN;
122
123 /*
124 * Ensure we don't overflow the input on MD5
125 */
126 if ((n + 2 + AUTH_PASS_LEN) > *pwlen) {
127 block_len = *pwlen - n - 2;
128 }
129
130 if (n == 0) {
131 base = 1;
132
133 fr_md5_final(digest, md5_ctx);
134 fr_md5_ctx_copy(md5_ctx, md5_ctx_old);
135
136 /*
137 * A quick check: decrypt the first octet
138 * of the password, which is the
139 * 'data_len' field. Ensure it's sane.
140 */
141 embedded_len = passwd[2] ^ digest[0];
142 if (embedded_len > encrypted_len) {
143 fr_strerror_printf("Tunnel Password is too long for the attribute "
144 "(shared secret is probably incorrect!)");
146 fr_md5_ctx_free_from_list(&md5_ctx_old);
147 return -1;
148 }
149
150 fr_md5_update(md5_ctx, passwd + 2, block_len);
151
152 } else {
153 base = 0;
154
155 fr_md5_final(digest, md5_ctx);
156
157 fr_md5_ctx_copy(md5_ctx, md5_ctx_old);
158 fr_md5_update(md5_ctx, passwd + n + 2, block_len);
159 }
160
161 for (i = base; i < block_len; i++) {
162 passwd[n + i - 1] = passwd[n + i + 2] ^ digest[i];
163 }
164 }
165
167 fr_md5_ctx_free_from_list(&md5_ctx_old);
168
169 /*
170 * Check trailing bytes
171 */
172 if (packet_ctx->tunnel_password_zeros) for (i = embedded_len; i < (encrypted_len - 1); i++) { /* -1 for length field */
173 if (passwd[i] != 0) {
174 fr_strerror_printf("Trailing garbage in Tunnel Password "
175 "(shared secret is probably incorrect!)");
176
177 return -1;
178 }
179 }
180
181 *pwlen = embedded_len;
182
183 passwd[embedded_len] = '\0';
184
185 return embedded_len;
186}
187
188/** Decode password
189 *
190 */
191static ssize_t fr_radius_decode_password(uint8_t passwd[static 256], size_t pwlen, fr_radius_decode_ctx_t *packet_ctx)
192{
193 fr_md5_ctx_t *md5_ctx, *md5_ctx_old;
195 size_t i, n;
196
198
199 /*
200 * Catch idiots.
201 */
202 if (pwlen == 0) goto done;
203
204 md5_ctx = fr_md5_ctx_alloc_from_list();
205 md5_ctx_old = fr_md5_ctx_alloc_from_list();
206
207 fr_md5_update(md5_ctx, (uint8_t const *) packet_ctx->common->secret, packet_ctx->common->secret_length);
208 fr_md5_ctx_copy(md5_ctx_old, md5_ctx); /* save intermediate work */
209
210 /*
211 * The inverse of the code above.
212 */
213 for (n = 0; n < pwlen; n += AUTH_PASS_LEN) {
214 size_t left = (pwlen - n);
215
216 if (left > AUTH_PASS_LEN) left = AUTH_PASS_LEN;
217
218 if (n == 0) {
220 fr_md5_final(digest, md5_ctx);
221
222 fr_md5_ctx_copy(md5_ctx, md5_ctx_old);
223 if (pwlen > AUTH_PASS_LEN) {
224 fr_md5_update(md5_ctx, (uint8_t *) passwd, AUTH_PASS_LEN);
225 }
226 } else {
227 fr_md5_final(digest, md5_ctx);
228
229 fr_md5_ctx_copy(md5_ctx, md5_ctx_old);
230 if (pwlen > (n + AUTH_PASS_LEN)) {
231 fr_md5_update(md5_ctx, (uint8_t *) passwd + n, AUTH_PASS_LEN);
232 }
233 }
234
235 for (i = 0; i < left; i++) passwd[i + n] ^= digest[i];
236 }
237
239 fr_md5_ctx_free_from_list(&md5_ctx_old);
240
241 done:
242 passwd[pwlen] = '\0';
243 return strlen((char *) passwd);
244}
245
246/** Check if a set of RADIUS formatted TLVs are OK
247 *
248 */
249int fr_radius_decode_tlv_ok(uint8_t const *data, size_t length, size_t dv_type, size_t dv_length)
250{
251 uint8_t const *end = data + length;
252
253 FR_PROTO_TRACE("Checking TLV %u/%u", (unsigned int) dv_type, (unsigned int) dv_length);
254
255 FR_PROTO_HEX_DUMP(data, length, "tlv_ok");
256
257 if ((dv_length > 2) || (dv_type == 0) || (dv_type > 4)) {
258 fr_strerror_printf("%s: Invalid arguments", __FUNCTION__);
259 return -1;
260 }
261
262 while (data < end) {
263 size_t attrlen;
264
265 if ((data + dv_type + dv_length) > end) {
266 fr_strerror_const("Attribute header overflow");
267 return -1;
268 }
269
270 switch (dv_type) {
271 case 4:
272 if ((data[0] == 0) && (data[1] == 0) &&
273 (data[2] == 0) && (data[3] == 0)) {
274 zero:
275 fr_strerror_const("Invalid attribute 0");
276 return -1;
277 }
278
279 if (data[0] != 0) {
280 fr_strerror_const("Invalid attribute > 2^24");
281 return -1;
282 }
283 break;
284
285 case 2:
286 if ((data[0] == 0) && (data[1] == 0)) goto zero;
287 break;
288
289 case 1:
290 /*
291 * Zero is allowed, because the Colubris
292 * people are dumb and use it.
293 */
294 break;
295
296 default:
297 fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
298 return -1;
299 }
300
301 switch (dv_length) {
302 case 0:
303 return 0;
304
305 case 2:
306 if (data[dv_type] != 0) {
307 fr_strerror_const("Attribute is longer than 256 octets");
308 return -1;
309 }
311 case 1:
312 attrlen = data[dv_type + dv_length - 1];
313 break;
314
315
316 default:
317 fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
318 return -1;
319 }
320
321 if (attrlen < (dv_type + dv_length)) {
322 fr_strerror_const("Attribute header has invalid length");
323 return -1;
324 }
325
326 if (attrlen > length) {
327 fr_strerror_const("Attribute overflows container");
328 return -1;
329 }
330
331 data += attrlen;
332 length -= attrlen;
333 }
334
335 return 0;
336}
337
338/** Convert a "concatenated" attribute to one long VP
339 *
340 */
341static ssize_t decode_concat(TALLOC_CTX *ctx, fr_pair_list_t *list,
342 fr_dict_attr_t const *parent, uint8_t const *data,
343 uint8_t const *end)
344{
345 size_t total;
346 uint8_t attr;
347 uint8_t const *ptr = data;
348 uint8_t *p;
349 fr_pair_t *vp;
350
352
353 total = 0;
354 attr = ptr[0];
355
356 /*
357 * See how many consecutive attributes there are.
358 */
359 while (ptr < end) {
360 if ((ptr + 2) == end) break;
361 if ((ptr + 2) > end) return -1;
362 if (ptr[1] <= 2) return -1;
363 if ((ptr + ptr[1]) > end) return -1;
364
365 total += ptr[1] - 2;
366
367 ptr += ptr[1];
368
369 if (ptr == end) break;
370
371 /*
372 * Attributes MUST be consecutive.
373 */
374 if (ptr[0] != attr) break;
375 }
376
377 /*
378 * Reset the end of the data we're trying to parse
379 */
380 end = ptr;
381
382 /*
383 * If there's no data, just return that we skipped the
384 * attribute header.
385 */
386 if (!total) return 2;
387
388 vp = fr_pair_afrom_da(ctx, parent);
389 if (!vp) return -1;
391
392 if (fr_pair_value_mem_alloc(vp, &p, total, true) != 0) {
393 fail:
395 return -1;
396 }
397
398 ptr = data;
399 while (ptr < end) {
400 if (!memcpy_bounded(p, ptr + 2, ptr[1] - 2, end)) goto fail;
401 p += ptr[1] - 2;
402 ptr += ptr[1];
403 }
404 fr_pair_append(list, vp);
405 return ptr - data;
406}
407
408/*
409 * Short-term hack to help clean things up.
410 */
411#define decode_value fr_radius_decode_pair_value
412
413/** decode an RFC-format TLV
414 *
415 */
416static ssize_t decode_rfc(TALLOC_CTX *ctx, fr_pair_list_t *out,
417 fr_dict_attr_t const *parent,
418 uint8_t const *data, size_t const data_len, void *decode_ctx)
419{
420 unsigned int attr;
421 size_t len;
422 ssize_t slen;
423 fr_dict_attr_t const *da;
424 fr_radius_decode_ctx_t *packet_ctx = decode_ctx;
425
426#ifdef STATIC_ANALYZER
427 if (!packet_ctx || !packet_ctx->tmp_ctx) return PAIR_DECODE_FATAL_ERROR;
428#endif
429
430 fr_assert(parent != NULL);
431
432 /*
433 * Must have at least a header.
434 */
435 if ((data_len < 2) || (data[1] < 2)) {
436 fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
437 return -(data_len);
438 }
439
440 /*
441 * Empty attributes are ignored.
442 */
443 if (data[1] == 2) return 2;
444
445 attr = data[0];
446 len = data[1];
447 if (len > data_len) {
448 fr_strerror_printf("%s: Attribute overflows input. "
449 "Length must be less than %zu bytes, got %zu bytes",
450 __FUNCTION__, data_len - 2, len - 2);
452 }
453
455 if (!da) {
456 da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, attr);
457 if (!da) return PAIR_DECODE_FATAL_ERROR;
458 slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len - 2);
459 if (slen < 0) return slen;
460 return len;
461 }
462 FR_PROTO_TRACE("decode context changed %s -> %s",da->parent->name, da->name);
463
464 if (da->flags.array) {
465 slen = fr_pair_array_from_network(ctx, out, da, data + 2, len - 2, decode_ctx, decode_value);
466
467 } else if (da->type == FR_TYPE_TLV) {
468 slen = fr_pair_tlvs_from_network(ctx, out, da, data + 2, len - 2, decode_ctx, decode_rfc, NULL, true);
469
470 } else {
471 slen = decode_value(ctx, out, da, data + 2, len - 2, decode_ctx);
472 }
473
474 if (slen < 0) return slen;
475
476 return len;
477}
478
479
480/** Decode NAS-Filter-Rule
481 *
482 * Similar to decode_concat, but contains multiple values instead of
483 * one.
484 */
486 fr_dict_attr_t const *parent, uint8_t const *data,
487 size_t const data_len, fr_radius_decode_ctx_t *packet_ctx)
488{
489 uint8_t const *ptr = data;
490 uint8_t const *end = data + data_len;
491 uint8_t const *decode, *decode_end;
492 uint8_t *buffer = NULL;
493 size_t total = 0;
494 int attrs = 0;
495
496 /*
497 * Figure out how long the total length of the data is.
498 * This is so that we can do the decoding from a
499 * temporary buffer. Which means that we coalesce data
500 * across multiple attributes, separately from chopping
501 * the data at zero bytes.
502 */
503 while (ptr < end) {
504 if ((ptr + 2) == end) break;
505 if ((ptr + 2) > end) return -1;
506 if ((ptr[0] != FR_NAS_FILTER_RULE)) break;
507 if (ptr[1] <= 2) return -1;
508 if ((ptr + ptr[1]) > end) return -1;
509
510 total += ptr[1] - 2;
511 ptr += ptr[1];
512 attrs++;
513 }
514 end = ptr;
515
516 FR_PROTO_TRACE("Coalesced NAS-Filter-Rule has %lu octets", total);
517
518 /*
519 * More than one attribute, create a temporary buffer,
520 * and copy all of the data over to it.
521 */
522 if (attrs > 1) {
523 uint8_t *p;
524
525 buffer = talloc_array(packet_ctx->tmp_ctx, uint8_t, total);
526 if (!buffer) return PAIR_DECODE_OOM;
527
528 p = buffer;
529 ptr = data;
530
531 /*
532 * Don't bother doing sanity checks, as they were
533 * already done above.
534 */
535 while (ptr < end) {
536 fr_assert(p < (buffer + total));
537 memcpy(p, ptr + 2, ptr[1] - 2);
538 p += ptr[1] - 2;
539 ptr += ptr[1];
540 }
541
542 decode = buffer;
543 decode_end = buffer + total;
544 } else {
545 decode = data + 2;
546 decode_end = data + data[1];
547 }
548
549 FR_PROTO_HEX_DUMP(decode, decode_end - decode, "NAS-Filter-Rule coalesced");
550
551 /*
552 * And now walk through "decode", decoding to VPs.
553 */
554 while (decode < decode_end) {
555 size_t len;
556 uint8_t const *p;
557
558 p = decode;
559
560 while (p < decode_end) {
561 if (*p == 0x00) break;
562 p++;
563 }
564
565 len = (p - decode);
566 if (len) {
567 fr_pair_t *vp;
568
569 FR_PROTO_TRACE("This NAS-Filter-Rule has %lu octets", len);
570 FR_PROTO_HEX_DUMP(decode, len, "This NAS-Filter-Rule");
571 vp = fr_pair_afrom_da(ctx, parent);
572 if (!vp) {
574 return -1;
575 }
577
578 if (fr_pair_value_bstrndup(vp, (char const *) decode, len, true) != 0) {
581 return -1;
582 }
584 }
585
586 /*
587 * Skip the zero byte
588 */
589 decode = p + 1;
590 }
591
593 return end - data; /* end of the NAS-Filter-Rule */
594}
595
596
597/** Decode Digest-Attributes
598 *
599 * The VPs are nested, and consecutive Digest-Attributes attributes are decoded into the same parent.
600 */
602 fr_dict_attr_t const *parent, uint8_t const *data,
603 size_t const data_len, fr_radius_decode_ctx_t *packet_ctx)
604{
605 ssize_t slen;
606 fr_pair_t *vp;
607 uint8_t const *p = data;
608 uint8_t const *end = data + data_len;
609
610 fr_assert(parent->type == FR_TYPE_TLV);
611
612 vp = fr_pair_afrom_da(ctx, parent);
613 if (!vp) return PAIR_DECODE_OOM;
615
616redo:
617 FR_PROTO_HEX_DUMP(p, end - p, "decode_digest_attributes");
618
619 if (((size_t) (end - p) < 2) || (p[1] < 2) || (p[1] > (size_t) (end - p))) {
620 slen = fr_pair_raw_from_network(vp, &vp->vp_group, parent, p, end - p);
621 if (slen < 0) goto error;
622
623 goto done;
624 }
625
626 slen = fr_pair_tlvs_from_network(vp, &vp->vp_group, parent, p + 2, p[1] - 2, packet_ctx, decode_rfc, NULL, false);
627 if (slen <= 0) {
628 error:
630 return slen;
631 }
632
633 /*
634 * Decode consecutive ones into the same parent.
635 */
636 p += p[1];
637 if (((p + 2) < end) && ((p[0] == FR_DIGEST_ATTRIBUTES) && (p[1] > 2))) {
638 goto redo;
639 }
640
641done:
643 return p - data;
644}
645
646
647/** Convert TLVs to one or more VPs
648 *
649 */
651 fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
652 fr_radius_decode_ctx_t *packet_ctx)
653{
654 uint8_t const *p = data, *end = data + data_len;
655 fr_dict_attr_t const *child;
657 fr_pair_list_t tlv_tmp;
658 fr_pair_t *vp;
659
661 if (data_len < 3) return -1; /* type, length, value */
662
663#ifdef STATIC_ANALYZER
664 if (!packet_ctx->tmp_ctx) return -1;
665#endif
666
667 FR_PROTO_HEX_DUMP(p, data_len, "tlvs");
668
669 if (fr_radius_decode_tlv_ok(p, data_len, 1, 1) < 0) return -1;
670
671 vp = fr_pair_afrom_da(ctx, parent);
672 if (!vp) return PAIR_DECODE_OOM;
674
675 /*
676 * Record where we were in the list when this function was called
677 * Create a temporary sub-list, so decode errors don't
678 * affect the main list.
679 */
680 fr_pair_list_init(&tlv_tmp);
681 while (p < end) {
682 ssize_t tlv_len;
683
684 child = fr_dict_attr_child_by_num(parent, p[0]);
685 if (!child) {
686 FR_PROTO_TRACE("Failed to find child %u of TLV %s", p[0], parent->name);
687
688 /*
689 * Child is unknown and not a TLV: build an unknown attr
690 */
691 if (fr_radius_decode_tlv_ok(p + 2, p[1] - 2, 1, 1) < 0) {
692 child = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, p[0]);
693 if (!child) {
694 error:
696 return -1;
697 }
698 } else {
699 /*
700 * Child is formed as a TLV, decode it as such
701 */
703 if (!child) goto error;
704
705 FR_PROTO_TRACE("decode context changed %s -> %s", parent->name, child->name);
706 tlv_len = fr_radius_decode_tlv(vp, &tlv_tmp, child, p + 2, p[1] - 2, packet_ctx);
707 goto check;
708 }
709 }
710 FR_PROTO_TRACE("decode context changed %s -> %s", parent->name, child->name);
711
712 tlv_len = fr_radius_decode_pair_value(vp, &tlv_tmp,
713 child, p + 2, p[1] - 2,
714 packet_ctx);
715 check:
716 if (tlv_len < 0) goto error;
717 p += p[1];
718 }
719
720 fr_pair_list_append(&vp->vp_group, &tlv_tmp);
722
723 return data_len;
724}
725
726/** Convert a top-level VSA to a VP.
727 *
728 * "length" can be LONGER than just this sub-vsa.
729 */
731 fr_dict_attr_t const *parent,
732 uint8_t const *data, size_t data_len,
733 fr_radius_decode_ctx_t *packet_ctx, fr_dict_vendor_t const *dv)
734{
735 unsigned int attribute;
736 ssize_t attrlen, my_len;
737 fr_dict_attr_t const *da;
738
739#ifdef STATIC_ANALYZER
740 if (!packet_ctx->tmp_ctx) return -1;
741#endif
742
743 /*
744 * Parent must be a vendor
745 */
746 if (!fr_cond_assert(parent->type == FR_TYPE_VENDOR)) {
747 fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
748 return -1;
749 }
750
751 FR_PROTO_TRACE("Length %u", (unsigned int)data_len);
752
753 if (data_len <= (dv->type + dv->length)) {
754 fr_strerror_printf("%s: Failure to call fr_radius_decode_tlv_ok", __FUNCTION__);
755 return -1;
756 }
757
758 switch (dv->type) {
759 case 4:
760 /* data[0] must be zero */
761 attribute = data[1] << 16;
762 attribute |= data[2] << 8;
763 attribute |= data[3];
764 break;
765
766 case 2:
767 attribute = data[0] << 8;
768 attribute |= data[1];
769 break;
770
771 case 1:
772 attribute = data[0];
773 break;
774
775 default:
776 fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
777 return -1;
778 }
779
780 switch (dv->length) {
781 case 2:
782 /* data[dv->type] must be zero, from fr_radius_decode_tlv_ok() */
783 attrlen = data[dv->type + 1];
784 break;
785
786 case 1:
787 attrlen = data[dv->type];
788 break;
789
790 case 0:
791 attrlen = data_len;
792 break;
793
794 default:
795 fr_strerror_printf("%s: Internal sanity check failed", __FUNCTION__);
796 return -1;
797 }
798
799 /*
800 * See if the VSA is known.
801 */
802 da = fr_dict_attr_child_by_num(parent, attribute);
803 if (da) {
804 decode:
805 FR_PROTO_TRACE("decode context changed %s -> %s", da->parent->name, da->name);
806
807 my_len = fr_radius_decode_pair_value(ctx, out,
808 da, data + dv->type + dv->length,
809 attrlen - (dv->type + dv->length),
810 packet_ctx);
811 if (my_len < 0) return my_len;
812
813 /*
814 * It's unknown. Let's see if we can decode it as a TLV. While this check can sometimes
815 * (rarely) decode non-TLVs as TLVs, that situation will be rare. And it's very useful
816 * to be able to decode nested unknown TLVs.
817 *
818 * Note that if the TLV length is zero, then we have no real way to tell if the TLV is
819 * well formed, so we just go create a raw VP.
820 */
821 } else if ((dv->length == 0) || (fr_radius_decode_tlv_ok(data + dv->type + dv->length, attrlen - (dv->type + dv->length), dv->type, dv->length) < 0)) {
822 da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, attribute);
823 if (!da) return -1;
824
825 goto decode;
826
827 } else {
828 da = fr_dict_attr_unknown_typed_afrom_num(packet_ctx->tmp_ctx, parent, attribute, FR_TYPE_TLV);
829 if (!da) return -1;
830
831 goto decode;
832 }
833
834 return attrlen;
835}
836
837
838/** Convert a fragmented extended attr to a VP
839 *
840 * Format is:
841 *
842 * attr
843 * length
844 * extended-attr
845 * flag
846 * data...
847 *
848 * But for the first fragment, we get passed a pointer to the "extended-attr"
849 */
851 fr_dict_attr_t const *parent,
852 uint8_t const *data, size_t attr_len,
853 fr_radius_decode_ctx_t *packet_ctx)
854{
855 ssize_t ret;
856 size_t fraglen;
857 uint8_t *head, *tail;
858 uint8_t const *frag, *end;
859 uint8_t const *attr;
860 int fragments;
861 bool last_frag;
862
863 /*
864 * data = Ext-Attr Flag ...
865 */
866
867 if (attr_len < 3) return -1;
868
869 /*
870 * No continuation, just decode the attribute in place.
871 */
872 if ((data[1] & 0x80) == 0) {
874 parent, data + 2, attr_len - 2, packet_ctx);
875 if (ret < 0) return -1;
876 return attr_len;
877 }
878
879 /*
880 * Calculate the length of all of the fragments. For
881 * now, they MUST be contiguous in the packet, and they
882 * MUST be all of the same TYPE and EXTENDED-TYPE
883 */
884 attr = data - 2;
885 fraglen = attr_len - 2;
886 frag = data + attr_len;
887 end = packet_ctx->end;
888 fragments = 1;
889 last_frag = false;
890
891 while (frag < end) {
892 if (last_frag || ((end - frag) < 4) ||
893 (frag[0] != attr[0]) ||
894 (frag[1] < 4) || /* too short for long_extended */
895 (frag[2] != attr[2]) ||
896 ((frag + frag[1]) > end)) { /* overflow */
897 end = frag;
898 break;
899 }
900
901 last_frag = ((frag[3] & 0x80) == 0);
902
903 fraglen += frag[1] - 4;
904 frag += frag[1];
905 fragments++;
906 }
907
908 head = tail = talloc_array(packet_ctx->tmp_ctx, uint8_t, fraglen);
909 if (!head) return -1;
910
911 FR_PROTO_TRACE("Fragments %d, total length %d", fragments, (int) fraglen);
912
913 /*
914 * And again, but faster and looser.
915 *
916 * We copy the first fragment, followed by the rest of
917 * the fragments.
918 */
919 frag = attr;
920
921 while (fragments > 0) {
922 if ((frag[1] > 4) && !memcpy_bounded(tail, frag + 4, frag[1] - 4, end)) {
924 return -1;
925 }
926 tail += frag[1] - 4;
927 frag += frag[1];
928 fragments--;
929 }
930
931 FR_PROTO_HEX_DUMP(head, fraglen, "long_extended fragments");
932
933 /*
934 * Reset the "end" pointer, because we're not passing in
935 * the real data.
936 */
937 {
938 uint8_t const *tmp = packet_ctx->end;
939 packet_ctx->end = head + fraglen;
940
942 parent, head, fraglen, packet_ctx);
943
944 packet_ctx->end = tmp;
945 }
946
948 if (ret < 0) return ret;
949
950 return end - data;
951}
952
953/** Fast path for most extended attributes.
954 *
955 * data_len has already been checked by the caller, so we don't care
956 * about it here.
957 */
958static ssize_t decode_extended(TALLOC_CTX *ctx, fr_pair_list_t *out,
959 fr_dict_attr_t const *da,
960 uint8_t const *data, UNUSED size_t data_len,
961 fr_radius_decode_ctx_t *packet_ctx)
962{
963 ssize_t slen;
964 fr_dict_attr_t const *child;
965 fr_pair_t *vp;
966
967 /*
968 * They MUST have one byte of Extended-Type. The
969 * case of "2" is already handled above with CUI.
970 */
971 if (data[1] == 3) {
972 slen = fr_pair_raw_from_network(ctx, out, da, data + 2, 1);
973 if (slen <= 0) return slen;
974 return 2 + slen;
975 }
976
977 /*
978 * Get a new child.
979 */
980 child = fr_dict_attr_child_by_num(da, data[2]);
981 if (!child) {
982 fr_dict_attr_t *unknown;
983 FR_PROTO_TRACE("Unknown extended attribute %u.%u", data[0], data[2]);
984 unknown = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, da, data[2]);
985 if (!unknown) return -1;
986
987 child = unknown;
988 }
989
990 /*
991 * One byte of type, and N bytes of data.
992 */
994 if (fr_pair_find_or_append_by_da(ctx, &vp, out, da) < 0) return PAIR_DECODE_OOM;
995
996 slen = fr_radius_decode_pair_value(vp, &vp->vp_group, child, data + 3, data[1] - 3, packet_ctx);
998 if (slen < 0 ) return slen;
999
1000 fr_assert(slen < (1 << 16));
1001 /* coverity[return_overflow] */
1002 return 3 + slen;
1003 }
1004
1005 /*
1006 * It MUST have one byte of type, and one byte of
1007 * flags. If there's no data here, we just
1008 * ignore it, whether or not the "More" bit is
1009 * set.
1010 */
1011 if (data[1] == 4) {
1013 slen = fr_pair_raw_from_network(ctx, out, da, data + 2, 2);
1014 if (slen < 0) return slen;
1015 return 4;
1016 }
1017
1018 if (fr_pair_find_or_append_by_da(ctx, &vp, out, da) < 0) return PAIR_DECODE_OOM;
1019
1020 /*
1021 * No continuation - just decode as-is.
1022 */
1023 if ((data[3] & 0x80) == 0) {
1024 slen = fr_radius_decode_pair_value(vp, &vp->vp_group, child, data + 4, data[1] - 4, packet_ctx);
1026 if (slen < 0 ) return slen;
1027 return 4 + slen;
1028 }
1029
1030 /*
1031 * Concatenate all of the fragments together, and decode the resulting thing.
1032 */
1033 slen = decode_extended_fragments(vp, &vp->vp_group, child, data + 2, data[1] - 2, packet_ctx);
1035 if (slen < 0) return slen;
1036 return 2 + slen;
1037}
1038
1039/** Convert a Vendor-Specific WIMAX to vps
1040 *
1041 * @note Called ONLY for Vendor-Specific
1042 */
1043static ssize_t decode_wimax(TALLOC_CTX *ctx, fr_pair_list_t *out,
1044 fr_dict_attr_t const *parent,
1045 uint8_t const *data, size_t attr_len,
1046 fr_radius_decode_ctx_t *packet_ctx)
1047{
1048 ssize_t ret;
1049 size_t wimax_len;
1050 bool more;
1051 uint8_t *head, *tail;
1052 uint8_t const *attr, *end;
1053 fr_dict_attr_t const *da;
1054 fr_pair_t *vsa, *vendor;
1055
1056#ifdef STATIC_ANALYZER
1057 if (!packet_ctx->tmp_ctx) return -1;
1058#endif
1059
1060 fr_assert(packet_ctx->end != NULL);
1061 fr_assert((data + attr_len) <= packet_ctx->end);
1062
1063 /*
1064 * data = VID VID VID VID WiMAX-Attr WiMAX-Len Continuation ...
1065 */
1066 if (attr_len < 8) {
1067 FR_PROTO_TRACE("attribute is too small to be WiMAX");
1068 return -1;
1069 }
1070
1071 /*
1072 * WiMAX-Attr WiMAX-Len Continuation
1073 */
1074 if (data[5] < 3) {
1075 FR_PROTO_TRACE("attribute is too small to be WiMAX-Attr-WiMAX-Len Continuation");
1076 return -1;
1077 }
1078
1079 /*
1080 * The WiMAX-Len + 4 VID must exactly fill the attribute.
1081 */
1082 if (((size_t) (data[5] + 4)) != attr_len) {
1083 FR_PROTO_TRACE("WiMAX VSA does not exactly fill the attribute");
1084 return -1;
1085 }
1086
1088
1089 if (fr_pair_find_or_append_by_da(vsa, &vendor, &vsa->vp_group, parent) < 0) return PAIR_DECODE_OOM;
1090
1092 if (!da) da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, data[4]);
1093 if (!da) return -1;
1094 FR_PROTO_TRACE("decode context changed %s -> %s", da->parent->name, da->name);
1095
1096 /*
1097 * No continuation, just decode the attribute in place.
1098 */
1099 if ((data[6] & 0x80) == 0) {
1100 FR_PROTO_TRACE("WiMAX no continuation");
1101 ret = fr_radius_decode_pair_value(vendor, &vendor->vp_group,
1102 da, data + 7, data[5] - 3, packet_ctx);
1103 if (ret < 0) return ret;
1104
1105 return attr_len;
1106 }
1107
1108 /*
1109 * Calculate the length of all of the fragments. For
1110 * now, they MUST be contiguous in the packet, and they
1111 * MUST be all of the same VSA, WiMAX, and WiMAX-attr.
1112 *
1113 * The first fragment doesn't have a RADIUS attribute
1114 * header.
1115 */
1116 wimax_len = 0;
1117 attr = data + 4;
1118 end = packet_ctx->end;
1119
1120 while (attr < end) {
1121 /*
1122 * Not enough room for Attribute + length +
1123 * continuation, it's bad.
1124 */
1125 if ((end - attr) < 3) {
1126 FR_PROTO_TRACE("end - attr < 3");
1127 return -1;
1128 }
1129
1130 /*
1131 * Must have non-zero data in the attribute.
1132 */
1133 if (attr[1] <= 3) {
1134 FR_PROTO_TRACE("attr[1] <= 3");
1135 return -1;
1136 }
1137
1138 /*
1139 * If the WiMAX attribute overflows the packet,
1140 * it's bad.
1141 */
1142 if ((attr + attr[1]) > end) {
1143 FR_PROTO_TRACE("attr + attr[1]) > end");
1144 return -1;
1145 }
1146
1147 /*
1148 * Check the continuation flag.
1149 */
1150 more = ((attr[2] & 0x80) != 0);
1151
1152 /*
1153 * Or, there's no more data, in which case we
1154 * shorten "end" to finish at this attribute.
1155 */
1156 if (!more) end = attr + attr[1];
1157
1158 /*
1159 * There's more data, but we're at the end of the
1160 * packet. The attribute is malformed!
1161 */
1162 if (more && ((attr + attr[1]) == end)) {
1163 FR_PROTO_TRACE("more && ((attr + attr[1]) == end)");
1164 return -1;
1165 }
1166
1167 /*
1168 * Add in the length of the data we need to
1169 * concatenate together.
1170 */
1171 wimax_len += attr[1] - 3;
1172
1173 /*
1174 * Go to the next attribute, and stop if there's
1175 * no more.
1176 */
1177 attr += attr[1];
1178 if (!more) break;
1179
1180 /*
1181 * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
1182 *
1183 * attr = Vendor-Specific VSA-Length VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
1184 *
1185 */
1186
1187 /*
1188 * No room for Vendor-Specific + length +
1189 * Vendor(4) + attr + length + continuation + data
1190 */
1191 if ((end - attr) < 9) {
1192 FR_PROTO_TRACE("(end - attr) < 9");
1193 return -1;
1194 }
1195
1196 if (attr[0] != FR_VENDOR_SPECIFIC) {
1197 FR_PROTO_TRACE("attr[0] != FR_VENDOR_SPECIFIC");
1198 return -1;
1199 }
1200
1201 if (attr[1] < 9) {
1202 FR_PROTO_TRACE("attr[1] < 9");
1203 return -1;
1204 }
1205
1206 if ((attr + attr[1]) > end) {
1207 FR_PROTO_TRACE("(attr + attr[1]) > end");
1208 return -1;
1209 }
1210
1211 if (memcmp(data, attr + 2, 4) != 0) {
1212 FR_PROTO_TRACE("not the same vendor");
1213 return -1; /* not WiMAX Vendor ID */
1214 }
1215
1216 if (attr[1] != (attr[7] + 6)) {
1217 FR_PROTO_TRACE("attr[1] != (attr[7] + 6)");
1218 return -1; /* WiMAX attr doesn't exactly fill the VSA */
1219 }
1220
1221 if (data[4] != attr[6]) {
1222 FR_PROTO_TRACE("data[4] != attr[6]");
1223 return -1; /* different WiMAX attribute */
1224 }
1225
1226 /*
1227 * Skip over the Vendor-Specific header, and
1228 * continue with the WiMAX attributes.
1229 */
1230 attr += 6;
1231 }
1232
1233 /*
1234 * No data in the WiMAX attribute, make a "raw" one.
1235 */
1236 if (!wimax_len) {
1237 FR_PROTO_TRACE("!wimax_len");
1238 return -1;
1239 }
1240
1241 head = tail = talloc_array(packet_ctx->tmp_ctx, uint8_t, wimax_len);
1242 if (!head) return -1;
1243
1244 /*
1245 * Copy the data over, this time trusting the attribute
1246 * contents.
1247 */
1248 attr = data;
1249 while (attr < end) {
1250 if (!memcpy_bounded(tail, attr + 4 + 3, attr[4 + 1] - 3, end)) {
1252 return -1;
1253 }
1254 tail += attr[4 + 1] - 3;
1255 attr += 4 + attr[4 + 1]; /* skip VID+WiMax header */
1256 attr += 2; /* skip Vendor-Specific header */
1257 }
1258
1259 FR_PROTO_HEX_DUMP(head, wimax_len, "Wimax fragments");
1260
1261 /*
1262 * Reset the "end" pointer, because we're not passing in
1263 * the real data.
1264 */
1265 {
1266 uint8_t const *tmp = packet_ctx->end;
1267 packet_ctx->end = head + wimax_len;
1268
1269 FR_PROTO_TRACE("WiMAX decode concatenated");
1270 FR_PROTO_HEX_DUMP(head, wimax_len, "%s", __FUNCTION__ );
1271 ret = fr_radius_decode_pair_value(vendor, &vendor->vp_group,
1272 da, head, wimax_len, packet_ctx);
1273
1274 packet_ctx->end = tmp;
1275 }
1276
1278 if (ret < 0) return ret;
1279
1280 return end - data;
1281}
1282
1283
1284/** Convert a top-level VSA to one or more VPs
1285 *
1286 */
1287static ssize_t CC_HINT(nonnull) decode_vsa(TALLOC_CTX *ctx, fr_pair_list_t *out,
1288 fr_dict_attr_t const *parent,
1289 uint8_t const *data, size_t attr_len,
1290 fr_radius_decode_ctx_t *packet_ctx)
1291{
1292 size_t total;
1293 ssize_t ret;
1294 uint32_t vendor_pen;
1295 fr_dict_vendor_t const *dv;
1297 fr_dict_vendor_t my_dv;
1298 fr_dict_attr_t const *vendor_da;
1299 fr_pair_list_t tlv_tmp;
1300 fr_pair_t *vsa, *vendor;
1301
1303
1304#ifdef STATIC_ANALYZER
1305 if (!packet_ctx->tmp_ctx) return -1;
1306#endif
1307
1308 /*
1309 * Container must be a VSA
1310 */
1311 if (!fr_cond_assert(parent->type == FR_TYPE_VSA)) return -1;
1312
1313 if ((data + attr_len) > packet_ctx->end) return -1;
1314 if (attr_len < 5) return -1; /* vid, value */
1315 if (data[0] != 0) return -1; /* we require 24-bit VIDs */
1316
1317 FR_PROTO_TRACE("Decoding VSA");
1318
1319 memcpy(&vendor_pen, data, 4);
1320 vendor_pen = ntohl(vendor_pen);
1321
1322 /*
1323 * Verify that the parent (which should be a VSA)
1324 * contains a fake attribute representing the vendor.
1325 *
1326 * If it doesn't then this vendor is unknown, but
1327 * (unlike DHCP) we know vendor attributes have a
1328 * standard format, so we can decode the data anyway.
1329 */
1330 vendor_da = fr_dict_attr_child_by_num(parent, vendor_pen);
1331 if (!vendor_da) {
1333 /*
1334 * RFC format is 1 octet type, 1 octet length
1335 */
1336 if (fr_radius_decode_tlv_ok(data + 4, attr_len - 4, 1, 1) < 0) {
1337 FR_PROTO_TRACE("Unknown TLVs not OK: %s", fr_strerror());
1338 return -1;
1339 }
1340
1341 n = fr_dict_attr_unknown_vendor_afrom_num(packet_ctx->tmp_ctx, parent, vendor_pen);
1342 if (!n) return -1;
1343 vendor_da = n;
1344
1345 fr_assert(vendor_da->flags.type_size == 1);
1346
1347 /*
1348 * Create an unknown DV too...
1349 */
1350 memset(&my_dv, 0, sizeof(my_dv));
1351
1352 my_dv.pen = vendor_pen;
1353 my_dv.type = 1;
1354 my_dv.length = 1;
1355
1356 dv = &my_dv;
1357
1358 goto create_attrs;
1359 }
1360
1361 /*
1362 * We found an attribute representing the vendor
1363 * so it *MUST* exist in the vendor tree.
1364 */
1365 dv = fr_dict_vendor_by_num(dict_radius, vendor_pen);
1366 if (!fr_cond_assert(dv)) return -1;
1367 FR_PROTO_TRACE("decode context %s -> %s", parent->name, vendor_da->name);
1368
1369 /*
1370 * WiMAX craziness
1371 */
1372 if (dv->continuation) {
1373 ret = decode_wimax(ctx, out, vendor_da, data, attr_len, packet_ctx);
1374 return ret;
1375 }
1376
1377 /*
1378 * VSAs should normally be in TLV format.
1379 */
1380 if (fr_radius_decode_tlv_ok(data + 4, attr_len - 4, dv->type, dv->length) < 0) {
1381 FR_PROTO_TRACE("TLVs not OK: %s", fr_strerror());
1382 return -1;
1383 }
1384
1385 /*
1386 * There may be more than one VSA in the
1387 * Vendor-Specific. If so, loop over them all.
1388 */
1389create_attrs:
1390 if (fr_pair_find_or_append_by_da(ctx, &vsa, out, parent) < 0) return PAIR_DECODE_OOM;
1391
1392 if (fr_pair_find_or_append_by_da(vsa, &vendor, &vsa->vp_group, vendor_da) < 0) return PAIR_DECODE_OOM;
1393
1394 data += 4;
1395 attr_len -= 4;
1396 total = 4;
1397
1398 fr_pair_list_init(&tlv_tmp);
1399 while (attr_len > 0) {
1400 ssize_t vsa_len;
1401
1402 /*
1403 * Vendor attributes can have subattributes (if you hadn't guessed)
1404 */
1405 vsa_len = decode_vsa_internal(vendor, &tlv_tmp,
1406 vendor_da, data, attr_len, packet_ctx, dv);
1407 if (vsa_len < 0) {
1408 FR_PROTO_TRACE("TLV decode failed: %s", fr_strerror());
1409 fr_strerror_printf("%s: Internal sanity check %d", __FUNCTION__, __LINE__);
1410 fr_pair_list_free(&tlv_tmp);
1411 return -1;
1412 }
1413
1414 data += vsa_len;
1415 attr_len -= vsa_len;
1416 total += vsa_len;
1417 }
1418 fr_pair_list_append(&vendor->vp_group, &tlv_tmp);
1419
1420 /*
1421 * Hacks for tags. The tagged VSAs don't go into the
1422 * root, they go into the Tag-# attribute. But we only
1423 * know that after we've created the parents. So clean up if necessary.
1424 *
1425 * @todo - maybe cache these somewhere to avoid bouncing.
1426 */
1427 if (fr_pair_list_num_elements(&vendor->vp_group) == 0) {
1428 if (fr_pair_list_num_elements(&vsa->vp_group) == 1) { /* only the vendor */
1429 fr_pair_delete(out, vsa);
1430 } else {
1431 fr_pair_delete(&vsa->vp_group, vendor);
1432 }
1433 }
1434
1435 /*
1436 * When the unknown attributes were created by
1437 * decode_vsa_internal, the hierarchy between that unknown
1438 * attribute and first known attribute was cloned
1439 * meaning we can now free the unknown vendor.
1440 */
1441
1442 return total;
1443}
1444
1445/** Wrapper called by fr_struct_from_network()
1446 *
1447 * Because extended attributes can continue across the current value.
1448 * So that function needs to know both the value length, *and* the
1449 * packet length. But when we're decoding values inside of a struct,
1450 * we're not using extended attributes.
1451 */
1453 fr_dict_attr_t const *parent,
1454 uint8_t const *data, size_t data_len, void *decode_ctx)
1455{
1456 return fr_radius_decode_pair_value(ctx, out, parent, data, data_len, decode_ctx);
1457}
1458
1459/** Wrapper called by fr_struct_from_network()
1460 */
1462 fr_dict_attr_t const *parent,
1463 uint8_t const *data, size_t data_len, void *decode_ctx)
1464{
1465 FR_PROTO_HEX_DUMP(data, data_len, "%s", __FUNCTION__ );
1466
1467 return fr_radius_decode_tlv(ctx, out, parent, data, data_len, decode_ctx);
1468}
1469
1470
1471/** Create any kind of VP from the attribute contents
1472 *
1473 * "length" is AT LEAST the length of this attribute, as we
1474 * expect the caller to have verified the data with
1475 * fr_packet_ok(). "length" may be up to the length of the
1476 * packet.
1477 *
1478 * This function will ONLY return -1 on programmer error or OOM. If
1479 * there's anything wrong with the attribute, it will ALWAYS create a
1480 * "raw" attribute.
1481 *
1482 * @return
1483 * - Length on success.
1484 * - -1 on failure.
1485 */
1487 fr_dict_attr_t const *parent,
1488 uint8_t const *data, size_t const attr_len,
1489 void *decode_ctx)
1490{
1491 int8_t tag = 0;
1492 size_t data_len;
1493 ssize_t ret;
1494 fr_dict_attr_t const *child;
1495 fr_pair_t *vp = NULL;
1496 uint8_t const *p = data;
1497 uint8_t buffer[256]; /* must be multiple of 16 */
1499 fr_radius_decode_ctx_t *packet_ctx = decode_ctx;
1500
1501 if (attr_len > 128 * 1024) {
1502 fr_strerror_printf("%s: packet is too large to be RADIUS", __FUNCTION__);
1503 return -1;
1504 }
1505
1506 if ((data + attr_len) > packet_ctx->end) {
1507 fr_strerror_printf("%s: input overflows packet", __FUNCTION__);
1508 return -1;
1509 }
1510
1511 FR_PROTO_HEX_DUMP(data, attr_len, "%s", __FUNCTION__ );
1512
1513 FR_PROTO_TRACE("Parent %s len %zu ... %zu", parent->name, attr_len, (size_t) (packet_ctx->end - data));
1514
1515 data_len = attr_len;
1516
1517 /*
1518 * Silently ignore zero-length attributes.
1519 */
1520 if (attr_len == 0) return 0;
1521
1522 /*
1523 * Hacks for tags.
1524 */
1526 /*
1527 * Check for valid tags and data types.
1528 */
1529 if (parent->type == FR_TYPE_UINT32) {
1530 if ((attr_len != 4) || (p[0] >= 0x20)) {
1531 goto raw;
1532 }
1533
1534 } else if (parent->type != FR_TYPE_STRING) {
1535 goto raw;
1536 }
1537
1538 /*
1539 * Tag values MUST be less than 32.
1540 */
1541 if (p[0] < 0x20) {
1542 /*
1543 * Only "short" attributes can be encrypted.
1544 */
1545 if (data_len >= sizeof(buffer)) goto raw;
1546
1547 if (parent->type == FR_TYPE_STRING) {
1548 memcpy(buffer, p + 1, data_len - 1);
1549 tag = p[0];
1550 data_len -= 1;
1551
1552 } else if (parent->type == FR_TYPE_UINT32) {
1553 memcpy(buffer, p, attr_len);
1554 tag = buffer[0];
1555 buffer[0] = 0;
1556 }
1557
1558 p = buffer;
1559
1560 } /* else the field is >=0x20, so it's not a tag */
1561 }
1562
1563 if (tag) {
1564 fr_radius_tag_ctx_t **new_tag_ctx = NULL;
1565
1566 if (!packet_ctx->tags) {
1567 /*
1568 * This should NOT be packet_ctx.tmp_ctx,
1569 * as that is freed after decoding every
1570 * packet. We wish to aggregate the tags
1571 * across multiple attributes.
1572 */
1573 new_tag_ctx = talloc_zero_array(NULL, fr_radius_tag_ctx_t *, 32);
1574 if (unlikely(!new_tag_ctx)) return PAIR_DECODE_OOM;
1575
1576 FR_PROTO_TRACE("Allocated tag cache %p", new_tag_ctx);
1577
1578 packet_ctx->tags = new_tag_ctx;
1579 }
1580
1581 fr_assert(tag < 0x20);
1582
1583 if (!packet_ctx->tags[tag]) {
1584 fr_pair_t *group;
1585 fr_dict_attr_t const *group_da;
1586
1587 packet_ctx->tags[tag] = talloc_zero(packet_ctx->tags, fr_radius_tag_ctx_t);
1588 if (unlikely(!packet_ctx->tags[tag])) {
1589 if (new_tag_ctx) TALLOC_FREE(packet_ctx->tags);
1590 return PAIR_DECODE_OOM;
1591 }
1592
1593 group_da = fr_dict_attr_child_by_num(fr_dict_root(dict_radius), FR_TAG_BASE + tag);
1594 if (unlikely(!group_da)) {
1595 tag_alloc_error:
1596 TALLOC_FREE(packet_ctx->tags[tag]);
1597 return PAIR_DECODE_OOM;
1598 }
1599
1600 group = fr_pair_afrom_da(packet_ctx->tag_root_ctx, group_da);
1601 if (unlikely(!group)) goto tag_alloc_error;
1602 PAIR_ALLOCED(group);
1603
1604 packet_ctx->tags[tag]->parent = group;
1605
1606 FR_PROTO_TRACE("Allocated tag attribute %p (%u)", group, tag);
1607
1608 fr_pair_append(packet_ctx->tag_root, group);
1609#ifdef TALLOC_GET_TYPE_ABORT_NOOP
1610 }
1611#else
1612 } else {
1613 talloc_get_type_abort(packet_ctx->tags, fr_radius_tag_ctx_t *);
1614 talloc_get_type_abort(packet_ctx->tags[tag], fr_radius_tag_ctx_t);
1615 talloc_get_type_abort(packet_ctx->tags[tag]->parent, fr_pair_t);
1616 }
1617#endif
1618 }
1619
1621
1622 /*
1623 * Decrypt the attribute.
1624 */
1625 if (encrypt) {
1626 FR_PROTO_TRACE("Decrypting type %d", encrypt);
1627 /*
1628 * Encrypted attributes can only exist for the
1629 * old-style format. Extended attributes CANNOT
1630 * be encrypted.
1631 */
1632 if (data_len > 253) goto raw;
1633
1634 if (p == data) memcpy(buffer, p, data_len);
1635 p = buffer;
1636
1637 switch (encrypt) { /* can't be tagged */
1638 /*
1639 * User-Password
1640 */
1642 if (!packet_ctx->request_authenticator) goto raw;
1643
1644 fr_radius_decode_password(buffer, data_len, packet_ctx);
1645
1646 /*
1647 * MS-CHAP-MPPE-Keys are 24 octets, and
1648 * encrypted. Since it's binary, we can't
1649 * look for trailing zeros.
1650 */
1651 if (parent->flags.length) {
1652 if (data_len > parent->flags.length) {
1653 data_len = parent->flags.length;
1654 } /* else leave data_len alone */
1655 } else {
1656 /*
1657 * Take off trailing zeros from the END.
1658 * This allows passwords to have zeros in
1659 * the middle of a field.
1660 *
1661 * However, if the password has a zero at
1662 * the end, it will get mashed by this
1663 * code. There's really no way around
1664 * that.
1665 */
1666 while ((data_len > 0) && (buffer[data_len - 1] == '\0')) data_len--;
1667 }
1668 break;
1669
1670 /*
1671 * Tunnel-Password's go in response packets,
1672 * except for CoA-Requests. They can have a tag,
1673 * so data_len is not the same as attrlen.
1674 */
1676 if (!packet_ctx->request_authenticator) goto raw;
1677
1678 if (fr_radius_decode_tunnel_password(buffer, &data_len, packet_ctx) < 0) {
1679 goto raw;
1680 }
1681 break;
1682
1683 /*
1684 * Ascend-Send-Secret
1685 * Ascend-Receive-Secret
1686 */
1688 if (!packet_ctx->request_authenticator) goto raw;
1689
1690 fr_radius_ascend_secret(&FR_DBUFF_TMP(buffer, sizeof(buffer)), p, data_len,
1691 packet_ctx->common->secret, packet_ctx->common->secret_length,
1692 packet_ctx->request_authenticator);
1694 data_len = strlen((char *) buffer);
1695 break;
1696
1697 default:
1698 /*
1699 * Chop the attribute to its maximum length.
1700 */
1701 if ((parent->type == FR_TYPE_OCTETS) &&
1702 (parent->flags.length && (data_len > parent->flags.length))) {
1703 data_len = parent->flags.length;
1704 }
1705 break;
1706 } /* switch over encryption flags */
1707 }
1708
1709 /*
1710 * Double-check the length after decrypting the
1711 * attribute.
1712 */
1713 FR_PROTO_TRACE("Type \"%s\" (%u)", fr_type_to_str(parent->type), parent->type);
1714
1715 switch (parent->type) {
1716 case FR_TYPE_LEAF:
1717 break;
1718
1719 case FR_TYPE_VSA:
1720 /*
1721 * VSAs in the RFC space are encoded one way.
1722 * VSAs in the "extended" space are different.
1723 */
1724 if (!parent->parent || !fr_radius_flag_extended(parent->parent)) {
1725 /*
1726 * VSAs can be WiMAX, in which case they don't
1727 * fit into one attribute.
1728 */
1729 ret = decode_vsa(ctx, out, parent, p, attr_len, packet_ctx);
1730 if (ret < 0) goto raw;
1731 return ret;
1732
1733 } else {
1734 fr_dict_attr_t const *vendor_da;
1735 fr_pair_t *vsa, *vendor;
1736 uint32_t vendor_pen;
1737
1738
1739 if (data_len < 6) goto raw; /* vid, vtype, value */
1740
1741 memcpy(&vendor_pen, p, 4);
1742 vendor_pen = ntohl(vendor_pen);
1743
1744 /*
1745 * For simplicity in our attribute tree, vendors are
1746 * represented as a subtlv(ish) of an EVS or VSA
1747 * attribute.
1748 */
1749 vendor_da = fr_dict_attr_child_by_num(parent, vendor_pen);
1750 if (!vendor_da) {
1751 /*
1752 * If there's no child, it means the vendor is unknown. Create a
1753 * temporary vendor in the packet_ctx. This will be cleaned up when the
1754 * decoder exists, which is fine. Because any unknown attributes which
1755 * depend on it will copy the entire hierarchy.
1756 */
1757 vendor_da = fr_dict_attr_unknown_vendor_afrom_num(packet_ctx->tmp_ctx, parent, vendor_pen);
1758 if (!vendor_da) return PAIR_DECODE_OOM;
1759 }
1760
1761 child = fr_dict_attr_child_by_num(vendor_da, p[4]);
1762 if (!child) {
1763 /*
1764 * Vendor exists but child didn't, create an unknown child.
1765 */
1766 child = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, vendor_da, p[4]);
1767 if (!child) {
1768 fr_strerror_printf_push("decoder failed creating unknown attribute in %s",
1769 parent->name);
1770 return -1;
1771 }
1772 }
1773
1774 if (fr_pair_find_or_append_by_da(ctx, &vsa, out, parent) < 0) return PAIR_DECODE_OOM;
1775
1776 if (fr_pair_find_or_append_by_da(vsa, &vendor, &vsa->vp_group, vendor_da) < 0) return PAIR_DECODE_OOM;
1777
1778 /*
1779 * Everything was found in the dictionary, we can
1780 * now recurse to decode the value.
1781 */
1782 ret = fr_radius_decode_pair_value(vendor, &vendor->vp_group,
1783 child, p + 5, attr_len - 5,
1784 packet_ctx);
1785 if (ret < 0) goto raw;
1786 return attr_len;
1787 }
1788
1789 case FR_TYPE_TLV:
1790 /*
1791 * We presume that the TLVs all fit into one
1792 * attribute, OR they've already been grouped
1793 * into a contiguous memory buffer.
1794 */
1795 ret = fr_radius_decode_tlv(ctx, out, parent, p, attr_len, packet_ctx);
1796 if (ret < 0) goto raw;
1797 return attr_len;
1798
1799 case FR_TYPE_STRUCT:
1800 /*
1801 * We presume that the struct fits into one
1802 * attribute, OR it's already been grouped
1803 * into a contiguous memory buffer.
1804 */
1805 ret = fr_struct_from_network(ctx, out, parent, p, attr_len,
1807 if (ret < 0) goto raw;
1808 return attr_len;
1809
1810 case FR_TYPE_GROUP:
1811 {
1812 fr_dict_attr_t const *ref;
1813 fr_dict_protocol_t const *proto;
1814
1815 ref = fr_dict_attr_ref(parent);
1816 if (!ref) goto raw;
1817
1818 fr_assert(ref->dict != parent->dict);
1819
1820 proto = fr_dict_protocol(ref->dict);
1821 fr_assert(proto != NULL);
1822
1823 if (!proto->decode) goto raw;
1824
1825 vp = fr_pair_afrom_da(ctx, parent);
1826 if (!vp) return -1;
1828
1829 ret = proto->decode(vp, &vp->vp_group, p, attr_len);
1830 if (ret < 0) goto raw;
1831
1832 vp->vp_tainted = true;
1833
1835 return attr_len;
1836 }
1837
1838 default:
1839 raw:
1840 if (vp) talloc_free(vp);
1841
1842 return fr_pair_raw_from_network(ctx, out, parent, data, attr_len);
1843 }
1844
1845 /*
1846 * And now that we've verified the basic type
1847 * information, decode the actual p.
1848 */
1849 if (!tag) {
1850 vp = fr_pair_afrom_da(ctx, parent);
1851 } else {
1852 fr_assert(packet_ctx->tags != NULL);
1853 fr_assert(packet_ctx->tags[tag] != NULL);
1854 vp = fr_pair_afrom_da_nested(packet_ctx->tags[tag]->parent, &packet_ctx->tags[tag]->parent->vp_group, parent);
1855 }
1856 if (!vp) return -1;
1858
1859 switch (parent->type) {
1860 /*
1861 * RFC8044 IPv4 prefix
1862 *
1863 * 0 1 2 3
1864 * 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
1865 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1866 * | Reserved | Prefix-Length | Prefix ...
1867 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1868 * ... Prefix |
1869 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1870 *
1871 * The bits outside of the prefix mask MUST be zero.
1872 */
1874 if (data_len != 6) goto raw;
1875 if (p[0] != 0) goto raw;
1876
1878 p[1], p + 2, 4, true, true) < 0) {
1879 goto raw;
1880 }
1881 break;
1882
1883 /*
1884 * RFC8044 IPv6 prefix
1885 *
1886 * 0 1 2 3
1887 * 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
1888 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1889 * | Type | Length | Reserved | Prefix-Length |
1890 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1891 * Prefix
1892 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1893 * Prefix
1894 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1895 * Prefix
1896 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1897 * Prefix |
1898 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1899 *
1900 * The bits outside of the prefix mask MUST be zero.
1901 */
1903 {
1904 if (data_len > 18) goto raw;
1905 if (data_len < 2) goto raw;
1906 if (p[0] != 0) goto raw; /* First byte is always 0 */
1907
1909 p[1], p + 2, data_len - 2, false, true) < 0) {
1910 goto raw;
1911 }
1912
1913 }
1914 break;
1915
1916 case FR_TYPE_STRING:
1918
1919 if (fr_radius_decode_abinary(vp, p, data_len) < 0) goto raw;
1920 break;
1921
1922 case FR_TYPE_OCTETS:
1923 /*
1924 * This attribute SHOULD have fixed size, but it
1925 * doesn't. Therefore it's malformed.
1926 */
1927 if (parent->flags.length && (data_len != parent->flags.length)) goto raw;
1929
1930 default:
1931 decode:
1932 ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
1933 &FR_DBUFF_TMP(p, data_len), data_len, true);
1934 if (ret < 0) {
1935 /*
1936 * Paranoid loop prevention
1937 */
1938 if (vp->da->flags.is_unknown) {
1939 talloc_free(vp);
1940 return -1;
1941 }
1942 goto raw;
1943 }
1944 break;
1945 }
1946
1947 vp->vp_tainted = true;
1948
1949 if (!tag) fr_pair_append(out, vp);
1950
1951 return attr_len;
1952}
1953
1954/*
1955 * Let's try to help the CPU as much as possible. If we have a
1956 * check on a buffer, that's less work than a series of if / then
1957 * / else conditions.
1958 */
1959static const bool special[UINT8_MAX + 1] = {
1960 [FR_NAS_FILTER_RULE] = true, /* magic rules */
1961 [FR_DIGEST_ATTRIBUTES] = true, /* magic rules */
1962
1963 [FR_EAP_MESSAGE] = true, /* concat */
1964 [FR_PKM_SS_CERT] = true, /* concat */
1965 [FR_PKM_CA_CERT] = true, /* concat */
1966 [FR_EAPOL_ANNOUNCEMENT] = true, /* concat */
1967
1968 [FR_EXTENDED_ATTRIBUTE_1] = true,
1969 [FR_EXTENDED_ATTRIBUTE_2] = true,
1970 [FR_EXTENDED_ATTRIBUTE_3] = true,
1971 [FR_EXTENDED_ATTRIBUTE_4] = true,
1972 [FR_EXTENDED_ATTRIBUTE_5] = true,
1973 [FR_EXTENDED_ATTRIBUTE_6] = true,
1974};
1975
1976/** Create a "normal" fr_pair_t from the given data
1977 *
1978 */
1980 uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx)
1981{
1982 ssize_t ret;
1983 fr_dict_attr_t const *da;
1984
1985 if ((data_len < 2) || (data[1] < 2) || (data[1] > data_len)) {
1986 fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
1987 return -1;
1988 }
1989
1990 /*
1991 * If we don't have a tag root already, then record where
1992 * we're putting the top level attributes and add the tags
1993 * there.
1994 */
1995 if (!packet_ctx->tag_root) {
1996 packet_ctx->tag_root = out;
1997 packet_ctx->tag_root_ctx = ctx;
1998 }
1999
2001 if (!da) {
2002 FR_PROTO_TRACE("Unknown attribute %u", data[0]);
2004 }
2005 if (!da) return -1;
2006 FR_PROTO_TRACE("decode context changed %s -> %s",da->parent->name, da->name);
2007
2008 /*
2009 * Empty attributes are silently ignored, except for CUI.
2010 */
2011 if (data[1] == 2) {
2012 fr_pair_t *vp;
2013
2014 if (data[0] != FR_CHARGEABLE_USER_IDENTITY) {
2015 return 2;
2016 }
2017
2018 /*
2019 * Hacks for CUI. The WiMAX spec says that it can be
2020 * zero length, even though this is forbidden by the
2021 * RADIUS specs. So... we make a special case for it.
2022 *
2023 * We can't create a zero length attribute,
2024 * because the talloc API won't let us. So, we
2025 * just create a fake attribute.
2026 */
2027 vp = fr_pair_afrom_da(ctx, da);
2028 if (!vp) return -1;
2030
2031 /*
2032 * Ensure that it has a value.
2033 */
2034 if (fr_pair_value_memdup(vp, (uint8_t const *) "", 0, false) < 0) {
2035 talloc_free(vp);
2036 return -1;
2037 }
2038
2040
2041 return 2;
2042 }
2043
2044 /*
2045 * A few attributes are special, but they're rare.
2046 */
2047 if (unlikely(special[data[0]])) {
2048 if (data[0] == FR_NAS_FILTER_RULE) {
2049 return decode_nas_filter_rule(ctx, out, da, data, data_len, packet_ctx);
2050 }
2051
2052 if (data[0] == FR_DIGEST_ATTRIBUTES) {
2053 return decode_digest_attributes(ctx, out, da, data, data_len, packet_ctx);
2054 }
2055
2056 /*
2057 * Concatenate consecutive top-level attributes together.
2058 */
2059 if (fr_radius_flag_concat(da)) {
2060 FR_PROTO_TRACE("Concat attribute");
2061 return decode_concat(ctx, out, da, data, packet_ctx->end);
2062 }
2063
2064 /*
2065 * Extended attributes have a horrible format.
2066 * Try to deal with that here, so that the rest
2067 * of the code doesn't have to.
2068 */
2069 if (fr_radius_flag_extended(da)) {
2070 return decode_extended(ctx, out, da, data, data_len, packet_ctx);
2071 }
2072
2073 /*
2074 * @todo - pre-concatenate WiMAX, if 26, and dv->continuation, too.
2075 */
2076 }
2077
2078 /*
2079 * Note that we pass the entire length, not just the
2080 * length of this attribute. The Extended or WiMAX
2081 * attributes may have the "continuation" bit set, and
2082 * will thus be more than one attribute in length.
2083 */
2085 da, data + 2, data[1] - 2,
2086 packet_ctx);
2087 if (ret < 0) return ret;
2088
2089 fr_assert(ret < (1 << 16));
2090
2091 return 2 + ret;
2092}
2093
2095 uint8_t const *data, size_t data_len)
2096{
2097 ssize_t slen;
2098 uint8_t const *attr, *end;
2099
2100 fr_radius_ctx_t common_ctx = {};
2101 fr_radius_decode_ctx_t decode_ctx = {
2102 .common = &common_ctx,
2103 .tmp_ctx = talloc(ctx, uint8_t),
2104 .end = data + data_len,
2105 };
2106
2107 fr_assert(dict_radius != NULL);
2108
2109 attr = data;
2110 end = decode_ctx.end;
2111
2112 while (attr < end) {
2113 slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), &decode_ctx);
2114 if (slen < 0) {
2115 talloc_free(decode_ctx.tmp_ctx);
2116 talloc_free(decode_ctx.tags);
2117 return slen;
2118 }
2119
2120 attr += slen;
2121 talloc_free_children(decode_ctx.tmp_ctx);
2122 }
2123
2124 talloc_free(decode_ctx.tmp_ctx);
2125 talloc_free(decode_ctx.tags);
2126 return data_len;
2127}
2128
2130{
2131 TALLOC_FREE(ctx->tags);
2132
2133 return 0;
2134}
2135
2136static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
2138{
2139 static uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH] = {
2140 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2141 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2142
2143 fr_radius_decode_ctx_t *test_ctx;
2144 fr_radius_ctx_t *common;
2145
2146 test_ctx = talloc_zero(ctx, fr_radius_decode_ctx_t);
2147 test_ctx->common = common = talloc_zero(test_ctx, fr_radius_ctx_t);
2148
2149 common->secret = talloc_strdup(common, "testing123");
2150 common->secret_length = talloc_strlen(common->secret);
2151
2152 test_ctx->request_authenticator = vector;
2153 test_ctx->tmp_ctx = talloc_zero(test_ctx, uint8_t);
2154 talloc_set_destructor(test_ctx, _test_ctx_free);
2155
2156 *out = test_ctx;
2157
2158 return 0;
2159}
2160
2162 uint8_t const *data, size_t data_len, void *proto_ctx)
2163{
2164 fr_radius_decode_ctx_t *test_ctx = talloc_get_type_abort(proto_ctx, fr_radius_decode_ctx_t);
2166 fr_pair_t *vp;
2167 size_t packet_len = data_len;
2168
2169 if (!fr_radius_ok(data, &packet_len, 200, false, &reason)) {
2170 fr_strerror_printf("Packet failed verification - %s", fr_radius_decode_fail_reason[reason]);
2171 return -1;
2172 }
2173
2174 /*
2175 * Decode the header
2176 */
2178 if (!vp) {
2179 fr_strerror_const("Failed creating Packet-Type");
2180 return -1;
2181 }
2183
2184 vp->vp_uint32 = data[0];
2186
2188 if (!vp) {
2189 fr_strerror_const("Failed creating Packet-Authentication-Vector");
2190 return -1;
2191 }
2193
2194 (void) fr_pair_value_memdup(vp, data + 4, 16, true);
2196
2197 test_ctx->end = data + packet_len;
2198
2199 return fr_radius_decode(ctx, out, UNCONST(uint8_t *, data), packet_len, test_ctx);
2200}
2201
2203 uint8_t const *data, size_t data_len, void *decode_ctx)
2204{
2205 fr_radius_decode_ctx_t *packet_ctx = decode_ctx;
2206
2208
2209 packet_ctx->end = data + data_len;
2210 return fr_radius_decode_pair(ctx, out, data, data_len, decode_ctx);
2211}
2212
2213
2214/*
2215 * Test points
2216 */
2222
ssize_t fr_radius_decode_abinary(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Print an Ascend binary filter attribute to a string,.
Definition abinary.c:1318
static int const char char buffer[256]
Definition acutest.h:576
int n
Definition acutest.h:577
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:512
#define NDEBUG_UNUSED
Definition build.h:347
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define unlikely(_x)
Definition build.h:407
#define UNUSED
Definition build.h:336
fr_dict_attr_t const * root_da
Definition common.c:32
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
#define FR_DIGEST_ATTRIBUTES
Definition defs.h:110
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:88
bool continuation
we only have one flag for now, for WiMAX
Definition dict.h:271
size_t type
Length of type data.
Definition dict.h:272
fr_dict_attr_decode_func_t decode
for decoding attributes.
Definition dict.h:487
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Definition dict.h:604
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition dict_util.c:5229
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:611
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2639
uint32_t pen
Private enterprise number.
Definition dict.h:270
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
size_t length
Length of length data.
Definition dict.h:273
static fr_dict_attr_t * fr_dict_attr_unknown_typed_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num, fr_type_t type)
Definition dict.h:596
fr_dict_vendor_t const * fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen)
Look up a vendor by its PEN.
Definition dict_util.c:2922
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:3570
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:455
Private enterprise.
Definition dict.h:269
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:148
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
static int _test_ctx_free(UNUSED fr_aka_sim_ctx_t *ctx)
Definition decode.c:1004
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_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
static const uint8_t * zero
Definition md4.c:359
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Free function for MD5 digest ctx.
Definition md5.c:515
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Allocation function for MD5 digest context.
Definition md5.c:470
#define fr_md5_final(_out, _ctx)
Finalise the ctx, producing the digest.
Definition md5.h:90
#define fr_md5_ctx_copy(_dst, _src)
Copy the contents of a ctx.
Definition md5.h:60
void fr_md5_ctx_t
Definition md5.h:25
#define fr_md5_update(_ctx, _in, _inlen)
Ingest plaintext into the digest.
Definition md5.h:83
bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, uint32_t max_attributes, bool require_message_authenticator, decode_fail_t *reason)
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ 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.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define UINT8_MAX
static fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code, bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH], uint8_t *data, size_t data_len)
Decode response packet data, extracting relevant information and validating the packet.
Definition bio.c:1192
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
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:2962
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
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
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:2812
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1833
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
Definition pair.c:2911
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition pair.c:480
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
static ssize_t decode_value_trampoline(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)
Handle arrays of DNS labels for fr_struct_from_network()
Definition decode.c:70
static ssize_t decode_vsa(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)
RFC 4243 Vendor Specific Suboptions.
Definition decode.c:369
static ssize_t decode_tlv_trampoline(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)
Definition decode.c:57
static ssize_t decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, NDEBUG_UNUSED fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Definition decode.c:489
HIDDEN fr_dict_attr_t const * attr_packet_authentication_vector
Definition base.c:55
ssize_t fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen, char const *secret, size_t secret_len, uint8_t const *vector)
Do Ascend-Send / Recv-Secret calculation.
Definition base.c:250
ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, fr_radius_decode_ctx_t *decode_ctx)
Definition base.c:1162
char const * fr_radius_decode_fail_reason[FR_RADIUS_FAIL_MAX+1]
Definition base.c:507
fr_test_point_proto_decode_t radius_tp_decode_proto
Definition decode.c:2224
ssize_t fr_radius_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
Definition decode.c:2094
static ssize_t decode_concat(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *parent, uint8_t const *data, uint8_t const *end)
Convert a "concatenated" attribute to one long VP.
Definition decode.c:341
static ssize_t decode_extended(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da, uint8_t const *data, UNUSED size_t data_len, fr_radius_decode_ctx_t *packet_ctx)
Fast path for most extended attributes.
Definition decode.c:958
static ssize_t fr_radius_decode_password(uint8_t passwd[static 256], size_t pwlen, fr_radius_decode_ctx_t *packet_ctx)
Decode password.
Definition decode.c:191
static ssize_t decode_digest_attributes(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, fr_radius_decode_ctx_t *packet_ctx)
Decode Digest-Attributes.
Definition decode.c:601
static ssize_t decode_wimax(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t attr_len, fr_radius_decode_ctx_t *packet_ctx)
Convert a Vendor-Specific WIMAX to vps.
Definition decode.c:1043
ssize_t fr_radius_decode_tlv(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx)
Convert TLVs to one or more VPs.
Definition decode.c:650
fr_test_point_pair_decode_t radius_tp_decode_pair
Definition decode.c:2218
#define decode_value
Definition decode.c:411
ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const attr_len, void *decode_ctx)
Create any kind of VP from the attribute contents.
Definition decode.c:1486
static ssize_t decode_extended_fragments(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t attr_len, fr_radius_decode_ctx_t *packet_ctx)
Convert a fragmented extended attr to a VP.
Definition decode.c:850
static ssize_t fr_radius_decode_tunnel_password(uint8_t passwd[static 256], size_t *pwlen, fr_radius_decode_ctx_t *packet_ctx)
Decode Tunnel-Password encrypted attributes.
Definition decode.c:70
static const bool special[UINT8_MAX+1]
Definition decode.c:1959
int fr_radius_decode_tlv_ok(uint8_t const *data, size_t length, size_t dv_type, size_t dv_length)
Check if a set of RADIUS formatted TLVs are OK.
Definition decode.c:249
ssize_t fr_radius_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx)
Create a "normal" fr_pair_t from the given data.
Definition decode.c:1979
static ssize_t decode_vsa_internal(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx, fr_dict_vendor_t const *dv)
Convert a top-level VSA to a VP.
Definition decode.c:730
static ssize_t decode_rfc(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 an RFC-format TLV
Definition decode.c:416
static bool memcpy_bounded(void *restrict dst, const void *restrict src, size_t n, const void *restrict end)
Definition decode.c:42
static ssize_t decode_nas_filter_rule(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, fr_radius_decode_ctx_t *packet_ctx)
Decode NAS-Filter-Rule.
Definition decode.c:485
static ssize_t fr_radius_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *proto_ctx)
Definition decode.c:2161
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
fr_pair_t * parent
Definition radius.h:122
fr_radius_tag_ctx_t ** tags
for decoding tagged attributes
Definition radius.h:174
#define fr_radius_flag_concat(_da)
Definition radius.h:205
#define fr_radius_flag_has_tag(_da)
Definition radius.h:204
uint8_t const * request_authenticator
Definition radius.h:160
#define AUTH_PASS_LEN
Definition radius.h:53
fr_radius_decode_fail_t
Failure reasons.
Definition radius.h:89
char const * secret
Definition radius.h:127
uint8_t const * end
end of the packet
Definition radius.h:163
#define RADIUS_MAX_STRING_LENGTH
Definition radius.h:35
#define fr_radius_flag_encrypted(_da)
Definition radius.h:207
static bool fr_radius_flag_extended(fr_dict_attr_t const *da)
Definition radius.h:209
TALLOC_CTX * tag_root_ctx
Where to allocate new tag attributes.
Definition radius.h:176
size_t secret_length
Definition radius.h:128
fr_radius_ctx_t const * common
Definition radius.h:158
#define fr_radius_flag_long_extended(_da)
Definition radius.h:216
fr_radius_attr_flags_encrypt_t
Definition radius.h:179
@ RADIUS_FLAG_ENCRYPT_USER_PASSWORD
Encrypt attribute RFC 2865 style.
Definition radius.h:182
@ RADIUS_FLAG_ENCRYPT_ASCEND_SECRET
Encrypt attribute ascend style.
Definition radius.h:184
@ RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD
Encrypt attribute RFC 2868 style.
Definition radius.h:183
#define fr_radius_flag_abinary(_da)
Definition radius.h:206
bool tunnel_password_zeros
check for trailing zeros on decode
Definition radius.h:169
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition radius.h:162
fr_pair_list_t * tag_root
Where to insert tag attributes.
Definition radius.h:175
static fr_dict_t const * dict_radius
Definition radsniff.c:93
static fr_dict_attr_t const * attr_vendor_specific
Definition radsnmp.c:115
fr_pair_t * vp
ssize_t fr_struct_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, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Definition struct.c:32
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
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:86
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:68
Entry point for pair decoders.
Definition test_point.h:85
Entry point for protocol decoders.
Definition test_point.h:67
static fr_slen_t head
Definition xlat.h:420
#define PAIR_ALLOCED(_x)
Definition pair.h:212
static int fr_pair_find_or_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Definition pair.h:540
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.
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
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:558
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
#define FR_TYPE_LEAF
Definition types.h:317
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:1892
ssize_t fr_value_box_ipaddr_from_network(fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, int prefix_len, uint8_t const *data, size_t data_len, bool fixed, bool tainted)
Decode a fr_value_box_t of type IP address / prefix.
Definition value.c:2296
static fr_slen_t data
Definition value.h:1340
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030