1 /*
2    Unix SMB/CIFS implementation.
3    Main DCOM functionality
4    Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org>
5    Copyright (C) 2006 Andrzej Hajda <andrzej.hajda@wp.pl>
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/epmapper.h"
25 #include "librpc/gen_ndr/ndr_remact_c.h"
26 #include "librpc/gen_ndr/com_dcom.h"
27 #include "librpc/gen_ndr/dcom.h"
28 #include "librpc/rpc/dcerpc.h"
29 #include "lib/com/dcom/dcom.h"
30 #include "librpc/ndr/ndr_table.h"
31 #include "../lib/util/dlinklist.h"
32 #include "auth/credentials/credentials.h"
33 #include "libcli/composite/composite.h"
34 
35 #define DCOM_NEGOTIATED_PROTOCOLS { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NCALRPC }
36 
dcerpc_binding_from_STRINGBINDING(TALLOC_CTX * mem_ctx,struct dcerpc_binding ** b_out,struct STRINGBINDING * bd)37 static NTSTATUS dcerpc_binding_from_STRINGBINDING(TALLOC_CTX *mem_ctx, struct dcerpc_binding **b_out, struct STRINGBINDING *bd)
38 {
39 	char *tstr;
40 	char *bstr;
41 	enum dcerpc_transport_t transport;
42 	struct dcerpc_binding *b;
43 
44 	transport = dcerpc_transport_by_endpoint_protocol(bd->wTowerId);
45 	if (transport == NCA_UNKNOWN) {
46 		DEBUG(1, ("Can't find transport match endpoint protocol %d\n", bd->wTowerId));
47 		return NT_STATUS_NOT_SUPPORTED;
48 	}
49 
50 	tstr = derpc_transport_string_by_transport(transport);
51 	bstr = talloc_asprintf(mem_ctx, "%s:%s", tstr, bd->NetworkAddr);
52 	if (bstr == NULL) {
53 		return NT_STATUS_NO_MEMORY;
54 	}
55 
56 	status = dcerpc_parse_binding(mem_ctx, bstr, &b);
57 	TALLOC_FREE(bstr);
58 	if (!NT_STATUS_IS_OK(status)) {
59 		return status;
60 	}
61 
62 	*b_out = b;
63 	return NT_STATUS_OK;
64 }
65 
dcom_get_server_credentials(struct com_context * ctx,const char * server)66 struct cli_credentials *dcom_get_server_credentials(struct com_context *ctx, const char *server)
67 {
68 	struct dcom_server_credentials *c;
69 	struct cli_credentials *d;
70 
71 	d = NULL;
72 	for (c = ctx->dcom->credentials; c; c = c->next) {
73 		if (c->server == NULL) {
74 			d = c->credentials;
75 			continue;
76 		}
77 		if (server && !strcmp(c->server, server)) return c->credentials;
78 	}
79 	return d;
80 }
81 
82 /**
83  * Register credentials for a specific server.
84  *
85  * @param ctx COM context
86  * @param server Name of server, can be NULL
87  * @param credentials Credentials object
88  */
dcom_add_server_credentials(struct com_context * ctx,const char * server,struct cli_credentials * credentials)89 void dcom_add_server_credentials(struct com_context *ctx, const char *server,
90 								 struct cli_credentials *credentials)
91 {
92 	struct dcom_server_credentials *c;
93 
94 	/* FIXME: Don't use talloc_find_parent_bytype */
95 	for (c = ctx->dcom->credentials; c; c = c->next) {
96 		if ((server == NULL && c->server == NULL) ||
97 			(server != NULL && c->server != NULL &&
98 			 !strcmp(c->server, server))) {
99 			if (c->credentials && c->credentials != credentials) {
100 				talloc_unlink(c, c->credentials);
101 				c->credentials = credentials;
102 				if (talloc_find_parent_bytype(c->credentials, struct dcom_server_credentials))
103 					(void)talloc_reference(c, c->credentials);
104 				else
105 					talloc_steal(c, c->credentials);
106 			}
107 
108 			return;
109 		}
110 	}
111 
112 	c = talloc(ctx->event_ctx, struct dcom_server_credentials);
113 	c->server = talloc_strdup(c, server);
114 	c->credentials = credentials;
115 	if (talloc_find_parent_bytype(c->credentials, struct dcom_server_credentials))
116 		(void)talloc_reference(c, c->credentials);
117 	else
118 		talloc_steal(c, c->credentials);
119 
120 	DLIST_ADD(ctx->dcom->credentials, c);
121 }
122 
dcom_update_credentials_for_aliases(struct com_context * ctx,const char * server,struct DUALSTRINGARRAY * pds)123 void dcom_update_credentials_for_aliases(struct com_context *ctx,
124 										 const char *server,
125 										 struct DUALSTRINGARRAY *pds)
126 {
127 	struct cli_credentials *cc;
128 	struct dcerpc_binding *b;
129 	uint32_t i;
130 	NTSTATUS status;
131 
132 	cc = dcom_get_server_credentials(ctx, server);
133         for (i = 0; pds->stringbindings[i]; ++i) {
134                 if (pds->stringbindings[i]->wTowerId != EPM_PROTOCOL_TCP)
135 					continue;
136                 status = dcerpc_binding_from_STRINGBINDING(ctx, &b, pds->stringbindings[i]);
137 		if (!NT_STATUS_IS_OK(status))
138 			continue;
139 		dcom_add_server_credentials(ctx, b->host, cc);
140 		talloc_free(b);
141 	}
142 }
143 
dcom_client_init(struct com_context * ctx,struct cli_credentials * credentials)144 struct dcom_client_context *dcom_client_init(struct com_context *ctx, struct cli_credentials *credentials)
145 {
146 	ctx->dcom = talloc_zero(ctx, struct dcom_client_context);
147 	if (!credentials) {
148                 credentials = cli_credentials_init(ctx);
149                 cli_credentials_set_conf(credentials, ctx->lp_ctx);
150                 cli_credentials_parse_string(credentials, "%", CRED_SPECIFIED);
151 	}
152 	dcom_add_server_credentials(ctx, NULL, credentials);
153 	return ctx->dcom;
154 }
155 
dcom_connect_host(struct com_context * ctx,struct dcerpc_pipe ** p,const char * server)156 static NTSTATUS dcom_connect_host(struct com_context *ctx,
157 								  struct dcerpc_pipe **p, const char *server)
158 {
159 	struct dcerpc_binding *bd;
160 	const char * available_transports[] = { "ncacn_ip_tcp", "ncacn_np" };
161 	int i;
162 	NTSTATUS status;
163 	TALLOC_CTX *loc_ctx;
164 
165 	if (server == NULL) {
166 		return dcerpc_pipe_connect(ctx->event_ctx, p, "ncalrpc",
167 								   &ndr_table_IRemoteActivation,
168 								   dcom_get_server_credentials(ctx, NULL), ctx->event_ctx, ctx->lp_ctx);
169 	}
170 	loc_ctx = talloc_new(ctx);
171 
172 	/* Allow server name to contain a binding string */
173 	if (strchr(server, ':') &&
174 		NT_STATUS_IS_OK(dcerpc_parse_binding(loc_ctx, server, &bd))) {
175 		if (DEBUGLVL(11))
176 			bd->flags |= DCERPC_DEBUG_PRINT_BOTH;
177 		status = dcerpc_pipe_connect_b(ctx->event_ctx, p, bd,
178 									   &ndr_table_IRemoteActivation,
179 								   dcom_get_server_credentials(ctx, bd->host), ctx->event_ctx, ctx->lp_ctx);
180 		goto end;
181 	}
182 
183 	for (i = 0; i < ARRAY_SIZE(available_transports); i++)
184 	{
185 		char *binding = talloc_asprintf(loc_ctx, "%s:%s", available_transports[i], server);
186 		if (!binding) {
187 			status = NT_STATUS_NO_MEMORY;
188 			goto end;
189 		}
190 		status = dcerpc_pipe_connect(ctx->event_ctx, p, binding,
191 									 &ndr_table_IRemoteActivation,
192 									 dcom_get_server_credentials(ctx, server),
193 									 ctx->event_ctx, ctx->lp_ctx);
194 
195 		if (NT_STATUS_IS_OK(status)) {
196 			if (DEBUGLVL(11))
197 				(*p)->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
198 			goto end;
199 		} else {
200 			DEBUG(1,(__location__": dcom_connect_host : %s\n", get_friendly_nt_error_msg(status)));
201 		}
202 	}
203 
204 end:
205 	talloc_free(loc_ctx);
206 	return status;
207 }
208 
object_exporter_by_oxid(struct com_context * ctx,uint64_t oxid)209 struct dcom_object_exporter *object_exporter_by_oxid(struct com_context *ctx,
210 													 uint64_t oxid)
211 {
212 	struct dcom_object_exporter *ox;
213 	for (ox = ctx->dcom->object_exporters; ox; ox = ox->next) {
214 		if (ox->oxid == oxid) {
215 			return ox;
216 		}
217 	}
218 
219 	return NULL;
220 }
221 
object_exporter_update_oxid(struct com_context * ctx,uint64_t oxid,struct DUALSTRINGARRAY * bindings)222 struct dcom_object_exporter *object_exporter_update_oxid(struct com_context *ctx, uint64_t oxid, struct DUALSTRINGARRAY *bindings)
223 {
224 	struct dcom_object_exporter *ox;
225 	ox = object_exporter_by_oxid(ctx, oxid);
226 	if (!ox) {
227 		ox = talloc_zero(ctx, struct dcom_object_exporter);
228 		DLIST_ADD(ctx->dcom->object_exporters, ox);
229 		ox->oxid = oxid;
230 	} else {
231 		talloc_free(ox->bindings);
232 	}
233 	ox->bindings = bindings;
234 	talloc_steal(ox, bindings);
235 	return ox;
236 }
237 
object_exporter_by_ip(struct com_context * ctx,struct IUnknown * ip)238 struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, struct IUnknown *ip)
239 {
240 	return object_exporter_by_oxid(ctx, ip->obj.u_objref.u_standard.std.oxid);
241 }
242 
dcom_create_object(struct com_context * ctx,struct GUID * clsid,const char * server,int num_ifaces,struct GUID * iid,struct IUnknown *** ip,HRESULT * results)243 WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, HRESULT *results)
244 {
245 	uint16_t protseq[] = DCOM_NEGOTIATED_PROTOCOLS;
246 	struct dcerpc_pipe *p;
247 	struct dcom_object_exporter *m;
248 	NTSTATUS status;
249 	struct RemoteActivation r;
250 	struct DUALSTRINGARRAY *pds;
251 	int i;
252 	HRESULT hr;
253 	uint64_t oxid;
254 	struct GUID ipidRemUnknown;
255 	struct IUnknown *ru_template;
256 	struct ORPCTHAT that;
257 	uint32_t AuthnHint;
258 	struct COMVERSION ServerVersion;
259 	struct MInterfacePointer **ifaces;
260 	TALLOC_CTX *loc_ctx;
261 
262 	status = dcom_connect_host(ctx, &p, server);
263 	if (NT_STATUS_IS_ERR(status)) {
264 		DEBUG(1, ("Unable to connect to %s - %s\n", server, get_friendly_nt_error_msg(status)));
265 		return ntstatus_to_werror(status);
266 	}
267 	loc_ctx = talloc_new(ctx);
268 
269 	ifaces = talloc_array(loc_ctx, struct MInterfacePointer *, num_ifaces);
270 
271 	ZERO_STRUCT(r.in);
272 	r.in.this.version.MajorVersion = COM_MAJOR_VERSION;
273 	r.in.this.version.MinorVersion = COM_MINOR_VERSION;
274 	r.in.this.cid = GUID_random();
275 	r.in.Clsid = *clsid;
276 	r.in.ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
277 	r.in.num_protseqs = ARRAY_SIZE(protseq);
278 	r.in.protseq = protseq;
279 	r.in.Interfaces = num_ifaces;
280 	r.in.pIIDs = iid;
281 	r.out.that = &that;
282 	r.out.pOxid = &oxid;
283 	r.out.pdsaOxidBindings = &pds;
284 	r.out.ipidRemUnknown = &ipidRemUnknown;
285 	r.out.AuthnHint = &AuthnHint;
286 	r.out.ServerVersion = &ServerVersion;
287 	r.out.hr = &hr;
288 	r.out.ifaces = ifaces;
289 	r.out.results = results;
290 
291 	status = dcerpc_RemoteActivation(p, loc_ctx, &r);
292 	talloc_free(p);
293 
294 	if(NT_STATUS_IS_ERR(status)) {
295 		DEBUG(1, ("Error while running RemoteActivation %s\n", nt_errstr(status)));
296 		hr = ntstatus_to_werror(status);
297 		goto end;
298 	}
299 
300 	if(!W_ERROR_IS_OK(r.out.result)) {
301 		hr = r.out.result;
302 		goto end;
303 	}
304 
305 	if(!HRES_IS_OK(hr)) {
306 		goto end;
307 	}
308 
309 	m = object_exporter_update_oxid(ctx, oxid, pds);
310 
311 	ru_template = NULL;
312 	*ip = talloc_array(ctx, struct IUnknown *, num_ifaces);
313 	for (i = 0; i < num_ifaces; i++) {
314 		(*ip)[i] = NULL;
315 		if (W_ERROR_IS_OK(results[i])) {
316 			status = dcom_IUnknown_from_OBJREF(ctx, &(*ip)[i], &r.out.ifaces[i]->obj);
317 			if (!NT_STATUS_IS_OK(status)) {
318 				results[i] = ntstatus_to_werror(status);
319 			} else if (!ru_template)
320 				ru_template = (*ip)[i];
321 		}
322 	}
323 
324 	/* TODO:avg check when exactly oxid should be updated,its lifetime etc */
325 	if (m->rem_unknown && memcmp(&m->rem_unknown->obj.u_objref.u_standard.std.ipid, &ipidRemUnknown, sizeof(ipidRemUnknown))) {
326 		talloc_free(m->rem_unknown);
327 		m->rem_unknown = NULL;
328 	}
329 	if (!m->rem_unknown) {
330 		if (!ru_template) {
331 			DEBUG(1,("dcom_create_object: Cannot Create IRemUnknown - template interface not available\n"));
332 			hr = WERR_GEN_FAILURE;
333 		}
334 		m->rem_unknown = talloc_zero(m, struct IRemUnknown);
335 		memcpy(m->rem_unknown, ru_template, sizeof(struct IUnknown));
336 		GUID_from_string(COM_IREMUNKNOWN_UUID, &m->rem_unknown->obj.iid);
337 		m->rem_unknown->obj.u_objref.u_standard.std.ipid = ipidRemUnknown;
338 		m->rem_unknown->vtable = (struct IRemUnknown_vtable *)dcom_proxy_vtable_by_iid(&m->rem_unknown->obj.iid);
339 		/* TODO:avg copy stringbindigs?? */
340 	}
341 
342 	dcom_update_credentials_for_aliases(ctx, server, pds);
343 	{
344 		char *c;
345 		c = strchr(server, '[');
346 		if (m->host) talloc_free(m->host);
347 		m->host = c ? talloc_strndup(m, server, c - server) : talloc_strdup(m, server);
348 	}
349 	hr = WERR_OK;
350 end:
351 	talloc_free(loc_ctx);
352 	return hr;
353 }
354 
find_similar_binding(struct STRINGBINDING ** sb,const char * host)355 int find_similar_binding(struct STRINGBINDING **sb, const char *host)
356 {
357 	int i, l;
358 	l = strlen(host);
359 	for (i = 0; sb[i]; ++i) {
360 		if ((sb[i]->wTowerId == EPM_PROTOCOL_TCP) && !strncasecmp(host, sb[i]->NetworkAddr, l) && (sb[i]->NetworkAddr[l] == '['))
361 		break;
362 	}
363 	return i;
364 }
365 
dcom_query_interface(struct IUnknown * d,uint32_t cRefs,uint16_t cIids,struct GUID * iids,struct IUnknown ** ip,WERROR * results)366 WERROR dcom_query_interface(struct IUnknown *d, uint32_t cRefs, uint16_t cIids, struct GUID *iids, struct IUnknown **ip, WERROR *results)
367 {
368 	struct dcom_object_exporter *ox;
369 	struct REMQIRESULT *rqir;
370 	WERROR result;
371 	NTSTATUS status;
372 	int i;
373 	TALLOC_CTX *loc_ctx;
374 	struct IUnknown ru;
375 
376 	loc_ctx = talloc_new(d);
377 	ox = object_exporter_by_ip(d->ctx, d);
378 
379 	result = IRemUnknown_RemQueryInterface(ox->rem_unknown, loc_ctx, &IUnknown_ipid(d), cRefs, cIids, iids, &rqir);
380 	if (!W_ERROR_IS_OK(result)) {
381 		DEBUG(1, ("dcom_query_interface failed: %08X\n", W_ERROR_V(result)));
382 		talloc_free(loc_ctx);
383 		return result;
384 	}
385 	ru = *(struct IUnknown *)ox->rem_unknown;
386 	for (i = 0; i < cIids; ++i) {
387 		ip[i] = NULL;
388 		results[i] = rqir[i].hResult;
389 		if (W_ERROR_IS_OK(results[i])) {
390 			ru.obj.iid = iids[i];
391 			ru.obj.u_objref.u_standard.std = rqir[i].std;
392 			status = dcom_IUnknown_from_OBJREF(d->ctx, &ip[i], &ru.obj);
393 			if (!NT_STATUS_IS_OK(status)) {
394 				results[i] = ntstatus_to_werror(status);
395 			}
396 		}
397 	}
398 
399 	talloc_free(loc_ctx);
400 	return WERR_OK;
401 }
402 
is_ip_binding(const char * s)403 int is_ip_binding(const char* s)
404 {
405 	while (*s && (*s != '[')) {
406 		if (((*s >= '0') && (*s <= '9')) || *s == '.')
407 			++s;
408 		else
409 		    return 0;
410 	}
411 	return 1;
412 }
413 
dcom_get_pipe(struct IUnknown * iface,struct dcerpc_pipe ** pp)414 NTSTATUS dcom_get_pipe(struct IUnknown *iface, struct dcerpc_pipe **pp)
415 {
416 	struct dcerpc_binding *binding;
417 	struct GUID iid;
418 	uint64_t oxid;
419 	NTSTATUS status;
420 	int i, j, isimilar;
421 	struct dcerpc_pipe *p;
422 	struct dcom_object_exporter *ox;
423 	const struct ndr_interface_table *table;
424 
425 	ox = object_exporter_by_oxid(iface->ctx, iface->obj.u_objref.u_standard.std.oxid);
426 	if (!ox) {
427 		DEBUG(0, ("dcom_get_pipe: OXID not found\n"));
428 		return NT_STATUS_NOT_SUPPORTED;
429 	}
430 
431 	p = ox->pipe;
432 
433 	iid = iface->vtable->iid;
434 	table = ndr_table_by_uuid(&iid);
435 	if (table == NULL) {
436 		char *guid_str;
437 		guid_str = GUID_string(NULL, &iid);
438 		DEBUG(0,(__location__": dcom_get_pipe - unrecognized interface{%s}\n", guid_str));
439 		talloc_free(guid_str);
440 		return NT_STATUS_NOT_SUPPORTED;
441 	}
442 
443 	if (p && p->last_fault_code) {
444 		talloc_free(p);
445 		ox->pipe = p = NULL;
446 	}
447 
448 	if (p) {
449 		if (!GUID_equal(&p->syntax.uuid, &iid)) {
450 			ox->pipe->syntax.uuid = iid;
451 
452 			/* interface will always be present, so
453 			 * idl_iface_by_uuid can't return NULL */
454 			/* status = dcerpc_secondary_context(p, &p2, idl_iface_by_uuid(&iid)); */
455 			status = dcerpc_alter_context(p, p, &ndr_table_by_uuid(&iid)->syntax_id, &p->transfer_syntax);
456 		} else
457 			status = NT_STATUS_OK;
458 		*pp = p;
459 		return status;
460 	}
461 
462 	status = NT_STATUS_NO_MORE_ENTRIES;
463 
464 	/* To avoid delays whe connecting nonroutable bindings we 1st check binding starting with hostname */
465 	/* FIX:low create concurrent connections to all bindings, fastest wins - Win2k and newer does this way???? */
466 	isimilar = find_similar_binding(ox->bindings->stringbindings, ox->host);
467 	DEBUG(1, (__location__": dcom_get_pipe: host=%s, similar=%s\n", ox->host, ox->bindings->stringbindings[isimilar] ? ox->bindings->stringbindings[isimilar]->NetworkAddr : "None"));
468 	j = isimilar - 1;
469 	for (i = 0; ox->bindings->stringbindings[i]; ++i) {
470 		if (!ox->bindings->stringbindings[++j]) j = 0;
471 		/* FIXME:LOW Use also other transports if possible */
472 		if ((j != isimilar) && (ox->bindings->stringbindings[j]->wTowerId != EPM_PROTOCOL_TCP || !is_ip_binding(ox->bindings->stringbindings[j]->NetworkAddr))) {
473 			DEBUG(9, ("dcom_get_pipe: Skipping stringbinding %24.24s\n", ox->bindings->stringbindings[j]->NetworkAddr));
474 			continue;
475 		}
476 		DEBUG(9, ("dcom_get_pipe: Trying stringbinding %s\n", ox->bindings->stringbindings[j]->NetworkAddr));
477 		status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding,
478 							   ox->bindings->stringbindings[j]);
479 		if (!NT_STATUS_IS_OK(status)) {
480 			DEBUG(1, ("Error parsing string binding"));
481 		} else {
482 			/* FIXME:LOW Make flags more flexible */
483 			binding->flags |= DCERPC_AUTH_NTLM | DCERPC_SIGN;
484 			if (DEBUGLVL(11))
485 				binding->flags |= DCERPC_DEBUG_PRINT_BOTH;
486 			status = dcerpc_pipe_connect_b(iface->ctx->event_ctx, &p, binding,
487 						       ndr_table_by_uuid(&iid),
488 						       dcom_get_server_credentials(iface->ctx, binding->host),
489 							   iface->ctx->event_ctx, iface->ctx->lp_ctx);
490 			talloc_unlink(iface->ctx, binding);
491 		}
492 		if (NT_STATUS_IS_OK(status)) break;
493 	}
494 
495 	if (NT_STATUS_IS_ERR(status)) {
496 		DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status)));
497 		return status;
498 	}
499 
500 	DEBUG(2, ("Successfully connected to OXID %llx\n", (long long)oxid));
501 
502 	ox->pipe = *pp = p;
503 
504 	return NT_STATUS_OK;
505 }
506 
dcom_OBJREF_from_IUnknown(TALLLOC_CTX * mem_ctx,struct OBJREF * o,struct IUnknown * p)507 NTSTATUS dcom_OBJREF_from_IUnknown(TALLLOC_CTX *mem_ctx, struct OBJREF *o, struct IUnknown *p)
508 {
509 	/* FIXME: Cache generated objref objects? */
510 	ZERO_STRUCTP(o);
511 
512 	if (!p) {
513 		o->signature = OBJREF_SIGNATURE;
514 		o->flags = OBJREF_NULL;
515 	} else {
516 		*o = p->obj;
517 		switch(o->flags) {
518 		case OBJREF_CUSTOM: {
519 			marshal_fn marshal;
520 
521 			marshal = dcom_marshal_by_clsid(&o->u_objref.u_custom.clsid);
522 			if (marshal) {
523 				return marshal(mem_ctx, p, o);
524 			} else {
525 				return NT_STATUS_NOT_SUPPORTED;
526 			}
527 		}
528 		}
529 	}
530 
531 	return NT_STATUS_OK;
532 }
533 
dcom_IUnknown_from_OBJREF(struct com_context * ctx,struct IUnknown ** _p,struct OBJREF * o)534 enum ndr_err_code dcom_IUnknown_from_OBJREF(struct com_context *ctx, struct IUnknown **_p, struct OBJREF *o)
535 {
536 	struct IUnknown *p;
537 	struct dcom_object_exporter *ox;
538 	unmarshal_fn unmarshal;
539 
540 	switch(o->flags) {
541 	case OBJREF_NULL:
542 		*_p = NULL;
543 		return NDR_ERR_SUCCESS;
544 
545 	case OBJREF_STANDARD:
546 		p = talloc_zero(ctx, struct IUnknown);
547 		p->ctx = ctx;
548 		p->obj = *o;
549 		p->vtable = dcom_proxy_vtable_by_iid(&o->iid);
550 
551 		if (!p->vtable) {
552 			DEBUG(0, ("Unable to find proxy class for interface with IID %s\n", GUID_string(ctx, &o->iid)));
553 			return NDR_ERR_INVALID_POINTER;
554 		}
555 
556 		p->vtable->Release_send = dcom_release_send;
557 
558 		ox = object_exporter_by_oxid(ctx, o->u_objref.u_standard.std.oxid);
559 		/* FIXME: Add object to list of objects to ping */
560 		*_p = p;
561 		return NDR_ERR_SUCCESS;
562 
563 	case OBJREF_HANDLER:
564 		p = talloc_zero(ctx, struct IUnknown);
565 		p->ctx = ctx;
566 		p->obj = *o;
567 		ox = object_exporter_by_oxid(ctx, o->u_objref.u_handler.std.oxid );
568 		/* FIXME: Add object to list of objects to ping */
569 /*FIXME		p->vtable = dcom_vtable_by_clsid(&o->u_objref.u_handler.clsid);*/
570 		/* FIXME: Do the custom unmarshaling call */
571 
572 		*_p = p;
573 		return NDR_ERR_BAD_SWITCH;
574 
575 	case OBJREF_CUSTOM:
576 		p = talloc_zero(ctx, struct IUnknown);
577 		p->ctx = ctx;
578 		p->vtable = NULL;
579 		p->obj = *o;
580 		unmarshal = dcom_unmarshal_by_clsid(&o->u_objref.u_custom.clsid);
581 		*_p = p;
582 		if (unmarshal) {
583 		    return unmarshal(ctx, o, _p);
584 		} else {
585 		    return NDR_ERR_BAD_SWITCH;
586 		}
587 	}
588 
589 	return NDR_ERR_BAD_SWITCH;
590 }
591 
dcom_get_current_oxid(void)592 uint64_t dcom_get_current_oxid(void)
593 {
594 	return getpid();
595 }
596 
597 /* FIXME:Fake async dcom_get_pipe_* */
dcom_get_pipe_send(struct IUnknown * d,TALLOC_CTX * mem_ctx)598 struct composite_context *dcom_get_pipe_send(struct IUnknown *d, TALLOC_CTX *mem_ctx)
599 {
600         struct composite_context *c;
601 
602         c = composite_create(0, d->ctx->event_ctx);
603         if (c == NULL) return NULL;
604         c->private_data = d;
605         /* composite_done(c); bugged - callback is triggered twice by composite_continue and composite_done */
606         c->state = COMPOSITE_STATE_DONE; /* this is workaround */
607 
608         return c;
609 }
610 
dcom_get_pipe_recv(struct composite_context * c,struct dcerpc_pipe ** pp)611 NTSTATUS dcom_get_pipe_recv(struct composite_context *c, struct dcerpc_pipe **pp)
612 {
613         NTSTATUS status;
614 
615         status = dcom_get_pipe((struct IUnknown *)c->private_data, pp);
616         talloc_free(c);
617 
618         return status;
619 }
620 
621 /* FIXME:avg put IUnknown_Release_out into header */
622 struct IUnknown_Release_out {
623         uint32_t result;
624 };
625 
dcom_release_continue(struct composite_context * cr)626 void dcom_release_continue(struct composite_context *cr)
627 {
628 	struct composite_context *c;
629 	struct IUnknown *d;
630 	struct IUnknown_Release_out *out;
631 	WERROR r;
632 
633 	c = talloc_get_type(cr->async.private_data, struct composite_context);
634 	d = c->private_data;
635 	r = IRemUnknown_RemRelease_recv(cr);
636 	talloc_free(d);
637 	out = talloc_zero(c, struct IUnknown_Release_out);
638 	out->result = W_ERROR_V(r);
639 	c->private_data = out;
640 	composite_done(c);
641 }
642 
dcom_release_send(struct IUnknown * d,TALLOC_CTX * mem_ctx)643 struct composite_context *dcom_release_send(struct IUnknown *d, TALLOC_CTX *mem_ctx)
644 {
645         struct composite_context *c, *cr;
646 	struct REMINTERFACEREF iref;
647 	struct dcom_object_exporter *ox;
648 
649         c = composite_create(d->ctx, d->ctx->event_ctx);
650         if (c == NULL) return NULL;
651         c->private_data = d;
652 
653 	ox = object_exporter_by_ip(d->ctx, d);
654 	iref.ipid = IUnknown_ipid(d);
655 	iref.cPublicRefs = 5;
656 	iref.cPrivateRefs = 0;
657 	cr = IRemUnknown_RemRelease_send(ox->rem_unknown, mem_ctx, 1, &iref);
658 
659 	composite_continue(c, cr, dcom_release_continue, c);
660 	return c;
661 }
662 
dcom_release_recv(struct composite_context * c)663 uint32_t dcom_release_recv(struct composite_context *c)
664 {
665 	NTSTATUS status;
666 	WERROR r;
667 
668 	status = composite_wait(c);
669 	if (!NT_STATUS_IS_OK(status))
670 		r = ntstatus_to_werror(status);
671 	else
672 		W_ERROR_V(r) = ((struct IUnknown_Release_out *)c->private_data)->result;
673 	talloc_free(c);
674 	return W_ERROR_IS_OK(r) ? 0 : W_ERROR_V(r);
675 }
676 
dcom_release(void * interface,TALLOC_CTX * mem_ctx)677 uint32_t dcom_release(void *interface, TALLOC_CTX *mem_ctx)
678 {
679 	struct composite_context *c;
680 
681 	c = dcom_release_send(interface, mem_ctx);
682 	return dcom_release_recv(c);
683 }
684 
dcom_proxy_async_call_recv_pipe_send_rpc(struct composite_context * c_pipe)685 void dcom_proxy_async_call_recv_pipe_send_rpc(struct composite_context *c_pipe)
686 {
687         struct composite_context *c;
688         struct dcom_proxy_async_call_state *s;
689         struct dcerpc_pipe *p;
690         struct rpc_request *req;
691         NTSTATUS status;
692 
693         c = c_pipe->async.private_data;
694         s = talloc_get_type(c->private_data, struct dcom_proxy_async_call_state);
695 
696         status = dcom_get_pipe_recv(c_pipe, &p);
697         if (!NT_STATUS_IS_OK(status)) {
698                 composite_error(c, NT_STATUS_RPC_NT_CALL_FAILED);
699                 return;
700         }
701 /*TODO: FIXME - for now this unused anyway */
702         req = dcerpc_ndr_request_send(p, &s->d->obj.u_objref.u_standard.std.ipid, s->table, s->opnum, s, s->r);
703         composite_continue_rpc(c, req, s->continuation, c);
704 }
705