diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/radius_dict.l | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/radius_dict.l')
-rw-r--r-- | epan/radius_dict.l | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/epan/radius_dict.l b/epan/radius_dict.l new file mode 100644 index 00000000..c8c1825c --- /dev/null +++ b/epan/radius_dict.l @@ -0,0 +1,817 @@ +%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: + */ |