817 lines
25 KiB
Plaintext
817 lines
25 KiB
Plaintext
%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>
|
|
|
|
/*
|
|
* 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 = 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_-]+ {
|
|
/*
|
|
* 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] = 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; }
|
|
|
|
|
|
%%
|
|
|
|
/*
|
|
* 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] = 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_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:
|
|
*/
|