Coverage Report

Created: 2026-09-28 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/protocols/radius/encode.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: 96b0cee145325d295a99edb6c65d144f67c3155a $
19
 *
20
 * @file protocols/radius/encode.c
21
 * @brief Functions to encode RADIUS attributes
22
 *
23
 * @copyright 2000-2003,2006-2015 The FreeRADIUS server project
24
 */
25
#include "protocols/radius/radius.h"
26
RCSID("$Id: 96b0cee145325d295a99edb6c65d144f67c3155a $")
27
28
#include <freeradius-devel/util/dbuff.h>
29
#include <freeradius-devel/util/md5.h>
30
#include <freeradius-devel/util/struct.h>
31
#include <freeradius-devel/io/test_point.h>
32
#include <freeradius-devel/protocol/radius/freeradius.internal.h>
33
#include "attrs.h"
34
35
0
#define TAG_VALID(x)    ((x) > 0 && (x) < 0x20)
36
37
static const bool allow_tunnel_passwords[FR_RADIUS_CODE_MAX] = {
38
  [ 0 ] = true,   /* only for testing */
39
  [ FR_RADIUS_CODE_ACCESS_ACCEPT ] = true,
40
  [ FR_RADIUS_CODE_COA_REQUEST ] = true,
41
};
42
43
44
static ssize_t encode_value(fr_dbuff_t *dbuff,
45
          fr_da_stack_t *da_stack, unsigned int depth,
46
          fr_dcursor_t *cursor, void *encode_ctx);
47
48
static ssize_t encode_child(fr_dbuff_t *dbuff,
49
          fr_da_stack_t *da_stack, unsigned int depth,
50
          fr_dcursor_t *cursor, void *encode_ctx);
51
52
/** "encrypt" a password RADIUS style
53
 *
54
 * Input and output buffers can be identical if in-place encryption is needed.
55
 */
56
static ssize_t encode_password(fr_dbuff_t *dbuff, fr_dbuff_marker_t *input, size_t inlen, fr_radius_encode_ctx_t *packet_ctx)
57
0
{
58
0
  fr_md5_ctx_t  *md5_ctx, *md5_ctx_old;
59
0
  uint8_t digest[RADIUS_AUTH_VECTOR_LENGTH];
60
0
  uint8_t passwd[256] = {0};
61
0
  size_t    i, n;
62
0
  size_t    len;
63
64
0
  if (!packet_ctx->request_authenticator) {
65
0
    fr_strerror_const("Request Authenticator is required to encode User-Password attributes");
66
0
    return -1;
67
0
  }
68
69
  /*
70
   *  If the length is zero, round it up.
71
   */
72
0
  len = inlen;
73
74
0
  if (len > RADIUS_MAX_STRING_LENGTH) {
75
0
    fr_strerror_const("User-Password is too long (253 octets max)");
76
0
    return -1;
77
0
  }
78
79
0
  (void) fr_dbuff_out_memcpy(passwd, input, len);
80
0
  if (len < sizeof(passwd)) memset(passwd + len, 0, sizeof(passwd) - len);
81
82
0
  if (len == 0) len = AUTH_PASS_LEN;
83
0
  else if ((len & 0x0f) != 0) {
84
0
    len += 0x0f;
85
0
    len &= ~0x0f;
86
0
  }
87
88
0
  md5_ctx = fr_md5_ctx_alloc_from_list();
89
0
  md5_ctx_old = fr_md5_ctx_alloc_from_list();
90
91
0
  fr_md5_update(md5_ctx, (uint8_t const *) packet_ctx->common->secret, packet_ctx->common->secret_length);
92
0
  fr_md5_ctx_copy(md5_ctx_old, md5_ctx);
93
94
  /*
95
   *  Do first pass.
96
   */
97
0
  fr_md5_update(md5_ctx, packet_ctx->request_authenticator, AUTH_PASS_LEN);
98
99
0
  for (n = 0; n < len; n += AUTH_PASS_LEN) {
100
0
    if (n > 0) {
101
0
      fr_md5_ctx_copy(md5_ctx, md5_ctx_old);
102
0
      fr_md5_update(md5_ctx, passwd + n - AUTH_PASS_LEN, AUTH_PASS_LEN);
103
0
    }
104
105
0
    fr_md5_final(digest, md5_ctx);
106
0
    for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i + n] ^= digest[i];
107
0
  }
108
109
0
  fr_md5_ctx_free_from_list(&md5_ctx);
110
0
  fr_md5_ctx_free_from_list(&md5_ctx_old);
111
112
0
  return fr_dbuff_in_memcpy(dbuff, passwd, len);
113
0
}
114
115
116
static ssize_t encode_tunnel_password(fr_dbuff_t *dbuff, fr_dbuff_marker_t *in, size_t inlen, fr_radius_encode_ctx_t *packet_ctx)
117
0
{
118
0
  fr_md5_ctx_t  *md5_ctx, *md5_ctx_old;
119
0
  uint8_t   digest[RADIUS_AUTH_VECTOR_LENGTH];
120
0
  uint8_t   tpasswd[RADIUS_MAX_STRING_LENGTH];
121
0
  size_t    i, n;
122
0
  uint32_t  r;
123
0
  size_t    output_len, encrypted_len, padding;
124
0
  ssize_t   slen;
125
0
  fr_dbuff_t  work_dbuff = FR_DBUFF_MAX(dbuff, RADIUS_MAX_STRING_LENGTH);
126
127
0
  if (!packet_ctx->request_authenticator) {
128
0
    fr_strerror_const("Request Authenticator is required to encode Tunnel-Password attributes");
129
0
    return -1;
130
0
  }
131
132
  /*
133
   *  Limit the maximum size of the input password.  2 bytes
134
   *  are taken up by the salt, and one by the encoded
135
   *  "length" field.
136
   */
137
0
  if (inlen > (RADIUS_MAX_STRING_LENGTH - 3)) {
138
0
  fail:
139
0
    fr_strerror_const("Input password is too large for tunnel password encoding");
140
0
    return -(inlen + 3);
141
0
  }
142
143
  /*
144
   *  Length of the encrypted data is the clear-text
145
   *  password length plus one byte which encodes the length
146
   *  of the password.  We round up to the nearest encoding
147
   *  block, and bound it by the size of the output buffer,
148
   *  while accounting for 2 bytes of salt.
149
   *
150
   *  And also ensuring that we don't truncate the input
151
   *  password.
152
   */
153
0
  encrypted_len = ROUND_UP(inlen + 1, 16);
154
0
  if (encrypted_len > (RADIUS_MAX_STRING_LENGTH - 2)) encrypted_len = (RADIUS_MAX_STRING_LENGTH - 2);
155
156
  /*
157
   *  Get the number of padding bytes in the last block.
158
   */
159
0
  padding = encrypted_len - (inlen + 1);
160
161
0
  output_len = encrypted_len + 2; /* account for the salt */
162
163
  /*
164
   *  We will have up to 253 octets of data in the output
165
   *  buffer, some of which are padding.
166
   *
167
   *  If we over-run the output buffer, see if we can drop
168
   *  some of the padding bytes.  If not, we return an error
169
   *  instead of truncating the password.
170
   *
171
   *  Otherwise we lower the amount of data we copy into the
172
   *  output buffer, because the last bit is just padding,
173
   *  and can be safely discarded.
174
   */
175
0
  slen = fr_dbuff_set(&work_dbuff, output_len);
176
0
  if (slen < 0) {
177
0
    if (((size_t) -slen) > padding) goto fail;
178
179
0
    output_len += slen;
180
0
  }
181
0
  fr_dbuff_set_to_start(&work_dbuff);
182
183
  /*
184
   *  Copy the password over, and fill the remainder with random data.
185
   */
186
0
  (void) fr_dbuff_out_memcpy(tpasswd + 3, in, inlen);
187
188
0
  for (i = 3 + inlen; i < sizeof(tpasswd); i++) {
189
0
    tpasswd[i] = fr_fast_rand(&packet_ctx->rand_ctx);
190
0
  }
191
192
  /*
193
   *  Generate salt.  The RFCs say:
194
   *
195
   *  The high bit of salt[0] must be set, each salt in a
196
   *  packet should be unique, and they should be random
197
   *
198
   *  So we get 15 bytes of randomness, and set the high bit.
199
   */
200
0
  r = fr_fast_rand(&packet_ctx->rand_ctx);
201
0
  tpasswd[0] = (0x80 | ((r >> 8) & 0x7f));
202
0
  tpasswd[1] = r & 0xff;
203
0
  tpasswd[2] = inlen; /* length of the password string */
204
205
0
  md5_ctx = fr_md5_ctx_alloc_from_list();
206
0
  md5_ctx_old = fr_md5_ctx_alloc_from_list();
207
208
0
  fr_md5_update(md5_ctx, (uint8_t const *) packet_ctx->common->secret, packet_ctx->common->secret_length);
209
0
  fr_md5_ctx_copy(md5_ctx_old, md5_ctx);
210
211
0
  fr_md5_update(md5_ctx, packet_ctx->request_authenticator, RADIUS_AUTH_VECTOR_LENGTH);
212
0
  fr_md5_update(md5_ctx, &tpasswd[0], 2);
213
214
  /*
215
   *  Do various hashing, and XOR the length+password with
216
   *  the output of the hash blocks.
217
   */
218
0
  for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
219
0
    size_t block_len;
220
221
0
    if (n > 0) {
222
0
      fr_md5_ctx_copy(md5_ctx, md5_ctx_old);
223
0
      fr_md5_update(md5_ctx, tpasswd + 2 + n - AUTH_PASS_LEN, AUTH_PASS_LEN);
224
0
    }
225
0
    fr_md5_final(digest, md5_ctx);
226
227
0
    block_len = encrypted_len - n;
228
0
    if (block_len > AUTH_PASS_LEN) block_len = AUTH_PASS_LEN;
229
230
0
    for (i = 0; i < block_len; i++) {
231
#ifdef __COVERITY__
232
    /*
233
     *  Coverity is not doing the calculations correctly - it doesn't see
234
     *  that setting block_len = encrypted_len - n puts a safe boundary
235
     *  on block_len so the access to tpasswd won't overflow.
236
     */
237
      if ((i + 2 + n) >= RADIUS_MAX_STRING_LENGTH) break;
238
#endif
239
0
      tpasswd[i + 2 + n] ^= digest[i];
240
0
    }
241
0
  }
