Initial revision
[freeradius.git] / src / lib / dict.c
1 /*
2  * dict.c       Routines to read the dictionary file.
3  *
4  * Version:     @(#)dict.c  2.30  25-Jul-1999  miquels@cistron.nl
5  *
6  */
7
8 #include        <autoconf.h>
9
10 #include        <stdio.h>
11 #include        <stdlib.h>
12 #include        <sys/types.h>
13 #include        <pwd.h>
14 #include        <ctype.h>
15 #include        <string.h>
16
17 #if HAVE_MALLOC_H
18 #  include      <malloc.h>
19 #endif
20
21 #include        "libradius.h"
22
23 static DICT_ATTR        *dictionary_attributes;
24 static DICT_VALUE       *dictionary_values;
25 static DICT_VENDOR      *dictionary_vendors;
26
27 static int              vendorno = 1;
28 static char *dtypes[] = {
29         "string",
30         "integer",
31         "ipaddr",
32         "date",
33         NULL,
34 };
35
36 #ifdef WITH_DICT_NOCASE
37 #define DICT_STRCMP strcasecmp
38 #else
39 #define DICT_STRCMP strcmp
40 #endif
41
42 /*
43  *      Free the dictionary_attributes and dictionary_values lists.
44  */
45 static void dict_free(void)
46 {
47         DICT_ATTR       *dattr, *anext;
48         DICT_VALUE      *dval, *vnext;
49         DICT_VENDOR     *dvend, *enext;
50
51         for (dattr = dictionary_attributes; dattr; dattr = anext) {
52                 anext = dattr->next;
53                 free(dattr);
54         }
55         for (dval = dictionary_values; dval; dval = vnext) {
56                 vnext = dval->next;
57                 free(dval);
58         }
59         for (dvend = dictionary_vendors; dvend; dvend = enext) {
60                 enext = dvend->next;
61                 free(dvend);
62         }
63         dictionary_attributes = NULL;
64         dictionary_values = NULL;
65         dictionary_vendors = NULL;
66         vendorno = 1;
67 }
68
69 /*
70  *      Add vendor to the list.
71  */
72 static int addvendor(char *name, int value)
73 {
74         DICT_VENDOR *vval;
75
76         if ((vval =(DICT_VENDOR *)malloc(sizeof(DICT_VENDOR))) == NULL) {
77                 librad_log("dict_init: out of memory");
78                 return -1;
79         }
80         strcpy(vval->vendorname, name);
81         vval->vendorpec  = value;
82         vval->vendorcode = vendorno++;
83
84         /* Insert at front. */
85         vval->next = dictionary_vendors;
86         dictionary_vendors = vval;
87
88         return 0;
89 }
90
91 /*
92  *      Initialize the dictionary.
93  */
94 static int my_dict_init(char *dir, char *fn)
95 {
96         FILE    *fp;
97         DICT_ATTR       *attr;
98         DICT_VALUE      *dval;
99         DICT_VENDOR     *v;
100         char    dirtmp[256];
101         char    buf[256];
102         char    namestr[64];
103         char    valstr[64];
104         char    attrstr[64];
105         char    typestr[64];
106         char    vendorstr[64];
107         char    *p;
108         char    *keyword;
109         char    *data;
110         int     line = 0;
111         int     value;
112         int     type;
113         int     vendor;
114         int     is_attrib;
115 #ifdef ATTRIB_NMC
116         int     vendor_usr_seen = 0;
117         int     is_nmc;
118 #endif
119
120         /*
121          *      First see if fn is relative to dir. If so, create
122          *      new filename. If not, remember the absolute dir.
123          */
124         if ((p = strrchr(fn, '/')) != NULL) {
125                 strcpy(dirtmp, fn);
126                 dirtmp[p - fn] = 0;
127                 dir = dirtmp;
128         } else if (dir && dir[0] && strcmp(dir, ".") != 0) {
129                 sprintf(dirtmp, "%s/%s", dir, fn);
130                 fn = dirtmp;
131         }
132
133         if ((fp = fopen(fn, "r")) == NULL) {
134                 librad_log("dict_init: Couldn't open dictionary: %s", fn);
135                 return -1;
136         }
137
138         while (fgets(buf, sizeof(buf), fp) != NULL) {
139
140                 line++;
141                 if (buf[0] == '#' || buf[0] == 0 || buf[0] == '\n')
142                         continue;
143
144                 keyword = strtok(buf, " \t\n");
145                 data    = strtok(NULL, "\n");
146                 if (data == NULL || data[0] == 0) {
147                         librad_log("dict_init: %s[%d]: invalid entry",
148                                 fn, line);
149                         return -1;
150                 }
151
152                 /*
153                  *      See if we need to import another dictionary.
154                  */
155                 if (strcasecmp(keyword, "$INCLUDE") == 0) {
156                         if (my_dict_init(dir, data) < 0)
157                                 return -1;
158                         continue;
159                 }
160
161                 /*
162                  *      Perhaps this is an attribute.
163                  */
164                 is_attrib = 0;
165                 if (strcmp(keyword, "ATTRIBUTE") == 0)
166                         is_attrib = 1;
167 #ifdef ATTRIB_NMC
168                 is_nmc = 0;
169                 if (strcmp(keyword, "ATTRIB_NMC") == 0)
170                         is_attrib = is_nmc = 1;
171 #endif
172                 if (is_attrib) {
173
174                         vendor = 0;
175                         vendorstr[0] = 0;
176                         if(sscanf(data, "%s%s%s%s", namestr,
177                                         valstr, typestr, vendorstr) < 3) {
178                                 librad_log(
179                                         "dict_init: %s[%d]: invalid attribute",
180                                         fn, line);
181                                 return -1;
182                         }
183
184 #ifdef ATTRIB_NMC
185                         /*
186                          *      Convert ATTRIB_NMC into our format.
187                          *      We might need to add USR to the list of
188                          *      vendors first.
189                          */
190                         if (is_nmc && vendorstr[0] == 0) {
191                                 if (!vendor_usr_seen) {
192                                         if (addvendor("USR", VENDORPEC_USR) < 0)
193                                                 return -1;
194                                         vendor_usr_seen = 1;
195                                 }
196                                 strcpy(vendorstr, "USR");
197                         }
198 #endif
199                         /*
200                          *      Validate all entries
201                          */
202                         if (strlen(namestr) > 31) {
203                                 librad_log(
204                                 "dict_init: %s[%d]: invalid name length",
205                                         fn, line);
206                                 return -1;
207                         }
208
209                         if (!isdigit(*valstr)) {
210                                 librad_log("dict_init: %s[%d]: invalid value",
211                                         fn, line);
212                                 return -1;
213                         }
214                         if (valstr[0] != '0')
215                                 value = atoi(valstr);
216                         else
217                                 sscanf(valstr, "%i", &value);
218
219                         /*
220                          *      find the type.
221                          */
222                         for (type = 0; dtypes[type]; type++) {
223                                 if (strcmp(typestr, dtypes[type]) == 0)
224                                         break;
225                         }
226                         if (dtypes[type] == NULL) {
227                                 librad_log("dict_init: %s[%d]: invalid type",
228                                         fn, line);
229                                 return -1;
230                         }
231
232                         /*
233                          *      Find the vendor, if any.
234                          */
235                         for (v = dictionary_vendors; v; v = v->next) {
236                                 if (strcmp(vendorstr, v->vendorname) == 0)
237                                         vendor = v->vendorcode;
238                         }
239                         if (vendorstr[0] && !vendor) {
240                                 librad_log(
241                                         "dict_init: %s[%d]: unknown vendor %s",
242                                         fn, line, vendorstr);
243                                 return -1;
244                         }
245
246                         /*
247                          *      Create a new attribute for the list
248                          */
249                         if ((attr = (DICT_ATTR *)malloc(sizeof(DICT_ATTR))) ==
250                                         NULL) {
251                                 librad_log("dict_init: out of memory");
252                                 return -1;
253                         }
254                         strcpy(attr->name, namestr);
255                         attr->attr = value;
256                         attr->type = type;
257                         if (vendor)
258                                 attr->attr |= (vendor << 16);
259
260                         /*
261                          *      Add to the front of the list, so that
262                          *      values at the end of the file override
263                          *      those in the begin.
264                          */
265                         attr->next = dictionary_attributes;
266                         dictionary_attributes = attr;
267
268                 }
269
270                 /*
271                  *      Process VALUE lines.
272                  */
273                 if (strcmp(keyword, "VALUE") == 0) {
274
275                         if (sscanf(data, "%s%s%s", attrstr,
276                                                 namestr, valstr) != 3) {
277                                 librad_log("dict_init: %s[%d]: invalid value",
278                                         fn, line);
279                                 return -1;
280                         }
281                         /*
282                          *      For Compatibility, skip "Server-Config"
283                          */
284                         if (strcmp(attrstr, "Server-Config") == 0)
285                                 continue;
286
287                         /*
288                          *      Validate all entries
289                          */
290                         if (strlen(attrstr) > 31) {
291                                 librad_log(
292                                 "dict_init: %s[%d]: invalid attribute length",
293                                         fn, line);
294                                 return -1;
295                         }
296
297                         if (strlen(namestr) > 31) {
298                                 librad_log(
299                                 "dict_init: %s[%d]: invalid name length",
300                                         fn, line);
301                                 return -1;
302                         }
303
304                         if (!isdigit(*valstr)) {
305                                 librad_log("dict_init: %s[%d]: invalid value",
306                                         fn, line);
307                                 return -1;
308                         }
309                         if (valstr[0] != '0')
310                                 value = atoi(valstr);
311                         else
312                                 sscanf(valstr, "%i", &value);
313
314                         if ((dval = (DICT_VALUE *)malloc(sizeof(DICT_VALUE))) ==
315                                         NULL) {
316                                 librad_log("dict_init: out of memory");
317                                 return -1;
318                         }
319
320                         strcpy(dval->name, namestr);
321                         strcpy(dval->attrname, attrstr);
322                         dval->attr = 0;
323                         dval->value = value;
324
325                         /* Insert at front. */
326                         dval->next = dictionary_values;
327                         dictionary_values = dval;
328                 }
329
330                 /*
331                  *      Process VENDOR lines.
332                  */
333                 if (strcmp(keyword, "VENDOR") == 0) {
334
335                         if (sscanf(data, "%s%s", attrstr, valstr) != 2) {
336                                 librad_log(
337                                 "dict_init: %s[%d] invalid vendor entry",
338                                         fn, line);
339                                 return -1;
340                         }
341
342                         /*
343                          *       Validate all entries
344                          */
345                         if (strlen(attrstr) > 31) {
346                                 librad_log(
347                                 "dict_init: %s[%d]: invalid attribute length",
348                                         fn, line);
349                                 return -1;
350                         }
351
352                         if (!isdigit(*valstr)) {
353                                 librad_log("dict_init: %s[%d]: invalid value",
354                                         fn, line);
355                                 return -1;
356                         }
357                         value = atoi(valstr);
358
359                         /* Create a new VENDOR entry for the list */
360                         if (addvendor(attrstr, value) < 0)
361                                 return -1;
362 #ifdef ATTRIB_NMC
363                         if (value == VENDORPEC_USR)
364                                 vendor_usr_seen = 1;
365 #endif
366                 }
367         }
368         fclose(fp);
369         return 0;
370 }
371
372 /*
373  *      Initialize the directory, then fix the attr member of
374  *      all attributes.
375  */
376 int dict_init(char *dir, char *fn)
377 {
378         DICT_ATTR       *attr;
379         DICT_VALUE      *dval;
380
381         dict_free();
382
383         if (my_dict_init(dir, fn) < 0)
384                 return -1;
385
386         for (dval = dictionary_values; dval; dval = dval->next) {
387                 if (dval->attr != 0)
388                         continue;
389                 if ((attr = dict_attrbyname(dval->attrname)) == NULL) {
390                 librad_log("dict_init: VALUE %s for unknown ATTRIBUTE %s",
391                         dval->name, dval->attrname);
392                         return -1;
393                 }
394                 dval->attr = attr->attr;
395         }
396
397         return 0;
398 }
399
400 /*
401  *      Get an attribute by its numerical value.
402  */
403 DICT_ATTR * dict_attrbyvalue(int val)
404 {
405         DICT_ATTR       *a;
406
407         for (a = dictionary_attributes; a; a = a->next) {
408                 if (a->attr == val)
409                         return a;
410         }
411
412         return NULL;
413 }
414
415 /*
416  *      Get an attribute by its name.
417  */
418 DICT_ATTR * dict_attrbyname(char *name)
419 {
420         DICT_ATTR       *a;
421
422         for (a = dictionary_attributes; a; a = a->next) {
423                 if (DICT_STRCMP(a->name, name) == 0)
424                         return a;
425         }
426
427         return NULL;
428 }
429
430 /*
431  *      Associate a value with an attribute and return it.
432  */
433 DICT_VALUE * dict_valbyattr(int attr, int val)
434 {
435         DICT_VALUE      *v;
436
437         for (v = dictionary_values; v; v = v->next) {
438                 if (v->attr == attr && v->value == val)
439                         return v;
440         }
441
442         return NULL;
443 }
444
445 /*
446  *      Get a value by its name.
447  */
448 DICT_VALUE * dict_valbyname(char *name)
449 {
450         DICT_VALUE      *v;
451
452         for (v = dictionary_values; v; v = v->next) {
453                 if (DICT_STRCMP(v->name, name) == 0)
454                         return v;
455         }
456
457         return NULL;
458 }
459
460 /*
461  *      Get the PEC (Private Enterprise Code) of the vendor
462  *      based on its internal number.
463  */
464 int dict_vendorpec(int code)
465 {
466         DICT_VENDOR     *v;
467
468         for (v = dictionary_vendors; v; v = v->next)
469                 if (v->vendorcode == code)
470                         break;
471
472         return v ? v->vendorpec : 0;
473 }
474
475 /*
476  *      Get the internal code of the vendor based on its PEC.
477  */
478 int dict_vendorcode(int pec)
479 {
480         DICT_VENDOR     *v;
481
482         for (v = dictionary_vendors; v; v = v->next)
483                 if (v->vendorpec == pec)
484                         break;
485         return v ? v->vendorcode : 0;
486 }
487