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