242
243
0
  fr_md5_ctx_free_from_list(&md5_ctx);
244
0
  fr_md5_ctx_free_from_list(&md5_ctx_old);
245
246
0
  FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, tpasswd, output_len);
247
248
0
  return fr_dbuff_set(dbuff, &work_dbuff);
249
0
}
250
251
/*
252
 *  Encode the contents of an attribute of type TLV.
253
 */
254
static ssize_t encode_tlv(fr_dbuff_t *dbuff,
255
        fr_da_stack_t *da_stack, unsigned int depth,
256
        fr_dcursor_t *cursor, void *encode_ctx)
257
0
{
258
0
  ssize_t   slen;
259
0
  fr_pair_t const *vp = fr_dcursor_current(cursor);
260
0
  fr_dict_attr_t const  *da = da_stack->da[depth];
261
0
  fr_dbuff_t    work_dbuff = FR_DBUFF_MAX(dbuff, RADIUS_MAX_STRING_LENGTH);
262
263
0
  for (;;) {
264
0
    FR_PROTO_STACK_PRINT(da_stack, depth);
265
266
    /*
267
     *  This attribute carries sub-TLVs.  The sub-TLVs
268
     *  can only carry a total of 253 bytes of data.
269
     */
270
271
    /*
272
     *  Determine the nested type and call the appropriate encoder
273
     */
274
0
    if (!da_stack->da[depth + 1]) {
275
0
      fr_dcursor_t child_cursor;
276
277
0
      if (vp->da != da_stack->da[depth]) {
278
0
        fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
279
0
        return 0;
280
0
      }
281
282
0
      fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
283
0
      vp = fr_dcursor_current(&child_cursor);
284
0
      if (!vp) goto next;
285
286
0
      fr_proto_da_stack_build(da_stack, vp->da);
287
288
      /*
289
       *  Call ourselves recursively to encode children.
290
       */
291
0
      slen = encode_tlv(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
292
0
      if (slen < 0) return slen;
293
294
0
    next:
295
0
      vp = fr_dcursor_next(cursor);
296
0
      fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
297
298
0
    } else {
299
0
      slen = encode_child(&work_dbuff, da_stack, depth + 1, cursor, encode_ctx);
300
0
      if (slen < 0) return slen;
301
0
    }
302
303
    /*
304
     *  If nothing updated the attribute, stop
305
     */
306
0
    if (!fr_dcursor_current(cursor) || (vp == fr_dcursor_current(cursor))) break;
307
308
    /*
309
     *  We can encode multiple sub TLVs, if after
310
     *  rebuilding the TLV Stack, the attribute
311
     *  at this depth is the same.
312
     */
313
0
    if ((da != da_stack->da[depth]) || (da_stack->depth < da->depth)) break;
314
0
    vp = fr_dcursor_current(cursor);
315
0
  }
316
317
0
  return fr_dbuff_set(dbuff, &work_dbuff);
318
0
}
319
320
static ssize_t encode_pairs(fr_dbuff_t *dbuff, fr_pair_list_t const *vps, void *encode_ctx)
321
0
{
322
0
  ssize_t     slen;
323
0
  fr_pair_t const *vp;
324
0
  fr_dcursor_t    cursor;
325
326
  /*
327
   *  Note that we skip tags inside of tags!
328
   */
329
0
  fr_pair_dcursor_iter_init(&cursor, vps, fr_proto_next_encodable, dict_radius);
330
0
  while ((vp = fr_dcursor_current(&cursor))) {
331
0
    PAIR_VERIFY(vp);
332
333
    /*
334
     *  Encode an individual VP
335
     */
336
0
    slen = fr_radius_encode_pair(dbuff, &cursor, encode_ctx);
337
0
    if (slen < 0) return slen;
338
0
  }
339
340
0
  return fr_dbuff_used(dbuff);
341
0
}
342
343
344
/** Encodes the data portion of an attribute
345
 *
346
 * @return
347
 *  > 0, Length of the data portion.
348
 *      = 0, we could not encode anything, skip this attribute (and don't encode the header)
349
 *    unless it's one of a list of exceptions.
350
 *  < 0, How many additional bytes we'd need as a negative integer.
351
 *  PAIR_ENCODE_FATAL_ERROR - Abort encoding the packet.
352
 */
353
static ssize_t encode_value(fr_dbuff_t *dbuff,
354
          fr_da_stack_t *da_stack, unsigned int depth,
355
          fr_dcursor_t *cursor, void *encode_ctx)
356
0
{
357
0
  ssize_t       slen;
358
0
  size_t        len;
359
0
  fr_pair_t const     *vp = fr_dcursor_current(cursor);
360
0
  fr_dict_attr_t const    *da = da_stack->da[depth];
361
0
  fr_radius_encode_ctx_t    *packet_ctx = encode_ctx;
362
0
  fr_dbuff_t      work_dbuff = FR_DBUFF(dbuff);
363
0
  fr_dbuff_t      value_dbuff;
364
0
  fr_dbuff_marker_t   value_start, src, dest;
365
0
  bool        encrypted = false;
366
367
0
  PAIR_VERIFY(vp);
368
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
369
370
  /*
371
   *  TLVs are just another type of value.
372
   */
373
0
  if (da->type == FR_TYPE_TLV) return encode_tlv(dbuff, da_stack, depth, cursor, encode_ctx);
374
375
0
  if (da->type == FR_TYPE_GROUP) return fr_pair_ref_to_network(dbuff, da_stack, depth, cursor);
376
377
  /*
378
   *  Catch errors early on.
379
   */
380
0
  if (fr_radius_flag_encrypted(vp->da) && !packet_ctx) {
381
0
    fr_strerror_const("Asked to encrypt attribute, but no packet context provided");
382
0
    return PAIR_ENCODE_FATAL_ERROR;
383
0
  }
384
385
  /*
386
   *  This has special requirements.
387
   */
388
0
  if ((vp->vp_type == FR_TYPE_STRUCT) || (da->type == FR_TYPE_STRUCT)) {
389
0
    slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, encode_child);
390
0
    if (slen <= 0) return slen;
391
392
0
    vp = fr_dcursor_current(cursor);
393
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
394
0
    return fr_dbuff_set(dbuff, &work_dbuff);
395
0
  }
396
397
  /*
398
   *  If it's not a TLV, it should be a value type RFC
399
   *  attribute make sure that it is.
400
   */
401
0
  if (da_stack->da[depth + 1] != NULL) {
402
0
    fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
403
0
    return PAIR_ENCODE_FATAL_ERROR;
404
0
  }
405
406
0
  if (vp->da != da) {
407
0
    fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
408
0
    return PAIR_ENCODE_FATAL_ERROR;
409
0
  }
410
411
0
  if (fr_type_is_structural(da->type)) {
412
0
    fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
413
0
           fr_type_to_str(da_stack->da[depth]->type));
414
0
    return PAIR_ENCODE_FATAL_ERROR;
415
0
  }
416
417
  /*
418
   *  Write tag byte
419
   *
420
   *  The Tag field is one octet in length and is intended to provide a
421
   *  means of grouping attributes in the same packet which refer to the
422
   *  same tunnel.  If the value of the Tag field is greater than 0x00
423
   *  and less than or equal to 0x1F, it SHOULD be interpreted as
424
   *  indicating which tunnel (of several alternatives) this attribute
425
   *  pertains.  If the Tag field is greater than 0x1F, it SHOULD be
426
   *  interpreted as the first byte of the following String field.
427
   *
428
   *  If the first byte of the string value looks like a
429
   *  tag, then we always encode a tag byte, even one that
430
   *  is zero.
431
   *
432
   *  And for Tunnel-Password, we always encode a tag byte.
433
   */
434
0
  if ((vp->vp_type == FR_TYPE_STRING) && fr_radius_flag_has_tag(vp->da)) {
435
0
    if (packet_ctx->tag) {
436
0
      FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t)packet_ctx->tag);
437
0
    } else if (TAG_VALID(vp->vp_strvalue[0]) ||
438
0
         (fr_radius_flag_encrypted(da) == RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD)) {
439
0
      FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t)0x00);
440
0
    }
441
0
  }
442
443
  /*
444
   * Starting here is a value that may require encryption.
445
   */
446
0
  value_dbuff = FR_DBUFF(&work_dbuff);
447
0
  fr_dbuff_marker(&value_start, &value_dbuff);
448
0
  fr_dbuff_marker(&src, &value_dbuff);
449
0
  fr_dbuff_marker(&dest, &value_dbuff);
