1 ###################################################
2 # Samba4 parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001,2004
5 # released under the GNU GPL
11 # the list of needed functions
24 #####################################################################
25 # work out is a parse function should be declared static or not
29 if ($fn->{TYPE} eq "TYPEDEF") {
30 if (util::has_property($fn->{DATA}, "public")) {
35 if ($fn->{TYPE} eq "FUNCTION") {
36 if (util::has_property($fn, "public")) {
44 #####################################################################
46 sub ParseFunctionPull($)
49 my $static = fn_prefix($fn);
52 pidl "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n";
54 pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n";
55 pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n";
56 pidl "\tpidl_tree ptree;\n\n";
58 pidl "\tptree.proto_tree = tree;\n";
59 pidl "\tptree.subtree_list = NULL;\n\n";
61 pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_IN, &ptree, r);\n";
63 pidl "\n\treturn ndr->offset;\n";
67 pidl "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n";
69 pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n";
70 pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n";
71 pidl "\tpidl_tree ptree;\n\n";
73 pidl "\tptree.proto_tree = tree;\n";
74 pidl "\tptree.subtree_list = NULL;\n\n";
76 pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_OUT, &ptree, r);\n";
78 pidl "\n\treturn ndr->offset;\n";
82 #####################################################################
83 # produce a function call table
86 my($interface) = shift;
87 my($data) = $interface->{DATA};
89 pidl "static dcerpc_sub_dissector dcerpc_dissectors[] = {\n";
91 foreach my $d (@{$data}) {
92 if ($d->{TYPE} eq "FUNCTION") {
93 # Strip module name from function name, if present
95 $n = substr($d->{NAME}, length($module) + 1),
96 if $module eq substr($d->{NAME}, 0, length($module));
97 pidl "\t{ $num, \"$n\",\n";
98 pidl "\t\t$d->{NAME}_rqst,\n";
99 pidl "\t\t$d->{NAME}_resp },\n";
110 return "FT_UINT32", if ($t eq "uint32");
111 return "FT_UINT16", if ($t eq "uint16");
112 return "FT_UINT8", if ($t eq "uint8");
116 # Determine the display base for an element
122 if (my $base = util::has_property($e, "display")) {
123 return "BASE_" . uc($base);
126 return "BASE_DEC", if ($e->{TYPE} eq "uint32") or
127 ($e->{TYPE} eq "uint16") or ($e->{TYPE} eq "uint8");
131 # Convert a IDL structure field name (e.g access_mask) to a prettier
132 # string like 'Access Mask'.
138 $field =~ s/_/ /g; # Replace underscores with spaces
139 $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
144 sub NeededFunction($)
147 $needed{"pull_$fn->{NAME}"} = 1;
148 foreach my $e (@{$fn->{DATA}}) {
150 $needed{"pull_$e->{TYPE}"} = 1;
152 if (util::is_scalar_type($e->{TYPE})) {
153 $needed{"hf_$e->{NAME}_$e->{TYPE}"} = {
154 'name' => field2name($e->{NAME}),
155 'type' => $e->{TYPE},
156 'ft' => type2ft($e->{TYPE}),
157 'base' => elementbase($e)
158 }, if !defined($needed{"hf_$e->{NAME}_$e->{TYPE}"});
161 $needed{"ett_$e->{TYPE}"} = 1;
169 if (util::has_property($t->{DATA}, "public")) {
170 $needed{"pull_$t->{NAME}"} = 1;
173 if ($t->{DATA}->{TYPE} eq "STRUCT") {
175 for my $e (@{$t->{DATA}->{ELEMENTS}}) {
176 $e->{PARENT} = $t->{DATA};
177 if ($needed{"pull_$t->{NAME}"}) {
178 $needed{"pull_$e->{TYPE}"} = 1;
181 if (util::is_scalar_type($e->{TYPE})) {
183 if (defined($e->{ARRAY_LEN}) or
184 util::has_property($e, "size_is")) {
186 # Arrays of scalar types are FT_BYTES
188 $needed{"hf_$e->{NAME}_$e->{TYPE}_array"} = {
189 'name' => field2name($e->{NAME}),
190 'type' => $e->{TYPE},
192 'base' => elementbase($e)
196 $needed{"hf_$e->{NAME}_$e->{TYPE}"} = {
197 'name' => field2name($e->{NAME}),
198 'type' => $e->{TYPE},
199 'ft' => type2ft($e->{TYPE}),
200 'base' => elementbase($e)
204 $e->{PARENT} = $t->{DATA};
206 if ($needed{"pull_$t->{NAME}"}) {
207 $needed{"pull_$e->{TYPE}"} = 1;
212 $needed{"ett_$e->{TYPE}"} = 1;
218 if ($t->{DATA}->{TYPE} eq "UNION") {
219 for my $e (@{$t->{DATA}->{DATA}}) {
220 $e->{PARENT} = $t->{DATA};
221 if ($e->{TYPE} eq "UNION_ELEMENT") {
222 if ($needed{"pull_$t->{NAME}"}) {
223 $needed{"pull_$e->{DATA}->{TYPE}"} = 1;
225 $needed{"ett_$e->{DATA}{TYPE}"} = 1;
229 $needed{"ett_$t->{NAME}"} = 1;
233 #####################################################################
234 # work out what parse functions are needed
237 my($interface) = shift;
238 my($data) = $interface->{DATA};
239 foreach my $d (@{$data}) {
240 ($d->{TYPE} eq "FUNCTION") &&
243 foreach my $d (reverse @{$data}) {
244 ($d->{TYPE} eq "TYPEDEF") &&
249 #####################################################################
250 # parse the interface definitions
255 $if_uuid = $h->{PROPERTIES}->{uuid};
256 $if_version = $h->{PROPERTIES}->{version};
257 $if_endpoints = $h->{PROPERTIES}->{endpoints};
260 #####################################################################
261 # Generate a header file that contains function prototypes for
262 # structs and typedefs.
266 my($filename) = shift;
268 open(OUT, ">$filename") || die "can't open $filename";
270 pidl "/* parser auto-generated by pidl */\n\n";
272 foreach my $x (@{$idl}) {
273 if ($x->{TYPE} eq "INTERFACE") {
274 foreach my $d (@{$x->{DATA}}) {
276 # Make prototypes for [public] structures and
279 if ($d->{TYPE} eq "TYPEDEF" and
280 util::has_property($d->{DATA}, "public")) {
282 if ($d->{DATA}{TYPE} eq "STRUCT") {
283 pidl "void ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, proto_tree *tree, struct $d->{NAME} *r);\n\n";
286 if ($d->{DATA}{TYPE} eq "UNION") {
287 pidl "void ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, proto_tree *tree, union $d->{NAME} *r, uint16 level);\n\n";
297 #####################################################################
298 # rewrite autogenerated header file
299 sub RewriteHeader($$$)
309 open(IN, "<$input") || die "can't open $input for reading";
310 open(OUT, ">$output") || die "can't open $output for writing";
312 # Read in entire file
318 # Not interested in ndr_push or ndr_print routines as they
319 # define structures we aren't interested in.
321 s/^NTSTATUS ndr_push.*?;\n//smg;
322 s/^void ndr_print.*?;\n//smg;
324 # Get rid of async send and receive function.
326 s/^NTSTATUS dcerpc_.*?;\n//smg;
327 s/^struct rpc_request.*?;\n\n//smg;
329 # Rewrite librpc includes
331 s/^\#include \"librpc\/gen_ndr\/ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg;
333 # Convert samba fixed width types to stdint types
335 s/((u)?int)([0-9]+)/$1$3_t/smg;
337 # Rename struct ndr_pull to struct pidl_pull
339 s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg;
341 # Change prototypes for public functions
343 s/(struct pidl_pull \*ndr, int ndr_flags)/$1, pidl_tree *tree/smg;
351 #####################################################################
352 # rewrite autogenerated C file
361 open(IN, "<$input") || die "can't open $input for reading";
362 open(OUT, ">$output") || die "can't open $output for writing";
366 foreach my $x (@{$idl}) {
367 if ($x->{TYPE} eq "INTERFACE") {
369 $module = $x->{NAME};
374 pidl "#include \"eparser.h\"\n\n";
376 pidl "extern const value_string NT_errors[];\n\n";
378 # Declarations for hf variables
380 pidl "static int hf_opnum = -1;\n";
381 pidl "static int hf_ptr = -1;\n";
382 pidl "static int hf_array_size = -1;\n";
383 pidl "static int hf_result_NTSTATUS = -1;\n";
385 foreach my $y (keys(%needed)) {
386 pidl "static int $y = -1;\n", if $y =~ /^hf_/;
391 foreach my $y (keys(%needed)) {
392 pidl "static gint $y = -1;\n", if $y =~ /^ett_/;
397 # Read in entire file for post-processing
403 # Ethereal take care of this for us. It also makes the other
404 # regular expressions easier to write and understand.
406 s/NDR_CHECK\((.*)\)/$1/g;
408 # We're not interested in ndr_print or ndr_push functions.
410 s/^(static )?NTSTATUS (ndr_push[^\(]+).*?^\}\n\n//smg;
411 s/^void (ndr_print[^\(]+).*?^\}\n\n//smg;
413 # Get rid of dcerpc interface structures and functions
415 s/^static const struct dcerpc_interface_call .*?^\};\n\n//smg;
416 s/^static const char \* const ([a-z]+)_endpoint_strings.*?^\};\n\n//smg;
417 s/^static const struct dcerpc_endpoint_list .*?^\};\n\n\n//smg;
418 s/^const struct dcerpc_interface_table .*?^\};\n\n//smg;
419 s/^static NTSTATUS dcerpc_ndr_([a-z]+)_init.*?^\}\n\n//smg;
420 s/^NTSTATUS dcerpc_([a-z]+)_init.*?^\}\n\n//smg;
422 # Include packet-dcerpc-foo.h instead of ndr_foo.h
424 s/^\#include \".*?ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg;
426 # Call ethereal wrapper for ndr_pull_ptr() function.
428 s/(ndr_pull_ptr\(ndr, ([^\)]*?)\);)/ndr_pull_ptr(ndr, tree, hf_ptr, $2);/smg;
430 # Wrap ndr_pull_array_size() - generate wrapper that won't get
431 # caught by the regex for wrapping scalar values below (i.e
432 # the leading space in front of the first parameter).
434 s/(ndr_pull_array_(size|length)\(ndr, ([^\)]*?)\);)/ndr_pull_array_$2( ndr, tree, $3);/smg;
436 # Add tree argument to ndr_pull_array()
438 s/(ndr_pull_array([^\(_]*?)\(ndr, (NDR_[^,]*?), ([^\)].*?)\);)/ndr_pull_array$2( ndr, $3, tree, $4);/smg;
440 s/(ndr_pull_array_([^\(]*?)\(ndr, (NDR_[^,]*?), (r->((in|out).)?([^,]*?)), (.*?)\);)/ndr_pull_array_$2( ndr, $3, tree, hf_$7_$2_array, $4, $8);/smg;
442 # Save ndr_pull_relative[12]() calls from being wrapped by the
445 s/ndr_pull_(relative1|relative2)\((.*?);/ndr_pull_$1( $2;/smg;
447 # Call ethereal wrappers for pull of scalar values in
448 # structures and functions:
450 # ndr_pull_uint32(ndr, &r->in.access_mask);
451 # ndr_pull_uint32(ndr, &r->idx);
453 s/(ndr_pull_([^\)]*?)\(ndr, (&?r->((in|out)\.)?([^\)]*?))\);)/ndr_pull_$2(ndr, tree, hf_$6_$2, $3);/smg;
455 # Pull of "internal" scalars like array sizes, levels, etcetera.
457 s/(ndr_pull_(uint32|uint16)\(ndr, (&_([^\)]*?))\);)/ndr_pull_$2(ndr, tree, hf_$4, $3);/smg;
459 # Call ethereal wrappers for pull of buffers in structures and
462 # ndr_pull_string(ndr, NDR_SCALARS|NDR_BUFFERS, &r->command);
463 # ndr_pull_atsvc_enum_ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr);
465 s/(ndr_pull_([^\)]*?)\(ndr, (NDR_[^,]*?), ([^\(].*?)\);)/ndr_pull_$2(ndr, $3, get_subtree(tree, \"$2\", ndr, ett_$2), $4);/smg;
467 # Add proto_tree parameter to pull functions:
469 # static NTSTATUS ndr_pull_atsvc_JobInfo(struct ndr_pull *ndr, int ndr_flags, struct atsvc_JobInfo *r)
471 s/^((static )?NTSTATUS ndr_pull_([^\(]*?)\(struct ndr_pull \*ndr, int (ndr_)?flags)/$1, proto_tree \*tree/smg;
473 # Add proto_tree parameter to ndr_pull_subcontext_flags_fn()
475 s/(ndr_pull_subcontext_flags_fn\(ndr)(.*?);/$1, tree$2;/smg;
477 # Get rid of ndr_pull_error() calls. Ethereal should take
478 # care of buffer overruns and inconsistent array sizes for us.
480 s/(return ndr_pull_error([^;]*?);)/return NT_STATUS_OK; \/\/ $1/smg;
482 # Rename proto_tree args to pidl_tree
484 s/(int (ndr_)?flags), proto_tree \*tree/$1, pidl_tree \*tree/smg;
486 # Rename struct ndr_pull to struct pidl_pull
488 s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg;
490 # Fix some internal variable declarations
492 s/uint(16|32) _level/uint$1_t _level/smg;
493 s/ndr_pull_([^\(]*)\(ndr, tree, hf_level, &_level\);/ndr_pull_$1(ndr, tree, hf_level_$1, &_level);/smg;
498 # Function call table
500 foreach my $x (@{$idl}) {
501 if ($x->{TYPE} eq "INTERFACE") {
502 foreach my $y (@{$x->{"INHERITED_DATA"}}) {
503 ($y->{TYPE} eq "FUNCTION") && ParseFunctionPull($y);
510 # Ethereal protocol registration
512 pidl "int proto_dcerpc_pidl_$module = -1;\n\n";
514 pidl "static gint ett_dcerpc_$module = -1;\n\n";
516 if (defined($if_uuid)) {
518 pidl "static e_uuid_t uuid_dcerpc_$module = {\n";
519 pidl "\t0x" . substr($if_uuid, 1, 8);
520 pidl ", 0x" . substr($if_uuid, 10, 4);
521 pidl ", 0x" . substr($if_uuid, 15, 4) . ",\n";
522 pidl "\t{ 0x" . substr($if_uuid, 20, 2);
523 pidl ", 0x" . substr($if_uuid, 22, 2);
524 pidl ", 0x" . substr($if_uuid, 25, 2);
525 pidl ", 0x" . substr($if_uuid, 27, 2);
526 pidl ", 0x" . substr($if_uuid, 29, 2);
527 pidl ", 0x" . substr($if_uuid, 31, 2);
528 pidl ", 0x" . substr($if_uuid, 33, 2);
529 pidl ", 0x" . substr($if_uuid, 35, 2) . " }\n";
533 if (defined($if_version)) {
534 pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n";
537 pidl "void proto_register_dcerpc_pidl_$module(void)\n";
540 pidl "\tstatic hf_register_info hf[] = {\n";
541 pidl "\t{ &hf_opnum, { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},\n";
542 pidl "\t{ &hf_result_NTSTATUS, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},\n";
543 pidl "\t{ &hf_ptr, { \"Pointer\", \"$module.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},\n";
545 foreach my $x (keys(%needed)) {
546 next, if !($x =~ /^hf_/);
548 pidl "\t { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base}, NULL, 0, \"$x\", HFILL }},\n";
553 pidl "\tstatic gint *ett[] = {\n";
554 pidl "\t\t&ett_dcerpc_$module,\n";
555 foreach my $x (keys(%needed)) {
556 pidl "\t\t&$x,\n", if $x =~ /^ett_/;
560 if (defined($if_uuid)) {
562 pidl "\tproto_dcerpc_pidl_$module = proto_register_protocol(\"pidl_$module\", \"pidl_$module\", \"pidl_$module\");\n\n";
564 pidl "\tproto_register_field_array(proto_dcerpc_pidl_$module, hf, array_length (hf));\n";
565 pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
569 pidl "void proto_reg_handoff_dcerpc_pidl_$module(void)\n";
571 pidl "\tdcerpc_init_uuid(proto_dcerpc_pidl_$module, ett_dcerpc_$module, \n";
572 pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n";
573 pidl "\t\tdcerpc_dissectors, hf_opnum);\n";
578 pidl "\tint proto_dcerpc;\n\n";
579 pidl "\tproto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");\n";
580 pidl "\tproto_register_field_array(proto_dcerpc, hf, array_length(hf));\n";
581 pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";