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