450
451
0
  switch (vp->vp_type) {
452
    /*
453
     *  IPv4 addresses are normal, but IPv6 addresses are special to RADIUS.
454
     */
455
0
  case FR_TYPE_COMBO_IP_ADDR:
456
0
    if (vp->vp_ip.af == AF_INET) goto encode;
457
0
    FALL_THROUGH;
458
459
  /*
460
   *  Common encoder might add scope byte, which we don't want.
461
   */
462
0
  case FR_TYPE_IPV6_ADDR:
463
0
    FR_DBUFF_IN_MEMCPY_RETURN(&value_dbuff, vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
464
0
    break;
465
466
0
  case FR_TYPE_COMBO_IP_PREFIX:
467
0
    if (vp->vp_ip.af == AF_INET) goto ipv4_prefix;
468
0
    FALL_THROUGH;
469
470
  /*
471
   *  Common encoder doesn't add reserved byte
472
   */
473
0
  case FR_TYPE_IPV6_PREFIX:
474
0
    len = fr_bytes_from_bits(vp->vp_ip.prefix);
475
0
    FR_DBUFF_IN_BYTES_RETURN(&value_dbuff, 0x00, vp->vp_ip.prefix);
476
    /* Only copy the minimum number of address bytes required */
477
0
    FR_DBUFF_IN_MEMCPY_RETURN(&value_dbuff, (uint8_t const *)vp->vp_ipv6addr, len);
478
0
    break;
479
480
  /*
481
   *  Common encoder doesn't add reserved byte, so we add one here to be compliant with RFC 8044
482
   *  Section 3.11.
483
   */
484
0
  case FR_TYPE_IPV4_PREFIX:
485
0
  ipv4_prefix:
486
0
    if (!vp->vp_ipv4addr) {
487
      /*
488
       *  If the ipaddr is all zeros, then the prefix length MUST be set to 32.
489
       */
490
0
      FR_DBUFF_IN_BYTES_RETURN(&value_dbuff, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00);
491
0
    } else {
492
0
      uint32_t ipaddr = vp->vp_ipv4addr;
493
494
0
      FR_DBUFF_IN_BYTES_RETURN(&value_dbuff, 0x00, vp->vp_ip.prefix);
495
496
0
      if (vp->vp_ip.prefix == 0) {
497
0
        ipaddr = 0;
498
499
0
      } else if (vp->vp_ip.prefix < 32) {
500
0
        ipaddr &= htonl(~((1UL << (32 - vp->vp_ip.prefix)) - 1));
501
502
0
      } /* else leave ipaddr alone */
503
504
0
      FR_DBUFF_IN_MEMCPY_RETURN(&value_dbuff, (uint8_t const *) &ipaddr, sizeof(ipaddr));
505
0
    }
506
0
    break;
507
508
  /*
509
   *  Special handling for "abinary".  Otherwise, fall
510
   *  through to using the common encoder.
511
   */
512
0
  case FR_TYPE_STRING:
513
0
    if (fr_radius_flag_abinary(da)) {
514
0
      slen = fr_radius_encode_abinary(vp, &value_dbuff);
515
0
      if (slen < 0) return slen;
516
0
      break;
517
0
    }
518
0
    FALL_THROUGH;
519
520
0
  case FR_TYPE_OCTETS:
521
522
  /*
523
   *  Simple data types use the common encoder.
524
   */
525
0
  default:
526
0
  encode:
527
0
    slen = fr_value_box_to_network(&value_dbuff, &vp->data);
528
0
    if (slen < 0) return slen;
529
0
    break;
530
0
  }
531
532
  /*
533
   *  No data: don't encode the value.  The type and length should still
534
   *  be written.
535
   */
536
0
  if (fr_dbuff_used(&value_dbuff) == 0) {
537
0
  return_0:
538
0
    vp = fr_dcursor_next(cursor);
539
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
540
0
    return 0;
541
0
  }
542
543
  /*
544
   *  We don't encode encrypted attributes in foreign protocols.
545
   */
546
0
  if (packet_ctx->foreign && (fr_radius_flag_encrypted(da) != RADIUS_FLAG_ENCRYPT_NONE)) goto return_0;
547
548
  /*
549
   *  Encrypt the various password styles
550
   *
551
   *  Attributes with encrypted values MUST be less than
552
   *  128 bytes long.
553
   */
554
0
  switch (fr_radius_flag_encrypted(da)) {
555
0
  case RADIUS_FLAG_ENCRYPT_USER_PASSWORD:
556
    /*
557
     *  Encode the password in place
558
     */
559
0
    slen = encode_password(&work_dbuff, &value_start, fr_dbuff_used(&value_dbuff), packet_ctx);
560
0
    if (slen < 0) return slen;
561
0
    encrypted = true;
562
0
    break;
563
564
0
  case RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD:
565
0
    fr_assert(packet_ctx->code < FR_RADIUS_CODE_MAX);
566
0
    if (!allow_tunnel_passwords[packet_ctx->code]) {
567
0
      fr_strerror_printf("Attributes with 'encrypt=Tunnel-Password' set cannot go into %s.",
568
0
             fr_radius_packet_name[packet_ctx->code]);
569
0
      goto return_0;
570
0
    }
571
572
0
    slen = encode_tunnel_password(&work_dbuff, &value_start, fr_dbuff_used(&value_dbuff), packet_ctx);
573
0
    if (slen < 0) return slen;
574
575
0
    encrypted = true;
576
0
    break;
577
578
  /*
579
   *  The code above ensures that this attribute
580
   *  always fits.
581
   */
582
0
  case RADIUS_FLAG_ENCRYPT_ASCEND_SECRET:
583
    /*
584
     *  @todo radius decoding also uses fr_radius_ascend_secret() (Vernam cipher
585
     *  is its own inverse). As part of converting decode, make sure the caller
586
     *  there can pass a marker so we can use it here, too.
587
     */
588
0
    slen = fr_radius_ascend_secret(&work_dbuff, fr_dbuff_current(&value_start), fr_dbuff_used(&value_dbuff),
589
0
                 packet_ctx->common->secret, packet_ctx->common->secret_length,
590
0
                 packet_ctx->request_authenticator);
591
0
    if (slen < 0) return slen;
592
0
    encrypted = true;
593
0
    break;
594
595
0
  case RADIUS_FLAG_ENCRYPT_NONE:
596
0
    break;
597
598
0
  case RADIUS_FLAG_ENCRYPT_INVALID:
599
0
    fr_strerror_const("Invalid encryption type");
600
0
    return PAIR_ENCODE_FATAL_ERROR;
601
0
  }
602
603
0
  if (!encrypted) {
604
0
    fr_dbuff_set(&work_dbuff, &value_dbuff);
605
0
    fr_dbuff_set(&value_start, fr_dbuff_start(&value_dbuff));
606
0
  }
607
608
  /*
609
   *  High byte of 32bit integers gets set to the tag
610
   *  value.
611
   *
612
   *  The Tag field is one octet in length and is intended to provide a
613
   *  means of grouping attributes in the same packet which refer to the
614
   *  same tunnel.  Valid values for this field are 0x01 through 0x1F,
615
   *  inclusive.  If the Tag field is unused, it MUST be zero (0x00).
616
   */
617
0
  if ((vp->vp_type == FR_TYPE_UINT32) && fr_radius_flag_has_tag(vp->da)) {
618
0
    uint8_t msb = 0;
619
    /*
620
     *  Only 24bit integers are allowed here
621
     */
622
0
    fr_dbuff_set(&src,  &value_start);
623
0
    (void) fr_dbuff_out(&msb, &src);
624
0
    if (msb != 0) {
625
0
      fr_strerror_const("Integer overflow for tagged uint32 attribute");
626
0
      goto return_0;
627
0
    }
628
0
    fr_dbuff_set(&dest, &value_start);
629
0
    fr_dbuff_in(&dest, packet_ctx->tag);
630
0
  }
631
632
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "value %s",
633
0
        fr_type_to_str(vp->vp_type));
634
635
  /*
636
   *  Rebuilds the TLV stack for encoding the next attribute
637
   */
638
0
  vp = fr_dcursor_next(cursor);
639
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
640
641
0
  return fr_dbuff_set(dbuff, &work_dbuff);
642
0
}
643
644
/** Breaks down large data into pieces, each with a header
645
 *
646
 * @param[out] data   we're fragmenting.
647
 * @param[in] data_len    the amount of data in the dbuff that makes up the value we're
648
 *            splitting.
649
 * @param[in,out] hdr       marker that points at said header
650
 * @param[in] hdr_len   length of the headers that will be added
651
 * @param[in] flag_offset offset within header of a flag byte whose MSB is set for all
652
 *        but the last piece.
653
 * @param[in] vsa_offset  if non-zero, the offset of a length field in a (sub?)-header
654
 *        of size 3 that also needs to be adjusted to include the number
655
 *        of bytes of data in the piece
656
 * @return
657
 *      - <0 the number of bytes we would have needed to create
658
 *    space for another attribute header in the buffer.
659
 *  - 0 data was not modified.
660
 *      - >0 the number additional bytes we used inserting extra
661
 *        headers.
662
 */
663
static ssize_t attr_fragment(fr_dbuff_t *data, size_t data_len, fr_dbuff_marker_t *hdr, size_t hdr_len,
664
           int flag_offset, int vsa_offset)
