diff options
Diffstat (limited to 'pidl/lib/Parse/Pidl/Samba4/COM')
-rw-r--r-- | pidl/lib/Parse/Pidl/Samba4/COM/Header.pm | 161 | ||||
-rw-r--r-- | pidl/lib/Parse/Pidl/Samba4/COM/Proxy.pm | 226 | ||||
-rw-r--r-- | pidl/lib/Parse/Pidl/Samba4/COM/Stub.pm | 322 |
3 files changed, 709 insertions, 0 deletions
diff --git a/pidl/lib/Parse/Pidl/Samba4/COM/Header.pm b/pidl/lib/Parse/Pidl/Samba4/COM/Header.pm new file mode 100644 index 0000000..159f417 --- /dev/null +++ b/pidl/lib/Parse/Pidl/Samba4/COM/Header.pm @@ -0,0 +1,161 @@ +# COM Header generation +# (C) 2005 Jelmer Vernooij <jelmer@samba.org> + +package Parse::Pidl::Samba4::COM::Header; + +use Parse::Pidl::Typelist qw(mapTypeName); +use Parse::Pidl::Util qw(has_property is_constant); + +use vars qw($VERSION); +$VERSION = '0.01'; + +use strict; +use warnings; + +sub GetArgumentProtoList($) +{ + my $f = shift; + my $res = ""; + + foreach my $a (@{$f->{ELEMENTS}}) { + + $res .= ", " . mapTypeName($a->{TYPE}) . " "; + + 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 GetArgumentList($) +{ + my $f = shift; + my $res = ""; + + foreach (@{$f->{ELEMENTS}}) { $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}) { + $res .= "\t" . mapTypeName($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n" if ($d->{TYPE} eq "FUNCTION"); + } + $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#ifndef _$if->{NAME}_\n"; + $res .= "#define _$if->{NAME}_\n"; + + $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"); + + $res .= "#define $if->{NAME}_$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . ") "; + + $res .= "((interface)->vtable->$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . "))"; + + $res .="\n"; + } + + $res .= "#endif\n"; + + return $res; +} + +sub ParseCoClass($) +{ + my ($c) = @_; + 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 = ""; + my $has_obj = 0; + + $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"; + $has_obj = 1; + } + } + + foreach (@{$idl}) + { + if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) { + $res.=ParseInterface($_); + $has_obj = 1; + } + + if ($_->{TYPE} eq "COCLASS") { + $res.=ParseCoClass($_); + $has_obj = 1; + } + } + + return $res if ($has_obj); + return undef; +} + +1; diff --git a/pidl/lib/Parse/Pidl/Samba4/COM/Proxy.pm b/pidl/lib/Parse/Pidl/Samba4/COM/Proxy.pm new file mode 100644 index 0000000..1630cf2 --- /dev/null +++ b/pidl/lib/Parse/Pidl/Samba4/COM/Proxy.pm @@ -0,0 +1,226 @@ +################################################### +# 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::Typelist qw(mapTypeName); +use Parse::Pidl::Util qw(has_property); + +use vars qw($VERSION); +$VERSION = '0.01'; + +use strict; +use warnings; + +my($res); + +sub ParseVTable($$) +{ + my ($interface, $name) = @_; + + # 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 .= "static NTSTATUS dcom_proxy_$interface->{NAME}_init(TALLOC_CTX *ctx) +{ + struct $interface->{NAME}_vtable *proxy_vtable = talloc(ctx, struct $interface->{NAME}_vtable); +"; + + if (defined($interface->{BASE})) { + $res.= " + struct GUID base_iid; + const void *base_vtable; + + base_iid = ndr_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.= " + proxy_vtable->iid = ndr_table_$interface->{NAME}.syntax_id.uuid; + + return dcom_register_proxy(ctx, (struct IUnknown_vtable *)proxy_vtable); +}\n\n"; +} + +##################################################################### +# parse a function +sub ParseFunction($$) +{ + my ($interface, $fn) = @_; + my $name = $fn->{NAME}; + my $uname = uc $name; + + my $tn = mapTypeName($fn->{RETURN_TYPE}); + + $res.=" +static $tn dcom_proxy_$interface->{NAME}_$name(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn) . ") +{ + struct dcerpc_pipe *p; + NTSTATUS status = dcom_get_pipe(d, &p); + struct $name r; + struct rpc_request *req; + + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + NDR_ZERO_STRUCT(r.in.ORPCthis); + r.in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION; + r.in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION; +"; + + # Put arguments into r + foreach my $a (@{$fn->{ELEMENTS}}) { + next unless (has_property($a, "in")); + if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) { + $res .="\tNDR_CHECK(dcom_OBJREF_from_IUnknown(mem_ctx, &r.in.$a->{NAME}.obj, $a->{NAME}));\n"; + } else { + $res .= "\tr.in.$a->{NAME} = $a->{NAME};\n"; + } + } + + $res .=" + if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) { + NDR_PRINT_IN_DEBUG($name, &r); + } + + status = dcerpc_ndr_request(p, &d->ipid, &ndr_table_$interface->{NAME}, NDR_$uname, mem_ctx, &r); + + if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) { + NDR_PRINT_OUT_DEBUG($name, r); + } + +"; + + # Put r info back into arguments + foreach my $a (@{$fn->{ELEMENTS}}) { + next unless (has_property($a, "out")); + + if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) { + $res .="\tNDR_CHECK(dcom_IUnknown_from_OBJREF(d->ctx, &$a->{NAME}, r.out.$a->{NAME}.obj));\n"; + } else { + $res .= "\t*$a->{NAME} = r.out.$a->{NAME};\n"; + } + + } + + if ($fn->{RETURN_TYPE} eq "NTSTATUS") { + $res .= "\tif (NT_STATUS_IS_OK(status)) status = r.out.result;\n"; + } + + $res .= + " + return r.out.result; +}\n\n"; +} + +##################################################################### +# 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 = ""; + my $has_obj = 0; + + $res .= "#include \"includes.h\"\n" . + "#include \"lib/com/dcom/dcom.h\"\n" . + "#include \"$comh_filename\"\n" . + "#include \"librpc/rpc/dcerpc.h\"\n"; + + foreach (@{$pidl}) { + next if ($_->{TYPE} ne "INTERFACE"); + next if has_property($_, "local"); + next unless has_property($_, "object"); + + $res .= ParseInterface($_); + + $has_obj = 1; + } + + return $res if ($has_obj); + return undef; +} + +1; diff --git a/pidl/lib/Parse/Pidl/Samba4/COM/Stub.pm b/pidl/lib/Parse/Pidl/Samba4/COM/Stub.pm new file mode 100644 index 0000000..7198038 --- /dev/null +++ b/pidl/lib/Parse/Pidl/Samba4/COM/Stub.pm @@ -0,0 +1,322 @@ +################################################### +# 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 warnings; + +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, uint32_t if_version) +{ +#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)) { + 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) { + 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) { + 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; |