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.
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
)
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
);
53 return NT_STATUS_NO_MEMORY
;
56 status
= dcerpc_parse_binding(mem_ctx
, bstr
, &b
);
58 if (!NT_STATUS_IS_OK(status
)) {
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
;
72 for (c
= ctx
->dcom
->credentials
; c
; c
= c
->next
) {
73 if (c
->server
== NULL
) {
77 if (server
&& !strcmp(c
->server
, server
)) return c
->credentials
;
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
);
105 talloc_steal(c
, c
->credentials
);
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
);
118 talloc_steal(c
, c
->credentials
);
120 DLIST_ADD(ctx
->dcom
->credentials
, c
);
123 void dcom_update_credentials_for_aliases(struct com_context
*ctx
,
125 struct DUALSTRINGARRAY
*pds
)
127 struct cli_credentials
*cc
;
128 struct dcerpc_binding
*b
;
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
)
136 status
= dcerpc_binding_from_STRINGBINDING(ctx
, &b
, pds
->stringbindings
[i
]);
137 if (!NT_STATUS_IS_OK(status
))
139 dcom_add_server_credentials(ctx
, b
->host
, cc
);
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
);
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
);
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" };
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
))) {
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
);
183 for (i
= 0; i
< ARRAY_SIZE(available_transports
); i
++)
185 char *binding
= talloc_asprintf(loc_ctx
, "%s:%s", available_transports
[i
], server
);
187 status
= NT_STATUS_NO_MEMORY
;
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
)) {
197 (*p
)->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
200 DEBUG(1,(__location__
": dcom_connect_host : %s\n", get_friendly_nt_error_msg(status
)));
205 talloc_free(loc_ctx
);
209 struct dcom_object_exporter
*object_exporter_by_oxid(struct com_context
*ctx
,
212 struct dcom_object_exporter
*ox
;
213 for (ox
= ctx
->dcom
->object_exporters
; ox
; ox
= ox
->next
) {
214 if (ox
->oxid
== oxid
) {
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
);
227 ox
= talloc_zero(ctx
, struct dcom_object_exporter
);
228 DLIST_ADD(ctx
->dcom
->object_exporters
, ox
);
231 talloc_free(ox
->bindings
);
233 ox
->bindings
= bindings
;
234 talloc_steal(ox
, bindings
);
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
;
249 struct RemoteActivation r
;
250 struct DUALSTRINGARRAY
*pds
;
254 struct GUID ipidRemUnknown
;
255 struct IUnknown
*ru_template
;
256 struct ORPCTHAT that
;
258 struct COMVERSION ServerVersion
;
259 struct MInterfacePointer
**ifaces
;
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
);
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();
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
;
283 r
.out
.pdsaOxidBindings
= &pds
;
284 r
.out
.ipidRemUnknown
= &ipidRemUnknown
;
285 r
.out
.AuthnHint
= &AuthnHint
;
286 r
.out
.ServerVersion
= &ServerVersion
;
288 r
.out
.ifaces
= ifaces
;
289 r
.out
.results
= results
;
291 status
= dcerpc_RemoteActivation(p
, loc_ctx
, &r
);
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
);
300 if(!W_ERROR_IS_OK(r
.out
.result
)) {
305 if(!W_ERROR_IS_OK(hr
)) {
309 m
= object_exporter_update_oxid(ctx
, oxid
, pds
);
312 *ip
= talloc_array(ctx
, struct IUnknown
*, num_ifaces
);
313 for (i
= 0; i
< num_ifaces
; i
++) {
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
) {
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
);
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
);
351 talloc_free(loc_ctx
);
355 int find_similar_binding(struct STRINGBINDING
**sb
, const char *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
] == '['))
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
;
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
);
385 ru
= *(struct IUnknown
*)ox
->rem_unknown
;
386 for (i
= 0; i
< cIids
; ++i
) {
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
);
403 int is_ip_binding(const char* s
)
405 while (*s
&& (*s
!= '[')) {
406 if (((*s
>= '0') && (*s
<= '9')) || *s
== '.')
414 NTSTATUS
dcom_get_pipe(struct IUnknown
*iface
, struct dcerpc_pipe
**pp
)
416 struct dcerpc_binding
*binding
;
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
);
427 DEBUG(0, ("dcom_get_pipe: OXID not found\n"));
428 return NT_STATUS_NOT_SUPPORTED
;
433 iid
= iface
->vtable
->iid
;
434 table
= ndr_table_by_uuid(&iid
);
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
) {
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
);
457 status
= NT_STATUS_OK
;
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"));
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
));
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"));
482 /* FIXME:LOW Make flags more flexible */
483 binding
->flags
|= DCERPC_AUTH_NTLM
| DCERPC_SIGN
;
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
)));
500 DEBUG(2, ("Successfully connected to OXID %llx\n", (long long)oxid
));
507 NTSTATUS
dcom_OBJREF_from_IUnknown(TALLLOC_CTX
*mem_ctx
, struct OBJREF
*o
, struct IUnknown
*p
)
509 /* FIXME: Cache generated objref objects? */
513 o
->signature
= OBJREF_SIGNATURE
;
514 o
->flags
= OBJREF_NULL
;
518 case OBJREF_CUSTOM
: {
521 marshal
= dcom_marshal_by_clsid(&o
->u_objref
.u_custom
.clsid
);
523 return marshal(mem_ctx
, p
, o
);
525 return NT_STATUS_NOT_SUPPORTED
;
534 enum ndr_err_code
dcom_IUnknown_from_OBJREF(struct com_context
*ctx
, struct IUnknown
**_p
, struct OBJREF
*o
)
537 struct dcom_object_exporter
*ox
;
538 unmarshal_fn unmarshal
;
543 return NDR_ERR_SUCCESS
;
545 case OBJREF_STANDARD
:
546 p
= talloc_zero(ctx
, struct IUnknown
);
549 p
->vtable
= dcom_proxy_vtable_by_iid(&o
->iid
);
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 */
561 return NDR_ERR_SUCCESS
;
564 p
= talloc_zero(ctx
, struct IUnknown
);
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 */
573 return NDR_ERR_BAD_SWITCH
;
576 p
= talloc_zero(ctx
, struct IUnknown
);
580 unmarshal
= dcom_unmarshal_by_clsid(&o
->u_objref
.u_custom
.clsid
);
583 return unmarshal(ctx
, o
, _p
);
585 return NDR_ERR_BAD_SWITCH
;
589 return NDR_ERR_BAD_SWITCH
;
592 uint64_t dcom_get_current_oxid(void)
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
;
605 /* composite_done(c); bugged - callback is triggered twice by composite_continue and composite_done */
606 c
->state
= COMPOSITE_STATE_DONE
; /* this is workaround */
611 NTSTATUS
dcom_get_pipe_recv(struct composite_context
*c
, struct dcerpc_pipe
**pp
)
615 status
= dcom_get_pipe((struct IUnknown
*)c
->private_data
, pp
);
621 /* FIXME:avg put IUnknown_Release_out into header */
622 struct IUnknown_Release_out
{
626 void dcom_release_continue(struct composite_context
*cr
)
628 struct composite_context
*c
;
630 struct IUnknown_Release_out
*out
;
633 c
= talloc_get_type(cr
->async
.private_data
, struct composite_context
);
635 r
= IRemUnknown_RemRelease_recv(cr
);
637 out
= talloc_zero(c
, struct IUnknown_Release_out
);
638 out
->result
= W_ERROR_V(r
);
639 c
->private_data
= out
;
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
;
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
);
663 uint32_t dcom_release_recv(struct composite_context
*c
)
668 status
= composite_wait(c
);
669 if (!NT_STATUS_IS_OK(status
))
670 r
= ntstatus_to_werror(status
);
672 W_ERROR_V(r
) = ((struct IUnknown_Release_out
*)c
->private_data
)->result
;
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
;
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
);
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
);