smbd: First watch, then defer
[Samba.git] / source4 / lib / com / dcom / main.c
blobea1e4f8b8f1f3cea506492a9e74d4f440eabdd65
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>
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.
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.
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.
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"
35 #define DCOM_NEGOTIATED_PROTOCOLS { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NCALRPC }
37 static NTSTATUS dcerpc_binding_from_STRINGBINDING(TALLOC_CTX *mem_ctx, struct dcerpc_binding **b_out, struct STRINGBINDING *bd)
39 char *tstr;
40 char *bstr;
41 enum dcerpc_transport_t transport;
42 struct dcerpc_binding *b;
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;
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;
56 status = dcerpc_parse_binding(mem_ctx, bstr, &b);
57 TALLOC_FREE(bstr);
58 if (!NT_STATUS_IS_OK(status)) {
59 return status;
62 *b_out = b;
63 return NT_STATUS_OK;
66 struct cli_credentials *dcom_get_server_credentials(struct com_context *ctx, const char *server)
68 struct dcom_server_credentials *c;
69 struct cli_credentials *d;
71 d = NULL;
72 for (c = ctx->dcom->credentials; c; c = c->next) {
73 if (c->server == NULL) {
74 d = c->credentials;
75 continue;
77 if (server && !strcmp(c->server, server)) return c->credentials;
79 return d;
82 /**
83 * Register credentials for a specific server.
85 * @param ctx COM context
86 * @param server Name of server, can be NULL
87 * @param credentials Credentials object
89 void dcom_add_server_credentials(struct com_context *ctx, const char *server,
90 struct cli_credentials *credentials)
92 struct dcom_server_credentials *c;
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);
108 return;
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);
120 DLIST_ADD(ctx->dcom->credentials, c);
123 void dcom_update_credentials_for_aliases(struct com_context *ctx,
124 const char *server,
125 struct DUALSTRINGARRAY *pds)
127 struct cli_credentials *cc;
128 struct dcerpc_binding *b;
129 uint32_t i;
130 NTSTATUS status;
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);
144 struct dcom_client_context *dcom_client_init(struct com_context *ctx, struct cli_credentials *credentials)
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);
152 dcom_add_server_credentials(ctx, NULL, credentials);
153 return ctx->dcom;
156 static NTSTATUS dcom_connect_host(struct com_context *ctx,
157 struct dcerpc_pipe **p, const char *server)
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;
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);
170 loc_ctx = talloc_new(ctx);
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;
183 for (i = 0; i < ARRAY_SIZE(available_transports); i++)
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;
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);
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)));
204 end:
205 talloc_free(loc_ctx);
206 return status;
209 struct dcom_object_exporter *object_exporter_by_oxid(struct com_context *ctx,
210 uint64_t oxid)
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;
219 return NULL;
222 struct dcom_object_exporter *object_exporter_update_oxid(struct com_context *ctx, uint64_t oxid, struct DUALSTRINGARRAY *bindings)
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);
233 ox->bindings = bindings;
234 talloc_steal(ox, bindings);
235 return ox;
238 struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, struct IUnknown *ip)
240 return object_exporter_by_oxid(ctx, ip->obj.u_objref.u_standard.std.oxid);
243 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)
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 WERROR 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;
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);
267 loc_ctx = talloc_new(ctx);
269 ifaces = talloc_array(loc_ctx, struct MInterfacePointer *, num_ifaces);
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;
291 status = dcerpc_RemoteActivation(p, loc_ctx, &r);
292 talloc_free(p);
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;
300 if(!W_ERROR_IS_OK(r.out.result)) {
301 hr = r.out.result;
302 goto end;
305 if(!W_ERROR_IS_OK(hr)) {
306 goto end;
309 m = object_exporter_update_oxid(ctx, oxid, pds);
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];
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;
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_GENERAL_FAILURE;
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?? */
342 dcom_update_credentials_for_aliases(ctx, server, pds);
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);
349 hr = WERR_OK;
350 end:
351 talloc_free(loc_ctx);
352 return hr;
355 int find_similar_binding(struct STRINGBINDING **sb, const char *host)
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;
363 return i;
366 WERROR dcom_query_interface(struct IUnknown *d, uint32_t cRefs, uint16_t cIids, struct GUID *iids, struct IUnknown **ip, WERROR *results)
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;
376 loc_ctx = talloc_new(d);
377 ox = object_exporter_by_ip(d->ctx, d);
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;
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);
399 talloc_free(loc_ctx);
400 return WERR_OK;
403 int is_ip_binding(const char* s)
405 while (*s && (*s != '[')) {
406 if (((*s >= '0') && (*s <= '9')) || *s == '.')
407 ++s;
408 else
409 return 0;
411 return 1;
414 NTSTATUS dcom_get_pipe(struct IUnknown *iface, struct dcerpc_pipe **pp)
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;
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;
431 p = ox->pipe;
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;
443 if (p && p->last_fault_code) {
444 talloc_free(p);
445 ox->pipe = p = NULL;
448 if (p) {
449 if (!GUID_equal(&p->syntax.uuid, &iid)) {
450 ox->pipe->syntax.uuid = iid;
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;
462 status = NT_STATUS_NO_MORE_ENTRIES;
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;
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);
492 if (NT_STATUS_IS_OK(status)) break;
495 if (NT_STATUS_IS_ERR(status)) {
496 DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status)));
497 return status;
500 DEBUG(2, ("Successfully connected to OXID %llx\n", (long long)oxid));
502 ox->pipe = *pp = p;
504 return NT_STATUS_OK;
507 NTSTATUS dcom_OBJREF_from_IUnknown(TALLLOC_CTX *mem_ctx, struct OBJREF *o, struct IUnknown *p)
509 /* FIXME: Cache generated objref objects? */
510 ZERO_STRUCTP(o);
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;
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;
531 return NT_STATUS_OK;
534 enum ndr_err_code dcom_IUnknown_from_OBJREF(struct com_context *ctx, struct IUnknown **_p, struct OBJREF *o)
536 struct IUnknown *p;
537 struct dcom_object_exporter *ox;
538 unmarshal_fn unmarshal;
540 switch(o->flags) {
541 case OBJREF_NULL:
542 *_p = NULL;
543 return NDR_ERR_SUCCESS;
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);
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;
556 p->vtable->Release_send = dcom_release_send;
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;
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 */
572 *_p = p;
573 return NDR_ERR_BAD_SWITCH;
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;
589 return NDR_ERR_BAD_SWITCH;
592 uint64_t dcom_get_current_oxid(void)
594 return getpid();
597 /* FIXME:Fake async dcom_get_pipe_* */
598 struct composite_context *dcom_get_pipe_send(struct IUnknown *d, TALLOC_CTX *mem_ctx)
600 struct composite_context *c;
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 */
608 return c;
611 NTSTATUS dcom_get_pipe_recv(struct composite_context *c, struct dcerpc_pipe **pp)
613 NTSTATUS status;
615 status = dcom_get_pipe((struct IUnknown *)c->private_data, pp);
616 talloc_free(c);
618 return status;
621 /* FIXME:avg put IUnknown_Release_out into header */
622 struct IUnknown_Release_out {
623 uint32_t result;
626 void dcom_release_continue(struct composite_context *cr)
628 struct composite_context *c;
629 struct IUnknown *d;
630 struct IUnknown_Release_out *out;
631 WERROR r;
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);
643 struct composite_context *dcom_release_send(struct IUnknown *d, TALLOC_CTX *mem_ctx)
645 struct composite_context *c, *cr;
646 struct REMINTERFACEREF iref;
647 struct dcom_object_exporter *ox;
649 c = composite_create(d->ctx, d->ctx->event_ctx);
650 if (c == NULL) return NULL;
651 c->private_data = d;
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);
659 composite_continue(c, cr, dcom_release_continue, c);
660 return c;
663 uint32_t dcom_release_recv(struct composite_context *c)
665 NTSTATUS status;
666 WERROR r;
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);
677 uint32_t dcom_release(void *interface, TALLOC_CTX *mem_ctx)
679 struct composite_context *c;
681 c = dcom_release_send(interface, mem_ctx);
682 return dcom_release_recv(c);
685 void dcom_proxy_async_call_recv_pipe_send_rpc(struct composite_context *c_pipe)
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;
693 c = c_pipe->async.private_data;
694 s = talloc_get_type(c->private_data, struct dcom_proxy_async_call_state);
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;
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);