2 * We don't use unput, so don't generate code for it.
7 * We don't read from the terminal.
9 %option never-interactive
12 * The language we're scanning is case-insensitive.
17 * Prefix scanner routines with "Radius" rather than "yy", so this scanner
18 * can coexist with other scanners.
20 %option prefix="Radius"
22 %option outfile="radius_dict.c"
27 * RADIUS dictionary parser
31 * Wireshark - Network traffic analyzer
32 * By Gerald Combs <gerald@wireshark.org>
33 * Copyright 1998 Gerald Combs
35 * This program is free software; you can redistribute it and/or
36 * modify it under the terms of the GNU General Public License
37 * as published by the Free Software Foundation; either version 2
38 * of the License, or (at your option) any later version.
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Public License for more details.
45 * You should have received a copy of the GNU General Public License
46 * along with this program; if not, write to the Free Software
47 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
59 #include <epan/packet.h>
60 #include <epan/dissectors/packet-radius.h>
61 #include "radius_dict_lex.h"
62 #include <wsutil/file_util.h>
65 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated */
66 /* with YY_INPUT code generated by flex versions such as 2.5.35. */
67 #pragma warning (disable:4018)
71 #define MAX_INCLUDE_DEPTH 10
73 void add_vendor(const gchar* name, guint32 vendor_id, guint vendor_type_octets, guint vendor_length_octets, gboolean vendor_has_flags);
74 void add_value(const gchar* attrib_name,const gchar* value_repr, long value);
75 void add_tlv(const gchar* name, const gchar* code, radius_attr_dissector_t type, const gchar* current_attr);
76 void add_attribute(const gchar*,const gchar*, radius_attr_dissector_t,const gchar*, gboolean, gboolean, const gchar*);
78 static YY_BUFFER_STATE include_stack[10];
79 static int include_stack_ptr = 0;
81 static radius_dictionary_t* dict = NULL;
82 static GHashTable* value_strings = NULL; /* GArray(value_string) by attribute name */
84 static gchar* attr_name = NULL;
85 static gchar* attr_id = NULL;
86 static radius_attr_dissector_t* attr_type = NULL;
87 static gchar* attr_vendor = NULL;
88 static gchar* vendor_name = NULL;
89 static guint32 vendor_id = 0;
90 static guint vendor_type_octets = 1;
91 static guint vendor_length_octets = 1;
92 static gboolean vendor_has_flags = FALSE;
93 static gchar* value_repr = NULL;
94 static gboolean encrypted = FALSE;
95 static gboolean has_tag = FALSE;
96 static gchar* current_vendor = NULL;
97 static gchar* current_attr = NULL;
99 static GString* error = NULL;
100 static gchar* directory = NULL;
101 static int linenums[] = {1,1,1,1,1,1,1,1,1,1};
102 static gchar* fullpaths[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
106 %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
113 <WS_OUT>VENDOR { BEGIN VENDOR; }
114 <WS_OUT>ATTRIBUTE { BEGIN ATTR; }
115 <WS_OUT>VALUE { BEGIN VALUE; }
116 <WS_OUT>\$INCLUDE { BEGIN INCLUDE; }
117 <WS_OUT>BEGIN-VENDOR { BEGIN BEGIN_VENDOR; }
118 <WS_OUT>END-VENDOR { BEGIN END_VENDOR; }
119 <WS_OUT>BEGIN-TLV { BEGIN BEGIN_TLV; }
120 <WS_OUT>END-TLV { BEGIN END_TLV; }
122 <BEGIN_VENDOR>[0-9a-z_-]+ {
123 if (current_vendor) {
124 g_free(current_vendor);
126 current_vendor = g_strdup(yytext);
130 if (current_vendor) {
131 g_free(current_vendor);
132 current_vendor = NULL;
137 <BEGIN_TLV>[0-9a-z_-]+ {
139 g_free(current_attr);
141 current_attr = g_strdup(yytext);
146 g_free(current_attr);
152 <VENDOR>[0-9a-z_-]+ {
153 vendor_name = g_strdup(yytext);
154 vendor_type_octets = 1;
155 vendor_length_octets = 1;
156 vendor_has_flags = FALSE;
159 <VENDOR_W_NAME>[0-9]+ {
160 vendor_id = strtol(yytext,NULL,10);
163 <VENDOR_W_NAME>0x[0-9a-f]+ {
164 vendor_id = strtol(yytext,NULL,16);
167 <VENDOR_W_ID>format= {
168 BEGIN VENDOR_W_FORMAT;
170 <VENDOR_W_FORMAT>[124] {
171 vendor_type_octets = strtol(yytext,NULL,10);
172 BEGIN VENDOR_W_TYPE_OCTETS;
174 <VENDOR_W_TYPE_OCTETS>,[012] {
175 vendor_length_octets = strtol(yytext+1,NULL,10);
176 BEGIN VENDOR_W_LENGTH_OCTETS;
178 <VENDOR_W_LENGTH_OCTETS>,c {
179 vendor_has_flags = TRUE;
180 BEGIN VENDOR_W_CONTINUATION;
182 <VENDOR_W_FORMAT>\n |
183 <VENDOR_W_TYPE_OCTETS>\n |
184 <VENDOR_W_LENGTH_OCTETS>\n |
185 <VENDOR_W_CONTINUATION>\n |
187 add_vendor(vendor_name, vendor_id, vendor_type_octets, vendor_length_octets, vendor_has_flags);
192 <ATTR>[0-9a-z_/-]+ { attr_name = g_strdup(yytext); encrypted = FALSE; has_tag = FALSE; BEGIN ATTR_W_NAME; }
193 <ATTR_W_NAME>[0-9]+ { attr_id = g_strdup(yytext); BEGIN ATTR_W_ID;}
194 <ATTR_W_NAME>0x[0-9a-f]+ { attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
195 <ATTR_W_ID>integer { attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
196 <ATTR_W_ID>string { attr_type = radius_string; BEGIN ATTR_W_TYPE; }
197 <ATTR_W_ID>octets { attr_type = radius_octets; BEGIN ATTR_W_TYPE; }
198 <ATTR_W_ID>ipaddr { attr_type = radius_ipaddr; BEGIN ATTR_W_TYPE; }
199 <ATTR_W_ID>ipv6addr { attr_type = radius_ipv6addr; BEGIN ATTR_W_TYPE; }
200 <ATTR_W_ID>ipv6prefix { attr_type = radius_ipv6prefix; BEGIN ATTR_W_TYPE; }
201 <ATTR_W_ID>ipxnet { attr_type = radius_ipxnet; BEGIN ATTR_W_TYPE; }
202 <ATTR_W_ID>date { attr_type = radius_date; BEGIN ATTR_W_TYPE; }
203 <ATTR_W_ID>abinary { attr_type = radius_abinary; BEGIN ATTR_W_TYPE; }
204 <ATTR_W_ID>ether { attr_type = radius_ether; BEGIN ATTR_W_TYPE; }
205 <ATTR_W_ID>ifid { attr_type = radius_ifid; BEGIN ATTR_W_TYPE; }
206 <ATTR_W_ID>byte { attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
207 <ATTR_W_ID>short { attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
208 <ATTR_W_ID>signed { attr_type = radius_signed; BEGIN ATTR_W_TYPE; }
209 <ATTR_W_ID>combo-ip { attr_type = radius_combo_ip; BEGIN ATTR_W_TYPE; }
210 <ATTR_W_ID>tlv { attr_type = radius_tlv; BEGIN ATTR_W_TYPE; }
211 <ATTR_W_ID>[0-9a-z_-]+ { attr_type = radius_octets; BEGIN ATTR_W_TYPE; }
212 <ATTR_W_TYPE>has_tag[,]? { has_tag = TRUE; }
213 <ATTR_W_TYPE>encrypt=1[,]? { encrypted=TRUE; }
214 <ATTR_W_TYPE>[0-9a-z_-]+=([^\n]*) ;
215 <ATTR_W_TYPE>[0-9a-z_-]+ {
216 attr_vendor = g_strdup(yytext);
217 add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
227 add_attribute(attr_name,attr_id,attr_type,current_vendor,encrypted,has_tag,current_attr);
230 linenums[include_stack_ptr]++;
236 add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
240 linenums[include_stack_ptr]++;
244 <VALUE>[0-9a-z_/-]+ { attr_name = g_strdup(yytext); BEGIN VALUE_W_ATTR; }
245 <VALUE_W_ATTR>[^[:blank:]]+ { value_repr = g_strdup(yytext); BEGIN VALUE_W_NAME; }
246 <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;}
247 <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;}
249 <INCLUDE>[^[:blank:]\n]+ {
250 if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
251 g_string_append_printf(error, "$INCLUDE files nested to deeply\n");
255 include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
257 fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
260 yyin = ws_fopen( fullpaths[include_stack_ptr], "r" );
264 g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], strerror(errno) );
268 linenums[include_stack_ptr] = 1;
269 yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
281 if ( --include_stack_ptr < 0 ) {
284 g_free(fullpaths[include_stack_ptr+1]);
285 fullpaths[include_stack_ptr+1] = NULL;
287 yy_delete_buffer( YY_CURRENT_BUFFER );
288 yy_switch_to_buffer(include_stack[include_stack_ptr]);
294 \n { linenums[include_stack_ptr]++; BEGIN WS_OUT; }
299 void add_vendor(const gchar* name, guint32 vendor_id, guint vendor_type_octets, guint vendor_length_octets, gboolean vendor_has_flags) {
300 radius_vendor_info_t* v;
302 v = g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(vendor_id));
305 v = g_malloc(sizeof(radius_vendor_info_t));
306 v->attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
311 /* Assume that the dictionary knows the 'ground truth' about the
312 * type/length/has_flags information and thus allow the dictionary to
313 * overwrite these values even for vendors that have already been loaded.
315 v->type_octets = vendor_type_octets;
316 v->length_octets = vendor_length_octets;
317 v->has_flags = vendor_has_flags;
320 g_free((gpointer) v->name);
321 v->name = g_strdup(name);
323 g_hash_table_insert(dict->vendors_by_id,GUINT_TO_POINTER(v->code),v);
324 g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
327 void add_attribute(const gchar* name, const gchar* codestr, radius_attr_dissector_t type, const gchar* vendor_name, gboolean crypt, gboolean tagged, const gchar* current_attr) {
328 radius_attr_info_t* a;
334 add_tlv(name, codestr, type, current_attr);
340 radius_vendor_info_t* v;
341 v = g_hash_table_lookup(dict->vendors_by_name,vendor_name);
344 g_string_append_printf(error, "Vendor: '%s', does not exist in %s:%i \n", vendor_name, fullpaths[include_stack_ptr], linenums[include_stack_ptr] );
348 by_id = v->attrs_by_id;
351 by_id = dict->attrs_by_id;
354 code=strtol(codestr, NULL, 10);
356 a=g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
359 a = g_malloc(sizeof(radius_attr_info_t));
374 a->tlvs_by_id = NULL;
377 g_free((gpointer) a->name);
378 a->name = g_strdup(name);
380 g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
381 g_hash_table_insert(dict->attrs_by_name,(gpointer) (a->name),a);
384 void add_tlv(const gchar* name, const gchar* codestr, radius_attr_dissector_t type, const gchar* current_attr) {
385 radius_attr_info_t* a;
386 radius_attr_info_t* s = g_malloc(sizeof(radius_attr_info_t));
389 a = g_hash_table_lookup(dict->attrs_by_name, current_attr);
392 g_string_sprintfa(error, "Attr: '%s', does not exist in %s:%i \n", current_attr, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
397 if (type == radius_tlv) {
398 g_string_sprintfa(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]);
404 if (! a->tlvs_by_id) {
405 a->tlvs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
408 code=strtol(codestr, NULL, 10);
410 s = g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
413 s = g_malloc(sizeof(radius_attr_info_t));
429 s->tlvs_by_id = NULL;
432 g_free((gpointer) s->name);
433 s->name = g_strdup(name);
435 g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
436 g_hash_table_insert(dict->tlvs_by_name,(gpointer) (s->name),s);
439 void add_value(const gchar* attrib_name, const gchar* value_repr, long value) {
441 GArray* a = g_hash_table_lookup(value_strings,attrib_name);
444 a = g_array_new(TRUE,TRUE,sizeof(value_string));
445 g_hash_table_insert(value_strings,g_strdup(attrib_name),a);
449 v.strptr = g_strdup(value_repr);
451 g_array_append_val(a,v);
454 static void setup_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
455 radius_attr_info_t* s = v;
463 if (g_hash_table_lookup_extended(value_strings, s->name, &key, &vs.p)) {
464 s->vs = (value_string*) vs.a->data;
465 g_array_free(vs.a, FALSE);
466 g_hash_table_remove(value_strings, key);
471 static void setup_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
472 radius_attr_info_t* a = v;
480 if (g_hash_table_lookup_extended(value_strings,a->name,&key,&vs.p) ) {
481 a->vs = (value_string*) vs.a->data;
482 g_array_free(vs.a,FALSE);
483 g_hash_table_remove(value_strings,key);
488 g_hash_table_foreach(a->tlvs_by_id, setup_tlvs, p);
492 static void setup_vendors(gpointer k _U_, gpointer v, gpointer p) {
493 radius_vendor_info_t* vnd = v;
495 g_hash_table_foreach(vnd->attrs_by_id,setup_attrs,p);
498 static gboolean destroy_value_strings(gpointer k, gpointer v, gpointer p _U_) {
499 value_string* vs = (value_string*)(((GArray*)v)->data);
503 for (;vs->strptr;vs++) {
504 g_free((void*)vs->strptr);
507 g_array_free(v,TRUE);
511 static gboolean destroy_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
512 radius_attr_info_t* s = v;
515 g_free((gpointer) (s->name));
518 for(i=0; s->vs[i].strptr; i++) {
519 g_free((void *)s->vs[i].strptr);
521 g_free((void *)s->vs);
527 static gboolean destroy_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
528 radius_attr_info_t* a = v;
531 g_free((gpointer) (a->name));
533 g_hash_table_foreach_remove(a->tlvs_by_id, destroy_tlvs, p);
534 g_hash_table_destroy(a->tlvs_by_id);
538 for(i=0; a->vs[i].strptr; i++) {
539 g_free((void *)a->vs[i].strptr);
541 g_free((void *)a->vs);
547 static gboolean destroy_vendors(gpointer k _U_, gpointer v, gpointer p) {
548 radius_vendor_info_t* vnd = v;
549 g_free( (gpointer) vnd->name);
550 g_hash_table_foreach_remove(vnd->attrs_by_id,destroy_attrs,p);
551 g_hash_table_destroy(vnd->attrs_by_id);
556 static void destroy_dict(radius_dictionary_t* d) {
557 g_hash_table_foreach_remove(d->attrs_by_id,destroy_attrs,NULL);
558 g_hash_table_foreach_remove(d->vendors_by_id,destroy_vendors,NULL);
559 g_hash_table_destroy(d->vendors_by_id);
560 g_hash_table_destroy(d->attrs_by_id);
561 g_hash_table_destroy(d->vendors_by_name);
562 g_hash_table_destroy(d->attrs_by_name);
566 gboolean radius_load_dictionary (radius_dictionary_t* d, gchar* dir, const gchar* filename, gchar** err_str) {
572 fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
575 error = g_string_new("");
577 yyin = ws_fopen(fullpaths[include_stack_ptr],"r");
580 g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], strerror(errno) );
581 g_free(fullpaths[include_stack_ptr]);
582 *err_str = error->str;
583 g_string_free(error,FALSE);
587 value_strings = g_hash_table_new(g_str_hash,g_str_equal);
593 if (yyin != NULL) fclose(yyin);
596 for (i=0; i < 10; i++) {
597 if (fullpaths[i]) g_free(fullpaths[i]);
600 g_hash_table_foreach(dict->attrs_by_id,setup_attrs,NULL);
601 g_hash_table_foreach(dict->vendors_by_id,setup_vendors,NULL);
602 g_hash_table_foreach_remove(value_strings,destroy_value_strings,NULL);
604 if (error->len > 0) {
605 *err_str = error->str;
606 g_string_free(error,FALSE);
611 g_string_free(error,TRUE);
617 * We want to stop processing when we get to the end of the input.
618 * (%option noyywrap is not used because if used then
619 * some flex versions (eg: 2.5.35) generate code which causes
620 * warnings by the Windows VC compiler).