~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/lib/dict.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Hampson
  • Date: 2006-01-15 13:34:13 UTC
  • mto: (3.1.3 dapper) (4.1.3 sid) (1.1.14 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060115133413-zo1dslttvdoalqym
Tags: upstream-1.1.0
ImportĀ upstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * dict.c       Routines to read the dictionary file.
3
3
 *
4
 
 * Version:     $Id: dict.c,v 1.50.2.4 2005/02/09 17:43:12 aland Exp $
 
4
 * Version:     $Id: dict.c,v 1.50.2.4.2.2 2006/01/09 23:02:47 aland Exp $
5
5
 *
6
6
 *   This library is free software; you can redistribute it and/or
7
7
 *   modify it under the terms of the GNU Lesser General Public
20
20
 * Copyright 2000  The FreeRADIUS server project
21
21
 */
22
22
 
23
 
static const char rcsid[] = "$Id: dict.c,v 1.50.2.4 2005/02/09 17:43:12 aland Exp $";
 
23
static const char rcsid[] = "$Id: dict.c,v 1.50.2.4.2.2 2006/01/09 23:02:47 aland Exp $";
24
24
 
25
25
#include        "autoconf.h"
26
26
 
32
32
#include        <malloc.h>
33
33
#endif
34
34
 
 
35
#ifdef HAVE_SYS_STAT_H
 
36
#include        <sys/stat.h>
 
37
#endif
 
38
 
 
39
#include        <unistd.h>
 
40
 
 
41
#include        "missing.h"
35
42
#include        "libradius.h"
36
 
#include        "missing.h"
 
43
 
 
44
#define DICT_VALUE_MAX_NAME_LEN (128)
 
45
#define DICT_VENDOR_MAX_NAME_LEN (128)
 
46
 
 
47
static lrad_hash_table_t *vendors_byname = NULL;
 
48
static lrad_hash_table_t *vendors_byvalue = NULL;
 
49
 
 
50
static lrad_hash_table_t *attributes_byname = NULL;
 
51
static lrad_hash_table_t *attributes_byvalue = NULL;
 
52
 
 
53
static lrad_hash_table_t *values_byvalue = NULL;
 
54
static lrad_hash_table_t *values_byname = NULL;
37
55
 
38
56
/*
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
41
 
 *      list here.
 
57
 *      For faster HUP's, we cache the stat information for
 
58
 *      files we've $INCLUDEd
42
59
 */
43
 
static DICT_VENDOR      *dictionary_vendors = NULL;
44
 
 
45
 
static rbtree_t *attributes_byname = NULL;
46
 
static rbtree_t *attributes_byvalue = NULL;
47
 
 
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;
 
62
        char               *name;
 
63
        time_t             mtime;
 
64
} dict_stat_t;
 
65
 
 
66
static char *stat_root_dir = NULL;
 
67
static char *stat_root_file = NULL;
 
68
 
 
69
static dict_stat_t *stat_head = NULL;
 
70
static dict_stat_t *stat_tail = NULL;
50
71
 
51
72
typedef struct value_fixup_t {
52
73
        char            attrstr[40];
 
74
        uint32_t        hash;
53
75
        DICT_VALUE      *dval;
54
76
        struct value_fixup_t *next;
55
77
} value_fixup_t;
56
78
 
 
79
 
57
80
/*
58
81
 *      So VALUEs in the dictionary can have forward references.
59
82
 */
73
96
};
74
97
 
75
98
/*
76
 
 *      Quick pointers to the base 0..255 attributes.
77
 
 *
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...)
82
 
 */
83
 
static DICT_ATTR *base_attributes[256];
 
99
 *      Create the hash of the name.
 
100
 */
 
101
static uint32_t dict_hashname(const char *name)
 
102
{
 
103
        const char *p;
 
104
        char *q;
 
105
        size_t len = 0;
 
106
        char buffer[1024];
 
107
        
 
108
        p = name;
 
109
        q = buffer;
 
110
        while (*p && (len < sizeof(buffer))) {
 
111
                if (isalpha(*p)) {
 
112
                        *(q++) = tolower((int) *(p++));
 
113
                } else {
 
114
                        *(q++) = *(p++);
 
115
                }
 
116
                len++;
 
117
        }
 
118
        return lrad_hash(buffer, len);
 
119
}
 
120
 
 
121
 
 
122
/*
 
123
 *      Free the list of stat buffers
 
124
 */
 
125
static void dict_stat_free(void)
 
126
{
 
127
        dict_stat_t *this, *next;
 
128
 
 
129
        free(stat_root_dir);
 
130
        stat_root_dir = NULL;
 
131
        free(stat_root_file);
 
132
        stat_root_file = NULL;
 
133
 
 
134
        if (!stat_head) {
 
135
                stat_tail = NULL;
 
136
                return;
 
137
        }
 
138
 
 
139
        for (this = stat_head; this != NULL; this = next) {
 
140
                next = this->next;
 
141
                free(this->name);
 
142
                free(this);
 
143
        }
 
144
 
 
145
        stat_head = stat_tail = NULL;
 
146
}
 
147
 
 
148
 
 
149
/*
 
150
 *      Add an entry to the list of stat buffers.
 
151
 */
 
152
static void dict_stat_add(const char *name, const struct stat *stat_buf)
 
153
{
 
154
        dict_stat_t *this;
 
155
 
 
156
        this = malloc(sizeof(*this));
 
157
        memset(this, 0, sizeof(*this));
 
158
 
 
159
        this->name = strdup(name);
 
160
        this->mtime = stat_buf->st_mtime;
 
161
 
 
162
        if (!stat_head) {
 
163
                stat_head = stat_tail = this;
 
164
        } else {
 
165
                stat_tail->next = this;
 
166
                stat_tail = this;
 
167
        }
 
168
}
 
169
 
 
170
 
 
171
/*
 
172
 *      See if any dictionaries have changed.  If not, don't
 
173
 *      do anything.
 
174
 */
 
175
static int dict_stat_check(const char *root_dir, const char *root_file)
 
