1 /*
2 * dict.c Routines to read the dictionary file.
3 *
4 * Version: $Id: 479bf1104ee02c98a8ef10939a78fc0a6206fcfa $
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * Copyright 2000,2006 The FreeRADIUS server project
21 */
22 RCSID("$Id: 479bf1104ee02c98a8ef10939a78fc0a6206fcfa $")
23
24 #include <freeradius-devel/libradius.h>
25
26 #ifdef WITH_DHCP
27 #include <freeradius-devel/dhcp.h>
28 #endif
29
30 #include <ctype.h>
31
32 #ifdef HAVE_MALLOC_H
33 #include <malloc.h>
34 #endif
35
36 #ifdef HAVE_SYS_STAT_H
37 #include <sys/stat.h>
38 #endif
39
40 static fr_hash_table_t *vendors_byname = NULL;
41 static fr_hash_table_t *vendors_byvalue = NULL;
42
43 static fr_hash_table_t *attributes_byname = NULL;
44 static fr_hash_table_t *attributes_byvalue = NULL;
45
46 static fr_hash_table_t *attributes_combo = NULL;
47
48 static fr_hash_table_t *values_byvalue = NULL;
49 static fr_hash_table_t *values_byname = NULL;
50
51 static DICT_ATTR *dict_base_attrs[256];
52
53 /*
54 * For faster HUP's, we cache the stat information for
55 * files we've $INCLUDEd
56 */
57 typedef struct dict_stat_t {
58 struct dict_stat_t *next;
59 struct stat stat_buf;
60 } dict_stat_t;
61
62 static dict_stat_t *stat_head = NULL;
63 static dict_stat_t *stat_tail = NULL;
64
65 typedef struct value_fixup_t {
66 char attrstr[DICT_ATTR_MAX_NAME_LEN];
67 DICT_VALUE *dval;
68 struct value_fixup_t *next;
69 } value_fixup_t;
70
71
72 /*
73 * So VALUEs in the dictionary can have forward references.
74 */
75 static value_fixup_t *value_fixup = NULL;
76
77 const FR_NAME_NUMBER dict_attr_types[] = {
78 { "integer", PW_TYPE_INTEGER },
79 { "string", PW_TYPE_STRING },
80 { "ipaddr", PW_TYPE_IPV4_ADDR },
81 { "date", PW_TYPE_DATE },
82 { "abinary", PW_TYPE_ABINARY },
83 { "octets", PW_TYPE_OCTETS },
84 { "ifid", PW_TYPE_IFID },
85 { "ipv6addr", PW_TYPE_IPV6_ADDR },
86 { "ipv6prefix", PW_TYPE_IPV6_PREFIX },
87 { "byte", PW_TYPE_BYTE },
88 { "short", PW_TYPE_SHORT },
89 { "ether", PW_TYPE_ETHERNET },
90 { "combo-ip", PW_TYPE_COMBO_IP_ADDR },
91 { "tlv", PW_TYPE_TLV },
92 { "signed", PW_TYPE_SIGNED },
93 { "extended", PW_TYPE_EXTENDED },
94 { "long-extended", PW_TYPE_LONG_EXTENDED },
95 { "evs", PW_TYPE_EVS },
96 { "uint8", PW_TYPE_BYTE },
97 { "uint16", PW_TYPE_SHORT },
98 { "uint32", PW_TYPE_INTEGER },
99 { "int32", PW_TYPE_SIGNED },
100 { "integer64", PW_TYPE_INTEGER64 },
101 { "uint64", PW_TYPE_INTEGER64 },
102 { "ipv4prefix", PW_TYPE_IPV4_PREFIX },
103 { "cidr", PW_TYPE_IPV4_PREFIX },
104 { "vsa", PW_TYPE_VSA },
105 { NULL, 0 }
106 };
107
108 /*
109 * Map data types to min / max data sizes.
110 */
111 const size_t dict_attr_sizes[PW_TYPE_MAX][2] = {
112 [PW_TYPE_INVALID] = {~0, 0},
113 [PW_TYPE_STRING] = {0, ~0},
114 [PW_TYPE_INTEGER] = {4, 4 },
115 [PW_TYPE_IPV4_ADDR] = {4, 4},
116 [PW_TYPE_DATE] = {4, 4},
117 [PW_TYPE_ABINARY] = {32, ~0},
118 [PW_TYPE_OCTETS] = {0, ~0},
119 [PW_TYPE_IFID] = {8, 8},
120 [PW_TYPE_IPV6_ADDR] = {16, 16},
121 [PW_TYPE_IPV6_PREFIX] = {2, 18},
122 [PW_TYPE_BYTE] = {1, 1},
123 [PW_TYPE_SHORT] = {2, 2},
124 [PW_TYPE_ETHERNET] = {6, 6},
125 [PW_TYPE_SIGNED] = {4, 4},
126 [PW_TYPE_COMBO_IP_ADDR] = {4, 16},
127 [PW_TYPE_TLV] = {2, ~0},
128 [PW_TYPE_EXTENDED] = {2, ~0},
129 [PW_TYPE_LONG_EXTENDED] = {3, ~0},
130 [PW_TYPE_EVS] = {6, ~0},
131 [PW_TYPE_INTEGER64] = {8, 8},
132 [PW_TYPE_IPV4_PREFIX] = {6, 6},
133 [PW_TYPE_VSA] = {4, ~0}
134 };
135
136 /*
137 * For packing multiple TLV numbers into one 32-bit integer. The
138 * first 3 bytes are just the 8-bit number. The next two are
139 * more limited. We only allow 31 attributes nested 3 layers
140 * deep, and only 7 nested 4 layers deep. This should be
141 * sufficient for most purposes.
142 *
143 * For TLVs and extended attributes, we packet the base attribute
144 * number into the upper 8 bits of the "vendor" field.
145 *
146 * e.g. OID attribute vendor
147 * 241.1 1 (241 << 24)
148 * 241.26.9.1 1 (241 << 24) | (9)
149 * 241.1.2 1 | (2 << 8) (241 << 24)
150 */
151 #define MAX_TLV_NEST (4)
152 /*
153 * Bit packing:
154 * 8 bits of base attribute
155 * 8 bits for nested TLV 1
156 * 8 bits for nested TLV 2
157 * 5 bits for nested TLV 3
158 * 3 bits for nested TLV 4
159 */
160 int const fr_attr_max_tlv = MAX_TLV_NEST;
161 int const fr_attr_shift[MAX_TLV_NEST + 1] = { 0, 8, 16, 24, 29 };
162
163 unsigned const fr_attr_mask[MAX_TLV_NEST + 1] = { 0xff, 0xff, 0xff, 0x1f, 0x07 };
164
165 /*
166 * attr & fr_attr_parent_mask[i] == Nth parent of attr
167 */
168 static unsigned int const fr_attr_parent_mask[MAX_TLV_NEST + 1] = { 0, 0x000000ff, 0x0000ffff, 0x00ffffff, 0x1fffffff };
169
170 /*
171 * Create the hash of the name.
172 *
173 * We copy the hash function here because it's substantially faster.
174 */
175 #define FNV_MAGIC_INIT (0x811c9dc5)
176 #define FNV_MAGIC_PRIME (0x01000193)
177
dict_hashname(char const * name)178 static uint32_t dict_hashname(char const *name)
179 {
180 uint32_t hash = FNV_MAGIC_INIT;
181 char const *p;
182
183 for (p = name; *p != '\0'; p++) {
184 int c = *(unsigned char const *) p;
185 if (isalpha(c)) c = tolower(c);
186
187 hash *= FNV_MAGIC_PRIME;
188 hash ^= (uint32_t ) (c & 0xff);
189 }
190
191 return hash;
192 }
193
194
195 /*
196 * Hash callback functions.
197 */
dict_attr_name_hash(void const * data)198 static uint32_t dict_attr_name_hash(void const *data)
199 {
200 return dict_hashname(((DICT_ATTR const *)data)->name);
201 }
202
dict_attr_name_cmp(void const * one,void const * two)203 static int dict_attr_name_cmp(void const *one, void const *two)
204 {
205 DICT_ATTR const *a = one;
206 DICT_ATTR const *b = two;
207
208 return strcasecmp(a->name, b->name);
209 }
210
dict_attr_value_hash(void const * data)211 static uint32_t dict_attr_value_hash(void const *data)
212 {
213 uint32_t hash;
214 DICT_ATTR const *attr = data;
215
216 hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
217 return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
218 }
219
dict_attr_value_cmp(void const * one,void const * two)220 static int dict_attr_value_cmp(void const *one, void const *two)
221 {
222 DICT_ATTR const *a = one;
223 DICT_ATTR const *b = two;
224
225 if (a->vendor < b->vendor) return -1;
226 if (a->vendor > b->vendor) return +1;
227
228 return a->attr - b->attr;
229 }
230
dict_attr_combo_hash(void const * data)231 static uint32_t dict_attr_combo_hash(void const *data)
232 {
233 uint32_t hash;
234 DICT_ATTR const *attr = data;
235
236 hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
237 hash = fr_hash_update(&attr->type, sizeof(attr->type), hash);
238 return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
239 }
240
dict_attr_combo_cmp(void const * one,void const * two)241 static int dict_attr_combo_cmp(void const *one, void const *two)
242 {
243 DICT_ATTR const *a = one;
244 DICT_ATTR const *b = two;
245
246 if (a->type < b->type) return -1;
247 if (a->type > b->type) return +1;
248
249 if (a->vendor < b->vendor) return -1;
250 if (a->vendor > b->vendor) return +1;
251
252 return a->attr - b->attr;
253 }
254
dict_vendor_name_hash(void const * data)255 static uint32_t dict_vendor_name_hash(void const *data)
256 {
257 return dict_hashname(((DICT_VENDOR const *)data)->name);
258 }
259
dict_vendor_name_cmp(void const * one,void const * two)260 static int dict_vendor_name_cmp(void const *one, void const *two)
261 {
262 DICT_VENDOR const *a = one;
263 DICT_VENDOR const *b = two;
264
265 return strcasecmp(a->name, b->name);
266 }
267
dict_vendor_value_hash(void const * data)268 static uint32_t dict_vendor_value_hash(void const *data)
269 {
270 return fr_hash(&(((DICT_VENDOR const *)data)->vendorpec),
271 sizeof(((DICT_VENDOR const *)data)->vendorpec));
272 }
273
dict_vendor_value_cmp(void const * one,void const * two)274 static int dict_vendor_value_cmp(void const *one, void const *two)
275 {
276 DICT_VENDOR const *a = one;
277 DICT_VENDOR const *b = two;
278
279 return a->vendorpec - b->vendorpec;
280 }
281
dict_value_name_hash(void const * data)282 static uint32_t dict_value_name_hash(void const *data)
283 {
284 uint32_t hash;
285 DICT_VALUE const *dval = data;
286
287 hash = dict_hashname(dval->name);
288 hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
289 return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
290 }
291
dict_value_name_cmp(void const * one,void const * two)292 static int dict_value_name_cmp(void const *one, void const *two)
293 {
294 int rcode;
295 DICT_VALUE const *a = one;
296 DICT_VALUE const *b = two;
297
298 rcode = a->attr - b->attr;
299 if (rcode != 0) return rcode;
300
301 rcode = a->vendor - b->vendor;
302 if (rcode != 0) return rcode;
303
304 return strcasecmp(a->name, b->name);
305 }
306
dict_value_value_hash(void const * data)307 static uint32_t dict_value_value_hash(void const *data)
308 {
309 uint32_t hash;
310 DICT_VALUE const *dval = data;
311
312 hash = fr_hash(&dval->attr, sizeof(dval->attr));
313 hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
314 return fr_hash_update(&dval->value, sizeof(dval->value), hash);
315 }
316
dict_value_value_cmp(void const * one,void const * two)317 static int dict_value_value_cmp(void const *one, void const *two)
318 {
319 int rcode;
320 DICT_VALUE const *a = one;
321 DICT_VALUE const *b = two;
322
323 if (a->vendor < b->vendor) return -1;
324 if (a->vendor > b->vendor) return +1;
325
326 rcode = a->attr - b->attr;
327 if (rcode != 0) return rcode;
328
329 return a->value - b->value;
330 }
331
332
333 /*
334 * Free the list of stat buffers
335 */
dict_stat_free(void)336 static void dict_stat_free(void)
337 {
338 dict_stat_t *this, *next;
339
340 if (!stat_head) {
341 stat_tail = NULL;
342 return;
343 }
344
345 for (this = stat_head; this != NULL; this = next) {
346 next = this->next;
347 free(this);
348 }
349
350 stat_head = stat_tail = NULL;
351 }
352
353
354 /*
355 * Add an entry to the list of stat buffers.
356 */
dict_stat_add(struct stat const * stat_buf)357 static void dict_stat_add(struct stat const *stat_buf)
358 {
359 dict_stat_t *this;
360
361 this = malloc(sizeof(*this));
362 if (!this) return;
363 memset(this, 0, sizeof(*this));
364
365 memcpy(&(this->stat_buf), stat_buf, sizeof(this->stat_buf));
366
367 if (!stat_head) {
368 stat_head = stat_tail = this;
369 } else {
370 stat_tail->next = this;
371 stat_tail = this;
372 }
373 }
374
375
376 /*
377 * See if any dictionaries have changed. If not, don't
378 * do anything.
379 */
dict_stat_check(char const * dir,char const * file)380 static int dict_stat_check(char const *dir, char const *file)
381 {
382 struct stat stat_buf;
383 dict_stat_t *this;
384 char buffer[2048];
385
386 /*
387 * Nothing cached, all files are new.
388 */
389 if (!stat_head) return 0;
390
391 /*
392 * Stat the file.
393 */
394 snprintf(buffer, sizeof(buffer), "%s/%s", dir, file);
395 if (stat(buffer, &stat_buf) < 0) return 0;
396
397 /*
398 * Find the cache entry.
399 * FIXME: use a hash table.
400 * FIXME: check dependencies, via children.
401 * if A loads B and B changes, we probably want
402 * to reload B at the minimum.
403 */
404 for (this = stat_head; this != NULL; this = this->next) {
405 if (this->stat_buf.st_dev != stat_buf.st_dev) continue;
406 if (this->stat_buf.st_ino != stat_buf.st_ino) continue;
407
408 /*
409 * The file has changed. Re-read it.
410 */
411 if (this->stat_buf.st_mtime < stat_buf.st_mtime) return 0;
412
413 /*
414 * The file is the same. Ignore it.
415 */
416 return 1;
417 }
418
419 /*
420 * Not in the cache.
421 */
422 return 0;
423 }
424
425 typedef struct fr_pool_t {
426 void *page_end;
427 void *free_ptr;
428 struct fr_pool_t *page_free;
429 struct fr_pool_t *page_next;
430 } fr_pool_t;
431
432 #define FR_POOL_SIZE (32768)
433 #define FR_ALLOC_ALIGN (8)
434
435 static fr_pool_t *dict_pool = NULL;
436
fr_pool_create(void)437 static fr_pool_t *fr_pool_create(void)
438 {
439 fr_pool_t *fp = malloc(FR_POOL_SIZE);
440
441 if (!fp) return NULL;
442
443 memset(fp, 0, FR_POOL_SIZE);
444
445 fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
446 fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
447 fp->page_free = fp;
448 fp->page_next = NULL;
449 return fp;
450 }
451
fr_pool_delete(fr_pool_t ** pfp)452 static void fr_pool_delete(fr_pool_t **pfp)
453 {
454 fr_pool_t *fp, *next;
455
456 if (!pfp || !*pfp) return;
457
458 for (fp = *pfp; fp != NULL; fp = next) {
459 next = fp->page_next;
460 fp->page_next = NULL;
461 free(fp);
462 }
463 *pfp = NULL;
464 }
465
466
fr_pool_alloc(size_t size)467 static void *fr_pool_alloc(size_t size)
468 {
469 void *ptr;
470
471 if (size == 0) return NULL;
472
473 if (size > 256) return NULL; /* shouldn't happen */
474
475 if (!dict_pool) {
476 dict_pool = fr_pool_create();
477 if (!dict_pool) return NULL;
478 }
479
480 if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
481 size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
482 }
483
484 if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
485 dict_pool->page_free->page_next = fr_pool_create();
486 if (!dict_pool->page_free->page_next) return NULL;
487 dict_pool->page_free = dict_pool->page_free->page_next;
488 }
489
490 ptr = dict_pool->page_free->free_ptr;
491 dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
492
493 return ptr;
494 }
495
496
fr_pool_free(UNUSED void * ptr)497 static void fr_pool_free(UNUSED void *ptr)
498 {
499 /*
500 * Place-holder for later code.
501 */
502 }
503
504 /*
505 * Free the dictionary_attributes and dictionary_values lists.
506 */
dict_free(void)507 void dict_free(void)
508 {
509 /*
510 * Free the tables
511 */
512 fr_hash_table_free(vendors_byname);
513 fr_hash_table_free(vendors_byvalue);
514 vendors_byname = NULL;
515 vendors_byvalue = NULL;
516
517 fr_hash_table_free(attributes_byname);
518 fr_hash_table_free(attributes_byvalue);
519 fr_hash_table_free(attributes_combo);
520 attributes_byname = NULL;
521 attributes_byvalue = NULL;
522 attributes_combo = NULL;
523
524 fr_hash_table_free(values_byname);
525 fr_hash_table_free(values_byvalue);
526 values_byname = NULL;
527 values_byvalue = NULL;
528
529 memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
530
531 fr_pool_delete(&dict_pool);
532
533 dict_stat_free();
534 }
535
536 /*
537 * Add vendor to the list.
538 */
dict_addvendor(char const * name,unsigned int value)539 int dict_addvendor(char const *name, unsigned int value)
540 {
541 size_t length;
542 DICT_VENDOR *dv;
543
544 if (value >= FR_MAX_VENDOR) {
545 fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 2^24");
546 return -1;
547 }
548
549 if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
550 fr_strerror_printf("dict_addvendor: vendor name too long");
551 return -1;
552 }
553
554 if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
555 fr_strerror_printf("dict_addvendor: out of memory");
556 return -1;
557 }
558
559 strcpy(dv->name, name);
560 dv->vendorpec = value;
561 dv->type = dv->length = 1; /* defaults */
562
563 if (!fr_hash_table_insert(vendors_byname, dv)) {
564 DICT_VENDOR *old_dv;
565
566 old_dv = fr_hash_table_finddata(vendors_byname, dv);
567 if (!old_dv) {
568 fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
569 return -1;
570 }
571 if (old_dv->vendorpec != dv->vendorpec) {
572 fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
573 return -1;
574 }
575
576 /*
577 * Already inserted. Discard the duplicate entry.
578 */
579 fr_pool_free(dv);
580 return 0;
581 }
582
583 /*
584 * Insert the SAME pointer (not free'd when this table is
585 * deleted), into another table.
586 *
587 * We want this behaviour because we want OLD names for
588 * the attributes to be read from the configuration
589 * files, but when we're printing them, (and looking up
590 * by value) we want to use the NEW name.
591 */
592 if (!fr_hash_table_replace(vendors_byvalue, dv)) {
593 fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
594 name);
595 return -1;
596 }
597
598 return 0;
599 }
600
601 const int dict_attr_allowed_chars[256] = {
602 /* 0x 0 1 2 3 4 5 6 7 8 9 a b c d e f */
603 /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
604 /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
605 /* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
606 /* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
607 /* 4 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
608 /* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
609 /* 6 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
610 /* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
611 /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
612 /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
613 /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
614 /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
615 /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
616 /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
617 /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
618 /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
619 };
620
621 /*
622 * [a-zA-Z0-9_-:.]+
623 */
dict_valid_name(char const * name)624 int dict_valid_name(char const *name)
625 {
626 uint8_t const *p;
627
628 for (p = (uint8_t const *) name; *p != '\0'; p++) {
629 if (!dict_attr_allowed_chars[*p]) {
630 char buff[5];
631
632 fr_prints(buff, sizeof(buff), (char const *)p, 1, '\'');
633 fr_strerror_printf("Invalid character '%s' in attribute", buff);
634
635 return -(p - (uint8_t const *)name);
636 }
637 }
638
639 return 0;
640 }
641
642
643 /*
644 * Find the parent of the attr/vendor.
645 */
dict_parent(unsigned int attr,unsigned int vendor)646 DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor)
647 {
648 int i;
649 unsigned int base_vendor;
650
651 /*
652 * RFC attributes can't be of type "tlv", except for dictionary.rfc6930
653 */
654 if (!vendor) {
655 #ifdef PW_IPV6_6RD_CONFIGURATION
656 if (attr == PW_IPV6_6RD_CONFIGURATION) return NULL;
657
658 if (((attr & 0xff) == PW_IPV6_6RD_CONFIGURATION) &&
659 (attr >> 8) < 4) {
660 return dict_attrbyvalue(PW_IPV6_6RD_CONFIGURATION, 0);
661 }
662 #endif
663 return NULL;
664 }
665
666 base_vendor = vendor & (FR_MAX_VENDOR - 1);
667
668 /*
669 * It's a real vendor.
670 */
671 if (base_vendor != 0) {
672 DICT_VENDOR const *dv;
673
674 dv = dict_vendorbyvalue(base_vendor);
675 if (!dv) return NULL;
676
677 /*
678 * Only standard format attributes can be of type "tlv",
679 * Except for DHCP. <sigh>
680 */
681 if ((vendor != 54) && ((dv->type != 1) || (dv->length != 1))) return NULL;
682
683 for (i = MAX_TLV_NEST; i > 0; i--) {
684 unsigned int parent;
685
686 parent = attr & fr_attr_parent_mask[i];
687
688 if (parent != attr) return dict_attrbyvalue(parent, vendor); /* not base_vendor */
689 }
690
691 /*
692 * It was a top-level VSA. There's no parent.
693 * We COULD return the appropriate enclosing VSA
694 * (26, or 241.26, etc.) but that's not what we
695 * want.
696 */
697 return NULL;
698 }
699
700 /*
701 * It's an extended attribute. Return the base Extended-Attr-X
702 */
703 if (attr < 256) return dict_attrbyvalue((vendor / FR_MAX_VENDOR) & 0xff, 0);
704
705 /*
706 * Figure out which attribute it is.
707 */
708 for (i = MAX_TLV_NEST; i > 0; i--) {
709 unsigned int parent;
710
711 parent = attr & fr_attr_parent_mask[i];
712 if (parent != attr) return dict_attrbyvalue(parent, vendor); /* not base_vendor */
713 }
714
715 return NULL;
716 }
717
718
719 /** Add an attribute to the dictionary
720 *
721 * @return 0 on success -1 on failure.
722 */
dict_addattr(char const * name,int attr,unsigned int vendor,PW_TYPE type,ATTR_FLAGS flags)723 int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type,
724 ATTR_FLAGS flags)
725 {
726 size_t namelen;
727 DICT_ATTR const *parent;
728 DICT_ATTR *n;
729 DICT_ATTR const *old;
730 static int max_attr = 0;
731
732 namelen = strlen(name);
733 if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
734 fr_strerror_printf("dict_addattr: attribute name too long");
735 return -1;
736 }
737
738 if (dict_valid_name(name) < 0) return -1;
739
740 if (flags.has_tag &&
741 !((type == PW_TYPE_INTEGER) || (type == PW_TYPE_STRING))) {
742 fr_strerror_printf("dict_addattr: Only 'integer' and 'string' attributes can have tags");
743 return -1;
744 }
745
746 /*
747 * Disallow attributes of type zero.
748 */
749 if (!attr && !vendor) {
750 fr_strerror_printf("dict_addattr: Attribute 0 is invalid and cannot be used");
751 return -1;
752 }
753
754 /*
755 * If the attr is '-1', that means use a pre-existing
756 * one (if it already exists). If one does NOT already exist,
757 * then create a new attribute, with a non-conflicting value,
758 * and use that.
759 */
760 if (attr == -1) {
761 if (dict_attrbyname(name)) {
762 return 0; /* exists, don't add it again */
763 }
764
765 attr = ++max_attr;
766
767 } else if (vendor == 0) {
768 /*
769 * Update 'max_attr'
770 */
771 if (attr > max_attr) {
772 max_attr = attr;
773 }
774 }
775
776 /*
777 * Check the parent attribute, and set the various flags
778 * based on the parents values. It's OK for the caller
779 * to not set them, as we'll set them. But if the caller
780 * sets them when he's not supposed to set them, that's
781 * an error.
782 */
783 parent = dict_parent(attr, vendor);
784 if (parent) {
785 /*
786 * We're still in the same space and the parent isn't a TLV. That's an error.
787 *
788 * Otherwise, dict_parent() has taken us from an Extended sub-attribute to
789 * a *the* Extended attribute, whish isn't what we want here.
790 */
791 if ((vendor == parent->vendor) && (parent->type != PW_TYPE_TLV)) {
792 fr_strerror_printf("dict_addattr: Attribute %s has parent attribute %s which is not of type 'tlv'",
793 name, parent->name);
794 return -1;
795 }
796
797 flags.extended |= parent->flags.extended;
798 flags.long_extended |= parent->flags.long_extended;
799 flags.evs |= parent->flags.evs;
800 }
801
802 /*
803 * Manually extended flags for extended attributes. We
804 * can't expect the caller to know all of the details of the flags.
805 */
806 if (vendor >= FR_MAX_VENDOR) {
807 DICT_ATTR const *da;
808
809 /*
810 * Trying to manually create an extended
811 * attribute, but the parent extended attribute
812 * doesn't exist? That's an error.
813 */
814 da = dict_attrbyvalue(vendor / FR_MAX_VENDOR, 0);
815 if (!da) {
816 fr_strerror_printf("Extended attributes must be defined from the extended space");
817 return -1;
818 }
819
820 flags.extended |= da->flags.extended;
821 flags.long_extended |= da->flags.long_extended;
822 flags.evs |= da->flags.evs;
823
824 /*
825 * There's still a real vendor. Since it's an
826 * extended attribute, set the EVS flag.
827 */
828 if ((vendor & (FR_MAX_VENDOR -1)) != 0) flags.evs = 1;
829 }
830
831 /*
832 * Additional checks for extended attributes.
833 */
834 if (flags.extended || flags.long_extended || flags.evs) {
835 if (vendor && (vendor < FR_MAX_VENDOR)) {
836 fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats");
837 return -1;
838 }
839 if (flags.has_tag
840 #ifdef WITH_DHCP
841 || flags.array
842 #endif
843 || ((flags.encrypt != FLAG_ENCRYPT_NONE) && (flags.encrypt != FLAG_ENCRYPT_TUNNEL_PASSWORD))) {
844 fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set");
845 return -1;
846 }
847 }
848
849 if (flags.evs) {
850 if (!(flags.extended || flags.long_extended)) {
851 fr_strerror_printf("dict_addattr: Attributes of type \"evs\" MUST have a parent of type \"extended\"");
852 return -1;
853 }
854 }
855
856 /*
857 * Do various sanity checks.
858 */
859 if (attr < 0) {
860 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
861 return -1;
862 }
863
864 if (flags.has_tlv && flags.length) {
865 fr_strerror_printf("TLVs cannot have a fixed length");
866 return -1;
867 }
868
869 if (vendor && flags.concat) {
870 fr_strerror_printf("VSAs cannot have the \"concat\" flag set");
871 return -1;
872 }
873
874 if (flags.concat && (type != PW_TYPE_OCTETS)) {
875 fr_strerror_printf("The \"concat\" flag can only be set for attributes of type \"octets\"");
876 return -1;
877 }
878
879 if (flags.concat && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv ||
880 flags.length || flags.evs || flags.extended || flags.long_extended ||
881 (flags.encrypt != FLAG_ENCRYPT_NONE))) {
882 fr_strerror_printf("The \"concat\" flag cannot be used with any other flag");
883 return -1;
884 }
885
886 if (flags.encrypt) flags.secret = 1;
887
888 if (flags.length && (type != PW_TYPE_OCTETS)) {
889 fr_strerror_printf("The \"length\" flag can only be set for attributes of type \"octets\"");
890 return -1;
891 }
892
893 if (flags.length && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv ||
894 flags.concat || flags.evs || flags.extended || flags.long_extended ||
895 (flags.encrypt > FLAG_ENCRYPT_USER_PASSWORD))) {
896 fr_strerror_printf("The \"length\" flag cannot be used with any other flag");
897 return -1;
898 }
899
900 /*
901 * Force "length" for data types of fixed length;
902 */
903 switch (type) {
904 case PW_TYPE_BYTE:
905 flags.length = 1;
906 break;
907
908 case PW_TYPE_SHORT:
909 flags.length = 2;
910 break;
911
912 case PW_TYPE_DATE:
913 case PW_TYPE_IPV4_ADDR:
914 case PW_TYPE_INTEGER:
915 case PW_TYPE_SIGNED:
916 flags.length = 4;
917 break;
918
919 case PW_TYPE_INTEGER64:
920 flags.length = 8;
921 break;
922
923 case PW_TYPE_ETHERNET:
924 flags.length = 6;
925 break;
926
927 case PW_TYPE_IFID:
928 flags.length = 8;
929 break;
930
931 case PW_TYPE_IPV6_ADDR:
932 flags.length = 16;
933 break;
934
935 case PW_TYPE_EXTENDED:
936 if ((vendor != 0) || (attr < 241)) {
937 fr_strerror_printf("Attributes of type \"extended\" MUST be "
938 "RFC attributes with value >= 241.");
939 return -1;
940 }
941
942 flags.length = 0;
943 flags.extended = 1;
944 break;
945
946 case PW_TYPE_LONG_EXTENDED:
947 if ((vendor != 0) || (attr < 241)) {
948 fr_strerror_printf("Attributes of type \"long-extended\" MUST "
949 "be RFC attributes with value >= 241.");
950 return -1;
951 }
952
953 flags.length = 0;
954 flags.extended = 1;
955 flags.long_extended = 1;
956 break;
957
958 case PW_TYPE_EVS:
959 if (attr != PW_VENDOR_SPECIFIC) {
960 fr_strerror_printf("Attributes of type \"evs\" MUST have "
961 "attribute code 26.");
962 return -1;
963 }
964
965 flags.length = 0;
966 flags.extended = 1;
967 flags.evs = 1;
968 break;
969
970 case PW_TYPE_STRING:
971 case PW_TYPE_OCTETS:
972 case PW_TYPE_TLV:
973 flags.is_pointer = true;
974 break;
975
976 default:
977 break;
978 }
979
980 /*
981 * Stupid hacks for MS-CHAP-MPPE-Keys. The User-Password
982 * encryption method has no provisions for encoding the
983 * length of the data. For User-Password, the data is
984 * (presumably) all printable non-zero data. For
985 * MS-CHAP-MPPE-Keys, the data is binary crap. So... we
986 * MUST specify a length in the dictionary.
987 */
988 if ((flags.encrypt == FLAG_ENCRYPT_USER_PASSWORD) && (type != PW_TYPE_STRING)) {
989 if (type != PW_TYPE_OCTETS) {
990 fr_strerror_printf("The \"encrypt=1\" flag cannot be used with non-string data types");
991 return -1;
992 }
993
994 if (flags.length == 0) {
995 fr_strerror_printf("The \"encrypt=1\" flag MUST be used with an explicit length for 'octets' data types");
996 return -1;
997 }
998 }
999
1000 if ((vendor & (FR_MAX_VENDOR -1)) != 0) {
1001 DICT_VENDOR *dv;
1002 static DICT_VENDOR *last_vendor = NULL;
1003
1004 if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
1005 fr_strerror_printf("TLV's cannot be encrypted");
1006 return -1;
1007 }
1008
1009 if (flags.is_tlv && flags.has_tag) {
1010 fr_strerror_printf("Sub-TLV's cannot have a tag");
1011 return -1;
1012 }
1013
1014 if (flags.has_tlv && flags.has_tag) {
1015 fr_strerror_printf("TLV's cannot have a tag");
1016 return -1;
1017 }
1018
1019 /*
1020 * Most ATTRIBUTEs are bunched together by
1021 * VENDOR. We can save a lot of lookups on
1022 * dictionary initialization by caching the last
1023 * vendor.
1024 */
1025 if (last_vendor &&
1026 ((vendor & (FR_MAX_VENDOR - 1)) == last_vendor->vendorpec)) {
1027 dv = last_vendor;
1028 } else {
1029 /*
1030 * Ignore the high byte (sigh)
1031 */
1032 dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
1033 last_vendor = dv;
1034 }
1035
1036 /*
1037 * If the vendor isn't defined, die.
1038 */
1039 if (!dv) {
1040 fr_strerror_printf("dict_addattr: Unknown vendor %u",
1041 vendor & (FR_MAX_VENDOR - 1));
1042 return -1;
1043 }
1044
1045 if (!attr && dv->type != 1) {
1046 fr_strerror_printf("dict_addattr: Attribute %s cannot have value zero",
1047 name);
1048 return -1;
1049 }
1050
1051 /*
1052 * FIXME: Switch over dv->type, and limit things
1053 * properly.
1054 */
1055 if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
1056 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255)");
1057 return -1;
1058 } /* else 256..65535 are allowed */
1059
1060 /*
1061 * <sigh> Alvarion, being *again* a horribly
1062 * broken vendor, has re-used the WiMAX format in
1063 * their proprietary vendor space. This re-use
1064 * means that there are *multiple* conflicting
1065 * Alvarion dictionaries.
1066 */
1067 flags.wimax = dv->flags;
1068 } /* it's a VSA of some kind */
1069
1070 /*
1071 * Create a new attribute for the list
1072 */
1073 if ((n = fr_pool_alloc(sizeof(*n) + namelen)) == NULL) {
1074 oom:
1075 fr_strerror_printf("dict_addattr: out of memory");
1076 return -1;
1077 }
1078
1079 memcpy(n->name, name, namelen);
1080 n->name[namelen] = '\0';
1081 n->attr = attr;
1082 n->vendor = vendor;
1083 n->type = type;
1084 n->flags = flags;
1085
1086 /*
1087 * Allow old-style names, but they always end up as
1088 * new-style names.
1089 */
1090 old = dict_attrbyvalue(n->attr, n->vendor);
1091 if (old && (old->type == n->type)) {
1092 DICT_ATTR *mutable;
1093
1094 memcpy(&mutable, &old, sizeof(old)); /* const issues */
1095 mutable->flags.is_dup = true;
1096 }
1097
1098 /*
1099 * Insert the attribute, only if it's not a duplicate.
1100 */
1101 if (!fr_hash_table_insert(attributes_byname, n)) {
1102 DICT_ATTR *a;
1103
1104 /*
1105 * If the attribute has identical number, then
1106 * ignore the duplicate.
1107 */
1108 a = fr_hash_table_finddata(attributes_byname, n);
1109 if (a && (strcasecmp(a->name, n->name) == 0)) {
1110 if (a->attr != n->attr) {
1111 fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
1112 fr_pool_free(n);
1113 return -1;
1114 }
1115
1116 /*
1117 * Same name, same vendor, same attr,
1118 * maybe the flags and/or type is
1119 * different. Let the new value
1120 * over-ride the old one.
1121 */
1122 }
1123
1124
1125 fr_hash_table_delete(attributes_byvalue, a);
1126
1127 if (!fr_hash_table_replace(attributes_byname, n)) {
1128 fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
1129 fr_pool_free(n);
1130 return -1;
1131 }
1132 }
1133
1134 /*
1135 * Insert the SAME pointer (not free'd when this entry is
1136 * deleted), into another table.
1137 *
1138 * We want this behaviour because we want OLD names for
1139 * the attributes to be read from the configuration
1140 * files, but when we're printing them, (and looking up
1141 * by value) we want to use the NEW name.
1142 */
1143 if (!fr_hash_table_replace(attributes_byvalue, n)) {
1144 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
1145 return -1;
1146 }
1147
1148 /*
1149 * Hacks for combo-IP
1150 */
1151 if (n->type == PW_TYPE_COMBO_IP_ADDR) {
1152 DICT_ATTR *v4, *v6;
1153
1154 v4 = fr_pool_alloc(sizeof(*v4) + namelen);
1155 if (!v4) goto oom;
1156
1157 v6 = fr_pool_alloc(sizeof(*v6) + namelen);
1158 if (!v6) goto oom;
1159
1160 memcpy(v4, n, sizeof(*v4) + namelen);
1161 v4->type = PW_TYPE_IPV4_ADDR;
1162
1163 memcpy(v6, n, sizeof(*v6) + namelen);
1164 v6->type = PW_TYPE_IPV6_ADDR;
1165 if (!fr_hash_table_replace(attributes_combo, v4)) {
1166 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv4", name);
1167 return -1;
1168 }
1169
1170 if (!fr_hash_table_replace(attributes_combo, v6)) {
1171 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv6", name);
1172 return -1;
1173 }
1174 }
1175
1176 if (!vendor && (attr > 0) && (attr < 256)) {
1177 dict_base_attrs[attr] = n;
1178 }
1179
1180 return 0;
1181 }
1182
1183
1184 /*
1185 * Add a value for an attribute to the dictionary.
1186 */
dict_addvalue(char const * namestr,char const * attrstr,int value)1187 int dict_addvalue(char const *namestr, char const *attrstr, int value)
1188 {
1189 size_t length;
1190 DICT_ATTR const *da;
1191 DICT_VALUE *dval;
1192
1193 static DICT_ATTR const *last_attr = NULL;
1194
1195 if (!*namestr) {
1196 fr_strerror_printf("dict_addvalue: empty names are not permitted");
1197 return -1;
1198 }
1199
1200 if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
1201 fr_strerror_printf("dict_addvalue: value name too long");
1202 return -1;
1203 }
1204
1205 if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
1206 fr_strerror_printf("dict_addvalue: out of memory");
1207 return -1;
1208 }
1209 memset(dval, 0, sizeof(*dval));
1210
1211 strcpy(dval->name, namestr);
1212 dval->value = value;
1213
1214 /*
1215 * Most VALUEs are bunched together by ATTRIBUTE. We can
1216 * save a lot of lookups on dictionary initialization by
1217 * caching the last attribute.
1218 */
1219 if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
1220 da = last_attr;
1221 } else {
1222 da = dict_attrbyname(attrstr);
1223 last_attr = da;
1224 }
1225
1226 /*
1227 * Remember which attribute is associated with this
1228 * value, if possible.
1229 */
1230 if (da) {
1231 if (da->flags.has_value_alias) {
1232 fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
1233 return -1;
1234 }
1235
1236 dval->attr = da->attr;
1237 dval->vendor = da->vendor;
1238
1239 /*
1240 * Enforce valid values
1241 *
1242 * Don't worry about fixups...
1243 */
1244 switch (da->type) {
1245 case PW_TYPE_BYTE:
1246 if (value > 255) {
1247 fr_pool_free(dval);
1248 fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
1249 return -1;
1250 }
1251 break;
1252 case PW_TYPE_SHORT:
1253 if (value > 65535) {
1254 fr_pool_free(dval);
1255 fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
1256 return -1;
1257 }
1258 break;
1259
1260 /*
1261 * Allow octets for now, because
1262 * of dictionary.cablelabs
1263 */
1264 case PW_TYPE_OCTETS:
1265
1266 case PW_TYPE_INTEGER:
1267 break;
1268
1269 case PW_TYPE_INTEGER64:
1270 default:
1271 fr_pool_free(dval);
1272 fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
1273 fr_int2str(dict_attr_types, da->type, "?Unknown?"));
1274 return -1;
1275 }
1276 /* in v4 this is done with the UNCONST #define */
1277 ((DICT_ATTR *)((uintptr_t)(da)))->flags.has_value = 1;
1278 } else {
1279 value_fixup_t *fixup;
1280
1281 fixup = (value_fixup_t *) malloc(sizeof(*fixup));
1282 if (!fixup) {
1283 fr_pool_free(dval);
1284 fr_strerror_printf("dict_addvalue: out of memory");
1285 return -1;
1286 }
1287 memset(fixup, 0, sizeof(*fixup));
1288
1289 strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
1290 fixup->dval = dval;
1291
1292 /*
1293 * Insert to the head of the list.
1294 */
1295 fixup->next = value_fixup;
1296 value_fixup = fixup;
1297
1298 return 0;
1299 }
1300
1301 /*
1302 * Add the value into the dictionary.
1303 */
1304 {
1305 DICT_ATTR *tmp;
1306 memcpy(&tmp, &dval, sizeof(tmp));
1307
1308 if (!fr_hash_table_insert(values_byname, tmp)) {
1309 if (da) {
1310 DICT_VALUE *old;
1311
1312 /*
1313 * Suppress duplicates with the same
1314 * name and value. There are lots in
1315 * dictionary.ascend.
1316 */
1317 old = dict_valbyname(da->attr, da->vendor, namestr);
1318 if (old && (old->value == dval->value)) {
1319 fr_pool_free(dval);
1320 return 0;
1321 }
1322 }
1323
1324 fr_pool_free(dval);
1325 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
1326 return -1;
1327 }
1328 }
1329
1330 /*
1331 * There are multiple VALUE's, keyed by attribute, so we
1332 * take care of that here.
1333 */
1334 if (!fr_hash_table_replace(values_byvalue, dval)) {
1335 fr_strerror_printf("dict_addvalue: Failed inserting value %s",
1336 namestr);
1337 return -1;
1338 }
1339
1340 return 0;
1341 }
1342
sscanf_i(char const * str,unsigned int * pvalue)1343 static int sscanf_i(char const *str, unsigned int *pvalue)
1344 {
1345 int rcode = 0;
1346 int base = 10;
1347 static char const *tab = "0123456789";
1348
1349 if ((str[0] == '0') &&
1350 ((str[1] == 'x') || (str[1] == 'X'))) {
1351 tab = "0123456789abcdef";
1352 base = 16;
1353
1354 str += 2;
1355 }
1356
1357 while (*str) {
1358 char const *c;
1359
1360 if (*str == '.') break;
1361
1362 c = memchr(tab, tolower((int) *str), base);
1363 if (!c) return 0;
1364
1365 rcode *= base;
1366 rcode += (c - tab);
1367 str++;
1368 }
1369
1370 *pvalue = rcode;
1371 return 1;
1372 }
1373
1374
1375 /*
1376 * Get the OID based on various pieces of information.
1377 *
1378 * Remember, the packing format is weird.
1379 *
1380 * Vendor Attribute
1381 * ------ ---------
1382 * 00VID 000000AA normal VSA for vendor VID
1383 * 00VID AABBCCDD normal VSAs with TLVs
1384 * EE000 000000AA extended attr (241.1)
1385 * EE000 AABBCCDD extended attr with TLVs
1386 * EEVID 000000AA EVS with vendor VID, attr AAA
1387 * EEVID AABBCCDD EVS with TLVs
1388 *
1389 * <whew>! Are we crazy, or what?
1390 */
dict_str2oid(char const * ptr,unsigned int * pvalue,unsigned int * pvendor,int tlv_depth)1391 int dict_str2oid(char const *ptr, unsigned int *pvalue, unsigned int *pvendor,
1392 int tlv_depth)
1393 {
1394 char const *p;
1395 unsigned int attr;
1396
1397 #ifdef WITH_DICT_OID_DEBUG
1398 fprintf(stderr, "PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
1399 tlv_depth, *pvalue, *pvendor);
1400 #endif
1401
1402 if (tlv_depth > fr_attr_max_tlv) {
1403 fr_strerror_printf("Too many sub-attributes");
1404 return -1;
1405 }
1406
1407 /*
1408 * No vendor, try to do basic parsing.
1409 */
1410 if (!*pvendor && !*pvalue) {
1411 /*
1412 * Can't call us with a pre-parsed value and no vendor.
1413 */
1414 if (tlv_depth != 0) {
1415 fr_strerror_printf("Invalid call with wrong TLV depth %d", tlv_depth);
1416 return -1;
1417 }
1418
1419 p = strchr(ptr, '.');
1420 if (!sscanf_i(ptr, &attr)) {
1421 fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
1422 return -1;
1423 }
1424
1425 /*
1426 * Normal attribute with no OID. Return it.
1427 */
1428 if (!p) {
1429 *pvalue = attr;
1430 goto done;
1431 }
1432
1433 /*
1434 * We have an OID, look up the attribute to see what it is.
1435 */
1436 if (attr != PW_VENDOR_SPECIFIC) {
1437 DICT_ATTR const *da;
1438
1439 da = dict_attrbyvalue(attr, 0);
1440 if (!da) {
1441 *pvalue = attr;
1442 goto done;
1443 }
1444
1445 /*
1446 * Standard attributes (including internal
1447 * ones) can have TLVs, but only for some
1448 * of them.
1449 */
1450 if (!da->flags.extended) {
1451 #ifdef PW_IPV6_6RD_CONFIGURATION
1452 if (attr == PW_IPV6_6RD_CONFIGURATION) {
1453 *pvalue = attr;
1454 ptr = p + 1;
1455 tlv_depth = 1;
1456 goto keep_parsing;
1457 }
1458 #endif
1459 fr_strerror_printf("Standard attributes cannot use OIDs");
1460 return -1;
1461 }
1462
1463 *pvendor = attr * FR_MAX_VENDOR;
1464 ptr = p + 1;
1465 } /* and fall through to re-parsing the VSA */
1466
1467 /*
1468 * Look for the attribute number.
1469 */
1470 if (!sscanf_i(ptr, &attr)) {
1471 fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
1472 return -1;
1473 }
1474
1475 p = strchr(ptr, '.');
1476
1477 /*
1478 * Handle VSAs. Either in the normal space, or in the extended space.
1479 */
1480 if (attr == PW_VENDOR_SPECIFIC) {
1481 if (!p) {
1482 *pvalue = attr;
1483 goto done;
1484 }
1485 ptr = p + 1;
1486
1487 if (!sscanf_i(ptr, &attr)) {
1488 fr_strerror_printf("Invalid data '%s' in vendor identifier", ptr);
1489 return -1;
1490 }
1491
1492 p = strchr(ptr, '.');
1493 if (!p) {
1494 fr_strerror_printf("Cannot define VENDOR in an ATTRIBUTE");
1495 return -1;
1496 }
1497 ptr = p + 1;
1498
1499 *pvendor |= attr;
1500 } else {
1501 *pvalue = attr;
1502 }
1503 } /* fall through to processing an OID with pre-defined *pvendor and *pvalue */
1504
1505 keep_parsing:
1506 #ifdef WITH_DICT_OID_DEBUG
1507 fprintf(stderr, "KEEP PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
1508 tlv_depth, *pvalue, *pvendor);
1509 #endif
1510
1511 /*
1512 * Check the vendor. Only RFC format attributes can have TLVs.
1513 */
1514 if (*pvendor) {
1515 DICT_VENDOR const *dv = NULL;
1516
1517 dv = dict_vendorbyvalue(*pvendor);
1518 if (dv && (dv->type != 1)) {
1519 if (*pvalue || (tlv_depth != 0)) {
1520 fr_strerror_printf("Attribute cannot have TLVs");
1521 return -1;
1522 }
1523
1524 if (!sscanf_i(ptr, &attr)) {
1525 fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
1526 return -1;
1527 }
1528
1529 if ((dv->type < 3) && (attr > (unsigned int) (1 << (8 * dv->type)))) {
1530 fr_strerror_printf("Number '%s' out of allowed range in attribute identifier", ptr);
1531 return -1;
1532 }
1533
1534 *pvalue = attr;
1535
1536 #ifdef WITH_DHCP
1537 /*
1538 * DHCP attributes can have TLVs. <sigh>
1539 */
1540 if (*pvendor == 54) goto dhcp_skip;
1541 #endif
1542 goto done;
1543 }
1544 }
1545
1546 /*
1547 * Parse the rest of the TLVs.
1548 */
1549 while (tlv_depth <= fr_attr_max_tlv) {
1550 #ifdef WITH_DICT_OID_DEBUG
1551 fprintf(stderr, "TLV PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
1552 tlv_depth, *pvalue, *pvendor);
1553 #endif
1554
1555 if (!sscanf_i(ptr, &attr)) {
1556 fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
1557 return -1;
1558 }
1559
1560 if (attr > fr_attr_mask[tlv_depth]) {
1561 fr_strerror_printf("Number '%s' out of allowed range in attribute identifier", ptr);
1562 return -1;
1563 }
1564
1565 attr <<= fr_attr_shift[tlv_depth];
1566
1567 #ifdef WITH_DICT_OID_DEBUG
1568 if (*pvendor) {
1569 DICT_ATTR const *da;
1570
1571 da = dict_parent(*pvalue | attr, *pvendor);
1572 if (!da) {
1573 fprintf(stderr, "STR2OID FAILED PARENT %08x | %08x, %08x\n",
1574 *pvalue, attr, *pvendor);
1575 } else if ((da->attr != *pvalue) || (da->vendor != *pvendor)) {
1576 fprintf(stderr, "STR2OID DISAGREEMENT WITH PARENT %08x, %08x\t%08x, %08x\n",
1577 *pvalue, *pvendor, da->attr, da->vendor);
1578 }
1579 }
1580 #endif
1581
1582 *pvalue |= attr;
1583
1584 #ifdef WITH_DHCP
1585 dhcp_skip:
1586 #endif
1587 p = strchr(ptr, '.');
1588 if (!p) break;
1589
1590 ptr = p + 1;
1591 tlv_depth++;
1592 }
1593
1594 done:
1595 #ifdef WITH_DICT_OID_DEBUG
1596 fprintf(stderr, "RETURNING %08x %08x\n", *pvalue, *pvendor);
1597 #endif
1598 return 0;
1599 }
1600
1601
1602 /*
1603 * Process the ATTRIBUTE command
1604 */
process_attribute(char const * fn,int const line,unsigned int block_vendor,DICT_ATTR const * block_tlv,int tlv_depth,char ** argv,int argc)1605 static int process_attribute(char const* fn, int const line,
1606 unsigned int block_vendor,
1607 DICT_ATTR const *block_tlv, int tlv_depth,
1608 char **argv, int argc)
1609 {
1610 int oid = 0;
1611 unsigned int vendor = 0;
1612 unsigned int value;
1613 int type;
1614 unsigned int length;
1615 ATTR_FLAGS flags;
1616 char *p;
1617
1618 if ((argc < 3) || (argc > 4)) {
1619 fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
1620 fn, line);
1621 return -1;
1622 }
1623
1624 /*
1625 * Dictionaries need to have real names, not shitty ones.
1626 */
1627 if (strncmp(argv[0], "Attr-", 5) == 0) {
1628 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute name",
1629 fn, line);
1630 return -1;
1631 }
1632
1633 memset(&flags, 0, sizeof(flags));
1634
1635 /*
1636 * Look for OIDs before doing anything else.
1637 */
1638 if (strchr(argv[1], '.') != NULL) oid = 1;
1639
1640 {
1641 DICT_ATTR const *da;
1642
1643 vendor = block_vendor;
1644
1645 if (!block_tlv) {
1646 value = 0;
1647 } else {
1648 value = block_tlv->attr;
1649 }
1650
1651 /*
1652 * Parse OID.
1653 */
1654 if (dict_str2oid(argv[1], &value, &vendor, tlv_depth) < 0) {
1655 char buffer[256];
1656
1657 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1658
1659 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier: %s", fn, line, buffer);
1660 return -1;
1661 }
1662 block_vendor = vendor;
1663
1664 if (oid) {
1665 /*
1666 * Set the flags based on the parents flags.
1667 */
1668 da = dict_parent(value, vendor);
1669 if (!da) {
1670 fr_strerror_printf("dict_init: %s[%d]: Parent attribute for %08x,%08x is undefined.", fn, line, value, vendor);
1671 return -1;
1672 }
1673
1674 flags.extended = da->flags.extended;
1675 flags.long_extended = da->flags.long_extended;
1676 flags.evs = da->flags.evs;
1677 if (da->flags.has_tlv) flags.is_tlv = 1;
1678 }
1679 }
1680
1681 if (strncmp(argv[2], "octets[", 7) != 0) {
1682 /*
1683 * find the type of the attribute.
1684 */
1685 type = fr_str2int(dict_attr_types, argv[2], -1);
1686 if (type < 0) {
1687 fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
1688 fn, line, argv[2]);
1689 return -1;
1690 }
1691
1692 } else {
1693 type = PW_TYPE_OCTETS;
1694
1695 p = strchr(argv[2] + 7, ']');
1696 if (!p) {
1697 fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
1698 return -1;
1699 }
1700
1701 *p = 0;
1702
1703 if (!sscanf_i(argv[2] + 7, &length)) {
1704 fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1705 return -1;
1706 }
1707
1708 if ((length == 0) || (length > 253)) {
1709 fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1710 return -1;
1711 }
1712
1713 flags.length = length;
1714 }
1715
1716 /*
1717 * Parse options.
1718 */
1719 if (argc >= 4) {
1720 char *key, *next, *last;
1721
1722 /*
1723 * Keep it real.
1724 */
1725 if (flags.extended) {
1726 fr_strerror_printf("dict_init: %s[%d]: Extended attributes cannot use flags", fn, line);
1727 return -1;
1728 }
1729
1730 key = argv[3];
1731 do {
1732 next = strchr(key, ',');
1733 if (next) *(next++) = '\0';
1734
1735 /*
1736 * Boolean flag, means this is a tagged
1737 * attribute.
1738 */
1739 if ((strcmp(key, "has_tag") == 0) || (strcmp(key, "has_tag=1") == 0)) {
1740 flags.has_tag = 1;
1741
1742 /*
1743 * Encryption method, defaults to 0 (none).
1744 * Currently valid is just type 2,
1745 * Tunnel-Password style, which can only
1746 * be applied to strings.
1747 */
1748 } else if (strncmp(key, "encrypt=", 8) == 0) {
1749 flags.encrypt = strtol(key + 8, &last, 0);
1750 if (*last) {
1751 fr_strerror_printf("dict_init: %s[%d] invalid option %s",
1752 fn, line, key);
1753 return -1;
1754 }
1755
1756 if ((flags.encrypt == FLAG_ENCRYPT_ASCEND_SECRET) &&
1757 (type != PW_TYPE_STRING)) {
1758 fr_strerror_printf("dict_init: %s[%d] Only \"string\" types can have the "
1759 "\"encrypt=3\" flag set", fn, line);
1760 return -1;
1761 }
1762 flags.secret = 1;
1763
1764 } else if (strncmp(key, "secret", 6) == 0) {
1765 flags.secret = 1;
1766
1767 } else if (strncmp(key, "array", 6) == 0) {
1768 flags.array = 1;
1769
1770 switch (type) {
1771 case PW_TYPE_IPV4_ADDR:
1772 case PW_TYPE_IPV6_ADDR:
1773 case PW_TYPE_BYTE:
1774 case PW_TYPE_SHORT:
1775 case PW_TYPE_INTEGER:
1776 case PW_TYPE_DATE:
1777 case PW_TYPE_STRING:
1778 break;
1779
1780 default:
1781 fr_strerror_printf("dict_init: %s[%d] \"%s\" type cannot have the "
1782 "\"array\" flag set",
1783 fn, line,
1784 fr_int2str(dict_attr_types, type, "<UNKNOWN>"));
1785 return -1;
1786 }
1787
1788 } else if (strncmp(key, "concat", 7) == 0) {
1789 flags.concat = 1;
1790
1791 if (type != PW_TYPE_OCTETS) {
1792 fr_strerror_printf("dict_init: %s[%d] Only \"octets\" type can have the "
1793 "\"concat\" flag set", fn, line);
1794 return -1;
1795 }
1796
1797 } else if (strncmp(key, "virtual", 8) == 0) {
1798 flags.virtual = 1;
1799
1800 if (vendor != 0) {
1801 fr_strerror_printf("dict_init: %s[%d] VSAs cannot have the \"virtual\" "
1802 "flag set", fn, line);
1803 return -1;
1804 }
1805
1806 if (value < 256) {
1807 fr_strerror_printf("dict_init: %s[%d] Standard attributes cannot "
1808 "have the \"virtual\" flag set", fn, line);
1809 return -1;
1810 }
1811
1812 /*
1813 * The only thing is the vendor name,
1814 * and it's a known name: allow it.
1815 */
1816 } else if ((key == argv[3]) && !next) {
1817 if (oid) {
1818 fr_strerror_printf("dict_init: %s[%d] New-style attributes cannot use "
1819 "a vendor flag", fn, line);
1820 return -1;
1821 }
1822
1823 if (block_vendor) {
1824 fr_strerror_printf("dict_init: %s[%d] Vendor flag inside of \"BEGIN-VENDOR\" "
1825 "is not allowed", fn, line);
1826 return -1;
1827 }
1828
1829 vendor = dict_vendorbyname(key);
1830 if (!vendor) goto unknown;
1831 break;
1832
1833 } else {
1834 unknown:
1835 fr_strerror_printf("dict_init: %s[%d]: unknown option \"%s\"", fn, line, key);
1836 return -1;
1837 }
1838
1839 key = next;
1840 if (key && !*key) break;
1841 } while (key);
1842 }
1843
1844 if (block_vendor) vendor = block_vendor;
1845
1846 /*
1847 * Special checks for tags, they make our life much more
1848 * difficult.
1849 */
1850 if (flags.has_tag) {
1851 /*
1852 * Only string, octets, and integer can be tagged.
1853 */
1854 switch (type) {
1855 case PW_TYPE_STRING:
1856 case PW_TYPE_INTEGER:
1857 break;
1858
1859 default:
1860 fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
1861 fn, line,
1862 fr_int2str(dict_attr_types, type, "?Unknown?"));
1863 return -1;
1864 }
1865 }
1866
1867 if (type == PW_TYPE_TLV) {
1868 if (vendor && (vendor < FR_MAX_VENDOR)
1869 #ifdef WITH_DHCP
1870 && (vendor != DHCP_MAGIC_VENDOR)
1871 #endif
1872 ) {
1873 DICT_VENDOR *dv;
1874
1875 dv = dict_vendorbyvalue(vendor);
1876 if (!dv || (dv->type != 1) || (dv->length != 1)) {
1877 fr_strerror_printf("dict_init: %s[%d]: Type \"tlv\" can only be for \"format=1,1\".",
1878 fn, line);
1879 return -1;
1880 }
1881
1882 }
1883 flags.has_tlv = 1;
1884 }
1885
1886 if (block_tlv) {
1887 /*
1888 * TLV's can be only one octet.
1889 */
1890 if ((value == 0) || ((value & ~fr_attr_mask[tlv_depth]) != 0)) {
1891 fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
1892 fn, line);
1893 return -1;
1894 }
1895
1896 /*
1897 * Shift the value left.
1898 */
1899 value <<= fr_attr_shift[tlv_depth];
1900 value |= block_tlv->attr;
1901 flags.is_tlv = 1;
1902 }
1903
1904 #ifdef WITH_DICTIONARY_WARNINGS
1905 /*
1906 * Hack to help us discover which vendors have illegal
1907 * attributes.
1908 */
1909 if (!vendor && (value < 256) &&
1910 !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
1911 fprintf(stderr, "WARNING: Illegal Attribute %s in %s\n",
1912 argv[0], fn);
1913 }
1914 #endif
1915
1916 /*
1917 * Add it in.
1918 */
1919 if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
1920 char buffer[256];
1921
1922 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1923
1924 fr_strerror_printf("dict_init: %s[%d]: %s",
1925 fn, line, buffer);
1926 return -1;
1927 }
1928
1929 return 0;
1930 }
1931
1932
1933 /*
1934 * Process the VALUE command
1935 */
process_value(char const * fn,int const line,char ** argv,int argc)1936 static int process_value(char const* fn, int const line, char **argv,
1937 int argc)
1938 {
1939 unsigned int value;
1940
1941 if (argc != 3) {
1942 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
1943 fn, line);
1944 return -1;
1945 }
1946 /*
1947 * For Compatibility, skip "Server-Config"
1948 */
1949 if (strcasecmp(argv[0], "Server-Config") == 0)
1950 return 0;
1951
1952 /*
1953 * Validate all entries
1954 */
1955 if (!sscanf_i(argv[2], &value)) {
1956 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1957 fn, line);
1958 return -1;
1959 }
1960
1961 if (dict_addvalue(argv[1], argv[0], value) < 0) {
1962 char buffer[256];
1963
1964 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1965
1966 fr_strerror_printf("dict_init: %s[%d]: %s",
1967 fn, line, buffer);
1968 return -1;
1969 }
1970
1971 return 0;
1972 }
1973
1974
1975 /*
1976 * Process the VALUE-ALIAS command
1977 *
1978 * This allows VALUE mappings to be shared among multiple
1979 * attributes.
1980 */
process_value_alias(char const * fn,int const line,char ** argv,int argc)1981 static int process_value_alias(char const* fn, int const line, char **argv,
1982 int argc)
1983 {
1984 DICT_ATTR const *my_da, *da;
1985 DICT_VALUE *dval;
1986
1987 if (argc != 2) {
1988 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
1989 fn, line);
1990 return -1;
1991 }
1992
1993 my_da = dict_attrbyname(argv[0]);
1994 if (!my_da) {
1995 fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
1996 fn, line, argv[1]);
1997 return -1;
1998 }
1999
2000 if (my_da->flags.has_value_alias) {
2001 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
2002 fn, line, argv[0]);
2003 return -1;
2004 }
2005
2006 da = dict_attrbyname(argv[1]);
2007 if (!da) {
2008 fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
2009 fn, line, argv[1]);
2010 return -1;
2011 }
2012
2013 if (da->flags.has_value_alias) {
2014 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
2015 fn, line, argv[1]);
2016 return -1;
2017 }
2018
2019 if (my_da->type != da->type) {
2020 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
2021 fn, line);
2022 return -1;
2023 }
2024
2025 if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
2026 fr_strerror_printf("dict_addvalue: out of memory");
2027 return -1;
2028 }
2029
2030 dval->name[0] = '\0'; /* empty name */
2031 dval->attr = my_da->attr;
2032 dval->vendor = my_da->vendor;
2033 dval->value = da->attr;
2034
2035 if (!fr_hash_table_insert(values_byname, dval)) {
2036 fr_strerror_printf("dict_init: %s[%d]: Error create alias",
2037 fn, line);
2038 fr_pool_free(dval);
2039 return -1;
2040 }
2041
2042 return 0;
2043 }
2044
2045
parse_format(char const * fn,int line,char const * format,int * ptype,int * plength,bool * pcontinuation)2046 static int parse_format(char const *fn, int line, char const *format, int *ptype, int *plength, bool *pcontinuation)
2047 {
2048 char const *p;
2049 int type, length;
2050 bool continuation = false;
2051
2052 if (strncasecmp(format, "format=", 7) != 0) {
2053 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected \"format=\", got \"%s\"",
2054 fn, line, format);
2055 return -1;
2056 }
2057
2058 p = format + 7;
2059 if ((strlen(p) < 3) ||
2060 !isdigit((int) p[0]) ||
2061 (p[1] != ',') ||
2062 !isdigit((int) p[2]) ||
2063 (p[3] && (p[3] != ','))) {
2064 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
2065 fn, line, p);
2066 return -1;
2067 }
2068
2069 type = (int) (p[0] - '0');
2070 length = (int) (p[2] - '0');
2071
2072 if ((type != 1) && (type != 2) && (type != 4)) {
2073 fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
2074 fn, line, type);
2075 return -1;
2076 }
2077
2078 if ((length != 0) && (length != 1) && (length != 2)) {
2079 fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
2080 fn, line, length);
2081 return -1;
2082 }
2083
2084 if (p[3] == ',') {
2085 if (!p[4]) {
2086 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
2087 fn, line, p);
2088 return -1;
2089 }
2090
2091 if ((p[4] != 'c') ||
2092 (p[5] != '\0')) {
2093 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
2094 fn, line, p);
2095 return -1;
2096 }
2097 continuation = true;
2098
2099 if ((type != 1) || (length != 1)) {
2100 fr_strerror_printf("dict_init: %s[%d]: Only 'format=1,1' VSAs can have continuations",
2101 fn, line);
2102 return -1;
2103 }
2104 }
2105
2106 *ptype = type;
2107 *plength = length;
2108 *pcontinuation = continuation;
2109 return 0;
2110 }
2111
2112
2113 /*
2114 * Process the VENDOR command
2115 */
process_vendor(char const * fn,int const line,char ** argv,int argc)2116 static int process_vendor(char const* fn, int const line, char **argv,
2117 int argc)
2118 {
2119 int value;
2120 int type, length;
2121 bool continuation = false;
2122 DICT_VENDOR *dv;
2123
2124 if ((argc < 2) || (argc > 3)) {
2125 fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
2126 fn, line);
2127 return -1;
2128 }
2129
2130 /*
2131 * Validate all entries
2132 */
2133 if (!isdigit((int) argv[1][0])) {
2134 fr_strerror_printf("dict_init: %s[%d]: invalid value",
2135 fn, line);
2136 return -1;
2137 }
2138 value = atoi(argv[1]);
2139
2140 /* Create a new VENDOR entry for the list */
2141 if (dict_addvendor(argv[0], value) < 0) {
2142 char buffer[256];
2143
2144 strlcpy(buffer, fr_strerror(), sizeof(buffer));
2145
2146 fr_strerror_printf("dict_init: %s[%d]: %s",
2147 fn, line, buffer);
2148 return -1;
2149 }
2150
2151 /*
2152 * Look for a format statement. Allow it to over-ride the hard-coded formats below.
2153 */
2154 if (argc == 3) {
2155 if (parse_format(fn, line, argv[2], &type, &length, &continuation) < 0) {
2156 return -1;
2157 }
2158
2159 } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
2160 type = 4;
2161 length = 0;
2162
2163 } else if (value == VENDORPEC_LUCENT) {
2164 type = 2;
2165 length = 1;
2166
2167 } else if (value == VENDORPEC_STARENT) {
2168 type = 2;
2169 length = 2;
2170
2171 } else {
2172 type = length = 1;
2173 }
2174
2175 dv = dict_vendorbyvalue(value);
2176 if (!dv) {
2177 fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
2178 fn, line);
2179 return -1;
2180 }
2181
2182 dv->type = type;
2183 dv->length = length;
2184 dv->flags = continuation;
2185
2186 return 0;
2187 }
2188
2189 /*
2190 * String split routine. Splits an input string IN PLACE
2191 * into pieces, based on spaces.
2192 */
str2argv(char * str,char ** argv,int max_argc)2193 int str2argv(char *str, char **argv, int max_argc)
2194 {
2195 int argc = 0;
2196
2197 while (*str) {
2198 if (argc >= max_argc) break;
2199
2200 /*
2201 * Chop out comments early.
2202 */
2203 if (*str == '#') {
2204 *str = '\0';
2205 break;
2206 }
2207
2208 while ((*str == ' ') ||
2209 (*str == '\t') ||
2210 (*str == '\r') ||
2211 (*str == '\n')) *(str++) = '\0';
2212
2213 if (!*str) break;
2214
2215 argv[argc] = str;
2216 argc++;
2217
2218 while (*str &&
2219 (*str != ' ') &&
2220 (*str != '\t') &&
2221 (*str != '\r') &&
2222 (*str != '\n')) str++;
2223 }
2224
2225 return argc;
2226 }
2227
2228 static int my_dict_init(char const *parent, char const *filename,
2229 char const *src_file, int src_line);
2230
dict_read(char const * dir,char const * filename)2231 int dict_read(char const *dir, char const *filename)
2232 {
2233 if (!attributes_byname) {
2234 fr_strerror_printf("Must call dict_init() before dict_read()");
2235 return -1;
2236 }
2237
2238 return my_dict_init(dir, filename, NULL, 0);
2239 }
2240
2241
2242 #define MAX_ARGV (16)
2243
2244 /*
2245 * Initialize the dictionary.
2246 */
my_dict_init(char const * parent,char const * filename,char const * src_file,int src_line)2247 static int my_dict_init(char const *parent, char const *filename,
2248 char const *src_file, int src_line)
2249 {
2250 FILE *fp;
2251 char dir[256], fn[256];
2252 char buf[256];
2253 char *p;
2254 int line = 0;
2255 unsigned int vendor;
2256 unsigned int block_vendor;
2257 struct stat statbuf;
2258 char *argv[MAX_ARGV];
2259 int argc;
2260 DICT_ATTR const *da, *block_tlv[MAX_TLV_NEST + 1];
2261 int which_block_tlv = 0;
2262
2263 block_tlv[0] = NULL;
2264 block_tlv[1] = NULL;
2265 block_tlv[2] = NULL;
2266 block_tlv[3] = NULL;
2267
2268 if ((strlen(parent) + 3 + strlen(filename)) > sizeof(dir)) {
2269 fr_strerror_printf("dict_init: filename name too long");
2270 return -1;
2271 }
2272
2273 /*
2274 * If it's an absolute dir, forget the parent dir,
2275 * and remember the new one.
2276 *
2277 * If it's a relative dir, tack on the current filename
2278 * to the parent dir. And use that.
2279 */
2280 if (!FR_DIR_IS_RELATIVE(filename)) {
2281 strlcpy(dir, filename, sizeof(dir));
2282 p = strrchr(dir, FR_DIR_SEP);
2283 if (p) {
2284 p[1] = '\0';
2285 } else {
2286 strlcat(dir, "/", sizeof(dir));
2287 }
2288
2289 strlcpy(fn, filename, sizeof(fn));
2290 } else {
2291 strlcpy(dir, parent, sizeof(dir));
2292 p = strrchr(dir, FR_DIR_SEP);
2293 if (p) {
2294 if (p[1]) strlcat(dir, "/", sizeof(dir));
2295 } else {
2296 strlcat(dir, "/", sizeof(dir));
2297 }
2298 strlcat(dir, filename, sizeof(dir));
2299 p = strrchr(dir, FR_DIR_SEP);
2300 if (p) {
2301 p[1] = '\0';
2302 } else {
2303 strlcat(dir, "/", sizeof(dir));
2304 }
2305
2306 p = strrchr(filename, FR_DIR_SEP);
2307 if (p) {
2308 snprintf(fn, sizeof(fn), "%s%s", dir, p);
2309 } else {
2310 snprintf(fn, sizeof(fn), "%s%s", dir, filename);
2311 }
2312
2313 }
2314
2315 /*
2316 * Check if we've loaded this file before. If so, ignore it.
2317 */
2318 p = strrchr(fn, FR_DIR_SEP);
2319 if (p) {
2320 *p = '\0';
2321 if (dict_stat_check(fn, p + 1)) {
2322 *p = FR_DIR_SEP;
2323 return 0;
2324 }
2325 *p = FR_DIR_SEP;
2326 }
2327
2328 if ((fp = fopen(fn, "r")) == NULL) {
2329 if (!src_file) {
2330 fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
2331 fn, fr_syserror(errno));
2332 } else {
2333 fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
2334 src_file, src_line, fn, fr_syserror(errno));
2335 }
2336 return -2;
2337 }
2338
2339 stat(fn, &statbuf); /* fopen() guarantees this will succeed */
2340 if (!S_ISREG(statbuf.st_mode)) {
2341 fclose(fp);
2342 fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
2343 fn);
2344 return -1;
2345 }
2346
2347 /*
2348 * Globally writable dictionaries means that users can control
2349 * the server configuration with little difficulty.
2350 */
2351 #ifdef S_IWOTH
2352 if ((statbuf.st_mode & S_IWOTH) != 0) {
2353 fclose(fp);
2354 fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable. Refusing to start due to insecure configuration.",
2355 fn);
2356 return -1;
2357 }
2358 #endif
2359
2360 dict_stat_add(&statbuf);
2361
2362 /*
2363 * Seed the random pool with data.
2364 */
2365 fr_rand_seed(&statbuf, sizeof(statbuf));
2366
2367 block_vendor = 0;
2368
2369 while (fgets(buf, sizeof(buf), fp) != NULL) {
2370 line++;
2371 if (buf[0] == '#' || buf[0] == 0 ||
2372 buf[0] == '\n' || buf[0] == '\r')
2373 continue;
2374
2375 /*
2376 * Comment characters should NOT be appearing anywhere but
2377 * as start of a comment;
2378 */
2379 p = strchr(buf, '#');
2380 if (p) *p = '\0';
2381
2382 argc = str2argv(buf, argv, MAX_ARGV);
2383 if (argc == 0) continue;
2384
2385 if (argc == 1) {
2386 fr_strerror_printf( "dict_init: %s[%d] invalid entry",
2387 fn, line);
2388 fclose(fp);
2389 return -1;
2390 }
2391
2392 /*
2393 * Process VALUE lines.
2394 */
2395 if (strcasecmp(argv[0], "VALUE") == 0) {
2396 if (process_value(fn, line,
2397 argv + 1, argc - 1) == -1) {
2398 fclose(fp);
2399 return -1;
2400 }
2401 continue;
2402 }
2403
2404 /*
2405 * Perhaps this is an attribute.
2406 */
2407 if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
2408 if (process_attribute(fn, line, block_vendor,
2409 block_tlv[which_block_tlv],
2410 which_block_tlv,
2411 argv + 1, argc - 1) == -1) {
2412 fclose(fp);
2413 return -1;
2414 }
2415 continue;
2416 }
2417
2418 /*
2419 * See if we need to import another dictionary.
2420 */
2421 if (strcasecmp(argv[0], "$INCLUDE") == 0) {
2422 if (my_dict_init(dir, argv[1], fn, line) < 0) {
2423 fclose(fp);
2424 return -1;
2425 }
2426 continue;
2427 } /* $INCLUDE */
2428
2429 /*
2430 * Optionally include a dictionary
2431 */
2432 if ((strcasecmp(argv[0], "$INCLUDE-") == 0) ||
2433 (strcasecmp(argv[0], "$-INCLUDE") == 0)) {
2434 int rcode = my_dict_init(dir, argv[1], fn, line);
2435
2436 if (rcode == -2) continue;
2437
2438 if (rcode < 0) {
2439 fclose(fp);
2440 return -1;
2441 }
2442 continue;
2443 } /* $INCLUDE- */
2444
2445 if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
2446 if (process_value_alias(fn, line,
2447 argv + 1, argc - 1) == -1) {
2448 fclose(fp);
2449 return -1;
2450 }
2451 continue;
2452 }
2453
2454 /*
2455 * Process VENDOR lines.
2456 */
2457 if (strcasecmp(argv[0], "VENDOR") == 0) {
2458 if (process_vendor(fn, line,
2459 argv + 1, argc - 1) == -1) {
2460 fclose(fp);
2461 return -1;
2462 }
2463 continue;
2464 }
2465
2466 if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
2467 if (argc != 2) {
2468 fr_strerror_printf(
2469 "dict_init: %s[%d] invalid BEGIN-TLV entry",
2470 fn, line);
2471 fclose(fp);
2472 return -1;
2473 }
2474
2475 da = dict_attrbyname(argv[1]);
2476 if (!da) {
2477 fr_strerror_printf(
2478 "dict_init: %s[%d]: unknown attribute %s",
2479 fn, line, argv[1]);
2480 fclose(fp);
2481 return -1;
2482 }
2483
2484 if (da->type != PW_TYPE_TLV) {
2485 fr_strerror_printf(
2486 "dict_init: %s[%d]: attribute %s is not of type tlv",
2487 fn, line, argv[1]);
2488 fclose(fp);
2489 return -1;
2490 }
2491
2492 if (which_block_tlv >= MAX_TLV_NEST) {
2493 fr_strerror_printf(
2494 "dict_init: %s[%d]: TLVs are nested too deep",
2495 fn, line);
2496 fclose(fp);
2497 return -1;
2498 }
2499
2500
2501 block_tlv[++which_block_tlv] = da;
2502 continue;
2503 } /* BEGIN-TLV */
2504
2505 if (strcasecmp(argv[0], "END-TLV") == 0) {
2506 if (argc != 2) {
2507 fr_strerror_printf(
2508 "dict_init: %s[%d] invalid END-TLV entry",
2509 fn, line);
2510 fclose(fp);
2511 return -1;
2512 }
2513
2514 da = dict_attrbyname(argv[1]);
2515 if (!da) {
2516 fr_strerror_printf(
2517 "dict_init: %s[%d]: unknown attribute %s",
2518 fn, line, argv[1]);
2519 fclose(fp);
2520 return -1;
2521 }
2522
2523 if (da != block_tlv[which_block_tlv]) {
2524 fr_strerror_printf(
2525 "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
2526 fn, line, argv[1]);
2527 fclose(fp);
2528 return -1;
2529 }
2530 block_tlv[which_block_tlv--] = NULL;
2531 continue;
2532 } /* END-VENDOR */
2533
2534 if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
2535 if (argc < 2) {
2536 fr_strerror_printf(
2537 "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
2538 fn, line);
2539 fclose(fp);
2540 return -1;
2541 }
2542
2543 vendor = dict_vendorbyname(argv[1]);
2544 if (!vendor) {
2545 fr_strerror_printf(
2546 "dict_init: %s[%d]: unknown vendor %s",
2547 fn, line, argv[1]);
2548 fclose(fp);
2549 return -1;
2550 }
2551
2552 block_vendor = vendor;
2553
2554 /*
2555 * Check for extended attr VSAs
2556 *
2557 * BEGIN-VENDOR foo format=Foo-Encapsulation-Attr
2558 */
2559 if (argc > 2) {
2560 if ((strncmp(argv[2], "format=", 7) != 0) &&
2561 (strncmp(argv[2], "parent=", 7) != 0)) {
2562 fr_strerror_printf(
2563 "dict_init: %s[%d]: Invalid format %s",
2564 fn, line, argv[2]);
2565 fclose(fp);
2566 return -1;
2567 }
2568
2569 p = argv[2] + 7;
2570 da = dict_attrbyname(p);
2571 if (!da) {
2572 fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR: unknown attribute \"%s\"",
2573 fn, line, p);
2574 fclose(fp);
2575 return -1;
2576 }
2577
2578 if (!da->flags.evs) {
2579 fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR. Attribute \"%s\" is not of \"evs\" data type",
2580 fn, line, p);
2581 fclose(fp);
2582 return -1;
2583 }
2584
2585 /*
2586 * Pack the encapsulating
2587 * attribute into the upper 8
2588 * bits of the vendor ID
2589 */
2590 block_vendor |= da->vendor;
2591 }
2592
2593 continue;
2594 } /* BEGIN-VENDOR */
2595
2596 if (strcasecmp(argv[0], "END-VENDOR") == 0) {
2597 if (argc != 2) {
2598 fr_strerror_printf(
2599 "dict_init: %s[%d] invalid END-VENDOR entry",
2600 fn, line);
2601 fclose(fp);
2602 return -1;
2603 }
2604
2605 vendor = dict_vendorbyname(argv[1]);
2606 if (!vendor) {
2607 fr_strerror_printf(
2608 "dict_init: %s[%d]: unknown vendor %s",
2609 fn, line, argv[1]);
2610 fclose(fp);
2611 return -1;
2612 }
2613
2614 if (vendor != (block_vendor & (FR_MAX_VENDOR - 1))) {
2615 fr_strerror_printf(
2616 "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
2617 fn, line, argv[1]);
2618 fclose(fp);
2619 return -1;
2620 }
2621 block_vendor = 0;
2622 continue;
2623 } /* END-VENDOR */
2624
2625 /*
2626 * Any other string: We don't recognize it.
2627 */
2628 fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
2629 fn, line, argv[0]);
2630 fclose(fp);
2631 return -1;
2632 }
2633 fclose(fp);
2634 return 0;
2635 }
2636
2637
2638 /*
2639 * Empty callback for hash table initialization.
2640 */
null_callback(UNUSED void * ctx,UNUSED void * data)2641 static int null_callback(UNUSED void *ctx, UNUSED void *data)
2642 {
2643 return 0;
2644 }
2645
2646
2647 /*
2648 * Initialize the directory, then fix the attr member of
2649 * all attributes.
2650 */
dict_init(char const * dir,char const * fn)2651 int dict_init(char const *dir, char const *fn)
2652 {
2653 /*
2654 * Check if we need to change anything. If not, don't do
2655 * anything.
2656 */
2657 if (dict_stat_check(dir, fn)) {
2658 return 0;
2659 }
2660
2661 /*
2662 * Free the dictionaries, and the stat cache.
2663 */
2664 dict_free();
2665
2666 /*
2667 * Create the table of vendor by name. There MAY NOT
2668 * be multiple vendors of the same name.
2669 *
2670 * Each vendor is malloc'd, so the free function is free.
2671 */
2672 vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
2673 dict_vendor_name_cmp,
2674 fr_pool_free);
2675 if (!vendors_byname) {
2676 return -1;
2677 }
2678
2679 /*
2680 * Create the table of vendors by value. There MAY
2681 * be vendors of the same value. If there are, we
2682 * pick the latest one.
2683 */
2684 vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
2685 dict_vendor_value_cmp,
2686 fr_pool_free);
2687 if (!vendors_byvalue) {
2688 return -1;
2689 }
2690
2691 /*
2692 * Create the table of attributes by name. There MAY NOT
2693 * be multiple attributes of the same name.
2694 *
2695 * Each attribute is malloc'd, so the free function is free.
2696 */
2697 attributes_byname = fr_hash_table_create(dict_attr_name_hash,
2698 dict_attr_name_cmp,
2699 fr_pool_free);
2700 if (!attributes_byname) {
2701 return -1;
2702 }
2703
2704 /*
2705 * Create the table of attributes by value. There MAY
2706 * be attributes of the same value. If there are, we
2707 * pick the latest one.
2708 */
2709 attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
2710 dict_attr_value_cmp,
2711 fr_pool_free);
2712 if (!attributes_byvalue) {
2713 return -1;
2714 }
2715
2716 /*
2717 * Horrible hacks for combo-IP.
2718 */
2719 attributes_combo = fr_hash_table_create(dict_attr_combo_hash,
2720 dict_attr_combo_cmp,
2721 fr_pool_free);
2722 if (!attributes_combo) {
2723 return -1;
2724 }
2725
2726 values_byname = fr_hash_table_create(dict_value_name_hash,
2727 dict_value_name_cmp,
2728 fr_pool_free);
2729 if (!values_byname) {
2730 return -1;
2731 }
2732
2733 values_byvalue = fr_hash_table_create(dict_value_value_hash,
2734 dict_value_value_cmp,
2735 fr_pool_free);
2736 if (!values_byvalue) {
2737 return -1;
2738 }
2739
2740 value_fixup = NULL; /* just to be safe. */
2741
2742 if (my_dict_init(dir, fn, NULL, 0) < 0)
2743 return -1;
2744
2745 if (value_fixup) {
2746 DICT_ATTR const *a;
2747 value_fixup_t *this, *next;
2748
2749 for (this = value_fixup; this != NULL; this = next) {
2750 next = this->next;
2751
2752 a = dict_attrbyname(this->attrstr);
2753 if (!a) {
2754 fr_strerror_printf(
2755 "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
2756 this->attrstr, this->dval->name);
2757 return -1; /* leak, but they should die... */
2758 }
2759
2760 this->dval->attr = a->attr;
2761
2762 /*
2763 * Add the value into the dictionary.
2764 */
2765 if (!fr_hash_table_replace(values_byname,
2766 this->dval)) {
2767 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
2768 return -1;
2769 }
2770
2771 /*
2772 * Allow them to use the old name, but
2773 * prefer the new name when printing
2774 * values.
2775 */
2776 if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
2777 fr_hash_table_replace(values_byvalue,
2778 this->dval);
2779 }
2780 free(this);
2781
2782 /*
2783 * Just so we don't lose track of things.
2784 */
2785 value_fixup = next;
2786 }
2787 }
2788
2789 /*
2790 * Walk over all of the hash tables to ensure they're
2791 * initialized. We do this because the threads may perform
2792 * lookups, and we don't want multi-threaded re-ordering
2793 * of the table entries. That would be bad.
2794 */
2795 fr_hash_table_walk(vendors_byname, null_callback, NULL);
2796 fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
2797
2798 fr_hash_table_walk(attributes_byname, null_callback, NULL);
2799 fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
2800
2801 fr_hash_table_walk(values_byvalue, null_callback, NULL);
2802 fr_hash_table_walk(values_byname, null_callback, NULL);
2803
2804 return 0;
2805 }
2806
print_attr_oid(char * buffer,size_t bufsize,unsigned int attr,unsigned int vendor)2807 static size_t print_attr_oid(char *buffer, size_t bufsize, unsigned int attr, unsigned int vendor)
2808 {
2809 int nest, dv_type = 1;
2810 size_t len;
2811 char *p = buffer;
2812
2813 if (vendor > FR_MAX_VENDOR) {
2814 len = snprintf(p, bufsize, "%u.", vendor / FR_MAX_VENDOR);
2815 p += len;
2816 bufsize -= len;
2817 vendor &= (FR_MAX_VENDOR) - 1;
2818 }
2819
2820 if (vendor) {
2821 DICT_VENDOR *dv;
2822
2823 /*
2824 * dv_type is the length of the vendor's type field
2825 * RFC 2865 never defined a mandatory length, so
2826 * different vendors have different length type fields.
2827 */
2828 dv = dict_vendorbyvalue(vendor);
2829 if (dv) dv_type = dv->type;
2830
2831 len = snprintf(p, bufsize, "26.%u.", vendor);
2832
2833 p += len;
2834 bufsize -= len;
2835 }
2836
2837
2838 switch (dv_type) {
2839 default:
2840 case 1:
2841 len = snprintf(p, bufsize, "%u", attr & 0xff);
2842 p += len;
2843 bufsize -= len;
2844 if ((attr >> 8) == 0) return p - buffer;
2845 break;
2846
2847 case 2:
2848 len = snprintf(p, bufsize, "%u", attr & 0xffff);
2849 p += len;
2850 return p - buffer;
2851
2852 case 4:
2853 len = snprintf(p, bufsize, "%u", attr);
2854 p += len;
2855 return p - buffer;
2856
2857 }
2858
2859 /*
2860 * "attr" is a sequence of packed numbers. Unpack them.
2861 */
2862 for (nest = 1; nest <= fr_attr_max_tlv; nest++) {
2863 if (((attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]) == 0) break;
2864
2865 len = snprintf(p, bufsize, ".%u",
2866 (attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]);
2867
2868 p += len;
2869 bufsize -= len;
2870 }
2871
2872 return p - buffer;
2873 }
2874
2875 /** Free dynamically allocated (unknown attributes)
2876 *
2877 * If the da was dynamically allocated it will be freed, else the function
2878 * will return without doing anything.
2879 *
2880 * @param da to free.
2881 */
dict_attr_free(DICT_ATTR const ** da)2882 void dict_attr_free(DICT_ATTR const **da)
2883 {
2884 DICT_ATTR **tmp;
2885
2886 if (!da || !*da) return;
2887
2888 /* Don't free real DAs */
2889 if (!(*da)->flags.is_unknown) {
2890 return;
2891 }
2892
2893 memcpy(&tmp, &da, sizeof(*tmp));
2894 talloc_free(*tmp);
2895
2896 *tmp = NULL;
2897 }
2898
2899
2900 /** Initialises a dictionary attr for unknown attributes
2901 *
2902 * Initialises a dict attr for an unknown attribute/vendor/type without adding
2903 * it to dictionary pools/hashes.
2904 *
2905 * @param[in,out] da struct to initialise, must be at least DICT_ATTR_SIZE bytes.
2906 * @param[in] attr number.
2907 * @param[in] vendor number.
2908 * @return 0 on success.
2909 */
dict_unknown_from_fields(DICT_ATTR * da,unsigned int attr,unsigned int vendor)2910 int dict_unknown_from_fields(DICT_ATTR *da, unsigned int attr, unsigned int vendor)
2911 {
2912 char *p;
2913 size_t len = 0;
2914 size_t bufsize = DICT_ATTR_MAX_NAME_LEN;
2915
2916 memset(da, 0, DICT_ATTR_SIZE);
2917
2918 da->attr = attr;
2919 da->vendor = vendor;
2920 da->type = PW_TYPE_OCTETS;
2921 da->flags.is_unknown = true;
2922 da->flags.is_pointer = true;
2923
2924 /*
2925 * Unknown attributes of the "WiMAX" vendor get marked up
2926 * as being for WiMAX.
2927 */
2928 if (vendor == VENDORPEC_WIMAX) {
2929 da->flags.wimax = 1;
2930 }
2931
2932 p = da->name;
2933
2934 len = snprintf(p, bufsize, "Attr-");
2935 p += len;
2936 bufsize -= len;
2937
2938 print_attr_oid(p, bufsize , attr, vendor);
2939
2940 return 0;
2941 }
2942
2943 /** Allocs a dictionary attr for unknown attributes
2944 *
2945 * Allocs a dict attr for an unknown attribute/vendor/type without adding
2946 * it to dictionary pools/hashes.
2947 *
2948 * @param[in] ctx to allocate DA in.
2949 * @param[in] attr number.
2950 * @param[in] vendor number.
2951 * @return 0 on success.
2952 */
dict_unknown_afrom_fields(TALLOC_CTX * ctx,unsigned int attr,unsigned int vendor)2953 DICT_ATTR const *dict_unknown_afrom_fields(TALLOC_CTX *ctx, unsigned int attr, unsigned int vendor)
2954 {
2955 uint8_t *p;
2956 DICT_ATTR *da;
2957
2958 p = talloc_zero_array(ctx, uint8_t, DICT_ATTR_SIZE);
2959 if (!p) {
2960 fr_strerror_printf("Out of memory");
2961 return NULL;
2962 }
2963 da = (DICT_ATTR *) p;
2964 talloc_set_type(da, DICT_ATTR);
2965
2966 if (dict_unknown_from_fields(da, attr, vendor) < 0) {
2967 talloc_free(p);
2968 return NULL;
2969 }
2970
2971 return da;
2972 }
2973
2974 /** Create a DICT_ATTR from an ASCII attribute and value
2975 *
2976 * Where the attribute name is in the form:
2977 * - Attr-%d
2978 * - Attr-%d.%d.%d...
2979 * - Vendor-%d-Attr-%d
2980 * - VendorName-Attr-%d
2981 *
2982 * @param[in] da to initialise.
2983 * @param[in] name of attribute.
2984 * @return 0 on success -1 on failure.
2985 */
dict_unknown_from_str(DICT_ATTR * da,char const * name)2986 int dict_unknown_from_str(DICT_ATTR *da, char const *name)
2987 {
2988 unsigned int attr = 0, vendor = 0;
2989
2990 char const *p = name;
2991 char *q;
2992
2993 if (dict_valid_name(name) < 0) return -1;
2994
2995 /*
2996 * Pull off vendor prefix first.
2997 */
2998 if (strncasecmp(p, "Attr-", 5) != 0) {
2999 if (strncasecmp(p, "Vendor-", 7) == 0) {
3000 vendor = (int) strtol(p + 7, &q, 10);
3001 if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
3002 fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", name);
3003
3004 return -1;
3005 }
3006
3007 p = q;
3008
3009 /* must be vendor name */
3010 } else {
3011 char buffer[256];
3012
3013 q = strchr(p, '-');
3014
3015 if (!q) {
3016 fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", name);
3017 return -1;
3018 }
3019
3020 if ((size_t) (q - p) >= sizeof(buffer)) {
3021 fr_strerror_printf("Vendor name too long in attribute name \"%s\"", name);
3022
3023 return -1;
3024 }
3025
3026 memcpy(buffer, p, (q - p));
3027 buffer[q - p] = '\0';
3028
3029 vendor = dict_vendorbyname(buffer);
3030 if (!vendor) {
3031 fr_strerror_printf("Unknown name \"%s\"", name);
3032
3033 return -1;
3034 }
3035
3036 p = q;
3037 }
3038
3039 if (*p != '-') {
3040 fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", name);
3041
3042 return -1;
3043 }
3044 p++;
3045 }
3046
3047 /*
3048 * Attr-%d
3049 */
3050 if (strncasecmp(p, "Attr-", 5) != 0) {
3051 fr_strerror_printf("Unknown attribute \"%s\"", name);
3052
3053 return -1;
3054 }
3055
3056 /*
3057 * Parse the OID, with a (possibly) pre-defined vendor.
3058 */
3059 if (dict_str2oid(p + 5, &attr, &vendor, 0) < 0) {
3060 return -1;
3061 }
3062
3063 return dict_unknown_from_fields(da, attr, vendor);
3064 }
3065
3066 /** Create a DICT_ATTR from an ASCII attribute and value
3067 *
3068 * Where the attribute name is in the form:
3069 * - Attr-%d
3070 * - Attr-%d.%d.%d...
3071 * - Vendor-%d-Attr-%d
3072 * - VendorName-Attr-%d
3073 *
3074 * @param[in] ctx to alloc new attribute in.
3075 * @param[in] name of attribute.
3076 * @return 0 on success -1 on failure.
3077 */
dict_unknown_afrom_str(TALLOC_CTX * ctx,char const * name)3078 DICT_ATTR const *dict_unknown_afrom_str(TALLOC_CTX *ctx, char const *name)
3079 {
3080 uint8_t *p;
3081 DICT_ATTR *da;
3082
3083 p = talloc_zero_array(ctx, uint8_t, DICT_ATTR_SIZE);
3084 if (!p) {
3085 fr_strerror_printf("Out of memory");
3086 return NULL;
3087 }
3088 da = (DICT_ATTR *) p;
3089 talloc_set_type(da, DICT_ATTR);
3090
3091 if (dict_unknown_from_str(da, name) < 0) {
3092 talloc_free(p);
3093 return NULL;
3094 }
3095
3096 return da;
3097 }
3098
3099 /** Create a dictionary attribute by name embedded in another string
3100 *
3101 * Find the first invalid attribute name char in the string pointed
3102 * to by name.
3103 *
3104 * Copy the characters between the start of the name string and the first
3105 * none dict_attr_allowed_char to a buffer and initialise da as an
3106 * unknown attribute.
3107 *
3108 * @param[out] da to initialise.
3109 * @param[in,out] name string start.
3110 * @return 0 on success or -1 on error;
3111 */
dict_unknown_from_substr(DICT_ATTR * da,char const ** name)3112 int dict_unknown_from_substr(DICT_ATTR *da, char const **name)
3113 {
3114 char const *p;
3115 size_t len;
3116 char buffer[DICT_ATTR_MAX_NAME_LEN + 1];
3117
3118 if (!name || !*name) return -1;
3119
3120 /*
3121 * Advance p until we get something that's not part of
3122 * the dictionary attribute name.
3123 */
3124 for (p = *name; dict_attr_allowed_chars[(int) *p] || (*p == '.' ) || (*p == '-'); p++);
3125
3126 len = p - *name;
3127 if (len > DICT_ATTR_MAX_NAME_LEN) {
3128 fr_strerror_printf("Attribute name too long");
3129
3130 return -1;
3131 }
3132 if (len == 0) {
3133 fr_strerror_printf("Invalid attribute name");
3134 return -1;
3135 }
3136 strlcpy(buffer, *name, len + 1);
3137
3138 if (dict_unknown_from_str(da, buffer) < 0) return -1;
3139
3140 *name = p;
3141
3142 return 0;
3143 }
3144
3145 /*
3146 * Get an attribute by its numerical value.
3147 */
dict_attrbyvalue(unsigned int attr,unsigned int vendor)3148 DICT_ATTR const *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
3149 {
3150 DICT_ATTR da;
3151
3152 if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
3153
3154 da.attr = attr;
3155 da.vendor = vendor;
3156
3157 return fr_hash_table_finddata(attributes_byvalue, &da);
3158 }
3159
3160
3161 /** Get an attribute by its numerical value and data type
3162 *
3163 * Used only for COMBO_IP
3164 *
3165 * @return The attribute, or NULL if not found
3166 */
dict_attrbytype(unsigned int attr,unsigned int vendor,PW_TYPE type)3167 DICT_ATTR const *dict_attrbytype(unsigned int attr, unsigned int vendor,
3168 PW_TYPE type)
3169 {
3170 DICT_ATTR da;
3171
3172 da.attr = attr;
3173 da.vendor = vendor;
3174 da.type = type;
3175
3176 return fr_hash_table_finddata(attributes_combo, &da);
3177 }
3178
3179 /** Using a parent and attr/vendor, find a child attr/vendor
3180 *
3181 */
dict_attr_child(DICT_ATTR const * parent,unsigned int * pattr,unsigned int * pvendor)3182 int dict_attr_child(DICT_ATTR const *parent,
3183 unsigned int *pattr, unsigned int *pvendor)
3184 {
3185 unsigned int attr, vendor;
3186 DICT_ATTR da;
3187
3188 if (!parent || !pattr || !pvendor) return false;
3189
3190 attr = *pattr;
3191 vendor = *pvendor;
3192
3193 /*
3194 * Only some types can have children
3195 */
3196 switch (parent->type) {
3197 default: return false;
3198
3199 case PW_TYPE_VSA:
3200 case PW_TYPE_TLV:
3201 case PW_TYPE_EVS:
3202 case PW_TYPE_EXTENDED:
3203 case PW_TYPE_LONG_EXTENDED:
3204 break;
3205 }
3206
3207 if ((vendor == 0) && (parent->vendor != 0)) return false;
3208
3209 /*
3210 * Bootstrap by starting off with the parents values.
3211 */
3212 da.attr = parent->attr;
3213 da.vendor = parent->vendor;
3214
3215 /*
3216 * Do various butchery to insert the "attr" value.
3217 *
3218 * 00VID 000000AA normal VSA for vendor VID
3219 * 00VID DDCCBBAA normal VSAs with TLVs
3220 * EE000 000000AA extended attr (241.1)
3221 * EE000 DDCCBBAA extended attr with TLVs
3222 * EEVID 000000AA EVS with vendor VID, attr AAA
3223 * EEVID DDCCBBAA EVS with TLVs
3224 */
3225 if (!da.vendor) {
3226 da.vendor = parent->attr * FR_MAX_VENDOR;
3227 da.vendor |= vendor;
3228 da.attr = attr;
3229
3230 } else {
3231 int i;
3232
3233 /*
3234 * Trying to nest too deep. It's an error
3235 */
3236 if (parent->attr & (fr_attr_mask[MAX_TLV_NEST] << fr_attr_shift[MAX_TLV_NEST])) {
3237 return false;
3238 }
3239
3240 for (i = MAX_TLV_NEST - 1; i >= 0; i--) {
3241 if ((parent->attr & (fr_attr_mask[i] << fr_attr_shift[i]))) {
3242 da.attr |= (attr & fr_attr_mask[i + 1]) << fr_attr_shift[i + 1];
3243 goto find;
3244 }
3245 }
3246
3247 return false;
3248 }
3249
3250 find:
3251 #if 0
3252 fprintf(stderr, "LOOKING FOR %08x %08x + %08x %08x --> %08x %08x\n",
3253 parent->vendor, parent->attr, attr, vendor,
3254 da.vendor, da.attr);
3255 #endif
3256
3257 *pattr = da.attr;
3258 *pvendor = da.vendor;
3259 return true;
3260 }
3261
3262 /*
3263 * Get an attribute by it's numerical value, and the parent
3264 */
dict_attrbyparent(DICT_ATTR const * parent,unsigned int attr,unsigned int vendor)3265 DICT_ATTR const *dict_attrbyparent(DICT_ATTR const *parent, unsigned int attr, unsigned int vendor)
3266 {
3267 unsigned int my_attr, my_vendor;
3268 DICT_ATTR da;
3269
3270 my_attr = attr;
3271 my_vendor = vendor;
3272
3273 if (!dict_attr_child(parent, &my_attr, &my_vendor)) return NULL;
3274
3275 da.attr = my_attr;
3276 da.vendor = my_vendor;
3277
3278 return fr_hash_table_finddata(attributes_byvalue, &da);
3279 }
3280
3281
3282 /*
3283 * Get an attribute by its name.
3284 */
dict_attrbyname(char const * name)3285 DICT_ATTR const *dict_attrbyname(char const *name)
3286 {
3287 DICT_ATTR *da;
3288 uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
3289
3290 if (!name) return NULL;
3291
3292 da = (DICT_ATTR *) buffer;
3293 strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
3294
3295 da = fr_hash_table_finddata(attributes_byname, da);
3296 if (!da) return NULL;
3297
3298 if (!da->flags.is_dup) return da;
3299
3300 /*
3301 * This MUST exist if the dup flag is set.
3302 */
3303 return dict_attrbyvalue(da->attr, da->vendor);
3304 }
3305
3306 /** Look up a dictionary attribute by name embedded in another string
3307 *
3308 * Find the first invalid attribute name char in the string pointed
3309 * to by name.
3310 *
3311 * Copy the characters between the start of the name string and the first
3312 * none dict_attr_allowed_char to a buffer and perform a dictionary lookup
3313 * using that value.
3314 *
3315 * If the attribute exists, advance the pointer pointed to by name
3316 * to the first none dict_attr_allowed_char char, and return the DA.
3317 *
3318 * If the attribute does not exist, don't advance the pointer and return
3319 * NULL.
3320 *
3321 * @param[in,out] name string start.
3322 * @return NULL if no attributes matching the name could be found, else
3323 */
dict_attrbyname_substr(char const ** name)3324 DICT_ATTR const *dict_attrbyname_substr(char const **name)
3325 {
3326 DICT_ATTR *find;
3327 DICT_ATTR const *da;
3328 char const *p;
3329 size_t len;
3330 uint32_t buffer[(sizeof(*find) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
3331
3332 if (!name || !*name) return NULL;
3333
3334 find = (DICT_ATTR *) buffer;
3335
3336 /*
3337 * Advance p until we get something that's not part of
3338 * the dictionary attribute name.
3339 */
3340 for (p = *name; dict_attr_allowed_chars[(int) *p]; p++);
3341
3342 len = p - *name;
3343 if (len > DICT_ATTR_MAX_NAME_LEN) {
3344 fr_strerror_printf("Attribute name too long");
3345
3346 return NULL;
3347 }
3348 strlcpy(find->name, *name, len + 1);
3349
3350 da = fr_hash_table_finddata(attributes_byname, find);
3351 if (!da) {
3352 fr_strerror_printf("Unknown attribute \"%s\"", find->name);
3353 return NULL;
3354 }
3355 *name = p;
3356
3357 return da;
3358 }
3359
3360 /*
3361 * Associate a value with an attribute and return it.
3362 */
dict_valbyattr(unsigned int attr,unsigned int vendor,int value)3363 DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
3364 {
3365 DICT_VALUE dval, *dv;
3366
3367 /*
3368 * First, look up aliases.
3369 */
3370 dval.attr = attr;
3371 dval.vendor = vendor;
3372 dval.name[0] = '\0';
3373
3374 /*
3375 * Look up the attribute alias target, and use
3376 * the correct attribute number if found.
3377 */
3378 dv = fr_hash_table_finddata(values_byname, &dval);
3379 if (dv) dval.attr = dv->value;
3380
3381 dval.value = value;
3382
3383 return fr_hash_table_finddata(values_byvalue, &dval);
3384 }
3385
3386 /*
3387 * Associate a value with an attribute and return it.
3388 */
dict_valnamebyattr(unsigned int attr,unsigned int vendor,int value)3389 char const *dict_valnamebyattr(unsigned int attr, unsigned int vendor, int value)
3390 {
3391 DICT_VALUE *dv;
3392
3393 dv = dict_valbyattr(attr, vendor, value);
3394 if (!dv) return "";
3395
3396 return dv->name;
3397 }
3398
3399 /*
3400 * Get a value by its name, keyed off of an attribute.
3401 */
dict_valbyname(unsigned int attr,unsigned int vendor,char const * name)3402 DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, char const *name)
3403 {
3404 DICT_VALUE *my_dv, *dv;
3405 uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
3406
3407 if (!name) return NULL;
3408
3409 my_dv = (DICT_VALUE *) buffer;
3410 my_dv->attr = attr;
3411 my_dv->vendor = vendor;
3412 my_dv->name[0] = '\0';
3413
3414 /*
3415 * Look up the attribute alias target, and use
3416 * the correct attribute number if found.
3417 */
3418 dv = fr_hash_table_finddata(values_byname, my_dv);
3419 if (dv) my_dv->attr = dv->value;
3420
3421 strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
3422
3423 return fr_hash_table_finddata(values_byname, my_dv);
3424 }
3425
3426 /*
3427 * Get the vendor PEC based on the vendor name
3428 *
3429 * This is efficient only for small numbers of vendors.
3430 */
dict_vendorbyname(char const * name)3431 int dict_vendorbyname(char const *name)
3432 {
3433 DICT_VENDOR *dv;
3434 size_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + sizeof(size_t) - 1) / sizeof(size_t)];
3435
3436 if (!name) return 0;
3437
3438 dv = (DICT_VENDOR *) buffer;
3439 strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
3440
3441 dv = fr_hash_table_finddata(vendors_byname, dv);
3442 if (!dv) return 0;
3443
3444 return dv->vendorpec;
3445 }
3446
3447 /*
3448 * Return the vendor struct based on the PEC.
3449 */
dict_vendorbyvalue(int vendorpec)3450 DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
3451 {
3452 DICT_VENDOR dv;
3453
3454 dv.vendorpec = vendorpec;
3455
3456 return fr_hash_table_finddata(vendors_byvalue, &dv);
3457 }
3458
3459 /** Converts an unknown to a known by adding it to the internal dictionaries.
3460 *
3461 * Does not free old DICT_ATTR, that is left up to the caller.
3462 *
3463 * @param old unknown attribute to add.
3464 * @return existing DICT_ATTR if old was found in a dictionary, else the new entry in the dictionary
3465 * representing old.
3466 */
dict_unknown_add(DICT_ATTR const * old)3467 DICT_ATTR const *dict_unknown_add(DICT_ATTR const *old)
3468 {
3469 DICT_ATTR const *da, *parent;
3470 ATTR_FLAGS flags;
3471
3472 if (!old) return NULL;
3473
3474 if (!old->flags.is_unknown) return old;
3475
3476 da = dict_attrbyvalue(old->attr, old->vendor);
3477 if (da) return da;
3478
3479 memcpy(&flags, &old->flags, sizeof(flags));
3480 flags.is_unknown = false;
3481
3482 parent = dict_parent(old->attr, old->vendor);
3483 if (parent) {
3484 if (parent->flags.has_tlv) flags.is_tlv = true;
3485 flags.evs = parent->flags.evs;
3486 flags.extended = parent->flags.extended;
3487 flags.long_extended = parent->flags.long_extended;
3488 }
3489
3490 if (dict_addattr(old->name, old->attr, old->vendor, old->type, flags) < 0) {
3491 return NULL;
3492 }
3493
3494 da = dict_attrbyvalue(old->attr, old->vendor);
3495 return da;
3496 }
3497
dict_print_oid(char * buffer,size_t buflen,DICT_ATTR const * da)3498 size_t dict_print_oid(char *buffer, size_t buflen, DICT_ATTR const *da)
3499 {
3500 return print_attr_oid(buffer, buflen, da->attr, da->vendor);
3501 }
3502
dict_walk(fr_hash_table_walk_t callback,void * context)3503 int dict_walk(fr_hash_table_walk_t callback, void *context)
3504 {
3505 return fr_hash_table_walk(attributes_byname, callback, context);
3506 }
3507