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