176
{
 
177
        struct stat buf;
 
178
        dict_stat_t *this;
 
179
 
 
180
        if (!stat_root_dir) return 0;
 
181
        if (!stat_root_file) return 0;
 
182
 
 
183
        if (strcmp(root_dir, stat_root_dir) != 0) return 0;
 
184
        if (strcmp(root_file, stat_root_file) != 0) return 0;
 
185
 
 
186
        if (!stat_head) return 0; /* changed, reload */
 
187
 
 
188
        for (this = stat_head; this != NULL; this = this->next) {
 
189
                if (stat(this->name, &buf) < 0) return 0;
 
190
 
 
191
                if (buf.st_mtime != this->mtime) return 0;
 
192
        }
 
193
 
 
194
        return 1;
 
195
}
 
196
 
84
197
 
85
198
/*
86
199
 *      Free the dictionary_attributes and dictionary_values lists.
87
200
 */
88
201
void dict_free(void)
89
202
{
90
 
        DICT_VENDOR     *dvend, *enext;
91
 
 
92
 
        memset(base_attributes, 0, sizeof(base_attributes));
93
 
 
94
 
        for (dvend = dictionary_vendors; dvend; dvend = enext) {
95
 
                enext = dvend->next;
96
 
                free(dvend);
97
 
        }
98
 
 
99
 
        dictionary_vendors = NULL;
100
 
 
101
203
        /*
102
 
         *      Free the tree of attributes by name and value.
 
204
         *      Free the trees
103
205
         */
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;
 
210
 
 
211
        lrad_hash_table_free(attributes_byname);
 
212
        lrad_hash_table_free(attributes_byvalue);
106
213
        attributes_byname = NULL;
107
214
        attributes_byvalue = NULL;
108
215
 
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;
 
220
 
 
221
        dict_stat_free();
113
222
}
114
223
 
 
224
 
115
225
/*
116
226
 *      Add vendor to the list.
117
227
 */
118
228
int dict_addvendor(const char *name, int value)
119
229
{
120
 
        DICT_VENDOR *vval;
 
230
        size_t length;
 
231
        uint32_t hash;
 
232
        DICT_VENDOR *dv;
121
233
 
122
234
        if (value >= (1 << 16)) {
123
235
                librad_log("dict_addvendor: Cannot handle vendor ID larger than 65535");
124
236
                return -1;
125
237
        }
126
238
 
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");
129
241
                return -1;
130
242
        }
131
 
 
132
 
        if ((vval =(DICT_VENDOR *)malloc(sizeof(DICT_VENDOR))) == NULL) {
 
243
        
 
244
        if ((dv = malloc(sizeof(*dv) + length)) == NULL) {
133
245
                librad_log("dict_addvendor: out of memory");
134
246
                return -1;
135
247
        }
136
 
        strcpy(vval->name, name);
137
 
        vval->vendorpec  = value;
138
 
 
139
 
        /* Insert at front. */
140
 
        vval->next = dictionary_vendors;
141
 
        dictionary_vendors = vval;
 
248
 
 
249
        hash = dict_hashname(name);
 
250
        strcpy(dv->name, name);
 
251
        dv->vendorpec  = value;
 
252
        dv->type = dv->length = 1; /* defaults */
 
253
 
 
254
        if (lrad_hash_table_insert(vendors_byname, hash, dv) == 0) {
 
255
                DICT_VENDOR *old_dv;
 
256
 
 
257
                old_dv = lrad_hash_table_finddata(vendors_byname, hash);
 
258
                if (!old_dv) {
 
259
                        librad_log("dict_addvendor: Failed inserting vendor name %s", name);
 
260
                        return -1;
 
261
                }
 
262
                if (old_dv->vendorpec != dv->vendorpec) {
 
263
                        librad_log("dict_addvendor: Duplicate vendor name %s", name);
 
264
                        return -1;
 
265
                }
 
266
 
 
267
                /*
 
268
                 *      Already inserted.  Discard the duplicate entry.
 
269
                 */
 
270
                free(dv);
 
271
                return 0;
 
272
        }
 
273
 
 
274
        /*
 
275
         *      Insert the SAME pointer (not free'd when this tree is
 
276
         *      deleted), into another tree.
 
277
         *
 
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.
 
282
         *
 
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.
 
287
         */
 
288
        lrad_hash_table_insert(vendors_byvalue, dv->vendorpec, dv);
142
289
 
143
290
        return 0;
144
291
}
150
297
                 ATTR_FLAGS flags)
151
298
{
152
299
        static int      max_attr = 0;
 
300
        uint32_t        hash;
153
301
        DICT_ATTR       *attr;
154
302
 
155
303
        if (strlen(name) > (sizeof(attr->name) -1)) {
164
312
         *      and use that.
165
313
         */
166
314
        if (value == -1) {
167
 
                attr = dict_attrbyname(name);
168
 
                if (attr != NULL) {
 
315
                if (dict_attrbyname(name)) {
169
316
                        return 0; /* exists, don't add it again */
170
317
                }
171
318
 
180
327
                }
181
328
        }
182
329
 
 
330
        if (value < 0) {
 
331
                librad_log("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
 
332
                return -1;
 
333
        }
 
334
 
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).");
185
337
                return -1;
186
338
        }
187
339
 
 
340
        if (vendor) {
 
341
                DICT_VENDOR *dv = dict_vendorbyvalue(vendor);
 
342
 
 
343
                /*
 
344
                 *      If the vendor isn't defined, die/
 
345
                 */
 
346
                if (!dv) {
 
347
                        librad_log("dict_addattr: Unknown vendor");
 
348
                        return -1;
 
349
                }
 
350
 
 
351
                /*
 
352
                 *      With a few exceptions, attributes can only be
 
353
                 *      1..255.  The check above catches the less than
 
354
                 *      zero case.
 
355
                 */
 
356
                if ((dv->type == 1) && (value >= 256)) {
 
357
                        librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
 
358
                        return -1;
 
359
                } /* else 256..65535 are allowed */
 
360
        }
 
361
 
188
362
        /*
189
363
         *      Create a new attribute for the list
190
364
         */
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");
193
367
                return -1;
194
368
        }
 
