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