The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_validate.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/** 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 * @copyright 2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: 38643c6f0d15668455a176fb6575a838a139f78d $")
25
26#include <freeradius-devel/util/dict_priv.h>
27
28/** Validate a set of flags
29 *
30 * @param[in] da to check.
31 * @return
32 * - true if attribute definition is valid.
33 * - false if attribute definition is not valid.
34 */
36{
37 int bit;
38 uint32_t all_flags;
39 uint32_t shift_is_root, shift_internal;
40 uint32_t shift_array, shift_has_value;
41 uint32_t shift_subtype, shift_extra;
42 uint32_t shift_counter;
43 fr_dict_attr_t const *v;
44 fr_dict_t *dict = da->dict;
45 fr_dict_attr_t const *parent = da->parent;
46 char const *name = da->name;
47 int attr = da->attr;
48 fr_type_t type = da->type;
49 fr_dict_attr_flags_t *flags = &da->flags;
50
51 /*
52 * Convert the 1-bit fields into bits numbers, so that we
53 * can check them in parallel.
54 */
55 all_flags = 0;
56 bit = -1;
57
58#define SET_FLAG(_flag) do { shift_ ## _flag = 1 << ++bit; if (flags->_flag) all_flags |= (1 << bit); } while (0)
59 SET_FLAG(is_root);
60 SET_FLAG(internal);
61 SET_FLAG(array);
62 SET_FLAG(has_value);
63 SET_FLAG(extra);
64 SET_FLAG(counter);
65 SET_FLAG(subtype);
66
67#define FORBID_OTHER_FLAGS(_flag, _allowed) \
68 do { \
69 if (all_flags & ~shift_ ## _flag & ~(_allowed)) { \
70 fr_strerror_printf("The '" STRINGIFY(_flag) "' flag cannot be used with any other flag (%u) %s[%d]", all_flags, da->filename, da->line); \
71 return false; \
72 } \
73 } while (0)
74
75#define ALLOW_FLAG(_flag) do { all_flags &= ~shift_ ## _flag; } while (0)
76
77 // is_root
78 // is_unknown
79 // internal
80 // array
81 // has_value
82 // extra
83 // encrypt
84 // length
85 // type_size
86
87 if (flags->is_root) {
88 FORBID_OTHER_FLAGS(is_root, 0);
89 }
90
91 if (flags->is_unknown) {
92 fr_strerror_const("The 'unknown' flag cannot be set for attributes in the dictionary.");
93 return false;
94 }
95
96 if (flags->local != parent->flags.local) {
97 fr_strerror_const("Cannot mix local variables with non-local attributes");
98 return false;
99 }
100
101 /*
102 * Only some data types can be in arrays, because we need
103 * to be able to decode the various array members.
104 */
105 if (flags->array) {
106 if (!flags->is_known_width) switch (type) {
107 default:
108 fr_strerror_printf("The 'array' flag cannot be used with attributes of type '%s'",
110 return false;
111
116 case FR_TYPE_UINT8:
117 case FR_TYPE_UINT16:
118 case FR_TYPE_UINT32:
119 case FR_TYPE_DATE:
121 break;
122
123 case FR_TYPE_STRING:
124 case FR_TYPE_OCTETS:
125 if (!flags->length) {
126 fr_strerror_const("Variable length attributes cannot be marked as 'array'");
127 return false;
128 }
129
130 flags->is_known_width = 1;
131 break;
132
133 case FR_TYPE_STRUCT:
134 /*
135 * If we have arrays of structs, then the structure MUST be known width.
136 */
137 flags->is_known_width = 1;
138 break;
139 }
140
141 /*
142 * DHCPv6 has arrays of string / octets, prefixed
143 * with a uint16 field of "length". Also, arrays of dns_labels.
144 */
145 ALLOW_FLAG(extra);
146 ALLOW_FLAG(subtype);
147
148 FORBID_OTHER_FLAGS(array, 0);
149 }
150
151 /*
152 * 'has_value' should only be set internally. If the
153 * caller sets it, we still sanity check it.
154 */
155 if (flags->has_value) {
156 if (type != FR_TYPE_UINT32) {
157 fr_strerror_printf("The 'has_value' flag can only be used with attributes "
158 "of type 'integer'");
159 return false;
160 }
161
162 FORBID_OTHER_FLAGS(has_value, shift_internal);
163 }
164
165 /*
166 * The "extra" flag is a grab-bag of stuff, depending on
167 * the data type.
168 */
169 if (flags->extra) {
170 if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD) &&
171 (flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) {
172 fr_strerror_const("The 'key' and 'length' flags cannot be used with any other flags.");
173 return false;
174 }
175
176 switch (type) {
177 case FR_TYPE_BOOL:
178 case FR_TYPE_UINT8:
179 case FR_TYPE_UINT16:
180 case FR_TYPE_UINT32:
181 case FR_TYPE_UINT64:
182 if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD)) {
183 fr_strerror_const("Invalid type (not 'key' field or 'bit' field) for extra flag.");
184 return false;
185 }
186
187 if (parent->type != FR_TYPE_STRUCT) {
188 fr_strerror_const("The 'key' flag can only be used inside of a 'struct'.");
189 return false;
190 }
191
192 ALLOW_FLAG(extra);
193 ALLOW_FLAG(subtype);
194 break;
195
196 case FR_TYPE_OCTETS:
197 case FR_TYPE_STRING:
198 if (flags->length != 0) {
199 fr_strerror_const("Cannot use [..] and length=uint...");
200 return false;
201 }
202
203 /*
204 * We can do arrays of variable-length types, so long as they have a "length="
205 * modifier.
206 *
207 * But any other modifier is foridden, including the use of "length=" outside of
208 * the context of arrays.
209 */
210 if (flags->array) {
211 ALLOW_FLAG(array);
212
213 if ((flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) goto invalid_extra;
214 } else if (flags->subtype) {
215 invalid_extra:
216 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
217 return false;
218 }
219
220 ALLOW_FLAG(extra);
221 ALLOW_FLAG(subtype);
222 break;
223
224 case FR_TYPE_STRUCT:
225 if ((flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) {
226 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
227 return false;
228 }
229
230 ALLOW_FLAG(extra);
231 ALLOW_FLAG(subtype);
232 ALLOW_FLAG(array);
233 break;
234
235 case FR_TYPE_TLV:
236 ALLOW_FLAG(extra);
237 /* @todo - allow arrays of struct? */
238 ALLOW_FLAG(subtype);
239 break;
240
241 default:
242 fr_strerror_printf("Type %s cannot hold extra flags",
244 return false;
245 }
246
247 if (((flags->subtype == FLAG_LENGTH_UINT8) || (flags->subtype == FLAG_LENGTH_UINT16)) &&
248 ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_STRUCT))) {
249 fr_strerror_printf("The 'length' flag cannot be used used with type %s",
251 return false;
252 }
253
254 FORBID_OTHER_FLAGS(extra, 0);
255 }
256
257 /*
258 * Force "length" for fixed-size data types which aren't
259 * bit fields. Check / set "length" and "type_size" for
260 * other types.
261 */
262 if (!flags->extra || (flags->subtype != FLAG_BIT_FIELD)) switch (type) {
263 case FR_TYPE_UINT8:
264 case FR_TYPE_BOOL:
265 flags->length = 1;
266 break;
267
268 case FR_TYPE_UINT16:
269 flags->length = 2;
270 break;
271
272 case FR_TYPE_DATE:
274 if (!flags->length) flags->length = 4;
275
276 if ((flags->length != 2) && (flags->length != 4) && (flags->length != 8)) {
277 fr_strerror_printf("Invalid length %u for attribute of type '%s'",
278 flags->length, fr_type_to_str(type));
279 return false;
280 }
281 break;
282
284 case FR_TYPE_UINT32:
285 case FR_TYPE_INT32:
286 case FR_TYPE_FLOAT32:
287 flags->length = 4;
288 break;
289
290 case FR_TYPE_UINT64:
291 case FR_TYPE_FLOAT64:
292 flags->length = 8;
293 break;
294
295 case FR_TYPE_SIZE:
296 flags->length = sizeof(size_t);
297 break;
298
299 case FR_TYPE_ETHERNET:
300 flags->length = 6;
301 break;
302
303 case FR_TYPE_IFID:
304 flags->length = 8;
305 break;
306
309 flags->length = 16;
310 break;
311
314 flags->length = 17;
315 break;
316
317 case FR_TYPE_STRUCT:
318 ALLOW_FLAG(internal);
319 ALLOW_FLAG(array);
320 if (all_flags) {
321 fr_strerror_const("Invalid flag for attribute of type 'struct'");
322 return false;
323 }
324 break;
325
326 case FR_TYPE_VENDOR:
327 if (parent->type != FR_TYPE_VSA) {
328 fr_strerror_printf("Attributes of type 'vendor' MUST have a parent of type 'vsa' "
329 "instead of '%s'",
330 fr_type_to_str(parent->type));
331 return false;
332 }
333
334 if (flags->length) {
335 if ((flags->length != 1) &&
336 (flags->length != 2) &&
337 (flags->length != 4)) {
338 fr_strerror_const("The 'length' flag can only be used for attributes of type 'vendor' with lengths of 1,2 or 4");
339 return false;
340 }
341
342 break;
343 }
344
345 /*
346 * Set the length / type_size of vendor
347 * attributes from the vendor definition.
348 */
349 flags->type_size = 1;
350 flags->length = 1;
351 if (attr > 0) {
352 fr_dict_vendor_t const *dv;
353
354 dv = fr_dict_vendor_by_num(dict, attr);
355 if (dv) {
356 flags->type_size = dv->type;
357 flags->length = dv->length;
358 }
359 }
360 break;
361
362 case FR_TYPE_TLV:
363 if (flags->length) {
364 if ((flags->length != 1) &&
365 (flags->length != 2) &&
366 (flags->length != 4)) {
367 fr_strerror_const("The 'length' flag can only be used for attributes of type 'tlv' with lengths of 1,2 or 4");
368 return false;
369 }
370
371 break;
372 }
373
374 /*
375 * Find an appropriate parent to copy the
376 * TLV-specific fields from.
377 */
378 for (v = parent; v != NULL; v = v->parent) {
379 if ((v->type == FR_TYPE_TLV) || (v->type == FR_TYPE_VENDOR)) {
380 break;
381 }
382 }
383
384 /*
385 * root is always FR_TYPE_TLV, so we're OK.
386 */
387 if (!v) {
388 fr_strerror_printf("Attributes of type '%s' require a parent attribute",
390 return false;
391 }
392
393 /*
394 * Over-ride whatever was there before, so we
395 * don't have multiple formats of VSAs.
396 */
397 flags->type_size = v->flags.type_size;
398 flags->length = v->flags.length;
399 break;
400
401 /*
402 * 'octets[n]' can only be used in a few limited situations.
403 */
404 case FR_TYPE_OCTETS:
405 if (flags->length) {
406 /*
407 * Internal attributes can use octets[n]
408 * MS-MPPE-Keys use octets[18],encrypt=User-Password
409 * EAP-SIM-RAND uses array
410 */
411 ALLOW_FLAG(internal);
412 ALLOW_FLAG(subtype);
413 ALLOW_FLAG(array);
414
415 if (all_flags) {
416 fr_strerror_const("The 'octets[...]' syntax cannot be used any other flag");
417 return false;
418 }
419
420 if (flags->length > 253) {
421 fr_strerror_printf("Invalid length %d", flags->length);
422 return false;
423 }
424 }
425 break;
426
427 case FR_TYPE_NULL:
428 fr_strerror_printf("Attributes of type '%s' cannot be used in dictionaries",
430 return false;
431
432 default:
433 break;
434 }
435
436 /*
437 * type_size is used to limit the maximum attribute number, so it's checked first.
438 */
439 if (flags->type_size) {
440 if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
441 /*
442 * Allow all time res here
443 */
444 } else if (!flags->extra) {
445 if ((type != FR_TYPE_TLV) && (type != FR_TYPE_VENDOR)) {
446 fr_strerror_const("The 'format=' flag can only be used with attributes of type 'tlv'");
447 return false;
448 }
449
450 if ((flags->type_size != 1) &&
451 (flags->type_size != 2) &&
452 (flags->type_size != 4)) {
453 fr_strerror_const("The 'format=' flag can only be used with attributes of type size 1,2 or 4");
454 return false;
455 }
456 }
457 }
458
459 /*
460 * Counters can be time deltas, or unsigned integers.
461 * For other data types, we don't know how to
462 * automatically add two counters.
463 */
464 if (flags->counter) {
466 ALLOW_FLAG(counter);
467 } else {
468 fr_strerror_printf("The 'counter' flag cannot be used with '%s'", fr_type_to_str(type));
469 return false;
470 }
471 }
472
473 /*
474 * Check flags against the parent attribute.
475 */
476 switch (parent->type) {
477 case FR_TYPE_STRUCT:
478 ALLOW_FLAG(extra);
479 ALLOW_FLAG(subtype);
480
481 if (parent->flags.is_known_width && !flags->is_known_width && !flags->length) {
482 fr_strerror_const("Variable-sized fields cannot be used within a 'struct' which is 'array'");
483 return false;
484 }
485
486 if (flags->array) {
487 switch (type) {
489 ALLOW_FLAG(array);
490 break;
491
492 default:
493 if (flags->is_known_width) ALLOW_FLAG(array);
494 break;
495 }
496 }
497
498 if (all_flags) {
499 fr_strerror_const("Invalid flag for attribute inside of a 'struct'");
500 return false;
501 }
502
503 if (!attr) break;
504
505 /*
506 * If we have keyed structs, then the first
507 * member can be variable length.
508 *
509 * For subsequent children, have each one check
510 * the previous child.
511 */
512 if (attr != 1) {
513 int i;
514 fr_dict_attr_t const *sibling;
515
516 sibling = fr_dict_attr_child_by_num(parent, (attr) - 1);
517
518 /*
519 * sibling might not exist, if it's a deferred 'tlv clone=...'
520 */
521
522 /*
523 * Variable sized elements cannot have anything after them in a struct.
524 */
525 if (sibling && !sibling->flags.length && !sibling->flags.is_known_width) {
526 fr_strerror_const("No other field can follow a struct MEMBER which is variable sized");
527 return false;
528 }
529
530 /*
531 * The same goes for arrays.
532 */
533 if (sibling && sibling->flags.array) {
534 fr_strerror_const("No other field can follow a struct MEMBER which is 'array'");
535 return false;
536 }
537
538 /*
539 * Check for bad key fields, or multiple
540 * key fields. Yes, this is O(N^2), but
541 * the structs are small.
542 */
543 if (flags->extra && (flags->subtype == FLAG_KEY_FIELD)) {
544 for (i = 1; i < attr; i++) {
545 sibling = fr_dict_attr_child_by_num(parent, i);
546 if (!sibling) {
547 fr_strerror_printf("Child %d of 'struct' type attribute %s does not exist.",
548 i, parent->name);
549 return false;
550 }
551
552 if (!fr_dict_attr_is_key_field(sibling)) continue;
553
554 fr_strerror_printf("Duplicate key attributes '%s' and '%s' in 'struct' type attribute %s are forbidden",
555 name, sibling->name, parent->name);
556 return false;
557 }
558 }
559 }
560 break;
561
562 case FR_TYPE_VSA:
563 if ((type != FR_TYPE_VENDOR) && !flags->internal) {
564 fr_strerror_printf("Attributes of type '%s' cannot be children of the 'vsa' type",
566 return false;
567 }
568 break;
569
570 case FR_TYPE_TLV:
571 case FR_TYPE_VENDOR:
572 break;
573
574 /*
575 * "key" fields inside of a STRUCT can have
576 * children, even if they are integer data type.
577 */
578 case FR_TYPE_UINT8:
579 case FR_TYPE_UINT16:
580 case FR_TYPE_UINT32:
583
584 default:
585 fr_strerror_printf("Attributes of type '%s' cannot have child attributes",
586 fr_type_to_str(parent->type));
587 return false;
588 }
589
590 return true;
591}
592
593
594/** Validate a new attribute definition
595 *
596 * @todo we need to check length of none vendor attributes.
597 *
598 * @param[in] da to validate.
599 * @return
600 * - true if attribute definition is valid.
601 * - false if attribute definition is not valid.
602 */
604{
605 if (!fr_cond_assert(da->parent)) return false;
606
607 if (fr_dict_valid_name(da->name, -1) <= 0) return false;
608
609 /*
610 * Run protocol-specific validation functions, BEFORE we
611 * do the rest of the checks.
612 */
613 if (da->dict->proto->attr.valid && !da->dict->proto->attr.valid(da)) return false;
614
615 /*
616 * Check the flags, data types, and parent data types and flags.
617 */
618 if (!dict_attr_flags_valid(da)) return false;
619
620 return true;
621}
#define RCSID(id)
Definition build.h:483
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
size_t type
Length of type data.
Definition dict.h:248
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:149
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition dict.h:150
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition dict.h:147
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition dict.h:148
unsigned int has_value
Has a value.
Definition dict.h:93
unsigned int is_root
Is root of a dictionary.
Definition dict.h:75
unsigned int array
Pack multiples into 1 attr.
Definition dict.h:89
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition dict.h:113
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:87
uint8_t type_size
For TLV2 and root attributes.
Definition dict.h:136
size_t length
Length of length data.
Definition dict.h:249
unsigned int local
is a local variable
Definition dict.h:115
unsigned int is_known_width
is treated as if it has a known width for structs
Definition dict.h:91
fr_dict_vendor_t const * fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen)
Look up a vendor by its PEN.
Definition dict_util.c:2680
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4620
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3328
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:153
uint8_t subtype
protocol-specific values, OR key fields
Definition dict.h:122
uint8_t length
length of the attribute
Definition dict.h:128
unsigned int counter
integer attribute is actually an impulse / counter
Definition dict.h:97
unsigned int is_unknown
This dictionary attribute is ephemeral and not part of the main dictionary.
Definition dict.h:77
Values of the encryption flags.
Private enterprise.
Definition dict.h:245
#define FORBID_OTHER_FLAGS(_flag, _allowed)
bool dict_attr_flags_valid(fr_dict_attr_t *da)
Validate a set of flags.
bool dict_attr_valid(fr_dict_attr_t *da)
Validate a new attribute definition.
#define ALLOW_FLAG(_flag)
#define SET_FLAG(_flag)
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
unsigned long int size_t
static char const * name
fr_aka_sim_id_type_t type
static fr_slen_t parent
Definition pair.h:851
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_signed(_x)
Definition types.h:362
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
#define fr_type_is_integer(_x)
Definition types.h:360
#define FR_TYPE_FIXED_SIZE
Definition types.h:290