wireshark/epan/radius_dict.l
João Valverde 79c3a77752 Add macros to control lemon diagnostics
Rename flex macros using parenthesis (mostly a style issue):

DIAG_OFF_FLEX -> DIAG_OFF_FLEX()
DIAG_ON_FLEX  -> DIAG_ON_FLEX()

Use the same kind of construct with lemon generated code using
DIAG_OFF_LEMON() and DIAG_ON_LEMON(). Use %include and %code
directives to enforce the desired order with generated code
in the middle in between pragmas.

Fix a clang-specific pragma to use DIAG_OFF_CLANG().

DIAG_OFF(unreachable-code) -> DIAG_OFF_CLANG(unreachable-code).

Apparently GCC is ignoring the -Wunreachable flag, that's why
it did not trigger an unknown pragma warning. From [1}:

  The -Wunreachable-code has been removed, because it was unstable: it
  relied on the optimizer, and so different versions of gcc would warn
  about different code.  The compiler still accepts and ignores the
  command line option so that existing Makefiles are not broken.  In some
  future release the option will be removed entirely. - Ian

[1] https://gcc.gnu.org/legacy-ml/gcc-help/2011-05/msg00360.html
2022-11-20 10:11:27 +00:00

818 lines
25 KiB
Text

%top {
/* Include this before everything else, for various large-file definitions */
#include "config.h"
#include <wireshark.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>
/*
* Disable diagnostics in the code generated by Flex.
*/
DIAG_OFF_FLEX()
/*
* See
*
* http://freeradius.org/radiusd/man/dictionary.html
*
* for the format of RADIUS dictionary files.
*
* XXX - features not currently supported:
*
* integer64, ipv4prefix, combo-prefix, bool, size, decimal,
* timeval, struct, extended, long-extended, vsa, evs, vendor,
* cidr, uint{8,16,32,64}, int{8,16,32,64} as attribute types
* (some of these aren't documented);
*
* octets[N], where N is an integer, as an attribute type
* (not documented in the man page);
*
* internal, array, concat, and virtual as attribute flags (not
* documented in the man page);
*
* We should, perhaps, adopt FreeRADIUS's dictionary-parsing code in
* src/lib/dict.c and use that, rather than writing our own parser.
* See bug 13176.
*/
#define YY_USER_INIT BEGIN WS_OUT;
#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;
guint current_vendor_evs_type;
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 VALUE VALUE_W_ATTR VALUE_W_NAME INCLUDE JUNK BEGIN_VENDOR BEGIN_VENDOR_FORMAT 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 BEGIN_VENDOR_FORMAT;
}
<BEGIN_VENDOR_FORMAT>format=Extended-Vendor-Specific-[123456] {
if (strcmp(yytext, "format=Extended-Vendor-Specific-1") == 0) {
yyextra->current_vendor_evs_type = 241;
} else if(strcmp(yytext, "format=Extended-Vendor-Specific-2") == 0) {
yyextra->current_vendor_evs_type = 242;
} else if(strcmp(yytext, "format=Extended-Vendor-Specific-3") == 0) {
yyextra->current_vendor_evs_type = 243;
} else if(strcmp(yytext, "format=Extended-Vendor-Specific-4") == 0) {
yyextra->current_vendor_evs_type = 244;
} else if(strcmp(yytext, "format=Extended-Vendor-Specific-5") == 0) {
yyextra->current_vendor_evs_type = 245;
} else if(strcmp(yytext, "format=Extended-Vendor-Specific-6") == 0) {
yyextra->current_vendor_evs_type = 246;
}
BEGIN WS_OUT;
}
<BEGIN_VENDOR_FORMAT>\n {BEGIN WS_OUT;}
<END_VENDOR>[^\n]* {
if (yyextra->current_vendor) {
g_free(yyextra->current_vendor);
yyextra->current_vendor = NULL;
}
yyextra->current_vendor_evs_type = 0;
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 = ws_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_-]+ {
/*
* Support for "ATTRIBUTE name oid type vendor", where the token
* following the type matches neither has_tag nor encrypt={1,2,3},
* but is a sequence of digits, lower-case letters, underscores,
* and hyphens.
*
* We mark this as a vendor-specific attribute (VSA), with the token
* following the type being the vendor name; this notation is deprecated
* in favor of BEGIN-VENDOR/END-VENDOR blocks.
*/
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;
}
<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] = ws_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; }
%%
/*
* Turn diagnostics back on, so we check the code that we've written.
*/
DIAG_ON_FLEX()
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_full(g_direct_hash, g_direct_equal, NULL, free_radius_attr_info);
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;
radius_attr_type_t code;
guint8 code0 = 0, code1 = 0;
gchar *dot, *buf = NULL;
if (attr){
return add_tlv(state, name, codestr, type, attr);
}
buf = g_strdup(codestr);
dot = strchr(codestr, '.');
if (dot)
*dot = '\0';
code0 = (guint8) strtoul(buf, NULL, 10);
if (dot)
code1 = (guint8) strtoul(dot + 1, NULL, 10);
g_free(buf);
memset(&code, 0, sizeof(code));
if (vendor) {
if (state->current_vendor_evs_type) {
code.u8_code[0] = (guint8) state->current_vendor_evs_type;
code.u8_code[1] = code0;
} else {
code.u8_code[0] = code0;
code.u8_code[1] = 0;
}
radius_vendor_info_t* 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 {
code.u8_code[0] = code0;
code.u8_code[1] = code1;
by_id = state->dict->attrs_by_id;
}
a=(radius_attr_info_t*)g_hash_table_lookup(by_id, GUINT_TO_POINTER(code.value));
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.value),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. Steal the entry from the by-name hash table
* and re-insert it with the new name. (Don't
* remove it - that calls the free routine, which
* frees up the entry.)
*/
g_hash_table_steal(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;
radius_attr_type_t 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_full(g_direct_hash, g_direct_equal, NULL, free_radius_attr_info);
}
memset(&code, 0, sizeof(code));
code.u8_code[0] = (guint8) strtoul(codestr, NULL, 10);
s = (radius_attr_info_t*)g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code.value));
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.value),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) {
/* Ensure that the array is zero terminated. */
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)) {
g_hash_table_steal(state->value_strings, key);
s->vs = (value_string*)(void *)g_array_free(vs.a, FALSE);
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) ) {
g_hash_table_steal(state->value_strings, key);
a->vs = (value_string*)(void *)g_array_free(vs.a, FALSE);
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 void destroy_value_strings(gpointer v) {
value_string* vs = (value_string*)(void *)(((GArray*)v)->data);
for (;vs->strptr;vs++) {
g_free((void*)vs->strptr);
}
g_array_free((GArray*)v,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_vendor_evs_type = 0;
state.current_attr = NULL;
state.directory = dir;
state.fullpaths[0] = ws_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_full(g_str_hash, g_str_equal, g_free, destroy_value_strings);
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++) {
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_destroy(state.value_strings);
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 - https://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:
*/