Coverage Report

Created: 2026-06-30 07:16

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