Witness: add pidl output
[wireshark-wip.git] / epan / radius_dict.l
blobd2ebdff822770b35b2b431201aecbe2e143558dc
1 /*
2  * We don't use input, so don't generate code for it.
3  */
4 %option noinput
6 /*
7  * We don't use unput, so don't generate code for it.
8  */
9 %option nounput
12  * We don't read from the terminal.
13  */
14 %option never-interactive
17  * The language we're scanning is case-insensitive.
18  */
19 %option caseless
22  * Prefix scanner routines with "Radius" rather than "yy", so this scanner
23  * can coexist with other scanners.
24  */
25 %option prefix="Radius"
27 %option outfile="radius_dict.c"
30         /* radius_dict.l
31         *
32         * RADIUS dictionary parser
33         *
34         * $Id$
35         *
36         * Wireshark - Network traffic analyzer
37         * By Gerald Combs <gerald@wireshark.org>
38         * Copyright 1998 Gerald Combs
39         *
40         * This program is free software; you can redistribute it and/or
41         * modify it under the terms of the GNU General Public License
42         * as published by the Free Software Foundation; either version 2
43         * of the License, or (at your option) any later version.
44         *
45         * This program is distributed in the hope that it will be useful,
46         * but WITHOUT ANY WARRANTY; without even the implied warranty of
47         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
48         * GNU General Public License for more details.
49         *
50         * You should have received a copy of the GNU General Public License
51         * along with this program; if not, write to the Free Software
52         * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
53         */
55 #include "config.h"
57 #include <glib.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <errno.h>
62 #include <epan/packet.h>
63 #include <epan/dissectors/packet-radius.h>
64 #include "radius_dict_lex.h"
65 #include <wsutil/file_util.h>
67 #ifdef _WIN32
68 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated  */
69 /* with YY_INPUT code generated by flex versions such as 2.5.35.              */
70 #pragma warning (disable:4018)
71 #endif
73 #define ECHO
74 #define MAX_INCLUDE_DEPTH 10
76         static void add_vendor(const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags);
77         static void add_value(const gchar* attrib_name,const  gchar* repr, long value);
78         static void add_tlv(const gchar* name, const  gchar* code, radius_attr_dissector_t type, const gchar* attr);
79         static void add_attribute(const gchar*,const  gchar*, radius_attr_dissector_t,const  gchar*, guint, gboolean, const gchar*);
81         static YY_BUFFER_STATE include_stack[10];
82         static int include_stack_ptr = 0;
84         static radius_dictionary_t* dict = NULL;
85         static GHashTable* value_strings = NULL; /* GArray(value_string) by attribute name */
87         static gchar* attr_name = NULL;
88         static gchar* attr_id = NULL;
89         static radius_attr_dissector_t* attr_type = NULL;
90         static gchar* attr_vendor = NULL;
91         static gchar* vendor_name = NULL;
92         static guint32 vendor_id = 0;
93         static guint vendor_type_octets = 1;
94         static guint vendor_length_octets = 1;
95         static gboolean vendor_has_flags = FALSE;
96         static gchar* value_repr = NULL;
97         static guint encrypted = 0;
98         static gboolean has_tag = FALSE;
99         static gchar* current_vendor = NULL;
100         static gchar* current_attr = NULL;
102         static GString* error = NULL;
103         static gchar* directory = NULL;
104         static int linenums[] = {1,1,1,1,1,1,1,1,1,1};
105         static gchar* fullpaths[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
109 /* Note: FreeRadius allows VENDOR, ATTRIBUTE and VALUE names to contain any non-blank character.
110  *       Using a negated "blank character class" pattern below for those names fails for some reason
111  *       so for now the patterns for each name type include those characters found for the corresponding
112  *       name types in the FreeRadius dictionaries.
113  */
115 %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
117 [:blank:]   ;
118 #[^\n]*         ;
120 <JUNK>.*\qn             ;
122 <WS_OUT>VENDOR { BEGIN VENDOR; }
123 <WS_OUT>ATTRIBUTE { BEGIN ATTR; }
124 <WS_OUT>VALUE { BEGIN VALUE; }
125 <WS_OUT>\$INCLUDE { BEGIN INCLUDE; }
126 <WS_OUT>BEGIN-VENDOR { BEGIN BEGIN_VENDOR; }
127 <WS_OUT>END-VENDOR { BEGIN END_VENDOR; }
128 <WS_OUT>BEGIN-TLV { BEGIN BEGIN_TLV; }
129 <WS_OUT>END-TLV { BEGIN END_TLV; }
131 <BEGIN_VENDOR>[0-9a-z_-]+ {
132     if (current_vendor) {
133         g_free(current_vendor);
134     }
135     current_vendor = g_strdup(yytext);
136     BEGIN WS_OUT;
138 <END_VENDOR>[^\n]* {
139     if (current_vendor) {
140         g_free(current_vendor);
141         current_vendor = NULL;
142     }
143     BEGIN WS_OUT;
146 <BEGIN_TLV>[0-9a-z_-]+ {
147     if (current_attr) {
148         g_free(current_attr);
149     }
150     current_attr = g_strdup(yytext);
151     BEGIN WS_OUT;
153 <END_TLV>[^\n]* {
154     if (current_attr) {
155         g_free(current_attr);
156         current_attr = NULL;
157     }
158     BEGIN WS_OUT;
161 <VENDOR>[0-9a-z_-]+   {
162     vendor_name = g_strdup(yytext);
163     vendor_type_octets = 1;
164     vendor_length_octets = 1;
165     vendor_has_flags = FALSE;
166     BEGIN VENDOR_W_NAME;
168 <VENDOR_W_NAME>[0-9]+   {
169     vendor_id = strtol(yytext,NULL,10);
170     BEGIN VENDOR_W_ID;
172 <VENDOR_W_NAME>0x[0-9a-f]+   {
173     vendor_id = strtol(yytext,NULL,16);
174     BEGIN VENDOR_W_ID;
176 <VENDOR_W_ID>format= {
177     BEGIN VENDOR_W_FORMAT;
179 <VENDOR_W_FORMAT>[124] {
180     vendor_type_octets = strtol(yytext,NULL,10);
181     BEGIN VENDOR_W_TYPE_OCTETS;
183 <VENDOR_W_TYPE_OCTETS>,[012] {
184     vendor_length_octets = strtol(yytext+1,NULL,10);
185     BEGIN VENDOR_W_LENGTH_OCTETS;
187 <VENDOR_W_LENGTH_OCTETS>,c {
188     vendor_has_flags = TRUE;
189     BEGIN VENDOR_W_CONTINUATION;
191 <VENDOR_W_FORMAT>\n |
192 <VENDOR_W_TYPE_OCTETS>\n |
193 <VENDOR_W_LENGTH_OCTETS>\n |
194 <VENDOR_W_CONTINUATION>\n |
195 <VENDOR_W_ID>\n {
196     add_vendor(vendor_name, vendor_id, vendor_type_octets, vendor_length_octets, vendor_has_flags);
197     g_free(vendor_name);
198     BEGIN WS_OUT;
201 <ATTR>[0-9a-z_/.-]+                     { attr_name = g_strdup(yytext); encrypted = 0; has_tag = FALSE; BEGIN ATTR_W_NAME; }
202 <ATTR_W_NAME>[0-9]+                     { attr_id = g_strdup(yytext);  BEGIN ATTR_W_ID;}
203 <ATTR_W_NAME>0x[0-9a-f]+                { attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
204 <ATTR_W_ID>integer                      { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
205 <ATTR_W_ID>string                       { attr_type = radius_string;  BEGIN ATTR_W_TYPE; }
206 <ATTR_W_ID>octets                       { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
207 <ATTR_W_ID>ipaddr                       { attr_type = radius_ipaddr;  BEGIN ATTR_W_TYPE; }
208 <ATTR_W_ID>ipv6addr                     { attr_type = radius_ipv6addr;  BEGIN ATTR_W_TYPE; }
209 <ATTR_W_ID>ipv6prefix                   { attr_type = radius_ipv6prefix;  BEGIN ATTR_W_TYPE; }
210 <ATTR_W_ID>ipxnet                       { attr_type = radius_ipxnet;  BEGIN ATTR_W_TYPE; }
211 <ATTR_W_ID>date                         { attr_type = radius_date;  BEGIN ATTR_W_TYPE; }
212 <ATTR_W_ID>abinary                      { attr_type = radius_abinary;  BEGIN ATTR_W_TYPE; }
213 <ATTR_W_ID>ether                        { attr_type = radius_ether;  BEGIN ATTR_W_TYPE; }
214 <ATTR_W_ID>ifid                         { attr_type = radius_ifid;  BEGIN ATTR_W_TYPE; }
215 <ATTR_W_ID>byte                         { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
216 <ATTR_W_ID>short                        { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
217 <ATTR_W_ID>signed                       { attr_type = radius_signed;  BEGIN ATTR_W_TYPE; }
218 <ATTR_W_ID>combo-ip                     { attr_type = radius_combo_ip;  BEGIN ATTR_W_TYPE; }
219 <ATTR_W_ID>tlv                          { attr_type = radius_tlv;  BEGIN ATTR_W_TYPE; }
220 <ATTR_W_ID>[0-9a-z_-]+                  { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
221 <ATTR_W_TYPE>has_tag[,]?                { has_tag = TRUE; }
222 <ATTR_W_TYPE>encrypt=[123][,]?          { encrypted = strtol(yytext+8,NULL,10); }
223 <ATTR_W_TYPE>[0-9a-z_-]+=([^\n]*)       ;
224 <ATTR_W_TYPE>[0-9a-z_-]+                {
225     attr_vendor = g_strdup(yytext);
226     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
227     g_free(attr_id);
228     g_free(attr_vendor);
229     g_free(attr_name);
230     attr_id = NULL;
231     attr_vendor = NULL;
232     attr_name = NULL;
233     BEGIN WS_OUT;
235 <ATTR_W_TYPE>\n                                         {
236     add_attribute(attr_name,attr_id,attr_type,current_vendor,encrypted,has_tag,current_attr);
237     g_free(attr_id);
238     g_free(attr_name);
239     linenums[include_stack_ptr]++;
240     has_tag = FALSE;
241     encrypted=FALSE;
242     BEGIN WS_OUT;
244 <ATTR_W_VENDOR>\n                                       {
245     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
246     g_free(attr_id);
247     g_free(attr_vendor);
248     g_free(attr_name);
249     linenums[include_stack_ptr]++;
250     BEGIN WS_OUT;
253 <VALUE>[0-9a-z_/-]+                                     { attr_name = g_strdup(yytext); BEGIN VALUE_W_ATTR; }
254 <VALUE_W_ATTR>[^[:blank:]]+                     { value_repr = g_strdup(yytext); BEGIN VALUE_W_NAME; }
255 <VALUE_W_NAME>[0-9]+                            { add_value(attr_name,value_repr,strtol(yytext,NULL,10));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
256 <VALUE_W_NAME>0x[0-9a-f]+                       { add_value(attr_name,value_repr,strtol(yytext,NULL,16));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
258 <INCLUDE>[^[:blank:]\n]+   {
259         if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
260                 g_string_append_printf(error, "$INCLUDE files nested to deeply\n");
261                 yyterminate();
262         }
264         include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
266         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
267             directory,yytext);
269         yyin = ws_fopen( fullpaths[include_stack_ptr], "r" );
271         if (!yyin) {
272                 if (errno) {
273                         g_string_append_printf(error,
274                                         "Could not open file: '%s', error: %s\n",
275                                         fullpaths[include_stack_ptr],
276                                         g_strerror(errno) );
277                 } else {
278                         g_string_append_printf(error,
279                                         "Could not open file: '%s', no errno\n",
280                                         fullpaths[include_stack_ptr]);
281                 }
282                 g_free(fullpaths[include_stack_ptr]);
283                 fullpaths[include_stack_ptr] = NULL;
284                 include_stack_ptr--;
285         } else {
286                 linenums[include_stack_ptr] = 1;
287                 yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
288         }
291         BEGIN WS_OUT;
294 <<EOF>> {
296         fclose(yyin);
297         yyin = NULL;
299         if ( --include_stack_ptr < 0 ) {
300                 yyterminate();
301         } else {
302                 g_free(fullpaths[include_stack_ptr+1]);
303                 fullpaths[include_stack_ptr+1] = NULL;
305                 yy_delete_buffer( YY_CURRENT_BUFFER );
306                 yy_switch_to_buffer(include_stack[include_stack_ptr]);
307         }
309         BEGIN WS_OUT;
312 \n      { linenums[include_stack_ptr]++; BEGIN WS_OUT; }
317 static void add_vendor(const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags) {
318         radius_vendor_info_t* v;
320         v = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(id));
322         if (!v) {
323                 v = g_new(radius_vendor_info_t,1);
324                 v->attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
325                 v->code = id;
326                 v->ett = -1;
327                 v->name = NULL;
328         }
329         /* Assume that the dictionary knows the 'ground truth' about the
330          * type/length/has_flags information and thus allow the dictionary to
331          * overwrite these values even for vendors that have already been loaded.
332          */
333         v->type_octets = type_octets;
334         v->length_octets = length_octets;
335         v->has_flags = has_flags;
337         if (v->name)
338                 g_free((gpointer) v->name);
339         v->name = g_strdup(name);
341         g_hash_table_insert(dict->vendors_by_id,GUINT_TO_POINTER(v->code),v);
342         g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
345 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) {
346         radius_attr_info_t* a;
347         GHashTable* by_id;
348         guint32 code;
349         const gchar *tmpName = NULL;
352         if (attr){
353                 add_tlv(name, codestr, type, attr);
354                 return;
355         }
358         if (vendor) {
359                 radius_vendor_info_t* v;
360                 v = (radius_vendor_info_t *)g_hash_table_lookup(dict->vendors_by_name,vendor);
362                 if (! v) {
363                         g_string_append_printf(error, "Vendor: '%s', does not exist in %s:%i \n", vendor, fullpaths[include_stack_ptr], linenums[include_stack_ptr] );
364                         BEGIN JUNK;
365                         return;
366                 } else {
367                         by_id = v->attrs_by_id;
368                 }
369         } else {
370                 by_id = dict->attrs_by_id;
371         }
373         code=strtol(codestr, NULL, 10);
375         a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
377         if (!a) {
378                 a = g_new(radius_attr_info_t,1);
379                 a->name = NULL;
380                 a->dissector = NULL;
381         }
383         a->code = code;
384         a->encrypt = encrypted_flag;
385         a->tagged =  tagged;
386         a->type = type;
387         a->vs = NULL;
388         a->hf = -1;
389         a->hf_alt = -1;
390         a->hf_tag = -1;
391         a->hf_len = -1;
392         a->ett = -1;
393         a->tlvs_by_id = NULL;
395         if (a->name) {
396                 tmpName = a->name;
397         }
398         a->name = g_strdup(name);
400         g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
401         g_hash_table_insert(dict->attrs_by_name,(gpointer) (a->name),a);
403         /* Don't free the old name until after the hash_table ops, since it
404            seems to end up being used in there somewhere, causing valgrind
405            errors. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7803 */
406         if (tmpName) {
407                 g_free((gpointer) tmpName);
408         }
411 static void add_tlv(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const gchar* attr) {
412         radius_attr_info_t* a;
413         radius_attr_info_t* s;
414         guint32 code;
416         a = (radius_attr_info_t*)g_hash_table_lookup(dict->attrs_by_name, attr);
418         if (! a) {
419                 g_string_append_printf(error, "Attr: '%s', does not exist in %s:%i \n", attr, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
420                 BEGIN JUNK;
421                 return;
422         }
424         if (type == radius_tlv) {
425                 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]);
426                 BEGIN JUNK;
427                 return;
428         }
431         if (! a->tlvs_by_id) {
432                 a->tlvs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
433         }
435         code=strtol(codestr, NULL, 10);
437         s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
439         if (!s) {
440                 s = g_new(radius_attr_info_t,1);
441                 s->name = NULL;
442                 s->dissector = NULL;
443         }
445         s->code = code;
446         s->type = type;
447         s->encrypt = FALSE;
448         s->tagged = FALSE;
449         s->dissector = NULL;
450         s->vs = NULL;
451         s->hf = -1;
452         s->hf_alt = -1;
453         s->hf_tag = -1;
454         s->hf_len = -1;
455         s->ett = -1;
456         s->tlvs_by_id = NULL;
458         if (s->name)
459                 g_free((gpointer) s->name);
460         s->name = g_strdup(name);
462         g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
463         g_hash_table_insert(dict->tlvs_by_name,(gpointer) (s->name),s);
466 void add_value(const gchar* attrib_name, const gchar* repr, long value) {
467         value_string v;
468         GArray* a = (GArray*)g_hash_table_lookup(value_strings,attrib_name);
470         if (! a) {
471                 a = g_array_new(TRUE,TRUE,sizeof(value_string));
472                 g_hash_table_insert(value_strings,g_strdup(attrib_name),a);
473         }
475         v.value = value;
476         v.strptr = g_strdup(repr);
478         g_array_append_val(a,v);
481 static void setup_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
482         radius_attr_info_t* s = (radius_attr_info_t*)v;
483         gpointer key;
485         union {
486                 GArray* a;
487                 gpointer p;
488         } vs;
490         if (g_hash_table_lookup_extended(value_strings, s->name, &key, &vs.p)) {
491                 s->vs = (value_string*)(void *)vs.a->data;
492                 g_array_free(vs.a, FALSE);
493                 g_hash_table_remove(value_strings, key);
494                 g_free(key);
495         }
498 static void setup_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
499         radius_attr_info_t* a = (radius_attr_info_t*)v;
500         gpointer key;
502         union {
503                 GArray* a;
504                 gpointer p;
505         } vs;
507         if (g_hash_table_lookup_extended(value_strings,a->name,&key,&vs.p) ) {
508                 a->vs = (value_string*)(void *)vs.a->data;
509                 g_array_free(vs.a,FALSE);
510                 g_hash_table_remove(value_strings,key);
511                 g_free(key);
512         }
514         if (a->tlvs_by_id) {
515                 g_hash_table_foreach(a->tlvs_by_id, setup_tlvs, p);
516         }
519 static void setup_vendors(gpointer k _U_, gpointer v, gpointer p) {
520         radius_vendor_info_t* vnd = (radius_vendor_info_t*)v;
522         g_hash_table_foreach(vnd->attrs_by_id,setup_attrs,p);
525 static gboolean destroy_value_strings(gpointer k, gpointer v, gpointer p _U_) {
526         value_string* vs = (value_string*)(void *)(((GArray*)v)->data);
528         g_free(k);
530         for (;vs->strptr;vs++) {
531                 g_free((void*)vs->strptr);
532         }
534         g_array_free((GArray*)v,TRUE);
535         return TRUE;
538 gboolean radius_load_dictionary (radius_dictionary_t* d, gchar* dir, const gchar* filename, gchar** err_str) {
539         int i;
541         dict = d;
542         directory = dir;
544         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
545             directory,filename);
547         error = g_string_new("");
549         yyin = ws_fopen(fullpaths[include_stack_ptr],"r");
551         if (!yyin) {
552                 g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], g_strerror(errno) );
553                 g_free(fullpaths[include_stack_ptr]);
554                 *err_str = error->str;
555                 g_string_free(error,FALSE);
556                 return FALSE;
557         }
559         value_strings = g_hash_table_new(g_str_hash,g_str_equal);
561         BEGIN WS_OUT;
563         yylex();
565         if (yyin != NULL) fclose(yyin);
566         yyin = NULL;
568         for (i=0; i < 10; i++) {
569                 if (fullpaths[i]) g_free(fullpaths[i]);
570         }
572         g_hash_table_foreach(dict->attrs_by_id,setup_attrs,NULL);
573         g_hash_table_foreach(dict->vendors_by_id,setup_vendors,NULL);
574         g_hash_table_foreach_remove(value_strings,destroy_value_strings,NULL);
576         if (error->len > 0) {
577                 *err_str = error->str;
578                 g_string_free(error,FALSE);
579                 return FALSE;
580         } else {
581                 *err_str = NULL;
582                 g_string_free(error,TRUE);
583                 return TRUE;
584         }
588  * We want to stop processing when we get to the end of the input.
589  * (%option noyywrap is not used because if used then
590  * some flex versions (eg: 2.5.35) generate code which causes
591  * warnings by the Windows VC compiler).
592  */
594 int yywrap(void) {
595     return 1;
599  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
601  * Local variables:
602  * c-basic-offset: 8
603  * tab-width: 8
604  * indent-tabs-mode: t
605  * End:
607  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
608  * :indentSize=8:tabSize=8:noTabs=false:
609  */