pidl:NDR/ServerCompat: Compat server PIDL parser
authorSamuel Cabrero <scabrero@suse.de>
Tue, 15 Jan 2019 16:55:07 +0000 (17:55 +0100)
committerSamuel Cabrero <scabrero@sn-devel-184>
Fri, 20 Mar 2020 15:36:31 +0000 (15:36 +0000)
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
buildtools/wafsamba/samba_pidl.py
librpc/idl/wscript_build
pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm [new file with mode: 0644]
pidl/pidl

index d7e1247aa20ea6d50129c775b6413adcf279b009..0ce860ca6ae629a0de1247e4b08c68a4400ae8dc 100644 (file)
@@ -28,6 +28,7 @@ def SAMBA_PIDL(bld, pname, source,
                     '--samba3-ndr-server' : 'srv_%s.c srv_%s.h',
                     '--samba3-ndr-client' : 'cli_%s.c cli_%s.h',
                     '--server'            : 'ndr_%s_s.c',
+                    '--server-compat'     : 'ndr_%s_scompat.c ndr_%s_scompat.h',
                     '--client'            : 'ndr_%s_c.c ndr_%s_c.h',
                     '--python'            : 'py_%s.c',
                     '--tdr-parser'        : 'tdr_%s.c tdr_%s.h',
index b66f27be901e2113994efe7e8c1d7f6ee3676f0d..7acf5542fa2f0d8737e351d9a7f6e444209c818b 100644 (file)
@@ -11,7 +11,7 @@ bld.SAMBA_PIDL_LIST('PIDL',
                        svcctl.idl wkssvc.idl eventlog6.idl backupkey.idl
                        witness.idl clusapi.idl
                        mdssvc.idl''',
-                    options='--header --ndr-parser --samba3-ndr-server --server --client --python',
+                    options='--header --ndr-parser --samba3-ndr-server --server-compat --server --client --python',
                     output_dir='../gen_ndr')
 
 # The interface names here are not the same as the IDL name, so the
@@ -21,7 +21,7 @@ bld.SAMBA_PIDL_LIST('PIDL',
                        fsrvp.idl
                        lsa.idl
                        winspool.idl''',
-                    options='--header --ndr-parser --samba3-ndr-server --server --client --python',
+                    options='--header --ndr-parser --samba3-ndr-server --server-compat --server --client --python',
                     output_dir='../gen_ndr',
                     generate_fuzzers=False)
 
@@ -34,14 +34,14 @@ bld.SAMBA_PIDL_LIST('PIDL',
 # Services that we only have a server in the source3 style
 bld.SAMBA_PIDL_LIST('PIDL',
                     '''initshutdown.idl ntsvcs.idl''',
-                    options='--header --ndr-parser --client --python --samba3-ndr-server',
+                    options='--header --ndr-parser --client --python --samba3-ndr-server --server-compat',
                     output_dir='../gen_ndr')
 
 # The interface names here are not the same as the IDL name, so the
 # auto-genration of the fuzzer fails to link
 bld.SAMBA_PIDL_LIST('PIDL',
                     '''dfs.idl''',
-                    options='--header --ndr-parser --client --python --samba3-ndr-server',
+                    options='--header --ndr-parser --client --python --samba3-ndr-server --server-compat',
                     output_dir='../gen_ndr',
                     generate_fuzzers=False)
 
@@ -170,6 +170,6 @@ bld.SAMBA_PIDL_LIST('PIDL',
 
 bld.SAMBA_PIDL_LIST('PIDL',
                     'winbind.idl',
-                    options='--header --ndr-parser --samba3-ndr-server --client --python',
+                    options='--header --ndr-parser --samba3-ndr-server --server-compat --client --python',
                     output_dir='../gen_ndr')
 
diff --git a/pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm b/pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm
new file mode 100644 (file)
index 0000000..236e6e1
--- /dev/null
@@ -0,0 +1,488 @@
+###################################################
+# server boilerplate generator
+# Copyright tridge@samba.org 2003
+# Copyright metze@samba.org 2004
+# Copyright scabrero@samba.org 2019
+# released under the GNU GPL
+
+package Parse::Pidl::Samba4::NDR::ServerCompat;
+
+use Exporter;
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(Parse);
+
+use Parse::Pidl::Util qw(print_uuid);
+use Parse::Pidl::Typelist qw(mapTypeName);
+
+use vars qw($VERSION);
+$VERSION = '1.0';
+
+use strict;
+
+sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
+sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
+sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
+sub pidlnoindent($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$txt\n" : "\n"; }
+sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
+sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; }
+
+sub new($)
+{
+       my ($class) = shift;
+       my $self = { res => "", res_hdr => "", tabs => "" };
+       bless($self, $class);
+}
+
+#####################################################
+# generate the switch statement for function dispatch
+sub gen_dispatch_switch($)
+{
+       my ($self, $interface) = @_;
+
+       foreach my $fn (@{$interface->{FUNCTIONS}}) {
+               next if not defined($fn->{OPNUM});
+
+               my $fname = $fn->{NAME};
+               my $ufname = uc($fname);
+
+               $self->pidl("case $fn->{OPNUM}: { /* $fn->{NAME} */");
+               $self->indent();
+               $self->pidl("struct $fname *r2 = (struct $fname *)r;");
+               $self->pidl("if (DEBUGLEVEL >= 10) {");
+               $self->indent();
+               $self->pidl("NDR_PRINT_FUNCTION_DEBUG($fname, NDR_IN, r2);");
+               $self->deindent();
+               $self->pidl("}");
+
+               $self->pidl_hdr("struct $fname;");
+
+               if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
+                       $self->pidl_hdr(mapTypeName($fn->{RETURN_TYPE}) . " _$fname(struct pipes_struct *p, struct $fname *r);");
+                       $self->pidl("r2->out.result = _$fname(p, r2);");
+               } else {
+                       $self->pidl_hdr("void _$fname(struct pipes_struct *p, struct $fname *r);");
+                       $self->pidl("_$fname(p, r2);");
+               }
+
+               $self->pidl("break;");
+               $self->deindent();
+               $self->pidl("}");
+       }
+}
+
+#####################################################
+# generate the switch statement for function reply
+sub gen_reply_switch($)
+{
+       my ($self, $interface) = @_;
+
+       foreach my $fn (@{$interface->{FUNCTIONS}}) {
+               next if not defined($fn->{OPNUM});
+
+               $self->pidl("case $fn->{OPNUM}: { /* $fn->{NAME} */");
+               $self->indent();
+               $self->pidl("struct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;");
+               $self->pidl("if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {");
+               $self->indent();
+               $self->pidl("DEBUG(5,(\"function $fn->{NAME} replied async\\n\"));");
+               $self->deindent();
+               $self->pidl("}");
+               $self->pidl("if (DEBUGLEVEL >= 10 && dce_call->fault_code == 0) {");
+               $self->indent();
+               $self->pidl("NDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);");
+               $self->deindent();
+               $self->pidl("}");
+               $self->pidl("if (dce_call->fault_code != 0) {");
+               $self->indent();
+               $self->pidl("DBG_WARNING(\"dcerpc_fault %s in $fn->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code));");
+               $self->deindent();
+               $self->pidl("}");
+               $self->pidl("break;");
+               $self->deindent();
+               $self->pidl("}");
+       }
+}
+
+#####################################################################
+# produce boilerplate code for a interface
+sub boilerplate_iface($)
+{
+       my ($self, $interface) = @_;
+
+       my $name = $interface->{NAME};
+       my $uname = uc $name;
+       my $uuid = lc($interface->{UUID});
+       my $if_version = $interface->{VERSION};
+
+       $self->pidl("static NTSTATUS $name\__op_bind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("/* TODO Retrieve pipes struct */");
+       $self->pidl("/* TODO Init pipe handles */");
+       $self->pidl("/* TODO Init pipe context */");
+       $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_BIND");
+       $self->pidl("return DCESRV_INTERFACE_$uname\_BIND(context,iface);");
+       $self->pidlnoindent("#else");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("#endif");
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)");
+       $self->pidl("{");
+       $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_UNBIND");
+       $self->indent();
+       $self->pidl("DCESRV_INTERFACE_$uname\_UNBIND(context, iface);");
+       $self->pidlnoindent("#else");
+       $self->pidl("return;");
+       $self->pidlnoindent("#endif");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("enum ndr_err_code ndr_err;");
+       $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
+       $self->pidl("");
+       $self->pidl("dce_call->fault_code = 0;");
+       $self->pidl("");
+       $self->pidl("if (opnum >= ndr_table_$name.num_calls) {");
+       $self->indent();
+       $self->pidl("dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;");
+       $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("*r = talloc_named(mem_ctx, ndr_table_$name.calls[opnum].struct_size, \"struct %s\", ndr_table_$name.calls[opnum].name);");
+       $self->pidl("NT_STATUS_HAVE_NO_MEMORY(*r);");
+       $self->pidl("");
+       $self->pidl("/* unravel the NDR for the packet */");
+       $self->pidl("ndr_err = ndr_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);");
+       $self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {");
+       $self->indent();
+       $self->pidl("dce_call->fault_code = DCERPC_FAULT_NDR;");
+       $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
+       $self->pidl("struct pipes_struct *p = NULL;");
+       $self->pidl("NTSTATUS status = NT_STATUS_OK;");
+       $self->pidl("");
+       $self->pidl("/* TODO Retrieve pipes struct */");
+       $self->pidl("/* TODO Update pipes struct opnum */");
+       $self->pidl("/* TODO Update pipes struct session info */");
+       $self->pidl("/* TODO Reset pipes struct fault state */");
+       $self->pidl("");
+       $self->pidl("switch (opnum) {");
+       $self->gen_dispatch_switch($interface);
+       $self->pidl("default:");
+       $self->indent();
+       $self->pidl("dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;");
+       $self->pidl("break;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("/* TODO Check pipes struct fault state */");
+       $self->pidl("if (dce_call->fault_code != 0) {");
+       $self->indent();
+       $self->pidl("status = NT_STATUS_NET_WRITE_FAULT;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("return status;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
+       $self->pidl("");
+       $self->pidl("switch (opnum) {");
+       $self->gen_reply_switch($interface);
+       $self->pidl("default:");
+       $self->indent();
+       $self->pidl("dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;");
+       $self->pidl("break;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("if (dce_call->fault_code != 0) {");
+       $self->indent();
+       $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("enum ndr_err_code ndr_err;");
+       $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
+       $self->pidl("");
+       $self->pidl("ndr_err = ndr_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);");
+       $self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {");
+       $self->indent();
+       $self->pidl("dce_call->fault_code = DCERPC_FAULT_NDR;");
+       $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static const struct dcesrv_interface dcesrv\_$name\_interface = {");
+       $self->indent();
+       $self->pidl(".name      = \"$name\",");
+       $self->pidl(".syntax_id = {".print_uuid($uuid).",$if_version},");
+       $self->pidl(".bind      = $name\__op_bind,");
+       $self->pidl(".unbind    = $name\__op_unbind,");
+       $self->pidl(".ndr_pull  = $name\__op_ndr_pull,");
+       $self->pidl(".dispatch  = $name\__op_dispatch,");
+       $self->pidl(".reply     = $name\__op_reply,");
+       $self->pidl(".ndr_push  = $name\__op_ndr_push,");
+       $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_FLAGS");
+       $self->pidl(".flags     = DCESRV_INTERFACE_$uname\_FLAGS");
+       $self->pidlnoindent("#else");
+       $self->pidl(".flags     = 0");
+       $self->pidlnoindent("#endif");
+       $self->deindent();
+       $self->pidl("};");
+       $self->pidl("");
+}
+
+#####################################################################
+# produce boilerplate code for an endpoint server
+sub boilerplate_ep_server($)
+{
+       my ($self, $interface) = @_;
+       my $name = $interface->{NAME};
+       my $uname = uc $name;
+
+       $self->pidl("static NTSTATUS $name\__check_register_in_endpoint(const char *name, struct dcerpc_binding *binding) {");
+       $self->indent();
+       $self->pidl("enum dcerpc_transport_t transport = dcerpc_binding_get_transport(binding);");
+       $self->pidl("");
+       $self->pidl("/* If service is embedded, register only for ncacn_np");
+       $self->pidl(" * see 8466b3c85e4b835e57e41776853093f4a0edc8b8");
+       $self->pidl(" */");
+       $self->pidl("if (rpc_service_mode(name) == RPC_SERVICE_MODE_EMBEDDED && transport != NCACN_NP) {");
+       $self->indent();
+       $self->pidl("DBG_INFO(\"Interface \'$name\' not registered in endpoint \'%s\' as service is embedded\\n\", name);");
+       $self->pidl("return NT_STATUS_NOT_SUPPORTED;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("int i;");
+       $self->pidl("NTSTATUS ret;");
+       $self->pidl("struct dcerpc_binding *binding;");
+       $self->pidl("");
+       $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_NCACN_NP_SECONDARY_ENDPOINT");
+       $self->pidl("const char *ncacn_np_secondary_endpoint = DCESRV_INTERFACE_$uname\_NCACN_NP_SECONDARY_ENDPOINT;");
+       $self->pidlnoindent("#else");
+       $self->pidl("const char *ncacn_np_secondary_endpoint = NULL;");
+       $self->pidlnoindent("#endif");
+       $self->pidl("");
+       $self->pidl("for (i=0;i<ndr_table_$name.endpoints->count;i++) {");
+       $self->indent();
+       $self->pidl("const char *name = ndr_table_$name.endpoints->names[i];");
+       $self->pidl("");
+       $self->pidl("/* TODO Register the interface for local dispatching */");
+       $self->pidl("");
+       $self->pidl("ret = dcerpc_parse_binding(dce_ctx, name, &binding);");
+       $self->pidl("if (NT_STATUS_IS_ERR(ret)) {");
+       $self->indent();
+       $self->pidl("DBG_ERR(\"Failed to parse binding string \'%s\'\\n\", name);");
+       $self->pidl("return ret;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("ret = $name\__check_register_in_endpoint(\"$name\", binding);");
+       $self->pidl("if (NT_STATUS_IS_ERR(ret)) {");
+       $self->indent();
+       $self->pidl("talloc_free(binding);");
+       $self->pidl("continue;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("talloc_free(binding);");
+       $self->pidl("");
+       $self->pidl("ret = dcesrv_interface_register(dce_ctx, name, ncacn_np_secondary_endpoint, &dcesrv_$name\_interface, NULL);");
+       $self->pidl("if (!NT_STATUS_IS_OK(ret)) {");
+       $self->indent();
+       $self->pidl("DBG_ERR(\"Failed to register endpoint \'%s\'\\n\",name);");
+       $self->pidl("return ret;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static NTSTATUS $name\__op_shutdown_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("return NT_STATUS_OK;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static bool $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("if (dcesrv_$name\_interface.syntax_id.if_version == if_version && GUID_equal(\&dcesrv\_$name\_interface.syntax_id.uuid, uuid)) {");
+       $self->indent();
+       $self->pidl("memcpy(iface,&dcesrv\_$name\_interface, sizeof(*iface));");
+       $self->pidl("return true;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return false;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static bool $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("if (strcmp(dcesrv_$name\_interface.name, name)==0) {");
+       $self->indent();
+       $self->pidl("memcpy(iface, &dcesrv_$name\_interface, sizeof(*iface));");
+       $self->pidl("return true;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+       $self->pidl("return false;");
+       $self->deindent();
+       $self->pidl("}");
+       $self->pidl("");
+
+       $self->pidl("static const struct dcesrv_endpoint_server $name\_ep_server = {");
+       $self->indent();
+       $self->pidl("/* fill in our name */");
+       $self->pidl(".name = \"$name\",");
+       $self->pidl("");
+       $self->pidl("/* Initialization flag */");
+       $self->pidl(".initialized = false,");
+       $self->pidl("");
+       $self->pidl("/* fill in all the operations */");
+       $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_INIT_SERVER");
+       $self->pidl(".init_server = DCESRV_INTERFACE_$uname\_INIT_SERVER,");
+       $self->pidlnoindent("#else");
+       $self->pidl(".init_server = $name\__op_init_server,");
+       $self->pidlnoindent("#endif");
+       $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_SHUTDOWN_SERVER");
+       $self->pidl(".shutdown_server = DCESRV_INTERFACE_$uname\_SHUTDOWN_SERVER,");
+       $self->pidlnoindent("#else");
+       $self->pidl(".shutdown_server = $name\__op_shutdown_server,");
+       $self->pidlnoindent("#endif");
+       $self->pidl(".interface_by_uuid = $name\__op_interface_by_uuid,");
+       $self->pidl(".interface_by_name = $name\__op_interface_by_name");
+       $self->deindent();
+       $self->pidl("};");
+       $self->pidl("");
+
+       $self->pidl("const struct dcesrv_endpoint_server *$name\_get_ep_server(void)");
+       $self->pidl("{");
+       $self->indent();
+       $self->pidl("return &$name\_ep_server;");
+       $self->deindent();
+       $self->pidl("}");
+}
+
+#####################################################################
+# dcerpc server boilerplate from a parsed IDL structure
+sub parse_interface($)
+{
+       my ($self, $interface) = @_;
+       my $count = 0;
+       my $uif = uc($interface->{NAME});
+
+
+       $self->pidl_hdr("#ifndef __NDR_${uif}_SCOMPAT_H__");
+       $self->pidl_hdr("#define __NDR_${uif}_SCOMPAT_H__");
+       $self->pidl_hdr("");
+       $self->pidl_hdr("struct pipes_struct;");
+       $self->pidl_hdr("struct dcesrv_endpoint_server;");
+       $self->pidl_hdr("struct dcesrv_call_state;");
+       $self->pidl_hdr("");
+       $self->pidl_hdr("const struct dcesrv_endpoint_server *$interface->{NAME}\_get_ep_server(void);");
+       $self->pidl_hdr("");
+
+       if (!defined $interface->{PROPERTIES}->{uuid}) {
+               $self->pidl_hdr("#endif /* __NDR_${uif}_SCOMPAT_H__ */");
+               return;
+       }
+
+       if (!defined $interface->{PROPERTIES}->{version}) {
+               $interface->{PROPERTIES}->{version} = "0.0";
+       }
+
+       foreach my $fn (@{$interface->{FUNCTIONS}}) {
+               if (defined($fn->{OPNUM})) { $count++; }
+       }
+
+       if ($count == 0) {
+               $self->pidl_hdr("#endif /* __NDR_${uif}_SCOMPAT_H__ */");
+               return;
+       }
+
+       $self->pidl("/* $interface->{NAME} - dcerpc server boilerplate generated by pidl */");
+       $self->boilerplate_iface($interface);
+       $self->boilerplate_ep_server($interface);
+
+       $self->pidl_hdr("#endif /* __NDR_${uif}_SCOMPAT_H__ */");
+}
+
+sub Parse($$)
+{
+       my ($self, $ndr, $h_scompat, $header) = @_;
+
+       $self->pidl("/* s3 compat server functions auto-generated by pidl */");
+       $self->pidl("#include \"$header\"");
+       $self->pidl("#include \"$h_scompat\"");
+
+       $self->pidl("#include <librpc/rpc/dcesrv_core.h>");
+       $self->pidl("#include <rpc_server/rpc_config.h>");
+       $self->pidl("#include <util/debug.h>");
+       $self->pidl("");
+
+       foreach my $x (@{$ndr}) {
+               $self->parse_interface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
+       }
+
+       return ($self->{res}, $self->{res_hdr});
+}
+
+1;
index 3f48ef8e0f4a4025e258059f9f564a910b7dcf81..762824e6851e43797063e51781305167f5a67063 100755 (executable)
--- a/pidl/pidl
+++ b/pidl/pidl
@@ -475,6 +475,7 @@ my($opt_template) = 0;
 my($opt_client);
 my($opt_typelib);
 my($opt_server);
+my($opt_server_compat);
 my($opt_ndr_parser);
 my($opt_tdr_parser);
 my($opt_ws_parser);
@@ -560,6 +561,7 @@ my $result = GetOptions (
                'samba3-template' => \$opt_samba3_template,
                'header:s' => \$opt_header,
                'server:s' => \$opt_server,
+               'server-compat:s' => \$opt_server_compat,
                'typelib:s' => \$opt_typelib,
                'tdr-parser:s' => \$opt_tdr_parser,
                'template' => \$opt_template,
@@ -670,6 +672,7 @@ sub process_file($)
        if (defined($opt_ws_parser) or
                defined($opt_client) or
                defined($opt_server) or
+               defined($opt_server_compat) or
                defined($opt_header) or
                defined($opt_ndr_parser) or
                defined($opt_python) or
@@ -798,6 +801,19 @@ sub process_file($)
                FileSave($header, $h_code);
        }
 
+       if (defined($opt_server_compat)) {
+               require Parse::Pidl::Samba4::NDR::ServerCompat;
+
+               my $c_scompat = ($opt_server_compat or "$outputdir/ndr_$basename\_scompat.c");
+               my $h_scompat = $c_scompat;
+               $h_scompat =~ s/\.c$/.h/;
+
+               my $generator = new Parse::Pidl::Samba4::NDR::ServerCompat();
+               my ($source, $header) = $generator->Parse($ndr, $h_scompat, $h_filename);
+
+               FileSave($c_scompat, $source);
+               FileSave($h_scompat, $header);
+       }
 }
 
 if (scalar(@ARGV) == 0) {