r5674: - Re-enable DCOM support.
[samba.git] / source4 / lib / com / dcom / main.c
1 /*
2    Unix SMB/CIFS implementation.
3    Main DCOM functionality
4    Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org>
5
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.
10
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.
15
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.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "dlinklist.h"
24 #include "librpc/gen_ndr/ndr_epmapper.h"
25 #include "librpc/gen_ndr/ndr_remact.h"
26 #include "librpc/gen_ndr/ndr_oxidresolver.h"
27 #include "librpc/gen_ndr/ndr_dcom.h"
28 #include "librpc/gen_ndr/com_dcom.h"
29
30 #define DCOM_NEGOTIATED_PROTOCOLS { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NCALRPC }
31
32 static NTSTATUS dcerpc_binding_from_STRINGBINDING(TALLOC_CTX *mem_ctx, struct dcerpc_binding *b, struct STRINGBINDING *bd)
33 {
34         char *host, *endpoint;
35
36         ZERO_STRUCTP(b);
37         
38         b->transport = dcerpc_transport_by_endpoint_protocol(bd->wTowerId);
39
40         if (b->transport == -1) {
41                 DEBUG(1, ("Can't find transport match endpoint protocol %d\n", bd->wTowerId));
42                 return NT_STATUS_NOT_SUPPORTED;
43         }
44
45         host = talloc_strdup(mem_ctx, bd->NetworkAddr);
46         endpoint = strchr(host, '[');
47
48         if (endpoint) {
49                 *endpoint = '\0';
50                 endpoint++;
51
52                 endpoint[strlen(endpoint)-1] = '\0';
53         }
54
55         b->host = host;
56         b->endpoint = endpoint;
57
58         return NT_STATUS_OK;
59 }
60
61 static NTSTATUS dcom_connect_host(struct com_context *ctx, struct dcerpc_pipe **p, const char *server)
62 {
63         struct dcerpc_binding bd;
64         enum dcerpc_transport_t available_transports[] = { NCACN_IP_TCP, NCACN_NP };
65         int i;
66         NTSTATUS status;
67         TALLOC_CTX *mem_ctx = talloc_init("dcom_connect");
68
69         if (server == NULL) { 
70                 bd.transport = NCALRPC; 
71                 return dcerpc_pipe_connect_b(p, &bd, 
72                                         DCERPC_IREMOTEACTIVATION_UUID, 
73                                         DCERPC_IREMOTEACTIVATION_VERSION, 
74                                         ctx->dcom.domain, ctx->dcom.user, ctx->dcom.password);
75         }
76
77         /* Allow server name to contain a binding string */
78         if (NT_STATUS_IS_OK(dcerpc_parse_binding(mem_ctx, server, &bd))) {
79                 status = dcerpc_pipe_connect_b(p, &bd, 
80                                         DCERPC_IREMOTEACTIVATION_UUID, 
81                                         DCERPC_IREMOTEACTIVATION_VERSION, 
82                                         ctx->dcom.domain, ctx->dcom.user, ctx->dcom.password);
83
84                 talloc_free(mem_ctx);
85                 return status;
86         }
87         talloc_free(mem_ctx);
88
89         ZERO_STRUCT(bd);
90         bd.host = server;
91         
92         for (i = 0; i < ARRAY_SIZE(available_transports); i++)
93         {
94                 bd.transport = available_transports[i];
95                 
96                 status = dcerpc_pipe_connect_b(p, &bd, 
97                                                 DCERPC_IREMOTEACTIVATION_UUID, 
98                                                 DCERPC_IREMOTEACTIVATION_VERSION, 
99                                                 ctx->dcom.domain, ctx->dcom.user, ctx->dcom.password);
100
101                 if (NT_STATUS_IS_OK(status)) {
102                         return status;
103                 }
104         }
105         
106         return status;
107 }
108
109 struct dcom_object_exporter *object_exporter_by_oxid(struct com_context *ctx, uint64_t oxid)
110 {
111         return NULL; /* FIXME */
112 }
113
114 struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, struct IUnknown *ip)
115 {
116         return NULL; /* FIXME */
117 }
118
119 WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, WERROR *results)
120 {
121         uint16_t protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
122         struct dcerpc_pipe *p;
123         struct dcom_object_exporter *m;
124         NTSTATUS status;
125         struct RemoteActivation r;
126         struct DUALSTRINGARRAY dualstring;
127         int i;
128
129         status = dcom_connect_host(ctx, &p, server);
130         if (NT_STATUS_IS_ERR(status)) {
131                 DEBUG(1, ("Unable to connect to %s - %s\n", server, nt_errstr(status)));
132                 return ntstatus_to_werror(status);
133         }
134
135         ZERO_STRUCT(r.in);
136         r.in.this.version.MajorVersion = COM_MAJOR_VERSION;
137         r.in.this.version.MinorVersion = COM_MINOR_VERSION;
138         r.in.this.cid = GUID_random();
139         r.in.Clsid = *clsid;
140         r.in.ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
141         r.in.num_protseqs = ARRAY_SIZE(protseq);
142         r.in.protseq = protseq;
143         r.in.Interfaces = num_ifaces;
144         r.in.pIIDs = iid;
145         r.out.ifaces = talloc_array(ctx, struct MInterfacePointer, num_ifaces);
146         r.out.pdsaOxidBindings = &dualstring;
147         
148         status = dcerpc_RemoteActivation(p, ctx, &r);
149         if(NT_STATUS_IS_ERR(status)) {
150                 DEBUG(1, ("Error while running RemoteActivation %s\n", nt_errstr(status)));
151                 return ntstatus_to_werror(status);
152         }
153
154         if(!W_ERROR_IS_OK(r.out.result)) {
155                 return r.out.result; 
156         }
157         
158         if(!W_ERROR_IS_OK(r.out.hr)) { 
159                 return r.out.hr; 
160         }
161
162         *ip = talloc_array(ctx, struct IUnknown *, num_ifaces);
163         for (i = 0; i < num_ifaces; i++) {
164                 results[i] = r.out.results[i];
165                 (*ip)[i] = NULL;
166                 if (W_ERROR_IS_OK(results[i])) {
167                         status = dcom_IUnknown_from_OBJREF(ctx, &(*ip)[i], &r.out.ifaces[i].obj);
168                         if (!NT_STATUS_IS_OK(status)) {
169                                 results[i] = ntstatus_to_werror(status);
170                         }
171                 }
172         }
173
174         /* Add the OXID data for the returned oxid */
175         m = object_exporter_by_oxid(ctx, r.out.pOxid);
176         m->bindings = *r.out.pdsaOxidBindings;
177         
178         return WERR_OK;
179 }
180
181 WERROR dcom_get_class_object(struct com_context *ctx, struct GUID *clsid, const char *server, struct GUID *iid, struct IUnknown **ip)
182 {
183         struct dcom_object_exporter *m;
184         struct RemoteActivation r;
185         struct dcerpc_pipe *p;
186         struct DUALSTRINGARRAY dualstring;
187         NTSTATUS status;
188         struct MInterfacePointer pm;
189         uint16_t protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
190
191         if (!server) {
192                 return com_get_class_object(ctx, clsid, iid, ip);
193         }
194
195         status = dcom_connect_host(ctx, &p, server);
196         if (NT_STATUS_IS_ERR(status)) {
197                 DEBUG(1, ("Unable to connect to %s - %s\n", server, nt_errstr(status)));
198                 return ntstatus_to_werror(status);
199         }
200
201         ZERO_STRUCT(r.in);
202         r.in.this.version.MajorVersion = COM_MAJOR_VERSION;
203         r.in.this.version.MinorVersion = COM_MINOR_VERSION;
204         r.in.this.cid = GUID_random();
205         r.in.Clsid = *clsid;
206         r.in.ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
207         r.in.num_protseqs = ARRAY_SIZE(protseq);
208         r.in.protseq = protseq;
209         r.in.Interfaces = 1;
210         r.in.pIIDs = iid;
211         r.in.Mode = MODE_GET_CLASS_OBJECT;
212         r.out.ifaces = &pm;
213         r.out.pdsaOxidBindings = &dualstring;
214
215         status = dcerpc_RemoteActivation(p, ctx, &r);
216         if(NT_STATUS_IS_ERR(status)) {
217                 DEBUG(1, ("Error while running RemoteActivation - %s\n", nt_errstr(status)));
218                 return ntstatus_to_werror(status);
219         }
220
221         if(!W_ERROR_IS_OK(r.out.result)) { return r.out.result; }
222         if(!W_ERROR_IS_OK(r.out.hr)) { return r.out.hr; }
223         if(!W_ERROR_IS_OK(r.out.results[0])) { return r.out.results[0]; }
224         
225         /* Set up the interface data */
226         dcom_IUnknown_from_OBJREF(ctx, ip, &pm.obj);
227         
228         /* Add the OXID data for the returned oxid */
229         m = object_exporter_by_oxid(ctx, r.out.pOxid);
230         m->bindings = *r.out.pdsaOxidBindings;
231
232         return WERR_OK;
233 }
234
235 NTSTATUS dcom_get_pipe (struct IUnknown *iface, struct dcerpc_pipe **pp)
236 {
237         struct dcerpc_binding binding;
238         struct GUID iid;
239         uint64_t oxid;
240         NTSTATUS status;
241         int i;
242         struct dcerpc_pipe *p;
243         TALLOC_CTX *tmp_ctx;
244         const char *uuid;
245         struct dcom_object_exporter *ox;
246
247         ox = object_exporter_by_ip(iface->ctx, iface);
248
249         tmp_ctx = talloc_new(NULL);
250
251         p = ox->pipe;
252         
253         iid = iface->vtable->iid;
254
255         uuid = GUID_string(tmp_ctx, &iid);
256         
257         if (p) {
258                 if (!GUID_equal(&p->syntax.uuid, &iid)) {
259                         struct dcerpc_pipe *p2;
260                         ox->pipe->syntax.uuid = iid;
261                         status = dcerpc_secondary_context(p, &p2, uuid, 0);
262                         if (NT_STATUS_IS_OK(status)) {
263                                 p = p2;
264                         }
265                 } else {
266                         p = talloc_reference(NULL, p);
267                 }
268                 *pp = p;
269                 talloc_free(tmp_ctx);
270                 return status;
271         }
272
273         i = 0;
274         do {
275                 status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding, 
276                                                            ox->bindings.stringbindings[i]);
277                 if (!NT_STATUS_IS_OK(status)) {
278                         DEBUG(1, ("Error parsing string binding"));
279                 } else {
280                         status = dcerpc_pipe_connect_b(&p, &binding, 
281                                                        uuid, 0.0, 
282                                                        iface->ctx->dcom.domain, iface->ctx->dcom.user, 
283                                                        iface->ctx->dcom.password);
284                 }
285
286                 i++;
287         } while (NT_STATUS_IS_ERR(status) && ox->bindings.stringbindings[i]);
288
289         if (NT_STATUS_IS_ERR(status)) {
290                 DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status)));
291                 talloc_free(tmp_ctx);
292                 return status;
293         }
294
295         DEBUG(2, ("Successfully connected to OXID %llx\n", oxid));
296         
297         *pp = p;
298         talloc_free(tmp_ctx);
299
300         return NT_STATUS_OK;
301 }
302
303 NTSTATUS dcom_OBJREF_from_IUnknown(struct OBJREF *o, struct IUnknown *p)
304 {
305         /* FIXME: Cache generated objref objects? */
306         ZERO_STRUCTP(o);
307         
308         o->signature = OBJREF_SIGNATURE;
309         
310         if (!p) {
311                 o->flags = OBJREF_NULL;
312         } else {
313                 o->iid = p->vtable->iid;
314                 /* 
315                 OBJREF_STANDARD
316                 OBJREF_CUSTOM
317                 OBJREF_HANDLER
318                 */
319         }
320
321         return NT_STATUS_NOT_IMPLEMENTED;       
322 }
323
324 NTSTATUS dcom_IUnknown_from_OBJREF(struct com_context *ctx, struct IUnknown **_p, struct OBJREF *o)
325 {
326         struct IUnknown *p;
327         struct dcom_object_exporter *ox;
328
329         switch(o->flags) {
330         case OBJREF_NULL: 
331                 *_p = NULL;
332                 return NT_STATUS_OK;
333                 
334         case OBJREF_STANDARD:
335                 p = talloc(ctx, struct IUnknown);
336                 p->ctx = ctx;   
337                 p->vtable = dcom_proxy_vtable_by_iid(&o->iid);
338                 if (!p->vtable) {
339                         DEBUG(0, ("Unable to find proxy class for interface with IID %s\n", GUID_string(ctx, &o->iid)));
340                         return NT_STATUS_NOT_SUPPORTED;
341                 }
342
343                 ox = object_exporter_by_oxid(ctx, o->u_objref.u_standard.std.oxid);
344                 /* FIXME: Add object to list of objects to ping */
345                 *_p = p;
346                 return NT_STATUS_OK;
347                 
348         case OBJREF_HANDLER:
349                 p = talloc(ctx, struct IUnknown);
350                 p->ctx = ctx;   
351                 ox = object_exporter_by_oxid(ctx, o->u_objref.u_handler.std.oxid );
352                 /* FIXME: Add object to list of objects to ping */
353 /*FIXME         p->vtable = dcom_vtable_by_clsid(&o->u_objref.u_handler.clsid);*/
354                 /* FIXME: Do the custom unmarshaling call */
355         
356                 *_p = p;
357                 return NT_STATUS_OK;
358                 
359         case OBJREF_CUSTOM:
360                 p = talloc(ctx, struct IUnknown);
361                 p->ctx = ctx;   
362                 p->vtable = NULL;
363                 /* FIXME: Do the actual custom unmarshaling call */
364                 *_p = p;
365                 return NT_STATUS_NOT_SUPPORTED;
366         }
367
368         return NT_STATUS_NOT_SUPPORTED;
369 }
370
371 uint64_t dcom_get_current_oxid(void)
372 {
373         return getpid();
374 }