wireshark/epan/radius_dict.l
Guy Harris 6f37317539 Include config.h at the very beginning of all Flex scanners.
That way, if we #define anything for large file support, that's done
before we include any system header files that either depend on that
definition or that define it themselves if it's not already defined.

Change-Id: I9b07344151103be337899dead44d6960715d6813
Reviewed-on: https://code.wireshark.org/review/19035
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2016-12-02 21:02:10 +00:00

750 lines
23 KiB
Text

%top {
/* Include this before everything else, for various large-file definitions */
#include "config.h"
}
/*
* We want a reentrant scanner.
*/
%option reentrant
/*
* We don't use input, so don't generate code for it.
*/
%option noinput
/*
* We don't use unput, so don't generate code for it.
*/
%option nounput
/*
* We don't read interactively from the terminal.
*/
%option never-interactive
/*
* We want to stop processing when we get to the end of the input.
*/
%option noyywrap
/*
* The language we're scanning is case-insensitive.
*/
%option caseless
/*
* The type for the state we keep for a scanner.
*/
%option extra-type="Radius_scanner_state_t*"
/*
* We have to override the memory allocators so that we don't get
* "unused argument" warnings from the yyscanner argument (which
* we don't use, as we have a global memory allocator).
*
* We provide, as macros, our own versions of the routines generated by Flex,
* which just call malloc()/realloc()/free() (as the Flex versions do),
* discarding the extra argument.
*/
%option noyyalloc
%option noyyrealloc
%option noyyfree
/*
* Prefix scanner routines with "Radius_" rather than "yy", so this scanner
* can coexist with other scanners.
*/
%option prefix="Radius_"
%option outfile="radius_dict.c"
%{
/* radius_dict.l
*
* RADIUS dictionary parser
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <epan/packet.h>
#include <epan/dissectors/packet-radius.h>
#include <wsutil/file_util.h>
#define YY_USER_INIT BEGIN WS_OUT;
#ifdef _WIN32
/* disable Windows VC compiler warning "signed/unsigned mismatch" associated */
/* with YY_INPUT code generated by flex versions such as 2.5.35. */
#pragma warning (disable:4018)
#endif
#define ECHO
#define MAX_INCLUDE_DEPTH 10
typedef struct {
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr;
radius_dictionary_t* dict;
GHashTable* value_strings; /* GArray(value_string) by attribute name */
gchar* attr_name;
gchar* attr_id;
radius_attr_dissector_t* attr_type;
gchar* attr_vendor;
gchar* vendor_name;
guint32 vendor_id;
guint vendor_type_octets;
guint vendor_length_octets;
gboolean vendor_has_flags;
gchar* value_repr;
guint encrypted;
gboolean has_tag;
gchar* current_vendor;
gchar* current_attr;
gchar* directory;
gchar* fullpaths[MAX_INCLUDE_DEPTH];
int linenums[MAX_INCLUDE_DEPTH];
GString* error;
} Radius_scanner_state_t;
static void add_vendor(Radius_scanner_state_t* state, const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags);
static gboolean add_attribute(Radius_scanner_state_t* state, const gchar*,const gchar*, radius_attr_dissector_t,const gchar*, guint, gboolean, const gchar*);
static gboolean add_tlv(Radius_scanner_state_t* state, const gchar* name, const gchar* code, radius_attr_dissector_t type, const gchar* attr);
static void add_value(Radius_scanner_state_t* state, const gchar* attrib_name, const gchar* repr, guint32 value);
/*
* Sleazy hack to suppress compiler warnings in yy_fatal_error().
*/
#define YY_EXIT_FAILURE ((void)yyscanner, 2)
/*
* Macros for the allocators, to discard the extra argument.
*/
#define Radius_alloc(size, yyscanner) (void *)malloc(size)
#define Radius_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size))
#define Radius_free(ptr, yyscanner) free((char *)ptr)
%}
/* Note: FreeRadius allows VENDOR, ATTRIBUTE and VALUE names to contain any non-blank character.
* Using a negated "blank character class" pattern below for those names fails for some reason
* so for now the patterns for each name type include those characters found for the corresponding
* name types in the FreeRadius dictionaries.
*/
%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
%%
[:blank:] ;
#[^\n]* ;
<JUNK>.*\qn ;
<WS_OUT>VENDOR { BEGIN VENDOR; }
<WS_OUT>ATTRIBUTE { BEGIN ATTR; }
<WS_OUT>VALUE { BEGIN VALUE; }
<WS_OUT>\$INCLUDE { BEGIN INCLUDE; }
<WS_OUT>BEGIN-VENDOR { BEGIN BEGIN_VENDOR; }
<WS_OUT>END-VENDOR { BEGIN END_VENDOR; }
<WS_OUT>BEGIN-TLV { BEGIN BEGIN_TLV; }
<WS_OUT>END-TLV { BEGIN END_TLV; }
<BEGIN_VENDOR>[0-9a-z_-]+ {
if (yyextra->current_vendor) {
g_free(yyextra->current_vendor);
}
yyextra->current_vendor = g_strdup(yytext);
BEGIN WS_OUT;
}
<END_VENDOR>[^\n]* {
if (yyextra->current_vendor) {
g_free(yyextra->current_vendor);
yyextra->current_vendor = NULL;
}
BEGIN WS_OUT;
}
<BEGIN_TLV>[0-9a-z_-]+ {
if (yyextra->current_attr) {
g_free(yyextra->current_attr);
}
yyextra->current_attr = g_strdup(yytext);
BEGIN WS_OUT;
}
<END_TLV>[^\n]* {
if (yyextra->current_attr) {
g_free(yyextra->current_attr);
yyextra->current_attr = NULL;
}
BEGIN WS_OUT;
}
<VENDOR>[0-9a-z_-]+ {
yyextra->vendor_name = g_strdup(yytext);
yyextra->vendor_type_octets = 1;
yyextra->vendor_length_octets = 1;
yyextra->vendor_has_flags = FALSE;
BEGIN VENDOR_W_NAME;
}
<VENDOR_W_NAME>[0-9]+ {
yyextra->vendor_id = (guint32) strtoul(yytext,NULL,10);
BEGIN VENDOR_W_ID;
}
<VENDOR_W_NAME>0x[0-9a-f]+ {
yyextra->vendor_id = (guint32) strtoul(yytext,NULL,16);
BEGIN VENDOR_W_ID;
}
<VENDOR_W_ID>format= {
BEGIN VENDOR_W_FORMAT;
}
<VENDOR_W_FORMAT>[124] {
yyextra->vendor_type_octets = (guint) strtoul(yytext,NULL,10);
BEGIN VENDOR_W_TYPE_OCTETS;
}
<VENDOR_W_TYPE_OCTETS>,[012] {
yyextra->vendor_length_octets = (guint) strtoul(yytext+1,NULL,10);
BEGIN VENDOR_W_LENGTH_OCTETS;
}
<VENDOR_W_LENGTH_OCTETS>,c {
yyextra->vendor_has_flags = TRUE;
BEGIN VENDOR_W_CONTINUATION;
}
<VENDOR_W_FORMAT>\n |
<VENDOR_W_TYPE_OCTETS>\n |
<VENDOR_W_LENGTH_OCTETS>\n |
<VENDOR_W_CONTINUATION>\n |
<VENDOR_W_ID>\n {
add_vendor(yyextra, yyextra->vendor_name, yyextra->vendor_id, yyextra->vendor_type_octets, yyextra->vendor_length_octets, yyextra->vendor_has_flags);
g_free(yyextra->vendor_name);
BEGIN WS_OUT;
}
<ATTR>[0-9a-z_/.-]+ { yyextra->attr_name = g_strdup(yytext); yyextra->encrypted = 0; yyextra->has_tag = FALSE; BEGIN ATTR_W_NAME; }
<ATTR_W_NAME>[0-9]+ { yyextra->attr_id = g_strdup(yytext); BEGIN ATTR_W_ID;}
<ATTR_W_NAME>0x[0-9a-f]+ { yyextra->attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
<ATTR_W_ID>integer { yyextra->attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>string { yyextra->attr_type = radius_string; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>octets { yyextra->attr_type = radius_octets; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>ipaddr { yyextra->attr_type = radius_ipaddr; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>ipv6addr { yyextra->attr_type = radius_ipv6addr; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>ipv6prefix { yyextra->attr_type = radius_ipv6prefix; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>ipxnet { yyextra->attr_type = radius_ipxnet; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>date { yyextra->attr_type = radius_date; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>abinary { yyextra->attr_type = radius_abinary; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>ether { yyextra->attr_type = radius_ether; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>ifid { yyextra->attr_type = radius_ifid; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>byte { yyextra->attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>short { yyextra->attr_type = radius_integer; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>signed { yyextra->attr_type = radius_signed; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>combo-ip { yyextra->attr_type = radius_combo_ip; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>tlv { yyextra->attr_type = radius_tlv; BEGIN ATTR_W_TYPE; }
<ATTR_W_ID>[0-9a-z_-]+ { yyextra->attr_type = radius_octets; BEGIN ATTR_W_TYPE; }
<ATTR_W_TYPE>has_tag[,]? { yyextra->has_tag = TRUE; }
<ATTR_W_TYPE>encrypt=[123][,]? { yyextra->encrypted = (guint) strtoul(yytext+8,NULL,10); }
<ATTR_W_TYPE>[0-9a-z_-]+=([^\n]*) ;
<ATTR_W_TYPE>[0-9a-z_-]+ {
gboolean attribute_ok;
yyextra->attr_vendor = g_strdup(yytext);
attribute_ok = add_attribute(yyextra, yyextra->attr_name, yyextra->attr_id, yyextra->attr_type, yyextra->attr_vendor, yyextra->encrypted, yyextra->has_tag, yyextra->current_attr);
g_free(yyextra->attr_id);
g_free(yyextra->attr_vendor);
g_free(yyextra->attr_name);
yyextra->attr_id = NULL;
yyextra->attr_vendor = NULL;
yyextra->attr_name = NULL;
if (attribute_ok)
BEGIN WS_OUT;
else
BEGIN JUNK;
}
<ATTR_W_TYPE>\n {
add_attribute(yyextra, yyextra->attr_name, yyextra->attr_id, yyextra->attr_type, yyextra->current_vendor, yyextra->encrypted, yyextra->has_tag, yyextra->current_attr);
g_free(yyextra->attr_id);
g_free(yyextra->attr_name);
yyextra->linenums[yyextra->include_stack_ptr]++;
yyextra->has_tag = FALSE;
yyextra->encrypted=FALSE;
BEGIN WS_OUT;
}
<ATTR_W_VENDOR>\n {
add_attribute(yyextra, yyextra->attr_name, yyextra->attr_id, yyextra->attr_type, yyextra->attr_vendor, yyextra->encrypted, yyextra->has_tag, yyextra->current_attr);
g_free(yyextra->attr_id);
g_free(yyextra->attr_vendor);
g_free(yyextra->attr_name);
yyextra->linenums[yyextra->include_stack_ptr]++;
BEGIN WS_OUT;
};
<VALUE>[0-9a-z_/-]+ { yyextra->attr_name = g_strdup(yytext); BEGIN VALUE_W_ATTR; }
<VALUE_W_ATTR>[^[:blank:]]+ { yyextra->value_repr = g_strdup(yytext); BEGIN VALUE_W_NAME; }
<VALUE_W_NAME>[0-9]+ { add_value(yyextra, yyextra->attr_name,yyextra->value_repr, (guint32) strtoul(yytext,NULL,10)); g_free(yyextra->attr_name); g_free(yyextra->value_repr); BEGIN WS_OUT;}
<VALUE_W_NAME>0x[0-9a-f]+ { add_value(yyextra, yyextra->attr_name,yyextra->value_repr, (guint32) strtoul(yytext,NULL,16)); g_free(yyextra->attr_name); g_free(yyextra->value_repr); BEGIN WS_OUT;}
<INCLUDE>[^[:blank:]\n]+ {
if ( yyextra->include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
g_string_append_printf(yyextra->error, "$INCLUDE files nested too deeply\n");
yyterminate();
}
yyextra->include_stack[yyextra->include_stack_ptr++] = YY_CURRENT_BUFFER;
yyextra->fullpaths[yyextra->include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
yyextra->directory,yytext);
yyin = ws_fopen( yyextra->fullpaths[yyextra->include_stack_ptr], "r" );
if (!yyin) {
if (errno) {
g_string_append_printf(yyextra->error,
"Could not open file: '%s', error: %s\n",
yyextra->fullpaths[yyextra->include_stack_ptr],
g_strerror(errno) );
} else {
g_string_append_printf(yyextra->error,
"Could not open file: '%s', no errno\n",
yyextra->fullpaths[yyextra->include_stack_ptr]);
}
g_free(yyextra->fullpaths[yyextra->include_stack_ptr]);
yyextra->fullpaths[yyextra->include_stack_ptr] = NULL;
yyextra->include_stack_ptr--;
} else {
yyextra->linenums[yyextra->include_stack_ptr] = 1;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner), yyscanner);
}
BEGIN WS_OUT;
}
<<EOF>> {
fclose(yyin);
yyin = NULL;
if ( --yyextra->include_stack_ptr < 0 ) {
yyterminate();
} else {
g_free(yyextra->fullpaths[yyextra->include_stack_ptr+1]);
yyextra->fullpaths[yyextra->include_stack_ptr+1] = NULL;
Radius__delete_buffer(YY_CURRENT_BUFFER, yyscanner);
Radius__switch_to_buffer(yyextra->include_stack[yyextra->include_stack_ptr], yyscanner);
}
BEGIN WS_OUT;
}
\n { yyextra->linenums[yyextra->include_stack_ptr]++; BEGIN WS_OUT; }
%%
static void add_vendor(Radius_scanner_state_t* state, const gchar* name, guint32 id, guint type_octets, guint length_octets, gboolean has_flags) {
radius_vendor_info_t* v;
v = (radius_vendor_info_t *)g_hash_table_lookup(state->dict->vendors_by_id, GUINT_TO_POINTER(id));
if (!v) {
/*
* New vendor.
* Allocate a new entry and insert it into the by-ID and
* by-name hash tables.
*/
v = g_new(radius_vendor_info_t,1);
v->attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
v->code = id;
v->ett = -1;
v->name = g_strdup(name);
v->type_octets = type_octets;
v->length_octets = length_octets;
v->has_flags = has_flags;
g_hash_table_insert(state->dict->vendors_by_id,GUINT_TO_POINTER(v->code),v);
g_hash_table_insert(state->dict->vendors_by_name, (gpointer) v->name, v);
} else {
/*
* This vendor is already in the table.
*
* Assume that the dictionary knows the 'ground truth' about
* the type/length/has_flags information and thus allow the
* dictionary to overwrite these values even for vendors that
* have already been loaded.
*
* XXX - this could be due to the vendor being in multiple
* dictionary files, rather than having been specially
* entered by the RADIUS dissector, as a side effect of
* specially entering an attribute; should we report vendors
* that appear in different dictionaries with different
* properties?
*/
v->type_octets = type_octets;
v->length_octets = length_octets;
v->has_flags = has_flags;
/*
* Did the name change?
*/
if (g_strcmp0(v->name, name) != 0) {
/*
* Yes. Remove the entry from the by-name hash table
* and re-insert it with the new name.
*/
g_hash_table_remove(state->dict->vendors_by_name, (gpointer) v->name);
g_free((gpointer) v->name);
v->name = g_strdup(name);
g_hash_table_insert(state->dict->vendors_by_name, (gpointer) v->name, v);
}
}
}
static gboolean add_attribute(Radius_scanner_state_t* state, const gchar* name, const gchar* codestr, radius_attr_dissector_t type, const gchar* vendor, guint encrypted_flag, gboolean tagged, const gchar* attr) {
radius_attr_info_t* a;
GHashTable* by_id;
guint32 code;
if (attr){
return add_tlv(state, name, codestr, type, attr);
}
if (vendor) {
radius_vendor_info_t* v;
v = (radius_vendor_info_t *)g_hash_table_lookup(state->dict->vendors_by_name,vendor);
if (! v) {
g_string_append_printf(state->error, "Vendor: '%s', does not exist in %s:%i \n", vendor, state->fullpaths[state->include_stack_ptr], state->linenums[state->include_stack_ptr] );
return FALSE;
} else {
by_id = v->attrs_by_id;
}
} else {
by_id = state->dict->attrs_by_id;
}
code= (guint32) strtoul(codestr, NULL, 10);
a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
if (!a) {
/*
* New attribute.
* Allocate a new entry and insert it into the by-ID and
* by-name hash tables.
*/
a = g_new(radius_attr_info_t,1);
a->code = code;
a->name = g_strdup(name);
a->dissector = NULL;
a->encrypt = encrypted_flag;
a->tagged = tagged;
a->type = type;
a->vs = NULL;
a->hf = -1;
a->hf_alt = -1;
a->hf_tag = -1;
a->hf_len = -1;
a->ett = -1;
a->tlvs_by_id = NULL;
g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
g_hash_table_insert(state->dict->attrs_by_name,(gpointer) (a->name),a);
} else {
/*
* This attribute is already in the table.
*
* Overwrite the encrypted flag, tagged property, and type;
* the other properties don't get set until after we've
* finished reading the dictionaries.
*
* XXX - this could be due to the attribute being in
* multiple dictionary files, rather than having been
* specially entered by the RADIUS dissector to give it
* a special dissection routine; should we report attributes
* that appear in different dictionaries with different
* properties?
*/
a->encrypt = encrypted_flag;
a->tagged = tagged;
a->type = type;
/*
* Did the name change?
*/
if (g_strcmp0(a->name, name) != 0) {
/*
* Yes. Remove the entry from the by-name hash table
* and re-insert it with the new name.
*/
g_hash_table_remove(state->dict->attrs_by_name, (gpointer) (a->name));
g_free((gpointer) a->name);
a->name = g_strdup(name);
g_hash_table_insert(state->dict->attrs_by_name, (gpointer) (a->name),a);
}
}
return TRUE;
}
static gboolean add_tlv(Radius_scanner_state_t* state, const gchar* name, const gchar* codestr, radius_attr_dissector_t type, const gchar* attr) {
radius_attr_info_t* a;
radius_attr_info_t* s;
guint32 code;
a = (radius_attr_info_t*)g_hash_table_lookup(state->dict->attrs_by_name, attr);
if (! a) {
g_string_append_printf(state->error, "Attr: '%s', does not exist in %s:%i \n", attr, state->fullpaths[state->include_stack_ptr], state->linenums[state->include_stack_ptr]);
return FALSE;
}
if (type == radius_tlv) {
g_string_append_printf(state->error, "sub-TLV: '%s', sub-TLV's type is specified as tlv in %s:%i \n", name, state->fullpaths[state->include_stack_ptr], state->linenums[state->include_stack_ptr]);
return FALSE;
}
if (! a->tlvs_by_id) {
a->tlvs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
}
code = (guint32) strtoul(codestr, NULL, 10);
s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
if (!s) {
/*
* This TLV doesn't yet exist in this attribute's TLVs-by-ID
* hash table. Add it.
*/
s = g_new(radius_attr_info_t,1);
s->name = g_strdup(name);
s->dissector = NULL;
s->code = code;
s->type = type;
s->encrypt = FALSE;
s->tagged = FALSE;
s->dissector = NULL;
s->vs = NULL;
s->hf = -1;
s->hf_alt = -1;
s->hf_tag = -1;
s->hf_len = -1;
s->ett = -1;
s->tlvs_by_id = NULL;
g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
g_hash_table_insert(state->dict->tlvs_by_name,(gpointer) (s->name),s);
}
/*
* If it *does* exist, leave it alone; there shouldn't be duplicate
* entries by name in the dictionaries (even if there might be
* multiple entries for a given attribute in the dictionaries, each
* one adding some TLV values), and we don't directly add entries
* for TLVs in the RADIUS dissector.
*
* XXX - report the duplicate entries?
*/
return TRUE;
}
void add_value(Radius_scanner_state_t* state, const gchar* attrib_name, const gchar* repr, guint32 value) {
value_string v;
GArray* a = (GArray*)g_hash_table_lookup(state->value_strings,attrib_name);
if (! a) {
a = g_array_new(TRUE,TRUE,sizeof(value_string));
g_hash_table_insert(state->value_strings,g_strdup(attrib_name),a);
}
v.value = value;
v.strptr = g_strdup(repr);
g_array_append_val(a,v);
}
static void setup_tlvs(gpointer k _U_, gpointer v, gpointer p) {
radius_attr_info_t* s = (radius_attr_info_t*)v;
Radius_scanner_state_t* state = (Radius_scanner_state_t*)p;
gpointer key;
union {
GArray* a;
gpointer p;
} vs;
if (g_hash_table_lookup_extended(state->value_strings, s->name, &key, &vs.p)) {
s->vs = (value_string*)(void *)vs.a->data;
g_array_free(vs.a, FALSE);
g_hash_table_remove(state->value_strings, key);
g_free(key);
}
}
static void setup_attrs(gpointer k _U_, gpointer v, gpointer p) {
radius_attr_info_t* a = (radius_attr_info_t*)v;
Radius_scanner_state_t* state = (Radius_scanner_state_t*)p;
gpointer key;
union {
GArray* a;
gpointer p;
} vs;
if (g_hash_table_lookup_extended(state->value_strings,a->name,&key,&vs.p) ) {
a->vs = (value_string*)(void *)vs.a->data;
g_array_free(vs.a,FALSE);
g_hash_table_remove(state->value_strings,key);
g_free(key);
}
if (a->tlvs_by_id) {
g_hash_table_foreach(a->tlvs_by_id, setup_tlvs, p);
}
}
static void setup_vendors(gpointer k _U_, gpointer v, gpointer p) {
radius_vendor_info_t* vnd = (radius_vendor_info_t*)v;
g_hash_table_foreach(vnd->attrs_by_id,setup_attrs,p);
}
static gboolean destroy_value_strings(gpointer k, gpointer v, gpointer p _U_) {
value_string* vs = (value_string*)(void *)(((GArray*)v)->data);
g_free(k);
for (;vs->strptr;vs++) {
g_free((void*)vs->strptr);
}
g_array_free((GArray*)v,TRUE);
return TRUE;
}
gboolean radius_load_dictionary (radius_dictionary_t* d, gchar* dir, const gchar* filename, gchar** err_str) {
FILE *in;
yyscan_t scanner;
Radius_scanner_state_t state;
int i;
state.include_stack_ptr = 0;
state.dict = d;
state.value_strings = NULL;
state.attr_name = NULL;
state.attr_id = NULL;
state.attr_type = NULL;
state.attr_vendor = NULL;
state.vendor_name = NULL;
state.vendor_id = 0;
state.vendor_type_octets = 1;
state.vendor_length_octets = 1;
state.vendor_has_flags = FALSE;
state.value_repr = NULL;
state.encrypted = 0;
state.has_tag = FALSE;
state.current_vendor = NULL;
state.current_attr = NULL;
state.directory = dir;
state.fullpaths[0] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
state.directory,filename);
state.linenums[0] = 1;
for (i = 1; i < MAX_INCLUDE_DEPTH; i++) {
state.fullpaths[i] = NULL;
state.linenums[i] = 1;
}
state.error = g_string_new("");
in = ws_fopen(state.fullpaths[0],"r");
if (!in) {
g_string_append_printf(state.error, "Could not open file: '%s', error: %s\n", state.fullpaths[0], g_strerror(errno));
g_free(state.fullpaths[0]);
*err_str = g_string_free(state.error,FALSE);
return FALSE;
}
state.value_strings = g_hash_table_new(g_str_hash,g_str_equal);
if (Radius_lex_init(&scanner) != 0) {
g_string_append_printf(state.error, "Can't initialize scanner: %s",
strerror(errno));
fclose(in);
g_free(state.fullpaths[0]);
*err_str = g_string_free(state.error,FALSE);
return FALSE;
}
Radius_set_in(in, scanner);
/* Associate the state with the scanner */
Radius_set_extra(&state, scanner);
Radius_lex(scanner);
Radius_lex_destroy(scanner);
/*
* XXX - can the lexical analyzer terminate without closing
* all open input files?
*/
for (i = 0; i < MAX_INCLUDE_DEPTH; i++) {
if (state.fullpaths[i])
g_free(state.fullpaths[i]);
}
g_hash_table_foreach(state.dict->attrs_by_id,setup_attrs,&state);
g_hash_table_foreach(state.dict->vendors_by_id,setup_vendors,&state);
g_hash_table_foreach_remove(state.value_strings,destroy_value_strings,NULL);
if (state.error->len > 0) {
*err_str = g_string_free(state.error,FALSE);
return FALSE;
} else {
*err_str = NULL;
g_string_free(state.error,TRUE);
return TRUE;
}
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/