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