Coverage Report

Created: 2026-02-26 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/util/struct.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
/** Functions to encode / decode structures on the wire
18
 *
19
 * @file src/lib/util/struct.c
20
 *
21
 * @copyright 2018 The FreeRADIUS server project
22
 * @copyright 2018 Alan DeKok (aland@freeradius.org)
23
 */
24
RCSID("$Id: 2d6c4ef4935c7ff5015b89802b5aaeec8ba9e9ec $")
25
26
#include <freeradius-devel/util/struct.h>
27
#include <freeradius-devel/io/pair.h>
28
29
/** Convert a STRUCT to one or more VPs
30
 *
31
 */
32
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out,
33
             fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
34
             void *decode_ctx,
35
             fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
36
78.2k
{
37
78.2k
  unsigned int    child_num;
38
78.2k
  uint8_t const   *p = data, *end = data + data_len;
39
78.2k
  fr_dict_attr_t const  *child, *substruct_da;
40
78.2k
  fr_pair_list_t    child_list_head;
41
78.2k
  fr_pair_list_t    *child_list;
42
78.2k
  fr_pair_t   *vp, *key_vp, *struct_vp = NULL;
43
78.2k
  unsigned int    offset = 0;
44
78.2k
  TALLOC_CTX    *child_ctx;
45
78.2k
  ssize_t     slen;
46
78.2k
  size_t      child_length;
47
48
78.2k
  if (data_len == 0) {
49
2.07k
    fr_strerror_const("struct decoder was passed zero bytes of data");
50
2.07k
    return -1; /* at least one byte of data */
51
2.07k
  }
52
53
76.2k
  FR_PROTO_TRACE("Decoding struct %s", parent->name);
54
76.2k
  FR_PROTO_HEX_DUMP(data, data_len, "fr_struct_from_network");
55
56
  /*
57
   *  Start a child list.
58
   */
59
76.2k
  fr_assert(parent->type == FR_TYPE_STRUCT);
60
61
76.2k
  struct_vp = fr_pair_afrom_da(ctx, parent);
62
76.2k
  if (!struct_vp) {
63
0
    return PAIR_DECODE_OOM;
64
0
  }
65
76.2k
  PAIR_ALLOCED(struct_vp);
66
67
76.2k
  fr_pair_list_init(&child_list_head); /* still used elsewhere */
68
76.2k
  child_list = &struct_vp->vp_group;
69
76.2k
  child_ctx = struct_vp;
70
76.2k
  key_vp = NULL;
71
72
  /*
73
   *  Simplify the code by having a generic decode routine.
74
   */
75
76.2k
  if (!decode_value) decode_value = fr_pair_decode_value;
76
77
  /*
78
   *  Decode structs with length prefixes.
79
   */
80
76.2k
  if (da_is_length_field(parent)) {
81
3.41k
    size_t claimed_len, field_len, calc_len;
82
83
    /*
84
     *  Set how many bytes there are in the "length" field.
85
     */
86
3.41k
    if (da_is_length_field8(parent)) {
87
2.07k
      field_len = 1;
88
2.07k
    } else {
89
1.33k
      fr_assert(da_is_length_field16(parent));
90
1.33k
      field_len = 2;
91
1.33k
    }
92
93
3.41k
    if ((size_t) (end - p) < field_len) {
94
1
      FR_PROTO_TRACE("Insufficient room for length field");
95
96
986
    invalid_struct:
97
      /*
98
       *  Some field could not be decoded.  Nuke the entire struct, and just make the
99
       *  whole thing "raw".
100
       */
101
986
      TALLOC_FREE(struct_vp);
102
103
986
      slen = fr_pair_raw_from_network(ctx, out, parent, data, data_len);
104
986
      if (slen < 0) return slen;
105
99
      return data_len;
106
986
    }
107
108
3.41k
    claimed_len = p[0];
109
3.41k
    if (field_len > 1) {
110
1.33k
      claimed_len <<= 8;
111
1.33k
      claimed_len |= p[1];
112
1.33k
    }
113
3.41k
    p += field_len;
114
115
3.41k
    if (claimed_len < da_length_offset(parent)) {
116
8
      FR_PROTO_TRACE("Length header (%zu) is smaller than minimum value (%u)",
117
8
               claimed_len, parent->flags.type_size);
118
8
      goto invalid_struct;
119
8
    }
120
121
    /*
122
     *  Get the calculated length of the actual data.
123
     */
124
3.40k
    calc_len = claimed_len - da_length_offset(parent);
125
126
3.40k
    if (calc_len > (size_t) (end - p)) {
127
977
      FR_PROTO_TRACE("Length header (%zu) is larger than remaining data (%zu)",
128
977
               claimed_len + field_len, (size_t) (end - p));
129
977
      goto invalid_struct;
130
977
    }
131
132
    /*
133
     *  Limit the size of the decoded structure to the correct length.
134
     */
135
2.42k
    data_len = calc_len;
136
2.42k
    end = p + data_len;
137
2.42k
  }
138
139
  /*
140
   *  @todo - If the struct is truncated on a MEMBER boundary, we silently omit
141
   *  the trailing members.  Maybe this should be an error?
142
   */
143
75.2k
  for (child_num = 1;
144
342k
       (p < end) && (child = fr_dict_attr_child_by_num(parent, child_num)) != NULL;
145
275k
       child_num++) {
146
275k
    FR_PROTO_TRACE("Decoding struct %s child %s (%d)", parent->name, child->name, child->attr);
147
275k
    FR_PROTO_HEX_DUMP(p, (end - p), "fr_struct_from_network - remaining %zu", (size_t) (end - p));
148
149
    /*
150
     *  Check for bit fields.
151
     */
152
275k
    if (da_is_bit_field(child)) {
153
51.3k
      uint8_t array[8];
154
51.3k
      unsigned int num_bits;
155
51.3k
      uint64_t value;
156
157
51.3k
      num_bits = offset + child->flags.length;
158
51.3k
      if ((size_t)(end - p) < fr_bytes_from_bits(num_bits)) {
159
694
        FR_PROTO_TRACE("not enough data for bit decoder?");
160
694
        goto remainder_raw;
161
694
      }
162
163
50.6k
      memset(array, 0, sizeof(array));
164
50.6k
      memcpy(&array[0], p, fr_bytes_from_bits(num_bits));
165
166
50.6k
      if (offset > 0) array[0] &= (1 << (8 - offset)) - 1; /* mask off bits we don't care about */
167
168
50.6k
      memcpy(&value, &array[0], sizeof(value));
169
50.6k
      value = htonll(value);
170
50.6k
      value >>= (8 - offset); /* move it to the lower bits */
171
50.6k
      value >>= (56 - child->flags.length);
172
173
50.6k
      vp = fr_pair_afrom_da(child_ctx, child);
174
50.6k
      if (!vp) {
175
0
        FR_PROTO_TRACE("fr_struct_from_network - failed allocating child VP");
176
0
      oom:
177
0
        talloc_free(struct_vp);
178
0
        return PAIR_DECODE_OOM;
179
0
      }
180
50.6k
      PAIR_ALLOCED(vp);
181
182
50.6k
      switch (child->type) {
183
30.0k
        case FR_TYPE_BOOL:
184
30.0k
          vp->vp_bool = value;
185
30.0k
          break;
186
187
18.5k
        case FR_TYPE_UINT8:
188
18.5k
          vp->vp_uint8 = value;
189
18.5k
          break;
190
191
1.53k
        case FR_TYPE_UINT16:
192
1.53k
          vp->vp_uint16 = value;
193
1.53k
          break;
194
195
382
        case FR_TYPE_UINT32:
196
382
          vp->vp_uint32 = value;
197
382
          break;
198
199
100
        case FR_TYPE_UINT64:
200
100
          vp->vp_uint64 = value;
201
100
          break;
202
203
0
        default:
204
0
          FR_PROTO_TRACE("Can't decode unknown type?");
205
0
          goto remainder_raw;
206
50.6k
      }
207
208
50.6k
      vp->vp_tainted = true;
209
50.6k
      fr_pair_append(child_list, vp);
210
211
50.6k
      p += (num_bits >> 3); /* go to the LAST bit, not the byte AFTER the last bit */
212
50.6k
      offset = num_bits & 0x07;
213
50.6k
      continue;
214
50.6k
    }
215
216
223k
    fr_assert(offset == 0);
217
223k
    offset = 0; /* reset for non-bit-field attributes */
218
219
    /*
220
     *  The child is either unknown width, OR known width with a length that is too large for
221
     *  the "length" field, OR is known width via some kind of protocol-specific length header.
222
     */
223
223k
    if (!child->flags.length || child->flags.array) {
224
57.4k
      child_length = end - p;
225
226
166k
    } else {
227
166k
      child_length = child->flags.length;
228
229
      /*
230
       *  If this field overflows the input, then *all*
231
       *  of the input is suspect.
232
       */
233
166k
      if (child_length > (size_t) (end - p)) {
234
2.56k
        child_length = (size_t) (end - p);
235
2.56k
      }
236
166k
    }
237
238
    /*
239
     *  We only allow a limited number of data types
240
     *  inside of a struct.
241
     */
242
223k
    switch (child->type) {
243
0
    case FR_TYPE_INTERNAL:
244
0
    case FR_TYPE_NULL:
245
0
      FR_PROTO_TRACE("fr_struct_from_network - unknown child type");
246
0
      goto remainder_raw;
247
248
1.85k
    case FR_TYPE_STRUCT:
249
1.85k
    case FR_TYPE_VSA:
250
1.85k
    case FR_TYPE_VENDOR:
251
2.22k
    case FR_TYPE_GROUP:
252
218k
    case FR_TYPE_LEAF:
253
218k
      break;
254
255
    /*
256
     *  Decode child TLVs, according to the parent attribute.
257
     */
258
691
    case FR_TYPE_TLV:
259
691
      fr_assert(!key_vp);
260
261
691
      if (!decode_tlv) {
262
0
        fr_strerror_const("Decoding TLVs requires a decode_tlv() function to be passed");
263
0
        talloc_free(struct_vp);
264
0
        return -(p - data);
265
0
      }
266
267
      /*
268
       *  Decode all of the remaining data as
269
       *  TLVs.  Any malformed TLVs are appended
270
       *  as raw VP.
271
       */
272
959
      while (p < end) {
273
691
        slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
274
691
        if (slen < 0) {
275
423
          FR_PROTO_TRACE("failed decoding TLV?");
276
423
          goto remainder_raw;
277
423
        }
278
268
        p += slen;
279
268
      }
280
281
268
      goto done;
282
283
    /*
284
     *  The child is a union, it MUST be at the end of
285
     *  the struct, and we must have seen a key before
286
     *  we reach the union.  See dict_tokenize.
287
     */
288
4.48k
    case FR_TYPE_UNION:
289
      /*
290
       *  Create the union wrapper, and reset the child_ctx and child_list to it.
291
       */
292
4.48k
      vp = fr_pair_afrom_da(child_ctx, child);
293
4.48k
      if (!vp) goto oom;
294
4.48k
      PAIR_ALLOCED(vp);
295
296
4.48k
      fr_pair_append(child_list, vp);
297
4.48k
      substruct_da = child;
298
4.48k
      child_ctx = vp;
299
4.48k
      child_list = &vp->vp_group;
300
301
4.48k
      fr_assert(!fr_dict_attr_child_by_num(parent, child_num + 1)); /* has to be the last one */
302
4.48k
      if (!key_vp) {
303
1.11k
      remainder_raw:
304
1.11k
        child_length = (size_t) (end - p);
305
1.11k
        goto raw;
306
0
      }
307
308
4.48k
      goto substruct;
309
223k
    }
310
311
    /*
312
     *  Magic values get the callback called.
313
     *
314
     *  @todo - if this is an array of DNS labels, we
315
     *  need to do decompression checks on the entire
316
     *  block, and then decode each field
317
     *  individually.
318
     */
319
218k
    if (child->flags.array) {
320
2.55k
      slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value);
321
216k
    } else {
322
216k
      slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
323
216k
    }
324
218k
    if (slen < 0) {
325
2.46k
      FR_PROTO_TRACE("Failed decoding value");
326
327
3.58k
    raw:
328
3.58k
      slen = fr_pair_raw_from_network(child_ctx, child_list, child, p, child_length);
329
3.58k
      if (slen < 0) {
330
3.58k
        talloc_free(struct_vp);
331
3.58k
        return slen;
332
3.58k
      }
333
3.58k
    }
334
335
216k
    p += slen;    /* not always the same as child->flags.length */
336
337
216k
    if (fr_dict_attr_is_key_field(child)) {
338
4.88k
      fr_assert(!key_vp);
339
4.88k
      key_vp = fr_pair_list_tail(child_list);
340
4.88k
    }
341
216k
  }
