/src/freeradius-server/src/lib/util/dict_validate.c
Line | Count | Source (jump to first uncovered line) |
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 | | /** Validation framework to allow protocols to set custom validation rules |
18 | | * |
19 | | * @file src/lib/util/dict_validate.c |
20 | | * |
21 | | * @copyright 2019 The FreeRADIUS server project |
22 | | */ |
23 | | RCSID("$Id: 312858ec7b631038798ee2c34ca4ced2a0ad3465 $") |
24 | | |
25 | | #include <freeradius-devel/util/dict_priv.h> |
26 | | |
27 | | /** Validate a set of flags |
28 | | * |
29 | | * @param[in] dict of protocol context we're operating in. |
30 | | * If NULL the internal dictionary will be used. |
31 | | * @param[in] parent to add attribute under. |
32 | | * @param[in] name of the attribute. |
33 | | * @param[in] attr number. |
34 | | * @param[in] type of attribute. |
35 | | * @param[in] flags to check in the attribute. |
36 | | * @return |
37 | | * - true if attribute definition is valid. |
38 | | * - false if attribute definition is not valid. |
39 | | */ |
40 | | bool dict_attr_flags_valid(fr_dict_t *dict, fr_dict_attr_t const *parent, |
41 | | char const *name, int *attr, fr_type_t type, fr_dict_attr_flags_t *flags) |
42 | 80.8k | { |
43 | 80.8k | int bit; |
44 | 80.8k | uint32_t all_flags; |
45 | 80.8k | uint32_t shift_is_root, shift_internal; |
46 | 80.8k | uint32_t shift_array, shift_has_value; |
47 | 80.8k | uint32_t shift_subtype, shift_extra; |
48 | 80.8k | uint32_t shift_counter; |
49 | 80.8k | fr_dict_attr_t const *v; |
50 | | |
51 | | /* |
52 | | * Convert the 1-bit fields into bits numbers, so that we |
53 | | * can check them in parallel. |
54 | | */ |
55 | 80.8k | all_flags = 0; |
56 | 80.8k | bit = -1; |
57 | | |
58 | 566k | #define SET_FLAG(_flag) do { shift_ ## _flag = 1 << ++bit; if (flags->_flag) all_flags |= (1 << bit); } while (0) |
59 | 80.8k | SET_FLAG(is_root); |
60 | 80.8k | SET_FLAG(internal); |
61 | 80.8k | SET_FLAG(array); |
62 | 80.8k | SET_FLAG(has_value); |
63 | 80.8k | SET_FLAG(extra); |
64 | 80.8k | SET_FLAG(counter); |
65 | 80.8k | SET_FLAG(subtype); |
66 | | |
67 | 80.8k | #define FORBID_OTHER_FLAGS(_flag) do { if (all_flags & ~shift_ ## _flag) { fr_strerror_printf("The '" STRINGIFY(_flag) "' flag cannot be used with any other flag"); return false; } } while (0) |
68 | 80.8k | #define ALLOW_FLAG(_flag) do { all_flags &= ~shift_ ## _flag; } while (0) |
69 | | |
70 | | // is_root |
71 | | // is_unknown |
72 | | // internal |
73 | | // array |
74 | | // has_value |
75 | | // extra |
76 | | // encrypt |
77 | | // length |
78 | | // type_size |
79 | | |
80 | 80.8k | if (flags->is_root) { |
81 | 0 | FORBID_OTHER_FLAGS(is_root); |
82 | 0 | } |
83 | | |
84 | 80.8k | if (flags->is_unknown) { |
85 | 0 | fr_strerror_const("The 'unknown' flag cannot be set for attributes in the dictionary."); |
86 | 0 | return false; |
87 | 0 | } |
88 | | |
89 | | /* |
90 | | * Only some data types can be in arrays, because we need |
91 | | * to be able to decode the various array members. |
92 | | */ |
93 | 80.8k | if (flags->array) { |
94 | 452 | if (!flags->is_known_width) switch (type) { |
95 | 0 | default: |
96 | 0 | fr_strerror_printf("The 'array' flag cannot be used with attributes of type '%s'", |
97 | 0 | fr_type_to_str(type)); |
98 | 0 | return false; |
99 | | |
100 | 240 | case FR_TYPE_IPV4_ADDR: |
101 | 246 | case FR_TYPE_IPV4_PREFIX: |
102 | 308 | case FR_TYPE_IPV6_ADDR: |
103 | 308 | case FR_TYPE_IPV6_PREFIX: |
104 | 314 | case FR_TYPE_UINT8: |
105 | 348 | case FR_TYPE_UINT16: |
106 | 348 | case FR_TYPE_UINT32: |
107 | 348 | case FR_TYPE_DATE: |
108 | 348 | case FR_TYPE_TIME_DELTA: |
109 | 348 | break; |
110 | | |
111 | 0 | case FR_TYPE_STRING: |
112 | 0 | case FR_TYPE_OCTETS: |
113 | 0 | if (!flags->length) { |
114 | 0 | fr_strerror_const("Variable length attributes cannot be marked as 'array'"); |
115 | 0 | return false; |
116 | 0 | } |
117 | | |
118 | 0 | flags->is_known_width = 1; |
119 | 0 | break; |
120 | | |
121 | 0 | case FR_TYPE_STRUCT: |
122 | | /* |
123 | | * If we have arrays of structs, then the structure MUST be known width. |
124 | | */ |
125 | 0 | flags->is_known_width = 1; |
126 | 0 | break; |
127 | 348 | } |
128 | | |
129 | | /* |
130 | | * DHCPv6 has arrays of string / octets, prefixed |
131 | | * with a uint16 field of "length". Also, arrays of dns_labels. |
132 | | */ |
133 | 452 | ALLOW_FLAG(extra); |
134 | 452 | ALLOW_FLAG(subtype); |
135 | | |
136 | 452 | FORBID_OTHER_FLAGS(array); |
137 | 452 | } |
138 | | |
139 | | /* |
140 | | * 'has_value' should only be set internally. If the |
141 | | * caller sets it, we still sanity check it. |
142 | | */ |
143 | 80.8k | if (flags->has_value) { |
144 | 0 | if (type != FR_TYPE_UINT32) { |
145 | 0 | fr_strerror_printf("The 'has_value' flag can only be used with attributes " |
146 | 0 | "of type 'integer'"); |
147 | 0 | return false; |
148 | 0 | } |
149 | | |
150 | 0 | FORBID_OTHER_FLAGS(has_value); |
151 | 0 | } |
152 | | |
153 | | /* |
154 | | * The "extra" flag is a grab-bag of stuff, depending on |
155 | | * the data type. |
156 | | */ |
157 | 80.8k | if (flags->extra) { |
158 | 824 | if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD) && |
159 | 824 | (flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) { |
160 | 0 | fr_strerror_const("The 'key' and 'length' flags cannot be used with any other flags."); |
161 | 0 | return false; |
162 | 0 | } |
163 | | |
164 | 824 | switch (type) { |
165 | 440 | case FR_TYPE_BOOL: |
166 | 644 | case FR_TYPE_UINT8: |
167 | 698 | case FR_TYPE_UINT16: |
168 | 730 | case FR_TYPE_UINT32: |
169 | 770 | case FR_TYPE_UINT64: |
170 | 770 | if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD)) { |
171 | 0 | fr_strerror_const("Invalid type (not 'key' field or 'bit' field) for extra flag."); |
172 | 0 | return false; |
173 | 0 | } |
174 | | |
175 | 770 | if (parent->type != FR_TYPE_STRUCT) { |
176 | 0 | fr_strerror_const("The 'key' flag can only be used inside of a 'struct'."); |
177 | 0 | return false; |
178 | 0 | } |
179 | | |
180 | 770 | ALLOW_FLAG(extra); |
181 | 770 | ALLOW_FLAG(subtype); |
182 | 770 | break; |
183 | | |
184 | 8 | case FR_TYPE_OCTETS: |
185 | 18 | case FR_TYPE_STRING: |
186 | 18 | if (flags->length != 0) { |
187 | 0 | fr_strerror_const("Cannot use [..] and length=uint..."); |
188 | 0 | return false; |
189 | 0 | } |
190 | | |
191 | | /* |
192 | | * We can do arrays of variable-length types, so long as they have a "length=" |
193 | | * modifier. |
194 | | * |
195 | | * But any other modifier is foridden, including the use of "length=" outside of |
196 | | * the context of arrays. |
197 | | */ |
198 | 18 | if (flags->array) { |
199 | 18 | ALLOW_FLAG(array); |
200 | | |
201 | 18 | if ((flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) goto invalid_extra; |
202 | 18 | } else if (flags->subtype) { |
203 | 0 | invalid_extra: |
204 | 0 | fr_strerror_const("Invalid type (not 'length=...') for extra flag."); |
205 | 0 | return false; |
206 | 0 | } |
207 | | |
208 | 18 | ALLOW_FLAG(extra); |
209 | 18 | ALLOW_FLAG(subtype); |
210 | 18 | break; |
211 | | |
212 | 36 | case FR_TYPE_STRUCT: |
213 | 36 | if ((flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) { |
214 | 0 | fr_strerror_const("Invalid type (not 'length=...') for extra flag."); |
215 | 0 | return false; |
216 | 0 | } |
217 | | |
218 | 36 | ALLOW_FLAG(extra); |
219 | 36 | ALLOW_FLAG(subtype); |
220 | 36 | ALLOW_FLAG(array); |
221 | 36 | break; |
222 | | |
223 | 0 | case FR_TYPE_TLV: |
224 | 0 | ALLOW_FLAG(extra); |
225 | | /* @todo - allow arrays of struct? */ |
226 | 0 | ALLOW_FLAG(subtype); |
227 | 0 | break; |
228 | | |
229 | 0 | default: |
230 | 0 | fr_strerror_printf("Type %s cannot hold extra flags", |
231 | 0 | fr_type_to_str(type)); |
232 | 0 | return false; |
233 | 824 | } |
234 | | |
235 | 824 | if (((flags->subtype == FLAG_LENGTH_UINT8) || (flags->subtype == FLAG_LENGTH_UINT16)) && |
236 | 824 | ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_STRUCT))) { |
237 | 0 | fr_strerror_printf("The 'length' flag cannot be used used with type %s", |
238 | 0 | fr_type_to_str(type)); |
239 | 0 | return false; |
240 | 0 | } |
241 | | |
242 | 824 | FORBID_OTHER_FLAGS(extra); |
243 | 824 | } |
244 | | |
245 | | /* |
246 | | * Force "length" for fixed-size data types which aren't |
247 | | * bit fields. Check / set "length" and "type_size" for |
248 | | * other types. |
249 | | */ |
250 | 80.8k | if (!flags->extra || (flags->subtype != FLAG_BIT_FIELD)) switch (type) { |
251 | 1.92k | case FR_TYPE_UINT8: |
252 | 2.61k | case FR_TYPE_BOOL: |
253 | 2.61k | flags->length = 1; |
254 | 2.61k | break; |
255 | | |
256 | 1.33k | case FR_TYPE_UINT16: |
257 | 1.33k | flags->length = 2; |
258 | 1.33k | break; |
259 | | |
260 | 1.08k | case FR_TYPE_DATE: |
261 | 1.76k | case FR_TYPE_TIME_DELTA: |
262 | 1.76k | if (!flags->length) flags->length = 4; |
263 | | |
264 | 1.76k | if ((flags->length != 2) && (flags->length != 4) && (flags->length != 8)) { |
265 | 0 | fr_strerror_printf("Invalid length %u for attribute of type '%s'", |
266 | 0 | flags->length, fr_type_to_str(type)); |
267 | 0 | return false; |
268 | 0 | } |
269 | 1.76k | break; |
270 | | |
271 | 3.53k | case FR_TYPE_IPV4_ADDR: |
272 | 28.9k | case FR_TYPE_UINT32: |
273 | 29.3k | case FR_TYPE_INT32: |
274 | 29.7k | case FR_TYPE_FLOAT32: |
275 | 29.7k | flags->length = 4; |
276 | 29.7k | break; |
277 | | |
278 | 1.28k | case FR_TYPE_UINT64: |
279 | 1.28k | case FR_TYPE_FLOAT64: |
280 | 1.28k | flags->length = 8; |
281 | 1.28k | break; |
282 | | |
283 | 0 | case FR_TYPE_SIZE: |
284 | 0 | flags->length = sizeof(size_t); |
285 | 0 | break; |
286 | | |
287 | 432 | case FR_TYPE_ETHERNET: |
288 | 432 | flags->length = 6; |
289 | 432 | break; |
290 | | |
291 | 72 | case FR_TYPE_IFID: |
292 | 72 | flags->length = 8; |
293 | 72 | break; |
294 | | |
295 | 786 | case FR_TYPE_IPV6_ADDR: |
296 | 906 | case FR_TYPE_COMBO_IP_ADDR: |
297 | 906 | flags->length = 16; |
298 | 906 | break; |
299 | | |
300 | 188 | case FR_TYPE_IPV6_PREFIX: |
301 | 188 | case FR_TYPE_COMBO_IP_PREFIX: |
302 | 188 | flags->length = 17; |
303 | 188 | break; |
304 | | |
305 | 1.25k | case FR_TYPE_STRUCT: |
306 | 1.25k | ALLOW_FLAG(internal); |
307 | 1.25k | ALLOW_FLAG(array); |
308 | 1.25k | if (all_flags) { |
309 | 0 | fr_strerror_const("Invalid flag for attribute of type 'struct'"); |
310 | 0 | return false; |
311 | 0 | } |
312 | 1.25k | break; |
313 | | |
314 | 4.29k | case FR_TYPE_VENDOR: |
315 | 4.29k | if (parent->type != FR_TYPE_VSA) { |
316 | 0 | fr_strerror_printf("Attributes of type 'vendor' MUST have a parent of type 'vsa' " |
317 | 0 | "instead of '%s'", |
318 | 0 | fr_type_to_str(parent->type)); |
319 | 0 | return false; |
320 | 0 | } |
321 | | |
322 | 4.29k | if (flags->length) { |
323 | 0 | if ((flags->length != 1) && |
324 | 0 | (flags->length != 2) && |
325 | 0 | (flags->length != 4)) { |
326 | 0 | fr_strerror_const("The 'length' flag can only be used for attributes of type 'vendor' with lengths of 1,2 or 4"); |
327 | 0 | return false; |
328 | 0 | } |
329 | | |
330 | 0 | break; |
331 | 0 | } |
332 | | |
333 | | /* |
334 | | * Set the length / type_size of vendor |
335 | | * attributes from the vendor definition. |
336 | | */ |
337 | 4.29k | flags->type_size = 1; |
338 | 4.29k | flags->length = 1; |
339 | 4.29k | if (attr) { |
340 | 4.29k | fr_dict_vendor_t const *dv; |
341 | | |
342 | 4.29k | dv = fr_dict_vendor_by_num(dict, *attr); |
343 | 4.29k | if (dv) { |
344 | 4.29k | flags->type_size = dv->type; |
345 | 4.29k | flags->length = dv->length; |
346 | 4.29k | } |
347 | 4.29k | } |
348 | 4.29k | break; |
349 | | |
350 | 994 | case FR_TYPE_TLV: |
351 | 994 | if (flags->length) { |
352 | 466 | if ((flags->length != 1) && |
353 | 466 | (flags->length != 2) && |
354 | 466 | (flags->length != 4)) { |
355 | 0 | fr_strerror_const("The 'length' flag can only be used for attributes of type 'tlv' with lengths of 1,2 or 4"); |
356 | 0 | return false; |
357 | 0 | } |
358 | | |
359 | 466 | break; |
360 | 466 | } |
361 | | |
362 | | /* |
363 | | * Find an appropriate parent to copy the |
364 | | * TLV-specific fields from. |
365 | | */ |
366 | 540 | for (v = parent; v != NULL; v = v->parent) { |
367 | 540 | if ((v->type == FR_TYPE_TLV) || (v->type == FR_TYPE_VENDOR)) { |
368 | 528 | break; |
369 | 528 | } |
370 | 540 | } |
371 | | |
372 | | /* |
373 | | * root is always FR_TYPE_TLV, so we're OK. |
374 | | */ |
375 | 528 | if (!v) { |
376 | 0 | fr_strerror_printf("Attributes of type '%s' require a parent attribute", |
377 | 0 | fr_type_to_str(type)); |
378 | 0 | return false; |
379 | 0 | } |
380 | | |
381 | | /* |
382 | | * Over-ride whatever was there before, so we |
383 | | * don't have multiple formats of VSAs. |
384 | | */ |
385 | 528 | flags->type_size = v->flags.type_size; |
386 | 528 | flags->length = v->flags.length; |
387 | 528 | break; |
388 | | |
389 | | /* |
390 | | * 'octets[n]' can only be used in a few limited situations. |
391 | | */ |
392 | 6.53k | case FR_TYPE_OCTETS: |
393 | 6.53k | if (flags->length) { |
394 | | /* |
395 | | * Internal attributes can use octets[n] |
396 | | * MS-MPPE-Keys use octets[18],encrypt=1 |
397 | | * EAP-SIM-RAND uses array |
398 | | */ |
399 | 430 | ALLOW_FLAG(internal); |
400 | 430 | ALLOW_FLAG(subtype); |
401 | 430 | ALLOW_FLAG(array); |
402 | | |
403 | 430 | if (all_flags) { |
404 | 0 | fr_strerror_const("The 'octets[...]' syntax cannot be used any other flag"); |
405 | 0 | return false; |
406 | 0 | } |
407 | | |
408 | 430 | if (flags->length > 253) { |
409 | 0 | fr_strerror_printf("Invalid length %d", flags->length); |
410 | 0 | return false; |
411 | 0 | } |
412 | 430 | } |
413 | 6.53k | break; |
414 | | |
415 | 6.53k | case FR_TYPE_NULL: |
416 | 0 | fr_strerror_printf("Attributes of type '%s' cannot be used in dictionaries", |
417 | 0 | fr_type_to_str(type)); |
418 | 0 | return false; |
419 | | |
420 | 28.7k | default: |
421 | 28.7k | break; |
422 | 80.1k | } |
423 | | |
424 | | /* |
425 | | * type_size is used to limit the maximum attribute number, so it's checked first. |
426 | | */ |
427 | 80.8k | if (flags->type_size) { |
428 | 6.12k | if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) { |
429 | | /* |
430 | | * Allow all time res here |
431 | | */ |
432 | 5.93k | } else if (!flags->extra) { |
433 | 5.28k | if ((type != FR_TYPE_TLV) && (type != FR_TYPE_VENDOR)) { |
434 | 0 | fr_strerror_const("The 'format=' flag can only be used with attributes of type 'tlv'"); |
435 | 0 | return false; |
436 | 0 | } |
437 | | |
438 | 5.28k | if ((flags->type_size != 1) && |
439 | 5.28k | (flags->type_size != 2) && |
440 | 5.28k | (flags->type_size != 4)) { |
441 | 0 | fr_strerror_const("The 'format=' flag can only be used with attributes of type size 1,2 or 4"); |
442 | 0 | return false; |
443 | 0 | } |
444 | 5.28k | } |
445 | 6.12k | } |
446 | | |
447 | | /* |
448 | | * Counters can be time deltas, or unsigned integers. |
449 | | * For other data types, we don't know how to |
450 | | * automatically add two counters. |
451 | | */ |
452 | 80.8k | if (flags->counter) { |
453 | 0 | if ((type == FR_TYPE_TIME_DELTA) || (fr_type_is_integer(type) && !fr_type_is_signed(type))) { |
454 | 0 | ALLOW_FLAG(counter); |
455 | 0 | } else { |
456 | 0 | fr_strerror_printf("The 'counter' flag cannot be used with '%s'", fr_type_to_str(type)); |
457 | 0 | return false; |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | | /* |
462 | | * Check flags against the parent attribute. |
463 | | */ |
464 | 80.8k | switch (parent->type) { |
465 | 3.91k | case FR_TYPE_STRUCT: |
466 | 3.91k | ALLOW_FLAG(extra); |
467 | 3.91k | ALLOW_FLAG(subtype); |
468 | | |
469 | 3.91k | if (parent->flags.is_known_width && !flags->is_known_width && !flags->length) { |
470 | 0 | fr_strerror_const("Variable-sized fields cannot be used within a 'struct' which is 'array'"); |
471 | 0 | return false; |
472 | 0 | } |
473 | | |
474 | 3.91k | if (flags->array) { |
475 | 38 | switch (type) { |
476 | 18 | case FR_TYPE_FIXED_SIZE: |
477 | 18 | ALLOW_FLAG(array); |
478 | 18 | break; |
479 | | |
480 | 20 | default: |
481 | 20 | if (flags->is_known_width) ALLOW_FLAG(array); |
482 | 20 | break; |
483 | 38 | } |
484 | 38 | } |
485 | | |
486 | 3.91k | if (all_flags) { |
487 | 0 | fr_strerror_const("Invalid flag for attribute inside of a 'struct'"); |
488 | 0 | return false; |
489 | 0 | } |
490 | | |
491 | 3.91k | if (!attr) break; |
492 | | |
493 | | /* |
494 | | * If we have keyed structs, then the first |
495 | | * member can be variable length. |
496 | | * |
497 | | * For subsequent children, have each one check |
498 | | * the previous child. |
499 | | */ |
500 | 2.01k | if (*attr != 1) { |
501 | 1.25k | int i; |
502 | 1.25k | fr_dict_attr_t const *sibling; |
503 | | |
504 | 1.25k | sibling = fr_dict_attr_child_by_num(parent, (*attr) - 1); |
505 | 1.25k | if (!sibling) { |
506 | 0 | fr_strerror_printf("Child \"%s\" of 'struct' attribute \"%s\" MUST be " |
507 | 0 | "numbered consecutively %u.", |
508 | 0 | name, parent->name, *attr); |
509 | 0 | return false; |
510 | 0 | } |
511 | | |
512 | | /* |
513 | | * Variable sized elements cannot have anything after them in a struct. |
514 | | */ |
515 | 1.25k | if (!sibling->flags.length && !sibling->flags.is_known_width) { |
516 | 0 | fr_strerror_const("No other field can follow a struct MEMBER which is variable sized"); |
517 | 0 | return false; |
518 | 0 | } |
519 | | |
520 | | /* |
521 | | * The same goes for arrays. |
522 | | */ |
523 | 1.25k | if (sibling->flags.array) { |
524 | 0 | fr_strerror_const("No other field can follow a struct MEMBER which is 'array'"); |
525 | 0 | return false; |
526 | 0 | } |
527 | | |
528 | | /* |
529 | | * Check for bad key fields, or multiple |
530 | | * key fields. Yes, this is O(N^2), but |
531 | | * the structs are small. |
532 | | */ |
533 | 1.25k | if (flags->extra && (flags->subtype == FLAG_KEY_FIELD)) { |
534 | 50 | for (i = 1; i < *attr; i++) { |
535 | 40 | sibling = fr_dict_attr_child_by_num(parent, i); |
536 | 40 | if (!sibling) { |
537 | 0 | fr_strerror_printf("Child %d of 'struct' type attribute %s does not exist.", |
538 | 0 | i, parent->name); |
539 | 0 | return false; |
540 | 0 | } |
541 | | |
542 | 40 | if (!fr_dict_attr_is_key_field(sibling)) continue; |
543 | | |
544 | 0 | fr_strerror_printf("Duplicate key attributes '%s' and '%s' in 'struct' type attribute %s are forbidden", |
545 | 0 | name, sibling->name, parent->name); |
546 | 0 | return false; |
547 | 40 | } |
548 | 10 | } |
549 | 1.25k | } |
550 | 2.01k | break; |
551 | | |
552 | 4.29k | case FR_TYPE_VSA: |
553 | 4.29k | if ((type != FR_TYPE_VENDOR) && !flags->internal) { |
554 | 0 | fr_strerror_printf("Attributes of type '%s' cannot be children of the 'vsa' type", |
555 | 0 | fr_type_to_str(type)); |
556 | 0 | return false; |
557 | 0 | } |
558 | 4.29k | break; |
559 | | |
560 | 21.2k | case FR_TYPE_TLV: |
561 | 72.4k | case FR_TYPE_VENDOR: |
562 | 72.4k | break; |
563 | | |
564 | | /* |
565 | | * "key" fields inside of a STRUCT can have |
566 | | * children, even if they are integer data type. |
567 | | */ |
568 | 52 | case FR_TYPE_UINT8: |
569 | 252 | case FR_TYPE_UINT16: |
570 | 252 | case FR_TYPE_UINT32: |
571 | 252 | if (fr_dict_attr_is_key_field(parent)) break; |
572 | 252 | FALL_THROUGH; |
573 | | |
574 | 0 | default: |
575 | 0 | fr_strerror_printf("Attributes of type '%s' cannot have child attributes", |
576 | 0 | fr_type_to_str(parent->type)); |
577 | 0 | return false; |
578 | 80.8k | } |
579 | | |
580 | 80.8k | return true; |
581 | 80.8k | } |
582 | | |
583 | | |
584 | | /** Validate a new attribute definition |
585 | | * |
586 | | * @todo we need to check length of none vendor attributes. |
587 | | * |
588 | | * @param[in] dict of protocol context we're operating in. |
589 | | * If NULL the internal dictionary will be used. |
590 | | * @param[in] parent to add attribute under. |
591 | | * @param[in] name of the attribute. |
592 | | * @param[in] attr number. |
593 | | * @param[in] type of attribute. |
594 | | * @param[in] flags to set in the attribute. |
595 | | * @return |
596 | | * - true if attribute definition is valid. |
597 | | * - false if attribute definition is not valid. |
598 | | */ |
599 | | bool dict_attr_fields_valid(fr_dict_t *dict, fr_dict_attr_t const *parent, |
600 | | char const *name, int *attr, fr_type_t type, fr_dict_attr_flags_t *flags) |
601 | 43.4k | { |
602 | 43.4k | fr_dict_attr_t const *v; |
603 | 43.4k | fr_dict_attr_t *mutable; |
604 | | |
605 | 43.4k | if (!fr_cond_assert(parent)) return false; |
606 | | |
607 | 43.4k | if (fr_dict_valid_name(name, -1) <= 0) return false; |
608 | | |
609 | 43.4k | mutable = UNCONST(fr_dict_attr_t *, parent); |
610 | | |
611 | | /******************** sanity check attribute number ********************/ |
612 | | |
613 | | /* |
614 | | * The value -1 is the special flag for "self |
615 | | * allocated" numbers. i.e. we want an |
616 | | * attribute, but we don't care what the number |
617 | | * is. |
618 | | */ |
619 | 43.4k | if (*attr == -1) { |
620 | | /* |
621 | | * If we don't care about the number, then this attribute is almost always |
622 | | * an internal one. Unless it's a "name only" attribute for string-based |
623 | | * protocols. |
624 | | * |
625 | | * We can use DEFINE in number-based protocol dictionaries, and the attributes will be |
626 | | * marked up as "internal". |
627 | | */ |
628 | 74 | flags->internal |= !flags->name_only | !dict->string_based; |
629 | | |
630 | 74 | v = fr_dict_attr_by_name(NULL, parent, name); |
631 | 74 | if (v) { |
632 | 0 | fr_dict_attr_flags_t cmp; |
633 | | |
634 | | /* |
635 | | * Exact duplicates are allowed. The caller will take care of |
636 | | * not inserting the duplicate attribute. |
637 | | */ |
638 | 0 | if (v->type != type) { |
639 | 0 | fr_strerror_printf("Conflicting type (asked %s, found %s) for re-definition for attribute %s", |
640 | 0 | fr_type_to_str(type), fr_type_to_str(v->type), name); |
641 | 0 | return false; |
642 | 0 | } |
643 | | |
644 | | /* |
645 | | * 'has_value' is set if we define VALUEs for it. But the new definition doesn't |
646 | | * know that yet. |
647 | | */ |
648 | 0 | cmp = v->flags; |
649 | 0 | cmp.has_value = 0; |
650 | |
|
651 | 0 | if (memcmp(&cmp, flags, sizeof(*flags)) != 0) { |
652 | 0 | fr_strerror_printf("Conflicting flags for re-definition for attribute %s", name); |
653 | 0 | return false; |
654 | 0 | } |
655 | | |
656 | 0 | return true; |
657 | 0 | } |
658 | | |
659 | 74 | *attr = ++mutable->last_child_attr; |
660 | | |
661 | 43.3k | } else if (*attr < 0) { |
662 | 0 | fr_strerror_printf("ATTRIBUTE number %i is invalid, must be greater than zero", *attr); |
663 | 0 | return false; |
664 | |
|
665 | 43.3k | } else if ((unsigned int) *attr > mutable->last_child_attr) { |
666 | 0 | mutable->last_child_attr = *attr; |
667 | | |
668 | | /* |
669 | | * If the attribute is outside of the bounds of |
670 | | * the type size, then it MUST be an internal |
671 | | * attribute. Set the flag in this attribute, so |
672 | | * that the encoder doesn't have to do complex |
673 | | * checks. |
674 | | */ |
675 | 0 | if ((uint64_t) *attr >= (((uint64_t)1) << (8 * parent->flags.type_size))) flags->internal = true; |
676 | 0 | } |
677 | | |
678 | | /* |
679 | | * Initialize the length field, which is needed for the attr_valid() callback. |
680 | | */ |
681 | 43.4k | if (!flags->length && fr_type_is_leaf(type) && !fr_type_is_variable_size(type)) { |
682 | 770 | fr_value_box_t box; |
683 | | |
684 | 770 | fr_value_box_init(&box, type, NULL, false); |
685 | 770 | flags->length = fr_value_box_network_length(&box); |
686 | 770 | } |
687 | | |
688 | 43.4k | if (type == FR_TYPE_STRUCT) flags->is_known_width |= flags->array; |
689 | | |
690 | | /* |
691 | | * Run protocol-specific validation functions, BEFORE we |
692 | | * do the rest of the checks. |
693 | | */ |
694 | 43.4k | if (dict->attr_valid && !dict->attr_valid(dict, parent, name, *attr, type, flags)) return false; |
695 | | |
696 | | /* |
697 | | * Check the flags, data types, and parent data types and flags. |
698 | | */ |
699 | 43.4k | if (!dict_attr_flags_valid(dict, parent, name, attr, type, flags)) return false; |
700 | | |
701 | 43.4k | return true; |
702 | 43.4k | } |