665
0
{
666
0
  unsigned int    num_fragments, i = 0;
667
0
  size_t      max_frag_data = UINT8_MAX - hdr_len;
668
0
  fr_dbuff_t    frag_data = FR_DBUFF_ABS(hdr);
669
0
  fr_dbuff_marker_t frag_hdr, frag_hdr_p;
670
671
0
  if (unlikely(!data_len)) return 0; /* Shouldn't have been called */
672
673
0
  num_fragments = ROUND_UP_DIV(data_len, max_frag_data);
674
0
  if (num_fragments == 1) return 0; /* Nothing to do */
675
676
0
  fr_dbuff_marker(&frag_hdr, &frag_data);
677
0
  fr_dbuff_marker(&frag_hdr_p, &frag_data);
678
679
0
  fr_dbuff_advance(&frag_data, hdr_len);
680
681
0
  FR_PROTO_HEX_DUMP(fr_dbuff_current(hdr), hdr_len + data_len, "attr_fragment in");
682
0
  for (;;) {
683
0
    bool  last = (i + 1) == num_fragments;
684
0
    uint8_t frag_len;
685
686
    /*
687
     *  How long is this fragment?
688
     */
689
0
    if (last) {
690
0
      frag_len = (data_len - (max_frag_data * (num_fragments - 1)));
691
0
    } else {
692
0
      frag_len = max_frag_data;
693
0
    }
694
695
    /*
696
     *  Update the "outer" header to reflect the actual
697
     *  length of the fragment
698
     */
699
0
    fr_dbuff_set(&frag_hdr_p, &frag_hdr);
700
0
    fr_dbuff_advance(&frag_hdr_p, 1);
701
0
    fr_dbuff_in(&frag_hdr_p, (uint8_t)(hdr_len + frag_len));
702
703
    /*
704
     *  Update the "inner" header.  The length here is
705
     *  the inner VSA header length (3) + the fragment
706
     *  length.
707
     */
708
0
    if (vsa_offset) {
709
0
      fr_dbuff_set(&frag_hdr_p, fr_dbuff_current(&frag_hdr) + vsa_offset);
710
0
      fr_dbuff_in(&frag_hdr_p, (uint8_t)(3 + frag_len));
711
0
    }
712
713
    /*
714
     *  Just over-ride the flag field.  Nothing else
715
     *  uses it.
716
     */
717
0
    if (flag_offset) {
718
0
      fr_dbuff_set(&frag_hdr_p, fr_dbuff_current(&frag_hdr) + flag_offset);
719
0
      fr_dbuff_in(&frag_hdr_p, (uint8_t)(!last << 7));
720
0
    }
721
722
0
    FR_PROTO_HEX_DUMP(fr_dbuff_current(hdr), frag_len + hdr_len,
723
0
          "attr_fragment fragment %u/%u", i + 1, num_fragments);
724
725
0
    fr_dbuff_advance(&frag_data, frag_len); /* Go to the start of the next fragment */
726
0
    if (last) break;
727
728
    /*
729
     *  There's still trailing data after this
730
     *  fragment.  Move the trailing data to *past*
731
     *  the next header.  And after there's room, copy
732
     *  the header over.
733
     *
734
     *  This process leaves the next header in place,
735
     *  ready for the next iteration of the loop.
736
     *
737
     *  Yes, moving things multiple times is less than
738
     *  efficient.  Oh well.  it's ~1K memmoved()
739
     *  maybe 4 times.  We are nowhere near the CPU /
740
     *  electrical requirements of Bitcoin.
741
     */
742
0
    i++;
743
744
0
    fr_dbuff_set(&frag_hdr, &frag_data);    /* Remember where the header should be */
745
0
    fr_dbuff_advance(&frag_data, hdr_len);    /* Advance past the header */
746
747
    /*
748
     *  Shift remaining data by hdr_len.
749
     */
750
0
    FR_DBUFF_IN_MEMCPY_RETURN(&FR_DBUFF(&frag_data), &frag_hdr, data_len - (i * max_frag_data));
751
0
    fr_dbuff_in_memcpy(&FR_DBUFF(&frag_hdr), hdr, hdr_len); /* Copy the old header over */
752
0
  }
753
754
0
  return fr_dbuff_set(data, &frag_data);
755
0
}
756
757
/** Encode an "extended" attribute
758
 *
759
 */
760
static ssize_t encode_extended(fr_dbuff_t *dbuff,
761
           fr_da_stack_t *da_stack, NDEBUG_UNUSED unsigned int depth,
762
           fr_dcursor_t *cursor, void *encode_ctx)
763
0
{
764
0
  ssize_t     slen;
765
0
  uint8_t     hlen;
766
0
  size_t      vendor_hdr;
767
0
  bool      extra;
768
0
  int     my_depth;
769
0
  fr_dict_attr_t const  *da;
770
0
  fr_dbuff_marker_t hdr, length_field;
771
0
  fr_pair_t const   *vp = fr_dcursor_current(cursor);
772
0
  fr_dbuff_t    work_dbuff;
773
774
0
  PAIR_VERIFY(vp);
775
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
776
777
0
  extra = fr_radius_flag_long_extended(da_stack->da[0]);
778
779
  /*
780
   *  The data used here can be more than 255 bytes, but only for the
781
   *  "long" extended type.
782
   */
783
0
  if (extra) {
784
0
    work_dbuff = FR_DBUFF_BIND_CURRENT(dbuff);
785
0
  } else {
786
0
    work_dbuff = FR_DBUFF_MAX_BIND_CURRENT(dbuff, UINT8_MAX);
787
0
  }
788
0
  fr_dbuff_marker(&hdr, &work_dbuff);
789
790
  /*
791
   *  Encode the header for "short" or "long" attributes
792
   */
793
0
  hlen = 3 + extra;
794
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)da_stack->da[0]->attr);
795
0
  fr_dbuff_marker(&length_field, &work_dbuff);
796
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, hlen); /* this gets overwritten later*/
797
798
  /*
799
   *  Encode which extended attribute it is.
800
   */
801
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)da_stack->da[1]->attr);
802
803
0
  if (extra) FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00);  /* flags start off at zero */
804
805
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
806
807
  /*
808
   *  Handle VSA as "VENDOR + attr"
809
   */
810
0
  if (da_stack->da[1]->type == FR_TYPE_VSA) {
811
0
    fr_assert(da_stack->da[2]);
812
0
    fr_assert(da_stack->da[2]->type == FR_TYPE_VENDOR);
813
814
0
    FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t) da_stack->da[2]->attr);
815
816
0
    fr_assert(da_stack->da[3]);
817
818
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)da_stack->da[3]->attr);
819
820
0
    hlen += 5;
821
0
    vendor_hdr = 5;
822
823
0
    FR_PROTO_STACK_PRINT(da_stack, depth);
824
0
    FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr), hlen, "header extended vendor specific");
825
826
0
    my_depth = 3;
827
0
  } else {
828
0
    vendor_hdr = 0;
829
0
    FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr), hlen, "header extended");
830
831
0
    my_depth = 1;
832
0
  }
833
834
  /*
835
   *  We're at the point where we need to encode something.
836
   */
837
0
  da = da_stack->da[my_depth];
838
0
  fr_assert(vp->da == da);
839
840
0
  if (da->type != FR_TYPE_STRUCT) {
841
0
    slen = encode_value(&work_dbuff, da_stack, my_depth, cursor, encode_ctx);
842
843
0
  } else {
844
0
    slen = fr_struct_to_network(&work_dbuff, da_stack, my_depth, cursor, encode_ctx, encode_value, encode_child);
845
0
  }
846
0
  if (slen <= 0) return slen;
847
848
  /*
849
   *  There may be more than 255 octets of data encoded in
850
   *  the attribute.  If so, move the data up in the packet,
851
   *  and copy the existing header over.  Set the "M" flag ONLY
852
   *  after copying the rest of the data.
853
   *
854
   *  Note that we add "vendor_hdr" to the length of the
855
   *  encoded data.  That 5 octet field is logically part of
856
   *  the data, and not part of the header.
857
   */
858
0
  if (slen > (UINT8_MAX - hlen)) {
859
0
    slen = attr_fragment(&work_dbuff, (size_t)vendor_hdr + slen, &hdr, 4, 3, 0);
860
0
    if (slen <= 0) return slen;
861
862
0
    return fr_dbuff_set(dbuff, &work_dbuff);
863
0
  }
864
865
0
  fr_dbuff_in_bytes(&length_field, (uint8_t) fr_dbuff_used(&work_dbuff));
866
0
  FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr), hlen, "header extended");
867
868
0
  return fr_dbuff_set(dbuff, &work_dbuff);
869
0
}
870
871
/*
872
 *  The encode_extended() function expects to see the TLV or
873
 *  STRUCT inside of the extended attribute, in which case it
874
 *  creates the attribute header and calls encode_value() for the
875
 *  leaf type, or child TLV / struct.
876
 *
877
 *  If we see VSA or VENDOR, then we recurse past that to a child
878
 *  which is either a leaf, or a TLV, or a STRUCT.
879
 */
880
static ssize_t encode_extended_nested(fr_dbuff_t *dbuff,
881
              fr_da_stack_t *da_stack, unsigned int depth,
882
              fr_dcursor_t *cursor, void *encode_ctx)
