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