Add pidl. Add preliminary work on SecIP.

Please note that the Alphatronics implementation does not follow the Vebon specification.
An extra padding byte had to be added to the idl..
This commit is contained in:
Wilco Baan Hofman 2012-08-01 03:30:50 +02:00
parent 1972b32b60
commit ad758df90b
67 changed files with 24048 additions and 1 deletions

View file

@ -0,0 +1,418 @@
###################################################
# Samba3 client generator for IDL structures
# on top of Samba4 style NDR functions
# Copyright jelmer@samba.org 2005-2006
# Copyright gd@samba.org 2008
# released under the GNU GPL
package Parse::Pidl::Samba3::ClientNDR;
use Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(ParseFunction $res $res_hdr);
use strict;
use Parse::Pidl qw(fatal warning error);
use Parse::Pidl::Util qw(has_property ParseExpr);
use Parse::Pidl::NDR qw(ContainsPipe);
use Parse::Pidl::Typelist qw(mapTypeName);
use Parse::Pidl::Samba4 qw(DeclLong);
use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
use vars qw($VERSION);
$VERSION = '0.01';
sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
sub genpad($)
{
my ($s) = @_;
my $nt = int((length($s)+1)/8);
my $lt = ($nt*8)-1;
my $ns = (length($s)-$lt);
return "\t"x($nt)." "x($ns);
}
sub new($)
{
my ($class) = shift;
my $self = { res => "", res_hdr => "", tabs => "" };
bless($self, $class);
}
sub ElementDirection($)
{
my ($e) = @_;
return "[in,out]" if (has_property($e, "in") and has_property($e, "out"));
return "[in]" if (has_property($e, "in"));
return "[out]" if (has_property($e, "out"));
return "[in,out]";
}
sub HeaderProperties($$)
{
my($props,$ignores) = @_;
my $ret = "";
foreach my $d (keys %{$props}) {
next if (grep(/^$d$/, @$ignores));
if($props->{$d} ne "1") {
$ret.= "$d($props->{$d}),";
} else {
$ret.="$d,";
}
}
if ($ret) {
return "[" . substr($ret, 0, -1) . "]";
}
}
sub ParseInvalidResponse($$)
{
my ($self, $type) = @_;
if ($type eq "sync") {
$self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;");
} elsif ($type eq "async") {
$self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);");
$self->pidl("return;");
} else {
die("ParseInvalidResponse($type)");
}
}
sub ParseFunctionAsyncState($$$)
{
my ($self, $if, $fn) = @_;
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $done_fn = "rpccli_$fn->{NAME}_done";
$self->pidl("$state_str {");
$self->indent;
$self->pidl("TALLOC_CTX *out_mem_ctx;");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl(mapTypeName($fn->{RETURN_TYPE}). " result;");
}
$self->deindent;
$self->pidl("};");
$self->pidl("");
$self->pidl("static void $done_fn(struct tevent_req *subreq);");
$self->pidl("");
}
sub ParseFunctionAsyncSend($$$)
{
my ($self, $if, $fn) = @_;
my $fn_args = "";
my $uif = uc($if);
my $ufn = "NDR_".uc($fn->{NAME});
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $done_fn = "rpccli_$fn->{NAME}_done";
my $out_mem_ctx = "rpccli_$fn->{NAME}_out_memory";
my $fn_str = "struct tevent_req *rpccli_$fn->{NAME}_send";
my $pad = genpad($fn_str);
$fn_args .= "TALLOC_CTX *mem_ctx";
$fn_args .= ",\n" . $pad . "struct tevent_context *ev";
$fn_args .= ",\n" . $pad . "struct rpc_pipe_client *cli";
foreach (@{$fn->{ELEMENTS}}) {
my $dir = ElementDirection($_);
my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
$fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req;");
$self->pidl("$state_str *state;");
$self->pidl("struct tevent_req *subreq;");
$self->pidl("");
$self->pidl("req = tevent_req_create(mem_ctx, &state,");
$self->pidl("\t\t\t$state_str);");
$self->pidl("if (req == NULL) {");
$self->indent;
$self->pidl("return NULL;");
$self->deindent;
$self->pidl("}");
$self->pidl("state->out_mem_ctx = NULL;");
$self->pidl("");
my $out_params = 0;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/out/, @{$_->{DIRECTION}})) {
$out_params++;
}
}
if ($out_params > 0) {
$self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,");
$self->pidl("\t\t \"$out_mem_ctx\");");
$self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
$fn_str = "subreq = dcerpc_$fn->{NAME}_send";
$pad = "\t" . genpad($fn_str);
$fn_args = "state,\n" . $pad . "ev,\n" . $pad . "cli->binding_handle";
foreach (@{$fn->{ELEMENTS}}) {
$fn_args .= ",\n" . $pad . "_". $_->{NAME};
}
$self->pidl("$fn_str($fn_args);");
$self->pidl("if (tevent_req_nomem(subreq, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
$self->pidl("return req;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunctionAsyncDone($$$)
{
my ($self, $if, $fn) = @_;
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $done_fn = "rpccli_$fn->{NAME}_done";
$self->pidl("static void $done_fn(struct tevent_req *subreq)");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req = tevent_req_callback_data(");
$self->pidl("\tsubreq, struct tevent_req);");
$self->pidl("$state_str *state = tevent_req_data(");
$self->pidl("\treq, $state_str);");
$self->pidl("NTSTATUS status;");
$self->pidl("TALLOC_CTX *mem_ctx;");
$self->pidl("");
$self->pidl("if (state->out_mem_ctx) {");
$self->indent;
$self->pidl("mem_ctx = state->out_mem_ctx;");
$self->deindent;
$self->pidl("} else {");
$self->indent;
$self->pidl("mem_ctx = state;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
my $fn_str = "status = dcerpc_$fn->{NAME}_recv";
my $pad = "\t" . genpad($fn_str);
my $fn_args = "subreq,\n" . $pad . "mem_ctx";
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . "&state->result";
}
$self->pidl("$fn_str($fn_args);");
$self->pidl("TALLOC_FREE(subreq);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("tevent_req_nterror(req, status);");
$self->pidl("return;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("tevent_req_done(req);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunctionAsyncRecv($$$)
{
my ($self, $if, $fn) = @_;
my $fn_args = "";
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $fn_str = "NTSTATUS rpccli_$fn->{NAME}_recv";
my $pad = genpad($fn_str);
$fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx";
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . "$fn->{RETURN_TYPE} *result";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("$state_str *state = tevent_req_data(");
$self->pidl("\treq, $state_str);");
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("if (tevent_req_is_nterror(req, &status)) {");
$self->indent;
$self->pidl("tevent_req_received(req);");
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Steal possible out parameters to the callers context */");
$self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
$self->pidl("");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl("/* Return result */");
$self->pidl("*result = state->result;");
$self->pidl("");
}
$self->pidl("tevent_req_received(req);");
$self->pidl("return NT_STATUS_OK;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunctionSync($$$)
{
my ($self, $if, $fn) = @_;
my $fn_args = "";
my $uif = uc($if);
my $ufn = "NDR_".uc($fn->{NAME});
my $fn_str = "NTSTATUS rpccli_$fn->{NAME}";
my $pad = genpad($fn_str);
$fn_args .= "struct rpc_pipe_client *cli,\n" . $pad . "TALLOC_CTX *mem_ctx";
foreach (@{$fn->{ELEMENTS}}) {
my $dir = ElementDirection($_);
my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
$fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
}
if (defined($fn->{RETURN_TYPE}) && ($fn->{RETURN_TYPE} eq "WERROR")) {
$fn_args .= ",\n" . $pad . "WERROR *werror";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
if (defined($fn->{RETURN_TYPE})) {
$self->pidl(mapTypeName($fn->{RETURN_TYPE})." result;");
}
$self->pidl("NTSTATUS status;");
$self->pidl("");
$fn_str = "status = dcerpc_$fn->{NAME}";
$pad = "\t" . genpad($fn_str);
$fn_args = "cli->binding_handle,\n" . $pad . "mem_ctx";
foreach (@{$fn->{ELEMENTS}}) {
$fn_args .= ",\n" . $pad . "_". $_->{NAME};
}
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . "&result";
}
$self->pidl("$fn_str($fn_args);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Return result */");
if (not $fn->{RETURN_TYPE}) {
$self->pidl("return NT_STATUS_OK;");
} elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
$self->pidl("return result;");
} elsif ($fn->{RETURN_TYPE} eq "WERROR") {
$self->pidl("if (werror) {");
$self->indent;
$self->pidl("*werror = result;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("return werror_to_ntstatus(result);");
} else {
warning($fn->{ORIGINAL}, "Unable to convert $fn->{RETURN_TYPE} to NTSTATUS");
$self->pidl("return NT_STATUS_OK;");
}
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction($$$)
{
my ($self, $if, $fn) = @_;
$self->ParseFunctionAsyncState($if, $fn);
$self->ParseFunctionAsyncSend($if, $fn);
$self->ParseFunctionAsyncDone($if, $fn);
$self->ParseFunctionAsyncRecv($if, $fn);
$self->ParseFunctionSync($if, $fn);
}
sub ParseInterface($$)
{
my ($self, $if) = @_;
my $uif = uc($if->{NAME});
$self->pidl_hdr("#ifndef __CLI_$uif\__");
$self->pidl_hdr("#define __CLI_$uif\__");
foreach my $fn (@{$if->{FUNCTIONS}}) {
next if has_property($fn, "noopnum");
next if has_property($fn, "todo");
my $skip = 0;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (ContainsPipe($e, $e->{LEVELS}[0])) {
$skip = 1;
last;
}
}
next if $skip;
$self->ParseFunction($if->{NAME}, $fn);
}
$self->pidl_hdr("#endif /* __CLI_$uif\__ */");
}
sub Parse($$$$)
{
my($self,$ndr,$header,$c_header) = @_;
$self->pidl("/*");
$self->pidl(" * Unix SMB/CIFS implementation.");
$self->pidl(" * client auto-generated by pidl. DO NOT MODIFY!");
$self->pidl(" */");
$self->pidl("");
$self->pidl("#include \"includes.h\"");
$self->pidl("#include \"$header\"");
$self->pidl_hdr("#include \"$c_header\"");
$self->pidl("");
foreach (@$ndr) {
$self->ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
}
return ($self->{res}, $self->{res_hdr});
}
1;

View file

@ -0,0 +1,309 @@
###################################################
# Samba3 server generator for IDL structures
# on top of Samba4 style NDR functions
# Copyright jelmer@samba.org 2005-2006
# released under the GNU GPL
package Parse::Pidl::Samba3::ServerNDR;
use Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(DeclLevel);
use strict;
use Parse::Pidl qw(warning error fatal);
use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
use Parse::Pidl::Util qw(ParseExpr has_property is_constant);
use Parse::Pidl::NDR qw(GetNextLevel);
use Parse::Pidl::Samba4 qw(ElementStars DeclLong);
use Parse::Pidl::Samba4::Header qw(GenerateFunctionOutEnv);
use vars qw($VERSION);
$VERSION = '0.01';
my $res;
my $res_hdr;
my $tabs = "";
sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs, 1); }
sub pidl($) { my ($txt) = @_; $res .= $txt?$tabs.(shift)."\n":"\n"; }
sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
sub DeclLevel($$)
{
my ($e, $l) = @_;
my $res = "";
if (has_property($e, "charset")) {
$res .= "const char";
} else {
$res .= mapTypeName($e->{TYPE});
}
my $stars = ElementStars($e, $l);
$res .= " ".$stars unless ($stars eq "");
return $res;
}
sub AllocOutVar($$$$$)
{
my ($e, $mem_ctx, $name, $env, $fail) = @_;
my $l = $e->{LEVELS}[0];
# we skip pointer to arrays
if ($l->{TYPE} eq "POINTER") {
my $nl = GetNextLevel($e, $l);
$l = $nl if ($nl->{TYPE} eq "ARRAY");
} elsif
# we don't support multi-dimentional arrays yet
($l->{TYPE} eq "ARRAY") {
my $nl = GetNextLevel($e, $l);
if ($nl->{TYPE} eq "ARRAY") {
fatal($e->{ORIGINAL},"multi-dimentional [out] arrays are not supported!");
}
} else {
# neither pointer nor array, no need to alloc something.
return;
}
if ($l->{TYPE} eq "ARRAY") {
unless(defined($l->{SIZE_IS})) {
error($e->{ORIGINAL}, "No size known for array `$e->{NAME}'");
pidl "#error No size known for array `$e->{NAME}'";
} else {
my $size = ParseExpr($l->{SIZE_IS}, $env, $e);
pidl "$name = talloc_zero_array($mem_ctx, " . DeclLevel($e, 1) . ", $size);";
}
} else {
pidl "$name = talloc_zero($mem_ctx, " . DeclLevel($e, 1) . ");";
}
pidl "if ($name == NULL) {";
$fail->();
pidl "}";
pidl "";
}
sub CallWithStruct($$$$)
{
my ($pipes_struct, $mem_ctx, $fn, $fail) = @_;
my $env = GenerateFunctionOutEnv($fn);
my $hasout = 0;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/out/, @{$_->{DIRECTION}})) { $hasout = 1; }
}
pidl "ZERO_STRUCT(r->out);" if ($hasout);
my $proto = "_$fn->{NAME}(struct pipes_struct *p, struct $fn->{NAME} *r";
my $ret = "_$fn->{NAME}($pipes_struct, r";
foreach (@{$fn->{ELEMENTS}}) {
my @dir = @{$_->{DIRECTION}};
if (grep(/in/, @dir) and grep(/out/, @dir)) {
pidl "r->out.$_->{NAME} = r->in.$_->{NAME};";
}
}
foreach (@{$fn->{ELEMENTS}}) {
my @dir = @{$_->{DIRECTION}};
if (grep(/in/, @dir) and grep(/out/, @dir)) {
# noop
} elsif (grep(/out/, @dir) and not
has_property($_, "represent_as")) {
AllocOutVar($_, $mem_ctx, "r->out.$_->{NAME}", $env, $fail);
}
}
$ret .= ")";
$proto .= ");";
if ($fn->{RETURN_TYPE}) {
$ret = "r->out.result = $ret";
$proto = "$fn->{RETURN_TYPE} $proto";
} else {
$proto = "void $proto";
}
pidl_hdr "$proto";
pidl "$ret;";
}
sub ParseFunction($$)
{
my ($if,$fn) = @_;
my $op = "NDR_".uc($fn->{NAME});
pidl "static bool api_$fn->{NAME}(struct pipes_struct *p)";
pidl "{";
indent;
pidl "const struct ndr_interface_call *call;";
pidl "struct ndr_pull *pull;";
pidl "struct ndr_push *push;";
pidl "enum ndr_err_code ndr_err;";
pidl "struct $fn->{NAME} *r;";
pidl "";
pidl "call = &ndr_table_$if->{NAME}.calls[$op];";
pidl "";
pidl "r = talloc(talloc_tos(), struct $fn->{NAME});";
pidl "if (r == NULL) {";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "pull = ndr_pull_init_blob(&p->in_data.data, r);";
pidl "if (pull == NULL) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "pull->flags |= LIBNDR_FLAG_REF_ALLOC;";
pidl "if (p->endian) {";
pidl "\tpull->flags |= LIBNDR_FLAG_BIGENDIAN;";
pidl "}";
pidl "ndr_err = call->ndr_pull(pull, NDR_IN, r);";
pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10) {";
pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r);";
pidl "}";
pidl "";
CallWithStruct("p", "r", $fn,
sub {
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
}
);
pidl "";
pidl "if (p->rng_fault_state) {";
pidl "\ttalloc_free(r);";
pidl "\t/* Return true here, srv_pipe_hnd.c will take care */";
pidl "\treturn true;";
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10) {";
pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r);";
pidl "}";
pidl "";
pidl "push = ndr_push_init_ctx(r);";
pidl "if (push == NULL) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "/*";
pidl " * carry over the pointer count to the reply in case we are";
pidl " * using full pointer. See NDR specification for full pointers";
pidl " */";
pidl "push->ptr_count = pull->ptr_count;";
pidl "";
pidl "ndr_err = call->ndr_push(push, NDR_OUT, r);";
pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "p->out_data.rdata = ndr_push_blob(push);";
pidl "talloc_steal(p->mem_ctx, p->out_data.rdata.data);";
pidl "";
pidl "talloc_free(r);";
pidl "";
pidl "return true;";
deindent;
pidl "}";
pidl "";
}
sub ParseInterface($)
{
my $if = shift;
my $uif = uc($if->{NAME});
pidl_hdr "#ifndef __SRV_$uif\__";
pidl_hdr "#define __SRV_$uif\__";
foreach (@{$if->{FUNCTIONS}}) {
next if ($_->{PROPERTIES}{noopnum});
ParseFunction($if, $_);
}
pidl "";
pidl "/* Tables */";
pidl "static struct api_struct api_$if->{NAME}_cmds[] = ";
pidl "{";
indent;
foreach (@{$if->{FUNCTIONS}}) {
next if ($_->{PROPERTIES}{noopnum});
pidl "{\"" . uc($_->{NAME}) . "\", NDR_" . uc($_->{NAME}) . ", api_$_->{NAME}},";
}
deindent;
pidl "};";
pidl "";
pidl_hdr "void $if->{NAME}_get_pipe_fns(struct api_struct **fns, int *n_fns);";
pidl "void $if->{NAME}_get_pipe_fns(struct api_struct **fns, int *n_fns)";
pidl "{";
indent;
pidl "*fns = api_$if->{NAME}_cmds;";
pidl "*n_fns = sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct);";
deindent;
pidl "}";
pidl "";
if (not has_property($if, "no_srv_register")) {
pidl_hdr "struct rpc_srv_callbacks;";
pidl_hdr "NTSTATUS rpc_$if->{NAME}_init(const struct rpc_srv_callbacks *rpc_srv_cb);";
pidl "NTSTATUS rpc_$if->{NAME}_init(const struct rpc_srv_callbacks *rpc_srv_cb)";
pidl "{";
pidl "\treturn rpc_srv_register(SMB_RPC_INTERFACE_VERSION, \"$if->{NAME}\", \"$if->{NAME}\", \&ndr_table_$if->{NAME}, api_$if->{NAME}_cmds, sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct), rpc_srv_cb);";
pidl "}";
pidl "";
pidl_hdr "NTSTATUS rpc_$if->{NAME}_shutdown(void);";
pidl "NTSTATUS rpc_$if->{NAME}_shutdown(void)";
pidl "{";
pidl "\treturn rpc_srv_unregister(\&ndr_table_$if->{NAME});";
pidl "}";
}
pidl_hdr "#endif /* __SRV_$uif\__ */";
}
sub Parse($$$)
{
my($ndr,$header,$ndr_header) = @_;
$res = "";
$res_hdr = "";
pidl "/*";
pidl " * Unix SMB/CIFS implementation.";
pidl " * server auto-generated by pidl. DO NOT MODIFY!";
pidl " */";
pidl "";
pidl "#include \"includes.h\"";
pidl "#include \"ntdomain.h\"";
pidl "#include \"$header\"";
pidl_hdr "#include \"$ndr_header\"";
pidl "";
foreach (@$ndr) {
ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
}
return ($res, $res_hdr);
}
1;