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: 01e45b7109259f7605906d2c9a93690122d368b1 $")
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 TALLOC_CTX const *chunk_src,
62 void *src_ext_ptr, UNUSED size_t src_ext_len)
63{
65 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
66 fr_dict_attr_ext_enumv_t *src_ext = src_ext_ptr;
67 fr_hash_iter_t iter;
69
70 /*
71 * @todo - remove after migration_union_key is deleted
72 */
73 bool has_child = fr_dict_attr_is_key_field(da_src) && !da_src->flags.migration_union_key;
74
75 if (!src_ext->value_by_name) return 0;
76
77 /*
78 * Add all the enumeration values from
79 * the old attribute to the new attribute.
80 */
81 for (enumv = fr_hash_table_iter_init(src_ext->value_by_name, &iter);
82 enumv;
83 enumv = fr_hash_table_iter_next(src_ext->value_by_name, &iter)) {
84 fr_dict_attr_t *key_child_ref;
85
86 if (!has_child) {
87 key_child_ref = NULL;
88 } else {
89 fr_dict_t *dict = dict_by_da(enumv->key_child_ref[0]);
90
91 /*
92 * Copy the key_child_ref, and all if it's children recursively.
93 */
94 key_child_ref = dict_attr_acopy(dict->pool, enumv->key_child_ref[0], NULL);
95 if (!key_child_ref) return -1;
96
97 key_child_ref->parent = da_dst; /* we need to re-parent this attribute */
98
99 if (dict_attr_children(enumv->key_child_ref[0])) {
100 if (dict_attr_acopy_children(dict, key_child_ref, enumv->key_child_ref[0]) < 0) return -1;
101 }
102 }
103
104 if (dict_attr_enum_add_name(da_dst, enumv->name, enumv->value,
105 true, true, key_child_ref) < 0) return -1;
106 }
107
108 return 0;
109}
110
111/** Rediscover the parent of this attribute, and cache it
112 *
113 */
115 TALLOC_CTX *chunk_dst,
116 void *dst_ext_ptr, UNUSED size_t dst_ext_len,
117 UNUSED TALLOC_CTX const *chunk_src,
118 void *src_ext_ptr, UNUSED size_t src_ext_len)
119{
120 fr_dict_attr_t *da_dst = talloc_get_type_abort(chunk_dst, fr_dict_attr_t);
121 fr_dict_attr_ext_vendor_t *dst_ext = dst_ext_ptr, *src_ext = src_ext_ptr;
122 fr_dict_attr_t const **da_stack;
123 fr_dict_attr_t const *old_vendor = src_ext->vendor;
124 fr_dict_attr_t const *new_vendor, *da;
125
126 if (!old_vendor) {
127 dst_ext->vendor = NULL;
128 return 0;
129 }
130
131 /*
132 * If we have a da stack, see if we can
133 * find a vendor at the same depth as
134 * the old depth.
135 */
136 da_stack = fr_dict_attr_da_stack(da_dst);
137 if (da_stack) {
138 new_vendor = da_stack[old_vendor->depth];
139 if ((new_vendor->type == old_vendor->type) && (new_vendor->attr == old_vendor->attr)) {
140 dst_ext->vendor = new_vendor;
141 return 0;
142 }
143 }
144
145 /*
146 * Otherwise traverse the parent list
147 * looking for the vendor.
148 *
149 * Theoretically the attribute could
150 * have been moved to a different depth.
151 */
152 for (da = da_dst->parent; da; da = da->parent) {
153 if ((da->type == old_vendor->type) && (da->attr == old_vendor->attr)) {
154 dst_ext->vendor = da;
155 return 0;
156 }
157 }
158
159 return -1;
160}
161
163 TALLOC_CTX *dst_chunk,
164 void *dst_ext_ptr, size_t dst_ext_len,
165 TALLOC_CTX const *src_chunk,
166 void *src_ext_ptr, size_t src_ext_len)
167{
169 fr_dict_protocol_t const *from_proto = fr_dict_protocol(from->dict);
170 fr_dict_attr_t *to = talloc_get_type_abort(dst_chunk, fr_dict_attr_t);
171 fr_dict_protocol_t const *to_proto = fr_dict_protocol(to->dict);
172
173 /*
174 * Whilst it's not strictly disallowed, we can't do anything
175 * sane without an N x N matrix of copy functions for different
176 * protocols. Maybe we should add that at some point, but for
177 * now, just ignore the copy.
178 */
179 if (from->dict != to->dict) return 0;
180
181 /*
182 * Sanity checks...
183 */
184 if (unlikely(from_proto->attr.flags.len != src_ext_len)) {
185 fr_strerror_printf("Protocol specific extension length mismatch in source attribute %s. Expected %zu, got %zu",
186 from->name,
187 fr_dict_protocol(from->dict)->attr.flags.len, fr_dict_protocol(to->dict)->attr.flags.len);
188 return -1;
189 }
190
191 if (unlikely(to_proto->attr.flags.len != dst_ext_len)) {
192 fr_strerror_printf("Protocol specific extension length mismatch in destintion attribute %s. Expected %zu, got %zu",
193 to->name,
194 fr_dict_protocol(to->dict)->attr.flags.len, fr_dict_protocol(to->dict)->attr.flags.len);
195 return -1;
196 }
197
198 /*
199 * The simple case... No custom copy function, just memcpy
200 */
201 if (!to_proto->attr.flags.copy) {
202 memcpy(dst_ext_ptr, src_ext_ptr, src_ext_len);
203 return 0;
204 }
205
206 /*
207 * Call the custom copy function. This is only needed if
208 * there are heap allocated values, like strings, which
209 * need copying from sources flags to the destination.
210 */
211 return to_proto->attr.flags.copy(dst_chunk, dst_ext_ptr, src_ext_ptr);
212}
213
214/** Holds additional information about extension structures
215 *
216 */
218 .offset_of_exts = offsetof(fr_dict_attr_t, ext),
219 .name_table = dict_attr_ext_table,
220 .name_table_len = &dict_attr_ext_table_len,
222 .info = (fr_ext_info_t[]){ /* -Wgnu-flexible-array-initializer */
224 .min = sizeof(char),
225 .has_hdr = true,
227 .can_copy = false, /* Name may change, and we can only set it once */
228 },
230 .min = sizeof(fr_dict_attr_ext_children_t),
231 .can_copy = false, /* Limitation in hashing scheme we use */
232 },
234 .min = sizeof(fr_dict_attr_ext_ref_t),
235 .can_copy = true,
236 },
237 [FR_DICT_ATTR_EXT_KEY] = { //!< keys are just refs, but they're not auto-followed like refs
238 .min = sizeof(fr_dict_attr_ext_ref_t),
239 .can_copy = true,
240 },
242 .min = sizeof(fr_dict_attr_ext_vendor_t),
243 .can_copy = true,
245 },
247 .min = sizeof(fr_dict_attr_ext_da_stack_t),
248 .has_hdr = true,
249 .can_copy = false /* Reinitialised for each new attribute */
250 },
252 .min = sizeof(fr_dict_attr_ext_enumv_t),
253 .can_copy = true,
255 },
257 .min = sizeof(fr_dict_attr_ext_namespace_t),
258 .can_copy = false, /* Same limitation as ext_children */
259 },
261 .min = FR_EXT_ALIGNMENT, /* allow for one byte of protocol stuff */
262 .has_hdr = true, /* variable sized */
264 .can_copy = true /* Use the attr.flags.copy function */
265 },
267 }
268};
269
271 { L("key_child_ref"), FR_DICT_ENUM_EXT_KEY_CHILD_REF }
272};
274
276{
277 fr_ext_debug(&fr_dict_attr_ext_def, da->name, da);
278}
279
280/** Holds additional information about extension structures
281 *
282 */
284 .offset_of_exts = offsetof(fr_dict_enum_value_t, ext),
285 .name_table = dict_enum_ext_table,
286 .name_table_len = &dict_enum_ext_table_len,
288 .info = (fr_ext_info_t[]){ /* -Wgnu-flexible-array-initializer */
291 .can_copy = true
292 },
294 }
295};
#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
int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src)
Copy the children of an existing attribute.
Definition dict_util.c:1177
@ FR_DICT_ENUM_EXT_MAX
Definition dict.h:239
@ FR_DICT_ENUM_EXT_KEY_CHILD_REF
Reference to a child associated with this key.
Definition dict.h:238
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition dict_util.c:5089
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:250
struct fr_dict_protocol_t::@127 attr
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:190
@ FR_DICT_ATTR_EXT_MAX
Definition dict.h:191
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:188
@ FR_DICT_ATTR_EXT_NAMESPACE
Attribute has its own namespace.
Definition dict.h:189
@ FR_DICT_ATTR_EXT_DA_STACK
Cached da stack.
Definition dict.h:187
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:183
@ FR_DICT_ATTR_EXT_KEY
UNION attribute references a key.
Definition dict.h:185
@ FR_DICT_ATTR_EXT_VENDOR
Cached vendor pointer.
Definition dict.h:186
@ FR_DICT_ATTR_EXT_NAME
Name of the attribute.
Definition dict.h:181
@ FR_DICT_ATTR_EXT_CHILDREN
Attribute has children.
Definition dict.h:182
fr_dict_attr_t const * key_child_ref[]
for key fields
Definition dict.h:254
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:169
char const * name
Enum name.
Definition dict.h:247
Value of an enumerated attribute.
Definition dict.h:246
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:447
fr_ext_t const fr_dict_attr_ext_def
Holds additional information about extension structures.
Definition dict_ext.c:217
fr_ext_t const fr_dict_enum_ext_def
Holds additional information about extension structures.
Definition dict_ext.c:283
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:114
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:273
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, TALLOC_CTX const *chunk_src, void *src_ext_ptr, UNUSED size_t src_ext_len)
Copy all enumeration values from one attribute to another.
Definition dict_ext.c:58
void fr_dict_attr_ext_debug(fr_dict_attr_t const *da)
Definition dict_ext.c:275
static fr_table_num_ordered_t const dict_enum_ext_table[]
Definition dict_ext.c:270
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:162
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
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:168
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
Enum extension - Sub-struct or union pointer.
Definition dict_ext.h:124
static fr_dict_attr_t const ** dict_attr_children(fr_dict_attr_t const *da)
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:1830
fr_dict_t * dict_by_da(fr_dict_attr_t const *da)
Internal version of fr_dict_by_da.
Definition dict_util.c:2632
fr_dict_attr_t * dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *in, char const *new_name)
Copy a an existing attribute.
Definition dict_util.c:1089
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:626
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:678
Stores the state of the current iteration operation.
Definition hash.h:41
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:287
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64