diff options
Diffstat (limited to 'source4/build/pidl')
-rw-r--r-- | source4/build/pidl/eparser.pm | 376 | ||||
-rwxr-xr-x | source4/build/pidl/pidl.pl | 26 |
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) { |