2 Unix SMB/CIFS implementation.
3 Main DCOM functionality
4 Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "dlinklist.h"
23 #include "librpc/gen_ndr/ndr_epmapper.h"
24 #include "librpc/gen_ndr/ndr_remact.h"
25 #include "librpc/gen_ndr/ndr_oxidresolver.h"
26 #include "librpc/gen_ndr/ndr_dcom.h"
28 #define DCOM_NEGOTIATED_PROTOCOLS { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NCALRPC }
30 static NTSTATUS dcerpc_binding_from_STRINGBINDING(TALLOC_CTX *mem_ctx, struct dcerpc_binding *b, struct STRINGBINDING *bd)
32 char *host, *endpoint;
36 b->transport = dcerpc_transport_by_endpoint_protocol(bd->wTowerId);
38 if (b->transport == -1) {
39 DEBUG(1, ("Can't find transport match endpoint protocol %d\n", bd->wTowerId));
40 return NT_STATUS_NOT_SUPPORTED;
43 host = talloc_strdup(mem_ctx, bd->NetworkAddr);
44 endpoint = strchr(host, '[');
50 endpoint[strlen(endpoint)-1] = '\0';
54 b->endpoint = endpoint;
59 static NTSTATUS dcom_connect_host(struct dcom_context *ctx, struct dcerpc_pipe **p, const char *server)
61 struct dcerpc_binding bd;
62 enum dcerpc_transport_t available_transports[] = { NCACN_IP_TCP, NCACN_NP };
65 TALLOC_CTX *mem_ctx = talloc_init("dcom_connect");
67 /* Allow server name to contain a binding string */
68 if (NT_STATUS_IS_OK(dcerpc_parse_binding(mem_ctx, server, &bd))) {
69 status = dcerpc_pipe_connect_b(p, &bd,
70 DCERPC_IREMOTEACTIVATION_UUID,
71 DCERPC_IREMOTEACTIVATION_VERSION,
72 ctx->domain, ctx->user, ctx->password);
74 talloc_destroy(mem_ctx);
77 talloc_destroy(mem_ctx);
83 bd.transport = NCALRPC;
84 return dcerpc_pipe_connect_b(p, &bd,
85 DCERPC_IREMOTEACTIVATION_UUID,
86 DCERPC_IREMOTEACTIVATION_VERSION,
87 ctx->domain, ctx->user, ctx->password);
90 for (i = 0; i < ARRAY_SIZE(available_transports); i++)
92 bd.transport = available_transports[i];
94 status = dcerpc_pipe_connect_b(p, &bd,
95 DCERPC_IREMOTEACTIVATION_UUID,
96 DCERPC_IREMOTEACTIVATION_VERSION,
97 ctx->domain, ctx->user, ctx->password);
99 if (NT_STATUS_IS_OK(status)) {
107 WERROR dcom_init(struct dcom_context **ctx, const char *domain, const char *user, const char *pass)
109 *ctx = talloc_p(NULL, struct dcom_context);
110 (*ctx)->oxids = NULL;
111 (*ctx)->domain = talloc_strdup(*ctx, domain);
112 (*ctx)->user = talloc_strdup(*ctx, user);
113 (*ctx)->password = talloc_strdup(*ctx, pass);
114 (*ctx)->dcerpc_flags = 0;
119 static struct dcom_object_exporter *oxid_mapping_by_oxid (struct dcom_context *ctx, HYPER_T oxid)
121 struct dcom_object_exporter *m;
123 for (m = ctx->oxids;m;m = m->next) {
124 if (m->oxid == oxid) {
129 /* Add oxid mapping if we couldn't find one */
131 m = talloc_zero_p(ctx, struct dcom_object_exporter);
133 DLIST_ADD(ctx->oxids, m);
139 WERROR dcom_ping(struct dcom_context *ctx)
141 /* FIXME: If OID's waiting in queue, do a ComplexPing call */
142 /* FIXME: otherwise, do a SimplePing call */
146 static WERROR dcom_create_object_remote(struct dcom_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct dcom_interface_p ***ip, WERROR *results)
148 uint16 protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
149 struct dcerpc_pipe *p;
150 struct dcom_object_exporter *m;
152 struct RemoteActivation r;
153 struct DUALSTRINGARRAY dualstring;
156 status = dcom_connect_host(ctx, &p, server);
157 if (NT_STATUS_IS_ERR(status)) {
158 DEBUG(1, ("Unable to connect to %s - %s\n", server, nt_errstr(status)));
159 return ntstatus_to_werror(status);
163 r.in.this.version.MajorVersion = COM_MAJOR_VERSION;
164 r.in.this.version.MinorVersion = COM_MINOR_VERSION;
165 r.in.this.cid = GUID_random();
167 r.in.ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
168 r.in.num_protseqs = ARRAY_SIZE(protseq);
169 r.in.protseq = protseq;
170 r.in.Interfaces = num_ifaces;
172 r.out.ifaces = talloc_array_p(ctx, struct pMInterfacePointer, num_ifaces);
173 r.out.pdsaOxidBindings = &dualstring;
175 status = dcerpc_RemoteActivation(p, ctx, &r);
176 if(NT_STATUS_IS_ERR(status)) {
177 DEBUG(1, ("Error while running RemoteActivation %s\n", nt_errstr(status)));
178 return ntstatus_to_werror(status);
181 if(!W_ERROR_IS_OK(r.out.result)) {
185 if(!W_ERROR_IS_OK(r.out.hr)) {
189 *ip = talloc_array_p(ctx, struct dcom_interface_p *, num_ifaces);
190 for (i = 0; i < num_ifaces; i++) {
191 results[i] = r.out.results[i];
193 if (W_ERROR_IS_OK(results[i])) {
194 status = dcom_ifacep_from_OBJREF(ctx, &(*ip)[i], &r.out.ifaces[i].p->obj);
195 if (NT_STATUS_IS_OK(status)) {
196 (*ip)[i]->private_references = 1;
198 results[i] = ntstatus_to_werror(status);
203 /* Add the OXID data for the returned oxid */
204 m = oxid_mapping_by_oxid(ctx, r.out.pOxid);
205 m->bindings = *r.out.pdsaOxidBindings;
210 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)
212 struct dcom_interface_p *factory, *iunk;
213 struct QueryInterface qr;
215 struct CreateInstance cr;
220 if (server != NULL) {
221 return dcom_create_object_remote(ctx, clsid, server, num_ifaces, iid, ip, results);
224 /* Obtain class object */
225 error = dcom_get_class_object(ctx, clsid, server, iid, &factory);
226 if (!W_ERROR_IS_OK(error)) {
227 DEBUG(3, ("Unable to obtain class object for %s\n", GUID_string(NULL, clsid)));
231 dcom_OBJREF_from_ifacep(ctx, &cr.in.pUnknown->obj, factory);
233 GUID_from_string(DCERPC_ICLASSFACTORY_UUID, cr.in.iid);
235 /* Run IClassFactory::CreateInstance() */
236 status = dcom_IClassFactory_CreateInstance(factory, ctx, &cr);
237 if (NT_STATUS_IS_ERR(status)) {
238 DEBUG(3, ("Error while calling IClassFactory::CreateInstance : %s\n", nt_errstr(status)));
239 return ntstatus_to_werror(status);
242 /* Release class object */
243 status = dcom_IUnknown_Release(factory, ctx, &rr);
244 if (NT_STATUS_IS_ERR(status)) {
245 DEBUG(3, ("Error freeing class factory: %s\n", nt_errstr(status)));
246 return ntstatus_to_werror(status);
249 /* Do one or more QueryInterface calls */
250 for (i = 0; i < num_ifaces; i++) {
252 status = dcom_IUnknown_QueryInterface(iunk, ctx, &qr);
253 if (NT_STATUS_IS_ERR(status)) {
254 DEBUG(4, ("Error obtaining interface %s : %s\n", GUID_string(NULL, &iid[i]), nt_errstr(status)));
255 return ntstatus_to_werror(status);
257 results[i] = qr.out.result;
263 WERROR dcom_get_class_object_remote(struct dcom_context *ctx, struct GUID *clsid, const char *server, struct GUID *iid, struct dcom_interface_p **ip)
265 struct dcom_object_exporter *m;
266 struct RemoteActivation r;
267 struct dcerpc_pipe *p;
268 struct DUALSTRINGARRAY dualstring;
270 struct pMInterfacePointer pm;
271 uint16 protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
273 status = dcom_connect_host(ctx, &p, server);
274 if (NT_STATUS_IS_ERR(status)) {
275 DEBUG(1, ("Unable to connect to %s - %s\n", server, nt_errstr(status)));
276 return ntstatus_to_werror(status);
280 r.in.this.version.MajorVersion = COM_MAJOR_VERSION;
281 r.in.this.version.MinorVersion = COM_MINOR_VERSION;
282 r.in.this.cid = GUID_random();
284 r.in.ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
285 r.in.num_protseqs = ARRAY_SIZE(protseq);
286 r.in.protseq = protseq;
289 r.in.Mode = MODE_GET_CLASS_OBJECT;
291 r.out.pdsaOxidBindings = &dualstring;
293 status = dcerpc_RemoteActivation(p, ctx, &r);
294 if(NT_STATUS_IS_ERR(status)) {
295 DEBUG(1, ("Error while running RemoteActivation - %s\n", nt_errstr(status)));
296 return ntstatus_to_werror(status);
299 if(!W_ERROR_IS_OK(r.out.result)) { return r.out.result; }
300 if(!W_ERROR_IS_OK(r.out.hr)) { return r.out.hr; }
301 if(!W_ERROR_IS_OK(r.out.results[0])) { return r.out.results[0]; }
303 /* Set up the interface data */
304 dcom_ifacep_from_OBJREF(ctx, ip, &pm.p->obj);
305 (*ip)->private_references = 1;
307 /* Add the OXID data for the returned oxid */
308 m = oxid_mapping_by_oxid(ctx, r.out.pOxid);
309 m->bindings = *r.out.pdsaOxidBindings;
314 WERROR dcom_get_class_object(struct dcom_context *ctx, struct GUID *clsid, const char *server, struct GUID *iid, struct dcom_interface_p **ip)
316 const struct dcom_class *c;
317 struct QueryInterface qi;
320 if (server != NULL) {
321 return dcom_get_class_object_remote(ctx, clsid, server, iid, ip);
324 c = dcom_class_by_clsid(clsid);
326 /* FIXME: Better error code.. */
327 return WERR_DEST_NOT_FOUND;
332 status = dcom_IUnknown_QueryInterface(c->class_object, ctx, &qi );
333 if (NT_STATUS_IS_ERR(status)) {
334 return ntstatus_to_werror(status);
337 if (!W_ERROR_IS_OK(qi.out.result)) { return qi.out.result; }
339 dcom_ifacep_from_OBJREF(ctx, ip, &qi.out.data->obj);
344 NTSTATUS dcom_get_pipe (struct dcom_interface_p *iface, struct dcerpc_pipe **p)
346 struct dcerpc_binding binding;
354 oxid = iface->ox->oxid;
355 iid = iface->interface->iid;
357 if (iface->ox->pipe) {
358 if (!GUID_equal(&iface->ox->pipe->syntax.uuid, &iid)) {
359 iface->ox->pipe->syntax.uuid = iid;
360 status = dcerpc_alter(iface->ox->pipe, iface->ctx);
361 if (NT_STATUS_IS_ERR(status)) {
365 *p = iface->ox->pipe;
371 status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding, iface->ox->bindings.stringbindings[i]);
372 if (NT_STATUS_IS_ERR(status)) {
373 DEBUG(1, ("Error parsing string binding"));
375 binding.flags = iface->ctx->dcerpc_flags;
376 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);
380 } while (NT_STATUS_IS_ERR(status) && iface->ox->bindings.stringbindings[i]);
382 if (NT_STATUS_IS_ERR(status)) {
383 DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status)));
387 DEBUG(2, ("Successfully connected to OXID %llx\n", oxid));
389 *p = iface->ox->pipe;
393 struct dcom_object *dcom_object_by_oid(struct dcom_object_exporter *ox, HYPER_T oid)
395 struct dcom_object *o;
397 for (o = ox->objects; o; o = o->next) {
404 o = talloc_zero_p(ox, struct dcom_object);
406 DLIST_ADD(ox->objects, o);
413 NTSTATUS dcom_OBJREF_from_ifacep(struct dcom_context *ctx, struct OBJREF *o, struct dcom_interface_p *_p)
415 return NT_STATUS_NOT_IMPLEMENTED;
418 NTSTATUS dcom_ifacep_from_OBJREF(struct dcom_context *ctx, struct dcom_interface_p **_p, struct OBJREF *o)
420 struct dcom_interface_p *p = talloc_p(ctx, struct dcom_interface_p);
423 p->interface = dcom_interface_by_iid(&o->iid);
425 DEBUG(0, ("Unable to find interface with IID %s\n", GUID_string(ctx, &o->iid)));
426 return NT_STATUS_NOT_SUPPORTED;
429 p->private_references = 0;
430 p->objref_flags = o->flags;
432 switch(p->objref_flags) {
436 p->vtable = dcom_proxy_vtable_by_iid(&p->interface->iid);
437 ZERO_STRUCT(p->ipid);
441 case OBJREF_STANDARD:
442 p->ox = oxid_mapping_by_oxid(ctx, o->u_objref.u_standard.std.oxid);
443 p->ipid = o->u_objref.u_standard.std.ipid;
444 p->object = dcom_object_by_oid(p->ox, o->u_objref.u_standard.std.oid);
445 p->ox->resolver_address = o->u_objref.u_standard.saResAddr;
446 p->vtable = dcom_proxy_vtable_by_iid(&p->interface->iid);
451 p->ox = oxid_mapping_by_oxid(ctx, o->u_objref.u_handler.std.oxid );
452 p->ipid = o->u_objref.u_handler.std.ipid;
453 p->object = dcom_object_by_oid(p->ox, o->u_objref.u_standard.std.oid);
454 p->ox->resolver_address = o->u_objref.u_handler.saResAddr;
455 /*FIXME p->vtable = dcom_vtable_by_clsid(&o->u_objref.u_handler.clsid);*/
456 /* FIXME: Do the custom unmarshaling call */
465 /* FIXME: Do the actual custom unmarshaling call */
468 ZERO_STRUCT(p->ipid);
470 return NT_STATUS_NOT_SUPPORTED;
474 return NT_STATUS_NOT_SUPPORTED;
478 struct dcom_oxid_mapping *m;
479 /* Add OXID mapping if none present yet */
481 struct dcerpc_pipe *po;
482 struct ResolveOxid r;
483 uint16 protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
485 DEBUG(3, ("No binding data present yet, resolving OXID %llu\n", p->ox->oxid));
487 m = talloc_zero_p(p->ctx, struct dcom_oxid_mapping);
492 status = dcerpc_binding_from_STRINGBINDING(p->ctx, &binding, p->client.objref->u_objref.u_standard.saResAddr.stringbindings[i]);
494 if (NT_STATUS_IS_OK(status)) {
495 binding.flags = iface->ctx->dcerpc_flags;
496 status = dcerpc_pipe_connect_b(&po, &binding, DCERPC_IOXIDRESOLVER_UUID, DCERPC_IOXIDRESOLVER_VERSION, iface->ctx->domain, iface->ctx->user, iface->ctx->password);
498 DEBUG(1, ("Error parsing string binding - %s", nt_errstr(status)));
502 } while (!NT_STATUS_IS_OK(status) && iface->client.objref->u_objref.u_standard.saResAddr.stringbindings[i]);
504 if (NT_STATUS_IS_ERR(status)) {
505 DEBUG(1, ("Error while connecting to OXID Resolver : %s\n", nt_errstr(status)));
510 r.in.cRequestedProtseqs = ARRAY_SIZE(protseq);
511 r.in.arRequestedProtseqs = protseq;
512 r.out.ppdsaOxidBindings = &m->bindings;
514 status = dcerpc_ResolveOxid(po, iface->ctx, &r);
515 if (NT_STATUS_IS_ERR(status)) {
516 DEBUG(1, ("Error while resolving OXID: %s\n", nt_errstr(status)));
520 dcerpc_pipe_close(po);
522 DLIST_ADD(iface->ctx->oxids, m);
526 return NT_STATUS_NOT_SUPPORTED;
529 HYPER_T dcom_get_current_oxid(void)
534 struct dcom_interface_p *dcom_new_local_ifacep(struct dcom_context *ctx, const struct dcom_interface *iface, void *vtable, struct dcom_object *object)
536 struct dcom_interface_p *ip = talloc_p(ctx, struct dcom_interface_p);
539 ip->interface = iface;
541 ip->ipid = GUID_random();
543 ip->objref_flags = 0;
546 ip->private_references = 1;