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: 23a983bcc02d6930dac77b3ead9c8f047054ba8d $
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: 23a983bcc02d6930dac77b3ead9c8f047054ba8d $")
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_unknown_attr_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_unknown_attr_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_unknown_tlv_afrom_num(packet_ctx->tmp_ctx, parent, p[0]);
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_unknown_attr_afrom_num(packet_ctx->tmp_ctx, parent, attribute);
821  if (!da) return -1;
822 
823  goto decode;
824 
825  } else {
826  da = fr_dict_unknown_tlv_afrom_num(packet_ctx->tmp_ctx, parent, attribute);
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_unknown_attr_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 (!flag_long_extended(&da->flags)) {
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);
992  fr_dict_unknown_free(&child);
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_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_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_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_unknown_attr_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_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];
1487  fr_radius_decode_ctx_t *packet_ctx = decode_ctx;
1488 
1489  if (attr_len > 128 * 1024) {
1490  fr_strerror_printf("%s: packet is too large to be RADIUS", __FUNCTION__);
1491  return -1;
1492  }
1493 
1494  if ((data + attr_len) > packet_ctx->end) {
1495  fr_strerror_printf("%s: input overflows packet", __FUNCTION__);
1496  return -1;
1497  }
1498 
1499  FR_PROTO_HEX_DUMP(data, attr_len, "%s", __FUNCTION__ );
1500 
1501  FR_PROTO_TRACE("Parent %s len %zu ... %zu", parent->name, attr_len, packet_ctx->end - data);
1502 
1503  data_len = attr_len;
1504 
1505  /*
1506  * Silently ignore zero-length attributes.
1507  */
1508  if (attr_len == 0) return 0;
1509 
1510  /*
1511  * Hacks for tags.
1512  */
1513  if (flag_has_tag(&parent->flags)) {
1514  /*
1515  * Check for valid tags and data types.
1516  */
1517  if (parent->type == FR_TYPE_UINT32) {
1518  if ((attr_len != 4) || (p[0] >= 0x20)) {
1519  goto raw;
1520  }
1521 
1522  } else if (parent->type != FR_TYPE_STRING) {
1523  goto raw;
1524  }
1525 
1526  /*
1527  * Tag values MUST be less than 32.
1528  */
1529  if (p[0] < 0x20) {
1530  /*
1531  * Only "short" attributes can be encrypted.
1532  */
1533  if (data_len >= sizeof(buffer)) goto raw;
1534 
1535  if (parent->type == FR_TYPE_STRING) {
1536  memcpy(buffer, p + 1, data_len - 1);
1537  tag = p[0];
1538  data_len -= 1;
1539 
1540  } else if (parent->type == FR_TYPE_UINT32) {
1541  memcpy(buffer, p, attr_len);
1542  tag = buffer[0];
1543  buffer[0] = 0;
1544  }
1545 
1546  p = buffer;
1547 
1548  } /* else the field is >=0x20, so it's not a tag */
1549  }
1550 
1551  if (tag) {
1552  fr_radius_tag_ctx_t **new_tag_ctx = NULL;
1553 
1554  if (!packet_ctx->tags) {
1555  /*
1556  * This should NOT be packet_ctx.tmp_ctx,
1557  * as that is freed after decoding every
1558  * packet. We wish to aggregate the tags
1559  * across multiple attributes.
1560  */
1561  new_tag_ctx = talloc_zero_array(NULL, fr_radius_tag_ctx_t *, 32);
1562  if (unlikely(!new_tag_ctx)) return PAIR_DECODE_OOM;
1563 
1564  FR_PROTO_TRACE("Allocated tag cache %p", new_tag_ctx);
1565 
1566  packet_ctx->tags = new_tag_ctx;
1567  }
1568 
1569  fr_assert(tag < 0x20);
1570 
1571  if (!packet_ctx->tags[tag]) {
1572  fr_pair_t *group;
1573  fr_dict_attr_t const *group_da;
1574 
1575  packet_ctx->tags[tag] = talloc_zero(packet_ctx->tags, fr_radius_tag_ctx_t);
1576  if (unlikely(!packet_ctx->tags[tag])) {
1577  if (new_tag_ctx) TALLOC_FREE(packet_ctx->tags);
1578  return PAIR_DECODE_OOM;
1579  }
1580 
1581  group_da = fr_dict_attr_child_by_num(fr_dict_root(dict_radius), FR_TAG_BASE + tag);
1582  if (unlikely(!group_da)) {
1583  tag_alloc_error:
1584  TALLOC_FREE(packet_ctx->tags[tag]);
1585  return PAIR_DECODE_OOM;
1586  }
1587 
1588  group = fr_pair_afrom_da(packet_ctx->tag_root_ctx, group_da);
1589  if (unlikely(!group)) goto tag_alloc_error;
1590 
1591  packet_ctx->tags[tag]->parent = group;
1592 
1593  FR_PROTO_TRACE("Allocated tag attribute %p (%u)", group, tag);
1594 
1595  fr_pair_append(packet_ctx->tag_root, group);
1596 #ifdef TALLOC_GET_TYPE_ABORT_NOOP
1597  }
1598 #else
1599  } else {
1600  talloc_get_type_abort(packet_ctx->tags, fr_radius_tag_ctx_t *);
1601  talloc_get_type_abort(packet_ctx->tags[tag], fr_radius_tag_ctx_t);
1602  talloc_get_type_abort(packet_ctx->tags[tag]->parent, fr_pair_t);
1603  }
1604 #endif
1605  }
1606 
1607  /*
1608  * Decrypt the attribute.
1609  */
1610  if (flag_encrypted(&parent->flags)) {
1611  FR_PROTO_TRACE("Decrypting type %u", parent->flags.subtype);
1612  /*
1613  * Encrypted attributes can only exist for the
1614  * old-style format. Extended attributes CANNOT
1615  * be encrypted.
1616  */
1617  if (attr_len > 253) goto raw;
1618 
1619  if (p == data) memcpy(buffer, p, attr_len);
1620  p = buffer;
1621 
1622  switch (parent->flags.subtype) { /* can't be tagged */
1623  /*
1624  * User-Password
1625  */
1627  if (!packet_ctx->request_authenticator) goto raw;
1628 
1629  fr_radius_decode_password((char *)buffer, attr_len, packet_ctx);
1630  buffer[253] = '\0';
1631 
1632  /*
1633  * MS-CHAP-MPPE-Keys are 24 octets, and
1634  * encrypted. Since it's binary, we can't
1635  * look for trailing zeros.
1636  */
1637  if (parent->flags.length) {
1638  if (data_len > parent->flags.length) {
1639  data_len = parent->flags.length;
1640  } /* else leave data_len alone */
1641  } else {
1642  /*
1643  * Take off trailing zeros from the END.
1644  * This allows passwords to have zeros in
1645  * the middle of a field.
1646  *
1647  * However, if the password has a zero at
1648  * the end, it will get mashed by this
1649  * code. There's really no way around
1650  * that.
1651  */
1652  while ((data_len > 0) && (buffer[data_len - 1] == '\0')) data_len--;
1653  }
1654  break;
1655 
1656  /*
1657  * Tunnel-Password's go in response packets,
1658  * except for CoA-Requests. They can have a tag,
1659  * so data_len is not the same as attrlen.
1660  */
1663  if (!packet_ctx->request_authenticator) goto raw;
1664 
1665  if (fr_radius_decode_tunnel_password(buffer, &data_len, packet_ctx) < 0) {
1666  goto raw;
1667  }
1668  break;
1669 
1670  /*
1671  * Ascend-Send-Secret
1672  * Ascend-Receive-Secret
1673  */
1675  if (!packet_ctx->request_authenticator) goto raw;
1676 
1677  fr_radius_ascend_secret(&FR_DBUFF_TMP(buffer, sizeof(buffer)), p, data_len,
1678  packet_ctx->common->secret, packet_ctx->request_authenticator);
1680  data_len = strlen((char *) buffer);
1681  break;
1682 
1683  default:
1684  /*
1685  * Chop the attribute to its maximum length.
1686  */
1687  if ((parent->type == FR_TYPE_OCTETS) &&
1688  (parent->flags.length && (data_len > parent->flags.length))) {
1689  data_len = parent->flags.length;
1690  }
1691  break;
1692  } /* switch over encryption flags */
1693  }
1694 
1695  /*
1696  * Double-check the length after decrypting the
1697  * attribute.
1698  */
1699  FR_PROTO_TRACE("Type \"%s\" (%u)", fr_type_to_str(parent->type), parent->type);
1700 
1701  switch (parent->type) {
1702  case FR_TYPE_LEAF:
1703  break;
1704 
1705  case FR_TYPE_VSA:
1706  /*
1707  * VSAs in the RFC space are encoded one way.
1708  * VSAs in the "extended" space are different.
1709  */
1710  if (!parent->parent || !flag_extended(&parent->parent->flags)) {
1711  /*
1712  * VSAs can be WiMAX, in which case they don't
1713  * fit into one attribute.
1714  */
1715  ret = decode_vsa(ctx, out, parent, p, attr_len, packet_ctx);
1716  if (ret < 0) goto raw;
1717  return ret;
1718 
1719  } else {
1720  fr_dict_attr_t const *vendor_da;
1721  fr_pair_t *vsa, *vendor;
1722  uint32_t vendor_pen;
1723 
1724 
1725  if (data_len < 6) goto raw; /* vid, vtype, value */
1726 
1727  memcpy(&vendor_pen, p, 4);
1728  vendor_pen = ntohl(vendor_pen);
1729 
1730  /*
1731  * For simplicity in our attribute tree, vendors are
1732  * represented as a subtlv(ish) of an EVS or VSA
1733  * attribute.
1734  */
1735  vendor_da = fr_dict_attr_child_by_num(parent, vendor_pen);
1736  if (!vendor_da) {
1737  /*
1738  * If there's no child, it means the vendor is unknown. Create a
1739  * temporary vendor in the packet_ctx. This will be cleaned up when the
1740  * decoder exists, which is fine. Because any unknown attributes which
1741  * depend on it will copy the entire hierarchy.
1742  */
1743  vendor_da = fr_dict_unknown_vendor_afrom_num(packet_ctx->tmp_ctx, parent, vendor_pen);
1744  if (!vendor_da) return PAIR_DECODE_OOM;
1745  }
1746 
1747  child = fr_dict_attr_child_by_num(vendor_da, p[4]);
1748  if (!child) {
1749  /*
1750  * Vendor exists but child didn't, create an unknown child.
1751  */
1752  child = fr_dict_unknown_attr_afrom_num(packet_ctx->tmp_ctx, vendor_da, p[4]);
1753  if (!child) {
1754  fr_strerror_printf_push("decoder failed creating unknown attribute in %s",
1755  parent->name);
1756  return -1;
1757  }
1758  }
1759 
1760  if (fr_pair_find_or_append_by_da(ctx, &vsa, out, parent) < 0) return PAIR_DECODE_OOM;
1761 
1762  if (fr_pair_find_or_append_by_da(vsa, &vendor, &vsa->vp_group, vendor_da) < 0) return PAIR_DECODE_OOM;
1763 
1764  /*
1765  * Everything was found in the dictionary, we can
1766  * now recurse to decode the value.
1767  */
1768  ret = fr_radius_decode_pair_value(vendor, &vendor->vp_group,
1769  child, p + 5, attr_len - 5,
1770  packet_ctx);
1771  if (ret < 0) goto raw;
1772  return attr_len;
1773  }
1774 
1775  case FR_TYPE_TLV:
1776  /*
1777  * We presume that the TLVs all fit into one
1778  * attribute, OR they've already been grouped
1779  * into a contiguous memory buffer.
1780  */
1781  ret = fr_radius_decode_tlv(ctx, out, parent, p, attr_len, packet_ctx);
1782  if (ret < 0) goto raw;
1783  return attr_len;
1784 
1785  case FR_TYPE_STRUCT:
1786  /*
1787  * We presume that the struct fits into one
1788  * attribute, OR it's already been grouped
1789  * into a contiguous memory buffer.
1790  */
1791  ret = fr_struct_from_network(ctx, out, parent, p, attr_len, true,
1793  if (ret < 0) goto raw;
1794  return attr_len;
1795 
1796  case FR_TYPE_GROUP:
1797  {
1798  fr_dict_attr_t const *ref;
1799  fr_dict_protocol_t const *proto;
1800 
1801  ref = fr_dict_attr_ref(parent);
1802  if (!ref) goto raw;
1803 
1804  fr_assert(ref->dict != parent->dict);
1805 
1806  proto = fr_dict_protocol(ref->dict);
1807  fr_assert(proto != NULL);
1808 
1809  if (!proto->decode) goto raw;
1810 
1811  vp = fr_pair_afrom_da(ctx, parent);
1812  if (!vp) return -1;
1813 
1814  ret = proto->decode(vp, &vp->vp_group, p, attr_len);
1815  if (ret < 0) goto raw;
1816 
1817  vp->vp_tainted = true;
1818 
1819  fr_pair_append(out, vp);
1820  return attr_len;
1821  }
1822 
1823  default:
1824  raw:
1825  if (vp) talloc_free(vp);
1826 
1827  return fr_pair_raw_from_network(ctx, out, parent, data, attr_len);
1828  }
1829 
1830  /*
1831  * And now that we've verified the basic type
1832  * information, decode the actual p.
1833  */
1834  if (!tag) {
1835  vp = fr_pair_afrom_da(ctx, parent);
1836  } else {
1837  fr_assert(packet_ctx->tags != NULL);
1838  fr_assert(packet_ctx->tags[tag] != NULL);
1839  vp = fr_pair_afrom_da_nested(packet_ctx->tags[tag]->parent, &packet_ctx->tags[tag]->parent->vp_group, parent);
1840  }
1841  if (!vp) return -1;
1842 
1843  switch (parent->type) {
1844  /*
1845  * Magic RADIUS format IPv4 prefix
1846  *
1847  * 0 1 2 3
1848  * 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
1849  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1850  * | Reserved | Prefix-Length | Prefix ...
1851  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1852  * ... Prefix |
1853  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1854  *
1855  * RFC does not require non-masked bits to be zero.
1856  */
1857  case FR_TYPE_IPV4_PREFIX:
1858  if (data_len != 6) goto raw;
1859  if (p[0] != 0) goto raw;
1860  if ((p[1] & 0x3f) > 32) goto raw;
1861 
1862  vp->vp_ip.af = AF_INET;
1863  vp->vp_ip.scope_id = 0;
1864  vp->vp_ip.prefix = p[1] & 0x3f;
1865  memcpy((uint8_t *)&vp->vp_ipv4addr, p + 2, data_len - 2);
1866  fr_ipaddr_mask(&vp->vp_ip, p[1] & 0x3f);
1867  break;
1868 
1869  /*
1870  * Magic RADIUS format IPv6 prefix
1871  *
1872  * 0 1 2 3
1873  * 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
1874  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1875  * | Type | Length | Reserved | Prefix-Length |
1876  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1877  * Prefix
1878  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1879  * Prefix
1880  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1881  * Prefix
1882  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1883  * Prefix |
1884  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1885  *
1886  * RFC says non-masked bits MUST be zero.
1887  */
1888  case FR_TYPE_IPV6_PREFIX:
1889  {
1890  if (data_len > 18) goto raw;
1891  if (data_len < 2) goto raw;
1892  if (p[0] != 0) goto raw; /* First byte is always 0 */
1893  if (p[1] > 128) goto raw;
1894 
1895  /*
1896  * Convert prefix bits to bytes to check that
1897  * we have sufficient data.
1898  *
1899  * If Prefix has more data than Prefix-Length
1900  * indicates, we just ignore the rest.
1901  */
1902  if (fr_bytes_from_bits(p[1]) > (data_len - 2)) goto raw;
1903 
1904  vp->vp_ip.af = AF_INET6;
1905  vp->vp_ip.scope_id = 0;
1906  vp->vp_ip.prefix = p[1];
1907 
1908  memcpy((uint8_t *)&vp->vp_ipv6addr, p + 2, data_len - 2);
1909  fr_ipaddr_mask(&vp->vp_ip, p[1]);
1910 
1911  /*
1912  * Check the prefix data is the same before
1913  * and after casting (it should be).
1914  */
1915  if (memcmp(p + 2, (uint8_t *)&vp->vp_ipv6addr, data_len - 2) != 0) goto raw;
1916  }
1917  break;
1918 
1919  case FR_TYPE_STRING:
1920  if (!flag_abinary(&parent->flags)) goto decode;
1921 
1922  if (fr_radius_decode_abinary(vp, p, data_len) < 0) goto raw;
1923  break;
1924 
1925  case FR_TYPE_OCTETS:
1926  /*
1927  * This attribute SHOULD have fixed size, but it
1928  * doesn't. Therefore it's malformed.
1929  */
1930  if (parent->flags.length && (data_len != parent->flags.length)) goto raw;
1931  FALL_THROUGH;
1932 
1933  default:
1934  decode:
1935  ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da,
1936  &FR_DBUFF_TMP(p, data_len), data_len, true);
1937  if (ret < 0) {
1938  /*
1939  * Paranoid loop prevention
1940  */
1941  if (vp->da->flags.is_unknown) {
1942  talloc_free(vp);
1943  return -1;
1944  }
1945  goto raw;
1946  }
1947  break;
1948  }
1949 
1950  vp->vp_tainted = true;
1951 
1952  if (!tag) fr_pair_append(out, vp);
1953 
1954  return attr_len;
1955 }
1956 
1957 /*
1958  * Let's try to help the CPU as much as possible. If we have a
1959  * check on a buffer, that's less work than a series of if / then
1960  * / else conditions.
1961  */
1962 static const bool special[UINT8_MAX + 1] = {
1963  [FR_NAS_FILTER_RULE] = true, /* magic rules */
1964  [FR_DIGEST_ATTRIBUTES] = true, /* magic rules */
1965 
1966  [FR_EAP_MESSAGE] = true, /* concat */
1967  [FR_PKM_SS_CERT] = true, /* concat */
1968  [FR_PKM_CA_CERT] = true, /* concat */
1969  [FR_EAPOL_ANNOUNCEMENT] = true, /* concat */
1970 
1971  [FR_EXTENDED_ATTRIBUTE_1] = true,
1972  [FR_EXTENDED_ATTRIBUTE_2] = true,
1973  [FR_EXTENDED_ATTRIBUTE_3] = true,
1974  [FR_EXTENDED_ATTRIBUTE_4] = true,
1975  [FR_EXTENDED_ATTRIBUTE_5] = true,
1976  [FR_EXTENDED_ATTRIBUTE_6] = true,
1977 };
1978 
1979 /** Create a "normal" fr_pair_t from the given data
1980  *
1981  */
1983  uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx)
1984 {
1985  ssize_t ret;
1986  fr_dict_attr_t const *da;
1987 
1988  if ((data_len < 2) || (data[1] < 2) || (data[1] > data_len)) {
1989  fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
1990  return -1;
1991  }
1992 
1993  /*
1994  * If we don't have a tag root already, then record where
1995  * we're putting the top level attributes and add the tags
1996  * there.
1997  */
1998  if (!packet_ctx->tag_root) {
1999  packet_ctx->tag_root = out;
2000  packet_ctx->tag_root_ctx = ctx;
2001  }
2002 
2004  if (!da) {
2005  FR_PROTO_TRACE("Unknown attribute %u", data[0]);
2007  }
2008  if (!da) return -1;
2009  FR_PROTO_TRACE("decode context changed %s -> %s",da->parent->name, da->name);
2010 
2011  /*
2012  * Empty attributes are silently ignored, except for CUI.
2013  */
2014  if (data[1] == 2) {
2015  fr_pair_t *vp;
2016 
2017  if (data[0] != FR_CHARGEABLE_USER_IDENTITY) {
2018  return 2;
2019  }
2020 
2021  /*
2022  * Hacks for CUI. The WiMAX spec says that it can be
2023  * zero length, even though this is forbidden by the
2024  * RADIUS specs. So... we make a special case for it.
2025  *
2026  * We can't create a zero length attribute,
2027  * because the talloc API won't let us. So, we
2028  * just create a fake attribute.
2029  */
2030  vp = fr_pair_afrom_da(ctx, da);
2031  if (!vp) return -1;
2032 
2033  fr_pair_append(out, vp);
2034  vp->vp_tainted = true; /* not REALLY necessary, but what the heck */
2035 
2036  return 2;
2037  }
2038 
2039  /*
2040  * A few attributes are special, but they're rare.
2041  */
2042  if (unlikely(special[data[0]])) {
2043  if (data[0] == FR_NAS_FILTER_RULE) {
2044  return decode_nas_filter_rule(ctx, out, da, data, data_len, packet_ctx);
2045  }
2046 
2047  if (data[0] == FR_DIGEST_ATTRIBUTES) {
2048  return decode_digest_attributes(ctx, out, da, data, data_len, packet_ctx);
2049  }
2050 
2051  /*
2052  * Concatenate consecutive top-level attributes together.
2053  */
2054  if (flag_concat(&da->flags)) {
2055  FR_PROTO_TRACE("Concat attribute");
2056  return decode_concat(ctx, out, da, data, packet_ctx->end);
2057  }
2058 
2059  /*
2060  * Extended attributes have a horrible format.
2061  * Try to deal with that here, so that the rest
2062  * of the code doesn't have to.
2063  */
2064  if (flag_extended(&da->flags)) {
2065  return decode_extended(ctx, out, da, data, data_len, packet_ctx);
2066  }
2067 
2068  /*
2069  * @todo - pre-concatenate WiMAX, if 26, and dv->continuation, too.
2070  */
2071  }
2072 
2073  /*
2074  * Note that we pass the entire length, not just the
2075  * length of this attribute. The Extended or WiMAX
2076  * attributes may have the "continuation" bit set, and
2077  * will thus be more than one attribute in length.
2078  */
2079  ret = fr_radius_decode_pair_value(ctx, out,
2080  da, data + 2, data[1] - 2,
2081  packet_ctx);
2082  if (ret < 0) return ret;
2083 
2084  return 2 + ret;
2085 }
2086 
2088  uint8_t const *data, size_t data_len)
2089 {
2090  ssize_t slen;
2091  uint8_t const *attr, *end;
2092 
2093  fr_radius_ctx_t common_ctx = {};
2094  fr_radius_decode_ctx_t decode_ctx = {
2095  .common = &common_ctx,
2096  .tmp_ctx = talloc(ctx, uint8_t),
2097  .end = data + data_len,
2098  };
2099 
2100  fr_assert(dict_radius != NULL);
2101 
2102  attr = data;
2103  end = decode_ctx.end;
2104 
2105  while (attr < end) {
2106  slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), &decode_ctx);
2107  if (slen < 0) {
2108 // fail:
2109  talloc_free(decode_ctx.tmp_ctx);
2110  talloc_free(decode_ctx.tags);
2111  return slen;
2112  }
2113 
2114 #if 0
2115  /*
2116  * If slen is larger than the room in the packet,
2117  * all kinds of bad things happen.
2118  */
2119  if (!fr_cond_assert(slen <= (end - attr))) {
2120  goto fail;
2121  }
2122 #endif
2123 
2124  attr += slen;
2125  talloc_free_children(decode_ctx.tmp_ctx);
2126  }
2127 
2128  talloc_free(decode_ctx.tmp_ctx);
2129  talloc_free(decode_ctx.tags);
2130  return data_len;
2131 }
2132 
2134 {
2135  TALLOC_FREE(ctx->tags);
2136 
2137  return 0;
2138 }
2139 
2140 static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
2141 {
2142  static uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH] = {
2143  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2144  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2145 
2146  fr_radius_decode_ctx_t *test_ctx;
2147 
2148  test_ctx = talloc_zero(ctx, fr_radius_decode_ctx_t);
2149  test_ctx->common = talloc_zero(test_ctx, fr_radius_ctx_t);
2150 
2151  test_ctx->common->secret = talloc_strdup(test_ctx->common, "testing123");
2152  test_ctx->common->secret_length = talloc_array_length(test_ctx->common->secret) - 1;
2153 
2154  test_ctx->request_authenticator = vector;
2155  test_ctx->tmp_ctx = talloc_zero(test_ctx, uint8_t);
2156  talloc_set_destructor(test_ctx, _test_ctx_free);
2157 
2158  *out = test_ctx;
2159 
2160  return 0;
2161 }
2162 
2163 static const char *reason_name[DECODE_FAIL_MAX] = {
2164  [ DECODE_FAIL_NONE ] = "all OK",
2165  [ DECODE_FAIL_MIN_LENGTH_PACKET ] = "packet is too small",
2166  [ DECODE_FAIL_MIN_LENGTH_FIELD ] = "length field is too small",
2167  [ DECODE_FAIL_MIN_LENGTH_MISMATCH ] = "length mismatch",
2168  [ DECODE_FAIL_HEADER_OVERFLOW ] = "header overflow",
2169  [ DECODE_FAIL_UNKNOWN_PACKET_CODE ] = "unknown packet code",
2170  [ DECODE_FAIL_INVALID_ATTRIBUTE ] = "invalid attribute",
2171  [ DECODE_FAIL_ATTRIBUTE_TOO_SHORT ] = "attribute too short",
2172  [ DECODE_FAIL_ATTRIBUTE_OVERFLOW ] = "attribute overflows the packet",
2173  [ DECODE_FAIL_MA_INVALID_LENGTH ] = "invalid length for Message-Authenticator",
2174  [ DECODE_FAIL_ATTRIBUTE_UNDERFLOW ] = "attribute underflows the packet",
2175  [ DECODE_FAIL_TOO_MANY_ATTRIBUTES ] = "too many attributes",
2176  [ DECODE_FAIL_MA_MISSING ] = "Message-Authenticator is required, but missing",
2177  [ DECODE_FAIL_MA_INVALID ] = "Message-Authenticator is invalid",
2178  [ DECODE_FAIL_UNKNOWN ] = "unknown",
2179 };
2180 
2182  uint8_t const *data, size_t data_len, void *proto_ctx)
2183 {
2184  fr_radius_decode_ctx_t *test_ctx = talloc_get_type_abort(proto_ctx, fr_radius_decode_ctx_t);
2185  decode_fail_t reason;
2186  fr_pair_t *vp;
2187  size_t packet_len = data_len;
2188 
2189  if (!fr_radius_ok(data, &packet_len, 200, false, &reason)) {
2190  fr_strerror_printf("Packet failed verification - %s", reason_name[reason]);
2191  return -1;
2192  }
2193 
2194  /*
2195  * Decode the header
2196  */
2198  if (!vp) {
2199  fr_strerror_const("Failed creating Packet-Type");
2200  return -1;
2201  }
2202  vp->vp_uint32 = data[0];
2203  fr_pair_append(out, vp);
2204 
2206  if (!vp) {
2207  fr_strerror_const("Failed creating Packet-Authentication-Vector");
2208  return -1;
2209  }
2210  (void) fr_pair_value_memdup(vp, data + 4, 16, true);
2211  fr_pair_append(out, vp);
2212 
2213  test_ctx->end = data + packet_len;
2214 
2215  return fr_radius_decode(ctx, out, UNCONST(uint8_t *, data), packet_len, test_ctx);
2216 }
2217 
2219  uint8_t const *data, size_t data_len, void *decode_ctx)
2220 {
2221  fr_radius_decode_ctx_t *packet_ctx = decode_ctx;
2222 
2224 
2225  packet_ctx->end = data + data_len;
2226  return fr_radius_decode_pair(ctx, out, data, data_len, decode_ctx);
2227 }
2228 
2229 
2230 /*
2231  * Test points
2232  */
2236  .func = decode_pair
2237 };
2238 
2242  .func = fr_radius_decode_proto
2243 };
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:444
#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:378
#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:509
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#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:229
size_t type
Length of type data.
Definition: dict.h:230
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
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:2277
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
uint32_t pen
Private enterprise number.
Definition: dict.h:228
fr_dict_attr_t * fr_dict_unknown_tlv_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:312
size_t length
Length of length data.
Definition: dict.h:231
fr_dict_attr_t * fr_dict_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor))
Build an unknown vendor, parented by a VSA attribute.
Definition: dict_unknown.c:272
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition: dict_util.c:4537
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:341
Private enterprise.
Definition: dict.h:227
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:164
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition: inet.c:203
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
Definition: pair.h:46
#define PAIR_DECODE_FATAL_ERROR
Fatal error - Failed decoding the packet.
Definition: pair.h:50
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:365
fr_md5_update_t fr_md5_update
Definition: md5.c:450
fr_md5_final_t fr_md5_final
Definition: md5.c:451
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition: md5.c:530
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition: md5.c:485
fr_md5_ctx_copy_t fr_md5_ctx_copy
Definition: md5.c:447
void fr_md5_ctx_t
Definition: md5.h:28
@ 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
bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, uint32_t max_attributes, bool require_ma, decode_fail_t *reason)
Definition: merged_model.c:259
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:228
#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:278
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:2978
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
fr_pair_t * fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition: pair.c:1819
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:462
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:2781
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:2927
HIDDEN fr_dict_attr_t const * attr_packet_authentication_vector
Definition: base.c:53
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:190
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:997
fr_test_point_proto_decode_t radius_tp_decode_proto
Definition: decode.c:2240
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:2087
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:2163
fr_test_point_pair_decode_t radius_tp_decode_pair
Definition: decode.c:2234
#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:2140
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:1962
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:1982
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:2133
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:2181
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:2218
VQP attributes.
static fr_dict_t const * dict_radius
Definition: radclient-ng.c:102
static bool done
Definition: radclient.c:80
fr_pair_t * parent
Definition: radius.h:106
fr_radius_tag_ctx_t ** tags
for decoding tagged attributes
Definition: radius.h:150
@ FLAG_ENCRYPT_ASCEND_SECRET
Encrypt attribute ascend style.
Definition: radius.h:93
@ FLAG_ENCRYPT_TUNNEL_PASSWORD
Encrypt attribute RFC 2868 style.
Definition: radius.h:92
@ FLAG_ENCRYPT_USER_PASSWORD
Encrypt attribute RFC 2865 style.
Definition: radius.h:91
@ FLAG_TAGGED_TUNNEL_PASSWORD
the attribute has a tag and is encrypted
Definition: radius.h:89
#define flag_has_tag(_flags)
Definition: radius.h:97
uint8_t const * request_authenticator
Definition: radius.h:139
#define AUTH_PASS_LEN
Definition: radius.h:53
char const * secret
Definition: radius.h:111
#define flag_extended(_flags)
Definition: radius.h:101
uint8_t const * end
end of the packet
Definition: radius.h:142
#define RADIUS_MAX_STRING_LENGTH
Definition: radius.h:34
#define flag_encrypted(_flags)
Definition: radius.h:100
TALLOC_CTX * tag_root_ctx
Where to allocate new tag attributes.
Definition: radius.h:152
size_t secret_length
Definition: radius.h:112
#define RADIUS_MAX_PASS_LENGTH
Definition: radius.h:38
@ DECODE_FAIL_UNKNOWN
Definition: radius.h:74
@ DECODE_FAIL_INVALID_ATTRIBUTE
Definition: radius.h:66
@ DECODE_FAIL_ATTRIBUTE_UNDERFLOW
Definition: radius.h:70
@ DECODE_FAIL_MIN_LENGTH_FIELD
Definition: radius.h:62
@ DECODE_FAIL_HEADER_OVERFLOW
Definition: radius.h:64
@ DECODE_FAIL_ATTRIBUTE_TOO_SHORT
Definition: radius.h:67
@ DECODE_FAIL_MA_INVALID
Definition: radius.h:73
@ DECODE_FAIL_ATTRIBUTE_OVERFLOW
Definition: radius.h:68
@ DECODE_FAIL_TOO_MANY_ATTRIBUTES
Definition: radius.h:71
@ DECODE_FAIL_NONE
Definition: radius.h:60
@ DECODE_FAIL_MIN_LENGTH_PACKET
Definition: radius.h:61
@ DECODE_FAIL_MIN_LENGTH_MISMATCH
Definition: radius.h:63
@ DECODE_FAIL_MA_INVALID_LENGTH
Definition: radius.h:69
@ DECODE_FAIL_MAX
Definition: radius.h:75
@ DECODE_FAIL_MA_MISSING
Definition: radius.h:72
@ DECODE_FAIL_UNKNOWN_PACKET_CODE
Definition: radius.h:65
#define flag_abinary(_flags)
Definition: radius.h:99
#define flag_concat(_flags)
Definition: radius.h:98
bool tunnel_password_zeros
check for trailing zeros on decode
Definition: radius.h:146
fr_radius_ctx_t * common
Definition: radius.h:137
#define flag_long_extended(_flags)
Definition: radius.h:102
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition: radius.h:141
fr_pair_list_t * tag_root
Where to insert tag attributes.
Definition: radius.h:151
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, bool nested, 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:84
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:66
Entry point for pair decoders.
Definition: test_point.h:83
Entry point for protocol decoders.
Definition: test_point.h:65
static fr_slen_t head
Definition: xlat.h:408
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:522
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:844
#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:1709
static fr_slen_t data
Definition: value.h:1259
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:984