wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
###################################################
# package to parse IDL files and generate code for
# rpc functions in Samba
# Copyright tridge@samba.org 2000-2003
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl;
use strict;
use vars qw ( $VERSION );
$VERSION = '0.02';
1;
+180
View File
@@ -0,0 +1,180 @@
###################################################
# IDL Compatibility checker
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Compat;
use Parse::Pidl::Util qw(has_property);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
my %supported_properties = (
# interface
"helpstring" => ["INTERFACE", "FUNCTION"],
"version" => ["INTERFACE"],
"uuid" => ["INTERFACE"],
"endpoint" => ["INTERFACE"],
"pointer_default" => ["INTERFACE"],
# dcom
"object" => ["INTERFACE"],
"local" => ["INTERFACE", "FUNCTION"],
"iid_is" => ["ELEMENT"],
"call_as" => ["FUNCTION"],
"idempotent" => ["FUNCTION"],
# function
"in" => ["ELEMENT"],
"out" => ["ELEMENT"],
# pointer
"ref" => ["ELEMENT"],
"ptr" => ["ELEMENT"],
"unique" => ["ELEMENT"],
"ignore" => ["ELEMENT"],
"value" => ["ELEMENT"],
# generic
"public" => ["FUNCTION", "TYPEDEF"],
"nopush" => ["FUNCTION", "TYPEDEF"],
"nopull" => ["FUNCTION", "TYPEDEF"],
"noprint" => ["FUNCTION", "TYPEDEF"],
"noejs" => ["FUNCTION", "TYPEDEF"],
# union
"switch_is" => ["ELEMENT"],
"switch_type" => ["ELEMENT", "TYPEDEF"],
"case" => ["ELEMENT"],
"default" => ["ELEMENT"],
# subcontext
"subcontext" => ["ELEMENT"],
"subcontext_size" => ["ELEMENT"],
# enum
"enum16bit" => ["TYPEDEF"],
"v1_enum" => ["TYPEDEF"],
# bitmap
"bitmap8bit" => ["TYPEDEF"],
"bitmap16bit" => ["TYPEDEF"],
"bitmap32bit" => ["TYPEDEF"],
"bitmap64bit" => ["TYPEDEF"],
# array
"range" => ["ELEMENT"],
"size_is" => ["ELEMENT"],
"string" => ["ELEMENT"],
"noheader" => ["ELEMENT"],
"charset" => ["ELEMENT"],
"length_is" => ["ELEMENT"],
);
sub warning($$)
{
my ($l,$m) = @_;
print STDERR "$l->{FILE}:$l->{LINE}:warning:$m\n";
}
sub CheckTypedef($)
{
my ($td) = @_;
if (has_property($td, "nodiscriminant")) {
warning($td, "nodiscriminant property not supported");
}
if ($td->{TYPE} eq "BITMAP") {
warning($td, "converting bitmap to scalar");
#FIXME
}
if (has_property($td, "gensize")) {
warning($td, "ignoring gensize() property. ");
}
if (has_property($td, "enum8bit") and has_property($td, "enum16bit")) {
warning($td, "8 and 16 bit enums not supported, converting to scalar");
#FIXME
}
StripProperties($td);
}
sub CheckElement($)
{
my $e = shift;
if (has_property($e, "noheader")) {
warning($e, "noheader property not supported");
return;
}
if (has_property($e, "subcontext")) {
warning($e, "converting subcontext to byte array");
#FIXME
}
if (has_property($e, "compression")) {
warning($e, "compression() property not supported");
}
if (has_property($e, "sptr")) {
warning($e, "sptr() pointer property not supported");
}
if (has_property($e, "relative")) {
warning($e, "relative() pointer property not supported");
}
if (has_property($e, "flag")) {
warning($e, "ignoring flag() property");
}
if (has_property($e, "value")) {
warning($e, "ignoring value() property");
}
}
sub CheckFunction($)
{
my $fn = shift;
if (has_property($fn, "noopnum")) {
warning($fn, "noopnum not converted. Opcodes will be out of sync.");
}
}
sub CheckInterface($)
{
my $if = shift;
if (has_property($if, "pointer_default_top") and
$if->{PROPERTIES}->{pointer_default_top} ne "ref") {
warning($if, "pointer_default_top() is pidl-specific");
}
foreach my $x (@{$if->{DATA}}) {
if ($x->{TYPE} eq "DECLARE") {
warning($if, "the declare keyword is pidl-specific");
next;
}
}
}
sub Check($)
{
my $pidl = shift;
my $nidl = [];
foreach (@{$pidl}) {
push (@$nidl, CheckInterface($_)) if ($_->{TYPE} eq "INTERFACE");
}
}
1;
+292
View File
@@ -0,0 +1,292 @@
###################################################
# dump function for IDL structures
# Copyright tridge@samba.org 2000
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
=pod
=head1 NAME
Parse::Pidl::Dump - Dump support
=head1 DESCRIPTION
This module provides functions that can generate IDL code from
internal pidl data structures.
=cut
package Parse::Pidl::Dump;
use Exporter;
use vars qw($VERSION);
$VERSION = '0.01';
@ISA = qw(Exporter);
@EXPORT_OK = qw(DumpTypedef DumpStruct DumpEnum DumpBitmap DumpUnion DumpFunction);
use strict;
use Parse::Pidl::Util qw(has_property);
my($res);
#####################################################################
# dump a properties list
sub DumpProperties($)
{
my($props) = shift;
my $res = "";
foreach my $d ($props) {
foreach my $k (keys %{$d}) {
if ($k eq "in") {
$res .= "[in] ";
next;
}
if ($k eq "out") {
$res .= "[out] ";
next;
}
if ($k eq "ref") {
$res .= "[ref] ";
next;
}
$res .= "[$k($d->{$k})] ";
}
}
return $res;
}
#####################################################################
# dump a structure element
sub DumpElement($)
{
my($element) = shift;
my $res = "";
(defined $element->{PROPERTIES}) &&
($res .= DumpProperties($element->{PROPERTIES}));
$res .= DumpType($element->{TYPE});
$res .= " ";
for my $i (1..$element->{POINTERS}) {
$res .= "*";
}
$res .= "$element->{NAME}";
foreach (@{$element->{ARRAY_LEN}}) {
$res .= "[$_]";
}
return $res;
}
#####################################################################
# dump a struct
sub DumpStruct($)
{
my($struct) = shift;
my($res);
$res .= "struct {\n";
if (defined $struct->{ELEMENTS}) {
foreach (@{$struct->{ELEMENTS}}) {
$res .= "\t" . DumpElement($_) . ";\n";
}
}
$res .= "}";
return $res;
}
#####################################################################
# dump a struct
sub DumpEnum($)
{
my($enum) = shift;
my($res);
$res .= "enum {\n";
foreach (@{$enum->{ELEMENTS}}) {
if (/^([A-Za-z0-9_]+)[ \t]*\((.*)\)$/) {
$res .= "\t$1 = $2,\n";
} else {
$res .= "\t$_,\n";
}
}
$res.= "}";
return $res;
}
#####################################################################
# dump a struct
sub DumpBitmap($)
{
my($bitmap) = shift;
my($res);
$res .= "bitmap {\n";
foreach (@{$bitmap->{ELEMENTS}}) {
if (/^([A-Za-z0-9_]+)[ \t]*\((.*)\)$/) {
$res .= "\t$1 = $2,\n";
} else {
die ("Bitmap $bitmap->{NAME} has field $_ without proper value");
}
}
$res.= "}";
return $res;
}
#####################################################################
# dump a union element
sub DumpUnionElement($)
{
my($element) = shift;
my($res);
if (has_property($element, "default")) {
$res .= "[default] ;\n";
} else {
$res .= "[case($element->{PROPERTIES}->{case})] ";
$res .= DumpElement($element), if defined($element);
$res .= ";\n";
}
return $res;
}
#####################################################################
# dump a union
sub DumpUnion($)
{
my($union) = shift;
my($res);
(defined $union->{PROPERTIES}) &&
($res .= DumpProperties($union->{PROPERTIES}));
$res .= "union {\n";
foreach my $e (@{$union->{ELEMENTS}}) {
$res .= DumpUnionElement($e);
}
$res .= "}";
return $res;
}
#####################################################################
# dump a type
sub DumpType($)
{
my($data) = shift;
my($res);
if (ref($data) eq "HASH") {
($data->{TYPE} eq "STRUCT") && ($res .= DumpStruct($data));
($data->{TYPE} eq "UNION") && ($res .= DumpUnion($data));
($data->{TYPE} eq "ENUM") && ($res .= DumpEnum($data));
($data->{TYPE} eq "BITMAP") && ($res .= DumpBitmap($data));
} else {
$res .= "$data";
}
return $res;
}
#####################################################################
# dump a typedef
sub DumpTypedef($)
{
my($typedef) = shift;
my($res);
$res .= "typedef ";
$res .= DumpType($typedef->{DATA});
$res .= " $typedef->{NAME};\n\n";
return $res;
}
#####################################################################
# dump a typedef
sub DumpFunction($)
{
my($function) = shift;
my($first) = 1;
my($res);
$res .= DumpType($function->{RETURN_TYPE});
$res .= " $function->{NAME}(\n";
for my $d (@{$function->{ELEMENTS}}) {
unless ($first) { $res .= ",\n"; } $first = 0;
$res .= DumpElement($d);
}
$res .= "\n);\n\n";
return $res;
}
#####################################################################
# dump a module header
sub DumpInterfaceProperties($)
{
my($header) = shift;
my($data) = $header->{DATA};
my($first) = 1;
my($res);
$res .= "[\n";
foreach my $k (keys %{$data}) {
$first || ($res .= ",\n"); $first = 0;
$res .= "$k($data->{$k})";
}
$res .= "\n]\n";
return $res;
}
#####################################################################
# dump the interface definitions
sub DumpInterface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my($res);
$res .= DumpInterfaceProperties($interface->{PROPERTIES});
$res .= "interface $interface->{NAME}\n{\n";
foreach my $d (@{$data}) {
($d->{TYPE} eq "TYPEDEF") &&
($res .= DumpTypedef($d));
($d->{TYPE} eq "FUNCTION") &&
($res .= DumpFunction($d));
}
$res .= "}\n";
return $res;
}
#####################################################################
# dump a parsed IDL structure back into an IDL file
sub Dump($)
{
my($idl) = shift;
my($res);
$res = "/* Dumped by pidl */\n\n";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") &&
($res .= DumpInterface($x));
}
return $res;
}
1;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+101
View File
@@ -0,0 +1,101 @@
##########################################
# Converts ODL stuctures to IDL structures
# (C) 2004-2005 Jelmer Vernooij <jelmer@samba.org>
package Parse::Pidl::ODL;
use Parse::Pidl::Util qw(has_property);
use Parse::Pidl::Typelist qw(hasType getType);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
#####################################################################
# find an interface in an array of interfaces
sub get_interface($$)
{
my($if,$n) = @_;
foreach(@$if) {
next if ($_->{TYPE} ne "INTERFACE");
return $_ if($_->{NAME} eq $n);
}
return 0;
}
sub FunctionAddObjArgs($)
{
my $e = shift;
unshift(@{$e->{ELEMENTS}}, {
'NAME' => 'ORPCthis',
'POINTERS' => 0,
'PROPERTIES' => { 'in' => '1' },
'TYPE' => 'ORPCTHIS',
'FILE' => $e->{FILE},
'LINE' => $e->{LINE}
});
unshift(@{$e->{ELEMENTS}}, {
'NAME' => 'ORPCthat',
'POINTERS' => 1,
'PROPERTIES' => { 'out' => '1', 'ref' => '1' },
'TYPE' => 'ORPCTHAT',
'FILE' => $e->{FILE},
'LINE' => $e->{LINE}
});
}
sub ReplaceInterfacePointers($)
{
my $e = shift;
foreach my $x (@{$e->{ELEMENTS}}) {
next unless (hasType($x->{TYPE}));
next unless getType($x->{TYPE})->{DATA}->{TYPE} eq "INTERFACE";
$x->{TYPE} = "MInterfacePointer";
}
}
# Add ORPC specific bits to an interface.
sub ODL2IDL($)
{
my $odl = shift;
my $addedorpc = 0;
foreach my $x (@$odl) {
next if ($x->{TYPE} ne "INTERFACE");
# Add [in] ORPCTHIS *this, [out] ORPCTHAT *that
# and replace interfacepointers with MInterfacePointer
# for 'object' interfaces
if (has_property($x, "object")) {
foreach my $e (@{$x->{DATA}}) {
($e->{TYPE} eq "FUNCTION") && FunctionAddObjArgs($e);
ReplaceInterfacePointers($e);
}
$addedorpc = 1;
}
if ($x->{BASE}) {
my $base = get_interface($odl, $x->{BASE});
foreach my $fn (reverse @{$base->{DATA}}) {
next unless ($fn->{TYPE} eq "FUNCTION");
unshift (@{$x->{DATA}}, $fn);
push (@{$x->{INHERITED_FUNCTIONS}}, $fn->{NAME});
}
}
}
unshift (@$odl, {
TYPE => "IMPORT",
PATHS => [ "\"orpc.idl\"" ],
FILE => undef,
LINE => undef
}) if ($addedorpc);
return $odl;
}
1;
@@ -0,0 +1,149 @@
###################################################
# Samba3 client 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::ClientNDR;
use strict;
use Parse::Pidl::Typelist qw(hasType getType mapType scalar_is_reference);
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
use Parse::Pidl::Samba4 qw(DeclLong_cli IsUniqueOut);
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($) { $res .= $tabs.(shift)."\n"; }
sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
sub fatal($$) { my ($e,$s) = @_; die("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
sub warning($$) { my ($e,$s) = @_; warn("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
sub ParseFunction($$)
{
my ($if,$fn) = @_;
my $inargs = "";
my $defargs = "";
my $uif = uc($if->{NAME});
my $ufn = "DCERPC_".uc($fn->{NAME});
foreach (@{$fn->{ELEMENTS}}) {
$defargs .= ", " . DeclLong_cli($_);
}
fn_declare "NTSTATUS rpccli_$fn->{NAME}(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx$defargs)";
pidl "{";
indent;
pidl "struct $fn->{NAME} r;";
pidl "NTSTATUS status;";
pidl "";
pidl "/* In parameters */";
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/in/, @{$_->{DIRECTION}})) {
if ( IsUniqueOut($_) ) {
pidl "r.in.$_->{NAME} = *$_->{NAME};";
}
else {
pidl "r.in.$_->{NAME} = $_->{NAME};";
}
}
}
pidl "";
pidl "if (DEBUGLEVEL >= 10)";
pidl "\tNDR_PRINT_IN_DEBUG($fn->{NAME}, &r);";
pidl "";
pidl "status = cli_do_rpc_ndr(cli, mem_ctx, PI_$uif, $ufn, &r, (ndr_pull_flags_fn_t)ndr_pull_$fn->{NAME}, (ndr_push_flags_fn_t)ndr_push_$fn->{NAME});";
pidl "";
pidl "if ( !NT_STATUS_IS_OK(status) ) {";
indent;
pidl "return status;";
deindent;
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10)";
pidl "\tNDR_PRINT_OUT_DEBUG($fn->{NAME}, &r);";
pidl "";
pidl "if (NT_STATUS_IS_ERR(status)) {";
pidl "\treturn status;";
pidl "}";
pidl "";
pidl "/* Return variables */";
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless (grep(/out/, @{$e->{DIRECTION}}));
fatal($e, "[out] argument is not a pointer or array") if ($e->{LEVELS}[0]->{TYPE} ne "POINTER" and $e->{LEVELS}[0]->{TYPE} ne "ARRAY");
if ( IsUniqueOut($e) ) {
pidl "*$e->{NAME} = r.out.$e->{NAME};";
} else {
pidl "*$e->{NAME} = *r.out.$e->{NAME};";
}
}
pidl"";
pidl "/* Return result */";
if (not $fn->{RETURN_TYPE}) {
pidl "return NT_STATUS_OK;";
} elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
pidl "return r.out.result;";
} elsif ($fn->{RETURN_TYPE} eq "WERROR") {
pidl "return werror_to_ntstatus(r.out.result);";
} else {
pidl "/* Sorry, don't know how to convert $fn->{RETURN_TYPE} to NTSTATUS */";
pidl "return NT_STATUS_OK;";
}
deindent;
pidl "}";
pidl "";
}
sub ParseInterface($)
{
my $if = shift;
my $uif = uc($if->{NAME});
pidl_hdr "#ifndef __CLI_$uif\__";
pidl_hdr "#define __CLI_$uif\__";
ParseFunction($if, $_) foreach (@{$if->{FUNCTIONS}});
pidl_hdr "#endif /* __CLI_$uif\__ */";
}
sub Parse($$$)
{
my($ndr,$header,$ndr_header) = @_;
$res = "";
$res_hdr = "";
pidl "/*";
pidl " * Unix SMB/CIFS implementation.";
pidl " * client auto-generated by pidl. DO NOT MODIFY!";
pidl " */";
pidl "";
pidl "#include \"includes.h\"";
pidl "#include \"$header\"";
pidl_hdr "#include \"$ndr_header\"";
pidl "";
foreach (@$ndr) {
ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
}
return ($res, $res_hdr);
}
1;
@@ -0,0 +1,230 @@
###################################################
# 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 strict;
use Parse::Pidl::Typelist qw(hasType getType mapType scalar_is_reference);
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
use Parse::Pidl::Samba4 qw(DeclLong);
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($) { $res .= $tabs.(shift)."\n"; }
sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
sub fatal($$) { my ($e,$s) = @_; die("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
sub warning($$) { my ($e,$s) = @_; warn("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
sub AllocOutVar($$$$)
{
my ($e, $mem_ctx, $name, $env) = @_;
my $l = $e->{LEVELS}[0];
if ($l->{TYPE} eq "POINTER") {
$l = GetNextLevel($e, $l);
}
if ($l->{TYPE} eq "ARRAY") {
my $size = ParseExpr($l->{SIZE_IS}, $env);
pidl "$name = talloc_zero_size($mem_ctx, sizeof(*$name) * $size);";
} else {
pidl "$name = talloc_zero_size($mem_ctx, sizeof(*$name));";
}
pidl "if ($name == NULL) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
}
sub ParseFunction($$)
{
my ($if,$fn) = @_;
pidl "static BOOL api_$fn->{NAME}(pipes_struct *p)";
pidl "{";
indent;
pidl "struct ndr_pull *pull;";
pidl "struct ndr_push *push;";
pidl "NTSTATUS status;";
pidl "DATA_BLOB blob;";
pidl "struct $fn->{NAME} r;";
pidl "TALLOC_CTX *mem_ctx = talloc_init(\"api_$fn->{NAME}\");";
pidl "";
pidl "if (!prs_data_blob(&p->in_data.data, &blob, mem_ctx)) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
pidl "pull = ndr_pull_init_blob(&blob, mem_ctx);";
pidl "if (pull == NULL) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
pidl "pull->flags |= LIBNDR_FLAG_REF_ALLOC;";
pidl "status = ndr_pull_$fn->{NAME}(pull, NDR_IN, &r);";
pidl "if (NT_STATUS_IS_ERR(status)) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10)";
pidl "\tNDR_PRINT_IN_DEBUG($fn->{NAME}, &r);";
pidl "";
my %env = ();
my $hasout = 0;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/out/, @{$_->{DIRECTION}})) { $hasout = 1; }
next unless (grep (/in/, @{$_->{DIRECTION}}));
$env{$_->{NAME}} = "r.in.$_->{NAME}";
}
pidl "ZERO_STRUCT(r.out);" if ($hasout);
my $proto = "_$fn->{NAME}(pipes_struct *p";
my $ret = "_$fn->{NAME}(p";
foreach (@{$fn->{ELEMENTS}}) {
my @dir = @{$_->{DIRECTION}};
if (grep(/in/, @dir) and grep(/out/, @dir)) {
pidl "r.out.$_->{NAME} = r.in.$_->{NAME};";
} elsif (grep(/out/, @dir)) {
AllocOutVar($_, "mem_ctx", "r.out.$_->{NAME}", \%env);
}
if (grep(/in/, @dir)) { $ret .= ", r.in.$_->{NAME}"; }
else { $ret .= ", r.out.$_->{NAME}"; }
$proto .= ", " . DeclLong($_);
}
$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;";
pidl "";
pidl "if (p->rng_fault_state) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\t/* Return True here, srv_pipe_hnd.c will take care */";
pidl "\treturn True;";
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10)";
pidl "\tNDR_PRINT_OUT_DEBUG($fn->{NAME}, &r);";
pidl "";
pidl "push = ndr_push_init_ctx(mem_ctx);";
pidl "if (push == NULL) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
pidl "status = ndr_push_$fn->{NAME}(push, NDR_OUT, &r);";
pidl "if (NT_STATUS_IS_ERR(status)) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
pidl "blob = ndr_push_blob(push);";
pidl "if (!prs_copy_data_in(&p->out_data.rdata, (const char *)blob.data, (uint32)blob.length)) {";
pidl "\ttalloc_free(mem_ctx);";
pidl "\treturn False;";
pidl "}";
pidl "";
pidl "talloc_free(mem_ctx);";
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\__";
ParseFunction($if, $_) foreach (@{$if->{FUNCTIONS}});
pidl "";
pidl "/* Tables */";
pidl "static struct api_struct api_$if->{NAME}_cmds[] = ";
pidl "{";
indent;
foreach (@{$if->{FUNCTIONS}}) {
pidl "{\"" . uc($_->{NAME}) . "\", DCERPC_" . 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 "";
pidl_hdr "NTSTATUS rpc_$if->{NAME}_init(void);";
pidl "NTSTATUS rpc_$if->{NAME}_init(void)";
pidl "{";
pidl "\treturn rpc_pipe_register_commands(SMB_RPC_INTERFACE_VERSION, \"$if->{NAME}\", \"$if->{NAME}\", api_$if->{NAME}_cmds, sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct));";
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 \"$header\"";
pidl_hdr "#include \"$ndr_header\"";
pidl "";
foreach (@$ndr) {
ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
}
return ($res, $res_hdr);
}
1;
@@ -0,0 +1,94 @@
###################################################
# Common Samba4 functions
# Copyright jelmer@samba.org 2006
# released under the GNU GPL
package Parse::Pidl::Samba4;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(is_intree choose_header DeclLong DeclLong_cli IsUniqueOut);
use Parse::Pidl::Util qw(has_property is_constant);
use Parse::Pidl::Typelist qw(mapType scalar_is_reference);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
sub is_intree()
{
return 4 if (-f "kdc/kdc.c");
return 3 if (-f "include/smb.h");
return 0;
}
# Return an #include line depending on whether this build is an in-tree
# build or not.
sub choose_header($$)
{
my ($in,$out) = @_;
return "#include \"$in\"" if (is_intree());
return "#include <$out>";
}
sub IsUniqueOut($)
{
my ($e) = shift;
return grep(/out/, @{$e->{DIRECTION}}) &&
((($e->{LEVELS}[0]->{TYPE} eq "POINTER") &&
($e->{LEVELS}[0]->{POINTER_TYPE} eq "unique")) ||
($e->{LEVELS}[0]->{TYPE} eq "ARRAY"));
}
sub DeclLong_int($$)
{
my($element,$cli) = @_;
my $ret = "";
if (has_property($element, "represent_as")) {
$ret.=mapType($element->{PROPERTIES}->{represent_as})." ";
} else {
if (has_property($element, "charset")) {
$ret.="const char";
} else {
$ret.=mapType($element->{TYPE});
}
$ret.=" ";
my $numstar = $element->{ORIGINAL}->{POINTERS};
if ($numstar >= 1) {
$numstar-- if scalar_is_reference($element->{TYPE});
}
foreach (@{$element->{ORIGINAL}->{ARRAY_LEN}})
{
next if is_constant($_) and
not has_property($element, "charset");
$numstar++;
}
if ($cli && IsUniqueOut($element)) {
$numstar++;
}
$ret.="*" foreach (1..$numstar);
}
$ret.=$element->{NAME};
foreach (@{$element->{ARRAY_LEN}}) {
next unless (is_constant($_) and not has_property($element, "charset"));
$ret.="[$_]";
}
return $ret;
}
sub DeclLong($)
{
return DeclLong_int($_, 0);
}
sub DeclLong_cli($)
{
return DeclLong_int($_, 1);
}
1;
@@ -0,0 +1,184 @@
# COM Header generation
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
package Parse::Pidl::Samba4::COM::Header;
use Parse::Pidl::Typelist qw(mapType);
use Parse::Pidl::Util qw(has_property is_constant);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub HeaderType($)
{
my($e) = @_;
if (has_property($e, "charset")) {
return "const char";
} else {
return mapType($e->{TYPE});
}
}
sub GetArgumentProto($)
{
my $a = shift;
my $res = HeaderType($a) . " ";
my $l = $a->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($a->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
if (defined $a->{ARRAY_LEN}[0] && !is_constant($a->{ARRAY_LEN}[0]) &&
!$a->{POINTERS}) {
$res .= "*";
}
$res .= $a->{NAME};
if (defined $a->{ARRAY_LEN}[0] && is_constant($a->{ARRAY_LEN}[0])) {
$res .= "[$a->{ARRAY_LEN}[0]]";
}
return $res;
}
sub GetArgumentProtoList
{
my ($f,$filter) = @_;
my $res = "";
foreach my $a (@{$f->{ELEMENTS}}) {
next if defined($filter) && !has_property($a, $filter);
$res .= ", " . GetArgumentProto($a);
}
return $res;
}
sub GetArgumentList
{
my ($f,$filter) = @_;
my $res = "";
foreach (@{$f->{ELEMENTS}}) {
next if defined($filter) && !has_property($_, $filter);
$res .= ", $_->{NAME}";
}
return $res;
}
#####################################################################
# generate vtable structure for COM interface
sub HeaderVTable($)
{
my $interface = shift;
my $res;
$res .= "#define " . uc($interface->{NAME}) . "_METHODS \\\n";
if (defined($interface->{BASE})) {
$res .= "\t" . uc($interface->{BASE} . "_METHODS") . "\\\n";
}
my $data = $interface->{DATA};
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") {
# $res .= "\t" . mapType($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n";
$res .= "\tstruct composite_context *(*$d->{NAME}_send) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d, "in") . ");\\\n";
}
}
$res .= "\n";
$res .= "struct $interface->{NAME}_vtable {\n";
$res .= "\tstruct GUID iid;\n";
$res .= "\t" . uc($interface->{NAME}) . "_METHODS\n";
$res .= "};\n\n";
return $res;
}
sub ParseInterface($)
{
my $if = shift;
my $res;
$res .="\n\n/* $if->{NAME} */\n";
$res .="#define COM_" . uc($if->{NAME}) . "_UUID $if->{PROPERTIES}->{uuid}\n\n";
$res .="struct $if->{NAME}_vtable;\n\n";
$res .="struct $if->{NAME} {
struct OBJREF obj;
struct com_context *ctx;
struct $if->{NAME}_vtable *vtable;
void *object_data;
};\n\n";
$res.=HeaderVTable($if);
foreach my $d (@{$if->{DATA}}) {
next if ($d->{TYPE} ne "FUNCTION");
my $defname = ($d->{NAME} =~ /^$if->{NAME}_(.*)$/) ? $1 : $d->{NAME};
# $res .= "#define $if->{NAME}_${defname}(interface, mem_ctx" . GetArgumentList($d) . ") ";
# $res .= "((interface)->vtable->$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . "))";
$res .= mapType($d->{RETURN_TYPE}) . " $if->{NAME}_${defname}(struct $if->{NAME} *interface, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\n";
$res .= "#define $if->{NAME}_${defname}_send(interface, mem_ctx" . GetArgumentList($d, "in") . ") ";
$res .= "((interface)->vtable->$d->{NAME}_send(interface, mem_ctx" . GetArgumentList($d, "in") . "))";
$res .="\n";
# $res .= "#define $if->{NAME}_${defname}_recv(c" . GetArgumentList($d, "out") . ") ";
# $res .= "((interface)->vtable->$d->{NAME}_recv(c" . GetArgumentList($d, "out") . "))";
$res .= mapType($d->{RETURN_TYPE}) . " $if->{NAME}_${defname}_recv(struct composite_context *c" . GetArgumentProtoList($d, "out") . ");\n";
$res .="\n";
}
$res .= "\nNTSTATUS dcom_proxy_$if->{NAME}_init(void);\n";
return $res;
}
sub ParseCoClass($)
{
my $c = shift;
my $res = "";
$res .= "#define CLSID_" . uc($c->{NAME}) . " $c->{PROPERTIES}->{uuid}\n";
if (has_property($c, "progid")) {
$res .= "#define PROGID_" . uc($c->{NAME}) . " $c->{PROPERTIES}->{progid}\n";
}
$res .= "\n";
return $res;
}
sub Parse($$)
{
my ($idl,$ndr_header) = @_;
my $res = "";
$res .= "#include \"librpc/gen_ndr/orpc.h\"\n" .
"#include \"$ndr_header\"\n\n";
foreach (@{$idl})
{
if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) {
$res.="struct $_->{NAME};\n";
foreach my $s (@{$_->{DATA}}) {
next if ($s->{TYPE} ne "TYPEDEF" || defined($s->{DATA_TYPE}) || $s->{DATA}{TYPE} ne "STRUCT");
$res.="struct $s->{NAME};\n";
}
}
}
foreach (@{$idl})
{
if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) {
$res.=ParseInterface($_);
}
if ($_->{TYPE} eq "COCLASS") {
$res.=ParseCoClass($_);
}
}
return $res;
}
1;
@@ -0,0 +1,397 @@
###################################################
# DCOM parser for Samba
# Basically the glue between COM and DCE/RPC with NDR
# Copyright jelmer@samba.org 2003-2005
# released under the GNU GPL
package Parse::Pidl::Samba4::COM::Proxy;
use Parse::Pidl::Samba4::COM::Header;
use Parse::Pidl::Util qw(has_property);
use Parse::Pidl::Typelist qw(mapType);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
my($res);
sub ParseVTable($$)
{
my $interface = shift;
my $name = shift;
# Generate the vtable
$res .="\tstruct $interface->{NAME}_vtable $name = {";
if (defined($interface->{BASE})) {
$res .= "\n\t\t{},";
}
my $data = $interface->{DATA};
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") {
$res .= "\n\t\tdcom_proxy_$interface->{NAME}_$d->{NAME}";
$res .= ",";
}
}
$res .= "\n\t};\n\n";
}
sub ParseRegFunc($)
{
my $interface = shift;
$res .= "\nNTSTATUS dcom_proxy_$interface->{NAME}_init(void)
{
struct $interface->{NAME}_vtable *proxy_vtable = talloc(talloc_autofree_context(), struct $interface->{NAME}_vtable);
";
if (defined($interface->{BASE})) {
$res.= "
struct GUID base_iid;
const void *base_vtable;
base_iid = dcerpc_table_$interface->{BASE}.syntax_id.uuid;
base_vtable = dcom_proxy_vtable_by_iid(&base_iid);
if (base_vtable == NULL) {
DEBUG(0, (\"No proxy registered for base interface '$interface->{BASE}'\\n\"));
return NT_STATUS_FOOBAR;
}
memcpy(proxy_vtable, base_vtable, sizeof(struct $interface->{BASE}_vtable));
";
}
foreach my $x (@{$interface->{DATA}}) {
next unless ($x->{TYPE} eq "FUNCTION");
# $res .= "\tproxy_vtable->$x->{NAME} = dcom_proxy_$interface->{NAME}_$x->{NAME};\n";
$res .= "\tproxy_vtable->$x->{NAME}_send = dcom_proxy_$interface->{NAME}_$x->{NAME}_send;\n";
}
$res.= "
proxy_vtable->iid = dcerpc_table_$interface->{NAME}.syntax_id.uuid;
return dcom_register_proxy((struct IUnknown_vtable *)proxy_vtable);
}\n\n";
}
#####################################################################
# parse a function
sub ParseFunction($$)
{
my $interface = shift;
my $fn = shift;
my $name = $fn->{NAME};
my $short_name = ($fn->{NAME} =~ /^$interface->{NAME}_(.*)$/) ? $1 : $fn->{NAME};
my $uname = uc $name;
my $args_in = 0;
my $args_out = 0;
my $if_in = 0;
my $if_out = 0;
foreach my $a (@{$fn->{ELEMENTS}}) {
$args_in++ if has_property($a, "in");
$args_out++ if has_property($a, "out");
$if_in++ if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE") && has_property($a, "in"));
$if_out++ if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE") && has_property($a, "out"));
}
$args_out++ if $fn->{RETURN_TYPE} ne "void";
#### declarations ############################################
$res.="
static void dcom_proxy_$interface->{NAME}_${name}_recv_rpc(struct rpc_request *req);
";
##### *_out struct ###########################################
if ($args_out > 0) {
$res.="
struct $interface->{NAME}_${name}_out {
";
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
my $decl = Parse::Pidl::Samba4::COM::Header::GetArgumentProto($a);
$decl =~ s/ \*/ /;
$res.= "\t" . $decl . ";\n";
}
if ($fn->{RETURN_TYPE} ne "void") {
$res.= "\t" . mapType($fn->{RETURN_TYPE}) . " result;\n";
}
$res.="};\n";
}
#### *_send ##################################################
$res.="
static struct composite_context *dcom_proxy_$interface->{NAME}_${name}_send(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn, "in") . ")
{
struct composite_context *c, *c_pipe;
struct dcom_proxy_async_call_state *s;
struct ${name} *r;
" . ($if_in > 0 ? "\tNTSTATUS status;\n" : "" ) . "
c = composite_create(mem_ctx, d->ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct dcom_proxy_async_call_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
r = talloc_zero(s, struct ${name});
if (composite_nomem(r, c)) return c;
s->d = (struct IUnknown *)d;
s->table = &dcerpc_table_$interface->{NAME};
s->opnum = DCERPC_$uname;
s->continuation = dcom_proxy_$interface->{NAME}_${name}_recv_rpc;
s->mem_ctx = mem_ctx;
s->r = r;
r->in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION;
r->in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION;
r->in.ORPCthis.cid = GUID_random();
";
# Put arguments into r
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "in"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
my $varname;
my $ctx = "mem_ctx";
my $n;
foreach $n (0..$a->{POINTERS}-1) {
$res .=sprintf(("\t" x $n)."\tif (%s$a->{NAME}) {\n", ("*" x $n));
$varname = ("*" x $n) . "r->in.$a->{NAME}";
$res .=sprintf(("\t" x $n)."\t\t$varname = talloc_zero($ctx, struct MInterfacePointer%s);\n", ("*" x ($a->{POINTERS}-$n-1)));
$ctx = $varname;
}
$n = $a->{POINTERS}-1;
$res .=("\t" x $n)."\t\t(${varname})->size = sizeof(struct OBJREF);\n";
$res .=sprintf(("\t" x $n)."\t\tstatus = dcom_OBJREF_from_IUnknown(&(*$varname).obj, (struct IUnknown *)%s$a->{NAME});\n", ("*" x ($a->{POINTERS}-1)));
$res .= ("\t" x $n)."\t\tif (!NT_STATUS_IS_OK(status)) {\n"
. ("\t" x $n)."\t\t\tcomposite_error(c, NT_STATUS_RPC_NT_CALL_FAILED);\n"
. ("\t" x $n)."\t\t\treturn c;\n"
. ("\t" x $n)."\t\t}\n";
for ($n =$a->{POINTERS}; $n > 0; --$n) {
$res .=("\t" x $n)."}\n";
}
} else {
$res .= "\tr->in.$a->{NAME} = $a->{NAME};\n";
}
}
$res .="
if (DEBUGLVL(12)) {
NDR_PRINT_IN_DEBUG(${name}, r);
}
c_pipe = dcom_get_pipe_send((struct IUnknown *)d, mem_ctx);
composite_continue(c, c_pipe, dcom_proxy_async_call_recv_pipe_send_rpc, c);
return c;
}
";
#### *_recv_rpc ##############################################
$res.="
static void dcom_proxy_$interface->{NAME}_${name}_recv_rpc(struct rpc_request *req)
{
struct composite_context *c;
struct dcom_proxy_async_call_state *s;
struct $interface->{NAME}_${name}_out *out;
struct ${name} *r;
struct ORPCTHAT that;
NTSTATUS status;
";
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res.="\tstruct MInterfacePointer *mip_$a->{NAME};\n";
}
}
$res.="
c = req->async.private;
s = c->private_data;
r = s->r;
out = talloc_zero(c, struct $interface->{NAME}_${name}_out);
if (composite_nomem(out, c)) return;
c->private_data = out;
r->out.ORPCthat = &that;
";
foreach $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res.="\tr->out.$a->{NAME} = &mip_$a->{NAME};\n";
} else {
$res.="\tr->out.$a->{NAME} = &out->$a->{NAME};\n";
}
}
$res.="
status = dcerpc_ndr_request_recv(req);
if (!NT_STATUS_IS_OK(status)) {
composite_error(c, NT_STATUS_RPC_NT_CALL_FAILED);
return;
}
if (DEBUGLVL(12)) {
NDR_PRINT_OUT_DEBUG(${name}, r);
}
";
foreach $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res .=
" if (r->out.$a->{NAME} && *r->out.$a->{NAME}) {
status = dcom_IUnknown_from_OBJREF(s->d->ctx, (struct IUnknown **)&out->$a->{NAME}, &(**r->out.$a->{NAME}).obj);
if (*r->out.$a->{NAME}) talloc_free(*r->out.$a->{NAME});
} else {
out->$a->{NAME} = NULL;
}
";
} elsif (defined($a->{POINTERS}) and $a->{POINTERS} > 1) {
$res .=
" talloc_steal(s->mem_ctx, out->$a->{NAME});
";
}
}
if ($fn->{RETURN_TYPE} ne "void") {
$res.="\tout->result = r->out.result;\n";
}
$res .="
talloc_free(s);
composite_done(c);
}
";
#### *_recv ##################################################
$res.="
" . mapType($fn->{RETURN_TYPE}) . " $interface->{NAME}_${name}_recv(struct composite_context *c" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn, "out") . ")
{
struct $interface->{NAME}_${name}_out *out;
NTSTATUS status;
" . (($fn->{RETURN_TYPE} ne "void") ? "\t" . mapType($fn->{RETURN_TYPE}) . " result;\n" : "") . "
status = composite_wait(c);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(c);
return";
if ($fn->{RETURN_TYPE} eq "WERROR") {
$res.=" ntstatus_to_werror(NT_STATUS_RPC_NT_CALL_FAILED)";
} elsif($fn->{RETURN_TYPE} eq "uint32") {
$res.=" 0";
}
$res .= ";
}
out = c->private_data;
";
foreach $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
$res.="\tif ($a->{NAME}) *$a->{NAME} = out->$a->{NAME};\n";
}
if ($fn->{RETURN_TYPE} ne "void") {
$res.="\tresult = out->result;\n";
}
$res .= "
talloc_free(c);
" . (($fn->{RETURN_TYPE} ne "void") ? "\treturn result;" : "") . "
}
";
#### * sync ##################################################
$res.="
" . mapType($fn->{RETURN_TYPE}) . " $interface->{NAME}_${short_name}(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn) . ")
{
struct composite_context *c;
c = $interface->{NAME}_${short_name}_send(d, mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentList($fn, "in") . ");
if (c == NULL) return";
if ($fn->{RETURN_TYPE} eq "WERROR") {
$res.=" WERR_NOMEM";
} elsif($fn->{RETURN_TYPE} eq "uint32") {
$res.=" 0";
}
$res.=";
" . (($fn->{RETURN_TYPE} ne "void") ? "return " : "") . "$interface->{NAME}_${name}_recv(c" . Parse::Pidl::Samba4::COM::Header::GetArgumentList($fn, "out") . ");
}
";
}
#####################################################################
# parse the interface definitions
sub ParseInterface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
$res = "/* DCOM proxy for $interface->{NAME} generated by pidl */\n\n";
foreach my $d (@{$data}) {
($d->{TYPE} eq "FUNCTION") &&
ParseFunction($interface, $d);
}
ParseRegFunc($interface);
}
sub RegistrationFunction($$)
{
my $idl = shift;
my $basename = shift;
my $res = "\n\nNTSTATUS dcom_$basename\_init(void)\n";
$res .= "{\n";
$res .="\tNTSTATUS status = NT_STATUS_OK;\n";
foreach my $interface (@{$idl}) {
next if $interface->{TYPE} ne "INTERFACE";
next if not has_property($interface, "object");
my $data = $interface->{DATA};
my $count = 0;
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") { $count++; }
}
next if ($count == 0);
$res .= "\tstatus = dcom_$interface->{NAME}_init();\n";
$res .= "\tif (NT_STATUS_IS_ERR(status)) {\n";
$res .= "\t\treturn status;\n";
$res .= "\t}\n\n";
}
$res .= "\treturn status;\n";
$res .= "}\n\n";
return $res;
}
sub Parse($$)
{
my ($pidl,$comh_filename) = @_;
my $res = "";
$res .= "#include \"includes.h\"\n" .
"#include \"librpc/rpc/dcerpc.h\"\n" .
"#include \"lib/com/dcom/dcom.h\"\n" .
"#include \"$comh_filename\"\n" .
"#include \"libcli/composite/composite.h\"\n";
foreach (@{$pidl}) {
next if ($_->{TYPE} ne "INTERFACE");
next if has_property($_, "local");
next unless has_property($_, "object");
$res .= ParseInterface($_);
}
return $res;
}
1;
@@ -0,0 +1,327 @@
###################################################
# DCOM stub boilerplate generator
# Copyright jelmer@samba.org 2004-2005
# Copyright tridge@samba.org 2003
# Copyright metze@samba.org 2004
# released under the GNU GPL
package Parse::Pidl::Samba4::COM::Stub;
use Parse::Pidl::Util qw(has_property);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
my($res);
sub pidl($)
{
$res .= shift;
}
#####################################################
# generate the switch statement for function dispatch
sub gen_dispatch_switch($)
{
my $data = shift;
my $count = 0;
foreach my $d (@{$data}) {
next if ($d->{TYPE} ne "FUNCTION");
pidl "\tcase $count: {\n";
if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
pidl "\t\tNTSTATUS result;\n";
}
pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
pidl "\t\tif (DEBUGLEVEL > 10) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_IN, r2);\n";
pidl "\t\t}\n";
if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
pidl "\t\tresult = vtable->$d->{NAME}(iface, mem_ctx, r2);\n";
} else {
pidl "\t\tvtable->$d->{NAME}(iface, mem_ctx, r2);\n";
}
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $d->{NAME} will reply async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
$count++;
}
}
#####################################################
# generate the switch statement for function reply
sub gen_reply_switch($)
{
my $data = shift;
my $count = 0;
foreach my $d (@{$data}) {
next if ($d->{TYPE} ne "FUNCTION");
pidl "\tcase $count: {\n";
pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $d->{NAME} replied async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tif (DEBUGLEVEL > 10 && dce_call->fault_code == 0) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
pidl "\t\t}\n";
pidl "\t\tif (dce_call->fault_code != 0) {\n";
pidl "\t\t\tDEBUG(2,(\"dcerpc_fault %s in $d->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code)));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
$count++;
}
}
#####################################################################
# produce boilerplate code for a interface
sub Boilerplate_Iface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my $name = $interface->{NAME};
my $uname = uc $name;
my $uuid = Parse::Pidl::Util::make_str($interface->{PROPERTIES}->{uuid});
my $if_version = $interface->{PROPERTIES}->{version};
pidl "
static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
{
#ifdef DCESRV_INTERFACE_$uname\_BIND
return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
#else
return NT_STATUS_OK;
#endif
}
static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
{
#ifdef DCESRV_INTERFACE_$uname\_UNBIND
DCESRV_INTERFACE_$uname\_UNBIND(context, iface);
#else
return;
#endif
}
static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
{
NTSTATUS status;
uint16_t opnum = dce_call->pkt.u.request.opnum;
dce_call->fault_code = 0;
if (opnum >= dcerpc_table_$name.num_calls) {
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
return NT_STATUS_NET_WRITE_FAULT;
}
*r = talloc_size(mem_ctx, dcerpc_table_$name.calls[opnum].struct_size);
NT_STATUS_HAVE_NO_MEMORY(*r);
/* unravel the NDR for the packet */
status = dcerpc_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
if (!NT_STATUS_IS_OK(status)) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
struct GUID ipid = dce_call->pkt.u.request.object.object;
struct dcom_interface_p *iface = dcom_get_local_iface_p(&ipid);
const struct dcom_$name\_vtable *vtable = iface->vtable;
switch (opnum) {
";
gen_dispatch_switch($data);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
switch (opnum) {
";
gen_reply_switch($data);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
{
NTSTATUS status;
uint16_t opnum = dce_call->pkt.u.request.opnum;
status = dcerpc_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static const struct dcesrv_interface $name\_interface = {
.name = \"$name\",
.uuid = $uuid,
.if_version = $if_version,
.bind = $name\__op_bind,
.unbind = $name\__op_unbind,
.ndr_pull = $name\__op_ndr_pull,
.dispatch = $name\__op_dispatch,
.reply = $name\__op_reply,
.ndr_push = $name\__op_ndr_push
};
";
}
#####################################################################
# produce boilerplate code for an endpoint server
sub Boilerplate_Ep_Server($)
{
my($interface) = shift;
my $name = $interface->{NAME};
my $uname = uc $name;
pidl "
static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
for (i=0;i<dcerpc_table_$name.endpoints->count;i++) {
NTSTATUS ret;
const char *name = dcerpc_table_$name.endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
return ret;
}
}
return NT_STATUS_OK;
}
static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32_t if_version)
{
if (dcerpc_table_$name.if_version == if_version &&
strcmp(dcerpc_table_$name.uuid, uuid)==0) {
memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
return True;
}
return False;
}
static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
if (strcmp(dcerpc_table_$name.name, name)==0) {
memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
return True;
}
return False;
}
NTSTATUS dcerpc_server_$name\_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
/* fill in our name */
ep_server.name = \"$name\";
/* fill in all the operations */
ep_server.init_server = $name\__op_init_server;
ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
ep_server.interface_by_name = $name\__op_interface_by_name;
/* register ourselves with the DCERPC subsystem. */
ret = dcerpc_register_ep_server(&ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
return ret;
}
return ret;
}
";
}
#####################################################################
# dcom interface stub from a parsed IDL structure
sub ParseInterface($)
{
my($interface) = shift;
return "" if has_property($interface, "local");
my($data) = $interface->{DATA};
my $count = 0;
$res = "";
if (!defined $interface->{PROPERTIES}->{uuid}) {
return $res;
}
if (!defined $interface->{PROPERTIES}->{version}) {
$interface->{PROPERTIES}->{version} = "0.0";
}
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") { $count++; }
}
if ($count == 0) {
return $res;
}
$res = "/* dcom interface stub generated by pidl */\n\n";
Boilerplate_Iface($interface);
Boilerplate_Ep_Server($interface);
return $res;
}
1;
@@ -0,0 +1,902 @@
###################################################
# EJS function wrapper generator
# Copyright jelmer@samba.org 2005
# Copyright Andrew Tridgell 2005
# released under the GNU GPL
package Parse::Pidl::Samba4::EJS;
use strict;
use Parse::Pidl::Typelist;
use Parse::Pidl::Util qw(has_property);
use vars qw($VERSION);
$VERSION = '0.01';
my $res;
my $res_hdr;
my %constants;
my $tabs = "";
sub pidl_hdr ($)
{
$res_hdr .= shift;
}
sub pidl($)
{
my $d = shift;
if ($d) {
$res .= $tabs;
$res .= $d;
}
$res .= "\n";
}
sub indent()
{
$tabs .= "\t";
}
sub deindent()
{
$tabs = substr($tabs, 0, -1);
}
# this should probably be in ndr.pm
sub GenerateStructEnv($)
{
my $x = shift;
my %env;
foreach my $e (@{$x->{ELEMENTS}}) {
if ($e->{NAME}) {
$env{$e->{NAME}} = "r->$e->{NAME}";
}
}
$env{"this"} = "r";
return \%env;
}
sub GenerateFunctionInEnv($)
{
my $fn = shift;
my %env;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/in/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = "r->in.$e->{NAME}";
}
}
return \%env;
}
sub GenerateFunctionOutEnv($)
{
my $fn = shift;
my %env;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/out/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = "r->out.$e->{NAME}";
} elsif (grep (/in/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = "r->in.$e->{NAME}";
}
}
return \%env;
}
sub get_pointer_to($)
{
my $var_name = shift;
if ($var_name =~ /^\*(.*)$/) {
return $1;
} elsif ($var_name =~ /^\&(.*)$/) {
return "&($var_name)";
} else {
return "&$var_name";
}
}
sub get_value_of($)
{
my $var_name = shift;
if ($var_name =~ /^\&(.*)$/) {
return $1;
} else {
return "*$var_name";
}
}
#####################################################################
# check that a variable we get from ParseExpr isn't a null pointer
sub check_null_pointer($)
{
my $size = shift;
if ($size =~ /^\*/) {
my $size2 = substr($size, 1);
pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
}
}
#####################################################################
# work out is a parse function should be declared static or not
sub fn_declare($$)
{
my ($fn,$decl) = @_;
if (has_property($fn, "public")) {
pidl_hdr "$decl;\n";
pidl "_PUBLIC_ $decl";
} else {
pidl "static $decl";
}
}
###########################
# pull a scalar element
sub EjsPullScalar($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
return if (has_property($e, "value"));
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
$var = get_pointer_to($var);
# have to handle strings specially :(
if ($e->{TYPE} eq "string" && $pl && $pl->{TYPE} eq "POINTER") {
$var = get_pointer_to($var);
}
pidl "NDR_CHECK(ejs_pull_$e->{TYPE}(ejs, v, $name, $var));";
}
###########################
# pull a pointer element
sub EjsPullPointer($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
pidl "if (ejs_pull_null(ejs, v, $name)) {";
indent;
if ($l->{POINTER_TYPE} eq "ref") {
pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
} else {
pidl "$var = NULL;";
}
deindent;
pidl "} else {";
indent;
pidl "EJS_ALLOC(ejs, $var);";
$var = get_value_of($var);
EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
deindent;
pidl "}";
}
###########################
# pull a string element
sub EjsPullString($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
$var = get_pointer_to($var);
pidl "NDR_CHECK(ejs_pull_string(ejs, v, $name, $var));";
}
###########################
# pull an array element
sub EjsPullArray($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
my $size = Parse::Pidl::Util::ParseExpr($l->{SIZE_IS}, $env);
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
if ($pl && $pl->{TYPE} eq "POINTER") {
$var = get_pointer_to($var);
}
# uint8 arrays are treated as data blobs
if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
if (!$l->{IS_FIXED}) {
check_null_pointer($size);
pidl "EJS_ALLOC_N(ejs, $var, $size);";
}
check_null_pointer($length);
pidl "ejs_pull_array_uint8(ejs, v, $name, $var, $length);";
return;
}
my $avar = $var . "[i]";
pidl "{";
indent;
pidl "uint32_t i;";
if (!$l->{IS_FIXED}) {
pidl "EJS_ALLOC_N(ejs, $var, $size);";
}
pidl "for (i=0;i<$length;i++) {";
indent;
pidl "char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
EjsPullElement($e, $nl, $avar, "id", $env);
pidl "talloc_free(id);";
deindent;
pidl "}";
pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
deindent;
pidl "}";
}
###########################
# pull a switch element
sub EjsPullSwitch($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
pidl "ejs_set_switch(ejs, $switch_var);";
EjsPullElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
}
###########################
# pull a structure element
sub EjsPullElement($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
if (has_property($e, "charset")) {
EjsPullString($e, $l, $var, $name, $env);
} elsif ($l->{TYPE} eq "ARRAY") {
EjsPullArray($e, $l, $var, $name, $env);
} elsif ($l->{TYPE} eq "DATA") {
EjsPullScalar($e, $l, $var, $name, $env);
} elsif (($l->{TYPE} eq "POINTER")) {
EjsPullPointer($e, $l, $var, $name, $env);
} elsif (($l->{TYPE} eq "SWITCH")) {
EjsPullSwitch($e, $l, $var, $name, $env);
} else {
pidl "return ejs_panic(ejs, \"unhandled pull type $l->{TYPE}\");";
}
}
#############################################
# pull a structure/union element at top level
sub EjsPullElementTop($$)
{
my $e = shift;
my $env = shift;
my $l = $e->{LEVELS}[0];
my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
my $name = "\"$e->{NAME}\"";
EjsPullElement($e, $l, $var, $name, $env);
}
###########################
# pull a struct
sub EjsStructPull($$)
{
my $name = shift;
my $d = shift;
my $env = GenerateStructEnv($d);
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, struct $name *r)");
pidl "{";
indent;
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
foreach my $e (@{$d->{ELEMENTS}}) {
EjsPullElementTop($e, $env);
}
pidl "return NT_STATUS_OK;";
deindent;
pidl "}\n";
}
###########################
# pull a union
sub EjsUnionPull($$)
{
my $name = shift;
my $d = shift;
my $have_default = 0;
my $env = GenerateStructEnv($d);
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, union $name *r)");
pidl "{";
indent;
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, name));";
pidl "switch (ejs->switch_var) {";
indent;
foreach my $e (@{$d->{ELEMENTS}}) {
if ($e->{CASE} eq "default") {
$have_default = 1;
}
pidl "$e->{CASE}:";
indent;
if ($e->{TYPE} ne "EMPTY") {
EjsPullElementTop($e, $env);
}
pidl "break;";
deindent;
}
if (! $have_default) {
pidl "default:";
indent;
pidl "return ejs_panic(ejs, \"Bad switch value\");";
deindent;
}
deindent;
pidl "}";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
}
##############################################
# put the enum elements in the constants array
sub EjsEnumConstant($)
{
my $d = shift;
my $v = 0;
foreach my $e (@{$d->{ELEMENTS}}) {
my $el = $e;
chomp $el;
if ($el =~ /^(.*)=\s*(.*)\s*$/) {
$el = $1;
$v = $2;
}
$constants{$el} = $v;
$v++;
}
}
###########################
# pull a enum
sub EjsEnumPull($$)
{
my $name = shift;
my $d = shift;
EjsEnumConstant($d);
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, enum $name *r)");
pidl "{";
indent;
pidl "unsigned e;";
pidl "NDR_CHECK(ejs_pull_enum(ejs, v, name, &e));";
pidl "*r = e;";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}\n";
}
###########################
# pull a bitmap
sub EjsBitmapPull($$)
{
my $name = shift;
my $d = shift;
my $type_fn = $d->{BASE_TYPE};
my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
fn_declare($d, "NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, $type_decl *r)");
pidl "{";
indent;
pidl "return ejs_pull_$type_fn(ejs, v, name, r);";
deindent;
pidl "}";
}
###########################
# generate a structure pull
sub EjsTypedefPull($)
{
my $d = shift;
return if (has_property($d, "noejs"));
if ($d->{DATA}->{TYPE} eq 'STRUCT') {
EjsStructPull($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'UNION') {
EjsUnionPull($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
EjsEnumPull($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
EjsBitmapPull($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'DECORATED') {
} else {
warn "Unhandled pull typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
}
}
#####################
# generate a function
sub EjsPullFunction($)
{
my $d = shift;
my $env = GenerateFunctionInEnv($d);
my $name = $d->{NAME};
pidl "\nstatic NTSTATUS ejs_pull_$name(struct ejs_rpc *ejs, struct MprVar *v, struct $name *r)";
pidl "{";
indent;
pidl "NDR_CHECK(ejs_pull_struct_start(ejs, &v, \"input\"));";
# we pull non-array elements before array elements as arrays
# may have length_is() or size_is() properties that depend
# on the non-array elements
foreach my $e (@{$d->{ELEMENTS}}) {
next unless (grep(/in/, @{$e->{DIRECTION}}));
next if (has_property($e, "length_is") || has_property($e, "size_is"));
EjsPullElementTop($e, $env);
}
foreach my $e (@{$d->{ELEMENTS}}) {
next unless (grep(/in/, @{$e->{DIRECTION}}));
next unless (has_property($e, "length_is") || has_property($e, "size_is"));
EjsPullElementTop($e, $env);
}
pidl "return NT_STATUS_OK;";
deindent;
pidl "}\n";
}
###########################
# push a scalar element
sub EjsPushScalar($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
# have to handle strings specially :(
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
if ($e->{TYPE} ne "string" || ($pl && $pl->{TYPE} eq "POINTER")) {
$var = get_pointer_to($var);
}
pidl "NDR_CHECK(ejs_push_$e->{TYPE}(ejs, v, $name, $var));";
}
###########################
# push a string element
sub EjsPushString($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
pidl "NDR_CHECK(ejs_push_string(ejs, v, $name, $var));";
}
###########################
# push a pointer element
sub EjsPushPointer($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
pidl "if (NULL == $var) {";
indent;
if ($l->{POINTER_TYPE} eq "ref") {
pidl "return NT_STATUS_INVALID_PARAMETER_MIX;";
} else {
pidl "NDR_CHECK(ejs_push_null(ejs, v, $name));";
}
deindent;
pidl "} else {";
indent;
$var = get_value_of($var);
EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
deindent;
pidl "}";
}
###########################
# push a switch element
sub EjsPushSwitch($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
my $switch_var = Parse::Pidl::Util::ParseExpr($l->{SWITCH_IS}, $env);
pidl "ejs_set_switch(ejs, $switch_var);";
EjsPushElement($e, Parse::Pidl::NDR::GetNextLevel($e, $l), $var, $name, $env);
}
###########################
# push an array element
sub EjsPushArray($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
my $nl = Parse::Pidl::NDR::GetNextLevel($e, $l);
my $length = Parse::Pidl::Util::ParseExpr($l->{LENGTH_IS}, $env);
my $pl = Parse::Pidl::NDR::GetPrevLevel($e, $l);
if ($pl && $pl->{TYPE} eq "POINTER") {
$var = get_pointer_to($var);
}
# uint8 arrays are treated as data blobs
if ($nl->{TYPE} eq 'DATA' && $e->{TYPE} eq 'uint8') {
check_null_pointer($length);
pidl "ejs_push_array_uint8(ejs, v, $name, $var, $length);";
return;
}
my $avar = $var . "[i]";
pidl "{";
indent;
pidl "uint32_t i;";
pidl "for (i=0;i<$length;i++) {";
indent;
pidl "const char *id = talloc_asprintf(ejs, \"%s.%u\", $name, i);";
EjsPushElement($e, $nl, $avar, "id", $env);
deindent;
pidl "}";
pidl "ejs_push_uint32(ejs, v, $name \".length\", &i);";
deindent;
pidl "}";
}
################################
# push a structure/union element
sub EjsPushElement($$$$$)
{
my ($e, $l, $var, $name, $env) = @_;
if (has_property($e, "charset")) {
EjsPushString($e, $l, $var, $name, $env);
} elsif ($l->{TYPE} eq "ARRAY") {
EjsPushArray($e, $l, $var, $name, $env);
} elsif ($l->{TYPE} eq "DATA") {
EjsPushScalar($e, $l, $var, $name, $env);
} elsif (($l->{TYPE} eq "POINTER")) {
EjsPushPointer($e, $l, $var, $name, $env);
} elsif (($l->{TYPE} eq "SWITCH")) {
EjsPushSwitch($e, $l, $var, $name, $env);
} else {
pidl "return ejs_panic(ejs, \"unhandled push type $l->{TYPE}\");";
}
}
#############################################
# push a structure/union element at top level
sub EjsPushElementTop($$)
{
my $e = shift;
my $env = shift;
my $l = $e->{LEVELS}[0];
my $var = Parse::Pidl::Util::ParseExpr($e->{NAME}, $env);
my $name = "\"$e->{NAME}\"";
EjsPushElement($e, $l, $var, $name, $env);
}
###########################
# push a struct
sub EjsStructPush($$)
{
my $name = shift;
my $d = shift;
my $env = GenerateStructEnv($d);
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const struct $name *r)");
pidl "{";
indent;
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
foreach my $e (@{$d->{ELEMENTS}}) {
EjsPushElementTop($e, $env);
}
pidl "return NT_STATUS_OK;";
deindent;
pidl "}\n";
}
###########################
# push a union
sub EjsUnionPush($$)
{
my $name = shift;
my $d = shift;
my $have_default = 0;
my $env = GenerateStructEnv($d);
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const union $name *r)");
pidl "{";
indent;
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, name));";
pidl "switch (ejs->switch_var) {";
indent;
foreach my $e (@{$d->{ELEMENTS}}) {
if ($e->{CASE} eq "default") {
$have_default = 1;
}
pidl "$e->{CASE}:";
indent;
if ($e->{TYPE} ne "EMPTY") {
EjsPushElementTop($e, $env);
}
pidl "break;";
deindent;
}
if (! $have_default) {
pidl "default:";
indent;
pidl "return ejs_panic(ejs, \"Bad switch value\");";
deindent;
}
deindent;
pidl "}";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
}
###########################
# push a enum
sub EjsEnumPush($$)
{
my $name = shift;
my $d = shift;
EjsEnumConstant($d);
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const enum $name *r)");
pidl "{";
indent;
pidl "unsigned e = *r;";
pidl "NDR_CHECK(ejs_push_enum(ejs, v, name, &e));";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}\n";
}
###########################
# push a bitmap
sub EjsBitmapPush($$)
{
my $name = shift;
my $d = shift;
my $type_fn = $d->{BASE_TYPE};
my($type_decl) = Parse::Pidl::Typelist::mapType($d->{BASE_TYPE});
# put the bitmap elements in the constants array
foreach my $e (@{$d->{ELEMENTS}}) {
if ($e =~ /^(\w*)\s*(.*)\s*$/) {
my $bname = $1;
my $v = $2;
$constants{$bname} = $v;
}
}
fn_declare($d, "NTSTATUS ejs_push_$name(struct ejs_rpc *ejs, struct MprVar *v, const char *name, const $type_decl *r)");
pidl "{";
indent;
pidl "return ejs_push_$type_fn(ejs, v, name, r);";
deindent;
pidl "}";
}
###########################
# generate a structure push
sub EjsTypedefPush($)
{
my $d = shift;
return if (has_property($d, "noejs"));
if ($d->{DATA}->{TYPE} eq 'STRUCT') {
EjsStructPush($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'UNION') {
EjsUnionPush($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'ENUM') {
EjsEnumPush($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'BITMAP') {
EjsBitmapPush($d->{NAME}, $d->{DATA});
} elsif ($d->{DATA}->{TYPE} eq 'DECORATED') {
} else {
warn "Unhandled push typedef $d->{NAME} of type $d->{DATA}->{TYPE}";
}
}
#####################
# generate a function
sub EjsPushFunction($)
{
my $d = shift;
my $env = GenerateFunctionOutEnv($d);
pidl "\nstatic NTSTATUS ejs_push_$d->{NAME}(struct ejs_rpc *ejs, struct MprVar *v, const struct $d->{NAME} *r)";
pidl "{";
indent;
pidl "NDR_CHECK(ejs_push_struct_start(ejs, &v, \"output\"));";
foreach my $e (@{$d->{ELEMENTS}}) {
next unless (grep(/out/, @{$e->{DIRECTION}}));
EjsPushElementTop($e, $env);
}
if ($d->{RETURN_TYPE}) {
my $t = $d->{RETURN_TYPE};
pidl "NDR_CHECK(ejs_push_$t(ejs, v, \"result\", &r->out.result));";
}
pidl "return NT_STATUS_OK;";
deindent;
pidl "}\n";
}
#################################
# generate a ejs mapping function
sub EjsFunction($$)
{
my $d = shift;
my $iface = shift;
my $name = $d->{NAME};
my $callnum = uc("DCERPC_$name");
my $table = "&dcerpc_table_$iface";
pidl "static int ejs_$name(int eid, int argc, struct MprVar **argv)";
pidl "{";
indent;
pidl "return ejs_rpc_call(eid, argc, argv, $table, $callnum, (ejs_pull_function_t)ejs_pull_$name, (ejs_push_function_t)ejs_push_$name);";
deindent;
pidl "}\n";
}
###################
# handle a constant
sub EjsConst($)
{
my $const = shift;
$constants{$const->{NAME}} = $const->{VALUE};
}
sub EjsImport
{
my @imports = @_;
foreach (@imports) {
s/\.idl\"$//;
s/^\"//;
pidl_hdr "#include \"librpc/gen_ndr/ndr_$_\_ejs\.h\"\n";
}
}
#####################################################################
# parse the interface definitions
sub EjsInterface($$)
{
my($interface,$needed) = @_;
my @fns = ();
my $name = $interface->{NAME};
%constants = ();
pidl_hdr "#ifndef _HEADER_EJS_$interface->{NAME}\n";
pidl_hdr "#define _HEADER_EJS_$interface->{NAME}\n\n";
pidl_hdr "\n";
foreach my $d (@{$interface->{TYPES}}) {
($needed->{"push_$d->{NAME}"}) && EjsTypedefPush($d);
($needed->{"pull_$d->{NAME}"}) && EjsTypedefPull($d);
}
foreach my $d (@{$interface->{FUNCTIONS}}) {
next if not defined($d->{OPNUM});
next if has_property($d, "noejs");
EjsPullFunction($d);
EjsPushFunction($d);
EjsFunction($d, $name);
push (@fns, $d->{NAME});
}
foreach my $d (@{$interface->{CONSTS}}) {
EjsConst($d);
}
pidl "static int ejs_$name\_init(int eid, int argc, struct MprVar **argv)";
pidl "{";
indent;
pidl "struct MprVar *obj = mprInitObject(eid, \"$name\", argc, argv);";
foreach (@fns) {
pidl "mprSetCFunction(obj, \"$_\", ejs_$_);";
}
foreach my $v (keys %constants) {
my $value = $constants{$v};
if (substr($value, 0, 1) eq "\"") {
pidl "mprSetVar(obj, \"$v\", mprString($value));";
} else {
pidl "mprSetVar(obj, \"$v\", mprCreateNumberVar($value));";
}
}
pidl "return ejs_rpc_init(obj, \"$name\");";
deindent;
pidl "}\n";
pidl "NTSTATUS ejs_init_$name(void)";
pidl "{";
indent;
pidl "ejsDefineCFunction(-1, \"$name\_init\", ejs_$name\_init, NULL, MPR_VAR_SCRIPT_HANDLE);";
pidl "return NT_STATUS_OK;";
deindent;
pidl "}";
pidl_hdr "\n";
pidl_hdr "#endif /* _HEADER_EJS_$interface->{NAME} */\n";
}
#####################################################################
# parse a parsed IDL into a C header
sub Parse($$)
{
my($ndr,$hdr) = @_;
my $ejs_hdr = $hdr;
$ejs_hdr =~ s/.h$/_ejs.h/;
$res = "";
$res_hdr = "";
pidl_hdr "/* header auto-generated by pidl */\n\n";
pidl "
/* EJS wrapper functions auto-generated by pidl */
#include \"includes.h\"
#include \"librpc/rpc/dcerpc.h\"
#include \"lib/appweb/ejs/ejs.h\"
#include \"scripting/ejs/ejsrpc.h\"
#include \"scripting/ejs/smbcalls.h\"
#include \"librpc/gen_ndr/ndr_misc_ejs.h\"
#include \"$hdr\"
#include \"$ejs_hdr\"
";
my %needed = ();
foreach my $x (@{$ndr}) {
($x->{TYPE} eq "INTERFACE") && NeededInterface($x, \%needed);
}
foreach my $x (@$ndr) {
($x->{TYPE} eq "INTERFACE") && EjsInterface($x, \%needed);
($x->{TYPE} eq "IMPORT") && EjsImport(@{$x->{PATHS}});
}
return ($res_hdr, $res);
}
sub NeededFunction($$)
{
my ($fn,$needed) = @_;
$needed->{"pull_$fn->{NAME}"} = 1;
$needed->{"push_$fn->{NAME}"} = 1;
foreach (@{$fn->{ELEMENTS}}) {
next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
if (grep(/in/, @{$_->{DIRECTION}})) {
$needed->{"pull_$_->{TYPE}"} = 1;
}
if (grep(/out/, @{$_->{DIRECTION}})) {
$needed->{"push_$_->{TYPE}"} = 1;
}
}
}
sub NeededTypedef($$)
{
my ($t,$needed) = @_;
if (has_property($t, "public")) {
$needed->{"pull_$t->{NAME}"} = not has_property($t, "noejs");
$needed->{"push_$t->{NAME}"} = not has_property($t, "noejs");
}
return if (($t->{DATA}->{TYPE} ne "STRUCT") and
($t->{DATA}->{TYPE} ne "UNION"));
foreach (@{$t->{DATA}->{ELEMENTS}}) {
next if (has_property($_, "subcontext")); #FIXME: Support subcontexts
unless (defined($needed->{"pull_$_->{TYPE}"})) {
$needed->{"pull_$_->{TYPE}"} = $needed->{"pull_$t->{NAME}"};
}
unless (defined($needed->{"push_$_->{TYPE}"})) {
$needed->{"push_$_->{TYPE}"} = $needed->{"push_$t->{NAME}"};
}
}
}
#####################################################################
# work out what parse functions are needed
sub NeededInterface($$)
{
my ($interface,$needed) = @_;
NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
NeededTypedef($_, $needed) foreach (reverse @{$interface->{TYPES}});
}
1;
@@ -0,0 +1,407 @@
###################################################
# create C header files for an IDL structure
# Copyright tridge@samba.org 2000
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Samba4::Header;
use strict;
use Parse::Pidl::Typelist qw(mapType);
use Parse::Pidl::Util qw(has_property is_constant);
use Parse::Pidl::NDR qw(GetNextLevel GetPrevLevel);
use Parse::Pidl::Samba4 qw(is_intree);
use vars qw($VERSION);
$VERSION = '0.01';
my($res);
my($tab_depth);
sub pidl($) { $res .= shift; }
sub tabs()
{
my $res = "";
$res .="\t" foreach (1..$tab_depth);
return $res;
}
#####################################################################
# parse a properties list
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) {
pidl "/* [" . substr($ret, 0, -1) . "] */";
}
}
#####################################################################
# parse a structure element
sub HeaderElement($)
{
my($element) = shift;
pidl tabs();
if (has_property($element, "represent_as")) {
pidl mapType($element->{PROPERTIES}->{represent_as})." ";
} else {
HeaderType($element, $element->{TYPE}, "");
pidl " ";
my $numstar = $element->{POINTERS};
if ($numstar >= 1) {
$numstar-- if Parse::Pidl::Typelist::scalar_is_reference($element->{TYPE});
}
foreach (@{$element->{ARRAY_LEN}})
{
next if is_constant($_) and
not has_property($element, "charset");
$numstar++;
}
pidl "*" foreach (1..$numstar);
}
pidl $element->{NAME};
foreach (@{$element->{ARRAY_LEN}}) {
next unless (is_constant($_) and
not has_property($element, "charset"));
pidl "[$_]";
}
pidl ";";
if (defined $element->{PROPERTIES}) {
HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
}
pidl "\n";
}
#####################################################################
# parse a struct
sub HeaderStruct($$)
{
my($struct,$name) = @_;
pidl "struct $name {\n";
$tab_depth++;
my $el_count=0;
if (defined $struct->{ELEMENTS}) {
foreach (@{$struct->{ELEMENTS}}) {
HeaderElement($_);
$el_count++;
}
}
if ($el_count == 0) {
# some compilers can't handle empty structures
pidl tabs()."char _empty_;\n";
}
$tab_depth--;
pidl tabs()."}";
if (defined $struct->{PROPERTIES}) {
HeaderProperties($struct->{PROPERTIES}, []);
}
}
#####################################################################
# parse a enum
sub HeaderEnum($$)
{
my($enum,$name) = @_;
my $first = 1;
if (not Parse::Pidl::Util::useUintEnums()) {
pidl "enum $name {\n";
$tab_depth++;
foreach my $e (@{$enum->{ELEMENTS}}) {
unless ($first) { pidl ",\n"; }
$first = 0;
pidl tabs();
pidl $e;
}
pidl "\n";
$tab_depth--;
pidl "}";
} else {
my $count = 0;
pidl "enum $name { __donnot_use_enum_$name=0x7FFFFFFF};\n";
my $with_val = 0;
my $without_val = 0;
foreach my $e (@{$enum->{ELEMENTS}}) {
my $t = "$e";
my $name;
my $value;
if ($t =~ /(.*)=(.*)/) {
$name = $1;
$value = $2;
$with_val = 1;
die ("you can't mix enum member with values and without values when using --uint-enums!")
unless ($without_val == 0);
} else {
$name = $t;
$value = $count++;
$without_val = 1;
die ("you can't mix enum member with values and without values when using --uint-enums!")
unless ($with_val == 0);
}
pidl "#define $name ( $value )\n";
}
pidl "\n";
}
}
#####################################################################
# parse a bitmap
sub HeaderBitmap($$)
{
my($bitmap,$name) = @_;
pidl "/* bitmap $name */\n";
pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
pidl "\n";
}
#####################################################################
# parse a union
sub HeaderUnion($$)
{
my($union,$name) = @_;
my %done = ();
pidl "union $name {\n";
$tab_depth++;
foreach my $e (@{$union->{ELEMENTS}}) {
if ($e->{TYPE} ne "EMPTY") {
if (! defined $done{$e->{NAME}}) {
HeaderElement($e);
}
$done{$e->{NAME}} = 1;
}
}
$tab_depth--;
pidl "}";
if (defined $union->{PROPERTIES}) {
HeaderProperties($union->{PROPERTIES}, []);
}
}
sub decorate($$)
{
my($name,$levels) = @_;
my $prev_ptr = 0;
foreach my $i (0..$#{$levels}) {
if ($levels->[$i]{TYPE} eq "POINTER") {
$name = "*$name";
$prev_ptr = 1;
} elsif ($levels->[$i]{TYPE} eq "ARRAY") {
$name = ($prev_ptr ? "($name)" : $name) . "[$levels->[$i]{SIZE_IS}]";
}
}
$name
}
sub HeaderDecorated($$)
{
my($e,$name) = @_;
$name = $e->{NAME} unless defined($name);
pidl "typedef ";
if (has_property($e, "charset")) {
pidl "const char";
} else {
pidl mapType($e->{DATA}{DATA_TYPE});
}
pidl " " . decorate($name, $e->{DATA}{LEVELS});
}
#####################################################################
# parse a type
sub HeaderType($$$)
{
my($e,$data,$name) = @_;
if (ref($data) eq "HASH") {
($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name);
($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name);
($data->{TYPE} eq "UNION") && HeaderUnion($data, $name);
($data->{TYPE} eq "DECORATED") && HeaderDecorated($e, $name);
return;
}
if (has_property($e, "charset") and $e->{TYPEREF}{DATA}{TYPE} ne "DECORATED") {
pidl "const char";
} else {
pidl mapType($e->{TYPE});
}
}
#####################################################################
# parse a typedef
sub HeaderTypedef($)
{
my($typedef) = shift;
HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
pidl ";\n\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
}
#####################################################################
# parse a const
sub HeaderConst($)
{
my($const) = shift;
if (!defined($const->{ARRAY_LEN}[0])) {
pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
} else {
pidl "#define $const->{NAME}\t $const->{VALUE}\n";
}
}
#####################################################################
# parse a function
sub HeaderFunctionInOut($$)
{
my($fn,$prop) = @_;
foreach (@{$fn->{ELEMENTS}}) {
HeaderElement($_) if (has_property($_, $prop));
}
}
#####################################################################
# determine if we need an "in" or "out" section
sub HeaderFunctionInOut_needed($$)
{
my($fn,$prop) = @_;
return 1 if ($prop eq "out" && $fn->{RETURN_TYPE} ne "void");
foreach (@{$fn->{ELEMENTS}}) {
return 1 if (has_property($_, $prop));
}
return undef;
}
my %headerstructs;
#####################################################################
# parse a function
sub HeaderFunction($)
{
my($fn) = shift;
return if ($headerstructs{$fn->{NAME}});
$headerstructs{$fn->{NAME}} = 1;
pidl "\nstruct $fn->{NAME} {\n";
$tab_depth++;
my $needed = 0;
if (HeaderFunctionInOut_needed($fn, "in")) {
pidl tabs()."struct {\n";
$tab_depth++;
HeaderFunctionInOut($fn, "in");
$tab_depth--;
pidl tabs()."} in;\n\n";
$needed++;
}
if (HeaderFunctionInOut_needed($fn, "out")) {
pidl tabs()."struct {\n";
$tab_depth++;
HeaderFunctionInOut($fn, "out");
if ($fn->{RETURN_TYPE} ne "void") {
pidl tabs().mapType($fn->{RETURN_TYPE}) . " result;\n";
}
$tab_depth--;
pidl tabs()."} out;\n\n";
$needed++;
}
if (! $needed) {
# sigh - some compilers don't like empty structures
pidl tabs()."int _dummy_element;\n";
}
$tab_depth--;
pidl "};\n\n";
}
sub HeaderImport
{
my @imports = @_;
foreach (@imports) {
s/\.idl\"$//;
s/^\"//;
pidl "#include \"librpc/gen_ndr/$_\.h\"\n";
}
}
sub HeaderInclude
{
my @includes = @_;
foreach (@includes) {
pidl "#include $_\n";
}
}
#####################################################################
# parse the interface definitions
sub HeaderInterface($)
{
my($interface) = shift;
pidl "#ifndef _HEADER_$interface->{NAME}\n";
pidl "#define _HEADER_$interface->{NAME}\n\n";
foreach my $d (@{$interface->{DATA}}) {
next if ($d->{TYPE} ne "CONST");
HeaderConst($d);
}
foreach my $d (@{$interface->{DATA}}) {
next if ($d->{TYPE} ne "TYPEDEF");
HeaderTypedef($d);
}
foreach my $d (@{$interface->{DATA}}) {
next if ($d->{TYPE} ne "FUNCTION");
HeaderFunction($d);
}
pidl "#endif /* _HEADER_$interface->{NAME} */\n";
}
#####################################################################
# parse a parsed IDL into a C header
sub Parse($)
{
my($idl) = shift;
$tab_depth = 0;
$res = "";
%headerstructs = ();
pidl "/* header auto-generated by pidl */\n\n";
if (!is_intree()) {
pidl "#include <core.h>\n\n";
}
foreach (@{$idl}) {
($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
}
return $res;
}
1;
@@ -0,0 +1,128 @@
###################################################
# client calls generator
# Copyright tridge@samba.org 2003
# Copyright jelmer@samba.org 2005-2006
# released under the GNU GPL
package Parse::Pidl::Samba4::NDR::Client;
use Parse::Pidl::Samba4 qw(choose_header is_intree);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
my($res,$res_hdr);
#####################################################################
# parse a function
sub ParseFunction($$)
{
my ($interface, $fn) = @_;
my $name = $fn->{NAME};
my $uname = uc $name;
$res_hdr .= "\nstruct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);
NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);
";
$res .= "
struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r)
{
if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
NDR_PRINT_IN_DEBUG($name, r);
}
return dcerpc_ndr_request_send(p, NULL, &dcerpc_table_$interface->{NAME}, DCERPC_$uname, mem_ctx, r);
}
NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r)
{
struct rpc_request *req;
NTSTATUS status;
req = dcerpc_$name\_send(p, mem_ctx, r);
if (req == NULL) return NT_STATUS_NO_MEMORY;
status = dcerpc_ndr_request_recv(req);
if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
NDR_PRINT_OUT_DEBUG($name, r);
}
";
if (defined($fn->{RETURN_TYPE}) and $fn->{RETURN_TYPE} eq "NTSTATUS") {
$res .= "\tif (NT_STATUS_IS_OK(status)) status = r->out.result;\n";
}
$res .=
"
return status;
}
";
}
my %done;
#####################################################################
# parse the interface definitions
sub ParseInterface($)
{
my($interface) = shift;
$res_hdr .= "#ifndef _HEADER_RPC_$interface->{NAME}\n";
$res_hdr .= "#define _HEADER_RPC_$interface->{NAME}\n\n";
if (defined $interface->{PROPERTIES}->{uuid}) {
$res_hdr .= "extern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
}
$res .= "/* $interface->{NAME} - client functions generated by pidl */\n\n";
foreach my $fn (@{$interface->{FUNCTIONS}}) {
next if not defined($fn->{OPNUM});
next if defined($done{$fn->{NAME}});
ParseFunction($interface, $fn);
$done{$fn->{NAME}} = 1;
}
$res_hdr .= "#endif /* _HEADER_RPC_$interface->{NAME} */\n";
return $res;
}
sub Parse($$$$)
{
my($ndr,$header,$ndr_header,$client_header) = @_;
$res = "";
$res_hdr = "";
$res .= "/* client functions auto-generated by pidl */\n";
$res .= "\n";
if (is_intree()) {
$res .= "#include \"includes.h\"\n";
} else {
$res .= "#define _GNU_SOURCE\n";
$res .= "#include <stdio.h>\n";
$res .= "#include <stdbool.h>\n";
$res .= "#include <stdlib.h>\n";
$res .= "#include <stdint.h>\n";
$res .= "#include <stdarg.h>\n";
$res .= "#include <core/nterr.h>\n";
}
$res .= "#include \"$ndr_header\"\n";
$res .= "#include \"$client_header\"\n";
$res .= "\n";
$res_hdr .= choose_header("librpc/rpc/dcerpc.h", "dcerpc.h")."\n";
$res_hdr .= "#include \"$header\"\n";
foreach my $x (@{$ndr}) {
($x->{TYPE} eq "INTERFACE") && ParseInterface($x);
}
return ($res,$res_hdr);
}
1;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,325 @@
###################################################
# server boilerplate generator
# Copyright tridge@samba.org 2003
# Copyright metze@samba.org 2004
# released under the GNU GPL
package Parse::Pidl::Samba4::NDR::Server;
use strict;
use Parse::Pidl::Util;
use vars qw($VERSION);
$VERSION = '0.01';
my($res);
sub pidl($)
{
$res .= shift;
}
#####################################################
# generate the switch statement for function dispatch
sub gen_dispatch_switch($)
{
my $interface = shift;
foreach my $fn (@{$interface->{FUNCTIONS}}) {
next if not defined($fn->{OPNUM});
pidl "\tcase $fn->{OPNUM}: {\n";
pidl "\t\tstruct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;\n";
pidl "\t\tif (DEBUGLEVEL >= 10) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r2);\n";
pidl "\t\t}\n";
if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
pidl "\t\tr2->out.result = $fn->{NAME}(dce_call, mem_ctx, r2);\n";
} else {
pidl "\t\t$fn->{NAME}(dce_call, mem_ctx, r2);\n";
}
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $fn->{NAME} will reply async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
}
}
#####################################################
# generate the switch statement for function reply
sub gen_reply_switch($)
{
my $interface = shift;
foreach my $fn (@{$interface->{FUNCTIONS}}) {
next if not defined($fn->{OPNUM});
pidl "\tcase $fn->{OPNUM}: {\n";
pidl "\t\tstruct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;\n";
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $fn->{NAME} replied async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tif (DEBUGLEVEL >= 10 && dce_call->fault_code == 0) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
pidl "\t\t}\n";
pidl "\t\tif (dce_call->fault_code != 0) {\n";
pidl "\t\t\tDEBUG(2,(\"dcerpc_fault %s in $fn->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code)));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
}
}
#####################################################################
# produce boilerplate code for a interface
sub Boilerplate_Iface($)
{
my($interface) = shift;
my $name = $interface->{NAME};
my $uname = uc $name;
my $uuid = lc($interface->{PROPERTIES}->{uuid});
my $if_version = $interface->{PROPERTIES}->{version};
pidl "
static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
{
#ifdef DCESRV_INTERFACE_$uname\_BIND
return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
#else
return NT_STATUS_OK;
#endif
}
static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
{
#ifdef DCESRV_INTERFACE_$uname\_UNBIND
DCESRV_INTERFACE_$uname\_UNBIND(context, iface);
#else
return;
#endif
}
static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
{
NTSTATUS status;
uint16_t opnum = dce_call->pkt.u.request.opnum;
dce_call->fault_code = 0;
if (opnum >= dcerpc_table_$name.num_calls) {
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
return NT_STATUS_NET_WRITE_FAULT;
}
*r = talloc_size(mem_ctx, dcerpc_table_$name.calls[opnum].struct_size);
NT_STATUS_HAVE_NO_MEMORY(*r);
/* unravel the NDR for the packet */
status = dcerpc_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
if (!NT_STATUS_IS_OK(status)) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
switch (opnum) {
";
gen_dispatch_switch($interface);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
switch (opnum) {
";
gen_reply_switch($interface);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
{
NTSTATUS status;
uint16_t opnum = dce_call->pkt.u.request.opnum;
status = dcerpc_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static const struct dcesrv_interface $name\_interface = {
.name = \"$name\",
.syntax_id = {".print_uuid($uuid).",$if_version},
.bind = $name\__op_bind,
.unbind = $name\__op_unbind,
.ndr_pull = $name\__op_ndr_pull,
.dispatch = $name\__op_dispatch,
.reply = $name\__op_reply,
.ndr_push = $name\__op_ndr_push
};
";
}
#####################################################################
# produce boilerplate code for an endpoint server
sub Boilerplate_Ep_Server($)
{
my($interface) = shift;
my $name = $interface->{NAME};
my $uname = uc $name;
pidl "
static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
for (i=0;i<dcerpc_table_$name.endpoints->count;i++) {
NTSTATUS ret;
const char *name = dcerpc_table_$name.endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
return ret;
}
}
return NT_STATUS_OK;
}
static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
{
if ($name\_interface.syntax_id.if_version == if_version &&
GUID_equal(\&$name\_interface.syntax_id.uuid, uuid)) {
memcpy(iface,&$name\_interface, sizeof(*iface));
return True;
}
return False;
}
static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
if (strcmp($name\_interface.name, name)==0) {
memcpy(iface,&$name\_interface, sizeof(*iface));
return True;
}
return False;
}
NTSTATUS dcerpc_server_$name\_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
/* fill in our name */
ep_server.name = \"$name\";
/* fill in all the operations */
ep_server.init_server = $name\__op_init_server;
ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
ep_server.interface_by_name = $name\__op_interface_by_name;
/* register ourselves with the DCERPC subsystem. */
ret = dcerpc_register_ep_server(&ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
return ret;
}
return ret;
}
";
}
#####################################################################
# dcerpc server boilerplate from a parsed IDL structure
sub ParseInterface($)
{
my($interface) = shift;
my $count = 0;
if (!defined $interface->{PROPERTIES}->{uuid}) {
return $res;
}
if (!defined $interface->{PROPERTIES}->{version}) {
$interface->{PROPERTIES}->{version} = "0.0";
}
foreach my $fn (@{$interface->{FUNCTIONS}}) {
if (defined($fn->{OPNUM})) { $count++; }
}
if ($count == 0) {
return $res;
}
$res .= "/* $interface->{NAME} - dcerpc server boilerplate generated by pidl */\n\n";
Boilerplate_Iface($interface);
Boilerplate_Ep_Server($interface);
return $res;
}
sub Parse($$)
{
my($ndr,$header) = @_;
$res = "";
$res .= "/* server functions auto-generated by pidl */\n";
$res .= "#include \"$header\"\n";
$res .= "\n";
foreach my $x (@{$ndr}) {
ParseInterface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
}
return $res;
}
1;
@@ -0,0 +1,176 @@
###################################################
# Samba4 parser generator for swig wrappers
# Copyright tpot@samba.org 2004,2005
# Copyright jelmer@samba.org 2006
# released under the GNU GPL
package Parse::Pidl::Samba4::SWIG;
use vars qw($VERSION);
use Parse::Pidl::Samba4 qw(DeclLong);
use Parse::Pidl::Typelist qw(mapType);
use Parse::Pidl::Util qw(has_property);
$VERSION = '0.01';
use strict;
my $ret = "";
my $tabs = "";
sub pidl($)
{
my $p = shift;
$ret .= $tabs. $p . "\n";
}
sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs,0,-1); }
sub IgnoreInterface($$)
{
my ($basename,$if) = @_;
foreach (@{$if->{TYPES}}) {
next unless (has_property($_, "public"));
pidl "\%types($_->{NAME});";
}
}
sub ParseInterface($$)
{
my ($basename,$if) = @_;
pidl "\%inline {";
pidl "struct $if->{NAME} { struct dcerpc_pipe *pipe; };";
pidl "}";
pidl "";
pidl "\%extend $if->{NAME} {";
indent();
pidl "$if->{NAME} (const char *binding, struct cli_credentials *cred = NULL, TALLOC_CTX *mem_ctx = NULL, struct event_context *event = NULL)";
pidl "{";
indent;
pidl "struct $if->{NAME} *ret = talloc(mem_ctx, struct $if->{NAME});";
pidl "NTSTATUS status;";
pidl "";
pidl "status = dcerpc_pipe_connect(mem_ctx, &ret->pipe, binding, &dcerpc_table_$if->{NAME}, cred, event);";
pidl "if (NT_STATUS_IS_ERR(status)) {";
pidl "\tntstatus_exception(status);";
pidl "\treturn NULL;";
pidl "}";
pidl "";
pidl "return ret;";
deindent;
pidl "}";
pidl "";
pidl "~$if->{NAME}() {";
pidl "\ttalloc_free(self);";
pidl "}";
pidl "";
foreach my $fn (@{$if->{FUNCTIONS}}) {
pidl "/* $fn->{NAME} */";
my $args = "";
foreach (@{$fn->{ELEMENTS}}) {
$args .= DeclLong($_) . ", ";
}
my $name = $fn->{NAME};
$name =~ s/^$if->{NAME}_//g;
$name =~ s/^$basename\_//g;
$args .= "TALLOC_CTX *mem_ctx = NULL";
pidl mapType($fn->{RETURN_TYPE}) . " $name($args)";
pidl "{";
indent;
pidl "struct $fn->{NAME} r;";
pidl "NTSTATUS status;";
pidl "";
pidl "/* Fill r structure */";
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/in/, @{$_->{DIRECTION}})) {
pidl "r.in.$_->{NAME} = $_->{NAME};";
}
}
pidl "";
pidl "status = dcerpc_$fn->{NAME}(self->pipe, mem_ctx, &r);";
pidl "if (NT_STATUS_IS_ERR(status)) {";
pidl "\tntstatus_exception(status);";
if (defined($fn->{RETURN_TYPE})) {
pidl "\treturn r.out.result;";
} else {
pidl "\treturn;";
}
pidl "}";
pidl "";
pidl "/* Set out arguments */";
foreach (@{$fn->{ELEMENTS}}) {
next unless (grep(/out/, @{$_->{DIRECTION}}));
pidl ("/* FIXME: $_->{NAME} [out] argument is not a pointer */") if ($_->{LEVELS}[0]->{TYPE} ne "POINTER");
pidl "*$_->{NAME} = *r.out.$_->{NAME};";
}
if (defined($fn->{RETURN_TYPE})) {
pidl "return r.out.result;";
}
deindent;
pidl "}";
pidl "";
}
deindent();
pidl "};";
pidl "";
foreach (@{$if->{TYPES}}) {
pidl "/* $_->{NAME} */";
}
pidl "";
}
sub Parse($$$$)
{
my($ndr,$basename,$header,$gen_header) = @_;
$ret = "";
pidl "/* This file is autogenerated by pidl. DO NOT EDIT */";
pidl "\%module $basename";
pidl "";
pidl "\%{";
pidl "#include \"includes.h\"";
pidl "#include \"auth/credentials/credentials.h\"";
pidl "#include \"$header\"";
pidl "#include \"$gen_header\"";
pidl "%}";
pidl "\%import \"samba.i\"";
pidl "";
pidl "\%inline {";
pidl "void ntstatus_exception(NTSTATUS status)";
pidl "{";
pidl "\t/* FIXME */";
pidl "}";
pidl "}";
pidl "";
foreach (@$ndr) {
IgnoreInterface($basename, $_) if ($_->{TYPE} eq "INTERFACE");
}
pidl "";
pidl "";
foreach (@$ndr) {
ParseInterface($basename, $_) if ($_->{TYPE} eq "INTERFACE");
}
#FIXME: Foreach ref pointer, set NONNULL
#FIXME: Foreach unique/full pointer, set MAYBENULL
#FIXME: Foreach [out] parameter, set OUTPARAM
return $ret;
}
1;
@@ -0,0 +1,263 @@
###################################################
# Trivial Parser Generator
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Samba4::TDR;
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
use Parse::Pidl::Samba4 qw(is_intree choose_header);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
my $ret;
my $ret_hdr;
my $tabs = "";
sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs, 1); }
sub pidl($) { $ret .= $tabs.(shift)."\n"; }
sub pidl_hdr($) { $ret_hdr .= (shift)."\n"; }
sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
sub typearg($) {
my $t = shift;
return(", const char *name") if ($t eq "print");
return(", TALLOC_CTX *mem_ctx") if ($t eq "pull");
return("");
}
sub fn_declare($$)
{
my ($p, $d) = @_;
if ($p) { pidl $d; pidl_hdr "$d;"; } else { pidl "static $d"; }
}
sub ContainsArray($)
{
my $e = shift;
foreach (@{$e->{ELEMENTS}}) {
next if (has_property($_, "charset") and
scalar(@{$_->{ARRAY_LEN}}) == 1);
return 1 if (defined($_->{ARRAY_LEN}) and
scalar(@{$_->{ARRAY_LEN}}) > 0);
}
return 0;
}
sub ParserElement($$$)
{
my ($e,$t,$env) = @_;
my $switch = "";
my $array = "";
my $name = "";
my $mem_ctx = "mem_ctx";
fatal($e,"Pointers not supported in TDR") if ($e->{POINTERS} > 0);
fatal($e,"size_is() not supported in TDR") if (has_property($e, "size_is"));
fatal($e,"length_is() not supported in TDR") if (has_property($e, "length_is"));
if ($t eq "print") {
$name = ", \"$e->{NAME}\"$array";
}
if (has_property($e, "flag")) {
pidl "{";
indent;
pidl "uint32_t saved_flags = tdr->flags;";
pidl "tdr->flags |= $e->{PROPERTIES}->{flag};";
}
if (has_property($e, "charset")) {
fatal($e,"charset() on non-array element") unless (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0);
my $len = ParseExpr(@{$e->{ARRAY_LEN}}[0], $env);
if ($len eq "*") { $len = "-1"; }
$name = ", mem_ctx" if ($t eq "pull");
pidl "TDR_CHECK(tdr_$t\_charset(tdr$name, &v->$e->{NAME}, $len, sizeof($e->{TYPE}_t), CH_$e->{PROPERTIES}->{charset}));";
return;
}
if (has_property($e, "switch_is")) {
$switch = ", " . ParseExpr($e->{PROPERTIES}->{switch_is}, $env);
}
if (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0) {
my $len = ParseExpr($e->{ARRAY_LEN}[0], $env);
if ($t eq "pull" and not is_constant($len)) {
pidl "TDR_ALLOC(mem_ctx, v->$e->{NAME}, $len);";
$mem_ctx = "v->$e->{NAME}";
}
pidl "for (i = 0; i < $len; i++) {";
indent;
$array = "[i]";
}
if ($t eq "pull") {
$name = ", $mem_ctx";
}
if (has_property($e, "value") && $t eq "push") {
pidl "v->$e->{NAME} = ".ParseExpr($e->{PROPERTIES}->{value}, $env).";";
}
pidl "TDR_CHECK(tdr_$t\_$e->{TYPE}(tdr$name$switch, &v->$e->{NAME}$array));";
if ($array) { deindent; pidl "}"; }
if (has_property($e, "flag")) {
pidl "tdr->flags = saved_flags;";
deindent;
pidl "}";
}
}
sub ParserStruct($$$$)
{
my ($e,$n,$t,$p) = @_;
fn_declare($p,,"NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", struct $n *v)");
pidl "{"; indent;
pidl "int i;" if (ContainsArray($e));
if ($t eq "print") {
pidl "tdr->print(tdr, \"\%-25s: struct $n\", name);";
pidl "tdr->level++;";
}
my %env = map { $_->{NAME} => "v->$_->{NAME}" } @{$e->{ELEMENTS}};
$env{"this"} = "v";
ParserElement($_, $t, \%env) foreach (@{$e->{ELEMENTS}});
if ($t eq "print") {
pidl "tdr->level--;";
}
pidl "return NT_STATUS_OK;";
deindent; pidl "}";
}
sub ParserUnion($$$$)
{
my ($e,$n,$t,$p) = @_;
fn_declare($p,"NTSTATUS tdr_$t\_$n(struct tdr_$t *tdr".typearg($t).", int level, union $n *v)");
pidl "{"; indent;
pidl "int i;" if (ContainsArray($e));
if ($t eq "print") {
pidl "tdr->print(tdr, \"\%-25s: union $n\", name);";
pidl "tdr->level++;";
}
pidl "switch (level) {"; indent;
foreach (@{$e->{ELEMENTS}}) {
if (has_property($_, "case")) {
pidl "case " . $_->{PROPERTIES}->{case} . ":";
} elsif (has_property($_, "default")) {
pidl "default:";
}
indent; ParserElement($_, $t, {}); deindent;
pidl "break;";
}
deindent; pidl "}";
if ($t eq "print") {
pidl "tdr->level--;";
}
pidl "return NT_STATUS_OK;\n";
deindent; pidl "}";
}
sub ParserBitmap($$$$)
{
my ($e,$n,$t,$p) = @_;
return if ($p);
pidl "#define tdr_$t\_$n tdr_$t\_" . Parse::Pidl::Typelist::bitmap_type_fn($e);
}
sub ParserEnum($$$$)
{
my ($e,$n,$t,$p) = @_;
my $bt = ($e->{PROPERTIES}->{base_type} or "uint8");
fn_declare($p, "NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", enum $n *v)");
pidl "{";
if ($t eq "pull") {
pidl "\t$bt\_t r;";
pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, mem_ctx, \&r));";
pidl "\t*v = r;";
} elsif ($t eq "push") {
pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, ($bt\_t *)v));";
} elsif ($t eq "print") {
pidl "\t/* FIXME */";
}
pidl "\treturn NT_STATUS_OK;";
pidl "}";
}
sub ParserTypedef($$)
{
my ($e,$t) = @_;
return if (has_property($e, "no$t"));
$e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
{ STRUCT => \&ParserStruct, UNION => \&ParserUnion,
ENUM => \&ParserEnum, BITMAP => \&ParserBitmap
}->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $t, has_property($e, "public"));
pidl "";
}
sub ParserInterface($)
{
my $x = shift;
pidl_hdr "#ifndef __TDR_$x->{NAME}_HEADER__";
pidl_hdr "#define __TDR_$x->{NAME}_HEADER__";
foreach (@{$x->{DATA}}) {
next if ($_->{TYPE} ne "TYPEDEF");
ParserTypedef($_, "pull");
ParserTypedef($_, "push");
ParserTypedef($_, "print");
}
pidl_hdr "#endif /* __TDR_$x->{NAME}_HEADER__ */";
}
sub Parser($$$)
{
my ($idl,$hdrname,$baseheader) = @_;
$ret = ""; $ret_hdr = "";
pidl "/* autogenerated by pidl */";
if (is_intree()) {
pidl "#include \"includes.h\"";
} else {
pidl "#include <stdio.h>";
pidl "#include <stdbool.h>";
pidl "#include <stdlib.h>";
pidl "#include <stdint.h>";
pidl "#include <stdarg.h>";
pidl "#include <string.h>";
pidl "#include <core/nterr.h>";
}
pidl "#include \"$hdrname\"";
pidl "";
pidl_hdr "/* autogenerated by pidl */";
pidl_hdr "#include \"$baseheader\"";
pidl_hdr choose_header("tdr/tdr.h", "tdr.h");
pidl_hdr "";
foreach (@$idl) { ParserInterface($_) if ($_->{TYPE} eq "INTERFACE"); }
return ($ret_hdr, $ret);
}
1;
@@ -0,0 +1,99 @@
###################################################
# server template function generator
# Copyright tridge@samba.org 2003
# released under the GNU GPL
package Parse::Pidl::Samba4::Template;
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
my($res);
#####################################################################
# produce boilerplate code for a interface
sub Template($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my $name = $interface->{NAME};
$res .=
"/*
Unix SMB/CIFS implementation.
endpoint server for the $name pipe
Copyright (C) YOUR NAME HERE YEAR
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include \"includes.h\"
#include \"rpc_server/dcerpc_server.h\"
#include \"librpc/gen_ndr/ndr_$name.h\"
#include \"rpc_server/common/common.h\"
";
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") {
my $fname = $d->{NAME};
$res .=
"
/*
$fname
*/
static $d->{RETURN_TYPE} $fname(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct $fname *r)
{
";
if ($d->{RETURN_TYPE} eq "void") {
$res .= "\tDCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);\n";
} else {
$res .= "\tDCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);\n";
}
$res .= "}
";
}
}
$res .=
"
/* include the generated boilerplate */
#include \"librpc/gen_ndr/ndr_$name\_s.c\"
"
}
#####################################################################
# parse a parsed IDL structure back into an IDL file
sub Parse($)
{
my($idl) = shift;
$res = "";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") &&
Template($x);
}
return $res;
}
1;
@@ -0,0 +1,230 @@
###################################################
# Samba4 parser generator for IDL structures
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Typelist;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(hasType getType mapType scalar_is_reference expandAlias);
use vars qw($VERSION);
$VERSION = '0.01';
use Parse::Pidl::Util qw(has_property);
use strict;
my %typedefs = ();
my @reference_scalars = (
"string", "string_array", "nbt_string",
"wrepl_nbt_name", "ipv4address"
);
# a list of known scalar types
my %scalars = (
"void" => "void",
"char" => "char",
"int8" => "int8_t",
"uint8" => "uint8_t",
"int16" => "int16_t",
"uint16" => "uint16_t",
"int32" => "int32_t",
"uint32" => "uint32_t",
"hyper" => "uint64_t",
"dlong" => "int64_t",
"udlong" => "uint64_t",
"udlongr" => "uint64_t",
"pointer" => "void*",
"DATA_BLOB" => "DATA_BLOB",
"string" => "const char *",
"string_array" => "const char **",
"time_t" => "time_t",
"NTTIME" => "NTTIME",
"NTTIME_1sec" => "NTTIME",
"NTTIME_hyper" => "NTTIME",
"WERROR" => "WERROR",
"NTSTATUS" => "NTSTATUS",
"COMRESULT" => "COMRESULT",
"nbt_string" => "const char *",
"wrepl_nbt_name"=> "struct nbt_name *",
"ipv4address" => "const char *",
);
my %aliases = (
"error_status_t" => "uint32",
"boolean8" => "uint8",
"boolean32" => "uint32",
"DWORD" => "uint32",
"int" => "int32",
"WORD" => "uint16",
"char" => "uint8",
"long" => "int32",
"short" => "int16",
"HYPER_T" => "hyper",
"HRESULT" => "COMRESULT",
);
sub expandAlias($)
{
my $name = shift;
return $aliases{$name} if defined($aliases{$name});
return $name;
}
# map from a IDL type to a C header type
sub mapScalarType($)
{
my $name = shift;
# it's a bug when a type is not in the list
# of known scalars or has no mapping
return $scalars{$name} if defined($scalars{$name});
die("Unknown scalar type $name");
}
sub addType($)
{
my $t = shift;
$typedefs{$t->{NAME}} = $t;
}
sub getType($)
{
my $t = shift;
return undef if not hasType($t);
return $typedefs{$t};
}
sub typeIs($$)
{
my ($t,$tt) = @_;
return 1 if (hasType($t) and getType($t)->{DATA}->{TYPE} eq $tt);
return 0;
}
sub hasType($)
{
my $t = shift;
return 1 if defined($typedefs{$t});
return 0;
}
sub is_scalar($)
{
my $type = shift;
return 0 unless(hasType($type));
if (my $dt = getType($type)->{DATA}->{TYPE}) {
return 1 if ($dt eq "SCALAR" or $dt eq "ENUM" or $dt eq "BITMAP");
}
return 0;
}
sub scalar_is_reference($)
{
my $name = shift;
return 1 if (grep(/^$name$/, @reference_scalars));
return 0;
}
sub RegisterScalars()
{
foreach (keys %scalars) {
addType({
NAME => $_,
TYPE => "TYPEDEF",
DATA => {
TYPE => "SCALAR",
NAME => $_
}
}
);
}
}
sub enum_type_fn($)
{
my $enum = shift;
$enum->{TYPE} eq "ENUM" or die("not an enum");
if (has_property($enum->{PARENT}, "enum8bit")) {
return "uint8";
} elsif (has_property($enum->{PARENT}, "v1_enum")) {
return "uint32";
}
return "uint16";
}
sub bitmap_type_fn($)
{
my $bitmap = shift;
$bitmap->{TYPE} eq "BITMAP" or die("not a bitmap");
if (has_property($bitmap, "bitmap8bit")) {
return "uint8";
} elsif (has_property($bitmap, "bitmap16bit")) {
return "uint16";
} elsif (has_property($bitmap, "bitmap64bit")) {
return "hyper";
}
return "uint32";
}
sub mapType($)
{
my $t = shift;
return "void" unless defined($t);
my $dt;
$t = expandAlias($t);
unless ($dt or ($dt = getType($t))) {
# Best guess
return "struct $t";
}
return mapScalarType($t) if ($dt->{DATA}->{TYPE} eq "SCALAR");
return "$dt->{NAME}" if ($dt->{DATA}{TYPE} eq "DECORATED");
return "enum $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "ENUM");
return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "STRUCT");
return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "INTERFACE");
return "union $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "UNION");
if ($dt->{DATA}->{TYPE} eq "BITMAP") {
return mapScalarType(bitmap_type_fn($dt->{DATA}));
}
die("Unknown type $dt->{DATA}->{TYPE}");
}
sub LoadIdl($)
{
my $idl = shift;
foreach my $x (@{$idl}) {
next if $x->{TYPE} ne "INTERFACE";
# DCOM interfaces can be types as well
addType({
NAME => $x->{NAME},
TYPE => "TYPEDEF",
DATA => $x
}) if (has_property($x, "object"));
foreach my $y (@{$x->{DATA}}) {
addType($y) if (
$y->{TYPE} eq "TYPEDEF"
or $y->{TYPE} eq "DECLARE");
}
}
}
RegisterScalars();
1;
+123
View File
@@ -0,0 +1,123 @@
###################################################
# utility functions to support pidl
# Copyright tridge@samba.org 2000
# released under the GNU GPL
package Parse::Pidl::Util;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(has_property property_matches ParseExpr is_constant make_str print_uuid);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
#####################################################################
# a dumper wrapper to prevent dependence on the Data::Dumper module
# unless we actually need it
sub MyDumper($)
{
require Data::Dumper;
my $s = shift;
return Data::Dumper::Dumper($s);
}
#####################################################################
# see if a pidl property list contains a given property
sub has_property($$)
{
my($e) = shift;
my($p) = shift;
if (!defined $e->{PROPERTIES}) {
return undef;
}
return $e->{PROPERTIES}->{$p};
}
#####################################################################
# see if a pidl property matches a value
sub property_matches($$$)
{
my($e) = shift;
my($p) = shift;
my($v) = shift;
if (!defined has_property($e, $p)) {
return undef;
}
if ($e->{PROPERTIES}->{$p} =~ /$v/) {
return 1;
}
return undef;
}
# return 1 if the string is a C constant
sub is_constant($)
{
my $s = shift;
if (defined $s && $s =~ /^\d/) {
return 1;
}
return 0;
}
# return a "" quoted string, unless already quoted
sub make_str($)
{
my $str = shift;
if (substr($str, 0, 1) eq "\"") {
return $str;
}
return "\"" . $str . "\"";
}
sub print_uuid($)
{
my ($uuid) = @_;
$uuid =~ s/"//g;
my ($time_low,$time_mid,$time_hi,$clock_seq,$node) = split /-/, $uuid;
my @clock_seq = $clock_seq =~ /(..)/g;
my @node = $node =~ /(..)/g;
return "{0x$time_low,0x$time_mid,0x$time_hi," .
"{".join(',', map {"0x$_"} @clock_seq)."}," .
"{".join(',', map {"0x$_"} @node)."}}";
}
# a hack to build on platforms that don't like negative enum values
my $useUintEnums = 0;
sub setUseUintEnums($)
{
$useUintEnums = shift;
}
sub useUintEnums()
{
return $useUintEnums;
}
sub ParseExpr($$)
{
my($expr,$varlist) = @_;
die("Undefined value in ParseExpr " . (caller(1))[3] . (caller(0))[2]) if not defined($expr);
my @tokens = split /((?:[A-Za-z_])(?:(?:(?:[A-Za-z0-9_.])|(?:->))+))/, $expr;
my $ret = "";
foreach my $t (@tokens) {
if (defined($varlist->{$t})) {
$ret .= $varlist->{$t};
} else {
$ret .= $t;
}
}
return $ret;
}
1;
@@ -0,0 +1,360 @@
###################################################
# parse an Wireshark conformance file
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
=pod
=head1 NAME
Parse::Pidl::Wireshark::Conformance - Conformance file parser for Wireshark
=head1 DESCRIPTION
This module supports parsing Wireshark conformance files (*.cnf).
=head1 FILE FORMAT
Pidl needs additional data for Wireshark output. This data is read from
so-called conformance files. This section describes the format of these
files.
Conformance files are simple text files with a single command on each line.
Empty lines and lines starting with a '#' character are ignored.
Arguments to commands are seperated by spaces.
The following commands are currently supported:
=over 4
=item I<TYPE> name dissector ft_type base_type mask valsstring alignment
Register new data type with specified name, what dissector function to call
and what properties to give header fields for elements of this type.
=item I<NOEMIT> type
Suppress emitting a dissect_type function for the specified type
=item I<PARAM_VALUE> type param
Set parameter to specify to dissector function for given type.
=item I<HF_FIELD> hf title filter ft_type base_type valsstring mask description
Generate a custom header field with specified properties.
=item I<HF_RENAME> old_hf_name new_hf_name
Force the use of new_hf_name when the parser generator was going to
use old_hf_name.
This can be used in conjunction with HF_FIELD in order to make more than
one element use the same filter name.
=item I<STRIP_PREFIX> prefix
Remove the specified prefix from all function names (if present).
=item I<PROTOCOL> longname shortname filtername
Change the short-, long- and filter-name for the current interface in
Wireshark.
=item I<FIELD_DESCRIPTION> field desc
Change description for the specified header field. `field' is the hf name of the field.
=item I<IMPORT> dissector code...
Code to insert when generating the specified dissector. @HF@ and
@PARAM@ will be substituted.
=item I<TFS> hf_name "true string" "false string"
Override the text shown when a bitmap boolean value is enabled or disabled.
=item I<MANUAL> fn_name
Force pidl to not generate a particular function but allow the user
to write a function manually. This can be used to remove the function
for only one level for a particular element rather than all the functions and
ett/hf variables for a particular element as the NOEMIT command does.
=back
=head1 EXAMPLE
INFO_KEY OpenKey.Ke
=cut
package Parse::Pidl::Wireshark::Conformance;
require Exporter;
use vars qw($VERSION);
$VERSION = '0.01';
@ISA = qw(Exporter);
@EXPORT_OK = qw(ReadConformance);
use strict;
use Parse::Pidl::Util qw(has_property);
sub handle_type($$$$$$$$$$)
{
my ($pos,$data,$name,$dissectorname,$ft_type,$base_type,$mask,$valsstring,$alignment) = @_;
unless(defined($alignment)) {
print "$pos: error incomplete TYPE command\n";
return;
}
unless ($dissectorname =~ /.*dissect_.*/) {
print "$pos: warning: dissector name does not contain `dissect'\n";
}
unless(valid_ft_type($ft_type)) {
print "$pos: warning: invalid FT_TYPE `$ft_type'\n";
}
unless (valid_base_type($base_type)) {
print "$pos: warning: invalid BASE_TYPE `$base_type'\n";
}
$data->{types}->{$name} = {
NAME => $name,
POS => $pos,
USED => 0,
DISSECTOR_NAME => $dissectorname,
FT_TYPE => $ft_type,
BASE_TYPE => $base_type,
MASK => $mask,
VALSSTRING => $valsstring,
ALIGNMENT => $alignment
};
}
sub handle_tfs($$$$$)
{
my ($pos,$data,$hf,$trues,$falses) = @_;
unless(defined($falses)) {
print "$pos: error: incomplete TFS command\n";
return;
}
$data->{tfs}->{$hf} = {
TRUE_STRING => $trues,
FALSE_STRING => $falses
};
}
sub handle_hf_rename($$$$)
{
my ($pos,$data,$old,$new) = @_;
unless(defined($new)) {
print "$pos: error: incomplete HF_RENAME command\n";
return;
}
$data->{hf_renames}->{$old} = {
OLDNAME => $old,
NEWNAME => $new,
POS => $pos,
USED => 0
};
}
sub handle_param_value($$$$)
{
my ($pos,$data,$dissector_name,$value) = @_;
unless(defined($value)) {
print "$pos: error: incomplete PARAM_VALUE command\n";
return;
}
$data->{dissectorparams}->{$dissector_name} = {
DISSECTOR => $dissector_name,
PARAM => $value,
POS => $pos,
USED => 0
};
}
sub valid_base_type($)
{
my $t = shift;
return 0 unless($t =~ /^BASE_.*/);
return 1;
}
sub valid_ft_type($)
{
my $t = shift;
return 0 unless($t =~ /^FT_.*/);
return 1;
}
sub handle_hf_field($$$$$$$$$$)
{
my ($pos,$data,$index,$name,$filter,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
unless(defined($blurb)) {
print "$pos: error: incomplete HF_FIELD command\n";
return;
}
unless(valid_ft_type($ft_type)) {
print "$pos: warning: invalid FT_TYPE `$ft_type'\n";
}
unless(valid_base_type($base_type)) {
print "$pos: warning: invalid BASE_TYPE `$base_type'\n";
}
$data->{header_fields}->{$index} = {
INDEX => $index,
POS => $pos,
USED => 0,
NAME => $name,
FILTER => $filter,
FT_TYPE => $ft_type,
BASE_TYPE => $base_type,
VALSSTRING => $valsstring,
MASK => $mask,
BLURB => $blurb
};
}
sub handle_strip_prefix($$$)
{
my ($pos,$data,$x) = @_;
push (@{$data->{strip_prefixes}}, $x);
}
sub handle_noemit($$$)
{
my ($pos,$data,$type) = @_;
if (defined($type)) {
$data->{noemit}->{$type} = 1;
} else {
$data->{noemit_dissector} = 1;
}
}
sub handle_manual($$$)
{
my ($pos,$data,$fn) = @_;
$data->{manual}->{$fn} = 1;
}
sub handle_protocol($$$$$$)
{
my ($pos, $data, $name, $longname, $shortname, $filtername) = @_;
$data->{protocols}->{$name} = {
LONGNAME => $longname,
SHORTNAME => $shortname,
FILTERNAME => $filtername
};
}
sub handle_fielddescription($$$$)
{
my ($pos,$data,$field,$desc) = @_;
$data->{fielddescription}->{$field} = {
DESCRIPTION => $desc,
POS => $pos,
USED => 0
};
}
sub handle_import
{
my $pos = shift @_;
my $data = shift @_;
my $dissectorname = shift @_;
unless(defined($dissectorname)) {
print "$pos: error: no dissectorname specified\n";
return;
}
$data->{imports}->{$dissectorname} = {
NAME => $dissectorname,
DATA => join(' ', @_),
USED => 0,
POS => $pos
};
}
my %field_handlers = (
TYPE => \&handle_type,
NOEMIT => \&handle_noemit,
MANUAL => \&handle_manual,
PARAM_VALUE => \&handle_param_value,
HF_FIELD => \&handle_hf_field,
HF_RENAME => \&handle_hf_rename,
TFS => \&handle_tfs,
STRIP_PREFIX => \&handle_strip_prefix,
PROTOCOL => \&handle_protocol,
FIELD_DESCRIPTION => \&handle_fielddescription,
IMPORT => \&handle_import
);
sub ReadConformance($$)
{
my ($f,$data) = @_;
$data->{override} = "";
my $incodeblock = 0;
open(IN,"<$f") or return undef;
my $ln = 0;
foreach (<IN>) {
$ln++;
next if (/^#.*$/);
next if (/^$/);
s/[\r\n]//g;
if ($_ eq "CODE START") {
$incodeblock = 1;
next;
} elsif ($incodeblock and $_ eq "CODE END") {
$incodeblock = 0;
next;
} elsif ($incodeblock) {
$data->{override}.="$_\n";
next;
}
my @fields = /([^ "]+|"[^"]+")/g;
my $cmd = $fields[0];
shift @fields;
if (not defined($field_handlers{$cmd})) {
print "$f:$ln: warning: Unknown command `$cmd'\n";
next;
}
$field_handlers{$cmd}("$f:$ln", $data, @fields);
}
close(IN);
}
1;
File diff suppressed because it is too large Load Diff