342
343
  /*
344
   *  Is there a substructure after this one?  If so, go
345
   *  decode it.
346
   */
347
66.9k
  if (key_vp) {
348
393
    fr_dict_enum_value_t const *enumv;
349
350
393
    substruct_da = key_vp->da;
351
352
4.87k
  substruct:
353
4.87k
    child = NULL;
354
355
4.87k
    FR_PROTO_TRACE("Key %s", key_vp->da->name);
356
4.87k
    FR_PROTO_HEX_DUMP(p, (end - p), "fr_struct_from_network - child structure");
357
358
    /*
359
     *  Nothing more to decode, don't decode it.
360
     */
361
4.87k
    if (p >= end) {
362
393
      FR_PROTO_TRACE("Expected substruct, but there is none. We're done decoding this structure");
363
393
      goto done;
364
393
    }
365
366
4.48k
    enumv = fr_dict_enum_by_value(key_vp->da, &key_vp->data);
367
4.48k
    if (enumv) child = fr_dict_enum_attr_ref(enumv);
368
369
4.48k
    if (!child) {
370
      /*
371
       *  Always encode the unknown child as attribute number 0.  Since the unknown
372
       *  children have no "real" number, and are all unique da's, they are
373
       *  incomparable.  And thus can all be given the same number.
374
       */
375
1.59k
      uint64_t attr;
376
377
1.59k
      FR_PROTO_TRACE("No matching child structure found");
378
379
1.88k
    unknown_child:
380
1.88k
      attr = 0;
381
382
      /*
383
       *  But if we have a key field, the unknown attribute number is taken from the
384
       *  from the key field.
385
       */
386
1.88k
      if (fr_type_is_integer(key_vp->vp_type)) {
387
1.88k
        attr = fr_value_box_as_uint64(&key_vp->data);
388
1.88k
      }
389
390
1.88k
      child = fr_dict_attr_unknown_raw_afrom_num(child_ctx, substruct_da, attr);
391
1.88k
      if (!child) {
392
0
        FR_PROTO_TRACE("failed allocating unknown child for key VP %s - %s",
393
0
                 key_vp->da->name, fr_strerror());
394
0
        goto oom;
395
0
      }
396
397
1.88k
      slen = fr_pair_raw_from_network(child_ctx, child_list, child, p, end - p);
398
1.88k
      if (slen < 0) {
399
0
        FR_PROTO_TRACE("Failed creating raw VP from malformed or unknown substruct for child %s", child->name);
400
0
        fr_dict_attr_unknown_free(&child);
401
0
        return slen;
402
0
      }
403
404
1.88k
      p = end;
405
406
2.88k
    } else {
407
2.88k
      switch (child->type) {
408
2.88k
      case FR_TYPE_STRUCT:
409
2.88k
        FR_PROTO_TRACE("Decoding child structure %s", child->name);
410
2.88k
        slen = fr_struct_from_network(child_ctx, child_list, child, p, end - p,
411
2.88k
                    decode_ctx, decode_value, decode_tlv);
412
2.88k
        break;
413
414
0
      case FR_TYPE_TLV:
415
0
        if (!decode_tlv) {
416
0
          FR_PROTO_TRACE("Failed to pass decode_tlv() for child tlv %s", child->name);
417
0
          goto unknown_child;
418
0
        }
419
420
0
        FR_PROTO_TRACE("Decoding child tlv %s", child->name);
421
422
0
        slen = decode_tlv(child_ctx, child_list, child, p, end - p, decode_ctx);
423
0
        break;
424
425
0
      case FR_TYPE_LEAF:
426
0
        fr_assert(decode_value);
427
428
0
        FR_PROTO_TRACE("Decoding child %s", child->name);
429
430
        /*
431
         *  @todo - unify this code with the code above, but for now copying is
432
         *  easier.
433
         */
434
435
        /*
436
         *  The child is either unknown width, OR known width with a length that is too large for
437
         *  the "length" field, OR is known width via some kind of protocol-specific length header.
438
         */
439
0
        if (!child->flags.length || child->flags.array) {
440
0
          child_length = end - p;
441
442
0
        } else {
443
0
          child_length = child->flags.length;
444
445
          /*
446
           *  If this field overflows the input, then *all*
447
           *  of the input is suspect.
448
           */
449
0
          if (child_length > (size_t) (end - p)) {
450
0
            FR_PROTO_TRACE("fr_struct_from_network - child length %zu overflows buffer", child_length);
451
0
            goto remainder_raw;
452
0
          }
453
0
        }
454
455
0
        if (child->flags.array) {
456
0
          slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value);
457
0
        } else {
458
0
          slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx);
459
0
        }
460
0
        break;
461
462
0
      default:
463
0
        FR_PROTO_TRACE("Unknown data type %s in child %s", fr_type_to_str(child->type), child->name);
464
0
        goto unknown_child;
465
2.88k
      }
