32
32
#include <malloc.h>
35
#ifdef HAVE_SYS_STAT_H
35
42
#include "libradius.h"
44
#define DICT_VALUE_MAX_NAME_LEN (128)
45
#define DICT_VENDOR_MAX_NAME_LEN (128)
47
static lrad_hash_table_t *vendors_byname = NULL;
48
static lrad_hash_table_t *vendors_byvalue = NULL;
50
static lrad_hash_table_t *attributes_byname = NULL;
51
static lrad_hash_table_t *attributes_byvalue = NULL;
53
static lrad_hash_table_t *values_byvalue = NULL;
54
static lrad_hash_table_t *values_byname = NULL;
39
* There are very few vendors, and they're looked up only when we
40
* read the dictionaries. So it's OK to have a singly linked
57
* For faster HUP's, we cache the stat information for
58
* files we've $INCLUDEd
43
static DICT_VENDOR *dictionary_vendors = NULL;
45
static rbtree_t *attributes_byname = NULL;
46
static rbtree_t *attributes_byvalue = NULL;
48
static rbtree_t *values_byvalue = NULL;
49
static rbtree_t *values_byname = NULL;
60
typedef struct dict_stat_t {
61
struct dict_stat_t *next;
66
static char *stat_root_dir = NULL;
67
static char *stat_root_file = NULL;
69
static dict_stat_t *stat_head = NULL;
70
static dict_stat_t *stat_tail = NULL;
51
72
typedef struct value_fixup_t {
54
76
struct value_fixup_t *next;
58
81
* So VALUEs in the dictionary can have forward references.
76
* Quick pointers to the base 0..255 attributes.
78
* These attributes are referenced a LOT, especially during
79
* decoding of the on-the-wire packets. It's useful to keep a
80
* cache of their dictionary entries, so looking them up is
81
* O(1), instead of O(log(N)). (N==number of dictionary entries...)
83
static DICT_ATTR *base_attributes[256];
99
* Create the hash of the name.
101
static uint32_t dict_hashname(const char *name)
110
while (*p && (len < sizeof(buffer))) {
112
*(q++) = tolower((int) *(p++));
118
return lrad_hash(buffer, len);
123
* Free the list of stat buffers
125
static void dict_stat_free(void)
127
dict_stat_t *this, *next;
130
stat_root_dir = NULL;
131
free(stat_root_file);
132
stat_root_file = NULL;
139
for (this = stat_head; this != NULL; this = next) {
145
stat_head = stat_tail = NULL;
150
* Add an entry to the list of stat buffers.
152
static void dict_stat_add(const char *name, const struct stat *stat_buf)
156
this = malloc(sizeof(*this));
157
memset(this, 0, sizeof(*this));
159
this->name = strdup(name);
160
this->mtime = stat_buf->st_mtime;
163
stat_head = stat_tail = this;
165
stat_tail->next = this;
172
* See if any dictionaries have changed. If not, don't
175
static int dict_stat_check(const char *root_dir, const char *root_file)
180
if (!stat_root_dir) return 0;
181
if (!stat_root_file) return 0;
183
if (strcmp(root_dir, stat_root_dir) != 0) return 0;
184
if (strcmp(root_file, stat_root_file) != 0) return 0;
186
if (!stat_head) return 0; /* changed, reload */
188
for (this = stat_head; this != NULL; this = this->next) {
189
if (stat(this->name, &buf) < 0) return 0;
191
if (buf.st_mtime != this->mtime) return 0;
86
199
* Free the dictionary_attributes and dictionary_values lists.
88
201
void dict_free(void)
90
DICT_VENDOR *dvend, *enext;
92
memset(base_attributes, 0, sizeof(base_attributes));
94
for (dvend = dictionary_vendors; dvend; dvend = enext) {
99
dictionary_vendors = NULL;
102
* Free the tree of attributes by name and value.
104
rbtree_free(attributes_byname);
105
rbtree_free(attributes_byvalue);
206
lrad_hash_table_free(vendors_byname);
207
lrad_hash_table_free(vendors_byvalue);
208
vendors_byname = NULL;
209
vendors_byvalue = NULL;
211
lrad_hash_table_free(attributes_byname);
212
lrad_hash_table_free(attributes_byvalue);
106
213
attributes_byname = NULL;
107
214
attributes_byvalue = NULL;
109
rbtree_free(values_byname);
110
rbtree_free(values_byvalue);
216
lrad_hash_table_free(values_byname);
217
lrad_hash_table_free(values_byvalue);
111
218
values_byname = NULL;
112
219
values_byvalue = NULL;
116
226
* Add vendor to the list.
118
228
int dict_addvendor(const char *name, int value)
122
234
if (value >= (1 << 16)) {
123
235
librad_log("dict_addvendor: Cannot handle vendor ID larger than 65535");
127
if (strlen(name) > (sizeof(vval->name) -1)) {
239
if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
128
240
librad_log("dict_addvendor: vendor name too long");
132
if ((vval =(DICT_VENDOR *)malloc(sizeof(DICT_VENDOR))) == NULL) {
244
if ((dv = malloc(sizeof(*dv) + length)) == NULL) {
133
245
librad_log("dict_addvendor: out of memory");
136
strcpy(vval->name, name);
137
vval->vendorpec = value;
139
/* Insert at front. */
140
vval->next = dictionary_vendors;
141
dictionary_vendors = vval;
249
hash = dict_hashname(name);
250
strcpy(dv->name, name);
251
dv->vendorpec = value;
252
dv->type = dv->length = 1; /* defaults */
254
if (lrad_hash_table_insert(vendors_byname, hash, dv) == 0) {
257
old_dv = lrad_hash_table_finddata(vendors_byname, hash);
259
librad_log("dict_addvendor: Failed inserting vendor name %s", name);
262
if (old_dv->vendorpec != dv->vendorpec) {
263
librad_log("dict_addvendor: Duplicate vendor name %s", name);
268
* Already inserted. Discard the duplicate entry.
275
* Insert the SAME pointer (not free'd when this tree is
276
* deleted), into another tree.
278
* If the newly inserted entry is a duplicate of an existing
279
* entry, then the old entry is tossed, and the new one
280
* replaces it. This behaviour is configured in the
281
* lrad_hash_table_create() function.
283
* We want this behaviour because we want OLD names for
284
* the attributes to be read from the configuration
285
* files, but when we're printing them, (and looking up
286
* by value) we want to use the NEW name.
288
lrad_hash_table_insert(vendors_byvalue, dv->vendorpec, dv);
331
librad_log("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
183
335
if (value >= 65536) {
184
librad_log("dict_addattr: ATTRIBUTE has invalid number.");
336
librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 65535).");
341
DICT_VENDOR *dv = dict_vendorbyvalue(vendor);
344
* If the vendor isn't defined, die/
347
librad_log("dict_addattr: Unknown vendor");
352
* With a few exceptions, attributes can only be
353
* 1..255. The check above catches the less than
356
if ((dv->type == 1) && (value >= 256)) {
357
librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
359
} /* else 256..65535 are allowed */
189
363
* Create a new attribute for the list
191
if ((attr = (DICT_ATTR *)malloc(sizeof(DICT_ATTR))) == NULL) {
365
if ((attr = malloc(sizeof(*attr))) == NULL) {
192
366
librad_log("dict_addattr: out of memory");
370
hash = dict_hashname(name);
195
371
strcpy(attr->name, name);
196
372
attr->attr = value;
373
attr->attr |= (vendor << 16); /* FIXME: hack */
197
374
attr->type = type;
198
375
attr->flags = flags;
376
attr->vendor = vendor;
200
if (vendor) attr->attr |= (vendor << 16);
203
380
* Insert the attribute, only if it's not a duplicate.
205
if (rbtree_insert(attributes_byname, attr) == 0) {
382
if (lrad_hash_table_insert(attributes_byname, hash, attr) == 0) {
209
386
* If the attribute has identical number, then
210
387
* ignore the duplicate.
212
a = rbtree_finddata(attributes_byname, attr);
389
a = lrad_hash_table_finddata(attributes_byname, hash);
213
390
if (a && (strcasecmp(a->name, attr->name) == 0)) {
214
391
if (a->attr != attr->attr) {
215
392
librad_log("dict_addattr: Duplicate attribute name %s", name);
240
409
* If the newly inserted entry is a duplicate of an existing
241
410
* entry, then the old entry is tossed, and the new one
242
411
* replaces it. This behaviour is configured in the
243
* rbtree_create() function.
412
* lrad_hash_table_create() function.
245
414
* We want this behaviour because we want OLD names for
246
415
* the attributes to be read from the configuration
247
416
* files, but when we're printing them, (and looking up
248
417
* by value) we want to use the NEW name.
250
rbtree_insert(attributes_byvalue, attr);
419
lrad_hash_table_insert(attributes_byvalue, (uint32_t) attr->attr, attr);
256
426
* Add a value for an attribute to the dictionary.
258
int dict_addvalue(const char *namestr, char *attrstr, int value)
428
int dict_addvalue(const char *namestr, const char *attrstr, int value)
260
431
DICT_ATTR *dattr;
261
433
DICT_VALUE *dval;
263
if (strlen(namestr) > (sizeof(dval->name) -1)) {
435
if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
264
436
librad_log("dict_addvalue: value name too long");
268
if ((dval = (DICT_VALUE *)malloc(sizeof(DICT_VALUE))) == NULL) {
440
if ((dval = malloc(sizeof(*dval) + length)) == NULL) {
269
441
librad_log("dict_addvalue: out of memory");
272
444
memset(dval, 0, sizeof(*dval));
446
hash = dict_hashname(namestr);
274
447
strcpy(dval->name, namestr);
275
448
dval->value = value;
358
535
* Validate all entries
360
if (!isdigit((int) *valstr)) {
537
if (!isdigit((int) argv[1][0])) {
361
538
librad_log("dict_init: %s[%d]: invalid value", fn, line);
364
if (valstr[0] != '0')
365
value = atoi(valstr);
367
sscanf(valstr, "%i", &value);
541
sscanf(argv[1], "%i", &value);
370
544
* find the type of the attribute.
372
type = lrad_str2int(type_table, typestr, -1);
546
type = lrad_str2int(type_table, argv[2], -1);
374
548
librad_log("dict_init: %s[%d]: invalid type \"%s\"",
382
if (optstr[0] == '#') optstr[0] = '\0';
385
554
* Only look up the vendor if the string
389
557
memset(&flags, 0, sizeof(flags));
390
s = strtok(optstr, ",");
392
if (strcmp(s, "has_tag") == 0 ||
393
strcmp(s, "has_tag=1") == 0) {
394
/* Boolean flag, means this is a
398
else if (strncmp(s, "len+=", 5) == 0 ||
399
strncmp(s, "len-=", 5) == 0) {
400
/* Length difference, to accomodate
401
braindead NASes & their vendors */
402
flags.len_disp = strtol(s + 5, &c, 0);
404
librad_log("dict_init: %s[%d] invalid option %s",
409
flags.len_disp = -flags.len_disp;
412
else if (strncmp(s, "encrypt=", 8) == 0) {
413
/* Encryption method, defaults to 0 (none).
414
Currently valid is just type 2,
415
Tunnel-Password style, which can only
416
be applied to strings. */
417
flags.encrypt = strtol(s + 8, &c, 0);
419
librad_log( "dict_init: %s[%d] invalid option %s",
425
/* Must be a vendor 'flag'... */
426
if (strncmp(s, "vendor=", 7) == 0) {
431
vendor = dict_vendorbyname(s);
433
librad_log( "dict_init: %s[%d]: unknown vendor %s",
437
if (block_vendor && optstr[0] &&
438
(block_vendor != vendor)) {
439
librad_log("dict_init: %s[%d]: mismatched vendor %s within BEGIN-VENDOR/END-VENDOR block",
444
s = strtok(NULL, ",");
559
s = strtok(argv[3], ",");
561
if (strcmp(s, "has_tag") == 0 ||
562
strcmp(s, "has_tag=1") == 0) {
563
/* Boolean flag, means this is a
567
} else if (strncmp(s, "encrypt=", 8) == 0) {
568
/* Encryption method, defaults to 0 (none).
569
Currently valid is just type 2,
570
Tunnel-Password style, which can only
571
be applied to strings. */
572
flags.encrypt = strtol(s + 8, &c, 0);
574
librad_log( "dict_init: %s[%d] invalid option %s",
579
/* Must be a vendor 'flag'... */
580
if (strncmp(s, "vendor=", 7) == 0) {
585
vendor = dict_vendorbyname(s);
587
librad_log( "dict_init: %s[%d]: unknown vendor %s",
591
if (block_vendor && argv[3][0] &&
592
(block_vendor != vendor)) {
593
librad_log("dict_init: %s[%d]: mismatched vendor %s within BEGIN-VENDOR/END-VENDOR block",
598
s = strtok(NULL, ",");
447
602
if (block_vendor) vendor = block_vendor;
449
if (dict_addattr(namestr, vendor, type, value, flags) < 0) {
605
* Special checks for tags, they make our life much more
610
* VSA's can't be tagged.
613
librad_log("dict_init: %s[%d]: Vendor attributes cannot be tagged.",
619
* Only string, octets, and integer can be tagged.
623
case PW_TYPE_INTEGER:
627
librad_log("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
629
lrad_int2str(type_table, type, "?Unknown?"));
638
if (dict_addattr(argv[0], vendor, type, value, flags) < 0) {
450
639
librad_log("dict_init: %s[%d]: %s",
451
640
fn, line, librad_errstr);
475
662
* For Compatibility, skip "Server-Config"
477
if (strcasecmp(attrstr, "Server-Config") == 0)
664
if (strcasecmp(argv[0], "Server-Config") == 0)
481
668
* Validate all entries
483
if (!isdigit((int) *valstr)) {
670
if (!isdigit((int) argv[2][0])) {
484
671
librad_log("dict_init: %s[%d]: invalid value",
488
if (valstr[0] != '0')
489
value = atoi(valstr);
491
sscanf(valstr, "%i", &value);
675
sscanf(argv[2], "%i", &value);
493
if (dict_addvalue(namestr, attrstr, value) < 0) {
678
* valuepair.c will get excited when creating attributes,
679
* if it sees values which look like integers, so we can't
682
if (isdigit(argv[1][0])) {
683
librad_log("dict_init: %s[%d]: Names for VALUEs cannot start with a digit.",
687
if (dict_addvalue(argv[1], argv[0], value) < 0) {
494
688
librad_log("dict_init: %s[%d]: %s",
495
689
fn, line, librad_errstr);
504
698
* Process the VENDOR command
506
static int process_vendor(const char* fn, const int line, const char* data)
700
static int process_vendor(const char* fn, const int line, char **argv,
704
const char *format = NULL;
512
if (sscanf(data, "%s%s", attrstr, valstr) != 2) {
514
"dict_init: %s[%d] invalid VENDOR entry",
706
if ((argc < 2) || (argc > 3)) {
707
librad_log( "dict_init: %s[%d] invalid VENDOR entry",
520
713
* Validate all entries
522
if (!isdigit((int) *valstr)) {
715
if (!isdigit((int) argv[1][0])) {
523
716
librad_log("dict_init: %s[%d]: invalid value",
527
value = atoi(valstr);
720
value = atoi(argv[1]);
529
722
/* Create a new VENDOR entry for the list */
530
if (dict_addvendor(attrstr, value) < 0) {
723
if (dict_addvendor(argv[0], value) < 0) {
531
724
librad_log("dict_init: %s[%d]: %s",
532
725
fn, line, librad_errstr);
730
* Look for a format statement
735
} else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
736
format = "format=4,0";
738
} else if (value == VENDORPEC_LUCENT) {
739
format = "format=2,1";
741
} else if (value == VENDORPEC_STARENT) {
742
format = "format=2,2";
744
} /* else no fixups to do */
751
if (strncasecmp(format, "format=", 7) != 0) {
752
librad_log("dict_init: %s[%d]: Invalid format for VENDOR. Expected \"format=\", got \"%s\"",
758
if ((strlen(p) != 3) ||
759
!isdigit((int) p[0]) ||
761
!isdigit((int) p[2])) {
762
librad_log("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
767
type = (int) (p[0] - '0');
768
length = (int) (p[2] - '0');
770
dv = dict_vendorbyvalue(value);
772
librad_log("dict_init: %s[%d]: Failed adding format for VENDOR",
777
if ((type != 1) && (type != 2) && (type != 4)) {
778
librad_log("dict_init: %s[%d]: invalid type value %d for VENDOR",
783
if ((length != 0) && (length != 1) && (length != 2)) {
784
librad_log("dict_init: %s[%d]: invalid length value %d for VENDOR",
797
* String split routine. Splits an input string IN PLACE
798
* into pieces, based on spaces.
800
static int str2argv(char *str, char **argv, int max_argc)
805
if (argc >= max_argc) return argc;
808
* Chop out comments early.
815
while ((*str == ' ') ||
818
(*str == '\n')) *(str++) = '\0';
820
if (!*str) return argc;
829
(*str != '\n')) str++;
835
#define MAX_ARGV (16)
541
838
* Initialize the dictionary.
599
904
p = strchr(buf, '#');
600
905
if (p) *p = '\0';
602
keyword = strtok(buf, " \t\r\n");
603
if (keyword == NULL) {
907
argc = str2argv(buf, argv, MAX_ARGV);
908
if (argc == 0) continue;
607
data = strtok(NULL, "\r\n");
608
if (data == NULL || data[0] == 0) {
609
librad_log("dict_init: %s[%d]: invalid entry for keyword %s",
911
librad_log( "dict_init: %s[%d] invalid entry",
920
fprintf(stderr, "ARGC = %d\n",argc);
921
for (i = 0; i < argc; i++) {
922
fprintf(stderr, "\t%s\n", argv[i]);
616
927
* See if we need to import another dictionary.
618
if (strcasecmp(keyword, "$INCLUDE") == 0) {
619
p = strtok(data, " \t");
620
if (my_dict_init(dir, data, fn, line) < 0) {
929
if (strcasecmp(argv[0], "$INCLUDE") == 0) {
930
if (my_dict_init(dir, argv[1], fn, line) < 0) {
726
* Callbacks for red-black trees.
728
static int attrname_cmp(const void *a, const void *b)
730
return strcasecmp(((const DICT_ATTR *)a)->name,
731
((const DICT_ATTR *)b)->name);
735
* Return: < 0 if a < b,
738
static int attrvalue_cmp(const void *a, const void *b)
740
return (((const DICT_ATTR *)a)->attr -
741
((const DICT_ATTR *)b)->attr);
745
* Compare values by name, keying off of the attribute number,
746
* and then the value name.
748
static int valuename_cmp(const void *a, const void *b)
751
rcode = (((const DICT_VALUE *)a)->attr -
752
((const DICT_VALUE *)b)->attr);
753
if (rcode != 0) return rcode;
755
return strcasecmp(((const DICT_VALUE *)a)->name,
756
((const DICT_VALUE *)b)->name);
760
* Compare values by value, keying off of the attribute number,
761
* and then the value number.
763
static int valuevalue_cmp(const void *a, const void *b)
766
rcode = (((const DICT_VALUE *)a)->attr -
767
((const DICT_VALUE *)b)->attr);
768
if (rcode != 0) return rcode;
770
return (((const DICT_VALUE *)a)->value -
771
((const DICT_VALUE *)b)->value);
775
1037
* Initialize the directory, then fix the attr member of
776
1038
* all attributes.
778
1040
int dict_init(const char *dir, const char *fn)
1043
* Check if we need to change anything. If not, don't do
1046
if (dict_stat_check(dir, fn)) {
1051
* Free the dictionaries, and the stat cache.
1054
stat_root_dir = strdup(dir);
1055
stat_root_file = strdup(fn);
1058
* Create the tree of vendor by name. There MAY NOT
1059
* be multiple vendors of the same name.
1061
* Each vendor is malloc'd, so the free function is free.
1063
vendors_byname = lrad_hash_table_create(8, free, 0);
1064
if (!vendors_byname) {
1069
* Create the tree of vendors by value. There MAY
1070
* be vendors of the same value. If there are, we
1071
* pick the latest one.
1073
vendors_byvalue = lrad_hash_table_create(8, NULL, 1);
1074
if (!vendors_byvalue) {
783
1079
* Create the tree of attributes by name. There MAY NOT
900
1191
DICT_VALUE *dict_valbyattr(int attr, int val)
907
return rbtree_finddata(values_byvalue, &myval);
1193
uint32_t hash = attr;
1195
hash = lrad_hash_update(&val, sizeof(val), hash);
1197
return lrad_hash_table_finddata(values_byvalue, hash);
911
* Get a value by its name.
912
* If you pass an actual attr, it will try to match it.
913
* If you just want it to return on the first match,
914
* send it 0 as the attr. I hope this works the way it
1201
* Get a value by its name, keyed off of an attribute.
917
1203
DICT_VALUE *dict_valbyname(int attr, const char *name)
922
strNcpy(myval.name, name, sizeof(myval.name));
924
return rbtree_finddata(values_byname, &myval);
1207
if (!name) return NULL;
1209
hash = dict_hashname(name);
1210
hash = lrad_hash_update(&attr, sizeof(&attr), hash);
1212
return lrad_hash_table_finddata(values_byname, hash);
928
1216
* Get the vendor PEC based on the vendor name
1218
* This is efficient only for small numbers of vendors.
930
1220
int dict_vendorbyname(const char *name)
935
* Find the vendor, if any.
937
for (v = dictionary_vendors; v; v = v->next) {
938
if (strcasecmp(name, v->name) == 0) {
1225
if (!name) return 0;
1227
hash = dict_hashname(name);
1229
dv = lrad_hash_table_finddata(vendors_byname, hash);
1232
return dv->vendorpec;