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
)
39 char *host
, *endpoint
;
40 struct dcerpc_binding
*b
;
42 b
= talloc_zero(mem_ctx
, struct dcerpc_binding
);
44 return NT_STATUS_NO_MEMORY
;
47 b
->transport
= dcerpc_transport_by_endpoint_protocol(bd
->wTowerId
);
49 if (b
->transport
== -1) {
50 DEBUG(1, ("Can't find transport match endpoint protocol %d\n", bd
->wTowerId
));
52 return NT_STATUS_NOT_SUPPORTED
;
55 host
= talloc_strdup(b
, bd
->NetworkAddr
);
56 endpoint
= strchr(host
, '[');
62 endpoint
[strlen(endpoint
)-1] = '\0';
66 b
->endpoint
= talloc_strdup(b
, endpoint
);
72 struct cli_credentials
*dcom_get_server_credentials(struct com_context
*ctx
, const char *server
)
74 struct dcom_server_credentials
*c
;
75 struct cli_credentials
*d
;
78 for (c
= ctx
->dcom
->credentials
; c
; c
= c
->next
) {
79 if (c
->server
== NULL
) {
83 if (server
&& !strcmp(c
->server
, server
)) return c
->credentials
;
89 * Register credentials for a specific server.
91 * @param ctx COM context
92 * @param server Name of server, can be NULL
93 * @param credentials Credentials object
95 void dcom_add_server_credentials(struct com_context
*ctx
, const char *server
,
96 struct cli_credentials
*credentials
)
98 struct dcom_server_credentials
*c
;
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
);
111 talloc_steal(c
, c
->credentials
);
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
);
124 talloc_steal(c
, c
->credentials
);
126 DLIST_ADD(ctx
->dcom
->credentials
, c
);
129 void dcom_update_credentials_for_aliases(struct com_context
*ctx
,
131 struct DUALSTRINGARRAY
*pds
)
133 struct cli_credentials
*cc
;
134 struct dcerpc_binding
*b
;
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
)
142 status
= dcerpc_binding_from_STRINGBINDING(ctx
, &b
, pds
->stringbindings
[i
]);
143 if (!NT_STATUS_IS_OK(status
))
145 dcom_add_server_credentials(ctx
, b
->host
, cc
);
150 struct dcom_client_context
*dcom_client_init(struct com_context
*ctx
, struct cli_credentials
*credentials
)
152 ctx
->dcom
= talloc_zero(ctx
, struct dcom_client_context
);
154 credentials
= cli_credentials_init(ctx
);
155 cli_credentials_set_conf(credentials
, ctx
->lp_ctx
);
156 cli_credentials_parse_string(credentials
, "%", CRED_SPECIFIED
);
158 dcom_add_server_credentials(ctx
, NULL
, credentials
);
162 static NTSTATUS
dcom_connect_host(struct com_context
*ctx
,
163 struct dcerpc_pipe
**p
, const char *server
)
165 struct dcerpc_binding
*bd
;
166 const char * available_transports
[] = { "ncacn_ip_tcp", "ncacn_np" };
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
);
176 loc_ctx
= talloc_new(ctx
);
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
))) {
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
);
189 for (i
= 0; i
< ARRAY_SIZE(available_transports
); i
++)
191 char *binding
= talloc_asprintf(loc_ctx
, "%s:%s", available_transports
[i
], server
);
193 status
= NT_STATUS_NO_MEMORY
;
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
);
201 if (NT_STATUS_IS_OK(status
)) {
203 (*p
)->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
206 DEBUG(1,(__location__
": dcom_connect_host : %s\n", get_friendly_nt_error_msg(status
)));
211 talloc_free(loc_ctx
);
215 struct dcom_object_exporter
*object_exporter_by_oxid(struct com_context
*ctx
,
218 struct dcom_object_exporter
*ox
;
219 for (ox
= ctx
->dcom
->object_exporters
; ox
; ox
= ox
->next
) {
220 if (ox
->oxid
== oxid
) {
228 struct dcom_object_exporter
*object_exporter_update_oxid(struct com_context
*ctx
, uint64_t oxid
, struct DUALSTRINGARRAY
*bindings
)
230 struct dcom_object_exporter
*ox
;
231 ox
= object_exporter_by_oxid(ctx
, oxid
);
233 ox
= talloc_zero(ctx
, struct dcom_object_exporter
);
234 DLIST_ADD(ctx
->dcom
->object_exporters
, ox
);
237 talloc_free(ox
->bindings
);
239 ox
->bindings
= bindings
;
240 talloc_steal(ox
, bindings
);
244 struct dcom_object_exporter
*object_exporter_by_ip(struct com_context
*ctx
, struct IUnknown
*ip
)
246 return object_exporter_by_oxid(ctx
, ip
->obj
.u_objref
.u_standard
.std
.oxid
);
249 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
)
251 uint16_t protseq
[] = DCOM_NEGOTIATED_PROTOCOLS
;
252 struct dcerpc_pipe
*p
;
253 struct dcom_object_exporter
*m
;
255 struct RemoteActivation r
;
256 struct DUALSTRINGARRAY
*pds
;
260 struct GUID ipidRemUnknown
;
261 struct IUnknown
*ru_template
;
262 struct ORPCTHAT that
;
264 struct COMVERSION ServerVersion
;
265 struct MInterfacePointer
**ifaces
;
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
);
273 loc_ctx
= talloc_new(ctx
);
275 ifaces
= talloc_array(loc_ctx
, struct MInterfacePointer
*, num_ifaces
);
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();
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
;
289 r
.out
.pdsaOxidBindings
= &pds
;
290 r
.out
.ipidRemUnknown
= &ipidRemUnknown
;
291 r
.out
.AuthnHint
= &AuthnHint
;
292 r
.out
.ServerVersion
= &ServerVersion
;
294 r
.out
.ifaces
= ifaces
;
295 r
.out
.results
= results
;
297 status
= dcerpc_RemoteActivation(p
, loc_ctx
, &r
);
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
);
306 if(!W_ERROR_IS_OK(r
.out
.result
)) {
311 if(!W_ERROR_IS_OK(hr
)) {
315 m
= object_exporter_update_oxid(ctx
, oxid
, pds
);
318 *ip
= talloc_array(ctx
, struct IUnknown
*, num_ifaces
);
319 for (i
= 0; i
< num_ifaces
; i
++) {
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
];
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
;
335 if (!m
->rem_unknown
) {
337 DEBUG(1,("dcom_create_object: Cannot Create IRemUnknown - template interface not available\n"));
338 hr
= WERR_GENERAL_FAILURE
;
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?? */
348 dcom_update_credentials_for_aliases(ctx
, server
, pds
);
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
);
357 talloc_free(loc_ctx
);
361 int find_similar_binding(struct STRINGBINDING
**sb
, const char *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
] == '['))
372 WERROR
dcom_query_interface(struct IUnknown
*d
, uint32_t cRefs
, uint16_t cIids
, struct GUID
*iids
, struct IUnknown
**ip
, WERROR
*results
)
374 struct dcom_object_exporter
*ox
;
375 struct REMQIRESULT
*rqir
;
382 loc_ctx
= talloc_new(d
);
383 ox
= object_exporter_by_ip(d
->ctx
, d
);
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
);
391 ru
= *(struct IUnknown
*)ox
->rem_unknown
;
392 for (i
= 0; i
< cIids
; ++i
) {
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
);
405 talloc_free(loc_ctx
);
409 int is_ip_binding(const char* s
)
411 while (*s
&& (*s
!= '[')) {
412 if (((*s
>= '0') && (*s
<= '9')) || *s
== '.')
420 NTSTATUS
dcom_get_pipe(struct IUnknown
*iface
, struct dcerpc_pipe
**pp
)
422 struct dcerpc_binding
*binding
;
427 struct dcerpc_pipe
*p
;
428 struct dcom_object_exporter
*ox
;
429 const struct ndr_interface_table
*table
;
431 ox
= object_exporter_by_oxid(iface
->ctx
, iface
->obj
.u_objref
.u_standard
.std
.oxid
);
433 DEBUG(0, ("dcom_get_pipe: OXID not found\n"));
434 return NT_STATUS_NOT_SUPPORTED
;
439 iid
= iface
->vtable
->iid
;
440 table
= ndr_table_by_uuid(&iid
);
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
;
449 if (p
&& p
->last_fault_code
) {
455 if (!GUID_equal(&p
->syntax
.uuid
, &iid
)) {
456 ox
->pipe
->syntax
.uuid
= iid
;
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
);
463 status
= NT_STATUS_OK
;
468 status
= NT_STATUS_NO_MORE_ENTRIES
;
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"));
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
));
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"));
488 /* FIXME:LOW Make flags more flexible */
489 binding
->flags
|= DCERPC_AUTH_NTLM
| DCERPC_SIGN
;
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
);
498 if (NT_STATUS_IS_OK(status
)) break;
501 if (NT_STATUS_IS_ERR(status
)) {
502 DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status
)));
506 DEBUG(2, ("Successfully connected to OXID %llx\n", (long long)oxid
));
513 NTSTATUS
dcom_OBJREF_from_IUnknown(TALLLOC_CTX
*mem_ctx
, struct OBJREF
*o
, struct IUnknown
*p
)
515 /* FIXME: Cache generated objref objects? */
519 o
->signature
= OBJREF_SIGNATURE
;
520 o
->flags
= OBJREF_NULL
;
524 case OBJREF_CUSTOM
: {
527 marshal
= dcom_marshal_by_clsid(&o
->u_objref
.u_custom
.clsid
);
529 return marshal(mem_ctx
, p
, o
);
531 return NT_STATUS_NOT_SUPPORTED
;
540 enum ndr_err_code
dcom_IUnknown_from_OBJREF(struct com_context
*ctx
, struct IUnknown
**_p
, struct OBJREF
*o
)
543 struct dcom_object_exporter
*ox
;
544 unmarshal_fn unmarshal
;
549 return NDR_ERR_SUCCESS
;
551 case OBJREF_STANDARD
:
552 p
= talloc_zero(ctx
, struct IUnknown
);
555 p
->vtable
= dcom_proxy_vtable_by_iid(&o
->iid
);
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
;
562 p
->vtable
->Release_send
= dcom_release_send
;
564 ox
= object_exporter_by_oxid(ctx
, o
->u_objref
.u_standard
.std
.oxid
);
565 /* FIXME: Add object to list of objects to ping */
567 return NDR_ERR_SUCCESS
;
570 p
= talloc_zero(ctx
, struct IUnknown
);
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 */
579 return NDR_ERR_BAD_SWITCH
;
582 p
= talloc_zero(ctx
, struct IUnknown
);
586 unmarshal
= dcom_unmarshal_by_clsid(&o
->u_objref
.u_custom
.clsid
);
589 return unmarshal(ctx
, o
, _p
);
591 return NDR_ERR_BAD_SWITCH
;
595 return NDR_ERR_BAD_SWITCH
;
598 uint64_t dcom_get_current_oxid(void)
603 /* FIXME:Fake async dcom_get_pipe_* */
604 struct composite_context
*dcom_get_pipe_send(struct IUnknown
*d
, TALLOC_CTX
*mem_ctx
)
606 struct composite_context
*c
;
608 c
= composite_create(0, d
->ctx
->event_ctx
);
609 if (c
== NULL
) return NULL
;
611 /* composite_done(c); bugged - callback is triggered twice by composite_continue and composite_done */
612 c
->state
= COMPOSITE_STATE_DONE
; /* this is workaround */
617 NTSTATUS
dcom_get_pipe_recv(struct composite_context
*c
, struct dcerpc_pipe
**pp
)
621 status
= dcom_get_pipe((struct IUnknown
*)c
->private_data
, pp
);
627 /* FIXME:avg put IUnknown_Release_out into header */
628 struct IUnknown_Release_out
{
632 void dcom_release_continue(struct composite_context
*cr
)
634 struct composite_context
*c
;
636 struct IUnknown_Release_out
*out
;
639 c
= talloc_get_type(cr
->async
.private_data
, struct composite_context
);
641 r
= IRemUnknown_RemRelease_recv(cr
);
643 out
= talloc_zero(c
, struct IUnknown_Release_out
);
644 out
->result
= W_ERROR_V(r
);
645 c
->private_data
= out
;
649 struct composite_context
*dcom_release_send(struct IUnknown
*d
, TALLOC_CTX
*mem_ctx
)
651 struct composite_context
*c
, *cr
;
652 struct REMINTERFACEREF iref
;
653 struct dcom_object_exporter
*ox
;
655 c
= composite_create(d
->ctx
, d
->ctx
->event_ctx
);
656 if (c
== NULL
) return NULL
;
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
);
665 composite_continue(c
, cr
, dcom_release_continue
, c
);
669 uint32_t dcom_release_recv(struct composite_context
*c
)
674 status
= composite_wait(c
);
675 if (!NT_STATUS_IS_OK(status
))
676 r
= ntstatus_to_werror(status
);
678 W_ERROR_V(r
) = ((struct IUnknown_Release_out
*)c
->private_data
)->result
;
680 return W_ERROR_IS_OK(r
) ? 0 : W_ERROR_V(r
);
683 uint32_t dcom_release(void *interface
, TALLOC_CTX
*mem_ctx
)
685 struct composite_context
*c
;
687 c
= dcom_release_send(interface
, mem_ctx
);
688 return dcom_release_recv(c
);
691 void dcom_proxy_async_call_recv_pipe_send_rpc(struct composite_context
*c_pipe
)
693 struct composite_context
*c
;
694 struct dcom_proxy_async_call_state
*s
;
695 struct dcerpc_pipe
*p
;
696 struct rpc_request
*req
;
699 c
= c_pipe
->async
.private_data
;
700 s
= talloc_get_type(c
->private_data
, struct dcom_proxy_async_call_state
);
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
);
707 /*TODO: FIXME - for now this unused anyway */
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
);