mirror of
https://github.com/samba-team/samba.git
synced 2025-06-24 15:17:06 +03:00
fields in structures with the same name as a structure (i.e security_ace.object and security_ace_object). I've twiddled the naming scheme a bit and things are a bit more unique but there is still may be some naming conflicts in other IDL files. We are now getting confused over fields with the same name in unions (e.g security_ace_object_ctr.object) plus some other union weirdness. (This used to be commit c2ad9f49a204d0075a3b460c5ea2ca9741fc7125)
874 lines
25 KiB
Perl
874 lines
25 KiB
Perl
##################################################
|
|
# Samba4 NDR parser generator for IDL structures
|
|
# Copyright tridge@samba.org 2000-2003
|
|
# Copyright tpot@samba.org 2001,2005
|
|
# Copyright jelmer@samba.org 2004-2005
|
|
# Portions based on idl2eth.c by Ronnie Sahlberg
|
|
# released under the GNU GPL
|
|
|
|
package Parse::Pidl::Ethereal::NDR;
|
|
|
|
use strict;
|
|
use Parse::Pidl::Typelist;
|
|
use Parse::Pidl::Util qw(has_property ParseExpr property_matches);
|
|
use Parse::Pidl::NDR;
|
|
use Parse::Pidl::Dump qw(DumpTypedef DumpFunction);
|
|
use Parse::Pidl::Ethereal::Conformance qw(ReadConformance);
|
|
|
|
my %types;
|
|
my %hf;
|
|
my @ett;
|
|
|
|
my $conformance = {imports=>{}};
|
|
|
|
my %ptrtype_mappings = (
|
|
"unique" => "NDR_POINTER_UNIQUE",
|
|
"ref" => "NDR_POINTER_REF",
|
|
"ptr" => "NDR_POINTER_PTR"
|
|
);
|
|
|
|
sub type2ft($)
|
|
{
|
|
my($t) = shift;
|
|
|
|
return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
|
|
return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
|
|
return "FT_UINT64", if $t eq "HYPER_T" or $t eq "NTTIME"
|
|
or $t eq "NTTIME_1sec" or $t eq "NTTIME_hyper" or $t eq "hyper";
|
|
|
|
return "FT_STRING" if ($t eq "string");
|
|
|
|
return "FT_NONE";
|
|
}
|
|
|
|
sub StripPrefixes($)
|
|
{
|
|
my ($s) = @_;
|
|
|
|
foreach (@{$conformance->{strip_prefixes}}) {
|
|
$s =~ s/^$_\_//g;
|
|
}
|
|
|
|
return $s;
|
|
}
|
|
|
|
# Convert a IDL structure field name (e.g access_mask) to a prettier
|
|
# string like 'Access Mask'.
|
|
|
|
sub field2name($)
|
|
{
|
|
my($field) = shift;
|
|
|
|
$field =~ s/_/ /g; # Replace underscores with spaces
|
|
$field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
|
|
|
|
return $field;
|
|
}
|
|
|
|
my %res = ();
|
|
my $tabs = "";
|
|
sub pidl_code($)
|
|
{
|
|
my $d = shift;
|
|
if ($d) {
|
|
$res{code} .= $tabs;
|
|
$res{code} .= $d;
|
|
}
|
|
$res{code} .="\n";
|
|
}
|
|
|
|
sub pidl_hdr($) { my $x = shift; $res{hdr} .= "$x\n"; }
|
|
sub pidl_def($) { my $x = shift; $res{def} .= "$x\n"; }
|
|
|
|
sub indent()
|
|
{
|
|
$tabs .= "\t";
|
|
}
|
|
|
|
sub deindent()
|
|
{
|
|
$tabs = substr($tabs, 0, -1);
|
|
}
|
|
|
|
sub PrintIdl($)
|
|
{
|
|
my $idl = shift;
|
|
|
|
foreach (split /\n/, $idl) {
|
|
pidl_code "/* IDL: $_ */";
|
|
}
|
|
|
|
pidl_code "";
|
|
}
|
|
|
|
#####################################################################
|
|
# parse the interface definitions
|
|
sub Interface($)
|
|
{
|
|
my($interface) = @_;
|
|
Const($_,$interface->{NAME}) foreach (@{$interface->{CONSTS}});
|
|
Typedef($_,$interface->{NAME}) foreach (@{$interface->{TYPEDEFS}});
|
|
Function($_,$interface->{NAME}) foreach (@{$interface->{FUNCTIONS}});
|
|
}
|
|
|
|
sub Enum($$$)
|
|
{
|
|
my ($e,$name,$ifname) = @_;
|
|
my $valsstring = "$ifname\_$name\_vals";
|
|
my $dissectorname = "$ifname\_dissect\_enum\_".StripPrefixes($name);
|
|
|
|
return if (defined($conformance->{noemit}->{$dissectorname}));
|
|
|
|
foreach (@{$e->{ELEMENTS}}) {
|
|
if (/([^=]*)=(.*)/) {
|
|
pidl_hdr "#define $1 ($2)";
|
|
}
|
|
}
|
|
|
|
pidl_hdr "extern const value_string $valsstring\[];";
|
|
pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
|
|
|
|
pidl_def "const value_string ".$valsstring."[] = {";
|
|
foreach (@{$e->{ELEMENTS}}) {
|
|
next unless (/([^=]*)=(.*)/);
|
|
pidl_def "\t{ $1, \"$1\" },";
|
|
}
|
|
|
|
pidl_def "{ 0, NULL }";
|
|
pidl_def "};";
|
|
|
|
pidl_code "int";
|
|
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param _U_)";
|
|
pidl_code "{";
|
|
indent;
|
|
pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, NULL);";
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
|
|
my $enum_size = $e->{BASE_TYPE};
|
|
$enum_size =~ s/uint//g;
|
|
register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "VALS($valsstring)", $enum_size / 8);
|
|
}
|
|
|
|
sub Bitmap($$$)
|
|
{
|
|
my ($e,$name,$ifname) = @_;
|
|
my $dissectorname = "$ifname\_dissect\_bitmap\_".StripPrefixes($name);
|
|
|
|
register_ett("ett_$ifname\_$name");
|
|
|
|
pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int hf_index, guint32 param);";
|
|
|
|
pidl_code "int";
|
|
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
|
|
pidl_code "{";
|
|
indent;
|
|
pidl_code "proto_item *item = NULL;";
|
|
pidl_code "proto_tree *tree = NULL;";
|
|
pidl_code "";
|
|
|
|
pidl_code "g$e->{BASE_TYPE} flags;";
|
|
if ($e->{ALIGN} > 1) {
|
|
pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
|
|
}
|
|
|
|
pidl_code "";
|
|
|
|
pidl_code "if(parent_tree) {";
|
|
indent;
|
|
pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, $e->{ALIGN}, TRUE);";
|
|
pidl_code "tree = proto_item_add_subtree(item,ett_$ifname\_$name);";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
|
|
pidl_code "offset = dissect_ndr_$e->{BASE_TYPE}(tvb, offset, pinfo, NULL, drep, -1, &flags);";
|
|
|
|
pidl_code "proto_item_append_text(item, \": \");\n";
|
|
pidl_code "if (!flags)";
|
|
pidl_code "\tproto_item_append_text(item, \"(No values set)\");\n";
|
|
|
|
foreach (@{$e->{ELEMENTS}}) {
|
|
next unless (/([^ ]*) (.*)/);
|
|
my ($en,$ev) = ($1,$2);
|
|
my $hf_bitname = "hf_$ifname\_$name\_$en";
|
|
my $filtername = "$ifname\.$name\.$en";
|
|
|
|
register_hf_field($hf_bitname, field2name($en), $filtername, "FT_BOOLEAN", $e->{ALIGN} * 8, "TFS(&$name\_$en\_tfs)", $ev, "");
|
|
|
|
pidl_def "static const true_false_string $name\_$en\_tfs = {";
|
|
pidl_def " \"$en is SET\",";
|
|
pidl_def " \"$en is NOT SET\",";
|
|
pidl_def "};";
|
|
|
|
pidl_code "proto_tree_add_boolean(tree, $hf_bitname, tvb, offset-$e->{ALIGN}, $e->{ALIGN}, flags);";
|
|
pidl_code "if (flags&$ev){";
|
|
pidl_code "\tproto_item_append_text(item, \"$en\");";
|
|
pidl_code "\tif (flags & (~$ev))";
|
|
pidl_code "\t\tproto_item_append_text(item, \", \");";
|
|
pidl_code "}";
|
|
pidl_code "flags&=(~$ev);";
|
|
pidl_code "";
|
|
}
|
|
|
|
pidl_code "if(flags){";
|
|
pidl_code "\tproto_item_append_text(item, \"Unknown bitmap value 0x%x\", flags);";
|
|
pidl_code "}\n";
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
|
|
my $size = $e->{BASE_TYPE};
|
|
$size =~ s/uint//g;
|
|
register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", type2ft($e->{BASE_TYPE}), "BASE_DEC", "0", "NULL", $size/8);
|
|
}
|
|
|
|
sub ElementLevel($$$$$)
|
|
{
|
|
my ($e,$l,$hf,$myname,$pn) = @_;
|
|
|
|
my $param = 0;
|
|
|
|
if (defined($conformance->{dissectorparams}->{$myname})) {
|
|
$param = $conformance->{dissectorparams}->{$myname};
|
|
}
|
|
|
|
if ($l->{TYPE} eq "POINTER") {
|
|
my $type;
|
|
if ($l->{LEVEL} eq "TOP") {
|
|
$type = "toplevel";
|
|
} elsif ($l->{LEVEL} eq "EMBEDDED") {
|
|
$type = "embedded";
|
|
}
|
|
pidl_code "offset = dissect_ndr_$type\_pointer(tvb, offset, pinfo, tree, drep, $myname\_, $ptrtype_mappings{$l->{POINTER_TYPE}}, \"Pointer to ".field2name(StripPrefixes($e->{NAME})) . " ($e->{TYPE})\",$hf);";
|
|
} elsif ($l->{TYPE} eq "ARRAY") {
|
|
|
|
if ($l->{IS_INLINE}) {
|
|
warn ("Inline arrays not supported");
|
|
pidl_code "/* FIXME: Handle inline array */";
|
|
} elsif ($l->{IS_FIXED}) {
|
|
pidl_code "int i;";
|
|
pidl_code "for (i = 0; i < $l->{SIZE_IS}; i++)";
|
|
pidl_code "\toffset = $myname\_(tvb, offset, pinfo, tree, drep);";
|
|
} else {
|
|
my $af = "";
|
|
($af = "ucarray") if ($l->{IS_CONFORMANT});
|
|
($af = "uvarray") if ($l->{IS_VARYING});
|
|
($af = "ucvarray") if ($l->{IS_CONFORMANT} and $l->{IS_VARYING});
|
|
|
|
pidl_code "offset = dissect_ndr_$af(tvb, offset, pinfo, tree, drep, $myname\_);";
|
|
}
|
|
} elsif ($l->{TYPE} eq "DATA") {
|
|
if ($l->{DATA_TYPE} eq "string") {
|
|
my $bs = 2; # Byte size defaults to that of UCS2
|
|
|
|
|
|
($bs = 1) if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_ASCII.*"));
|
|
|
|
if (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*") and property_matches($e, "flag", ".*LIBNDR_FLAG_STR_LEN4.*")) {
|
|
pidl_code "char *data;\n";
|
|
pidl_code "offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, &data);";
|
|
pidl_code "proto_item_append_text(tree, \": %s\", data);";
|
|
} elsif (property_matches($e, "flag", ".*LIBNDR_FLAG_STR_SIZE4.*")) {
|
|
pidl_code "offset = dissect_ndr_vstring(tvb, offset, pinfo, tree, drep, $bs, $hf, FALSE, NULL);";
|
|
} else {
|
|
warn("Unable to handle string with flags $e->{PROPERTIES}->{flag}");
|
|
}
|
|
} else {
|
|
my $call;
|
|
|
|
if (defined($types{$l->{DATA_TYPE}})) {
|
|
$call= $types{$l->{DATA_TYPE}}->{CALL};
|
|
} elsif ($conformance->{imports}->{$l->{DATA_TYPE}}) {
|
|
$call = $conformance->{imports}->{$l->{DATA_TYPE}};
|
|
} else {
|
|
if ($l->{DATA_TYPE} =~ /^([a-z]+)\_(.*)$/)
|
|
{
|
|
pidl_code "offset = $1_dissect_$2(tvb,offset,pinfo,tree,drep,$hf,$param);";
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
$call =~ s/\@HF\@/$hf/g;
|
|
$call =~ s/\@PARAM\@/$param/g;
|
|
pidl_code "$call";
|
|
}
|
|
} elsif ($_->{TYPE} eq "SUBCONTEXT") {
|
|
my $num_bits = ($l->{HEADER_SIZE}*8);
|
|
pidl_code "guint$num_bits size;";
|
|
pidl_code "int start_offset = offset;";
|
|
pidl_code "tvbuff_t *subtvb;";
|
|
pidl_code "offset = dissect_ndr_uint$num_bits(tvb, offset, pinfo, tree, drep, $hf, &size);";
|
|
pidl_code "proto_tree_add_text(tree, tvb, start_offset, offset - start_offset + size, \"Subcontext size\");";
|
|
|
|
pidl_code "subtvb = tvb_new_subset(tvb, offset, size, -1);";
|
|
pidl_code "$myname\_(subtvb, 0, pinfo, tree, drep);";
|
|
} else {
|
|
die("Unknown type `$_->{TYPE}'");
|
|
}
|
|
}
|
|
|
|
sub Element($$$)
|
|
{
|
|
my ($e,$pn,$ifname) = @_;
|
|
|
|
my $dissectorname = "$ifname\_dissect\_element\_".StripPrefixes($pn)."\_".StripPrefixes($e->{NAME});
|
|
|
|
my $call_code = "offset = $dissectorname(tvb, offset, pinfo, tree, drep);";
|
|
|
|
my $hf = register_hf_field("hf_$ifname\_$pn\_$e->{NAME}", field2name($e->{NAME}), "$ifname.$pn.$e->{NAME}", type2ft($e->{TYPE}), "BASE_HEX", "NULL", 0, "");
|
|
|
|
if (defined($conformance->{noemit}->{$dissectorname})) {
|
|
return $call_code;
|
|
}
|
|
|
|
my $add = "";
|
|
|
|
foreach (@{$e->{LEVELS}}) {
|
|
next if ($_->{TYPE} eq "SWITCH");
|
|
pidl_def "static int $dissectorname$add(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep);";
|
|
pidl_code "static int";
|
|
pidl_code "$dissectorname$add(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)";
|
|
pidl_code "{";
|
|
indent;
|
|
|
|
ElementLevel($e,$_,$hf,$dissectorname.$add,$pn);
|
|
|
|
pidl_code "";
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
$add.="_";
|
|
}
|
|
|
|
return $call_code;
|
|
}
|
|
|
|
sub Function($$$)
|
|
{
|
|
my ($fn,$ifname) = @_;
|
|
|
|
my %dissectornames;
|
|
|
|
foreach (@{$fn->{ELEMENTS}}) {
|
|
$dissectornames{$_->{NAME}} = Element($_, $fn->{NAME}, $ifname) if not defined($dissectornames{$_->{NAME}});
|
|
}
|
|
|
|
my $fn_name = $_->{NAME};
|
|
$fn_name =~ s/^${ifname}_//;
|
|
|
|
PrintIdl DumpFunction($fn->{ORIGINAL});
|
|
pidl_code "static int";
|
|
pidl_code "$ifname\_dissect\_${fn_name}_response(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
|
|
pidl_code "{";
|
|
indent;
|
|
foreach (@{$fn->{ELEMENTS}}) {
|
|
if (grep(/out/,@{$_->{DIRECTION}})) {
|
|
pidl_code "$dissectornames{$_->{NAME}}";
|
|
pidl_code "offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);";
|
|
pidl_code "";
|
|
}
|
|
}
|
|
|
|
if (not defined($fn->{RETURN_TYPE})) {
|
|
} elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
|
|
pidl_code "offset = dissect_ntstatus(tvb, offset, pinfo, tree, drep, hf\_$ifname\_status, NULL);";
|
|
} elsif ($fn->{RETURN_TYPE} eq "WERROR") {
|
|
pidl_code "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf\_$ifname\_werror, NULL);";
|
|
}
|
|
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
|
|
pidl_code "static int";
|
|
pidl_code "$ifname\_dissect\_${fn_name}_request(tvbuff_t *tvb _U_, int offset _U_, packet_info *pinfo _U_, proto_tree *tree _U_, guint8 *drep _U_)";
|
|
pidl_code "{";
|
|
indent;
|
|
foreach (@{$fn->{ELEMENTS}}) {
|
|
if (grep(/in/,@{$_->{DIRECTION}})) {
|
|
pidl_code "$dissectornames{$_->{NAME}}";
|
|
pidl_code "offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);";
|
|
}
|
|
|
|
}
|
|
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
}
|
|
|
|
sub Struct($$$)
|
|
{
|
|
my ($e,$name,$ifname) = @_;
|
|
my $dissectorname = "$ifname\_dissect\_struct\_".StripPrefixes($name);
|
|
|
|
return if (defined($conformance->{noemit}->{$dissectorname}));
|
|
|
|
register_ett("ett_$ifname\_$name");
|
|
|
|
my $res = "";
|
|
($res.="\t".Element($_, $name, $ifname)."\n\n") foreach (@{$e->{ELEMENTS}});
|
|
|
|
pidl_hdr "int $dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_);";
|
|
|
|
pidl_code "int";
|
|
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
|
|
pidl_code "{";
|
|
indent;
|
|
pidl_code "proto_item *item = NULL;";
|
|
pidl_code "proto_tree *tree = NULL;";
|
|
pidl_code "int old_offset;";
|
|
pidl_code "";
|
|
|
|
if ($e->{ALIGN} > 1) {
|
|
pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
|
|
}
|
|
pidl_code "";
|
|
|
|
pidl_code "old_offset = offset;";
|
|
pidl_code "";
|
|
pidl_code "if(parent_tree){";
|
|
indent;
|
|
pidl_code "item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, -1, TRUE);";
|
|
pidl_code "tree = proto_item_add_subtree(item, ett_$ifname\_$name);";
|
|
deindent;
|
|
pidl_code "}";
|
|
|
|
pidl_code "\n$res";
|
|
|
|
pidl_code "proto_item_set_len(item, offset-old_offset);\n";
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}\n";
|
|
|
|
register_type($name, "offset = $dissectorname(tvb,offset,pinfo,tree,drep,\@HF\@,\@PARAM\@);", "FT_NONE", "BASE_NONE", 0, "NULL", 0);
|
|
}
|
|
|
|
sub Union($$$)
|
|
{
|
|
my ($e,$name,$ifname) = @_;
|
|
|
|
my $dissectorname = "$ifname\_dissect_".StripPrefixes($name);
|
|
return if (defined($conformance->{noemit}->{$dissectorname}));
|
|
|
|
register_ett("ett_$ifname\_$name");
|
|
|
|
my $res = "";
|
|
foreach (@{$e->{ELEMENTS}}) {
|
|
$res.="\n\t\t$_->{CASE}:\n";
|
|
if ($_->{TYPE} ne "EMPTY") {
|
|
$res.="\t\t\t".Element($_, $name, $ifname)."\n";
|
|
}
|
|
$res.="\t\tbreak;\n";
|
|
}
|
|
|
|
pidl_code "static int";
|
|
pidl_code "$dissectorname(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep, int hf_index, guint32 param _U_)";
|
|
pidl_code "{";
|
|
indent;
|
|
pidl_code "proto_item *item = NULL;";
|
|
pidl_code "proto_tree *tree = NULL;";
|
|
pidl_code "int old_offset;";
|
|
pidl_code "g$e->{SWITCH_TYPE} level;";
|
|
pidl_code "";
|
|
|
|
if ($e->{ALIGN} > 1) {
|
|
pidl_code "ALIGN_TO_$e->{ALIGN}_BYTES;";
|
|
}
|
|
|
|
pidl_code "";
|
|
|
|
pidl_code "old_offset = offset;";
|
|
pidl_code "if(parent_tree){";
|
|
indent;
|
|
pidl_code "item = proto_tree_add_text(parent_tree, tvb, offset, -1, \"$name\");";
|
|
pidl_code "tree = proto_item_add_subtree(item, ett_$ifname\_$name);";
|
|
deindent;
|
|
pidl_code "}";
|
|
|
|
pidl_code "";
|
|
|
|
pidl_code "offset = dissect_ndr_$e->{SWITCH_TYPE}(tvb, offset, pinfo, tree, drep, hf_index, &level);";
|
|
|
|
pidl_code "switch(level) {$res\t}";
|
|
pidl_code "proto_item_set_len(item, offset-old_offset);\n";
|
|
pidl_code "return offset;";
|
|
deindent;
|
|
pidl_code "}";
|
|
|
|
register_type($name, "offset = $dissectorname(tvb, offset, pinfo, tree, drep, \@HF\@, \@PARAM\@);", "FT_NONE", "BASE_NONE", 0, "NULL", 0);
|
|
}
|
|
|
|
sub Const($$)
|
|
{
|
|
my ($const,$ifname) = @_;
|
|
|
|
if (!defined($const->{ARRAY_LEN}[0])) {
|
|
pidl_hdr "#define $const->{NAME}\t( $const->{VALUE} )\n";
|
|
} else {
|
|
pidl_hdr "#define $const->{NAME}\t $const->{VALUE}\n";
|
|
}
|
|
}
|
|
|
|
sub Typedef($$)
|
|
{
|
|
my ($e,$ifname) = @_;
|
|
|
|
PrintIdl DumpTypedef($e->{ORIGINAL});
|
|
|
|
{
|
|
ENUM => \&Enum,
|
|
STRUCT => \&Struct,
|
|
UNION => \&Union,
|
|
BITMAP => \&Bitmap
|
|
}->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $ifname);
|
|
}
|
|
|
|
sub RegisterInterface($)
|
|
{
|
|
my ($x) = @_;
|
|
|
|
pidl_code "void proto_register_dcerpc_$x->{NAME}(void)";
|
|
pidl_code "{";
|
|
indent;
|
|
|
|
$res{code}.=DumpHfList()."\n";
|
|
$res{code}.="\n".DumpEttList()."\n";
|
|
|
|
if (defined($x->{UUID})) {
|
|
# These can be changed to non-pidl_code names if the old dissectors
|
|
# in epan/dissctors are deleted.
|
|
|
|
my $name = "\"" . uc($x->{NAME}) . " (pidl)\"";
|
|
my $short_name = uc($x->{NAME});
|
|
my $filter_name = $x->{NAME};
|
|
|
|
if (has_property($x, "helpstring")) {
|
|
$name = $x->{PROPERTIES}->{helpstring};
|
|
}
|
|
|
|
if (defined($conformance->{protocols}->{$x->{NAME}})) {
|
|
$short_name = $conformance->{protocols}->{$x->{NAME}}->{SHORTNAME};
|
|
$name = $conformance->{protocols}->{$x->{NAME}}->{LONGNAME};
|
|
$filter_name = $conformance->{protocols}->{$x->{NAME}}->{FILTERNAME};
|
|
}
|
|
|
|
pidl_code "proto_dcerpc_$x->{NAME} = proto_register_protocol($name, \"$short_name\", \"$filter_name\");";
|
|
|
|
pidl_code "proto_register_field_array(proto_dcerpc_$x->{NAME}, hf, array_length (hf));";
|
|
pidl_code "proto_register_subtree_array(ett, array_length(ett));";
|
|
} else {
|
|
pidl_code "proto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");";
|
|
pidl_code "proto_register_field_array(proto_dcerpc, hf, array_length(hf));";
|
|
pidl_code "proto_register_subtree_array(ett, array_length(ett));";
|
|
}
|
|
|
|
deindent;
|
|
pidl_code "}\n";
|
|
}
|
|
|
|
sub RegisterInterfaceHandoff($)
|
|
{
|
|
my $x = shift;
|
|
|
|
if (defined($x->{UUID})) {
|
|
pidl_code "void proto_reg_handoff_dcerpc_$x->{NAME}(void)";
|
|
pidl_code "{";
|
|
indent;
|
|
pidl_code "dcerpc_init_uuid(proto_dcerpc_$x->{NAME}, ett_dcerpc_$x->{NAME},";
|
|
pidl_code "\t&uuid_dcerpc_$x->{NAME}, ver_dcerpc_$x->{NAME},";
|
|
pidl_code "\t$x->{NAME}_dissectors, hf_$x->{NAME}_opnum);";
|
|
deindent;
|
|
pidl_code "}";
|
|
}
|
|
}
|
|
|
|
sub ProcessInterface($)
|
|
{
|
|
my ($x) = @_;
|
|
|
|
push(@{$conformance->{strip_prefixes}}, $x->{NAME});
|
|
|
|
my $define = "__PACKET_DCERPC_" . uc($_->{NAME}) . "_H";
|
|
pidl_hdr "#ifndef $define";
|
|
pidl_hdr "#define $define";
|
|
pidl_hdr "";
|
|
|
|
if (defined $x->{PROPERTIES}->{depends}) {
|
|
foreach (split / /, $x->{PROPERTIES}->{depends}) {
|
|
next if($_ eq "security");
|
|
pidl_hdr "#include \"packet-dcerpc-$_\.h\"\n";
|
|
}
|
|
}
|
|
|
|
pidl_def "static gint proto_dcerpc_$x->{NAME} = -1;";
|
|
register_ett("ett_dcerpc_$x->{NAME}");
|
|
register_hf_field("hf_$x->{NAME}_opnum", "Operation", "$x->{NAME}.opnum", "FT_UINT16", "BASE_DEC", "NULL", 0, "");
|
|
register_hf_field("hf_$x->{NAME}_status", "Status", "$x->{NAME}.status", "FT_UINT32", "BASE_HEX", "VALS(NT_errors)", 0, "");
|
|
register_hf_field("hf_$x->{NAME}_werror", "Windows Error", "$x->{NAME}.werror", "FT_UINT32", "BASE_HEX", "NULL", 0, "");
|
|
|
|
if (defined($x->{UUID})) {
|
|
my $if_uuid = $x->{UUID};
|
|
|
|
pidl_def "/* Version information */\n\n";
|
|
|
|
pidl_def "static e_uuid_t uuid_dcerpc_$x->{NAME} = {";
|
|
pidl_def "\t0x" . substr($if_uuid, 1, 8)
|
|
. ", 0x" . substr($if_uuid, 10, 4)
|
|
. ", 0x" . substr($if_uuid, 15, 4) . ",";
|
|
pidl_def "\t{ 0x" . substr($if_uuid, 20, 2)
|
|
. ", 0x" . substr($if_uuid, 22, 2)
|
|
. ", 0x" . substr($if_uuid, 25, 2)
|
|
. ", 0x" . substr($if_uuid, 27, 2)
|
|
. ", 0x" . substr($if_uuid, 29, 2)
|
|
. ", 0x" . substr($if_uuid, 31, 2)
|
|
. ", 0x" . substr($if_uuid, 33, 2)
|
|
. ", 0x" . substr($if_uuid, 35, 2) . " }";
|
|
pidl_def "};";
|
|
|
|
my $maj = $x->{VERSION};
|
|
$maj =~ s/\.(.*)$//g;
|
|
pidl_def "static guint16 ver_dcerpc_$x->{NAME} = $maj;";
|
|
pidl_def "";
|
|
}
|
|
|
|
Interface($x);
|
|
|
|
pidl_code "\n".DumpFunctionTable($x);
|
|
|
|
RegisterInterface($x);
|
|
RegisterInterfaceHandoff($x);
|
|
|
|
pidl_hdr "#endif /* $define */";
|
|
}
|
|
|
|
|
|
sub register_type($$$$$$$)
|
|
{
|
|
my ($type,$call,$ft,$base,$mask,$vals,$length) = @_;
|
|
|
|
$types{$type} = {
|
|
TYPE => $type,
|
|
CALL => $call,
|
|
FT_TYPE => $ft,
|
|
BASE => $base,
|
|
MASK => $mask,
|
|
VALSSTRING => $vals,
|
|
LENGTH => $length
|
|
};
|
|
}
|
|
|
|
# Loads the default types
|
|
sub Initialize($)
|
|
{
|
|
my $cnf_file = shift;
|
|
|
|
$conformance = {};
|
|
|
|
ReadConformance($cnf_file, $conformance) or print "Warning: No conformance file `$cnf_file'\n";
|
|
|
|
foreach my $bytes (qw(1 2 4 8)) {
|
|
my $bits = $bytes * 8;
|
|
register_type("uint$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@,NULL);", "FT_UINT$bits", "BASE_DEC", 0, "NULL", $bytes);
|
|
register_type("int$bits", "offset = dissect_ndr_uint$bits(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_INT$bits", "BASE_DEC", 0, "NULL", $bytes);
|
|
}
|
|
|
|
register_type("udlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);", "FT_UINT64", "BASE_DEC", 0, "NULL", 4);
|
|
register_type("bool8", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
|
|
register_type("char", "offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT8", "BASE_DEC", 0, "NULL", 1);
|
|
register_type("long", "offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT32", "BASE_DEC", 0, "NULL", 4);
|
|
register_type("dlong", "offset = dissect_ndr_duint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_INT64", "BASE_DEC", 0, "NULL", 8);
|
|
register_type("GUID", "offset = dissect_ndr_uuid_t(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_GUID", "BASE_NONE", 0, "NULL", 4);
|
|
register_type("policy_handle", "offset = dissect_nt_policy_hnd(tvb, offset, pinfo, tree, drep, \@HF\@, NULL, NULL, \@PARAM\@&0x01, \@PARAM\@&0x02);","FT_BYTES", "BASE_NONE", 0, "NULL", 4);
|
|
register_type("NTTIME", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
|
|
register_type("NTTIME_hyper", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);","FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
|
|
register_type("time_t", "offset = dissect_ndr_time_t(tvb, offset, pinfo,tree, drep, \@HF\@, NULL);","FT_ABSOLUTE_TIME", "BASE_DEC", 0, "NULL", 4);
|
|
register_type("NTTIME_1sec", "offset = dissect_ndr_nt_NTTIME(tvb, offset, pinfo, tree, drep, \@HF\@);", "FT_ABSOLUTE_TIME", "BASE_NONE", 0, "NULL", 4);
|
|
register_type("SID", "
|
|
dcerpc_info *di = (dcerpc_info *)pinfo->private_data;
|
|
|
|
di->hf_index = \@HF\@;
|
|
|
|
offset = dissect_ndr_nt_SID_with_options(tvb, offset, pinfo, tree, drep, param);
|
|
","FT_STRING", "BASE_DEC", 0, "NULL", 4);
|
|
register_type("WERROR",
|
|
"offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, \@HF\@, NULL);","FT_UINT32", "BASE_DEC", 0, "VALS(NT_errors)", 4);
|
|
|
|
}
|
|
|
|
#####################################################################
|
|
# Generate ethereal parser and header code
|
|
sub Parse($$$$)
|
|
{
|
|
my($ndr,$idl_file,$h_filename,$cnf_file) = @_;
|
|
Initialize($cnf_file);
|
|
|
|
$tabs = "";
|
|
|
|
%res = (code=>"",def=>"",hdr=>"");
|
|
%hf = ();
|
|
@ett = ();
|
|
|
|
my $notice =
|
|
"/* DO NOT EDIT
|
|
This filter was automatically generated
|
|
from $idl_file and $cnf_file.
|
|
|
|
Pidl is a perl based IDL compiler for DCE/RPC idl files.
|
|
It is maintained by the Samba team, not the Ethereal team.
|
|
Instructions on how to download and install Pidl can be
|
|
found at http://wiki.ethereal.com/Pidl
|
|
*/
|
|
|
|
";
|
|
|
|
pidl_hdr $notice;
|
|
|
|
$res{headers} = "\n";
|
|
$res{headers} .= "#ifdef HAVE_CONFIG_H\n";
|
|
$res{headers} .= "#include \"config.h\"\n";
|
|
$res{headers} .= "#endif\n\n";
|
|
$res{headers} .= "#include <glib.h>\n";
|
|
$res{headers} .= "#include <string.h>\n";
|
|
$res{headers} .= "#include <epan/packet.h>\n\n";
|
|
|
|
$res{headers} .= "#include \"packet-dcerpc.h\"\n";
|
|
$res{headers} .= "#include \"packet-dcerpc-nt.h\"\n";
|
|
$res{headers} .= "#include \"packet-windows-common.h\"\n";
|
|
|
|
use File::Basename;
|
|
my $h_basename = basename($h_filename);
|
|
|
|
$res{headers} .= "#include \"$h_basename\"\n";
|
|
pidl_code "";
|
|
|
|
# Ethereal protocol registration
|
|
|
|
ProcessInterface($_) foreach (@$ndr);
|
|
|
|
$res{ett} = DumpEttDeclaration();
|
|
$res{hf} = DumpHfDeclaration();
|
|
|
|
my $parser = $notice;
|
|
$parser.= $res{headers};
|
|
$parser.=$res{ett};
|
|
$parser.=$res{hf};
|
|
$parser.=$res{def};
|
|
$parser.=$conformance->{override};
|
|
$parser.=$res{code};
|
|
|
|
my $header = "/* autogenerated by pidl */\n\n";
|
|
$header.=$res{hdr};
|
|
|
|
return ($parser,$header);
|
|
}
|
|
|
|
###############################################################################
|
|
# ETT
|
|
###############################################################################
|
|
|
|
sub register_ett($)
|
|
{
|
|
my $name = shift;
|
|
|
|
push (@ett, $name);
|
|
}
|
|
|
|
sub DumpEttList()
|
|
{
|
|
my $res = "\tstatic gint *ett[] = {\n";
|
|
foreach (@ett) {
|
|
$res .= "\t\t&$_,\n";
|
|
}
|
|
|
|
return "$res\t};\n";
|
|
}
|
|
|
|
sub DumpEttDeclaration()
|
|
{
|
|
my $res = "\n/* Ett declarations */\n";
|
|
foreach (@ett) {
|
|
$res .= "static gint $_ = -1;\n";
|
|
}
|
|
|
|
return "$res\n";
|
|
}
|
|
|
|
###############################################################################
|
|
# HF
|
|
###############################################################################
|
|
|
|
sub register_hf_field($$$$$$$$)
|
|
{
|
|
my ($index,$name,$filter_name,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
|
|
|
|
return $conformance->{hf_renames}->{$index} if defined ($conformance->{hf_renames}->{$index});
|
|
|
|
$hf{$index} = {
|
|
INDEX => $index,
|
|
NAME => $name,
|
|
FILTER => $filter_name,
|
|
FT_TYPE => $ft_type,
|
|
BASE_TYPE => $base_type,
|
|
VALS => $valsstring,
|
|
MASK => $mask,
|
|
BLURB => $blurb
|
|
};
|
|
|
|
return $index;
|
|
}
|
|
|
|
sub DumpHfDeclaration()
|
|
{
|
|
my $res = "";
|
|
|
|
$res = "\n/* Header field declarations */\n";
|
|
|
|
foreach (keys %hf)
|
|
{
|
|
$res .= "static gint $_ = -1;\n";
|
|
}
|
|
|
|
return "$res\n";
|
|
}
|
|
|
|
sub DumpHfList()
|
|
{
|
|
my $res = "\tstatic hf_register_info hf[] = {\n";
|
|
|
|
foreach (values %hf)
|
|
{
|
|
$res .= "\t{ &$_->{INDEX},
|
|
{ \"$_->{NAME}\", \"$_->{FILTER}\", $_->{FT_TYPE}, $_->{BASE_TYPE}, $_->{VALS}, $_->{MASK}, \"$_->{BLURB}\", HFILL }},
|
|
";
|
|
}
|
|
|
|
return $res."\t};\n";
|
|
}
|
|
|
|
|
|
###############################################################################
|
|
# Function table
|
|
###############################################################################
|
|
|
|
sub DumpFunctionTable($)
|
|
{
|
|
my $if = shift;
|
|
|
|
my $res = "static dcerpc_sub_dissector $if->{NAME}\_dissectors[] = {\n";
|
|
foreach (@{$if->{FUNCTIONS}}) {
|
|
my $fn_name = $_->{NAME};
|
|
$fn_name =~ s/^$if->{NAME}_//;
|
|
$res.= "\t{ $_->{OPNUM}, \"$fn_name\",\n";
|
|
$res.= "\t $if->{NAME}_dissect_${fn_name}_request, $if->{NAME}_dissect_${fn_name}_response},\n";
|
|
}
|
|
|
|
$res .= "\t{ 0, NULL, NULL, NULL }\n";
|
|
|
|
return "$res};\n";
|
|
}
|
|
|
|
1;
|