466
467
2.88k
      if (slen <= 0) {
468
289
        FR_PROTO_TRACE("failed decoding child %s", child->name);
469
289
        goto unknown_child;
470
289
      }
471
2.59k
      p += slen;
472
2.59k
    }
473
474
4.48k
    fr_dict_attr_unknown_free(&child);
475
4.48k
  }
476
477
71.6k
done:
478
71.6k
  fr_assert(struct_vp != NULL);
479
71.6k
  fr_pair_append(out, struct_vp);
480
481
71.6k
  FR_PROTO_TRACE("used %zu bytes", data_len);
482
71.6k
  return p - data;
483
66.9k
}
484
485
486
/** Put bits into an output dbuff
487
 *
488
 * @param dbuff   where the bytes go
489
 * @param p   where leftover bits go
490
 * @param start_bit start bit in the dbuff where the data goes, 0..7
491
 * @param num_bits  number of bits to write to the output, 0..55
492
 * @param data    data to write, all in the lower "num_bits" of the uint64_t variable
493
 * @return
494
 *  >= 0  the next value to pass in for start_bit
495
 *  <  0  no space or invalid start_bit or num_bits parameter
496
 */
497
static int put_bits_dbuff(fr_dbuff_t *dbuff, uint8_t *p, int start_bit, uint8_t num_bits, uint64_t data)
498
0
{
499
0
  uint64_t  used_bits;
500
501
0
  if (start_bit < 0 || start_bit > 7) return -1;
502
0
  if (num_bits < 1 || num_bits > 56) return -1;
503
504
  /* Get bits buffered in *p */
505
0
  used_bits = *p & (-256 >> start_bit);
506
507
  /* Mask out all but the least significant num_bits bits of data */
508
0
  data &= (((uint64_t) 1) << num_bits) - 1;
509
510
  /* Move it towards the most significant end and put used_bits at the top */
511
0
  data <<= (64 - (start_bit + num_bits));
512
0
  data |= used_bits << 56;
513
514
0
  data = htonll(data);
515
516
0
  start_bit += num_bits;
517
0
  if (start_bit > 7) FR_DBUFF_IN_MEMCPY_RETURN(dbuff, (uint8_t const *) &data, (size_t)(start_bit / 8));
518
519
0
  *p = ((uint8_t *) &data)[start_bit / 8];
520
0
  return start_bit % 8;
521
0
}
522
523
static int8_t pair_sort_increasing(void const *a, void const *b)
524
0
{
525
0
  fr_pair_t const *my_a = a;
526
0
  fr_pair_t const *my_b = b;
527
0
  int8_t ret;
528
529
  /*
530
   *  Deeper attributes come later in the list.
531
   */
532
0
  ret = CMP_PREFER_SMALLER(my_a->da->depth, my_b->da->depth);
533
0
  if (ret != 0) return ret;
534
535
0
  return CMP_PREFER_SMALLER(my_a->da->attr, my_b->da->attr);
536
0
}
537
538
static void *struct_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
539
0
{
540
0
  fr_pair_t *c = current;
541
0
  fr_dict_attr_t  *parent = talloc_get_type_abort(uctx, fr_dict_attr_t);
542
543
0
  while ((c = fr_dlist_next(cursor->dlist, c))) {
544
0
    PAIR_VERIFY(c);
545
546
0
    if (c->da->dict != parent->dict || c->da->flags.internal) continue;
547
0
    break;
548
0
  }
549
550
0
  return c;
551
0
}
552
553
static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_dict_attr_t const *tlv,
554
        fr_da_stack_t *da_stack, unsigned int depth,
