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: 2a61464a5cd138dabce07297168318e2f3bdfaa0 $
19 *
20 * Because what we need is yet *ANOTHER* serialisation scheme.
21 *
22 * @file protocols/internal/encode.c
23 * @brief Functions to encode data in our internal structure.
24 *
25 * @copyright 2020 The FreeRADIUS server project
26 * @copyright 2020 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
27 */
28#include <freeradius-devel/internal/internal.h>
29#include <freeradius-devel/io/pair.h>
30#include <freeradius-devel/io/test_point.h>
31#include <freeradius-devel/util/net.h>
32#include <freeradius-devel/util/proto.h>
33
34
36
37/** We use the same header for all types
38 *
39 */
40
41/** Encode the value of the value pair the cursor currently points at.
42 *
43 * @param dbuff data buffer to place the encoded data in
44 * @param da_stack da stack corresponding to the value pair
45 * @param depth in da_stack
46 * @param cursor cursor whose current value is the one to be encoded
47 * @param encode_ctx encoder context
48 *
49 * @return either a negative number, indicating an error
50 * or the number of bytes used to encode the value
51 */
53 fr_da_stack_t *da_stack, unsigned int depth,
54 fr_dcursor_t *cursor, void *encode_ctx)
55{
56 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
57 fr_dbuff_marker_t enc_field, len_field, value_field;
58 fr_dbuff_t value_dbuff;
59 fr_dict_attr_t const *da = da_stack->da[depth];
61 bool unknown = false, internal = false;
62
63 ssize_t slen;
64 size_t flen, vlen, mlen;
65
66 uint8_t buff[sizeof(uint64_t)];
67 uint8_t enc_byte = 0;
68 fr_internal_encode_ctx_t *our_encode_ctx = encode_ctx;
69
70 if (!our_encode_ctx) our_encode_ctx = &default_encode_ctx;
71
72 /*
73 * Silently skip name only attributes if we're writing
74 * to a database or cache.
75 */
76 if (!our_encode_ctx->allow_name_only && vp->da->flags.name_only) {
77 fr_dcursor_next(cursor);
78 return 0;
79 }
80
81 FR_PROTO_STACK_PRINT(da_stack, depth);
82
83 fr_dbuff_marker(&enc_field, &work_dbuff);
84
85 /*
86 * Advance past first encoding byte
87 */
88 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00);
89
90 switch (vp->vp_type) {
91 /*
92 * Only leaf attributes can be tainted
93 */
94 case FR_TYPE_LEAF:
95 if (vp->vp_tainted) enc_byte |= FR_INTERNAL_FLAG_TAINTED;
96 break;
97
98 default:
99 break;
100 }
101
102 /*
103 * Need to use the second encoding byte
104 *
105 * 0 1
106 * 0 1 2 3 4 5 6 7 8 9 0
107 * +-+-+-+-+-+-+-+-+-+-+
108 * |u|i|-|-|-|-|-|e|
109 * +-+-+-+-+-+-+-+-+-+-+
110 */
111 if ((unknown = da->flags.is_unknown) ||
112 (internal = (da->parent == fr_dict_root(fr_dict_internal())))) {
113 enc_byte |= FR_INTERNAL_FLAG_EXTENDED;
114 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff,
115 (unknown * FR_INTERNAL_FLAG_UNKNOWN) |
116 (internal * FR_INTERNAL_FLAG_INTERNAL));
117 }
118
119 /*
120 * Encode the type and write the width of the
121 * integer to the encoding byte.
122 */
123 flen = fr_dbuff_in_uint64v(&work_dbuff, da->attr);
124 if (flen <= 0) return flen;
125 enc_byte |= ((flen - 1) << 5);
126
127 /*
128 * Leave one byte in hopes that the length will fit
129 * so we needn't move the encoded data.
130 */
131 fr_dbuff_marker(&len_field, &work_dbuff);
132 FR_DBUFF_ADVANCE_RETURN(&work_dbuff, 1);
133
134 /*
135 * Create dbuff to hold encoded data--the fr_dbuff_move() done
136 * if the length field needs more than one byte will guard
137 * against insufficient space.
138 */
139 value_dbuff = FR_DBUFF_BIND_CURRENT(&work_dbuff);
140 fr_dbuff_marker(&value_field, &value_dbuff);
141
142 switch (da->type) {
143 case FR_TYPE_LEAF:
144 slen = fr_value_box_to_network(&value_dbuff, &vp->data);
145 if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
146 fr_dcursor_next(cursor);
147 break;
148
149 /*
150 * This is the vendor container.
151 * For RADIUS it'd be something like attr 26.
152 *
153 * Inside the VSA you then have the vendor
154 * which is just encoded as another TLVish
155 * type attribute.
156 *
157 * For small vendor PENs <= 255 this
158 * encoding is 6 bytes, the same as RADIUS.
159 *
160 * For larger vendor PENs it's more bytes
161 * but we really don't care.
162 */
163 case FR_TYPE_VSA:
164 case FR_TYPE_VENDOR:
165
166 /*
167 * Children of TLVs are encoded in the context
168 * of the TLV.
169 *
170 * STRUCTs are encoded as TLVs, because the struct
171 * packing only applies to the original protocol, and not
172 * to our internal encoding.
173 */
174 case FR_TYPE_TLV:
175 case FR_TYPE_STRUCT:
176 /*
177 * We've done the complete stack.
178 * Hopefully this TLV has some
179 * children to encode...
180 */
181 if (da == vp->da) {
182 fr_dcursor_t children;
183 fr_pair_t *child;
184
185 for (child = fr_pair_dcursor_init(&children, &vp->vp_group);
186 child;
187 child = fr_dcursor_current(&children)) {
188
189 FR_PROTO_TRACE("encode ctx changed %s -> %s", da->name, child->da->name);
190
191 fr_proto_da_stack_build_partial(da_stack, da_stack->da[depth], child->da);
192 FR_PROTO_STACK_PRINT(da_stack, depth);
193
194 slen = internal_encode(&value_dbuff, da_stack, depth + 1, &children, encode_ctx);
195 if (slen < 0) return slen;
196 }
197 fr_dcursor_next(cursor);
198 break;
199 }
200
201 /*
202 * Still encoding intermediary TLVs...
203 */
204 slen = internal_encode(&value_dbuff, da_stack, depth + 1, cursor, encode_ctx);
205 if (slen < 0) return slen;
206 break;
207
208 /*
209 * Each child of a group encodes from the
210 * dictionary root to the leaf da.
211 *
212 * Re-enter the encoder at the start.
213 * We do this, because the child may
214 * have a completely different da_stack.
215 */
216 case FR_TYPE_GROUP:
217 {
218 fr_dcursor_t children;
219 fr_pair_t *child;
220
221 for (child = fr_pair_dcursor_init(&children, &vp->vp_group);
222 child;
223 child = fr_dcursor_current(&children)) {
224 FR_PROTO_TRACE("encode ctx changed %s -> %s", da->name, child->da->name);
225
226 slen = fr_internal_encode_pair(&value_dbuff, &children, encode_ctx);
227 if (slen < 0) return slen;
228 }
229 fr_dcursor_next(cursor);
230 }
231 break;
232
233 default:
234 fr_strerror_printf("%s: Unexpected attribute type \"%s\"",
235 __FUNCTION__, fr_type_to_str(da->type));
237 }
238
239 /*
240 * Encode the total length, and write the width
241 * of the integer to the encoding byte.
242 *
243 * Already did length checks at the start of
244 * the function.
245 */
246 vlen = fr_dbuff_used(&value_dbuff);
247 flen = (ssize_t) fr_nbo_from_uint64v(buff, vlen);
248
249 /*
250 * Ugh, it's a long one, need to move the data.
251 */
252 if (flen > 1) {
253 fr_dbuff_advance(&value_field, flen - 1);
254 fr_dbuff_set_to_start(&value_dbuff);
255 mlen = fr_dbuff_move(&value_field, &value_dbuff, vlen);
256 if (mlen < vlen) return -(vlen - mlen);
257 }
258
259 FR_DBUFF_IN_MEMCPY_RETURN(&len_field, buff, flen);
260 enc_byte |= ((flen - 1) << 2);
261 FR_DBUFF_IN_RETURN(&enc_field, enc_byte);
262
263 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff) - vlen, "header");
264
265 FR_PROTO_HEX_DUMP(fr_dbuff_start(&value_dbuff), vlen, "value %s",
266 fr_type_to_str(vp->vp_type));
267
268 return fr_dbuff_set(dbuff, &work_dbuff);
269}
270
271/** Encode a data structure into an internal attribute
272 *
273 * @param[in,out] dbuff Where to write encoded data and how much one can write.
274 * @param[in] cursor Specifying attribute to encode.
275 * @param[in] encode_ctx Additional data such as the shared secret to use.
276 * @return
277 * - >0 The number of bytes written to out.
278 * - 0 Nothing to encode (or attribute skipped).
279 * - <0 an error occurred.
280 */
282{
283 fr_pair_t *vp;
284 fr_da_stack_t da_stack;
285
286 vp = fr_dcursor_current(cursor);
287 if (!vp) return 0;
288
289 fr_proto_da_stack_build(&da_stack, vp->da);
290
291 return internal_encode(dbuff, &da_stack, 0, cursor, encode_ctx);
292}
293
294/** Encode a list of pairs using the internal encoder
295 *
296 * @param[out] dbuff Where to write encoded data.
297 * @param[in] list List of attributes to encode.
298 * @param[in] encode_ctx Additional data to be used by the encoder.
299 * @return
300 * - length of encoded data on success
301 * - < 0 on failure
302 */
304{
305 fr_pair_t *vp;
306 fr_dcursor_t dcursor;
307 ssize_t ret = 0, len = 0;
308 fr_da_stack_t da_stack;
309
310 for (vp = fr_pair_dcursor_init(&dcursor, list);
311 vp;
312 vp = fr_dcursor_current(&dcursor)) {
313 fr_proto_da_stack_build(&da_stack, vp->da);
314 ret = internal_encode(dbuff, &da_stack, 0, &dcursor, encode_ctx);
315 if (ret < 0) return ret;
316 len += ret;
317 }
318
319 return len;
320}
321
322/*
323 * Test points
324 */
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1072
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:767
#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len)
Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range.
Definition dbuff.h:1088
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
#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:1004
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
Definition dbuff.h:1155
#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:240
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition dbuff.h:1192
#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num)
Copy an integer value into a dbuff or marker using our internal variable length encoding.
Definition dbuff.h:1612
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1382
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition dbuff.h:1585
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#define fr_dbuff_move(_out, _in, _len)
Copy in as many bytes as possible from one dbuff or marker to another.
Definition dbuff.h:1656
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1472
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_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4610
#define FR_INTERNAL_FLAG_INTERNAL
Definition internal.h:33
bool allow_name_only
Allow name only pairs.
Definition internal.h:36
#define FR_INTERNAL_FLAG_EXTENDED
Definition internal.h:26
#define FR_INTERNAL_FLAG_UNKNOWN
Definition internal.h:32
#define FR_INTERNAL_FLAG_TAINTED
Definition internal.h:27
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
Definition pair.h:36
@ FR_TYPE_TLV
Contains nested attributes.
@ 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_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
static size_t fr_nbo_from_uint64v(uint8_t out[static sizeof(uint64_t)], uint64_t num)
Write out an unsigned 64bit integer in wire format using the fewest bytes possible.
Definition nbo.h:118
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_da_stack_build_partial(fr_da_stack_t *stack, fr_dict_attr_t const *parent, fr_dict_attr_t const *da)
Complete the DA stack for a child attribute.
Definition proto.c:159
static fr_internal_encode_ctx_t encode_ctx
ssize_t fr_internal_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a data structure into an internal attribute.
Definition encode.c:281
ssize_t fr_internal_encode_list(fr_dbuff_t *dbuff, fr_pair_list_t const *list, void *encode_ctx)
Encode a list of pairs using the internal encoder.
Definition encode.c:303
fr_test_point_pair_encode_t internal_tp_encode_pair
Definition encode.c:326
static ssize_t internal_encode(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
We use the same header for all types.
Definition encode.c:52
static fr_internal_encode_ctx_t default_encode_ctx
Definition encode.c:35
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
fr_pair_t * vp
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:93
Entry point for pair encoders.
Definition test_point.h:92
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:591
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:41
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:40
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:43
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:54
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
#define FR_TYPE_LEAF
Definition types.h:297
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition value.c:1404