The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_ext.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program 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
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Extensions to dictionary structures
18 *
19 * @file src/lib/util/dict_ext.c
20 *
21 * @copyright 2020 The FreeRADIUS server project
22 * @copyright 2020,2024 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23 */
24RCSID("$Id: df1316b79126ecc3dd47c94e497c1be401c45b45 $")
25
26#include <freeradius-devel/util/dict_priv.h>
27
29 { L("name"), FR_DICT_ATTR_EXT_NAME },
30 { L("children"), FR_DICT_ATTR_EXT_CHILDREN },
31 { L("ref"), FR_DICT_ATTR_EXT_REF },
32 { L("key"), FR_DICT_ATTR_EXT_KEY },
33 { L("vendor"), FR_DICT_ATTR_EXT_VENDOR },
34 { L("da_stack"), FR_DICT_ATTR_EXT_DA_STACK },
35 { L("enumv"), FR_DICT_ATTR_EXT_ENUMV },
36 { L("namespace"), FR_DICT_ATTR_EXT_NAMESPACE },
37 { L("protocol-specific"), FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC }
38};
40
41/** Fixup name pointer on realloc
42 *
43 */
45 TALLOC_CTX *chunk,
46 void *ext_ptr, UNUSED size_t ext_ptr_len)
47{
48 fr_dict_attr_t *da = talloc_get_type_abort(chunk, fr_dict_attr_t);
49
50 da->name = ext_ptr;
51
52 return 0;
53}
54
55/** Copy all enumeration values from one attribute to another
56 *
57 */
59 TALLOC_CTX *chunk_dst,
60 UNUSED void *dst_ext_ptr, UNUSED size_t dst_ext_len,
61 UNUSED TALLOC_CTX const *chunk_src,
62 UNUSED void *src_ext_ptr, UNUSED size_t src_ext_len)
63{
64 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
65 fr_dict_attr_ext_enumv_t *src_ext = src_ext_ptr;
66 fr_hash_iter_t iter;
69 fr_value_box_t const *vb;
70
71 if (!src_ext->value_by_name) return 0;
72
73 /*
74 * Add all the enumeration values from
75 * the old attribute to the new attribute.
76 */
77 for (enumv = fr_hash_table_iter_init(src_ext->value_by_name, &iter);
78 enumv;
79 enumv = fr_hash_table_iter_next(src_ext->value_by_name, &iter)) {
81 fr_dict_attr_t const *key_child_ref;
82
83 key_child_ref = NULL;
84
85 /*
86 * If the enum refers to a child, it MUST refer to a child of a union.
87 *
88 * We then re-write the ref to point to the newly copied child.
89 */
91 if (ref) {
92 fr_dict_attr_t const *ref_parent;
93
95
96 ref_parent = fr_dict_attr_by_name(NULL, da_dst->parent, ref->da->parent->name);
97 fr_assert(ref_parent);
98 fr_assert(ref_parent->type == FR_TYPE_UNION);
99
100 /*
101 * The reference has to exist.
102 */
103 key_child_ref = fr_dict_attr_by_name(NULL, ref_parent, ref->da->name);
104 fr_assert(key_child_ref != NULL);
105 }
106
107 vb = enumv->value;
108 if (da_dst->type != enumv->value->type) {
110 fr_assert(fr_type_is_integer(da_dst->type));
111
112 if (fr_value_box_cast(da_dst, &box, da_dst->type, NULL, enumv->value) < 0) return -1;
113
114 vb = &box;
115 }
116
117 if (dict_attr_enum_add_name(da_dst, enumv->name, vb,
118 true, true, key_child_ref) < 0) return -1;
119 }
120
121 return 0;
122}
123
124/** Rediscover the parent of this attribute, and cache it
125 *
126 */
128 TALLOC_CTX *chunk_dst,
129 void *dst_ext_ptr, UNUSED size_t dst_ext_len,
130 UNUSED TALLOC_CTX const *chunk_src,
131 void *src_ext_ptr, UNUSED size_t src_ext_len)
132{
133 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
134 fr_dict_attr_ext_vendor_t *dst_ext = dst_ext_ptr, *src_ext = src_ext_ptr;
135 fr_dict_attr_t const **da_stack;
136 fr_dict_attr_t const *old_vendor = src_ext->vendor;
137 fr_dict_attr_t const *new_vendor, *da;
138
139 if (!old_vendor) {
140 dst_ext->vendor = NULL;
141 return 0;
142 }
143
144 /*
145 * If we have a da stack, see if we can
146 * find a vendor at the same depth as
147 * the old depth.
148 */
149 da_stack = fr_dict_attr_da_stack(da_dst);
150 if (da_stack) {
151 new_vendor = da_stack[old_vendor->depth];
152 if ((new_vendor->type == old_vendor->type) && (new_vendor->attr == old_vendor->attr)) {
153 dst_ext->vendor = new_vendor;
154 return 0;
155 }
156 }
157
158 /*
159 * Otherwise traverse the parent list
160 * looking for the vendor.
161 *
162 * Theoretically the attribute could
163 * have been moved to a different depth.
164 */
165 for (da = da_dst->parent; da; da = da->parent) {
166 if ((da->type == old_vendor->type) && (da->attr == old_vendor->attr)) {
167 dst_ext->vendor = da;
168 return 0;
169 }
170 }
171
172 return -1;
173}
174
176 TALLOC_CTX *dst_chunk,
177 void *dst_ext_ptr, size_t dst_ext_len,
178 TALLOC_CTX const *src_chunk,
179 void *src_ext_ptr, size_t src_ext_len)
180{
182 fr_dict_protocol_t const *from_proto = fr_dict_protocol(from->dict);
183 fr_dict_attr_t *to = talloc_get_type_abort(dst_chunk, fr_dict_attr_t);
184 fr_dict_protocol_t const *to_proto = fr_dict_protocol(to->dict);
185
186 /*
187 * Whilst it's not strictly disallowed, we can't do anything
188 * sane without an N x N matrix of copy functions for different
189 * protocols. Maybe we should add that at some point, but for
190 * now, just ignore the copy.
191 */
192 if (from->dict != to->dict) return 0;
193
194 /*
195 * Sanity checks...
196 */
197 if (unlikely(from_proto->attr.flags.len != src_ext_len)) {
198 fr_strerror_printf("Protocol specific extension length mismatch in source attribute %s. Expected %zu, got %zu",
199 from->name,
200 fr_dict_protocol(from->dict)->attr.flags.len, fr_dict_protocol(to->dict)->attr.flags.len);
201 return -1;
202 }
203
204 if (unlikely(to_proto->attr.flags.len != dst_ext_len)) {
205 fr_strerror_printf("Protocol specific extension length mismatch in destintion attribute %s. Expected %zu, got %zu",
206 to->name,
207 fr_dict_protocol(to->dict)->attr.flags.len, fr_dict_protocol(to->dict)->attr.flags.len);
208 return -1;
209 }
210
211 /*
212 * The simple case... No custom copy function, just memcpy
213 */
214 if (!to_proto->attr.flags.copy) {
215 memcpy(dst_ext_ptr, src_ext_ptr, src_ext_len);
216 return 0;
217 }
218
219 /*
220 * Call the custom copy function. This is only needed if
221 * there are heap allocated values, like strings, which
222 * need copying from sources flags to the destination.
223 */
224 return to_proto->attr.flags.copy(dst_chunk, dst_ext_ptr, src_ext_ptr);
225}
226
227/** Rediscover the key reference for this attribute, and cache it
228 *
229 * The UNION has a ref to the key DA, which is a sibling of the union.
230 */
232 TALLOC_CTX *chunk_dst,
233 void *dst_ext_ptr, UNUSED size_t dst_ext_len,
234 UNUSED TALLOC_CTX const *chunk_src,
235 void *src_ext_ptr, UNUSED size_t src_ext_len)
236{
237 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
238 fr_dict_attr_ext_ref_t *dst_ext = dst_ext_ptr, *src_ext = src_ext_ptr;
239 fr_dict_attr_t const *key;
240
241 fr_assert(da_dst->parent);
242 fr_assert(da_dst->type == FR_TYPE_UNION);
243 fr_assert(src_ext->type == FR_DICT_ATTR_REF_KEY);
244
245 fr_assert(da_dst->parent != src_ext->ref->parent);
246
247 key = fr_dict_attr_by_name(NULL, da_dst->parent, src_ext->ref->name);
248 if (!key) {
249 fr_strerror_printf("Parent %s has no key attribute '%s'",
250 da_dst->parent->name, src_ext->ref->name);
251 return -1;
252 }
253
254 dst_ext->ref = key; /* @todo - is ref_target? */
255
256 return 0;
257}
258
259/** Holds additional information about extension structures
260 *
261 */
263 .offset_of_exts = offsetof(fr_dict_attr_t, ext),
264 .name_table = dict_attr_ext_table,
265 .name_table_len = &dict_attr_ext_table_len,
267 .info = (fr_ext_info_t[]){ /* -Wgnu-flexible-array-initializer */
269 .min = sizeof(char),
270 .has_hdr = true,
272 .can_copy = false, /* Name may change, and we can only set it once */
273 },
275 .min = sizeof(fr_dict_attr_ext_children_t),
276 .can_copy = false, /* Limitation in hashing scheme we use */
277 },
279 .min = sizeof(fr_dict_attr_ext_ref_t),
280 /*
281 * Copying a CLONE or ENUM is OK.
282 *
283 * @todo - copying an ALIAS will copy the name,
284 * but the ref will be to the original destination DA.
285 */
286 .can_copy = true,
287 },
289 /*
290 * keys are mostly like refs, but they're not
291 * auto-followed like refs. The difference is
292 * that we can copy a ref as-is, because the ref
293 * points to something which exists, and is
294 * independent of us.
295 *
296 * But a key ref is only used in a UNION, and
297 * then points to the key attribute of the parent
298 * structure. If we do allow copying a UNION, we
299 * will also need to specify the new key ref.
300 *
301 * So we need a special copy function.
302 */
303 .min = sizeof(fr_dict_attr_ext_ref_t),
305 .can_copy = true,
306 },
308 .min = sizeof(fr_dict_attr_ext_vendor_t),
309 .can_copy = true,
311 },
313 .min = sizeof(fr_dict_attr_ext_da_stack_t),
314 .has_hdr = true,
315 .can_copy = false /* Reinitialised for each new attribute */
316 },
318 .min = sizeof(fr_dict_attr_ext_enumv_t),
319 .can_copy = true,
321 },
323 .min = sizeof(fr_dict_attr_ext_namespace_t),
324 .can_copy = false, /* Same limitation as ext_children */
325 },
327 .min = FR_EXT_ALIGNMENT, /* allow for one byte of protocol stuff */
328 .has_hdr = true, /* variable sized */
330 .can_copy = true /* Use the attr.flags.copy function */
331 },
333 }
334};
335
337 { L("attr_ref"), FR_DICT_ENUM_EXT_ATTR_REF }
338};
340
342{
343 fr_ext_debug(&fr_dict_attr_ext_def, da->name, da);
344}
345
346/** Holds additional information about extension structures
347 *
348 */
350 .offset_of_exts = offsetof(fr_dict_enum_value_t, ext),
351 .name_table = dict_enum_ext_table,
352 .name_table_len = &dict_enum_ext_table_len,
354 .info = (fr_ext_info_t[]){ /* -Wgnu-flexible-array-initializer */
356 .min = sizeof(fr_dict_enum_ext_attr_ref_t),
357 .can_copy = true
358 },
360 }
361};
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
@ FR_DICT_ENUM_EXT_MAX
Definition dict.h:240
@ FR_DICT_ENUM_EXT_ATTR_REF
Reference to a child attribute associated with this key value.
Definition dict.h:239
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition dict_util.c:5243
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3525
char const * name
Attribute name.
Definition dict.h:200
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:258
struct fr_dict_protocol_t::@127 attr
fr_dict_attr_t const * parent
Immediate parent of this attribute.
Definition dict.h:210
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:191
@ FR_DICT_ATTR_EXT_MAX
Definition dict.h:192
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:189
@ FR_DICT_ATTR_EXT_NAMESPACE
Attribute has its own namespace.
Definition dict.h:190
@ FR_DICT_ATTR_EXT_DA_STACK
Cached da stack.
Definition dict.h:188
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:184
@ FR_DICT_ATTR_EXT_KEY
UNION attribute references a key.
Definition dict.h:186
@ FR_DICT_ATTR_EXT_VENDOR
Cached vendor pointer.
Definition dict.h:187
@ FR_DICT_ATTR_EXT_NAME
Name of the attribute.
Definition dict.h:182
@ FR_DICT_ATTR_EXT_CHILDREN
Attribute has children.
Definition dict.h:183
char const * name
Enum name.
Definition dict.h:255
fr_type_t type
Value type.
Definition dict.h:208
fr_dict_attr_t const * da
the child structure referenced by this value of key
Definition dict.h:247
Enum extension - Sub-struct or union pointer.
Definition dict.h:246
Value of an enumerated attribute.
Definition dict.h:254
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:456
fr_ext_t const fr_dict_attr_ext_def
Holds additional information about extension structures.
Definition dict_ext.c:262
static int fr_dict_attr_ext_enumv_copy(UNUSED int ext, TALLOC_CTX *chunk_dst, UNUSED void *dst_ext_ptr, UNUSED size_t dst_ext_len, UNUSED TALLOC_CTX const *chunk_src, UNUSED void *src_ext_ptr, UNUSED size_t src_ext_len)
Copy all enumeration values from one attribute to another.
Definition dict_ext.c:58
fr_ext_t const fr_dict_enum_ext_def
Holds additional information about extension structures.
Definition dict_ext.c:349
static int fr_dict_attr_ext_vendor_copy(UNUSED int ext, TALLOC_CTX *chunk_dst, void *dst_ext_ptr, UNUSED size_t dst_ext_len, UNUSED TALLOC_CTX const *chunk_src, void *src_ext_ptr, UNUSED size_t src_ext_len)
Rediscover the parent of this attribute, and cache it.
Definition dict_ext.c:127
static int fr_dict_attr_ext_key_copy(UNUSED int ext, TALLOC_CTX *chunk_dst, void *dst_ext_ptr, UNUSED size_t dst_ext_len, UNUSED TALLOC_CTX const *chunk_src, void *src_ext_ptr, UNUSED size_t src_ext_len)
Rediscover the key reference for this attribute, and cache it.
Definition dict_ext.c:231
static size_t dict_attr_ext_table_len
Definition dict_ext.c:39
static size_t dict_enum_ext_table_len
Definition dict_ext.c:339
void fr_dict_attr_ext_debug(fr_dict_attr_t const *da)
Definition dict_ext.c:341
static fr_table_num_ordered_t const dict_enum_ext_table[]
Definition dict_ext.c:336
static int dict_ext_protocol_specific_copy(UNUSED int ext, TALLOC_CTX *dst_chunk, void *dst_ext_ptr, size_t dst_ext_len, TALLOC_CTX const *src_chunk, void *src_ext_ptr, size_t src_ext_len)
Definition dict_ext.c:175
static fr_table_num_ordered_t const dict_attr_ext_table[]
Definition dict_ext.c:28
static int fr_dict_attr_ext_name_fixup(UNUSED int ext, TALLOC_CTX *chunk, void *ext_ptr, UNUSED size_t ext_ptr_len)
Fixup name pointer on realloc.
Definition dict_ext.c:44
static void * fr_dict_enum_ext(fr_dict_enum_value_t const *enumv, fr_dict_enum_ext_t ext)
Definition dict_ext.h:246
fr_dict_attr_t const * vendor
ancestor which has type FR_TYPE_VENDOR
Definition dict_ext.h:89
fr_hash_table_t * value_by_name
Lookup an enumeration value by name.
Definition dict_ext.h:110
static fr_dict_attr_t const ** fr_dict_attr_da_stack(fr_dict_attr_t const *da)
Return the cached da stack (if any) associated with an attribute.
Definition dict_ext.h:161
@ FR_DICT_ATTR_REF_KEY
it is a UNION which has a ref to a key, and children.
Definition dict_ext.h:65
Attribute extension - Holds children for an attribute.
Definition dict_ext.h:52
Attribute extension - Stack of dictionary attributes that describe the path back to the root of the d...
Definition dict_ext.h:95
Attribute extension - Holds enumeration values.
Definition dict_ext.h:108
Attribute extension - Holds a hash table with the names of all children of this attribute.
Definition dict_ext.h:117
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition dict_ext.h:77
Attribute extension - Cached vendor pointer.
Definition dict_ext.h:88
int dict_attr_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool replace, fr_dict_attr_t const *child_struct)
Definition dict_util.c:2013
void fr_ext_debug(fr_ext_t const *def, char const *name, void const *chunk)
Print out all extensions and hexdump their contents.
Definition ext.c:339
size_t offset_of_exts
Where in the extended struct the extensions array starts.
Definition ext.h:127
#define FR_EXT_ALIGNMENT
The alignment of object extension structures.
Definition ext.h:54
Additional information for a given extension.
Definition ext.h:111
Structure to define a set of extensions.
Definition ext.h:126
void * fr_hash_table_iter_next(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Iterate over entries in a hash table.
Definition hash.c:625
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:677
Stores the state of the current iteration operation.
Definition hash.h:41
#define fr_assert(_expr)
Definition rad_assert.h:38
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
#define talloc_get_type_abort_const
Definition talloc.h:244
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:82
#define fr_type_is_integer(_x)
Definition types.h:382
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3730
fr_type_t _CONST type
Type and flags should appear together for packing efficiency.
Definition value.h:191