555
        fr_dcursor_t *cursor, void *encode_ctx,
556
        UNUSED fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
557
558
0
{
559
0
  fr_pair_t *vp;
560
0
  fr_dcursor_t  child_cursor;
561
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
562
563
0
  if (!encode_pair) {
564
0
    fr_strerror_printf("Asked to encode child attribute %s, but we were not passed an encoding function",
565
0
           tlv->name);
566
0
    return PAIR_ENCODE_FATAL_ERROR;
567
0
  }
568
569
0
  vp = fr_dcursor_current(cursor);
570
0
  if (!vp || (vp->da != tlv)) return 0;
571
572
0
  vp = fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
573
0
  if (vp) {
574
0
    ssize_t slen;
575
576
0
    FR_PROTO_TRACE("fr_struct_to_network trailing TLVs of %s", tlv->name);
577
0
    fr_proto_da_stack_build(da_stack, vp->da);
578
0
    FR_PROTO_STACK_PRINT(da_stack, depth);
579
580
0
    slen = fr_pair_cursor_to_network(&work_dbuff, da_stack, depth + 1, &child_cursor, encode_ctx, encode_pair);
581
0
    if (slen < 0) return slen;
582
0
  }
583
584
0
  return fr_dbuff_set(dbuff, &work_dbuff);
585
0
}
586
587
static ssize_t encode_union(fr_dbuff_t *dbuff, fr_dict_attr_t const *wrapper,
588
          fr_dict_attr_t const *key_da, fr_pair_t const *key_vp, fr_dbuff_marker_t *key_m,
589
          fr_da_stack_t *da_stack, unsigned int depth,
590
          fr_dcursor_t *cursor, void *encode_ctx,
591
          UNUSED fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
592
593
0
{
594
0
  ssize_t   slen;
595
0
  fr_pair_t *parent, *child, *found = NULL;
596
0
  fr_dict_attr_t const *child_ref;
597
0
  fr_dcursor_t  child_cursor;
598
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
599
600
0
  parent = fr_dcursor_current(cursor);
601
0
  if (!parent || (parent->da != wrapper)) return 0;
602
603
0
  fr_assert(key_vp); /* @todo */
604
605
0
  child = fr_pair_dcursor_init(&child_cursor, &parent->vp_group);
606
0
  if (!child) {
607
    /*
608
     *  @todo - do we want to skip encoding the entire parent structure?
609
     */
610
0
    FR_PROTO_TRACE("fr_struct_to_network union %s has no children", key_da->name);
611
0
    return 0;
612
0
  }
613
614
  /*
615
   *  There's a key VP, we find the matching child struct, and then set the cursor to encode just
616
   *  that child.
617
   */
618
0
  if (key_vp) {
619
0
    fr_dict_enum_value_t const *enumv;
620
621
0
    enumv = fr_dict_enum_by_value(key_da, &key_vp->data);
622
0
    if (enumv && ((child_ref = fr_dict_enum_attr_ref(enumv)) != NULL)) {
623
0
      found = fr_pair_find_by_da(&parent->vp_group, NULL, child_ref);
624
0
      if (found) {
625
0
        (void) fr_dcursor_set_current(&child_cursor, found);
626
0
      }
627
0
    }
628
0
  }
629
630
  /*
631
   *  @todo - encode the key field based on the attribute number?
632
   *
633
   *  However, we are likely better off just not doing that.
634
   *  Which allows us to have the key and UNION contents
635
   *  disagree.
636
   */
637
0
  if (!found && child->da->flags.is_unknown) {
638
0
    fr_assert(child->da->type == FR_TYPE_OCTETS);
639
640
0
    goto encode;
641
0
  }
642
643
  /*
644
   *  No child matching the key vp was found.  Either there's no key_vp, or the key_vp doesn't match
645
   *  the chld we have.
646
   *
647
   *  We then update the key field so that it corresponds to the child that we found.
648
   */
649
0
  if (!found) {
650
0
    fr_dict_enum_value_t const *enumv;
651
0
    fr_dict_enum_iter_t iter;
652
0
    fr_dbuff_t key_dbuff;
653
654
    /*
655
     *  Root through the enum values, looking for a child ref which matches the child we
656
     *  found.
657
     */
658
0
    for (enumv = fr_dict_enum_iter_init(key_da, &iter);
659
0
         enumv != NULL;
660
0
         enumv = fr_dict_enum_iter_next(key_da, &iter)) {
661
0
      child_ref = fr_dict_enum_attr_ref(enumv);
662
0
      if (!child_ref) continue;
663
664
0
      if (child_ref == child->da) break;
665
0
    }
666
667
    /*
668
     *  There's a child, but no matching enum.  That's a fatal error of the dictionary
669
     *  tokenizer.
670
     */
671
0
    if (!fr_cond_assert(enumv)) return PAIR_ENCODE_FATAL_ERROR;
672
673
    /*
674
     *  Create a dbuff for the key, and encode the key.
675
     *
676
     *  Note that enumv->value->vb_length is NOT set. That field is really only used for
677
     *  string / octet data types.
678
     */
679
0
    fr_assert(key_da->flags.length >= 1);
680
0
    fr_assert(key_da->flags.length <= 4);
681
682
0
    FR_DBUFF_INIT(&key_dbuff, fr_dbuff_current(key_m), (size_t) key_da->flags.length);
683
684
0
    FR_PROTO_TRACE("fr_struct_to_network union %s encoding key %s for child %s",
685
0
             parent->da->name, key_da->name, child->da->name);
686
687
0
    if (fr_value_box_to_network(&key_dbuff, enumv->value) <= 0) return PAIR_ENCODE_FATAL_ERROR;
688
0
  }
689
690
  /*
691
   *  And finally encode the one child.
692
   */
693
0
encode:
694
0
  FR_PROTO_TRACE("fr_struct_to_network union %s encoding child %s", parent->da->name, child->da->name);
695
0
  fr_proto_da_stack_build(da_stack, child->da);
696
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
697
698
0
  switch (child->da->type) {
699
0
  case FR_TYPE_STRUCT:
700
0
    slen = fr_struct_to_network(&work_dbuff, da_stack, depth + 2,
701
0
              &child_cursor, encode_ctx, encode_value, encode_pair);
702
0
    break;
703
704
0
  case FR_TYPE_TLV:
705
0
    slen = encode_tlv(&work_dbuff, child->da, da_stack, depth + 2, &child_cursor, encode_ctx, encode_value, encode_pair);
706
0
    break;
707
708
0
  case FR_TYPE_LEAF:
709
0
    slen = encode_value(&work_dbuff, da_stack, depth + 2, &child_cursor, encode_ctx);
710
0
    break;
711
712
0
  default:
713
0
    slen = 0;
714
0
    break;
715
0
  }
716
717
0
  if (slen < 0) return slen;
718
719
  /*
720
   *  @todo - if there is more than one child of the union, that's an error!
721
   */
722
723
0
  return fr_dbuff_set(dbuff, &work_dbuff);
724
0
}
725
726
static ssize_t encode_keyed_struct(fr_dbuff_t *dbuff, fr_pair_t const *vp,
727
           fr_da_stack_t *da_stack, unsigned int depth,
728
           fr_dcursor_t *cursor, void *encode_ctx,
729
           fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
730
0
{
731
0
  FR_PROTO_TRACE("fr_struct_to_network encoding key %s", vp->da->name);
732
733
  /*
734
   *  We usually have a keyed struct for the child.
735
   */
736
0
  if (vp->vp_type == FR_TYPE_STRUCT) {
737
0
    fr_proto_da_stack_build(da_stack, vp->da);
738
0
    return fr_struct_to_network(dbuff, da_stack, depth + 2, /* note + 2 !!! */
739
0
              cursor, encode_ctx, encode_value, encode_pair);
740
0
  }
741
742
  /*
743
   *  If it's not a real child, then it's a raw something.
744
   */
745
0
  fr_assert(vp->vp_type == FR_TYPE_OCTETS);
746
0
  fr_assert(vp->da->flags.is_unknown);
747
748
0
  if (fr_value_box_to_network(dbuff, &vp->data) <= 0) return PAIR_ENCODE_FATAL_ERROR;
749
0
  (void) fr_dcursor_next(cursor);
750
0
  return 0;
751
0
}
752
753
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff,
754
           fr_da_stack_t *da_stack, unsigned int depth,
755
           fr_dcursor_t *parent_cursor, void *encode_ctx,
756
           fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
757
0
{
758
0
  fr_dbuff_t    work_dbuff;
759
0
  fr_dbuff_marker_t hdr;
760
0
  int     offset = 0;
761
0
  unsigned int    child_num;
762
0
  bool      do_length = false;
763
0
  uint8_t     bit_buffer = 0;
764
0
  fr_pair_t const   *vp = fr_dcursor_current(parent_cursor);
765
0
  fr_pair_t const   *last = NULL;
766
0
  fr_pair_t const   *key_vp = NULL;
767
0
  fr_dict_attr_t const    *child, *parent, *key_da = NULL;
768
0
  fr_dcursor_t    child_cursor, *cursor;
769
0
  size_t      prefix_length = 0;
770
0
  ssize_t     slen;
771
0
  fr_dbuff_marker_t key_m;
772
773
0
  if (!vp) {
774
0
    fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
775
0
    return PAIR_ENCODE_FATAL_ERROR;
776
0
  }
777
778
0
  PAIR_VERIFY(vp);
779
0
  parent = da_stack->da[depth];
780
781
0
  if (parent->type != FR_TYPE_STRUCT) {
782
0
    fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
783
0
           fr_type_to_str(parent->type));
784
0
    return PAIR_ENCODE_FATAL_ERROR;
785
0
  }
786
787
  /*
788
   *  If we get passed a struct VP, sort its children.
789
   */
790
0
  if (vp->vp_type == FR_TYPE_STRUCT) {
791
0
    fr_pair_t *sorted = fr_dcursor_current(parent_cursor); /* NOT const */
792
793
0
    fr_pair_list_sort(&sorted->vp_group, pair_sort_increasing);
794
0
    fr_pair_dcursor_iter_init(&child_cursor, &sorted->vp_group, struct_next_encodable, parent);
795
796
    /*
797
     *  Build the da_stack for the new structure.
798
     */
799
0
    vp = fr_dcursor_current(&child_cursor);
800
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
801
802
0
    FR_PROTO_TRACE("fr_struct_to_network encoding nested with parent %s", parent->name);
803
0
    cursor = &child_cursor;
804
0
  } else {
805
0
    FR_PROTO_TRACE("fr_struct_to_network encoding flat");
806
0
    cursor = parent_cursor;
807
0
  }
808
809
  /*
810
   *  @todo - if we get a child which *eventually* has the
811
   *  given parent, then allow encoding of that struct, too.
812
   *  This allows us to encode structures automatically,
813
   *  even if key fields are omitted.
814
   *
815
   *  Note that this check catches TLVs which are "flat" and
816
   *  not nested.  We could fix that by adding a special
817
   *  case, but it's better to just fix everything to handle
818
   *  nested attributes.
819
   */
820
0
  if (vp && (vp->da->parent != parent)) {
821
0
    fr_strerror_printf("%s: Asked to encode %s, but its parent %s is not the expected parent %s",
822
0
           __FUNCTION__, vp->da->name, vp->da->parent->name, parent->name);
823
0
    return PAIR_ENCODE_FATAL_ERROR;
824
0
  }
825
826
  /*
827
   *  Some structs are prefixed by a 16-bit length.
828
   */
829
0
  if (!da_is_length_field(parent)) {
830
0
    work_dbuff = FR_DBUFF(dbuff);
831
832
0
  } else if (da_is_length_field8(parent)) {
833
0
    work_dbuff = FR_DBUFF_MAX(dbuff, UINT8_MAX);
834
0
    fr_dbuff_marker(&hdr, &work_dbuff);
835
836
0
    FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 1);
837
0
    prefix_length = 1;
838
0
    do_length = true;
839
840
0
  } else {
841
0
    fr_assert(da_is_length_field16(parent));
842
843
0
    work_dbuff = FR_DBUFF_MAX(dbuff, UINT16_MAX);
844
0
    fr_dbuff_marker(&hdr, &work_dbuff);
845
846
0
    FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 2);
847
0
    prefix_length = 2;
848
0
    do_length = true;
849
0
  }