369
 
 
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;
199
377
 
200
 
        if (vendor) attr->attr |= (vendor << 16);
201
378
 
202
379
        /*
203
380
         *      Insert the attribute, only if it's not a duplicate.
204
381
         */
205
 
        if (rbtree_insert(attributes_byname, attr) == 0) {
 
382
        if (lrad_hash_table_insert(attributes_byname, hash, attr) == 0) {
206
383
                DICT_ATTR       *a;
207
384
 
208
385
                /*
209
386
                 *      If the attribute has identical number, then
210
387
                 *      ignore the duplicate.
211
388
                 */
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);
217
394
                        }
218
395
 
219
396
                        /*
220
 
                         *      Same name, same attr, maybe the
221
 
                         *      flags and/or type is different.
222
 
                         *      Let the new value over-ride the
223
 
                         *      old one.
 
397
                         *      Same name, same vendor, same attr,
 
398
                         *      maybe the flags and/or type is
 
399
                         *      different.  Let the new value
 
400
                         *      over-ride the old one.
224
401
                         */
225
402
                }
226
403
        }
227
404
 
228
 
        if ((attr->attr >= 0) && (attr->attr < 256)) {
229
 
                /*
230
 
                 *      If it's an on-the-wire base attribute,
231
 
                 *      then keep a quick reference to it, for speed.
232
 
                 */
233
 
                base_attributes[attr->attr] = attr;
234
 
        }
235
 
 
236
405
        /*
237
406
         *      Insert the SAME pointer (not free'd when this tree is
238
407
         *      deleted), into another tree.
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.
244
413
         *
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.
249
418
         */
250
 
        rbtree_insert(attributes_byvalue, attr);
 
419
        lrad_hash_table_insert(attributes_byvalue, (uint32_t) attr->attr, attr);
251
420
 
252
421
        return 0;
253
422
}
254
423
 
 
424
 
255
425
/*
256
426
 *      Add a value for an attribute to the dictionary.
257
427
 */
258
 
int dict_addvalue(const char *namestr, char *attrstr, int value)
 
428
int dict_addvalue(const char *namestr, const char *attrstr, int value)
259
429
{
 
430
        size_t          length;
260
431
        DICT_ATTR       *dattr;
 
432
        uint32_t        hash;
261
433
        DICT_VALUE      *dval;
262
434
 
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");
265
437
                return -1;
266
438
        }
267
439
 
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");
270
442
                return -1;
271
443
        }
272
444
        memset(dval, 0, sizeof(*dval));
273
445
 
 
446
        hash = dict_hashname(namestr);
274
447
        strcpy(dval->name, namestr);
275
448
        dval->value = value;
276
449
 
281
454
        dattr = dict_attrbyname(attrstr);
