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