850
851
0
  if (!encode_value) encode_value = fr_pair_encode_value;
852
853
  /*
854
   *  Loop over all children.
855
   */
856
0
  for (child_num = 1;
857
0
       (child = fr_dict_attr_child_by_num(parent, child_num)) != NULL;
858
0
       child_num++) {
859
    /*
860
     *  The child attributes should be in order.  If
861
     *  they're not, we fill the struct with zeroes.
862
     *
863
     *  The caller will encode TLVs.
864
     */
865
0
    FR_PROTO_TRACE("fr_struct_to_network child %s", child->name);
866
867
    /*
868
     *  If the caller specifies a member twice, then we only encode the first member.
869
     */
870
0
    while (last && vp && (last->da->parent == vp->da->parent) && (last->da->attr == vp->da->attr)) {
871
0
      fr_assert(last != vp);
872
0
      vp = fr_dcursor_next(cursor);
873
0
    }
874
0
    last = vp;
875
876
    /*
877
     *  The MEMBER may be raw, in which case it is encoded as octets.
878
     *
879
     *  This can happen for the last MEMBER of a struct, such as when the last member is a TLV
880
     *  or GROUP, and the contents are malformed.
881
     *
882
     *  It can also happen if a middle MEMBER has the right length, but the wrong contents.
883
     *  e.g. when the contents have to be a well-formed IP prefix, but the prefix values are
884
     *  out of the permitted range.
885
     */
886
0
    if (vp && (vp->da != child) && (vp->da->parent == parent) && (vp->da->attr == child_num)) {
887
0
      fr_assert(vp->vp_raw);
888
0
      fr_assert(vp->vp_type == FR_TYPE_OCTETS);
889
0
      fr_assert(!da_is_bit_field(child));
890
891
0
      goto encode_data; /* we may have a raw entry in an array :( */
892
0
    }
893
894
    /*
895
     *  Remember the key field.  Note that we ignore raw key fields.
896
     */
897
0
    if (fr_dict_attr_is_key_field(child)) {
898
0
      fr_assert(!key_da);
899
900
0
      key_da = child;
901
0
      key_vp = vp;
902
0
      fr_dbuff_marker(&key_m, &work_dbuff);
903
0
    }
904
905
    /*
906
     *  Skipped a VP, or left one off at the end, fill the struct with zeros.
907
     */
908
0
    if (!vp || (vp->da != child)) {
909
0
      FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "    no child %s", child->name);
910
911
      /*
912
       *  Zero out the bit field.
913
       */
914
0
      if (da_is_bit_field(child)) {
915
0
        offset = put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, 0);
916
0
        if (offset < 0) {
917
0
          fr_strerror_printf("Failed encoding bit field %s", child->name);
918
0
          return offset;
919
0
        }
920
0
        last = NULL;
921
0
        continue;
922
0
      }