883
0
{
884
0
  ssize_t     slen;
885
0
  fr_pair_t   *parent, *vp;
886
0
  fr_dcursor_t    child_cursor;
887
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
888
889
0
  parent = fr_dcursor_current(cursor);
890
0
  fr_assert(fr_type_is_structural(parent->vp_type));
891
892
0
  (void) fr_pair_dcursor_child_iter_init(&child_cursor, &parent->vp_group, cursor);
893
894
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
895
896
0
  while ((vp = fr_dcursor_current(&child_cursor)) != NULL) {
897
0
    if ((vp->vp_type == FR_TYPE_VSA) || (vp->vp_type == FR_TYPE_VENDOR)) {
898
0
      slen = encode_extended_nested(&work_dbuff, da_stack, depth + 1, &child_cursor, encode_ctx);
899
900
0
    } else {
901
0
      fr_proto_da_stack_build(da_stack, vp->da);
902
0
      slen = encode_extended(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
903
0
      if (slen < 0) return slen;
904
0
    }
905
906
0
    if (slen < 0) return slen;
907
0
  }
908
909
0
  vp = fr_dcursor_next(cursor);
910
911
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
912
913
0
  return fr_dbuff_set(dbuff, &work_dbuff);
914
0
}
915
916
917
/** Encode an RFC format attribute, with the "concat" flag set
918
 *
919
 * If there isn't enough freespace in the packet, the data is
920
 * truncated to fit.
921
 *
922
 * The attribute is split on 253 byte boundaries, with a header
923
 * prepended to each chunk.
924
 */
925
static ssize_t encode_concat(fr_dbuff_t *dbuff,
926
           fr_da_stack_t *da_stack, unsigned int depth,
927
           fr_dcursor_t *cursor, UNUSED void *encode_ctx)
928
0
{
929
0
  uint8_t const   *p;
930
0
  size_t      data_len;
931
0
  fr_pair_t const   *vp = fr_dcursor_current(cursor);
932
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
933
0
  fr_dbuff_marker_t hdr;
934
935
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
936
937
0
  p = vp->vp_octets;
938
0
  data_len = vp->vp_length;
939
0
  fr_dbuff_marker(&hdr, &work_dbuff);
940
941
0
  while (data_len > 0) {
942
0
    size_t frag_len = (data_len > RADIUS_MAX_STRING_LENGTH) ? RADIUS_MAX_STRING_LENGTH : data_len;
943
944
0
    fr_dbuff_set(&hdr, &work_dbuff);
945
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) da_stack->da[depth]->attr, 0x00);
946
947
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, p, frag_len);
948
949
0
    fr_dbuff_advance(&hdr, 1);
950
0
    fr_dbuff_in(&hdr, (uint8_t) (2 + frag_len));
951
952
0
    FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr) - 1, 2 + frag_len, "encode_concat fragment");
953
954
0
    p += frag_len;
955
0
    data_len -= frag_len;
956
0
  }
957
958
0
  vp = fr_dcursor_next(cursor);
959
960
  /*
961
   *  @fixme: attributes with 'concat' MUST of type
962
   *  'octets', and therefore CANNOT have any TLV data in them.
963
   */
964
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
965
966
0
  return fr_dbuff_set(dbuff, &work_dbuff);
967
0
}
968
969
/** Encode an RFC format attribute.
970
 *
971
 * This could be a standard attribute, or a TLV data type.
972
 * If it's a standard attribute, then vp->da->attr == attribute.
973
 * Otherwise, attribute may be something else.
974
 */
975
static ssize_t encode_child(fr_dbuff_t *dbuff,
976
         fr_da_stack_t *da_stack, unsigned int depth,
977
         fr_dcursor_t *cursor, void *encode_ctx)
978
0
{
979
0
  ssize_t     slen;
980
0
  uint8_t     hlen;
981
0
  fr_dbuff_marker_t hdr;
982
0
  fr_dbuff_t    work_dbuff = FR_DBUFF_MAX(dbuff, UINT8_MAX);
983
984
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
985
986
0
  fr_assert(da_stack->da[depth] != NULL);
987
988
0
  fr_dbuff_marker(&hdr, &work_dbuff);
989
990
0
  hlen = 2;
991
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)da_stack->da[depth]->attr, hlen);
992
993
0
  slen = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
994
0
  if (slen <= 0) return slen;
995
996
0
  fr_dbuff_advance(&hdr, 1);
997
0
  fr_dbuff_in_bytes(&hdr, (uint8_t)(hlen + slen));
998
999
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), 2, "header rfc");
1000
1001
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1002
0
}
1003
1004
1005
/** Encode one full Vendor-Specific + Vendor-ID + Vendor-Attr + Vendor-Length + ...
1006
 */
1007
static ssize_t encode_vendor_attr(fr_dbuff_t *dbuff,
1008
          fr_da_stack_t *da_stack, unsigned int depth,
1009
          fr_dcursor_t *cursor, void *encode_ctx)
1010
0
{
1011
0
  ssize_t     slen;
1012
0
  size_t      hdr_len;
1013
0
  fr_dbuff_marker_t hdr, length_field, vsa_length_field;
1014
0
  fr_dict_attr_t const  *da, *dv;
1015
0
  fr_dbuff_t    work_dbuff;
1016
1017
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1018
1019
0
  dv = da_stack->da[depth++];
1020
1021
0
  if (dv->type != FR_TYPE_VENDOR) {
1022
0
    fr_strerror_const("Expected Vendor");
1023
0
    return PAIR_ENCODE_FATAL_ERROR;
1024
0
  }
1025
1026
  /*
1027
   *  Now we encode one vendor attribute.
1028
   */
1029
0
  da = da_stack->da[depth];
1030
0
  fr_assert(da != NULL);
1031
1032
  /*
1033
   *  Most VSAs get limited to the one attribute.  Only refs
1034
   *  (e.g. DHCPv4, DHCpv6) can get fragmented.
1035
   */
1036
0
  if (da->type != FR_TYPE_GROUP) {
1037
0
    work_dbuff = FR_DBUFF_MAX(dbuff, UINT8_MAX);
1038
0
  } else {
1039
0
    work_dbuff = FR_DBUFF(dbuff);
1040
0
  }
1041
1042
0
  fr_dbuff_marker(&hdr, &work_dbuff);
1043
1044
  /*
1045
   *  Build the Vendor-Specific header
1046
   */
1047
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_VENDOR_SPECIFIC);
1048
1049
0
  fr_dbuff_marker(&length_field, &work_dbuff);
1050
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0);
1051
1052
0
  FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t)dv->attr); /* Copy in the 32bit vendor ID */
1053
1054
1055
0
  hdr_len = dv->flags.type_size + dv->flags.length;
1056
1057
  /*
1058
   *  Vendors use different widths for their
1059
   *  attribute number fields.
1060
   */
1061
0
  switch (dv->flags.type_size) {
1062
0
  default:
1063
0
    fr_strerror_printf("%s: Internal sanity check failed, type %u", __FUNCTION__, (unsigned) dv->flags.type_size);
1064
0
    return PAIR_ENCODE_FATAL_ERROR;
1065
1066
0
  case 4:
1067
0
    fr_dbuff_in(&work_dbuff, (uint32_t)da->attr);
1068
0
    break;
1069
1070
0
  case 2:
1071
0
    fr_dbuff_in(&work_dbuff, (uint16_t)da->attr);
1072
0
    break;
1073
1074
0
  case 1:
1075
0
    fr_dbuff_in(&work_dbuff, (uint8_t)da->attr);
1076
0
    break;
1077
0
  }
1078
1079
  /*
1080
   *  The length fields will get over-written later.
1081
   */
1082
0
  switch (dv->flags.length) {
1083
0
  default:
1084
0
    fr_strerror_printf("%s: Internal sanity check failed, length %u", __FUNCTION__, (unsigned) dv->flags.length);
1085
0
    return PAIR_ENCODE_FATAL_ERROR;
1086
1087
0
  case 0:
1088
0
    break;
1089
1090
0
  case 2:
1091
0
    fr_dbuff_in_bytes(&work_dbuff, 0);
1092
0
    FALL_THROUGH;
1093
1094
0
  case 1:
1095
    /*
1096
     *  Length fields are set to zero, because they
1097
     *  will get over-ridden later.
1098
     */
1099
0
    fr_dbuff_marker(&vsa_length_field, &work_dbuff);
1100
0
    fr_dbuff_in_bytes(&work_dbuff, 0);
1101
0
    break;
1102
0
  }
1103
1104
0
  slen = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
1105
0
  if (slen <= 0) return slen;
1106
1107
  /*
1108
   *  There may be more than 253 octets of data encoded in
1109
   *  the attribute.  If so, move the data up in the packet,
1110
   *  and copy the existing header over.  Set the "C" flag
1111
   *  ONLY after copying the rest of the data.
1112
   *
1113
   *  Note that we do NOT check 'slen' here, as it's only
1114
   *  the size of the sub-sub attribute, and doesn't include
1115
   *  the RADIUS attribute header, or Vendor-ID.
1116
   */
1117
0
  if (fr_dbuff_used(&work_dbuff) > UINT8_MAX) {
1118
0
    size_t length_offset = 0;
1119
1120
0
    if (dv->flags.length) length_offset = 6 + hdr_len - 1;
1121
1122
0
    slen = attr_fragment(&work_dbuff, (size_t)slen, &hdr, 6 + hdr_len, 0, length_offset);
1123
0
    if (slen <= 0) return slen;
1124
0
  } else {
1125
0
    if (dv->flags.length) {
1126
0
      fr_dbuff_in(&vsa_length_field, (uint8_t)(hdr_len + slen));
1127
0
    }
1128
1129
0
    fr_dbuff_in(&length_field, (uint8_t) fr_dbuff_used(&work_dbuff));
1130
0
  }
1131
1132
0
  FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr), 6 + hdr_len, "header vsa");
1133
1134
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1135
0
}
1136
1137
/** Encode a WiMAX attribute
1138
 *
1139
 */
1140
static ssize_t encode_wimax(fr_dbuff_t *dbuff,
1141
        fr_da_stack_t *da_stack, unsigned int depth,
1142
        fr_dcursor_t *cursor, void *encode_ctx)
1143
0
{
1144
0
  ssize_t     slen;
1145
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
1146
0
  fr_dbuff_marker_t hdr, length_field, vsa_length_field;
1147
0
  fr_dict_attr_t const  *dv;
1148
0
  fr_pair_t const   *vp = fr_dcursor_current(cursor);
1149
1150
0
  fr_dbuff_marker(&hdr, &work_dbuff);
1151
1152
0
  PAIR_VERIFY(vp);
1153
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1154
1155
0
  dv = da_stack->da[depth++];
1156
1157
0
  if (dv->type != FR_TYPE_VENDOR) {
1158
0
    fr_strerror_const("Expected Vendor");
1159
0
    return PAIR_ENCODE_FATAL_ERROR;
1160
0
  }
1161
1162
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1163
1164
  /*
1165
   *  Build the Vendor-Specific header
1166
   */
1167
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_VENDOR_SPECIFIC);
1168
0
  fr_dbuff_marker(&length_field, &work_dbuff);
