packet-smb2: maintain a smb2_fid_info per open file
[metze/wireshark/wip.git] / epan / radius_dict.l
1 /*
2  * We don't use input, so don't generate code for it.
3  */
4 %option noinput
5
6 /*
7  * We don't use unput, so don't generate code for it.
8  */
9 %option nounput
10
11 /*
12  * We don't read from the terminal.
13  */
14 %option never-interactive
15
16 /*
17  * The language we're scanning is case-insensitive.
18  */
19 %option caseless
20
21 /*
22  * Prefix scanner routines with "Radius" rather than "yy", so this scanner
23  * can coexist with other scanners.
24  */
25 %option prefix="Radius"
26
27 %option outfile="radius_dict.c"
28
29 %{
30         /* radius_dict.l
31         *
32         * RADIUS dictionary parser
33         *
34         * Wireshark - Network traffic analyzer
35         * By Gerald Combs <gerald@wireshark.org>
36         * Copyright 1998 Gerald Combs
37         *
38         * This program is free software; you can redistribute it and/or
39         * modify it under the terms of the GNU General Public License
40         * as published by the Free Software Foundation; either version 2
41         * of the License, or (at your option) any later version.
42         *
43         * This program is distributed in the hope that it will be useful,
44         * but WITHOUT ANY WARRANTY; without even the implied warranty of
45         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
46         * GNU General Public License for more details.
47         *
48         * You should have received a copy of the GNU General Public License
49         * along with this program; if not, write to the Free Software
50         * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
51         */
52
53 #include "config.h"
54
55 #include <glib.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <errno.h>
60 #include <epan/packet.h>
61 #include <epan/dissectors/packet-radius.h>
62 #include "radius_dict_lex.h"
63 #include <wsutil/file_util.h>
64
65 #ifdef _WIN32
66 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated  */
67 /* with YY_INPUT code generated by flex versions such as 2.5.35.              */
68 #pragma warning (disable:4018)
69 #endif
70
71 #define ECHO
72 #define MAX_INCLUDE_DEPTH 10
73
74         static void add_vendor(const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags);
75         static void add_value(const gchar* attrib_name,const  gchar* repr, guint32 value);
76         static void add_tlv(const gchar* name, const  gchar* code, radius_attr_dissector_t type, const gchar* attr);
77         static void add_attribute(const gchar*,const  gchar*, radius_attr_dissector_t,const  gchar*, guint, gboolean, const gchar*);
78
79         static YY_BUFFER_STATE include_stack[10];
80         static int include_stack_ptr = 0;
81
82         static radius_dictionary_t* dict = NULL;
83         static GHashTable* value_strings = NULL; /* GArray(value_string) by attribute name */
84
85         static gchar* attr_name = NULL;
86         static gchar* attr_id = NULL;
87         static radius_attr_dissector_t* attr_type = NULL;
88         static gchar* attr_vendor = NULL;
89         static gchar* vendor_name = NULL;
90         static guint32 vendor_id = 0;
91         static guint vendor_type_octets = 1;
92         static guint vendor_length_octets = 1;
93         static gboolean vendor_has_flags = FALSE;
94         static gchar* value_repr = NULL;
95         static guint encrypted = 0;
96         static gboolean has_tag = FALSE;
97         static gchar* current_vendor = NULL;
98         static gchar* current_attr = NULL;
99
100         static GString* error = NULL;
101         static gchar* directory = NULL;
102         static int linenums[] = {1,1,1,1,1,1,1,1,1,1};
103         static gchar* fullpaths[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
104
105 %}
106
107 /* Note: FreeRadius allows VENDOR, ATTRIBUTE and VALUE names to contain any non-blank character.
108  *       Using a negated "blank character class" pattern below for those names fails for some reason
109  *       so for now the patterns for each name type include those characters found for the corresponding
110  *       name types in the FreeRadius dictionaries.
111  */
112
113 %START WS_OUT VENDOR VENDOR_W_NAME ATTR ATTR_W_NAME ATTR_W_ID ATTR_W_TYPE ATTR_W_VENDOR VALUE VALUE_W_ATTR VALUE_W_NAME INCLUDE JUNK BEGIN_VENDOR END_VENDOR VENDOR_W_ID VENDOR_W_FORMAT VENDOR_W_TYPE_OCTETS VENDOR_W_LENGTH_OCTETS VENDOR_W_CONTINUATION BEGIN_TLV END_TLV
114 %%
115 [:blank:]   ;
116 #[^\n]*         ;
117
118 <JUNK>.*\qn             ;
119
120 <WS_OUT>VENDOR { BEGIN VENDOR; }
121 <WS_OUT>ATTRIBUTE { BEGIN ATTR; }
122 <WS_OUT>VALUE { BEGIN VALUE; }
123 <WS_OUT>\$INCLUDE { BEGIN INCLUDE; }
124 <WS_OUT>BEGIN-VENDOR { BEGIN BEGIN_VENDOR; }
125 <WS_OUT>END-VENDOR { BEGIN END_VENDOR; }
126 <WS_OUT>BEGIN-TLV { BEGIN BEGIN_TLV; }
127 <WS_OUT>END-TLV { BEGIN END_TLV; }
128
129 <BEGIN_VENDOR>[0-9a-z_-]+ {
130     if (current_vendor) {
131         g_free(current_vendor);
132     }
133     current_vendor = g_strdup(yytext);
134     BEGIN WS_OUT;
135 }
136 <END_VENDOR>[^\n]* {
137     if (current_vendor) {
138         g_free(current_vendor);
139         current_vendor = NULL;
140     }
141     BEGIN WS_OUT;
142 }
143
144 <BEGIN_TLV>[0-9a-z_-]+ {
145     if (current_attr) {
146         g_free(current_attr);
147     }
148     current_attr = g_strdup(yytext);
149     BEGIN WS_OUT;
150 }
151 <END_TLV>[^\n]* {
152     if (current_attr) {
153         g_free(current_attr);
154         current_attr = NULL;
155     }
156     BEGIN WS_OUT;
157 }
158
159 <VENDOR>[0-9a-z_-]+   {
160     vendor_name = g_strdup(yytext);
161     vendor_type_octets = 1;
162     vendor_length_octets = 1;
163     vendor_has_flags = FALSE;
164     BEGIN VENDOR_W_NAME;
165 }
166 <VENDOR_W_NAME>[0-9]+   {
167     vendor_id = (guint32) strtoul(yytext,NULL,10);
168     BEGIN VENDOR_W_ID;
169 }
170 <VENDOR_W_NAME>0x[0-9a-f]+   {
171     vendor_id = (guint32) strtoul(yytext,NULL,16);
172     BEGIN VENDOR_W_ID;
173 }
174 <VENDOR_W_ID>format= {
175     BEGIN VENDOR_W_FORMAT;
176 }
177 <VENDOR_W_FORMAT>[124] {
178     vendor_type_octets = (guint) strtoul(yytext,NULL,10);
179     BEGIN VENDOR_W_TYPE_OCTETS;
180 }
181 <VENDOR_W_TYPE_OCTETS>,[012] {
182     vendor_length_octets = (guint) strtoul(yytext+1,NULL,10);
183     BEGIN VENDOR_W_LENGTH_OCTETS;
184 }
185 <VENDOR_W_LENGTH_OCTETS>,c {
186     vendor_has_flags = TRUE;
187     BEGIN VENDOR_W_CONTINUATION;
188 }
189 <VENDOR_W_FORMAT>\n |
190 <VENDOR_W_TYPE_OCTETS>\n |
191 <VENDOR_W_LENGTH_OCTETS>\n |
192 <VENDOR_W_CONTINUATION>\n |
193 <VENDOR_W_ID>\n {
194     add_vendor(vendor_name, vendor_id, vendor_type_octets, vendor_length_octets, vendor_has_flags);
195     g_free(vendor_name);
196     BEGIN WS_OUT;
197 }
198
199 <ATTR>[0-9a-z_/.-]+                     { attr_name = g_strdup(yytext); encrypted = 0; has_tag = FALSE; BEGIN ATTR_W_NAME; }
200 <ATTR_W_NAME>[0-9]+                     { attr_id = g_strdup(yytext);  BEGIN ATTR_W_ID;}
201 <ATTR_W_NAME>0x[0-9a-f]+                { attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
202 <ATTR_W_ID>integer                      { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
203 <ATTR_W_ID>string                       { attr_type = radius_string;  BEGIN ATTR_W_TYPE; }
204 <ATTR_W_ID>octets                       { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
205 <ATTR_W_ID>ipaddr                       { attr_type = radius_ipaddr;  BEGIN ATTR_W_TYPE; }
206 <ATTR_W_ID>ipv6addr                     { attr_type = radius_ipv6addr;  BEGIN ATTR_W_TYPE; }
207 <ATTR_W_ID>ipv6prefix                   { attr_type = radius_ipv6prefix;  BEGIN ATTR_W_TYPE; }
208 <ATTR_W_ID>ipxnet                       { attr_type = radius_ipxnet;  BEGIN ATTR_W_TYPE; }
209 <ATTR_W_ID>date                         { attr_type = radius_date;  BEGIN ATTR_W_TYPE; }
210 <ATTR_W_ID>abinary                      { attr_type = radius_abinary;  BEGIN ATTR_W_TYPE; }
211 <ATTR_W_ID>ether                        { attr_type = radius_ether;  BEGIN ATTR_W_TYPE; }
212 <ATTR_W_ID>ifid                         { attr_type = radius_ifid;  BEGIN ATTR_W_TYPE; }
213 <ATTR_W_ID>byte                         { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
214 <ATTR_W_ID>short                        { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
215 <ATTR_W_ID>signed                       { attr_type = radius_signed;  BEGIN ATTR_W_TYPE; }
216 <ATTR_W_ID>combo-ip                     { attr_type = radius_combo_ip;  BEGIN ATTR_W_TYPE; }
217 <ATTR_W_ID>tlv                          { attr_type = radius_tlv;  BEGIN ATTR_W_TYPE; }
218 <ATTR_W_ID>[0-9a-z_-]+                  { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
219 <ATTR_W_TYPE>has_tag[,]?                { has_tag = TRUE; }
220 <ATTR_W_TYPE>encrypt=[123][,]?          { encrypted = (guint) strtoul(yytext+8,NULL,10); }
221 <ATTR_W_TYPE>[0-9a-z_-]+=([^\n]*)       ;
222 <ATTR_W_TYPE>[0-9a-z_-]+                {
223     attr_vendor = g_strdup(yytext);
224     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
225     g_free(attr_id);
226     g_free(attr_vendor);
227     g_free(attr_name);
228     attr_id = NULL;
229     attr_vendor = NULL;
230     attr_name = NULL;
231     BEGIN WS_OUT;
232 }
233 <ATTR_W_TYPE>\n                                         {
234     add_attribute(attr_name,attr_id,attr_type,current_vendor,encrypted,has_tag,current_attr);
235     g_free(attr_id);
236     g_free(attr_name);
237     linenums[include_stack_ptr]++;
238     has_tag = FALSE;
239     encrypted=FALSE;
240     BEGIN WS_OUT;
241 }
242 <ATTR_W_VENDOR>\n                                       {
243     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
244     g_free(attr_id);
245     g_free(attr_vendor);
246     g_free(attr_name);
247     linenums[include_stack_ptr]++;
248     BEGIN WS_OUT;
249 };
250
251 <VALUE>[0-9a-z_/-]+                             { attr_name = g_strdup(yytext); BEGIN VALUE_W_ATTR; }
252 <VALUE_W_ATTR>[^[:blank:]]+                     { value_repr = g_strdup(yytext); BEGIN VALUE_W_NAME; }
253 <VALUE_W_NAME>[0-9]+                            { add_value(attr_name,value_repr, (guint32) strtoul(yytext,NULL,10));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
254 <VALUE_W_NAME>0x[0-9a-f]+                       { add_value(attr_name,value_repr, (guint32) strtoul(yytext,NULL,16));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
255
256 <INCLUDE>[^[:blank:]\n]+   {
257         if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
258                 g_string_append_printf(error, "$INCLUDE files nested to deeply\n");
259                 yyterminate();
260         }
261
262         include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
263
264         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
265             directory,yytext);
266
267         yyin = ws_fopen( fullpaths[include_stack_ptr], "r" );
268
269         if (!yyin) {
270                 if (errno) {
271                         g_string_append_printf(error,
272                                         "Could not open file: '%s', error: %s\n",
273                                         fullpaths[include_stack_ptr],
274                                         g_strerror(errno) );
275                 } else {
276                         g_string_append_printf(error,
277                                         "Could not open file: '%s', no errno\n",
278                                         fullpaths[include_stack_ptr]);
279                 }
280                 g_free(fullpaths[include_stack_ptr]);
281                 fullpaths[include_stack_ptr] = NULL;
282                 include_stack_ptr--;
283         } else {
284                 linenums[include_stack_ptr] = 1;
285                 yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
286         }
287
288
289         BEGIN WS_OUT;
290 }
291
292 <<EOF>> {
293
294         fclose(yyin);
295         yyin = NULL;
296
297         if ( --include_stack_ptr < 0 ) {
298                 yyterminate();
299         } else {
300                 g_free(fullpaths[include_stack_ptr+1]);
301                 fullpaths[include_stack_ptr+1] = NULL;
302
303                 yy_delete_buffer( YY_CURRENT_BUFFER );
304                 yy_switch_to_buffer(include_stack[include_stack_ptr]);
305         }
306
307         BEGIN WS_OUT;
308 }
309
310 \n      { linenums[include_stack_ptr]++; BEGIN WS_OUT; }
311
312
313 %%
314
315 static void add_vendor(const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags) {
316         radius_vendor_info_t* v;
317
318         v = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(id));
319
320         if (!v) {
321                 /*
322                  * New vendor.
323                  * Allocate a new entry and insert it into the by-ID and
324                  * by-name hash tables.
325                  */
326                 v = g_new(radius_vendor_info_t,1);
327                 v->attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
328                 v->code = id;
329                 v->ett = -1;
330                 v->name = g_strdup(name);
331                 v->type_octets = type_octets;
332                 v->length_octets = length_octets;
333                 v->has_flags = has_flags;
334
335                 g_hash_table_insert(dict->vendors_by_id,GUINT_TO_POINTER(v->code),v);
336                 g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
337         } else {
338                 /*
339                  * This vendor is already in the table.
340                  *
341                  * Assume that the dictionary knows the 'ground truth' about
342                  * the type/length/has_flags information and thus allow the
343                  * dictionary to overwrite these values even for vendors that
344                  * have already been loaded.
345                  *
346                  * XXX - this could be due to the vendor being in multiple
347                  * dictionary files, rather than having been specially
348                  * entered by the RADIUS dissector, as a side effect of
349                  * specially entering an attribute; should we report vendors
350                  * that appear in different dictionaries with different
351                  * properties?
352                  */
353                 v->type_octets = type_octets;
354                 v->length_octets = length_octets;
355                 v->has_flags = has_flags;
356
357                 /*
358                  * Did the name change?
359                  */
360                 if (g_strcmp0(v->name, name) != 0) {
361                         /*
362                          * Yes.  Remove the entry from the by-name hash table
363                          * and re-insert it with the new name.
364                          */
365                         g_hash_table_remove(dict->vendors_by_name, (gpointer) v->name);
366                         g_free((gpointer) v->name);
367                         v->name = g_strdup(name);
368                         g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
369                 }
370         }
371 }
372
373 static void add_attribute(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const  gchar* vendor, guint encrypted_flag, gboolean tagged, const gchar* attr) {
374         radius_attr_info_t* a;
375         GHashTable* by_id;
376         guint32 code;
377
378         if (attr){
379                 add_tlv(name, codestr, type, attr);
380                 return;
381         }
382
383
384         if (vendor) {
385                 radius_vendor_info_t* v;
386                 v = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_name,vendor);
387
388                 if (! v) {
389                         g_string_append_printf(error, "Vendor: '%s', does not exist in %s:%i \n", vendor, fullpaths[include_stack_ptr], linenums[include_stack_ptr] );
390                         BEGIN JUNK;
391                         return;
392                 } else {
393                         by_id = v->attrs_by_id;
394                 }
395         } else {
396                 by_id = dict->attrs_by_id;
397         }
398
399         code= (guint32) strtoul(codestr, NULL, 10);
400
401         a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
402
403         if (!a) {
404                 /*
405                  * New attribute.
406                  * Allocate a new entry and insert it into the by-ID and
407                  * by-name hash tables.
408                  */
409                 a = g_new(radius_attr_info_t,1);
410                 a->code = code;
411                 a->name = g_strdup(name);
412                 a->dissector = NULL;
413                 a->encrypt = encrypted_flag;
414                 a->tagged =  tagged;
415                 a->type = type;
416                 a->vs = NULL;
417                 a->hf = -1;
418                 a->hf_alt = -1;
419                 a->hf_tag = -1;
420                 a->hf_len = -1;
421                 a->ett = -1;
422                 a->tlvs_by_id = NULL;
423                 g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
424                 g_hash_table_insert(dict->attrs_by_name,(gpointer) (a->name),a);
425         } else {
426                 /*
427                  * This attribute is already in the table.
428                  *
429                  * Overwrite the encrypted flag, tagged property, and type;
430                  * the other properties don't get set until after we've
431                  * finished reading the dictionaries.
432                  *
433                  * XXX - this could be due to the attribute being in
434                  * multiple dictionary files, rather than having been
435                  * specially entered by the RADIUS dissector to give it
436                  * a special dissection routine; should we report attributes
437                  * that appear in different dictionaries with different
438                  * properties?
439                  */
440                 a->encrypt = encrypted_flag;
441                 a->tagged =  tagged;
442                 a->type = type;
443
444                 /*
445                  * Did the name change?
446                  */
447                 if (g_strcmp0(a->name, name) != 0) {
448                         /*
449                          * Yes.  Remove the entry from the by-name hash table
450                          * and re-insert it with the new name.
451                          */
452                         g_hash_table_remove(dict->attrs_by_name, (gpointer) (a->name));
453                         g_free((gpointer) a->name);
454                         a->name = g_strdup(name);
455                         g_hash_table_insert(dict->attrs_by_name, (gpointer) (a->name),a);
456                 }
457         }
458 }
459
460 static void add_tlv(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const gchar* attr) {
461         radius_attr_info_t* a;
462         radius_attr_info_t* s;
463         guint32 code;
464
465         a = (radius_attr_info_t*)g_hash_table_lookup(dict->attrs_by_name, attr);
466
467         if (! a) {
468                 g_string_append_printf(error, "Attr: '%s', does not exist in %s:%i \n", attr, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
469                 BEGIN JUNK;
470                 return;
471         }
472
473         if (type == radius_tlv) {
474                 g_string_append_printf(error, "sub-TLV: '%s', sub-TLV's type is specified as tlv in %s:%i \n", name, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
475                 BEGIN JUNK;
476                 return;
477         }
478
479
480         if (! a->tlvs_by_id) {
481                 a->tlvs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
482         }
483
484         code = (guint32) strtoul(codestr, NULL, 10);
485
486         s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
487
488         if (!s) {
489                 /*
490                  * This TLV doesn't yet exist in this attribute's TLVs-by-ID
491                  * hash table.  Add it.
492                  */
493                 s = g_new(radius_attr_info_t,1);
494                 s->name = g_strdup(name);
495                 s->dissector = NULL;
496                 s->code = code;
497                 s->type = type;
498                 s->encrypt = FALSE;
499                 s->tagged = FALSE;
500                 s->dissector = NULL;
501                 s->vs = NULL;
502                 s->hf = -1;
503                 s->hf_alt = -1;
504                 s->hf_tag = -1;
505                 s->hf_len = -1;
506                 s->ett = -1;
507                 s->tlvs_by_id = NULL;
508
509                 g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
510                 g_hash_table_insert(dict->tlvs_by_name,(gpointer) (s->name),s);
511         }
512
513         /*
514          * If it *does* exist, leave it alone; there shouldn't be duplicate
515          * entries by name in the dictionaries (even if there might be
516          * multiple entries for a given attribute in the dictionaries, each
517          * one adding some TLV values), and we don't directly add entries
518          * for TLVs in the RADIUS dissector.
519          *
520          * XXX - report the duplicate entries? 
521          */
522 }
523
524 void add_value(const gchar* attrib_name, const gchar* repr, guint32 value) {
525         value_string v;
526         GArray* a = (GArray*)g_hash_table_lookup(value_strings,attrib_name);
527
528         if (! a) {
529                 a = g_array_new(TRUE,TRUE,sizeof(value_string));
530                 g_hash_table_insert(value_strings,g_strdup(attrib_name),a);
531         }
532
533         v.value = value;
534         v.strptr = g_strdup(repr);
535
536         g_array_append_val(a,v);
537 }
538
539 static void setup_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
540         radius_attr_info_t* s = (radius_attr_info_t*)v;
541         gpointer key;
542
543         union {
544                 GArray* a;
545                 gpointer p;
546         } vs;
547
548         if (g_hash_table_lookup_extended(value_strings, s->name, &key, &vs.p)) {
549                 s->vs = (value_string*)(void *)vs.a->data;
550                 g_array_free(vs.a, FALSE);
551                 g_hash_table_remove(value_strings, key);
552                 g_free(key);
553         }
554 }
555
556 static void setup_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
557         radius_attr_info_t* a = (radius_attr_info_t*)v;
558         gpointer key;
559
560         union {
561                 GArray* a;
562                 gpointer p;
563         } vs;
564
565         if (g_hash_table_lookup_extended(value_strings,a->name,&key,&vs.p) ) {
566                 a->vs = (value_string*)(void *)vs.a->data;
567                 g_array_free(vs.a,FALSE);
568                 g_hash_table_remove(value_strings,key);
569                 g_free(key);
570         }
571
572         if (a->tlvs_by_id) {
573                 g_hash_table_foreach(a->tlvs_by_id, setup_tlvs, p);
574         }
575 }
576
577 static void setup_vendors(gpointer k _U_, gpointer v, gpointer p) {
578         radius_vendor_info_t* vnd = (radius_vendor_info_t*)v;
579
580         g_hash_table_foreach(vnd->attrs_by_id,setup_attrs,p);
581 }
582
583 static gboolean destroy_value_strings(gpointer k, gpointer v, gpointer p _U_) {
584         value_string* vs = (value_string*)(void *)(((GArray*)v)->data);
585
586         g_free(k);
587
588         for (;vs->strptr;vs++) {
589                 g_free((void*)vs->strptr);
590         }
591
592         g_array_free((GArray*)v,TRUE);
593         return TRUE;
594 }
595
596 gboolean radius_load_dictionary (radius_dictionary_t* d, gchar* dir, const gchar* filename, gchar** err_str) {
597         int i;
598
599         dict = d;
600         directory = dir;
601
602         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
603             directory,filename);
604
605         error = g_string_new("");
606
607         yyin = ws_fopen(fullpaths[include_stack_ptr],"r");
608
609         if (!yyin) {
610                 g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], g_strerror(errno) );
611                 g_free(fullpaths[include_stack_ptr]);
612                 *err_str = g_string_free(error,FALSE);
613                 return FALSE;
614         }
615
616         value_strings = g_hash_table_new(g_str_hash,g_str_equal);
617
618         BEGIN WS_OUT;
619
620         yylex();
621
622         if (yyin != NULL) fclose(yyin);
623         yyin = NULL;
624
625         for (i=0; i < 10; i++) {
626                 if (fullpaths[i]) g_free(fullpaths[i]);
627         }
628
629         g_hash_table_foreach(dict->attrs_by_id,setup_attrs,NULL);
630         g_hash_table_foreach(dict->vendors_by_id,setup_vendors,NULL);
631         g_hash_table_foreach_remove(value_strings,destroy_value_strings,NULL);
632
633         if (error->len > 0) {
634                 *err_str = g_string_free(error,FALSE);
635                 return FALSE;
636         } else {
637                 *err_str = NULL;
638                 g_string_free(error,TRUE);
639                 return TRUE;
640         }
641 }
642
643 /*
644  * We want to stop processing when we get to the end of the input.
645  * (%option noyywrap is not used because if used then
646  * some flex versions (eg: 2.5.35) generate code which causes
647  * warnings by the Windows VC compiler).
648  */
649
650 int yywrap(void) {
651     return 1;
652 }
653
654 /*
655  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
656  *
657  * Local variables:
658  * c-basic-offset: 8
659  * tab-width: 8
660  * indent-tabs-mode: t
661  * End:
662  *
663  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
664  * :indentSize=8:tabSize=8:noTabs=false:
665  */