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: 46f36bc666e5b1503f711390d5ad740904ffa73a $")
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_ATTR:
124 flags->is_known_width = 1;
125 break;
126
127 case FR_TYPE_STRING:
128 case FR_TYPE_OCTETS:
129 if (!flags->length) {
130 fr_strerror_const("Variable length attributes cannot be marked as 'array'");
131 return false;
132 }
133
134 flags->is_known_width = 1;
135 break;
136
137 case FR_TYPE_STRUCT:
138 /*
139 * If we have arrays of structs, then the structure MUST be known width.
140 */
141 flags->is_known_width = 1;
142 break;
143 }
144
145 /*
146 * DHCPv6 has arrays of string / octets, prefixed
147 * with a uint16 field of "length". Also, arrays of dns_labels.
148 */
149 ALLOW_FLAG(extra);
150 ALLOW_FLAG(subtype);
151
152 FORBID_OTHER_FLAGS(array, 0);
153 }
154
155 /*
156 * 'has_value' should only be set internally. If the
157 * caller sets it, we still sanity check it.
158 */
159 if (flags->has_value) {
160 if (type != FR_TYPE_UINT32) {
161 fr_strerror_printf("The 'has_value' flag can only be used with attributes "
162 "of type 'integer'");
163 return false;
164 }
165
166 FORBID_OTHER_FLAGS(has_value, shift_internal);
167 }
168
169 /*
170 * The "extra" flag is a grab-bag of stuff, depending on
171 * the data type.
172 */
173 if (flags->extra) {
174 if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD) &&
175 (flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) {
176 fr_strerror_const("The 'key' and 'length' flags cannot be used with any other flags.");
177 return false;
178 }
179
180 switch (type) {
181 case FR_TYPE_BOOL:
182 case FR_TYPE_UINT8:
183 case FR_TYPE_UINT16:
184 case FR_TYPE_UINT32:
185 case FR_TYPE_UINT64:
186 if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_BIT_FIELD)) {
187 fr_strerror_const("Invalid type (not 'key' field or 'bit' field) for extra flag.");
188 return false;
189 }
190
191 if (parent->type != FR_TYPE_STRUCT) {
192 fr_strerror_const("The 'key' flag can only be used inside of a 'struct'.");
193 return false;
194 }
195
196 ALLOW_FLAG(extra);
197 ALLOW_FLAG(subtype);
198 break;
199
200 case FR_TYPE_OCTETS:
201 case FR_TYPE_STRING:
202 if (flags->length != 0) {
203 fr_strerror_const("Cannot use [..] and length=uint...");
204 return false;
205 }
206
207 /*
208 * We can do arrays of variable-length types, so long as they have a "length="
209 * modifier.
210 *
211 * But any other modifier is foridden, including the use of "length=" outside of
212 * the context of arrays.
213 */
214 if (flags->array) {
215 ALLOW_FLAG(array);
216
217 if ((flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) goto invalid_extra;
218 } else if (flags->subtype) {
219 invalid_extra:
220 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
221 return false;
222 }
223
224 ALLOW_FLAG(extra);
225 ALLOW_FLAG(subtype);
226 break;
227
228 case FR_TYPE_STRUCT:
229 if ((flags->subtype != FLAG_LENGTH_UINT8) && (flags->subtype != FLAG_LENGTH_UINT16)) {
230 fr_strerror_const("Invalid type (not 'length=...') for extra flag.");
231 return false;
232 }
233
234 ALLOW_FLAG(extra);
235 ALLOW_FLAG(subtype);
236 ALLOW_FLAG(array);
237 break;
238
239 case FR_TYPE_TLV:
240 ALLOW_FLAG(extra);
241 /* @todo - allow arrays of struct? */
242 ALLOW_FLAG(subtype);
243 break;
244
245 default:
246 fr_strerror_printf("Type %s cannot hold extra flags",
248 return false;
249 }
250
251 if (((flags->subtype == FLAG_LENGTH_UINT8) || (flags->subtype == FLAG_LENGTH_UINT16)) &&
252 ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_STRUCT))) {
253 fr_strerror_printf("The 'length' flag cannot be used used with type %s",
255 return false;
256 }
257
258 FORBID_OTHER_FLAGS(extra, 0);
259 }
260
261 /*
262 * Force "length" for fixed-size data types which aren't
263 * bit fields. Check / set "length" and "type_size" for
264 * other types.
265 */
266 if (!flags->extra || (flags->subtype != FLAG_BIT_FIELD)) switch (type) {
267 case FR_TYPE_UINT8:
268 case FR_TYPE_BOOL:
269 flags->length = 1;
270 break;
271
272 case FR_TYPE_UINT16:
273 flags->length = 2;
274 break;
275
276 case FR_TYPE_DATE:
278 if (!flags->length) flags->length = 4;
279
280 if ((flags->length != 2) && (flags->length != 4) && (flags->length != 8)) {
281 fr_strerror_printf("Invalid length %u for attribute of type '%s'",
282 flags->length, fr_type_to_str(type));
283 return false;
284 }
285 break;
286
288 case FR_TYPE_UINT32:
289 case FR_TYPE_INT32:
290 case FR_TYPE_FLOAT32:
291 flags->length = 4;
292 break;
293
294 case FR_TYPE_UINT64:
295 case FR_TYPE_FLOAT64:
296 flags->length = 8;
297 break;
298
299 case FR_TYPE_SIZE:
300 flags->length = sizeof(size_t);
301 break;
302
303 case FR_TYPE_ETHERNET:
304 flags->length = 6;
305 break;
306
307 case FR_TYPE_IFID:
308 flags->length = 8;
309 break;
310
313 flags->length = 16;
314 break;
315
318 flags->length = 17;
319 break;
320
321 case FR_TYPE_STRUCT:
322 ALLOW_FLAG(internal);
323 ALLOW_FLAG(array);
324 if (all_flags) {
325 fr_strerror_const("Invalid flag for attribute of type 'struct'");
326 return false;
327 }
328 break;
329
330 case FR_TYPE_VENDOR:
331 if (parent->type != FR_TYPE_VSA) {
332 fr_strerror_printf("Attributes of type 'vendor' MUST have a parent of type 'vsa' "
333 "instead of '%s'",
334 fr_type_to_str(parent->type));
335 return false;
336 }
337
338 if (flags->length) {
339 if ((flags->length != 1) &&
340 (flags->length != 2) &&
341 (flags->length != 4)) {
342 fr_strerror_const("The 'length' flag can only be used for attributes of type 'vendor' with lengths of 1,2 or 4");
343 return false;
344 }
345
346 break;
347 }
348
349 /*
350 * Set the length / type_size of vendor
351 * attributes from the vendor definition.
352 */
353 flags->type_size = 1;
354 flags->length = 1;
355 if (attr > 0) {
356 fr_dict_vendor_t const *dv;
357
358 dv = fr_dict_vendor_by_num(dict, attr);
359 if (dv) {
360 flags->type_size = dv->type;
361 flags->length = dv->length;
362 }
363 }
364 break;
365
366 case FR_TYPE_TLV:
367 if (flags->length) {
368 if ((flags->length != 1) &&
369 (flags->length != 2) &&
370 (flags->length != 4)) {
371 fr_strerror_const("The 'length' flag can only be used for attributes of type 'tlv' with lengths of 1,2 or 4");
372 return false;
373 }
374
375 break;
376 }
377
378 /*
379 * Find an appropriate parent to copy the
380 * TLV-specific fields from.
381 */
382 for (v = parent; v != NULL; v = v->parent) {
383 if ((v->type == FR_TYPE_TLV) || (v->type == FR_TYPE_VENDOR)) {
384 break;
385 }
386 }
387
388 /*
389 * root is always FR_TYPE_TLV, so we're OK.
390 */
391 if (!v) {
392 fr_strerror_printf("Attributes of type '%s' require a parent attribute",
394 return false;
395 }
396
397 /*
398 * Over-ride whatever was there before, so we
399 * don't have multiple formats of VSAs.
400 */
401 flags->type_size = v->flags.type_size;
402 flags->length = v->flags.length;
403 break;
404
405 /*
406 * 'octets[n]' can only be used in a few limited situations.
407 */
408 case FR_TYPE_OCTETS:
409 if (flags->length) {
410 /*
411 * Internal attributes can use octets[n]
412 * MS-MPPE-Keys use octets[18],encrypt=User-Password
413 * EAP-SIM-RAND uses array
414 */
415 ALLOW_FLAG(internal);
416 ALLOW_FLAG(subtype);
417 ALLOW_FLAG(array);
418
419 if (all_flags) {
420 fr_strerror_const("The 'octets[...]' syntax cannot be used any other flag");
421 return false;
422 }
423
424 if (flags->length > 253) {
425 fr_strerror_printf("Invalid length %d", flags->length);
426 return false;
427 }
428 }
429 break;
430
431 case FR_TYPE_NULL:
432 fr_strerror_printf("Attributes of type '%s' cannot be used in dictionaries",
434 return false;
435
436 default:
437 break;
438 }
439
440 /*
441 * type_size is used to limit the maximum attribute number, so it's checked first.
442 */
443 if (flags->type_size) {
444 if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
445 /*
446 * Allow all time res here
447 */
448 } else if (!flags->extra) {
449 if ((type != FR_TYPE_TLV) && (type != FR_TYPE_VENDOR)) {
450 fr_strerror_const("The 'format=' flag can only be used with attributes of type 'tlv'");
451 return false;
452 }
453
454 if ((flags->type_size != 1) &&
455 (flags->type_size != 2) &&
456 (flags->type_size != 4)) {
457 fr_strerror_const("The 'format=' flag can only be used with attributes of type size 1,2 or 4");
458 return false;
459 }
460 }
461 }
462
463 /*
464 * Counters can be time deltas, or unsigned integers.
465 * For other data types, we don't know how to
466 * automatically add two counters.
467 */
468 if (flags->counter) {
470 ALLOW_FLAG(counter);
471 } else {
472 fr_strerror_printf("The 'counter' flag cannot be used with '%s'", fr_type_to_str(type));
473 return false;
474 }
475 }
476
477 /*
478 * Check flags against the parent attribute.
479 */
480 switch (parent->type) {
481 case FR_TYPE_STRUCT:
482 ALLOW_FLAG(extra);
483 ALLOW_FLAG(subtype);
484
485 if (parent->flags.is_known_width && !flags->is_known_width && !flags->length) {
486 fr_strerror_const("Variable-sized fields cannot be used within a 'struct' which is 'array'");
487 return false;
488 }
489
490 if (flags->array) {
491 switch (type) {
493 ALLOW_FLAG(array);
494 break;
495
496 default:
497 if (flags->is_known_width) ALLOW_FLAG(array);
498 break;
499 }
500 }
501
502 if (all_flags) {
503 fr_strerror_const("Invalid flag for attribute inside of a 'struct'");
504 return false;
505 }
506
507 if (!attr) break;
508
509 /*
510 * If we have keyed structs, then the first
511 * member can be variable length.
512 *
513 * For subsequent children, have each one check
514 * the previous child.
515 */
516 if (attr != 1) {
517 int i;
518 fr_dict_attr_t const *sibling;
519
520 sibling = fr_dict_attr_child_by_num(parent, (attr) - 1);
521
522 /*
523 * sibling might not exist, if it's a deferred 'tlv clone=...'
524 */
525
526 /*
527 * Variable sized elements cannot have anything after them in a struct.
528 */
529 if (sibling && !sibling->flags.length && !sibling->flags.is_known_width) {
530 fr_strerror_const("No other field can follow a struct MEMBER which is variable sized");
531 return false;
532 }
533
534 /*
535 * The same goes for arrays.
536 */
537 if (sibling && sibling->flags.array) {
538 fr_strerror_const("No other field can follow a struct MEMBER which is 'array'");
539 return false;
540 }
541
542 /*
543 * Check for bad key fields, or multiple
544 * key fields. Yes, this is O(N^2), but
545 * the structs are small.
546 */
547 if (flags->extra && (flags->subtype == FLAG_KEY_FIELD)) {
548 for (i = 1; i < attr; i++) {
549 sibling = fr_dict_attr_child_by_num(parent, i);
550 if (!sibling) {
551 fr_strerror_printf("Child %d of 'struct' type attribute %s does not exist.",
552 i, parent->name);
553 return false;
554 }
555
556 if (!fr_dict_attr_is_key_field(sibling)) continue;
557
558 fr_strerror_printf("Duplicate key attributes '%s' and '%s' in 'struct' type attribute %s are forbidden",
559 name, sibling->name, parent->name);
560 return false;
561 }
562 }
563 }
564 break;
565
566 case FR_TYPE_VSA:
567 if ((type != FR_TYPE_VENDOR) && !flags->internal) {
568 fr_strerror_printf("Attributes of type '%s' cannot be children of the 'vsa' type",
570 return false;
571 }
572 break;
573
574 case FR_TYPE_TLV:
575 case FR_TYPE_VENDOR:
576 break;
577
578 /*
579 * "key" fields inside of a STRUCT can have
580 * children, even if they are integer data type.
581 */
582 case FR_TYPE_UINT8:
583 case FR_TYPE_UINT16:
584 case FR_TYPE_UINT32:
587
588 default:
589 fr_strerror_printf("Attributes of type '%s' cannot have child attributes",
590 fr_type_to_str(parent->type));
591 return false;
592 }
593
594 return true;
595}
596
597
598/** Validate a new attribute definition
599 *
600 * @todo we need to check length of none vendor attributes.
601 *
602 * @param[in] da to validate.
603 * @return
604 * - true if attribute definition is valid.
605 * - false if attribute definition is not valid.
606 */
608{
609 if (!fr_cond_assert(da->parent)) return false;
610
611 if (fr_dict_valid_name(da->name, -1) <= 0) return false;
612
613 /*
614 * Run protocol-specific validation functions, BEFORE we
615 * do the rest of the checks.
616 */
617 if (da->dict->proto->attr.valid && !da->dict->proto->attr.valid(da)) return false;
618
619 /*
620 * Check the flags, data types, and parent data types and flags.
621 */
622 if (!dict_attr_flags_valid(da)) return false;
623
624 return true;
625}
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
size_t type
Length of type data.
Definition dict.h:254
unsigned int has_value
Has a value.
Definition dict.h:95
unsigned int is_root
Is root of a dictionary.
Definition dict.h:77
unsigned int array
Pack multiples into 1 attr.
Definition dict.h:91
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition dict.h:117
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:89
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:155
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition dict.h:156
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition dict.h:153
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition dict.h:154
uint8_t type_size
For TLV2 and root attributes.
Definition dict.h:142
size_t length
Length of length data.
Definition dict.h:255
unsigned int local
is a local variable
Definition dict.h:119
unsigned int is_known_width
is treated as if it has a known width for structs
Definition dict.h:93
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:2755
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4738
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:3403
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:159
uint8_t subtype
protocol-specific values, OR key fields
Definition dict.h:128
uint8_t length
length of the attribute
Definition dict.h:134
unsigned int counter
integer attribute is actually an impulse / counter
Definition dict.h:99
unsigned int is_unknown
This dictionary attribute is ephemeral and not part of the main dictionary.
Definition dict.h:79
Values of the encryption flags.
Private enterprise.
Definition dict.h:251
#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:841
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:83
#define fr_type_is_signed(_x)
Definition types.h:381
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:452
#define fr_type_is_integer(_x)
Definition types.h:379
#define FR_TYPE_FIXED_SIZE
Definition types.h:308