923
924
      /*
925
       *  A child TLV is missing, we're done, and we don't encode any data.
926
       *
927
       *  @todo - mark up the TLVs as required?
928
       */
929
0
      if (child->type == FR_TYPE_TLV) goto encode_length;
930
931
      /*
932
       *  Zero out the unused field.
933
       */
934
0
      FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, child->flags.length);
935
936
      /*
937
       *  We didn't encode the current VP, so it's not the last one.
938
       */
939
0
      last = NULL;
940
0
      continue;
941
0
    }
942
943
    /*
944
     *  The 'struct' encoder handles bit fields.
945
     *  They're just integers, so there's no need to
946
     *  call the protocol encoder.
947
     *
948
     *  This limitation means that we can't have
949
     *  encrypted bit fields, but that's fine.
950
     */
951
0
    if (da_is_bit_field(child)) {
952
0
      uint64_t value;
953
954
0
      FR_PROTO_TRACE("child %s is a bit field", child->name);
955
956
0
      switch (child->type) {
957
0
        case FR_TYPE_BOOL:
958
0
          value = vp->vp_bool;
959
0
          break;
960
961
0
        case FR_TYPE_UINT8:
962
0
          value = vp->vp_uint8;
963
0
          break;
964
965
0
        case FR_TYPE_UINT16:
966
0
          value = vp->vp_uint16;
967
0
          break;
968
969
0
        case FR_TYPE_UINT32:
970
0
          value = vp->vp_uint32;
971
0
          break;
972
973
0
        case FR_TYPE_UINT64:
974
0
          value = vp->vp_uint64;
975
0
          break;
976
977
0
        default:
978
0
          fr_strerror_const("Invalid bit field");
979
0
          return PAIR_ENCODE_FATAL_ERROR;
980
0
      }
981
982
0
      offset = put_bits_dbuff(&work_dbuff, &bit_buffer, offset, child->flags.length, value);
983
0
      if (offset < 0) {
984
0
        fr_strerror_printf("Failed encoding bit field %s", child->name);
985
0
        return offset;
986
0
      }
987
988
      /*
989
       *  We have to go to the next pair manually, as the protocol-specific
990
       *  encode_value() function will normally go to the next cursor entry.
991
       */
992
0
      vp = fr_dcursor_next(cursor);
993
      /* We need to continue, there may be more fields to encode */
994
995
0
      goto next;
996
0
    }
