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