1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-08 04:58:40 +03:00

r753: Big reorganisation of everything - also fixes handling of dissectors

for structures.

Instead of trying to parse everything to produce output in the right
order, generate parser in two steps: 1) gather information and register
names, fields, types etc.  2) generate output using data from step 1.
(This used to be commit 03863a2ca88c374e168d579e7e4f78877160215c)
This commit is contained in:
Tim Potter 2004-05-16 11:20:06 +00:00 committed by Gerald (Jerry) Carter
parent 6703be3ef0
commit 8b84f643bd

View File

@ -1,18 +1,129 @@
###################################################
# parser generator for IDL structures
# Copyright tpot@samba.org 2001
# Copyright tridge@samba.org 2000
# Copyright tpot@samba.org 2004
# released under the GNU GPL
package IdlEParser;
use strict;
use dump;
my($module);
#use Data::Dumper;
#####################################################################
# handlers for parsing ndr argument types
# Code for managing hf's
my %hf_info = ();
# Convert an idl type to an ethereal FT_* type
sub type2ft($)
{
my($t) = shift;
return "FT_UINT32", if ($t eq "uint32");
return "FT_UINT16", if ($t eq "uint16");
return "FT_BYTES";
}
# Select an ethereal BASE_* type for an idl type
sub type2base($)
{
my($t) = shift;
return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
return "BASE_NONE";
}
# Create a new field. The name of the field is hf_${name}_${type} where
# name and type are taken from the IDL definition for the element.
sub AddField($$)
{
my($name) = shift;
my($type) = shift;
my $hf_name = "${name}_${type}";
return, if defined $hf_info{$hf_name};
$hf_info{$hf_name} = {
'name' => $name, # Field name
'type' => $type, # Field type
'ft' => type2ft($type), # Ethereal type
'base' => type2base($type), # Base of type
};
}
# Generate field definitions from %hf_info
sub EtherealFieldDefinitions()
{
my($res) = "";
$res .= << "EOF";
static int hf_opnum = -1;
static int hf_rc = -1;
static int hf_policy_handle = -1;
EOF
foreach my $hf (keys(%hf_info)) {
my($hf_name) = "$hf_info{$hf}{name}_$hf_info{$hf}{type}";
$res .= "static int hf_$hf_name = -1;\n";
}
return $res;
}
# Generate field initialisers
sub EtherealFieldInitialisation($)
{
my($module) = shift;
my($res) = "";
# Fields present in all parsers
$res .= << "EOF";
\t{ &hf_opnum,
\t { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},
\t{ &hf_policy_handle,
\t { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},
\t{ &hf_rc,
\t { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},
EOF
foreach my $hf (keys(%hf_info)) {
$res .= "\t{ &hf_$hf,\n";
$res .= "\t { \"$hf_info{$hf}{name}\", \"$hf\", $hf_info{$hf}{ft}, $hf_info{$hf}{base},\n";
$res .= "\t NULL, 0, \"$hf\", HFILL }},\n";
}
return $res;
}
#####################################################################
# Code for managing subtrees
sub EtherealSubtreeDefinitions($)
{
my($module) = shift;
my($res) = "";
$res .= << "EOF";
static gint ett_dcerpc_$module = -1;
EOF
return $res;
}
sub EtherealSubtreeInitialisation()
{
my($res) = "";
return $res;
}
#####################################################################
# Generate dissection functions for NDR types
sub ParamSimpleNdrType($)
{
@ -49,45 +160,52 @@ sub ParamStruct($)
my($p) = shift;
my($res);
$res .= "\toffset = dissect_${module}_$p->{TYPE}(tvb, offset, pinfo, tree, drep);\n";
$res .= "\toffset = dissect_$p->{TYPE}(tvb, offset, pinfo, tree, drep);\n";
return $res;
}
# Index of NDR types and functions to generate code to dissect that type
my %param_handlers = (
'uint8' => \&ParamSimpleNdrType,
'uint16' => \&ParamSimpleNdrType,
'uint32' => \&ParamSimpleNdrType,
'uint8' => \&ParamSimpleNdrType,
'uint16' => \&ParamSimpleNdrType,
'uint32' => \&ParamSimpleNdrType,
'policy_handle' => \&ParamPolicyHandle,
'string' => \&ParamString,
'string' => \&ParamString,
);
my %hf_info = (); # Field info - remember for trailing stuff
# Generate a parser for a NDR parameter
#####################################################################
# parse a function
sub ParseParameter($)
{
my($p) = shift;
my($res);
# Call function registered for this type
if (defined($param_handlers{$p->{TYPE}})) {
$res .= &{$param_handlers{$p->{TYPE}}}($p);
return $res;
}
# Unknown type - make a note in the protocol tree
$res .= "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$p->{TYPE}'\");\n";
return $res;
}
#####################################################################
# parse a function
sub ParseFunction($)
# Generate code fragment for an IDL function
sub EtherealFunction($)
{
my($f) = shift;
my($res);
# Comment displaying IDL for this function
$res .= "/*\n\n";
$res .= IdlDump::DumpFunction($f);
$res .= "*/\n\n";
@ -125,52 +243,38 @@ sub ParseFunction($)
}
#####################################################################
# parse a function
sub ParseEnum($$)
{
my($name) = shift;
my($enum) = shift;
# Generate code fragment for an IDL struct
return "/* Enum $name */\n\n";
}
#####################################################################
# parse a function
sub ParseStruct($$)
{
my($name) = shift;
sub EtherealStruct($$)
{
my($module) = shift;
my($struct) = shift;
my($res);
# Add struct name to param handler list
$param_handlers{$name} = \&ParamStruct;
# Create parse function
my($res) = "";
$res .= "/*\n\n";
$res .= IdlDump::DumpStruct($struct);
$res .= IdlDump::DumpStruct($struct->{DATA});
$res .= "\n\n*/\n\n";
$res .= << "EOF";
int dissect_${module}_$name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
int dissect_$struct->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
{
proto_item *item = NULL;
proto_tree *tree = NULL;
int old_offset = offset;
if (parent_tree) {
item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$name");
item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$struct->{NAME}");
tree = proto_item_add_subtree(item, ett_dcerpc_$module);
}
EOF
foreach my $d (@{$struct->{ELEMENTS}}) {
# Parse elements
foreach my $d (@{$struct->{DATA}->{ELEMENTS}}) {
$res .= ParseParameter($d);
}
$res .= << "EOF";
proto_item_set_len(item, offset - old_offset);
@ -184,55 +288,75 @@ EOF
}
#####################################################################
# parse a function
sub ParseUnion($$)
{
my($name) = shift;
my($union) = shift;
# Generate code fragment for an IDL union
return "/* Union $name */\n\n";
}
#####################################################################
# parse a function
sub ParseTypedef($)
sub EtherealUnion($$)
{
my($typedef) = shift;
my($data) = $typedef->{DATA};
my($module) = shift;
my($union) = shift;
my($res) = "";
$res .= ParseEnum($typedef->{NAME}, $data), if $data->{TYPE} eq "ENUM";
$res .= ParseStruct($typedef->{NAME}, $data), if $data->{TYPE} eq "STRUCT";
$res .= ParseUnion($typedef->{NAME}, $data), if $data->{TYPE} eq "UNION";
$res .= "/*\n\n";
$res .= IdlDump::DumpUnion($union->{DATA});
$res .= "\n\n*/\n\n";
return $res;
}
#####################################################################
# parse the interface definitions
sub Pass2Interface($)
$res .= << "EOF";
int dissect_$union->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my($res) = "";
proto_item *item = NULL;
proto_tree *tree = NULL;
int old_offset = offset;
foreach my $d (@{$data}) {
$res .= ParseFunction($d), if $d->{TYPE} eq "FUNCTION";
$res .= ParseTypedef($d), if $d->{TYPE} eq "TYPEDEF";
if (parent_tree) {
item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$union->{NAME}");
tree = proto_item_add_subtree(item, ett_dcerpc_$module);
}
EOF
# TODO: Parse elements
$res .= << "EOF";
proto_item_set_len(item, offset - old_offset);
return offset;
}
EOF
return $res;
}
#####################################################################
# Pass 1: Stuff required before structs and functions
# Generate code fragment for an IDL typedef
sub Pass1ModuleHeader($)
sub EtherealTypedef($$)
{
my($module) = shift;
my($typedef) = shift;
return EtherealStruct($module, $typedef),
if $typedef->{DATA}{TYPE} eq "STRUCT";
return EtherealUnion($module, $typedef),
if $typedef->{DATA}{TYPE} eq "UNION";
return "/* Unsupported typedef $typedef->{DATA}{TYPE} " .
"$typedef->{NAME}*/\n\n";
}
#####################################################################
# Generate code fragment for the start of the dissector
sub EtherealHeader($)
{
my($d) = shift;
my($module) = shift;
my($res) = "";
$res .= << "EOF";
/* parser auto-generated by pidl */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -242,211 +366,51 @@ sub Pass1ModuleHeader($)
extern const value_string NT_errors[];
EOF
# UUID
if ($d->{TYPE} eq "MODULEHEADER" and defined($d->{PROPERTIES}->{uuid})) {
my $uuid = $d->{PROPERTIES}->{uuid};
$res .= "static e_uuid_t uuid_dcerpc_$module = {\n";
$res .= "\t0x" . substr($uuid, 0, 8);
$res .= ", 0x" . substr($uuid, 9, 4);
$res .= ", 0x" . substr($uuid, 14, 4) . ",\n";
$res .= "\t{ 0x" . substr($uuid, 19, 2);
$res .= ", 0x" . substr($uuid, 21, 2);
$res .= ", 0x" . substr($uuid, 24, 2);
$res .= ", 0x" . substr($uuid, 26, 2);
$res .= ", 0x" . substr($uuid, 28, 2);
$res .= ", 0x" . substr($uuid, 30, 2);
$res .= ", 0x" . substr($uuid, 32, 2);
$res .= ", 0x" . substr($uuid, 34, 2) . " }\n";
$res .= "};\n\n";
$res .= "static guint16 ver_dcerpc_samr = " .
$d->{PROPERTIES}->{version} . ";\n\n";
}
return $res;
}
# Convert an idl type to an ethereal FT_* type
sub type2ft($)
{
my($t) = shift;
return "FT_UINT32", if ($t eq "uint32");
return "FT_UINT16", if ($t eq "uint16");
return "FT_BYTES";
}
# Select an ethereal BASE_* type for an idl type
sub type2base($)
{
my($t) = shift;
return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
return "BASE_NONE";
}
sub AddField($$)
{
my($name) = shift;
my($type) = shift;
my($res) = "";
my $hf_name = "${name}_${type}";
return $res, if defined $hf_info{$hf_name};
# Make a note about new field
$res .= "static int hf_$hf_name = -1;\n";
$hf_info{$hf_name} = {
'ft' => type2ft($type),
'base' => type2base($name),
'name' => $name
};
return $res;
}
sub ScanFunction($)
{
my($fn) = shift;
my($res) = "";
foreach my $args ($fn) {
foreach my $params (@{$args}) {
$res .= AddField($params->{NAME}, $params->{TYPE});
}
}
return $res;
}
sub ScanTypedef($)
{
my($td) = shift;
my($res) = "";
if ($td->{TYPE} eq "STRUCT") {
foreach my $e (@{$td->{ELEMENTS}}) {
$res .= AddField($e->{NAME}, $e->{TYPE});
}
}
return $res;
}
sub Pass1Interface($)
{
my($interface) = shift;
my($res) = "";
$res .= << "EOF";
static int proto_dcerpc_$module = -1;
static int hf_opnum = -1;
static int hf_rc = -1;
static int hf_policy_handle = -1;
static gint ett_dcerpc_$module = -1;
EOF
foreach my $fn (@{$interface->{DATA}}) {
$res .= ScanFunction($fn->{DATA}), if $fn->{TYPE} eq "FUNCTION";
$res .= ScanTypedef($fn->{DATA}), if $fn->{TYPE} eq "TYPEDEF";
}
$res .= "\n";
return $res;
}
#####################################################################
# Pass 3: trailing stuff
sub Pass3Interface($)
sub EtherealUuidRegistration($$$)
{
my($interface) = shift;
my($module) = shift;
my($uuid) = shift;
my($uuid_version) = shift;
my($res) = "";
$res .= "static dcerpc_sub_dissector dcerpc_${module}_dissectors[] = {\n";
my $num = 0;
foreach my $d (@{$interface->{DATA}}) {
if ($d->{TYPE} eq "FUNCTION") {
# Strip module name from function name, if present
my $n = $d->{NAME};
$n = substr($d->{NAME}, length($module) + 1),
if $module eq substr($d->{NAME}, 0, length($module));
$res .= "\t{ $num, \"$n\",\n";
$res .= "\t\t$d->{NAME}_rqst,\n";
$res .= "\t\t$d->{NAME}_resp },\n";
$num++;
}
}
# Various objects for dissector initialisation
$res .= "static e_uuid_t uuid_dcerpc_$module = {\n";
$res .= "\t0x" . substr($uuid, 0, 8);
$res .= ", 0x" . substr($uuid, 9, 4);
$res .= ", 0x" . substr($uuid, 14, 4) . ",\n";
$res .= "\t{ 0x" . substr($uuid, 19, 2);
$res .= ", 0x" . substr($uuid, 21, 2);
$res .= ", 0x" . substr($uuid, 24, 2);
$res .= ", 0x" . substr($uuid, 26, 2);
$res .= ", 0x" . substr($uuid, 28, 2);
$res .= ", 0x" . substr($uuid, 30, 2);
$res .= ", 0x" . substr($uuid, 32, 2);
$res .= ", 0x" . substr($uuid, 34, 2) . " }\n";
$res .= "};\n\n";
$res .= "static guint16 ver_dcerpc_$module = " . $uuid_version . ";\n\n";
return $res;
}
#####################################################################
# parse a parsed IDL structure back into an IDL file
sub Parse($)
# Generate code fragment for the tail of the dissector
sub EtherealModuleRegistration($$$)
{
my($idl) = shift;
my($res) = "/* parser auto-generated by pidl */\n\n";
my($d);
my($module) = shift;
my($hf_register_info) = shift;
my($ett_info) = shift;
my($res) = "";
# Pass 0: set module name
foreach $d (@{$idl}) {
$module = $d->{NAME}, if ($d->{TYPE} eq "INTERFACE");
}
# Pass 1: header stuff
foreach $d (@{$idl}) {
$res .= Pass1ModuleHeader($d), if $d->{TYPE} eq "MODULEHEADER";
$res .= Pass1Interface($d), if $d->{TYPE} eq "INTERFACE";
}
# Pass 2: typedefs and functions
foreach $d (@{$idl}) {
$res .= Pass2Interface($d), if $d->{TYPE} eq "INTERFACE";
}
# Pass 3: trailing stuff
foreach $d (@{$idl}) {
$res .= Pass3Interface($d), if $d->{TYPE} eq "INTERFACE";
}
my $hf_register_info = << "EOF";
\t{ &hf_opnum,
\t { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},
\t{ &hf_policy_handle,
\t { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},
\t{ &hf_rc,
\t { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},
EOF
foreach my $hf (keys(%hf_info)) {
$hf_register_info .= "\t{ &hf_$hf,\n";
$hf_register_info .= "\t { \"$hf_info{$hf}{name}\", \"$hf\", $hf_info{$hf}{ft}, $hf_info{$hf}{base},\n";
$hf_register_info .= "\t NULL, 0, \"$hf\", HFILL }},\n";
}
my $ett_info = "/* spotty */";
$res .= << "EOF";
void
proto_register_dcerpc_${module}(void)
@ -462,7 +426,7 @@ $ett_info
proto_dcerpc_$module = proto_register_protocol("$module", "$module", "$module");
proto_register_field_array (proto_dcerpc_$module, hf, array_length (hf));
proto_register_field_array(proto_dcerpc_$module, hf, array_length (hf));
proto_register_subtree_array(ett, array_length(ett));
}
@ -479,4 +443,134 @@ EOF
return $res;
}
#####################################################################
# Generate code fragment for DCERPC subdissector registration
sub EtherealSubdissectorRegistration($$)
{
my($module) = shift;
my($functions) = shift;
my($res) = "";
$res .= "static dcerpc_sub_dissector dcerpc_${module}_dissectors[] = {\n";
my $num = 0;
foreach my $name (@$functions) {
# Strip module name from function name, if present
my($n) = $name;
$n = substr($name, length($module) + 1),
if $module eq substr($name, 0, length($module));
$res .= "\t{ $num, \"$n\",\n";
$res .= "\t\t${name}_rqst,\n";
$res .= "\t\t${name}_resp },\n";
$num++;
}
$res .= "};\n\n";
return $res;
}
#####################################################################
# Generate an ethereal dissector from an IDL syntax tree.
sub Parse($)
{
my($idl) = shift;
my($res) = "";
#
# Phase 1 : Gather information from IDL tree
#
my($module) = "";
my($uuid) = "";
my($uuid_version) = "";
my(@fns) = ();
foreach my $d (@$idl) {
# Get data from interface definition
$module = $d->{NAME}, if $d->{TYPE} eq "INTERFACE";
if ($d->{TYPE} eq "MODULEHEADER") {
$uuid = $d->{PROPERTIES}->{uuid};
$uuid_version = $d->{PROPERTIES}->{version};
}
# Iterate over function definitions and register field info
if ($d->{TYPE} eq "INTERFACE") {
foreach my $d (@{$d->{DATA}}) {
if ($d->{TYPE} eq "FUNCTION") {
# Register function name
$fns[$#fns + 1] = $d->{NAME};
# Register function fields (parameter names)
foreach my $e (@{$d->{DATA}}) {
AddField($e->{NAME}, $e->{TYPE});
}
}
if ($d->{TYPE} eq "TYPEDEF") {
# Register structure names
$param_handlers{$d->{NAME}} = \&ParamStruct;
# Register typedef fields (element names)
if ($d->{DATA}->{TYPE} eq "STRUCT") {
foreach my $e (@{$d->{DATA}->{ELEMENTS}}) {
AddField($e->{NAME}, $e->{TYPE});
}
}
}
}
}
}
#
# Phase 2 : Spit out parser from fragments generated above
#
$res .= EtherealHeader($module);
$res .= EtherealFieldDefinitions();
$res .= EtherealSubtreeDefinitions($module);
foreach my $d (@$idl) {
if ($d->{TYPE} eq "INTERFACE") {
foreach my $d (@{$d->{DATA}}) {
# Generate function code fragments
$res .= EtherealFunction($d), if $d->{TYPE} eq "FUNCTION";
# Generate structure code fragments
$res .= EtherealTypedef($module, $d),
if $d->{TYPE} eq "TYPEDEF";
}
}
}
$res .= EtherealSubdissectorRegistration($module, \@fns);
$res .= EtherealUuidRegistration($module, $uuid, $uuid_version);
$res .= EtherealModuleRegistration($module,
EtherealFieldInitialisation($module),
EtherealSubtreeInitialisation());
return $res;
}
1;