1169
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x09);
1170
1171
0
  FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t) dv->attr);
1172
1173
  /*
1174
   *  Encode the first attribute
1175
   */
1176
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)da_stack->da[depth]->attr);
1177
1178
0
  fr_dbuff_marker(&vsa_length_field, &work_dbuff);
1179
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x03, 0x00); /* length + continuation, both may be overwritten later */
1180
1181
  /*
1182
   *  We don't bound the size of work_dbuff; it can use more than UINT8_MAX bytes
1183
   *  because of the "continuation" byte.
1184
   */
1185
0
  slen = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
1186
0
  if (slen <= 0) return slen;
1187
1188
  /*
1189
   *  There may be more than 253 octets of data encoded in
1190
   *  the attribute.  If so, move the data up in the packet,
1191
   *  and copy the existing header over.  Set the "C" flag
1192
   *  ONLY after copying the rest of the data.
1193
   *
1194
   *  Note that we do NOT check 'slen' here, as it's only
1195
   *  the size of the sub-sub attribute, and doesn't include
1196
   *  the RADIUS attribute header, or Vendor-ID.
1197
   */
1198
0
  if (fr_dbuff_used(&work_dbuff) > UINT8_MAX) {
1199
0
    slen = attr_fragment(&work_dbuff, (size_t)slen, &hdr, 9, 8, 7);
1200
0
    if (slen <= 0) return slen;
1201
1202
0
    return fr_dbuff_set(dbuff, &work_dbuff);
1203
0
  }
1204
1205
0
  fr_dbuff_in_bytes(&vsa_length_field, (uint8_t) (fr_dbuff_used(&work_dbuff) - 6));
1206
0
  fr_dbuff_in_bytes(&length_field, (uint8_t) fr_dbuff_used(&work_dbuff));
1207
1208
0
  FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr), 9, "header wimax");
1209
1210
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1211
0
}
1212
1213
static ssize_t encode_vendor(fr_dbuff_t *dbuff,
1214
         fr_da_stack_t *da_stack, unsigned int depth,
1215
         fr_dcursor_t *cursor, void *encode_ctx)
1216
0
{
1217
0
  fr_dict_attr_t const  *da = da_stack->da[depth];
1218
0
  ssize_t     slen;
1219
0
  fr_pair_t   *vp;
1220
0
  fr_dict_vendor_t const  *dv;
1221
0
  fr_dcursor_t    child_cursor;
1222
0
  fr_dbuff_t    work_dbuff;
1223
1224
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1225
1226
0
  if (da->type != FR_TYPE_VENDOR) {
1227
0
    fr_strerror_printf("%s: Expected type \"vendor\" got \"%s\"", __FUNCTION__,
1228
0
           fr_type_to_str(da->type));
1229
0
    return PAIR_ENCODE_FATAL_ERROR;
1230
0
  }
1231
1232
0
  dv = fr_dict_vendor_by_da(da_stack->da[depth]);
1233
1234
  /*
1235
   *  Flat hierarchy, encode one attribute at a time.
1236
   *
1237
   *  Note that there's no attempt to encode multiple VSAs
1238
   *  into one attribute.  We can add that back as a flag,
1239
   *  once all of the nested attribute conversion has been
1240
   *  done.
1241
   */
1242
0
  if (da_stack->da[depth + 1]) {
1243
0
    if (dv && dv->continuation) {
1244
0
      return encode_wimax(dbuff, da_stack, depth, cursor, encode_ctx);
1245
0
    }
1246
1247
0
    return encode_vendor_attr(dbuff, da_stack, depth, cursor, encode_ctx);
1248
0
  }
1249
1250
  /*
1251
   *  Loop over the children of this attribute of type Vendor.
1252
   */
1253
0
  vp = fr_dcursor_current(cursor);
1254
0
  fr_assert(vp->da == da);
1255
0
  work_dbuff = FR_DBUFF(dbuff);
1256
1257
0
  fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
1258
0
  while ((vp = fr_dcursor_current(&child_cursor)) != NULL) {
1259
0
    fr_proto_da_stack_build(da_stack, vp->da);
1260
1261
0
    if (dv && dv->continuation) {
1262
0
      slen = encode_wimax(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
1263
0
    } else {
1264
0
      slen = encode_vendor_attr(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
1265
0
    }
1266
0
    if (slen < 0) return slen;
1267
0
  }
1268
1269
0
  vp = fr_dcursor_next(cursor);
1270
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
1271
1272
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1273
0
}
1274
1275
/** Encode a Vendor-Specific attribute
1276
 *
1277
 */
1278
static ssize_t encode_vsa(fr_dbuff_t *dbuff,
1279
            fr_da_stack_t *da_stack, unsigned int depth,
1280
            fr_dcursor_t *cursor, void *encode_ctx)
1281
0
{
1282
0
  ssize_t     slen;
1283
0
  fr_pair_t   *vp;
1284
0
  fr_dcursor_t    child_cursor;
1285
0
  fr_dict_attr_t const  *da = da_stack->da[depth];
1286
0
  fr_dbuff_t    work_dbuff;
1287
1288
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1289
1290
0
  if (da->type != FR_TYPE_VSA) {
1291
0
    fr_strerror_printf("%s: Expected type \"vsa\" got \"%s\"", __FUNCTION__,
1292
0
           fr_type_to_str(da->type));
1293
0
    return PAIR_ENCODE_FATAL_ERROR;
1294
0
  }
1295
1296
  /*
1297
   *  Loop over the contents of Vendor-Specific, each of
1298
   *  which MUST be of type FR_TYPE_VENDOR.
1299
   */
1300
0
  if (da_stack->da[depth + 1]) {
1301
0
    return encode_vendor(dbuff, da_stack, depth + 1, cursor, encode_ctx);
1302
0
  }
1303
1304
0
  work_dbuff = FR_DBUFF(dbuff);
1305
1306
0
  vp = fr_dcursor_current(cursor);
1307
0
  if (vp->da != da_stack->da[depth]) {
1308
0
    fr_strerror_printf("%s: Can't encode empty Vendor-Specific", __FUNCTION__);
1309
0
    return 0;
1310
0
  }
1311
1312
  /*
1313
   *  Loop over the children of this Vendor-Specific
1314
   *  attribute.
1315
   */
1316
0
  fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
1317
0
  while ((vp = fr_dcursor_current(&child_cursor)) != NULL) {
1318
0
    fr_proto_da_stack_build(da_stack, vp->da);
1319
1320
0
    fr_assert(da_stack->da[depth + 1]->type == FR_TYPE_VENDOR);
1321
1322
0
    slen = encode_vendor(&work_dbuff, da_stack, depth + 1, &child_cursor, encode_ctx);
1323
0
    if (slen < 0) return slen;
1324
0
  }
1325
1326
  /*
1327
   *  Fix up the da stack, and return the data we've encoded.
1328
   */
1329
0
  vp = fr_dcursor_next(cursor);
1330
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
1331
1332
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), 6, "header vsa");
1333
1334
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1335
0
}
1336
1337
/** Encode NAS-Filter-Rule
1338
 *
1339
 *  Concatenating the string attributes together, separated by a 0x00 byte,
1340
 */
1341
static ssize_t encode_nas_filter_rule(fr_dbuff_t *dbuff,
1342
              fr_da_stack_t *da_stack, NDEBUG_UNUSED unsigned int depth,
1343
              fr_dcursor_t *cursor, UNUSED void *encode_ctx)
1344
0
{
1345
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
1346
0
  fr_dbuff_marker_t hdr, frag_hdr;
1347
0
  fr_pair_t   *vp = fr_dcursor_current(cursor);
1348
0
  size_t      attr_len = 2;
1349
1350
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1351
1352
0
  fr_assert(vp);
1353
0
  fr_assert(vp->da);
1354
1355
0
  fr_dbuff_marker(&hdr, &work_dbuff);
1356
0
  fr_dbuff_marker(&frag_hdr, &work_dbuff);
1357
0
  fr_dbuff_advance(&hdr, 1);
1358
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 0x00);
1359
1360
0
  fr_assert(vp->da == attr_nas_filter_rule);
1361
1362
0
  while (true) {
1363
0
    size_t data_len = vp->vp_length;
1364
0
    size_t frag_len;
1365
0
    char const *p = vp->vp_strvalue;
1366
1367
    /*
1368
     *  Keep encoding this attribute until it's done.
1369
     */
1370
0
    while (data_len > 0) {
1371
0
      frag_len = data_len;
1372
1373
      /*
1374
       *  This fragment doesn't overflow the
1375
       *  attribute.  Copy it over, update the
1376
       *  length, but leave the marker at the
1377
       *  current header.
1378
       */
1379
0
      if ((attr_len + frag_len) <= UINT8_MAX) {
1380
0
        FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, p, frag_len);
1381
0
        attr_len += frag_len;
1382
1383
0
        fr_dbuff_set(&frag_hdr, &hdr);
1384
0
        fr_dbuff_in(&frag_hdr, (uint8_t) attr_len); /* there's no fr_dbuff_in_no_advance() */
1385
0
        break;
1386
0
      }
1387
1388
      /*
1389
       *  This fragment overflows the attribute.
1390
       *  Copy the fragment in, and create a new
1391
       *  attribute header.
1392
       */
1393
0
      frag_len = UINT8_MAX - attr_len;
1394
0
      FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, p, frag_len);