997
998
    /* Not a bit field; insist that no buffered bits remain. */
999
0
    if (offset != 0) {
1000
0
    leftover_bits:
1001
0
      fr_strerror_const("leftover bits");
1002
0
      return PAIR_ENCODE_FATAL_ERROR;
1003
0
    }
1004
1005
    /*
1006
     *  Encode child TLVs at the end of a struct.
1007
     *
1008
     *  In order to encode the child TLVs, we need to
1009
     *  know the length of "T" and "L", and we don't.
1010
     *  So just let the caller do the work.
1011
     */
1012
0
    if (child->type == FR_TYPE_TLV) {
1013
0
      fr_assert(!key_da);
1014
1015
0
      FR_PROTO_TRACE("child %s is a TLV field", child->name);
1016
0
      slen = encode_tlv(&work_dbuff, child, da_stack, depth, cursor,
1017
0
            encode_ctx, encode_value, encode_pair);
1018
0
      if (slen < 0) return slen;
1019
0
      goto encode_length;
1020
0
    }
1021
1022
0
    if (child->type == FR_TYPE_UNION) {
1023
0
      FR_PROTO_TRACE("child %s is a UNION field", child->name);
1024
1025
0
      if (!key_da) {
1026
0
        FR_PROTO_TRACE("structure %s is missing key_da", parent->name);
1027
0
        goto encode_length;
1028
0
      }
1029
1030
0
      slen = encode_union(&work_dbuff, child, key_da, key_vp, &key_m, da_stack, depth, cursor,
1031
0
              encode_ctx, encode_value, encode_pair);
1032
0
      if (slen < 0) return slen;
1033
0
      goto encode_length;
1034
0
    }