282
455
        if (dattr) {
283
456
                dval->attr = dattr->attr;
 
457
                hash = lrad_hash_update(&dval->attr, sizeof(dval->attr), hash);
284
458
        } else {
285
459
                value_fixup_t *fixup;
286
460
                
292
466
                memset(fixup, 0, sizeof(*fixup));
293
467
 
294
468
                strNcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
 
469
                fixup->hash = hash;
295
470
                fixup->dval = dval;
296
471
                
297
472
                /*
306
481
        /*
307
482
         *      Add the value into the dictionary.
308
483
         */
309
 
        if (rbtree_insert(values_byname, dval) == 0) {
 
484
        if (lrad_hash_table_insert(values_byname, hash, dval) == 0) {
310
485
                if (dattr) {
311
 
                        DICT_VALUE *dup;
 
486
                        DICT_VALUE *old;
312
487
                        
313
488
                        /*
314
489
                         *      Suppress duplicates with the same
315
490
                         *      name and value.  There are lots in
316
491
                         *      dictionary.ascend.
317
492
                         */
318
 
                        dup = dict_valbyname(dattr->attr, namestr);
319
 
                        if (dup && (dup->value == dval->value)) {
 
493
                        old = dict_valbyname(dattr->attr, namestr);
 
494
                        if (old && (old->value == dval->value)) {
320
495
                                free(dval);
321
496
                                return 0;
322
497
                        }
325
500
                librad_log("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
326
501
                return -1;
327
502
        }
328
 
        rbtree_insert(values_byvalue, dval);
 
503
 
 
504
        /*
 
505
         *      There are multiple VALUE's, keyed by attribute, so we
 
506
         *      take care of that here.
 
507
         */
 
508
        hash = dval->attr;
 
509
        hash = lrad_hash_update(&dval->value, sizeof(dval->value), hash);
 
510
        lrad_hash_table_insert(values_byvalue, hash, dval);
329
511
 
330
512
        return 0;
331
513
}
334
516
 *      Process the ATTRIBUTE command
335
517
 */
336
518
static int process_attribute(const char* fn, const int line,
337
 
                             const int block_vendor, const char* data)
 
519
                             const int block_vendor, char **argv,
 
520
                             int argc)
338
521
{
339
 
        int             vendor;
340
 
        char            namestr[256];
341
 
        char            valstr[256];
342
 
        char            typestr[256];
343
 
        char            optstr[256];
 
522
        int             vendor = 0;
344
523
        int             value;
345
524
        int             type;
346
525
        char            *s, *c;
347
526
        ATTR_FLAGS      flags;
348
527
 
349
 
        vendor = 0;
350
 
        optstr[0] = 0;
351
 
        if(sscanf(data, "%s%s%s%s", namestr, valstr, typestr, optstr) < 3) {
 
528
        if ((argc < 3) || (argc > 4)) {
352
529
                librad_log("dict_init: %s[%d]: invalid ATTRIBUTE line",
353
530
                        fn, line);
354
531
                return -1;
357
534
        /*
358
535
         *      Validate all entries
359
536
         */
360
 
        if (!isdigit((int) *valstr)) {
 
537
        if (!isdigit((int) argv[1][0])) {
361
538
                librad_log("dict_init: %s[%d]: invalid value", fn, line);
362
539
                return -1;
363
540
        }
364
 
        if (valstr[0] != '0')
365
 
                value = atoi(valstr);
366
 
        else
367
 
                sscanf(valstr, "%i", &value);
 
541
        sscanf(argv[1], "%i", &value);
368
542
 
369
543
        /*
370
544
         *      find the type of the attribute.
371
545
         */
372
 
        type = lrad_str2int(type_table, typestr, -1);
 
546
        type = lrad_str2int(type_table, argv[2], -1);
373
547
        if (type < 0) {
374
548
                librad_log("dict_init: %s[%d]: invalid type \"%s\"",
375
 
                        fn, line, typestr);
 
549
                        fn, line, argv[2]);
376
550
                return -1;
377
551
        }
378
552
 
379
553
        /*
380
 
         *      Ignore comments
381
 
         */
382
 
        if (optstr[0] == '#') optstr[0] = '\0';
383
 
 
384
 
        /*
385
554
         *      Only look up the vendor if the string
386
555
         *      is non-empty.
387
556
         */
388
 
 
389
557
        memset(&flags, 0, sizeof(flags));
390
 
        s = strtok(optstr, ",");
391
 
        while(s) {
392
 
                if (strcmp(s, "has_tag") == 0 ||
393
 
                    strcmp(s, "has_tag=1") == 0) {
394
 
                         /* Boolean flag, means this is a
395
 
                            tagged attribute */
396
 
                         flags.has_tag = 1;
397
 
                }
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);
403
 
                          if (*c) {
404
 
                                librad_log("dict_init: %s[%d] invalid option %s",
405
 
                                           fn, line, s);
406
 
                                return -1;
407
 
                          }
408
 
                          if (s[3] == '-') {
409
 
                                flags.len_disp = -flags.len_disp;
410
 
                          }
411
 
                }
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);
418
 
                          if (*c) {
419
 
                                librad_log( "dict_init: %s[%d] invalid option %s",
420
 
                                           fn, line, s);
421
 
                                return -1;
422
 
                          }
423
 
                }
424
 
                else {
425
 
                          /* Must be a vendor 'flag'... */
426
 
                          if (strncmp(s, "vendor=", 7) == 0) {
427
 
                                /* New format */
428
 
                                s += 7;
429
 
                          }
430
 
 
431
 
                          vendor = dict_vendorbyname(s);
432
 
                          if (!vendor) {
433
 
                                librad_log( "dict_init: %s[%d]: unknown vendor %s",
434
 
                                           fn, line, optstr);
435
 
                                return -1;
436
 
                          }
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",
440
 
                                           fn, line, optstr);
441
 
                                return -1;
442
 
                          }
443
 
                }
444
 
                s = strtok(NULL, ",");
 
558
        if (argc == 4) {
 
559
                s = strtok(argv[3], ",");
 
560
                while (s) {
 
561
                        if (strcmp(s, "has_tag") == 0 ||
 
562
                            strcmp(s, "has_tag=1") == 0) {
 
563
                                /* Boolean flag, means this is a
 
564
                                   tagged attribute */
 
565
                                flags.has_tag = 1;
 
566
                                
 
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);
 
573
                                if (*c) {
 
574
                                        librad_log( "dict_init: %s[%d] invalid option %s",
 
575
                                                    fn, line, s);
 
576
                                        return -1;
 
577
                                }
 
578
                        } else {
 
579
                                /* Must be a vendor 'flag'... */
 
580
                                if (strncmp(s, "vendor=", 7) == 0) {
 
581
                                        /* New format */
 
582
                                        s += 7;
 
583
                                }
 
584
                                
 
585
                                vendor = dict_vendorbyname(s);
 
586
                                if (!vendor) {
 
587
                                        librad_log( "dict_init: %s[%d]: unknown vendor %s",
 
588
                                                    fn, line, s);
 
589
                                        return -1;
 
590
                                }
 
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",
 
594
                                                   fn, line, argv[3]);
 
595
                                        return -1;
 
596
                                }
 
597
                        }
 
598
                        s = strtok(NULL, ",");
 
599
                }
445
600
        }
446
601
 
447
602
        if (block_vendor) vendor = block_vendor;
448
603
 
449
 
        if (dict_addattr(namestr, vendor, type, value, flags) < 0) {
 
604
        /*
 
605
         *      Special checks for tags, they make our life much more
 
606
         *      difficult.
 
607
         */
 
608
        if (flags.has_tag) {
 
609
                /*
 
610
                 *      VSA's can't be tagged.
 
611
                 */
 
612
                if (vendor) {
 
613
                        librad_log("dict_init: %s[%d]: Vendor attributes cannot be tagged.",
 
614
                                   fn, line);
 
615
                        return -1;
 
616
                }
 
617
 
 
618
                /*
 
619
                 *      Only string, octets, and integer can be tagged.
 
620
                 */
 
621
                switch (type) {
 
622
                case PW_TYPE_STRING:
 
623
                case PW_TYPE_INTEGER:
 
624
                        break;
 
625
 
 
626
                default:
 
627
                        librad_log("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
 
628
                                   fn, line,
 
629
                                   lrad_int2str(type_table, type, "?Unknown?"));
 
630
                        return -1;
 
631
                        
 
632
                }
 
633
        }
 
634
 
 
635
        /*
 
636
         *      Add it in.
 
637
         */
 
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);
452
641
                return -1;
459
648
/*
460
649
 *      Process the VALUE command
461
650
 */
462
 
static int process_value(const char* fn, const int line, const char* data)
 
651
static int process_value(const char* fn, const int line, char **argv,
 
652
                         int argc)
