summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/build/pidl/eparser.pm376
-rwxr-xr-xsource4/build/pidl/pidl.pl26
2 files changed, 335 insertions, 67 deletions
diff --git a/source4/build/pidl/eparser.pm b/source4/build/pidl/eparser.pm
index a6f44b5b14..09e2855e23 100644
--- a/source4/build/pidl/eparser.pm
+++ b/source4/build/pidl/eparser.pm
@@ -689,47 +689,17 @@ sub ParseFunctionPull($)
my($fn) = shift;
my $static = fn_prefix($fn);
- pidl "/*\n\n";
- pidl IdlDump::DumpFunction($fn);
- pidl "*/\n\n";
-
# request function
pidl "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n";
- pidl "\tstruct ndr_pull *ndr = ndr_pull_init(tvb, offset, pinfo, drep);\n";
- pidl "\tstruct $fn->{NAME} *r = (struct $fn->{NAME} *)g_malloc(sizeof(struct $fn->{NAME}));\n\n";
-
- # declare any internal pointers we need
- foreach my $e (@{$fn->{DATA}}) {
- if (util::need_wire_pointer($e) &&
- util::has_property($e, "in")) {
- pidl "\tuint32_t _ptr_$e->{NAME};\n";
- }
- }
-
- pidl "\n\tZERO_STRUCTP(r);\n\n";
+ pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n";
+ pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n";
+ pidl "\tpidl_tree ptree;\n\n";
- # auto-init the out section of a structure. I originally argued that
- # this was a bad idea as it hides bugs, but coping correctly
- # with initialisation and not wiping ref vars is turning
- # out to be too tricky (tridge)
- foreach my $e (@{$fn->{DATA}}) {
- if (util::has_property($e, "out")) {
- pidl "\tZERO_STRUCT(r->out);\n\n";
- last;
- }
- }
+ pidl "\tptree.proto_tree = tree;\n";
+ pidl "\tptree.subtree_list = NULL;\n\n";
- foreach my $e (@{$fn->{DATA}}) {
- if (util::has_property($e, "in")) {
- ParseFunctionElementPull($e, "in");
- }
- # we need to allocate any reference output variables, so that
- # a dcerpc backend can be sure they are non-null
- if (util::has_property($e, "out") && util::has_property($e, "ref")) {
- AllocateRefVars($e);
- }
- }
+ pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_IN, &ptree, r);\n";
pidl "\n\treturn ndr->offset;\n";
pidl "}\n\n";
@@ -737,28 +707,14 @@ sub ParseFunctionPull($)
# response function
pidl "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n";
- pidl "\tstruct ndr_pull *ndr = ndr_pull_init(tvb, offset, pinfo, drep);\n";
- pidl "\tstruct $fn->{NAME} *r = (struct $fn->{NAME} *)g_malloc(sizeof(struct $fn->{NAME}));\n\n";
-
- # declare any internal pointers we need
- foreach my $e (@{$fn->{DATA}}) {
- if (util::need_wire_pointer($e) &&
- util::has_property($e, "out")) {
- pidl "\tuint32_t _ptr_$e->{NAME};\n";
- }
- }
-
- pidl "\tZERO_STRUCTP(r);\n\n";
+ pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n";
+ pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n";
+ pidl "\tpidl_tree ptree;\n\n";
- foreach my $e (@{$fn->{DATA}}) {
- if (util::has_property($e, "out")) {
- ParseFunctionElementPull($e, "out");
- }
- }
+ pidl "\tptree.proto_tree = tree;\n";
+ pidl "\tptree.subtree_list = NULL;\n\n";
- if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
- pidl "\tndr_pull_$fn->{RETURN_TYPE}(ndr, tree, hf_rc, &r->out.result);\n";
- }
+ pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_OUT, &ptree, r);\n";
pidl "\n\treturn ndr->offset;\n";
pidl "}\n\n";
@@ -809,7 +765,6 @@ sub ParseInterface($)
}
FunctionTable($interface);
-
}
sub type2ft($)
@@ -990,7 +945,7 @@ sub ParseHeader($$)
#####################################################################
# parse a parsed IDL structure back into an IDL file
-sub Parse($$)
+sub OldParse($$)
{
my($idl) = shift;
my($filename) = shift;
@@ -1132,4 +1087,309 @@ sub Parse($$)
close(OUT);
}
+#####################################################################
+# rewrite autogenerated header file
+sub RewriteHeader($$$)
+{
+ my($idl) = shift;
+ my($input) = shift;
+ my($output) = shift;
+
+ %needed = ();
+
+ # Open files
+
+ open(IN, "<$input") || die "can't open $input for reading";
+ open(OUT, ">$output") || die "can't open $output for writing";
+
+ # Read in entire file
+
+ undef $/;
+
+ while(<IN>) {
+
+ # Not interested in ndr_push or ndr_print routines as they
+ # define structures we aren't interested in.
+
+ s/^NTSTATUS ndr_push.*?;\n//smg;
+ s/^void ndr_print.*?;\n//smg;
+
+ # Get rid of async send and receive function.
+
+ s/^NTSTATUS dcerpc_.*?;\n//smg;
+ s/^struct rpc_request.*?;\n\n//smg;
+
+ # Rewrite librpc includes
+
+ s/^\#include \"librpc\/gen_ndr\/ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg;
+
+ # Convert samba fixed width types to stdint types
+
+ s/((u)?int)([0-9]+)/$1$3_t/smg;
+
+ # Rename struct ndr_pull to struct pidl_pull
+
+ s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg;
+
+ # Change prototypes for public functions
+
+ s/(struct pidl_pull \*ndr, int ndr_flags)/$1, pidl_tree *tree/smg;
+
+ pidl $_;
+ }
+
+ close(OUT);
+}
+
+#####################################################################
+# rewrite autogenerated C file
+sub RewriteC($$$)
+{
+ my($idl) = shift;
+ my($input) = shift;
+ my($output) = shift;
+
+ # Open files
+
+ open(IN, "<$input") || die "can't open $input for reading";
+ open(OUT, ">$output") || die "can't open $output for writing";
+
+ # Get name of module
+
+ foreach my $x (@{$idl}) {
+ if ($x->{TYPE} eq "INTERFACE") {
+ ModuleHeader($x);
+ $module = $x->{NAME};
+ BuildNeeded($x);
+ }
+ }
+
+ pidl "#include \"eparser.h\"\n\n";
+
+ pidl "extern const value_string NT_errors[];\n\n";
+
+ # Declarations for hf variables
+
+ pidl "static int hf_opnum = -1;\n";
+ pidl "static int hf_ptr = -1;\n";
+ pidl "static int hf_array_size = -1;\n";
+ pidl "static int hf_result_NTSTATUS = -1;\n";
+
+ foreach my $y (keys(%needed)) {
+ pidl "static int $y = -1;\n", if $y =~ /^hf_/;
+ }
+
+ pidl "\n";
+
+ foreach my $y (keys(%needed)) {
+ pidl "static gint $y = -1;\n", if $y =~ /^ett_/;
+ }
+
+ pidl "\n";
+
+ # Read in entire file for post-processing
+
+ undef $/;
+
+ while(<IN>) {
+
+ # Ethereal take care of this for us. It also makes the other
+ # regular expressions easier to write and understand.
+
+ s/NDR_CHECK\((.*)\)/$1/g;
+
+ # We're not interested in ndr_print or ndr_push functions.
+
+ s/^(static )?NTSTATUS (ndr_push[^\(]+).*?^\}\n\n//smg;
+ s/^void (ndr_print[^\(]+).*?^\}\n\n//smg;
+
+ # Get rid of dcerpc interface structures and functions
+
+ s/^static const struct dcerpc_interface_call .*?^\};\n\n//smg;
+ s/^static const char \* const ([a-z]+)_endpoint_strings.*?^\};\n\n//smg;
+ s/^static const struct dcerpc_endpoint_list .*?^\};\n\n\n//smg;
+ s/^const struct dcerpc_interface_table .*?^\};\n\n//smg;
+ s/^static NTSTATUS dcerpc_ndr_([a-z]+)_init.*?^\}\n\n//smg;
+ s/^NTSTATUS dcerpc_([a-z]+)_init.*?^\}\n\n//smg;
+
+ # Include packet-dcerpc-foo.h instead of ndr_foo.h
+
+ s/^\#include \".*?ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg;
+
+ # Call ethereal wrapper for ndr_pull_ptr() function.
+
+ s/(ndr_pull_ptr\(ndr, ([^\)]*?)\);)/ndr_pull_ptr(ndr, tree, hf_ptr, $2);/smg;
+
+ # Wrap ndr_pull_array_size() - generate wrapper that won't get
+ # caught by the regex for wrapping scalar values below (i.e
+ # the leading space in front of the first parameter).
+
+ s/(ndr_pull_array_size\(ndr, ([^\)]*?)\);)/ndr_pull_array_size( ndr, tree, $2);/smg;
+
+ # Add tree argument to ndr_pull_array()
+
+ s/(ndr_pull_array([^\(]*?)\(ndr, (NDR_[^,]*?), ([^\)].*?)\);)/ndr_pull_array$2( ndr, $3, tree, $4);/smg;
+
+
+ # Call ethereal wrappers for pull of scalar values in
+ # structures and functions:
+ #
+ # ndr_pull_uint32(ndr, &r->in.access_mask);
+ # ndr_pull_uint32(ndr, &r->idx);
+
+ s/(ndr_pull_([^\)]*?)\(ndr, (&?r->((in|out)\.)?([^\)]*?))\);)/ndr_pull_$2(ndr, tree, hf_$6_$2, $3);/smg;
+
+ # Pull of "internal" scalars like array sizes, levels, etcetera.
+
+ s/(ndr_pull_(uint32|uint16)\(ndr, (&_([^\)]*?))\);)/ndr_pull_$2(ndr, tree, hf_$4, $3);/smg;
+
+ # Call ethereal wrappers for pull of buffers in structures and
+ # functions:
+ #
+ # ndr_pull_string(ndr, NDR_SCALARS|NDR_BUFFERS, &r->command);
+ # ndr_pull_atsvc_enum_ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr);
+
+ s/(ndr_pull_([^\)]*?)\(ndr, (NDR_[^,]*?), ([^\(].*?)\);)/ndr_pull_$2(ndr, $3, get_subtree(tree, \"$2\", ndr, ett_$2), $4);/smg;
+
+ # Add proto_tree parameter to pull functions:
+ #
+ # static NTSTATUS ndr_pull_atsvc_JobInfo(struct ndr_pull *ndr, int ndr_flags, struct atsvc_JobInfo *r)
+
+ s/^((static )?NTSTATUS ndr_pull_([^\(]*?)\(struct ndr_pull \*ndr, int (ndr_)?flags)/$1, proto_tree \*tree/smg;
+
+ # Get rid of ndr_pull_error() calls. Ethereal should take
+ # care of buffer overruns and inconsistent array sizes for us.
+
+ s/(return ndr_pull_error([^;]*?);)/return NT_STATUS_OK; \/\/ $1/smg;
+
+ # Rename proto_tree args to pidl_tree
+
+ s/(int (ndr_)?flags), proto_tree \*tree/$1, pidl_tree \*tree/smg;
+
+ # Rename struct ndr_pull to struct pidl_pull
+
+ s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg;
+
+ pidl $_;
+ }
+
+ # Function call table
+
+ foreach my $x (@{$idl}) {
+ if ($x->{TYPE} eq "INTERFACE") {
+ foreach my $y (@{$x->{"INHERITED_DATA"}}) {
+ ($y->{TYPE} eq "FUNCTION") && ParseFunctionPull($y);
+ }
+
+ FunctionTable($x);
+ }
+ }
+
+ # Ethereal protocol registration
+
+ pidl "int proto_dcerpc_pidl_$module = -1;\n\n";
+
+ pidl "static gint ett_dcerpc_$module = -1;\n\n";
+
+ if (defined($if_uuid)) {
+
+ pidl "static e_uuid_t uuid_dcerpc_$module = {\n";
+ pidl "\t0x" . substr($if_uuid, 1, 8);
+ pidl ", 0x" . substr($if_uuid, 10, 4);
+ pidl ", 0x" . substr($if_uuid, 15, 4) . ",\n";
+ pidl "\t{ 0x" . substr($if_uuid, 20, 2);
+ pidl ", 0x" . substr($if_uuid, 22, 2);
+ pidl ", 0x" . substr($if_uuid, 25, 2);
+ pidl ", 0x" . substr($if_uuid, 27, 2);
+ pidl ", 0x" . substr($if_uuid, 29, 2);
+ pidl ", 0x" . substr($if_uuid, 31, 2);
+ pidl ", 0x" . substr($if_uuid, 33, 2);
+ pidl ", 0x" . substr($if_uuid, 35, 2) . " }\n";
+ pidl "};\n\n";
+ }
+
+ if (defined($if_version)) {
+ pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n";
+ }
+
+ pidl "void proto_register_dcerpc_pidl_$module(void)\n";
+ pidl "{\n";
+
+ pidl "\tstatic hf_register_info hf[] = {\n";
+ pidl "\t{ &hf_opnum, { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},\n";
+ pidl "\t{ &hf_result_NTSTATUS, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},\n";
+ pidl "\t{ &hf_ptr, { \"Pointer\", \"$module.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},\n";
+
+ foreach my $x (keys(%needed)) {
+ next, if !($x =~ /^hf_/);
+ pidl "\t{ &$x,\n";
+ pidl "\t { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base}, NULL, 0, \"$x\", HFILL }},\n";
+ }
+
+ pidl "\t};\n\n";
+
+ pidl "\tstatic gint *ett[] = {\n";
+ pidl "\t\t&ett_dcerpc_$module,\n";
+ foreach my $x (keys(%needed)) {
+ pidl "\t\t&$x,\n", if $x =~ /^ett_/;
+ }
+ pidl "\t};\n\n";
+
+ if (defined($if_uuid)) {
+
+ pidl "\tproto_dcerpc_pidl_$module = proto_register_protocol(\"pidl_$module\", \"pidl_$module\", \"pidl_$module\");\n\n";
+
+ pidl "\tproto_register_field_array(proto_dcerpc_pidl_$module, hf, array_length (hf));\n";
+ pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
+
+ pidl "}\n\n";
+
+ pidl "void proto_reg_handoff_dcerpc_pidl_$module(void)\n";
+ pidl "{\n";
+ pidl "\tdcerpc_init_uuid(proto_dcerpc_pidl_$module, ett_dcerpc_$module, \n";
+ pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n";
+ pidl "\t\tdcerpc_dissectors, hf_opnum);\n";
+ pidl "}\n";
+
+ } else {
+
+ pidl "\tint proto_dcerpc;\n\n";
+ pidl "\tproto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");\n";
+ pidl "\tproto_register_field_array(proto_dcerpc, hf, array_length(hf));\n";
+ pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
+
+ pidl "}\n";
+
+ }
+
+ close(OUT);
+}
+
+#####################################################################
+# parse a parsed IDL structure back into an IDL file
+sub Parse($$)
+{
+ my($idl) = shift;
+ my($filename) = shift;
+
+ %needed = (); # Clear after generating header file
+
+ open(OUT, ">$filename") || die "can't open $filename";
+
+ # Look for name of module
+
+ foreach my $x (@{$idl}) {
+
+ if ($x->{TYPE} eq "INTERFACE") {
+ ModuleHeader($x);
+ $module = $x->{NAME};
+ BuildNeeded($x);
+ }
+ }
+
+ pidl "/* parser auto-generated by pidl */\n\n";
+
+ close(OUT);
+}
+
1;
diff --git a/source4/build/pidl/pidl.pl b/source4/build/pidl/pidl.pl
index c430c75236..6d0ff69081 100755
--- a/source4/build/pidl/pidl.pl
+++ b/source4/build/pidl/pidl.pl
@@ -205,15 +205,23 @@ $dcom
}
if ($opt_eparser) {
- my($parser) = dirname($output) . "/packet-dcerpc-$basename.c";
- IdlEParser::Parse($pidl, $parser);
- $parser = dirname($output) . "/packet-dcerpc-proto-$basename.h";
- IdlEParser::ParseHeader($pidl, $parser);
- my($header) = dirname($output) . "/packet-dcerpc-proto.h";
- open(OUT, ">>$header") || die "can't open $header";
- print OUT "#include \"ndr_$basename.h\"\n";
- print OUT "#include \"packet-dcerpc-proto-$basename.h\"\n";
- close(OUT);
+
+ # Generate regular .c and .h files for marshaling and
+ # unmarshaling.
+
+ my($parser) = util::ChangeExtension($output, ".c");
+ IdlParser::Parse($pidl, $parser);
+
+ my($header) = util::ChangeExtension($output, ".h");
+ util::FileSave($header, IdlHeader::Parse($pidl));
+
+ # Postprocess to produce ethereal parsers.
+
+ my($eparser) = dirname($output) . "/packet-dcerpc-$basename.c";
+ IdlEParser::RewriteC($pidl, $parser, $eparser);
+
+ my($eparserhdr) = dirname($output) . "/packet-dcerpc-$basename.h";
+ IdlEParser::RewriteHeader($pidl, $header, $eparserhdr);
}
if ($opt_swig) {