1035
1036
0
    FR_PROTO_TRACE("child %s encode_value", child->name);
1037
1038
    /*
1039
     *  Call the protocol encoder for non-bit fields.
1040
     */
1041
0
  encode_data:
1042
0
    fr_proto_da_stack_build(da_stack, child);
1043
1044
0
    if (child->flags.array) {
1045
0
      slen = fr_pair_array_to_network(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx, encode_value);
1046
0
    } else {
1047
0
      slen = encode_value(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
1048
0
    }
1049
0
    if (slen < 0) return slen;
1050
0
    vp = fr_dcursor_current(cursor);
1051
1052
0
  next:
1053
0
    FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "fr_struct_to_network after child %s", child->name);
1054
0
  }
1055
1056
  /* Check for leftover bits */
1057
0
  if (offset != 0) goto leftover_bits;
1058
1059
  /*
1060
   *  Check for keyed data to encode.
1061
   */
1062
0
  if (vp && key_da) {
1063
0
    fr_assert((vp->da->parent->type == FR_TYPE_UNION) || (vp->da->parent == key_da) || vp->da->flags.is_unknown || vp->da->flags.is_raw);
1064
1065
0
    slen = encode_keyed_struct(&work_dbuff, vp, da_stack, depth,
1066
0
             cursor, encode_ctx, encode_value, encode_pair);
1067
0
    if (slen < 0) return slen;
1068
0
  }
1069
1070
0
encode_length:
1071
0
  if (do_length) {
1072
0
    size_t length = fr_dbuff_used(&work_dbuff);
1073
1074
#ifdef __COVERITY__
1075
    /*
1076
     *  Coverity somehow can't infer that length
1077
     *  is at least as long as the prefix, instead
1078
     *  thinkings it's zero so that it underflows.
1079
     *  We therefore add a Coverity-only check to
1080
     *  reassure it.
1081
     */
1082
    if (length < prefix_length) return PAIR_ENCODE_FATAL_ERROR;
1083
#endif
1084
0
    if (da_is_length_field8(parent)) {
1085
0
      length -= prefix_length;
1086
1087
0
      length += da_length_offset(parent);
1088
1089
0
      if (length > UINT8_MAX) return PAIR_ENCODE_FATAL_ERROR;
1090
1091
0
      (void) fr_dbuff_in(&hdr, (uint8_t) length);
1092
0
    } else {
1093
0
      length -= prefix_length;
1094
1095
0
      length += da_length_offset(parent);
1096
1097
0
      if (length > UINT16_MAX) return PAIR_ENCODE_FATAL_ERROR;
1098
1099
0
      (void) fr_dbuff_in(&hdr, (uint16_t) length);
1100
0
    }
1101
0
  }
1102
1103
  /*
1104
   *  We've encoded the children, so tell the parent cursor
1105
   *  that we've encoded the parent.
1106
   */
1107
0
  if (cursor != parent_cursor) (void) fr_dcursor_next(parent_cursor);
1108
1109
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done fr_struct_to_network");
1110
1111
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1112
0
}