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