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: 1fb87ee2b4cbfbd3872c89fe2e770ba0f065b72e $")
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("enumv"), FR_DICT_ATTR_EXT_ENUMV },
35 { L("namespace"), FR_DICT_ATTR_EXT_NAMESPACE },
36 { L("protocol-specific"), FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC }
37};
39
40/** Fixup name pointer on realloc
41 *
42 */
44 TALLOC_CTX *chunk,
45 void *ext_ptr, UNUSED size_t ext_ptr_len)
46{
47 fr_dict_attr_t *da = talloc_get_type_abort(chunk, fr_dict_attr_t);
48
49 da->name = ext_ptr;
50
51 return 0;
52}
53
54/** Copy all enumeration values from one attribute to another
55 *
56 */
58 TALLOC_CTX *chunk_dst,
59 UNUSED void *dst_ext_ptr, UNUSED size_t dst_ext_len,
60 UNUSED TALLOC_CTX const *chunk_src,
61 UNUSED void *src_ext_ptr, UNUSED size_t src_ext_len)
62{
63 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
64 fr_dict_attr_ext_enumv_t *src_ext = src_ext_ptr;
65 fr_hash_iter_t iter;
68 fr_value_box_t const *vb;
69
70 if (!src_ext->value_by_name) return 0;
71
72 /*
73 * Add all the enumeration values from
74 * the old attribute to the new attribute.
75 */
76 for (enumv = fr_hash_table_iter_init(src_ext->value_by_name, &iter);
77 enumv;
78 enumv = fr_hash_table_iter_next(src_ext->value_by_name, &iter)) {
80 fr_dict_attr_t const *key_child_ref;
81
82 key_child_ref = NULL;
83
84 /*
85 * If the enum refers to a child, it MUST refer to a child of a union.
86 *
87 * We then re-write the ref to point to the newly copied child.
88 */
90 if (ref) {
91 fr_dict_attr_t const *ref_parent;
92
94
95 ref_parent = fr_dict_attr_by_name(NULL, da_dst->parent, ref->da->parent->name);
96 fr_assert(ref_parent);
97 fr_assert(ref_parent->type == FR_TYPE_UNION);
98
99 /*
100 * The reference has to exist.
101 */
102 key_child_ref = fr_dict_attr_by_name(NULL, ref_parent, ref->da->name);
103 fr_assert(key_child_ref != NULL);
104 }
105
106 vb = enumv->value;
107 if (da_dst->type != enumv->value->type) {
109 fr_assert(fr_type_is_integer(da_dst->type));
110
111 if (fr_value_box_cast(da_dst, &box, da_dst->type, NULL, enumv->value) < 0) return -1;
112
113 vb = &box;
114 }
115
116 if (dict_attr_enum_add_name(da_dst, enumv->name, vb,
117 true, true, key_child_ref) < 0) return -1;
118 }
119
120 return 0;
121}
122
123/** Rediscover the parent of this attribute, and cache it
124 *
125 */
127 TALLOC_CTX *chunk_dst,
128 void *dst_ext_ptr, UNUSED size_t dst_ext_len,
129 UNUSED TALLOC_CTX const *chunk_src,
130 void *src_ext_ptr, UNUSED size_t src_ext_len)
131{
132 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
133 fr_dict_attr_ext_vendor_t *dst_ext = dst_ext_ptr, *src_ext = src_ext_ptr;
134 fr_dict_attr_t const *old_vendor = src_ext->vendor;
135 fr_dict_attr_t const *da;
136
137 if (!old_vendor) {
138 dst_ext->vendor = NULL;
139 return 0;
140 }
141
142 /*
143 * Otherwise traverse the parent list
144 * looking for the vendor.
145 *
146 * Theoretically the attribute could
147 * have been moved to a different depth.
148 */
149 for (da = da_dst->parent; da; da = da->parent) {
150 if ((da->type == old_vendor->type) && (da->attr == old_vendor->attr)) {
151 dst_ext->vendor = da;
152 return 0;
153 }
154 }
155
156 return -1;
157}
158
160 TALLOC_CTX *dst_chunk,
161 void *dst_ext_ptr, size_t dst_ext_len,
162 TALLOC_CTX const *src_chunk,
163 void *src_ext_ptr, size_t src_ext_len)
164{
166 fr_dict_protocol_t const *from_proto = fr_dict_protocol(from->dict);
167 fr_dict_attr_t *to = talloc_get_type_abort(dst_chunk, fr_dict_attr_t);
168 fr_dict_protocol_t const *to_proto = fr_dict_protocol(to->dict);
169
170 /*
171 * Whilst it's not strictly disallowed, we can't do anything
172 * sane without an N x N matrix of copy functions for different
173 * protocols. Maybe we should add that at some point, but for
174 * now, just ignore the copy.
175 */
176 if (from->dict != to->dict) return 0;
177
178 /*
179 * Sanity checks...
180 */
181 if (unlikely(from_proto->attr.flags.len != src_ext_len)) {
182 fr_strerror_printf("Protocol specific extension length mismatch in source attribute %s. Expected %zu, got %zu",
183 from->name,
184 fr_dict_protocol(from->dict)->attr.flags.len, src_ext_len);
185 return -1;
186 }
187
188 if (unlikely(to_proto->attr.flags.len != dst_ext_len)) {
189 fr_strerror_printf("Protocol specific extension length mismatch in destination attribute %s. Expected %zu, got %zu",
190 to->name,
191 fr_dict_protocol(to->dict)->attr.flags.len, dst_ext_len);
192 return -1;
193 }
194
195 /*
196 * The simple case... No custom copy function, just memcpy
197 */
198 if (!to_proto->attr.flags.copy) {
199 memcpy(dst_ext_ptr, src_ext_ptr, src_ext_len);
200 return 0;
201 }
202
203 /*
204 * Call the custom copy function. This is only needed if
205 * there are heap allocated values, like strings, which
206 * need copying from sources flags to the destination.
207 */
208 return to_proto->attr.flags.copy(dst_chunk, dst_ext_ptr, src_ext_ptr);
209}
210
211/** Rediscover the key reference for this attribute, and cache it
212 *
213 * The UNION has a ref to the key DA, which is a sibling of the union.
214 */
216 TALLOC_CTX *chunk_dst,
217 void *dst_ext_ptr, UNUSED size_t dst_ext_len,
218 UNUSED TALLOC_CTX const *chunk_src,
219 void *src_ext_ptr, UNUSED size_t src_ext_len)
220{
221 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
222 fr_dict_attr_ext_ref_t *dst_ext = dst_ext_ptr, *src_ext = src_ext_ptr;
223 fr_dict_attr_t const *key;
224
225 fr_assert(da_dst->parent);
226 fr_assert(da_dst->type == FR_TYPE_UNION);
227 fr_assert(src_ext->type == FR_DICT_ATTR_REF_KEY);
228
229 fr_assert(da_dst->parent != src_ext->ref->parent);
230
231 key = fr_dict_attr_by_name(NULL, da_dst->parent, src_ext->ref->name);
232 if (!key) {
233 fr_strerror_printf("Parent %s has no key attribute '%s'",
234 da_dst->parent->name, src_ext->ref->name);
235 return -1;
236 }
237
238 dst_ext->ref = key; /* @todo - is ref_target? */
239
240 return 0;
241}
242
243/** Holds additional information about extension structures
244 *
245 */
247 .offset_of_exts = offsetof(fr_dict_attr_t, ext),
248 .name_table = dict_attr_ext_table,
249 .name_table_len = &dict_attr_ext_table_len,
251 .info = (fr_ext_info_t[]){ /* -Wgnu-flexible-array-initializer */
253 .min = sizeof(char),
254 .has_hdr = true,
256 .can_copy = false, /* Name may change, and we can only set it once */
257 },
259 .min = sizeof(fr_dict_attr_ext_children_t),
260 .can_copy = false, /* Limitation in hashing scheme we use */
261 },
263 .min = sizeof(fr_dict_attr_ext_ref_t),
264 /*
265 * Copying a CLONE or ENUM is OK.
266 *
267 * @todo - copying an ALIAS will copy the name,
268 * but the ref will be to the original destination DA.
269 */
270 .can_copy = true,
271 },
273 /*
274 * keys are mostly like refs, but they're not
275 * auto-followed like refs. The difference is
276 * that we can copy a ref as-is, because the ref
277 * points to something which exists, and is
278 * independent of us.
279 *
280 * But a key ref is only used in a UNION, and
281 * then points to the key attribute of the parent
282 * structure. If we do allow copying a UNION, we
283 * will also need to specify the new key ref.
284 *
285 * So we need a special copy function.
286 */
287 .min = sizeof(fr_dict_attr_ext_ref_t),
289 .can_copy = true,
290 },
292 .min = sizeof(fr_dict_attr_ext_vendor_t),
293 .can_copy = true,
295 },
297 .min = sizeof(fr_dict_attr_ext_enumv_t),
298 .can_copy = true,
300 },
302 .min = sizeof(fr_dict_attr_ext_namespace_t),
303 .can_copy = false, /* Same limitation as ext_children */
304 },
306 .min = FR_EXT_ALIGNMENT, /* allow for one byte of protocol stuff */
307 .has_hdr = true, /* variable sized */
309 .can_copy = true /* Use the attr.flags.copy function */
310 },
312 }
313};
314
316 { L("attr_ref"), FR_DICT_ENUM_EXT_ATTR_REF }
317};
319
321{
322 fr_ext_debug(&fr_dict_attr_ext_def, da->name, da);
323}
324
325/** Holds additional information about extension structures
326 *
327 */
329 .offset_of_exts = offsetof(fr_dict_enum_value_t, ext),
330 .name_table = dict_enum_ext_table,
331 .name_table_len = &dict_enum_ext_table_len,
333 .info = (fr_ext_info_t[]){ /* -Wgnu-flexible-array-initializer */
335 .min = sizeof(fr_dict_enum_ext_attr_ref_t),
336 .can_copy = true
337 },
339 }
340};
#define RCSID(id)
Definition build.h:487
#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:241
@ FR_DICT_ENUM_EXT_ATTR_REF
Reference to a child attribute associated with this key value.
Definition dict.h:240
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition dict_util.c:5266
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:3532
char const * name
Attribute name.
Definition dict.h:201
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:259
struct fr_dict_protocol_t::@127 attr
fr_dict_attr_t const * parent
Immediate parent of this attribute.
Definition dict.h:211
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:192
@ FR_DICT_ATTR_EXT_MAX
Definition dict.h:193
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:190
@ FR_DICT_ATTR_EXT_NAMESPACE
Attribute has its own namespace.
Definition dict.h:191
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:186
@ FR_DICT_ATTR_EXT_KEY
UNION attribute references a key.
Definition dict.h:188
@ FR_DICT_ATTR_EXT_VENDOR
Cached vendor pointer.
Definition dict.h:189
@ FR_DICT_ATTR_EXT_NAME
Name of the attribute.
Definition dict.h:184
@ FR_DICT_ATTR_EXT_CHILDREN
Attribute has children.
Definition dict.h:185
char const * name
Enum name.
Definition dict.h:256
fr_type_t type
Value type.
Definition dict.h:209
fr_dict_attr_t const * da
the child structure referenced by this value of key
Definition dict.h:248
Enum extension - Sub-struct or union pointer.
Definition dict.h:247
Value of an enumerated attribute.
Definition dict.h:255
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:457
fr_ext_t const fr_dict_attr_ext_def
Holds additional information about extension structures.
Definition dict_ext.c:246
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:57
fr_ext_t const fr_dict_enum_ext_def
Holds additional information about extension structures.
Definition dict_ext.c:328
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:126
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:215
static size_t dict_attr_ext_table_len
Definition dict_ext.c:38
static size_t dict_enum_ext_table_len
Definition dict_ext.c:318
void fr_dict_attr_ext_debug(fr_dict_attr_t const *da)
Definition dict_ext.c:320
static fr_table_num_ordered_t const dict_enum_ext_table[]
Definition dict_ext.c:315
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:159
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:43
static void * fr_dict_enum_ext(fr_dict_enum_value_t const *enumv, fr_dict_enum_ext_t ext)
Definition dict_ext.h:216
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:97
@ FR_DICT_ATTR_REF_KEY
it is a UNION which has a ref to a key, and children.
Definition dict_ext.h:64
Attribute extension - Holds children for an attribute.
Definition dict_ext.h:52
Attribute extension - Holds enumeration values.
Definition dict_ext.h:95
Attribute extension - Holds a hash table with the names of all children of this attribute.
Definition dict_ext.h:104
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:2022
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:3882
fr_type_t _CONST type
Type and flags should appear together for packing efficiency.
Definition value.h:191