463
653
{
464
 
        char    namestr[256];
465
 
        char    valstr[256];
466
 
        char    attrstr[256];
467
654
        int     value;
468
655
 
469
 
        if (sscanf(data, "%s%s%s", attrstr, namestr, valstr) != 3) {
 
656
        if (argc != 3) {
470
657
                librad_log("dict_init: %s[%d]: invalid VALUE line",
471
658
                        fn, line);
472
659
                return -1;
474
661
        /*
475
662
         *      For Compatibility, skip "Server-Config"
476
663
         */
477
 
        if (strcasecmp(attrstr, "Server-Config") == 0)
 
664
        if (strcasecmp(argv[0], "Server-Config") == 0)
478
665
                return 0;
479
666
 
480
667
        /*
481
668
         *      Validate all entries
482
669
         */
483
 
        if (!isdigit((int) *valstr)) {
 
670
        if (!isdigit((int) argv[2][0])) {
484
671
                librad_log("dict_init: %s[%d]: invalid value",
485
672
                        fn, line);
486
673
                return -1;
487
674
        }
488
 
        if (valstr[0] != '0')
489
 
                value = atoi(valstr);
490
 
        else
491
 
                sscanf(valstr, "%i", &value);
 
675
        sscanf(argv[2], "%i", &value);
492
676
 
493
 
        if (dict_addvalue(namestr, attrstr, value) < 0) {
 
677
        /*
 
678
         *      valuepair.c will get excited when creating attributes,
 
679
         *      if it sees values which look like integers, so we can't
 
680
         *      use them here.
 
681
         */
 
682
        if (isdigit(argv[1][0])) {
 
683
                librad_log("dict_init: %s[%d]: Names for VALUEs cannot start with a digit.",
 
684
                           fn, line);
 
685
        }
 
686
        
 
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);
496
690
                return -1;
503
697
/*
504
698
 *      Process the VENDOR command
505
699
 */
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,
 
701
                          int argc)
507
702
{
508
 
        char    valstr[256];
509
 
        char    attrstr[256];
510
703
        int     value;
 
704
        const   char *format = NULL;
511
705
 
512
 
        if (sscanf(data, "%s%s", attrstr, valstr) != 2) {
513
 
                librad_log(
514
 
                "dict_init: %s[%d] invalid VENDOR entry",
515
 
                        fn, line);
 
706
        if ((argc < 2) || (argc > 3)) {
 
707
                librad_log( "dict_init: %s[%d] invalid VENDOR entry",
 
708
                            fn, line);
516
709
                return -1;
517
710
        }
518
711
 
519
712
        /*
520
713
         *       Validate all entries
521
714
         */
522
 
        if (!isdigit((int) *valstr)) {
 
715
        if (!isdigit((int) argv[1][0])) {
523
716
                librad_log("dict_init: %s[%d]: invalid value",
524
717
                        fn, line);
525
718
                return -1;
526
719
        }
527
 
        value = atoi(valstr);
 
720
        value = atoi(argv[1]);
528
721
 
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);
533
726
                return -1;
534
727
        }
535
728
 
 
729
        /*
 
730
         *      Look for a format statement
 
731
         */
 
732
        if (argc == 3) {
 
733
                format = argv[2];
 
734
 
 
735
        } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
 
736
                format = "format=4,0";
 
737
 
 
738
        } else if (value == VENDORPEC_LUCENT) {
 
739
                format = "format=2,1";
 
740
 
 
741
        } else if (value == VENDORPEC_STARENT) {
 
742
                format = "format=2,2";
 
743
 
 
744
        } /* else no fixups to do */
 
745
 
 
746
        if (format) {
 
747
                int type, length;
 
748
                const char *p;
 
749
                DICT_VENDOR *dv;
 
750
 
 
751
                if (strncasecmp(format, "format=", 7) != 0) {
 
752
                        librad_log("dict_init: %s[%d]: Invalid format for VENDOR.  Expected \"format=\", got \"%s\"",
 
753
                                   fn, line, format);
 
754
                        return -1;
 
755
                }
 
756
 
 
757
                p = format + 7;
 
758
                if ((strlen(p) != 3) || 
 
759
                    !isdigit((int) p[0]) ||
 
760
                    (p[1] != ',') ||
 
761
                    !isdigit((int) p[2])) {
 
762
                        librad_log("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
 
763
                                   fn, line, p);
 
764
                        return -1;
 
765
                }
 
766
 
 
767
                type = (int) (p[0] - '0');
 
768
                length = (int) (p[2] - '0');
 
769
 
 
770
                dv = dict_vendorbyvalue(value);
 
771
                if (!dv) {
 
772
                        librad_log("dict_init: %s[%d]: Failed adding format for VENDOR",
 
773
                                   fn, line);
 
774
                        return -1;
 
775
                }
 
776
 
 
777
                if ((type != 1) && (type != 2) && (type != 4)) {
 
778
                        librad_log("dict_init: %s[%d]: invalid type value %d for VENDOR",
 
779
                                   fn, line, type);
 
780
                        return -1;
 
781
                }
 
782
 
 
783
                if ((length != 0) && (length != 1) && (length != 2)) {
 
784
                        librad_log("dict_init: %s[%d]: invalid length value %d for VENDOR",
 
785
                                   fn, line, length);
 
786
                        return -1;
 
787
                }
 
788
 
 
789
                dv->type = type;
 
790
                dv->length = length;
 
791
        }
 
792
 
536
793
        return 0;
537
794
}
538
795
 
 
796
/*
 
797
 *      String split routine.  Splits an input string IN PLACE
 
798
 *      into pieces, based on spaces.
 
799
 */
 
800
static int str2argv(char *str, char **argv, int max_argc)
 
801
{
 
802
        int argc = 0;
 
803
 
 
804
        while (*str) {
 
805
                if (argc >= max_argc) return argc;
 
806
 
 
807
                /*
 
808
                 *      Chop out comments early.
 
809
                 */
 
810
                if (*str == '#') {
 
811
                        *str = '\0';
 
812
                        break;
 
813
                }
 
814
 
 
815
                while ((*str == ' ') ||
 
816
                       (*str == '\t') ||
 
817
                       (*str == '\r') ||
 
818
                       (*str == '\n')) *(str++) = '\0';
 
819
 
 
820
                if (!*str) return argc;
 
821
 
 
822
                argv[argc] = str;
 
823
                argc++;
 
824
 
 
825
                while (*str &&
 
826
                       (*str != ' ') &&
 
827
                       (*str != '\t') &&
 
828
                       (*str != '\r') &&
 
829
                       (*str != '\n')) str++;
 
830
        }
 
831
 
 
832
        return argc;
 
833
}
 
834
 
 
835
#define MAX_ARGV (16)
539
836
 
540
837
/*
541
838
 *      Initialize the dictionary.
546
843
        FILE    *fp;
547
844
        char    dirtmp[256];
548
845
        char    buf[256];
549
 
        char    optstr[256];
550
846
        char    *p;
551
 
        char    *keyword;
552
 
        char    *data;
553
847
        int     line = 0;
554
848
        int     vendor;
555
849
        int     block_vendor;
 
850
        struct stat statbuf;
 
851
        char    *argv[MAX_ARGV];
 
852
        int     argc;
556
853
 
557
854
        if (strlen(fn) >= sizeof(dirtmp) / 2 ||
558
855
            strlen(dir) >= sizeof(dirtmp) / 2) {
584
881
                return -1;
585
882
        }
586
883
 
 
884
        stat(fn, &statbuf); /* fopen() guarantees this will succeed */
 
885
        dict_stat_add(fn, &statbuf);
 
886
 
 
887
        /*
 
888
         *      Seed the random pool with data.
 
889
         */
 
890
        lrad_rand_seed(&statbuf, sizeof(statbuf));
 
891
 
587
892
        block_vendor = 0;
588
893
 
589
894
        while (fgets(buf, sizeof(buf), fp) != NULL) {
599
904
                p = strchr(buf, '#');
600
905
                if (p) *p = '\0';
601
906
 
602
 
                keyword = strtok(buf, " \t\r\n");
603
 
                if (keyword == NULL) {
604
 
                        continue;
605
 
                }
 
907
                argc = str2argv(buf, argv, MAX_ARGV);
 
908
                if (argc == 0) continue;
606
909
 
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",
610
 
                                fn, line, keyword);
 
910
                if (argc == 1) {
 
911
                        librad_log( "dict_init: %s[%d] invalid entry",
 
912
                                    fn, line);
611
913
                        fclose(fp);
612
914
                        return -1;
613
915
                }
614
916
 
 
917
                if (0) {
 
918
                        int i;
 
919
 
 
920
                        fprintf(stderr, "ARGC = %d\n",argc);
 
921
                        for (i = 0; i < argc; i++) {
 
922
                                fprintf(stderr, "\t%s\n", argv[i]);
 
923
                        }
 
924
                }
 
925
 
615
926
                /*
616
927
                 *      See if we need to import another dictionary.
617
928
                 */
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) {
621
931
                                fclose(fp);
622
932
                                return -1;
623
933
                        }
627
937
                /*
628
938
                 *      Perhaps this is an attribute.
629
939
                 */
630
 
                if (strcasecmp(keyword, "ATTRIBUTE") == 0) {
631
 
                        if (process_attribute(fn, line, block_vendor, data) == -1) {
 
940
                if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
 
941
                        if (process_attribute(fn, line, block_vendor,
 
942
                                              argv + 1, argc - 1) == -1) {
632
943
                                fclose(fp);
633
944
                                return -1;
634
945
                        }
638
949
                /*
639
950
                 *      Process VALUE lines.
640
951
                 */
641
 
                if (strcasecmp(keyword, "VALUE") == 0) {
642
 
                        if (process_value(fn, line, data) == -1) {
 
952
                if (strcasecmp(argv[0], "VALUE") == 0) {
 
953
                        if (process_value(fn, line,
 
954
                                          argv + 1, argc - 1) == -1) {
643
955
                                fclose(fp);
644
956
                                return -1;
645
957
                        }
649
961
                /*
650
962
                 *      Process VENDOR lines.
651
963
                 */
652
 
                if (strcasecmp(keyword, "VENDOR") == 0) {
653
 
                        if (process_vendor(fn, line, data) == -1) {
 
964
                if (strcasecmp(argv[0], "VENDOR") == 0) {
 
965
                        if (process_vendor(fn, line,
 
966
                                           argv + 1, argc - 1) == -1) {
654
967
                                fclose(fp);
655
968
                                return -1;
656
969
                        }
657
970
                        continue;
658
971
                }
659
972
 
660
 
                if (strcasecmp(keyword, "BEGIN-VENDOR") == 0) {
661
 
                        optstr[0] = 0;
662
 
                        if (sscanf(data, "%s", optstr) != 1) {
 
973
                if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
 
974
                        if (argc != 2) {
663
975
                                librad_log(
664
976
                                "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
665
977
                                        fn, line);
667
979
                                return -1;
668
980
                        }
669
981
 
670
 
                        vendor = dict_vendorbyname(optstr);
 
982
                        vendor = dict_vendorbyname(argv[1]);
671
983
                        if (!vendor) {
672
984
                                librad_log(
673
985
                                        "dict_init: %s[%d]: unknown vendor %s",
674
 
                                        fn, line, optstr);
 
986
                                        fn, line, argv[1]);
675
987
                                fclose(fp);
676
988
                                return -1;
677
989
                        }
679
991
                        continue;
680
992
                } /* BEGIN-VENDOR */
681
993
 
682
 
                if (strcasecmp(keyword, "END-VENDOR") == 0) {
683
 
                        optstr[0] = 0;
684
 
                        if (sscanf(data, "%s", optstr) != 1) {
 
994
                if (strcasecmp(argv[0], "END-VENDOR") == 0) {
 
995
                        if (argc != 2) {
685
996
                                librad_log(
686
997
                                "dict_init: %s[%d] invalid END-VENDOR entry",
687
998
                                        fn, line);
689
1000
                                return -1;
690
1001
                        }
691
1002
 
692
 
                        vendor = dict_vendorbyname(optstr);
 
1003
                        vendor = dict_vendorbyname(argv[1]);
693
1004
                        if (!vendor) {
694
1005
                                librad_log(
695
1006
                                        "dict_init: %s[%d]: unknown vendor %s",
696
 
                                        fn, line, optstr);
 
1007
                                        fn, line, argv[1]);
697
1008
                                fclose(fp);
698
1009
                                return -1;
699
1010
                        }
701
1012
                        if (vendor != block_vendor) {
702
1013
                                librad_log(
703
1014
                                        "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
704
 
                                        fn, line, optstr);
 
1015
                                        fn, line, argv[1]);
705
1016
                                fclose(fp);
706
1017
                                return -1;
707
1018
                        }
714
1025
                 */
715
1026
                librad_log(
716
1027
                        "dict_init: %s[%d] invalid keyword \"%s\"",
717
 
                        fn, line, keyword);
 
1028
                        fn, line, argv[0]);
718
1029
                fclose(fp);
719
1030
                return -1;
720
1031
        }
723
1034
}
724
1035
 
725
1036
/*
726
 
 *      Callbacks for red-black trees.
727
 
 */
728
 
static int attrname_cmp(const void *a, const void *b)
729
 
{
730
 
        return strcasecmp(((const DICT_ATTR *)a)->name,
731
 
                          ((const DICT_ATTR *)b)->name);
732
 
}
733
 
 
734
 
/*
735
 
 *      Return: < 0  if a < b,
736
 
 *              == 0 if a == b
737
 
 */
738
 
static int attrvalue_cmp(const void *a, const void *b)
739
 
{
740
 
        return (((const DICT_ATTR *)a)->attr -
741
 
                ((const DICT_ATTR *)b)->attr);
742
 
}
743
 
 
744
 
/*
745
 
 *      Compare values by name, keying off of the attribute number,
746
 
 *      and then the value name.
747
 
 */
748
 
static int valuename_cmp(const void *a, const void *b)
749
 
{
750
 
        int rcode;
751
 
        rcode = (((const DICT_VALUE *)a)->attr -
752
 
                 ((const DICT_VALUE *)b)->attr);
753
 
        if (rcode != 0) return rcode;
754
 
 
755
 
return strcasecmp(((const DICT_VALUE *)a)->name,
756
 
                          ((const DICT_VALUE *)b)->name);
757
 
}
758
 
 
759
 
/*
760
 
 *      Compare values by value, keying off of the attribute number,
761
 
 *      and then the value number.
762
 
 */
763
 
static int valuevalue_cmp(const void *a, const void *b)
764
 
{
765
 
        int rcode;
766
 
        rcode = (((const DICT_VALUE *)a)->attr -
767
 
                 ((const DICT_VALUE *)b)->attr);
768
 
        if (rcode != 0) return rcode;
769
 
 
770
 
        return (((const DICT_VALUE *)a)->value -
771
 
                 ((const DICT_VALUE *)b)->value);
772
 
}
773
 
 
774
 
/*
775
1037
 *      Initialize the directory, then fix the attr member of
776
1038
 *      all attributes.
777
1039
 */
778
1040
int dict_init(const char *dir, const char *fn)
779
1041
{
 
1042
        /*
 
1043
         *      Check if we need to change anything.  If not, don't do
 
1044
         *      anything.
 
1045
         */
 
1046
        if (dict_stat_check(dir, fn)) {
 
1047
                return 0;
 
1048
        }
 
1049
 
 
1050
        /*
 
1051
         *      Free the dictionaries, and the stat cache.
 
1052
         */
780
1053
        dict_free();
 
1054
        stat_root_dir = strdup(dir);
 
1055
        stat_root_file = strdup(fn);
 
1056
 
 
1057
        /*
 
1058
         *      Create the tree of vendor by name.   There MAY NOT
 
1059
         *      be multiple vendors of the same name.
 
1060
         *
 
1061
         *      Each vendor is malloc'd, so the free function is free.
 
1062
         */
 
1063
        vendors_byname = lrad_hash_table_create(8, free, 0);
 
1064
        if (!vendors_byname) {
 
1065
                return -1;
 
1066
        }
 
1067
 
 
1068
        /*
 
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.
 
1072
         */
 
1073
        vendors_byvalue = lrad_hash_table_create(8, NULL, 1);
 
1074
        if (!vendors_byvalue) {
 
1075
                return -1;
 
1076
        }
781
1077
 
782
1078
        /*
783
1079
         *      Create the tree of attributes by name.   There MAY NOT
785
1081
         *
786
1082
         *      Each attribute is malloc'd, so the free function is free.
787
1083
         */
788
 
        attributes_byname = rbtree_create(attrname_cmp, free, 0);
 
1084
        attributes_byname = lrad_hash_table_create(11, free, 0);
789
1085
        if (!attributes_byname) {
790
1086
                return -1;
791
1087
        }
795
1091
         *      be attributes of the same value.  If there are, we
796
1092
         *      pick the latest one.
797
1093
         */
798
 
        attributes_byvalue = rbtree_create(attrvalue_cmp, NULL, 1);
 
1094
        attributes_byvalue = lrad_hash_table_create(11, NULL, 1);
799
1095
        if (!attributes_byvalue) {
800
1096
                return -1;
801
1097
        }
802
1098
 
803
 
        values_byname = rbtree_create(valuename_cmp, free, 0);
 
1099
        values_byname = lrad_hash_table_create(11, free, 0);
804
1100
        if (!values_byname) {
805
1101
                return -1;
806
1102
        }
807
1103
 
808
 
        values_byvalue = rbtree_create(valuevalue_cmp, NULL, 1);
 
1104
        values_byvalue = lrad_hash_table_create(11, NULL, 1);
809
1105
        if (!values_byvalue) {
810
1106
                return -1;
811
1107
        }
816
1112
                return -1;
817
1113
 
818
1114
        if (value_fixup) {
 
1115
                uint32_t hash;
819
1116
                DICT_ATTR *a;
820
1117
                value_fixup_t *this, *next;
821
1118
 
835
1132
                        /*
836
1133
                         *      Add the value into the dictionary.
837
1134
                         */
838
 
                        if (rbtree_insert(values_byname, this->dval) == 0) {
 
1135
                        hash = lrad_hash_update(&this->dval->attr,
 
1136
                                                sizeof(this->dval->attr),
 
1137
                                                this->hash);
 
1138
                        if (lrad_hash_table_insert(values_byname,
 
1139
                                                   hash, this->dval) == 0) {
839
1140
                                librad_log("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
840
1141
                                return -1;
841
1142
                        }
845
1146
                         *      prefer the new name when printing
846
1147
                         *      values.
847
1148
                         */
848
 
                        if (!rbtree_find(values_byvalue, this->dval)) {
849
 
                                rbtree_insert(values_byvalue, this->dval);
 
1149
                        hash = (uint32_t) this->dval->attr;
 
1150
                        hash = lrad_hash_update(&this->dval->value,
 
1151
                                                sizeof(this->dval->value),
 
1152
                                                hash);
 
1153
                        if (!lrad_hash_table_finddata(values_byvalue, hash)) {
 
1154
                                lrad_hash_table_insert(values_byvalue,
 
1155
                                                       hash, this->dval);
850
1156
                        }
851
1157
                        free(this);
852
1158
 
865
1171
 */
866
1172
DICT_ATTR *dict_attrbyvalue(int val)
867
1173
{
868
 
        /*
869
 
         *      If it's an on-the-wire base attribute, return
870
 
         *      the cached value for it.
871
 
         */
872
 
        if ((val >= 0) && (val < 256)) {
873
 
                return base_attributes[val];
874
 
 
875
 
        } else {
876
 
                DICT_ATTR myattr;
877
 
 
878
 
                myattr.attr = val;
879
 
                return rbtree_finddata(attributes_byvalue, &myattr);
880
 
        }
881
 
 
882
 
        return NULL;            /* never reached, but useful */
 
1174
        return lrad_hash_table_finddata(attributes_byvalue, (uint32_t) val);
883
1175
}
884
1176
 
885
1177
/*
887
1179
 */
888
1180
DICT_ATTR *dict_attrbyname(const char *name)
889
1181
{
890
 
        DICT_ATTR myattr;
891
 
 
892
 
        strNcpy(myattr.name, name, sizeof(myattr.name));
893
 
 
894
 
        return rbtree_finddata(attributes_byname, &myattr);
 
1182
        if (!name) return NULL;
 
1183
 
 
1184
        return lrad_hash_table_finddata(attributes_byname,
 
1185
                                        dict_hashname(name));
895
1186
}
896
1187
 
897
1188
/*
899
1190
 */
900
1191
DICT_VALUE *dict_valbyattr(int attr, int val)
901
1192
{
902
 
        DICT_VALUE      myval;
903
 
 
904
 
        myval.attr = attr;
905
 
        myval.value = val;
906
 
 
907
 
        return rbtree_finddata(values_byvalue, &myval);
 
1193
        uint32_t hash = attr;
 
1194
 
 
1195
        hash = lrad_hash_update(&val, sizeof(val), hash);
 
1196
 
 
1197
        return lrad_hash_table_finddata(values_byvalue, hash);
908
1198
}
909
1199
 
910
1200
/*
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
915
 
 *      seems to. :) --kph
 
1201
 *      Get a value by its name, keyed off of an attribute.
916
1202
 */
917
1203
DICT_VALUE *dict_valbyname(int attr, const char *name)
918
1204
{
919
 
        DICT_VALUE      myval;
920
 
 
921
 
        myval.attr = attr;
922
 
        strNcpy(myval.name, name, sizeof(myval.name));
923
 
 
924
 
        return rbtree_finddata(values_byname, &myval);
 
1205
        uint32_t hash;
 
1206
 
 
1207
        if (!name) return NULL;
 
1208
 
 
1209
        hash = dict_hashname(name);
 
1210
        hash = lrad_hash_update(&attr, sizeof(&attr), hash);
 
1211
 
 
1212
        return lrad_hash_table_finddata(values_byname, hash);
925
1213
}
926
1214
 
927
1215
/*
928
1216
 *      Get the vendor PEC based on the vendor name
 
1217
 *
 
1218
 *      This is efficient only for small numbers of vendors.
929
1219
 */
930
1220
int dict_vendorbyname(const char *name)
931
1221
{
932
 
        DICT_VENDOR *v;
933
 
 
934
 
        /*
935
 
         *      Find the vendor, if any.
936
 
         */
937
 
        for (v = dictionary_vendors; v; v = v->next) {
938
 
                if (strcasecmp(name, v->name) == 0) {
939
 
                        return v->vendorpec;
940
 
                }
941
 
        }
942
 
 
943
 
        return 0;
 
1222
        uint32_t hash;
 
1223
        DICT_VENDOR     *dv;
 
1224
 
 
1225
        if (!name) return 0;
 
1226
 
 
1227
        hash = dict_hashname(name);
 
1228
        
 
1229
        dv = lrad_hash_table_finddata(vendors_byname, hash);
 
1230
        if (!dv) return 0;
 
1231
 
 
1232
        return dv->vendorpec;
944
1233
}
945
1234
 
946
1235
/*
948
1237
 */
949
1238
DICT_VENDOR *dict_vendorbyvalue(int vendor)
950
1239
{
951
 
        DICT_VENDOR *v;
952
 
 
953
 
        /*
954
 
         *      Find the vendor, if any.
955
 
         */
956
 
        for (v = dictionary_vendors; v; v = v->next) {
957
 
                if (vendor == v->vendorpec) {
958
 
                        return v;
959
 
                }
960
 
        }
961
 
 
962
 
        return NULL;
963
 
 
 
1240
        return lrad_hash_table_finddata(vendors_byvalue, (uint32_t) vendor);
964
1241
}