From 79c5d73a71c35f5b16232072a7b52033cb9364cb Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij <jelmer@samba.org> Date: Fri, 12 Nov 2004 00:48:24 +0000 Subject: r3689: Large number of COM updates: - Work on server side and local COM support (should work, just no example classes yet) - Use vtables so that local and remote calls can be used transparently - Generate 'proxies and stubs' rather then heavily modified code in client.pm and server.pm. proxies (client side code) are generated in proxy.pm, stubs (server side dispatchers) are generated in stubs.pm - Support registering classes and interfaces - DCOM interfaces no longer have to be in the same IDL file as their base interface, which will allow us to split up dcom.idl (This used to be commit 7466947a23985f9bb15209b67880f7b94dc515c8) --- source4/lib/dcom/common/dcom.h | 36 +++++- source4/lib/dcom/common/local.c | 82 ------------- source4/lib/dcom/common/main.c | 243 ++++++++++++++++++++++++++------------- source4/lib/dcom/common/tables.c | 114 ++++++++++++++++++ 4 files changed, 307 insertions(+), 168 deletions(-) delete mode 100644 source4/lib/dcom/common/local.c create mode 100644 source4/lib/dcom/common/tables.c (limited to 'source4/lib/dcom/common') diff --git a/source4/lib/dcom/common/dcom.h b/source4/lib/dcom/common/dcom.h index 320b5a4a9f..9c09cc17d9 100644 --- a/source4/lib/dcom/common/dcom.h +++ b/source4/lib/dcom/common/dcom.h @@ -29,11 +29,18 @@ struct IUnknown_QueryInterface; struct dcom_context { - struct dcom_oxid_mapping { - struct dcom_oxid_mapping *prev, *next; + struct dcom_object_exporter { + struct dcom_object_exporter *prev, *next; + struct STRINGARRAY resolver_address; struct DUALSTRINGARRAY bindings; HYPER_T oxid; struct dcerpc_pipe *pipe; + struct dcom_object + { + struct dcom_object *prev, *next; + HYPER_T oid; + void *private_data; + } *objects; } *oxids; const char *domain; const char *user; @@ -41,11 +48,32 @@ struct dcom_context uint32_t dcerpc_flags; }; +/* Specific implementation of one or more interfaces */ +struct dcom_class +{ + const char *prog_id; + struct GUID clsid; + void (*get_class_object) (struct GUID *iid, void **vtable); +}; + struct dcom_interface +{ + struct GUID iid; + int num_methods; + struct GUID base_iid; + const void *proxy_vtable; +}; + +struct dcom_interface_p { struct dcom_context *ctx; - struct dcerpc_pipe *pipe; - struct OBJREF *objref; + const struct dcom_interface *interface; + const void *vtable; /* Points to one of the available implementations */ + struct GUID ipid; + struct dcom_object *object; + int objref_flags; + int orpc_flags; + struct dcom_object_exporter *ox; uint32_t private_references; }; diff --git a/source4/lib/dcom/common/local.c b/source4/lib/dcom/common/local.c deleted file mode 100644 index a68f5f4593..0000000000 --- a/source4/lib/dcom/common/local.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Implementation of some of the local COM calls. Interfaces: - - IUnknown - - Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org> - - 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 "dlinklist.h" -#include "librpc/gen_ndr/ndr_dcom.h" - -NTSTATUS dcerpc_IUnknown_AddRef(struct dcom_interface *p, TALLOC_CTX *mem_ctx, struct IUnknown_AddRef *rr) -{ - struct RemAddRef r; - struct REMINTERFACEREF ref; - - /* This is rather inefficient, but we'll patch it up later */ - r.in.cInterfaceRefs = 1; - r.in.InterfaceRefs = &ref; - - return dcerpc_RemAddRef(p, mem_ctx, &r); -} - -NTSTATUS dcerpc_IUnknown_Release(struct dcom_interface *p, TALLOC_CTX *mem_ctx, struct IUnknown_Release *rr) -{ - struct RemRelease r; - struct REMINTERFACEREF ref; - - return NT_STATUS_NOT_SUPPORTED; - - p->private_references--; - - /* Only do the remote version of this call when all local references have - * been released */ - if (p->private_references == 0) { - NTSTATUS status; - r.in.cInterfaceRefs = 1; - r.in.InterfaceRefs = &ref; - - status = dcerpc_RemRelease(p, mem_ctx, &r); - - if (NT_STATUS_IS_OK(status)) { - talloc_destroy(p); - } - - return status; - } - - return NT_STATUS_OK; -} - -NTSTATUS dcerpc_IUnknown_QueryInterface(struct dcom_interface *o, TALLOC_CTX *mem_ctx, struct IUnknown_QueryInterface *rr) -{ - /* FIXME: Ask local server for interface pointer. Local server can then - * call RemQueryInterface if necessary */ - return NT_STATUS_NOT_SUPPORTED; -} - -NTSTATUS dcerpc_IClassFactory_CreateInstance(struct dcom_interface *o, TALLOC_CTX *mem_ctx, struct IClassFactory_CreateInstance *rr) -{ - return NT_STATUS_NOT_SUPPORTED; -} - -NTSTATUS dcerpc_IClassFactory_LockServer(struct dcom_interface *o, TALLOC_CTX *mem_ctx, struct IClassFactory_LockServer *rr) -{ - return NT_STATUS_NOT_SUPPORTED; -} diff --git a/source4/lib/dcom/common/main.c b/source4/lib/dcom/common/main.c index 996432181a..60f866aede 100644 --- a/source4/lib/dcom/common/main.c +++ b/source4/lib/dcom/common/main.c @@ -111,10 +111,31 @@ WERROR dcom_init(struct dcom_context **ctx, const char *domain, const char *user (*ctx)->domain = talloc_strdup(*ctx, domain); (*ctx)->user = talloc_strdup(*ctx, user); (*ctx)->password = talloc_strdup(*ctx, pass); + (*ctx)->dcerpc_flags = 0; return WERR_OK; } +static struct dcom_object_exporter *oxid_mapping_by_oxid (struct dcom_context *ctx, HYPER_T oxid) +{ + struct dcom_object_exporter *m; + + for (m = ctx->oxids;m;m = m->next) { + if (m->oxid == oxid) { + break; + } + } + + /* Add oxid mapping if we couldn't find one */ + if (!m) { + m = talloc_zero_p(ctx, struct dcom_object_exporter); + m->oxid = oxid; + DLIST_ADD(ctx->oxids, m); + } + + return m; +} + WERROR dcom_ping(struct dcom_context *ctx) { /* FIXME: If OID's waiting in queue, do a ComplexPing call */ @@ -122,11 +143,12 @@ WERROR dcom_ping(struct dcom_context *ctx) return WERR_OK; } -WERROR dcom_create_object(struct dcom_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct dcom_interface **ip, WERROR *results) +WERROR dcom_create_object(struct dcom_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct dcom_interface_p ***ip, WERROR *results) { - struct dcom_oxid_mapping *m; struct RemoteActivation r; + struct DUALSTRINGARRAY dualstring; int i; + struct dcom_object_exporter *m; struct dcerpc_pipe *p; NTSTATUS status; uint16 protseq[] = DCOM_NEGOTIATED_PROTOCOLS; @@ -148,8 +170,7 @@ WERROR dcom_create_object(struct dcom_context *ctx, struct GUID *clsid, const ch r.in.Interfaces = num_ifaces; r.in.pIIDs = iid; r.out.ifaces = talloc_array_p(ctx, struct pMInterfacePointer, num_ifaces); - m = talloc_zero_p(ctx, struct dcom_oxid_mapping); - r.out.pdsaOxidBindings = &m->bindings; + r.out.pdsaOxidBindings = &dualstring; status = dcerpc_RemoteActivation(p, ctx, &r); if(NT_STATUS_IS_ERR(status)) { @@ -165,28 +186,33 @@ WERROR dcom_create_object(struct dcom_context *ctx, struct GUID *clsid, const ch return r.out.hr; } - *ip = talloc_array_p(ctx, struct dcom_interface, num_ifaces); + *ip = talloc_array_p(ctx, struct dcom_interface_p *, num_ifaces); for (i = 0; i < num_ifaces; i++) { results[i] = r.out.results[i]; - (*ip)[i].private_references = 1; - (*ip)[i].objref = &r.out.ifaces[i].p->obj; - (*ip)[i].pipe = NULL; - (*ip)[i].ctx = ctx; + (*ip)[i] = NULL; + if (W_ERROR_IS_OK(results[i])) { + status = dcom_ifacep_from_OBJREF(ctx, &(*ip)[i], &r.out.ifaces[i].p->obj); + if (NT_STATUS_IS_OK(status)) { + (*ip)[i]->private_references = 1; + } else { + results[i] = ntstatus_to_werror(status); + } + } } /* Add the OXID data for the returned oxid */ - m->oxid = r.out.pOxid; + m = oxid_mapping_by_oxid(ctx, r.out.pOxid); m->bindings = *r.out.pdsaOxidBindings; - DLIST_ADD(ctx->oxids, m); return WERR_OK; } -WERROR dcom_get_class_object(struct dcom_context *ctx, struct GUID *clsid, const char *server, struct GUID *iid, struct dcom_interface *ip) +WERROR dcom_get_class_object(struct dcom_context *ctx, struct GUID *clsid, const char *server, struct GUID *iid, struct dcom_interface_p **ip) { - struct dcom_oxid_mapping *m; + struct dcom_object_exporter *m; struct RemoteActivation r; struct dcerpc_pipe *p; + struct DUALSTRINGARRAY dualstring; NTSTATUS status; struct pMInterfacePointer pm; uint16 protseq[] = DCOM_NEGOTIATED_PROTOCOLS; @@ -209,8 +235,7 @@ WERROR dcom_get_class_object(struct dcom_context *ctx, struct GUID *clsid, const r.in.pIIDs = iid; r.in.Mode = MODE_GET_CLASS_OBJECT; r.out.ifaces = ± - m = talloc_zero_p(ctx, struct dcom_oxid_mapping); - r.out.pdsaOxidBindings = &m->bindings; + r.out.pdsaOxidBindings = &dualstring; status = dcerpc_RemoteActivation(p, ctx, &r); if(NT_STATUS_IS_ERR(status)) { @@ -223,74 +248,160 @@ WERROR dcom_get_class_object(struct dcom_context *ctx, struct GUID *clsid, const if(!W_ERROR_IS_OK(r.out.results[0])) { return r.out.results[0]; } /* Set up the interface data */ - ip->private_references = 1; - ip->pipe = NULL; - ip->objref = &pm.p->obj; - ip->ctx = ctx; + dcom_ifacep_from_OBJREF(ctx, ip, &pm.p->obj); + (*ip)->private_references = 1; /* Add the OXID data for the returned oxid */ - m->oxid = r.out.pOxid; + m = oxid_mapping_by_oxid(ctx, r.out.pOxid); m->bindings = *r.out.pdsaOxidBindings; - DLIST_ADD(ctx->oxids, m); return WERR_OK; } -static struct dcom_oxid_mapping *oxid_mapping_by_oxid (struct dcom_context *ctx, HYPER_T oxid) +NTSTATUS dcom_get_pipe (struct dcom_interface_p *iface, struct dcerpc_pipe **p) { - struct dcom_oxid_mapping *m; + struct dcerpc_binding binding; + struct GUID iid; + HYPER_T oxid; + NTSTATUS status; + int i; + + *p = NULL; - for (m = ctx->oxids;m;m = m->next) { - if (m->oxid == oxid) { - return m; + oxid = iface->ox->oxid; + iid = iface->interface->iid; + + if (iface->ox->pipe) { + if (!uuid_equal(&iface->ox->pipe->syntax.uuid, &iid)) { + iface->ox->pipe->syntax.uuid = iid; + status = dcerpc_alter(iface->ox->pipe, iface->ctx); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + } + *p = iface->ox->pipe; + return NT_STATUS_OK; + } + + i = 0; + do { + status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding, iface->ox->bindings.stringbindings[i]); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(1, ("Error parsing string binding")); + } else { + binding.flags = iface->ctx->dcerpc_flags; + status = dcerpc_pipe_connect_b(&iface->ox->pipe, &binding, GUID_string(iface->ctx, &iid) , 0.0, iface->ctx->domain, iface->ctx->user, iface->ctx->password); } + + i++; + } while (NT_STATUS_IS_ERR(status) && iface->ox->bindings.stringbindings[i]); + + if (NT_STATUS_IS_ERR(status)) { + DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status))); + return status; } - return NULL; + DEBUG(2, ("Successfully connected to OXID %llx\n", oxid)); + + *p = iface->ox->pipe; + return NT_STATUS_OK; } -NTSTATUS dcom_get_pipe (struct dcom_interface *iface, struct dcerpc_pipe **p) +struct dcom_object *dcom_object_by_oid(struct dcom_object_exporter *ox, HYPER_T oid) { - struct dcom_oxid_mapping *m; - struct dcerpc_binding binding; - struct GUID iid; - HYPER_T oxid; - NTSTATUS status; - int i; + struct dcom_object *o; - *p = NULL; + for (o = ox->objects; o; o = o->next) { + if (o->oid == oid) { + break; + } + } + + if (o == NULL) { + o = talloc_zero_p(ox, struct dcom_object); + o->oid = oid; + DLIST_ADD(ox->objects, o); + } - SMB_ASSERT(iface->objref->signature == OBJREF_SIGNATURE); + return o; +} + +NTSTATUS dcom_ifacep_from_OBJREF(struct dcom_context *ctx, struct dcom_interface_p **_p, struct OBJREF *o) +{ + struct dcom_interface_p *p = talloc_p(ctx, struct dcom_interface_p); - if (iface->objref->flags & OBJREF_HANDLER) { - DEBUG(0, ("dcom_get_pipe: OBJREF_HANDLER not supported!\n")); + p->ctx = ctx; + p->interface = dcom_interface_by_iid(&o->iid); + if (!p->interface) { + DEBUG(0, ("Unable to find interface with IID %s\n", GUID_string(ctx, &o->iid))); return NT_STATUS_NOT_SUPPORTED; } - if (iface->objref->flags & OBJREF_CUSTOM) { - DEBUG(0, ("dcom_get_pipe: OBJREF_CUSTOM not supported!\n")); + p->private_references = 0; + p->objref_flags = o->flags; + + switch(p->objref_flags) { + case OBJREF_NULL: + p->object = NULL; + p->ox = NULL; + p->vtable = dcom_proxy_vtable_by_iid(&p->interface->iid); + ZERO_STRUCT(p->ipid); + *_p = p; + return NT_STATUS_OK; + + case OBJREF_STANDARD: + p->ox = oxid_mapping_by_oxid(ctx, o->u_objref.u_standard.std.oxid); + p->ipid = o->u_objref.u_standard.std.ipid; + p->object = dcom_object_by_oid(p->ox, o->u_objref.u_standard.std.oid); + p->ox->resolver_address = o->u_objref.u_standard.saResAddr; + p->vtable = dcom_proxy_vtable_by_iid(&p->interface->iid); + *_p = p; + return NT_STATUS_OK; + + case OBJREF_HANDLER: + p->ox = oxid_mapping_by_oxid(ctx, o->u_objref.u_handler.std.oxid ); + p->ipid = o->u_objref.u_handler.std.ipid; + p->object = dcom_object_by_oid(p->ox, o->u_objref.u_standard.std.oid); + p->ox->resolver_address = o->u_objref.u_handler.saResAddr; + p->vtable = dcom_vtable_by_clsid(&o->u_objref.u_handler.clsid); + /* FIXME: Do the custom unmarshaling call */ + + *_p = p; + return NT_STATUS_OK; + + case OBJREF_CUSTOM: + { + const struct dcom_interface *imarshal = dcom_vtable_by_clsid(&o->u_objref.u_custom.clsid); + p->vtable = NULL; + + /* FIXME: Do the actual custom unmarshaling call */ + p->ox = NULL; + p->object = NULL; + ZERO_STRUCT(p->ipid); + *_p = p; return NT_STATUS_NOT_SUPPORTED; + } } - oxid = iface->objref->u_objref.u_standard.std.oxid; - iid = iface->objref->iid; - - m = oxid_mapping_by_oxid(iface->ctx, oxid); + return NT_STATUS_NOT_SUPPORTED; + +#if 0 + struct dcom_oxid_mapping *m; /* Add OXID mapping if none present yet */ if (!m) { struct dcerpc_pipe *po; struct ResolveOxid r; uint16 protseq[] = DCOM_NEGOTIATED_PROTOCOLS; - DEBUG(3, ("No binding data present yet, resolving OXID %llu\n", oxid)); + DEBUG(3, ("No binding data present yet, resolving OXID %llu\n", p->ox->oxid)); - m = talloc_zero_p(iface->ctx, struct dcom_oxid_mapping); + m = talloc_zero_p(p->ctx, struct dcom_oxid_mapping); m->oxid = oxid; i = 0; do { - status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding, iface->objref->u_objref.u_standard.saResAddr.stringbindings[i]); + status = dcerpc_binding_from_STRINGBINDING(p->ctx, &binding, p->client.objref->u_objref.u_standard.saResAddr.stringbindings[i]); if (NT_STATUS_IS_OK(status)) { binding.flags = iface->ctx->dcerpc_flags; @@ -300,7 +411,7 @@ NTSTATUS dcom_get_pipe (struct dcom_interface *iface, struct dcerpc_pipe **p) } i++; - } while (!NT_STATUS_IS_OK(status) && iface->objref->u_objref.u_standard.saResAddr.stringbindings[i]); + } while (!NT_STATUS_IS_OK(status) && iface->client.objref->u_objref.u_standard.saResAddr.stringbindings[i]); if (NT_STATUS_IS_ERR(status)) { DEBUG(1, ("Error while connecting to OXID Resolver : %s\n", nt_errstr(status))); @@ -322,39 +433,7 @@ NTSTATUS dcom_get_pipe (struct dcom_interface *iface, struct dcerpc_pipe **p) DLIST_ADD(iface->ctx->oxids, m); } +#endif - if (m->pipe) { - if (!uuid_equal(&m->pipe->syntax.uuid, &iid)) { - m->pipe->syntax.uuid = iid; - status = dcerpc_alter(m->pipe, iface->ctx); - if (NT_STATUS_IS_ERR(status)) { - return status; - } - } - *p = m->pipe; - return NT_STATUS_OK; - } - - i = 0; - do { - status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding, m->bindings.stringbindings[i]); - if (NT_STATUS_IS_ERR(status)) { - DEBUG(1, ("Error parsing string binding")); - } else { - binding.flags = iface->ctx->dcerpc_flags; - status = dcerpc_pipe_connect_b(&m->pipe, &binding, GUID_string(iface->ctx, &iid) , 0.0, iface->ctx->domain, iface->ctx->user, iface->ctx->password); - } - - i++; - } while (NT_STATUS_IS_ERR(status) && m->bindings.stringbindings[i]); - - if (NT_STATUS_IS_ERR(status)) { - DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status))); - return status; - } - - DEBUG(2, ("Successfully connected to OXID %llx\n", oxid)); - - *p = m->pipe; - return NT_STATUS_OK; + return NT_STATUS_NOT_SUPPORTED; } diff --git a/source4/lib/dcom/common/tables.c b/source4/lib/dcom/common/tables.c new file mode 100644 index 0000000000..d6b7cfa78f --- /dev/null +++ b/source4/lib/dcom/common/tables.c @@ -0,0 +1,114 @@ +/* + Unix SMB/CIFS implementation. + DCOM interface and class tables + Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org> + + 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 "dlinklist.h" + +static struct class_list { + struct class_list *prev, *next; + struct dcom_class class; +} *classes = NULL; + +static struct interface_list { + struct interface_list *prev, *next; + struct dcom_interface interface; +} *interfaces = NULL; + +const struct dcom_interface *dcom_interface_by_iid(const struct GUID *iid) +{ + struct interface_list *l = interfaces; + + while(l) { + + if (uuid_equal(iid, &l->interface.iid)) + return &l->interface; + + l = l->next; + } + + return NULL; +} + +const void *dcom_vtable_by_clsid(const struct GUID *clsid) +{ + struct class_list *c = classes; + + while(c) { + + if (uuid_equal(clsid, &c->class.clsid)) + return &c->class; + + c = c->next; + } + + return NULL; +} + +const void *dcom_proxy_vtable_by_iid(const struct GUID *iid) +{ + const struct dcom_interface *iface = dcom_interface_by_iid(iid); + + if (!iface) { + return NULL; + } + + return iface->proxy_vtable; +} + +static NTSTATUS dcom_register_interface(const void *_iface) +{ + const struct dcom_interface *iface = _iface; + struct interface_list *l = talloc_zero_p(interfaces, struct interface_list); + + l->interface = *iface; + + DLIST_ADD(interfaces, l); + + return NT_STATUS_OK; +} + +static NTSTATUS dcom_register_class(const void *_class) +{ + const struct dcom_class *class = _class; + struct class_list *l = talloc_zero_p(classes, struct class_list); + + l->class = *class; + + DLIST_ADD(classes, l); + + return NT_STATUS_OK; +} + +NTSTATUS libdcom_init(void) +{ + NTSTATUS status; + + status = register_subsystem("dcom_interface", dcom_register_interface); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + register_subsystem("dcom_class", dcom_register_class); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + return status; +} -- cgit