1395
0
      fr_dbuff_in(&hdr, (uint8_t) UINT8_MAX);
1396
1397
0
      fr_dbuff_set(&hdr, &work_dbuff);
1398
0
      fr_dbuff_advance(&hdr, 1);
1399
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 0x02);
1400
0
      attr_len = 2;
1401
1402
0
      p += frag_len;
1403
0
      data_len -= frag_len;
1404
0
    }
1405
1406
    /*
1407
     *  If we have nothing more to do here, then stop.
1408
     */
1409
0
    vp = fr_dcursor_next(cursor);
1410
0
    if (!vp || (vp->da != attr_nas_filter_rule)) {
1411
0
      break;
1412
0
    }
1413
1414
    /*
1415
     *  We have to add a zero byte.  If it doesn't
1416
     *  overflow the current attribute, then just add
1417
     *  it in.
1418
     */
1419
0
    if (attr_len < UINT8_MAX) {
1420
0
      attr_len++;
1421
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00);
1422
1423
0
      fr_dbuff_set(&frag_hdr, &hdr);
1424
0
      fr_dbuff_in(&frag_hdr, (uint8_t) attr_len); /* there's no fr_dbuff_in_no_advance() */
1425
0
      continue;
1426
0
    }
1427
1428
    /*
1429
     *  The zero byte causes the current attribute to
1430
     *  overflow.  Create a new header with the zero
1431
     *  byte already populated, and keep going.
1432
     */
1433
0
    fr_dbuff_set(&hdr, &work_dbuff);
1434
0
    fr_dbuff_advance(&hdr, 1);
1435
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 0x00, 0x00);
1436
0
    attr_len = 3;
1437
0
  }
1438
1439
0
  vp = fr_dcursor_current(cursor);
1440
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
1441
1442
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1443
0
}
1444
1445
/** Encode an RFC standard attribute 1..255
1446
 *
1447
 *  This function is not the same as encode_child(), because this
1448
 *  one treats some "top level" attributes as special.  e.g.
1449
 *  Message-Authenticator.
1450
 */
1451
static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth,
1452
            fr_dcursor_t *cursor, void *encode_ctx)
1453
0
{
1454
0
  fr_pair_t const *vp = fr_dcursor_current(cursor);
1455
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
1456
0
  fr_dbuff_marker_t start;
1457
0
  fr_radius_encode_ctx_t  *packet_ctx = encode_ctx;
1458
1459
0
  fr_dbuff_marker(&start, &work_dbuff);
1460
1461
  /*
1462
   *  Sanity checks
1463
   */
1464
0
  PAIR_VERIFY(vp);
1465
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
1466
1467
0
  switch (da_stack->da[depth]->type) {
1468
0
  case FR_TYPE_TLV:
1469
0
  case FR_TYPE_VSA:
1470
0
  case FR_TYPE_VENDOR:
1471
    /* FR_TYPE_STRUCT is actually allowed... */
1472
0
    fr_strerror_printf("%s: Expected leaf type got \"%s\"", __FUNCTION__,
1473
0
           fr_type_to_str(da_stack->da[depth]->type));
1474
0
    return PAIR_ENCODE_FATAL_ERROR;
1475
1476
0
  default:
1477
    /*
1478
     *  Attribute 0 is fine as a TLV leaf, or VSA, but not
1479
     *  in the original standards space.
1480
     */
1481
0
    if (((fr_dict_vendor_num_by_da(da_stack->da[depth]) == 0) && (da_stack->da[depth]->attr == 0)) ||
1482
0
        (da_stack->da[depth]->attr > UINT8_MAX)) {
1483
0
      (void) fr_dcursor_next(cursor);
1484
0
      return 0;
1485
0
    }
1486
0
    break;
1487
0
  }
1488
1489
  /*
1490
   *  Only CUI is allowed to have zero length.
1491
   *  Thank you, WiMAX!
1492
   */
1493
0
  if ((vp->da == attr_chargeable_user_identity) && (vp->vp_length == 0)) {
1494
0
    fr_dbuff_in_bytes(&work_dbuff, (uint8_t)vp->da->attr, 0x02);
1495
1496
0
    FR_PROTO_HEX_DUMP(fr_dbuff_current(&start), 2, "header rfc");
1497
1498
0
    vp = fr_dcursor_next(cursor);
1499
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
1500
0
    return fr_dbuff_set(dbuff, &work_dbuff);
1501
0
  }
1502
1503
  /*
1504
   *  Message-Authenticator is hard-coded.
1505
   */
1506
0
  if (vp->da == attr_message_authenticator) {
1507
0
    if (!packet_ctx->seen_message_authenticator) {
1508
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 18);
1509
0
      FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, RADIUS_MESSAGE_AUTHENTICATOR_LENGTH);
1510
1511
0
      FR_PROTO_HEX_DUMP(fr_dbuff_current(&start) + 2, RADIUS_MESSAGE_AUTHENTICATOR_LENGTH,
1512
0
            "message-authenticator");
1513
0
      FR_PROTO_HEX_DUMP(fr_dbuff_current(&start), 2, "header rfc");
1514
1515
0
      packet_ctx->seen_message_authenticator = true;
1516
0
    }
1517
1518
0
    vp = fr_dcursor_next(cursor);
1519
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
1520
0
    return fr_dbuff_set(dbuff, &work_dbuff);
1521
0
  }
1522
1523
  /*
1524
   *  NAS-Filter-Rule has a stupid format in order to save
1525
   *  one byte per attribute.
1526
   */
1527
0
  if (vp->da == attr_nas_filter_rule) {
1528
0
    return encode_nas_filter_rule(dbuff, da_stack, depth, cursor, encode_ctx);
1529
0
  }
1530
1531
  /*
1532
   *  Once we've checked for various top-level magic, RFC attributes are just TLVs.
1533
   */
1534
0
  return encode_child(dbuff, da_stack, depth, cursor, encode_ctx);
1535
0
}
1536
1537
/** Encode a data structure into a RADIUS attribute
1538
 *
1539
 * This is the main entry point into the encoder.  It sets up the encoder array
1540
 * we use for tracking our TLV/VSA nesting and then calls the appropriate
1541
 * dispatch function.
1542
 *
1543
 * @param[out] dbuff    Where to write encoded data.
1544
 * @param[in] cursor    Specifying attribute to encode.
1545
 * @param[in] encode_ctx  Additional data such as the shared secret to use.
1546
 * @return
1547
 *  - >0 The number of bytes written to out.
1548
 *  - 0 Nothing to encode (or attribute skipped).
1549
 *  - <0 an error occurred.
1550
 */
1551
ssize_t fr_radius_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
1552
0
{
1553
0
  fr_pair_t const   *vp;
1554
0
  ssize_t     slen;
1555
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
1556
1557
0
  fr_da_stack_t   da_stack;
1558
0
  fr_dict_attr_t const  *da = NULL;
1559
1560
0
  if (!cursor) return PAIR_ENCODE_FATAL_ERROR;
1561
1562
0
  vp = fr_dcursor_current(cursor);
1563
0
  if (!vp) return 0;
1564
1565
0
  PAIR_VERIFY(vp);
1566
1567
0
  if (vp->da->depth > FR_DICT_MAX_TLV_STACK) {
1568
0
    fr_strerror_printf("%s: Attribute depth %u exceeds maximum nesting depth %i",
1569
0
           __FUNCTION__, vp->da->depth, FR_DICT_MAX_TLV_STACK);
1570
0
    return PAIR_ENCODE_FATAL_ERROR;
1571
0
  }
1572
1573
  /*
1574
   *  Tags are *top-level*, and are never nested.
1575
   */
1576
0
  if ((vp->vp_type == FR_TYPE_GROUP) && vp->da->flags.internal &&
1577
0
      (vp->da->attr > FR_TAG_BASE) && (vp->da->attr < (FR_TAG_BASE + 0x20))) {
1578
0
    fr_radius_encode_ctx_t  *packet_ctx = encode_ctx;
1579
1580
0
    packet_ctx->tag = vp->da->attr - FR_TAG_BASE;
1581
0
    fr_assert(packet_ctx->tag > 0);
1582
0
    fr_assert(packet_ctx->tag < 0x20);
1583
1584
    // recurse to encode the children of this attribute
1585
0
    slen = encode_pairs(&work_dbuff, &vp->vp_group, encode_ctx);
1586
0
    packet_ctx->tag = 0;
1587
0
    if (slen < 0) return slen;
1588
1589
0
    fr_dcursor_next(cursor); /* skip the tag attribute */
1590
0
    return fr_dbuff_set(dbuff, &work_dbuff);
1591
0
  }
1592
1593
  /*
1594
   *  Check for zero-length attributes.
1595
   */
1596
0
  switch (vp->vp_type) {
1597
0
  default:
1598
0
    break;
1599
1600
    /*
1601
     *  Only variable length data types can be
1602
     *  variable sized.  All others have fixed size.
1603
     */
1604
0
  case FR_TYPE_STRING:
1605
0
  case FR_TYPE_OCTETS:
1606
    /*
1607
     *  Zero-length strings are allowed for CUI
1608
     *  (thanks WiMAX!), and for
1609
     *  Message-Authenticator, because we will
1610
     *  automagically generate that one ourselves.
1611
     */
1612
0
    if ((vp->vp_length == 0) &&
1613
0
        (vp->da != attr_chargeable_user_identity) &&
1614
0
        (vp->da != attr_message_authenticator)) {
1615
0
      fr_dcursor_next(cursor);
1616
0
      fr_strerror_const("Zero length string attributes not allowed");
1617
0
      return 0;
1618
0
    }
1619
0
    break;
1620
0
  }
1621
1622
  /*
1623
   *  Nested structures of attributes can't be longer than
1624
   *  255 bytes, so each call to an encode function can
1625
   *  only use 255 bytes of buffer space at a time.
1626
   */
1627
1628
  /*
1629
   *  Fast path for the common case.
1630
   */
1631
0
  if (vp->da->parent->flags.is_root && fr_radius_flag_encrypted(vp->da)) {
1632
0
    switch (vp->vp_type) {
1633
0
    case FR_TYPE_LEAF:
1634
0
      da_stack.da[0] = vp->da;
1635
0
      da_stack.da[1] = NULL;
1636
0
      da_stack.depth = 1;
1637
0
      FR_PROTO_STACK_PRINT(&da_stack, 0);
1638
0
      slen = encode_rfc(&work_dbuff, &da_stack, 0, cursor, encode_ctx);
1639
0
      if (slen < 0) return slen;
1640
0
      return fr_dbuff_set(dbuff, &work_dbuff);
1641
1642
0
    default:
1643
0
      break;
1644
0
    }
1645
0
  }
1646
1647
  /*
1648
   *  Do more work to set up the stack for the complex case.
1649
   */
1650
0
  fr_proto_da_stack_build(&da_stack, vp->da);
1651
0
  FR_PROTO_STACK_PRINT(&da_stack, 0);
1652
1653
  /*
1654
   *  Top-level attributes get treated specially.  Things
1655
   *  like VSAs inside of extended attributes are handled
1656
   *  inside of type-specific encoders.
1657
   */
1658
0
  da = da_stack.da[0];
1659
0
  switch (da->type) {
1660
0
  case FR_TYPE_OCTETS:
1661
0
    if (fr_radius_flag_concat(da)) {
1662
      /*
1663
       *  Attributes like EAP-Message are marked as
1664
       *  "concat", which means that they are fragmented
1665
       *  using a different scheme than the "long
1666
       *  extended" one.
1667
       */
1668
0
      slen = encode_concat(&work_dbuff, &da_stack, 0, cursor, encode_ctx);
1669
0
      if (slen < 0) return slen;
1670
0
      break;
1671
0
    }
1672
0
    FALL_THROUGH;
1673
1674
0
  default:
1675
0
    slen = encode_rfc(&work_dbuff, &da_stack, 0, cursor, encode_ctx);
1676
0
    if (slen < 0) return slen;
1677
0
    break;
1678
1679
0
  case FR_TYPE_VSA:
1680
0
    slen = encode_vsa(&work_dbuff, &da_stack, 0, cursor, encode_ctx);
1681
0
    if (slen < 0) return slen;
1682
0
    break;
1683
1684
0
  case FR_TYPE_TLV:
1685
0
    if (!fr_radius_flag_extended(da)) {
1686
0
      slen = encode_child(&work_dbuff, &da_stack, 0, cursor, encode_ctx);
1687
1688
0
    } else if (vp->da != da) {
1689
0
      fr_strerror_printf("extended attributes must be nested");
1690
0
      return PAIR_ENCODE_FATAL_ERROR;
1691
1692
0
    } else {
1693
0
      slen = encode_extended_nested(&work_dbuff, &da_stack, 0, cursor, encode_ctx);
1694
0
    }
1695
0
    if (slen < 0) return slen;
1696
0
    break;
1697
1698
0
  case FR_TYPE_NULL:
1699
0
  case FR_TYPE_VENDOR:
1700
0
  case FR_TYPE_MAX:
1701
0
    fr_strerror_printf("%s: Cannot encode attribute %s", __FUNCTION__, vp->da->name);
1702
0
    return PAIR_ENCODE_FATAL_ERROR;
1703
0
  }
1704
1705
  /*
1706
   *  We didn't encode any data, continue.
1707
   */
1708
0
  if (!slen) {
1709
0
    fr_assert(fr_dcursor_current(cursor) != vp);
1710
0
    return 0;
1711
0
  }
1712
1713
  /*
1714
   *  We couldn't do it, so we didn't do anything.
1715
   */
1716
0
  if (fr_dcursor_current(cursor) == vp) {
1717
0
    fr_strerror_printf("%s: Nested attribute structure too large to encode", __FUNCTION__);
1718
0
    return PAIR_ENCODE_FATAL_ERROR;
1719
0
  }
1720
1721
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1722
0
}
1723
1724
ssize_t fr_radius_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
1725
0
{
1726
0
        fr_radius_ctx_t common_ctx = {};
1727
0
  fr_radius_encode_ctx_t encode_ctx = {
1728
0
    .common = &common_ctx,
1729
0
    .foreign = true,    /* we are being called from a foreign protocol */
1730
0
  };
1731
1732
  /*
1733
   *  Just in case we need random numbers.
1734
   */
1735
0
  encode_ctx.rand_ctx.a = fr_rand();
1736
0
  encode_ctx.rand_ctx.b = fr_rand();
1737
1738
  /*
1739
   *  Encode the pairs.
1740
   */
1741
0
  return encode_pairs(dbuff, list, &encode_ctx);
1742
0
}
1743
1744
1745
static int encode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
1746
         UNUSED fr_dict_attr_t const *root_da)
1747
0
{
1748
0
  static uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH] = {
1749
0
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1750
0
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1751
1752
0
  fr_radius_encode_ctx_t  *test_ctx;
1753
0
  fr_radius_ctx_t   *common;
1754
1755
0
  test_ctx = talloc_zero(ctx, fr_radius_encode_ctx_t);
1756
0
  if (!test_ctx) return -1;
1757
1758
0
  test_ctx->common = common = talloc_zero(test_ctx, fr_radius_ctx_t);
1759
1760
0
  common->secret = talloc_strdup(common, "testing123");
1761
0
  common->secret_length = talloc_strlen(common->secret);
1762
1763
  /*
1764
   *  We don't want to automatically add Message-Authenticator
1765
   */
1766
0
  common->secure_transport = true;
1767
1768
0
  test_ctx->request_authenticator = vector;
1769
0
  test_ctx->rand_ctx.a = 6809;
1770
0
  test_ctx->rand_ctx.b = 2112;
1771
1772
0
  *out = test_ctx;
1773
1774
0
  return 0;
1775
0
}
1776
1777
static ssize_t fr_radius_encode_proto(TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, void *proto_ctx)
1778
0
{
1779
0
  fr_radius_encode_ctx_t  *packet_ctx = talloc_get_type_abort(proto_ctx, fr_radius_encode_ctx_t);
1780
0
  int packet_type = FR_RADIUS_CODE_ACCESS_REQUEST;
1781
0
  fr_pair_t *vp;
1782
0
  ssize_t slen;
1783
0
  uint8_t const *request_authenticator = NULL;
1784
1785
0
  vp = fr_pair_find_by_da(vps, NULL, attr_packet_type);
1786
0
  if (vp) {
1787
0
    packet_type = vp->vp_uint32;
1788
1789
0
    if (!FR_RADIUS_PACKET_CODE_VALID(packet_type)) {
1790
0
      fr_strerror_printf("Invalid packet code %u", packet_type);
1791
0
      return -1;
1792
0
    }
1793
0
  }
1794
1795
  /*
1796
   *  Force specific values for testing.
1797
   */
1798
0
  if ((packet_type == FR_RADIUS_CODE_ACCESS_REQUEST) || (packet_type == FR_RADIUS_CODE_STATUS_SERVER)) {
1799
0
    vp = fr_pair_find_by_da(vps, NULL, attr_packet_authentication_vector);
1800
0
    if (!vp) {
1801
0
      fr_pair_list_append_by_da_len(ctx, vp, vps, attr_packet_authentication_vector,
1802
0
                  packet_ctx->request_authenticator, RADIUS_AUTH_VECTOR_LENGTH, false);
1803
0
    }
1804
0
  }
1805
1806
0
  packet_ctx->code = packet_type;
1807
0
  packet_ctx->request_code = allowed_replies[packet_type];
1808
0
  if (packet_ctx->request_code) request_authenticator = packet_ctx->request_authenticator;
1809
1810
  /*
1811
   *  @todo - pass in packet_ctx to this function, so that we
1812
   *  can leverage a consistent random number generator.
1813
   */
1814
0
  slen = fr_radius_encode(&FR_DBUFF_TMP(data, data_len), vps, packet_ctx);
1815
0
  if (slen <= 0) return slen;
1816
1817
0
  if (fr_radius_sign(data, request_authenticator,
1818
0
         (uint8_t const *) packet_ctx->common->secret, talloc_strlen(packet_ctx->common->secret)) < 0) {
1819
0
    return -1;
1820
0
  }
1821
1822
0
  return slen;
1823
0
}
1824
1825
/*
1826
 *  No one else should be using this.
1827
 */
1828
extern void *fr_radius_next_encodable(fr_dcursor_t *cursor, void *to_eval, void *uctx);
1829
1830
/*
1831
 *  Test points
1832
 */
1833
extern fr_test_point_pair_encode_t radius_tp_encode_pair;
1834
fr_test_point_pair_encode_t radius_tp_encode_pair = {
1835
  .test_ctx = encode_test_ctx,
1836
  .func   = fr_radius_encode_pair,
1837
  .next_encodable = fr_radius_next_encodable,
1838
};
1839
1840
1841
extern fr_test_point_proto_encode_t radius_tp_encode_proto;
1842
fr_test_point_proto_encode_t radius_tp_encode_proto = {
1843
  .test_ctx = encode_test_ctx,
1844
  .func   = fr_radius_encode_proto
1845
};