2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1998,
5 * Largely re-written : 2005
6 * Copyright (C) Jeremy Allison 1998 - 2005
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "rpc_server/srv_pipe_internal.h"
26 #define DBGC_CLASS DBGC_RPC_SRV
28 static int pipes_open
;
30 static struct pipes_struct
*InternalPipes
;
33 * the following prototypes are declared here to avoid
34 * code being moved about too much for a patch to be
35 * disrupted / less obvious.
37 * these functions, and associated functions that they
38 * call, should be moved behind a .so module-loading
39 * system _anyway_. so that's the next step...
42 static int close_internal_rpc_pipe_hnd(struct pipes_struct
*p
);
44 /****************************************************************************
45 Internal Pipe iterator functions.
46 ****************************************************************************/
48 struct pipes_struct
*get_first_internal_pipe(void)
53 struct pipes_struct
*get_next_internal_pipe(struct pipes_struct
*p
)
58 static void free_pipe_rpc_context_internal( PIPE_RPC_FNS
*list
)
60 PIPE_RPC_FNS
*tmp
= list
;
72 bool check_open_pipes(void)
74 struct pipes_struct
*p
;
76 for (p
= InternalPipes
; p
!= NULL
; p
= p
->next
) {
77 if (num_pipe_handles(p
) != 0) {
84 /****************************************************************************
86 ****************************************************************************/
88 static int close_internal_rpc_pipe_hnd(struct pipes_struct
*p
)
91 DEBUG(0,("Invalid pipe in close_internal_rpc_pipe_hnd\n"));
95 if (p
->auth
.auth_data_free_func
) {
96 (*p
->auth
.auth_data_free_func
)(&p
->auth
);
99 free_pipe_rpc_context_internal( p
->contexts
);
101 /* Free the handles database. */
102 close_policy_by_pipe(p
);
104 DLIST_REMOVE(InternalPipes
, p
);
111 /****************************************************************************
112 Make an internal namedpipes structure
113 ****************************************************************************/
115 struct pipes_struct
*make_internal_rpc_pipe_p(TALLOC_CTX
*mem_ctx
,
116 const struct ndr_syntax_id
*syntax
,
117 const char *client_address
,
118 struct auth_serversupplied_info
*server_info
,
119 struct messaging_context
*msg_ctx
)
121 struct pipes_struct
*p
;
123 DEBUG(4,("Create pipe requested %s\n",
124 get_pipe_name_from_syntax(talloc_tos(), syntax
)));
126 p
= TALLOC_ZERO_P(mem_ctx
, struct pipes_struct
);
129 DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
133 p
->mem_ctx
= talloc_named(p
, 0, "pipe %s %p",
134 get_pipe_name_from_syntax(talloc_tos(),
136 if (p
->mem_ctx
== NULL
) {
137 DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
142 if (!init_pipe_handles(p
, syntax
)) {
143 DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
148 p
->server_info
= copy_serverinfo(p
, server_info
);
149 if (p
->server_info
== NULL
) {
150 DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n"));
151 close_policy_by_pipe(p
);
156 p
->msg_ctx
= msg_ctx
;
158 DLIST_ADD(InternalPipes
, p
);
160 strlcpy(p
->client_address
, client_address
, sizeof(p
->client_address
));
162 p
->endian
= RPC_LITTLE_ENDIAN
;
166 DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
167 get_pipe_name_from_syntax(talloc_tos(), syntax
), pipes_open
));
169 talloc_set_destructor(p
, close_internal_rpc_pipe_hnd
);
174 /****************************************************************************
175 ****************************************************************************/
177 static NTSTATUS
internal_ndr_push(TALLOC_CTX
*mem_ctx
,
178 struct rpc_pipe_client
*cli
,
179 const struct ndr_interface_table
*table
,
183 const struct ndr_interface_call
*call
;
184 struct ndr_push
*push
;
185 enum ndr_err_code ndr_err
;
187 if (!ndr_syntax_id_equal(&table
->syntax_id
, &cli
->abstract_syntax
) ||
188 (opnum
>= table
->num_calls
)) {
189 return NT_STATUS_INVALID_PARAMETER
;
192 call
= &table
->calls
[opnum
];
194 if (DEBUGLEVEL
>= 10) {
195 ndr_print_function_debug(call
->ndr_print
,
196 call
->name
, NDR_IN
, r
);
199 push
= ndr_push_init_ctx(mem_ctx
);
201 return NT_STATUS_NO_MEMORY
;
204 ndr_err
= call
->ndr_push(push
, NDR_IN
, r
);
205 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
207 return ndr_map_error2ntstatus(ndr_err
);
210 cli
->pipes_struct
->in_data
.data
= ndr_push_blob(push
);
211 talloc_steal(cli
->pipes_struct
->mem_ctx
,
212 cli
->pipes_struct
->in_data
.data
.data
);
218 /****************************************************************************
219 ****************************************************************************/
221 static NTSTATUS
internal_ndr_pull(TALLOC_CTX
*mem_ctx
,
222 struct rpc_pipe_client
*cli
,
223 const struct ndr_interface_table
*table
,
227 const struct ndr_interface_call
*call
;
228 struct ndr_pull
*pull
;
229 enum ndr_err_code ndr_err
;
231 if (!ndr_syntax_id_equal(&table
->syntax_id
, &cli
->abstract_syntax
) ||
232 (opnum
>= table
->num_calls
)) {
233 return NT_STATUS_INVALID_PARAMETER
;
236 call
= &table
->calls
[opnum
];
238 pull
= ndr_pull_init_blob(&cli
->pipes_struct
->out_data
.rdata
,
241 return NT_STATUS_NO_MEMORY
;
244 /* have the ndr parser alloc memory for us */
245 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
246 ndr_err
= call
->ndr_pull(pull
, NDR_OUT
, r
);
249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
250 return ndr_map_error2ntstatus(ndr_err
);
253 if (DEBUGLEVEL
>= 10) {
254 ndr_print_function_debug(call
->ndr_print
,
255 call
->name
, NDR_OUT
, r
);
261 /****************************************************************************
262 ****************************************************************************/
264 static NTSTATUS
rpc_pipe_internal_dispatch(struct rpc_pipe_client
*cli
,
266 const struct ndr_interface_table
*table
,
267 uint32_t opnum
, void *r
)
270 int num_cmds
= rpc_srv_get_pipe_num_cmds(&table
->syntax_id
);
271 const struct api_struct
*cmds
= rpc_srv_get_pipe_cmds(&table
->syntax_id
);
274 if (cli
->pipes_struct
== NULL
) {
275 return NT_STATUS_INVALID_PARAMETER
;
279 cli
->pipes_struct
->opnum
= opnum
;
281 for (i
= 0; i
< num_cmds
; i
++) {
282 if (cmds
[i
].opnum
== opnum
&& cmds
[i
].fn
!= NULL
) {
288 return NT_STATUS_INVALID_PARAMETER
;
291 status
= internal_ndr_push(mem_ctx
, cli
, table
, opnum
, r
);
292 if (!NT_STATUS_IS_OK(status
)) {
296 if (!cmds
[i
].fn(cli
->pipes_struct
)) {
297 data_blob_free(&cli
->pipes_struct
->in_data
.data
);
298 data_blob_free(&cli
->pipes_struct
->out_data
.rdata
);
299 talloc_free_children(cli
->pipes_struct
->mem_ctx
);
300 return NT_STATUS_UNSUCCESSFUL
;
303 status
= internal_ndr_pull(mem_ctx
, cli
, table
, opnum
, r
);
304 if (!NT_STATUS_IS_OK(status
)) {
305 data_blob_free(&cli
->pipes_struct
->in_data
.data
);
306 data_blob_free(&cli
->pipes_struct
->out_data
.rdata
);
307 talloc_free_children(cli
->pipes_struct
->mem_ctx
);
311 data_blob_free(&cli
->pipes_struct
->in_data
.data
);
312 data_blob_free(&cli
->pipes_struct
->out_data
.rdata
);
313 talloc_free_children(cli
->pipes_struct
->mem_ctx
);
318 static NTSTATUS
rpcint_dispatch(struct pipes_struct
*p
,
321 const DATA_BLOB
*in_data
,
324 uint32_t num_cmds
= rpc_srv_get_pipe_num_cmds(&p
->syntax
);
325 const struct api_struct
*cmds
= rpc_srv_get_pipe_cmds(&p
->syntax
);
332 for (i
= 0; i
< num_cmds
; i
++) {
333 if (cmds
[i
].opnum
== opnum
&& cmds
[i
].fn
!= NULL
) {
339 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
;
342 p
->in_data
.data
= *in_data
;
343 p
->out_data
.rdata
= data_blob_null
;
346 p
->in_data
.data
= data_blob_null
;
348 data_blob_free(&p
->out_data
.rdata
);
349 talloc_free_children(p
->mem_ctx
);
350 return NT_STATUS_RPC_CALL_FAILED
;
353 if (p
->fault_state
) {
354 p
->fault_state
= false;
355 data_blob_free(&p
->out_data
.rdata
);
356 talloc_free_children(p
->mem_ctx
);
357 return NT_STATUS_RPC_CALL_FAILED
;
360 if (p
->bad_handle_fault_state
) {
361 p
->bad_handle_fault_state
= false;
362 data_blob_free(&p
->out_data
.rdata
);
363 talloc_free_children(p
->mem_ctx
);
364 return NT_STATUS_RPC_SS_CONTEXT_MISMATCH
;
367 if (p
->rng_fault_state
) {
368 p
->rng_fault_state
= false;
369 data_blob_free(&p
->out_data
.rdata
);
370 talloc_free_children(p
->mem_ctx
);
371 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
;
374 *out_data
= p
->out_data
.rdata
;
375 talloc_steal(mem_ctx
, out_data
->data
);
376 p
->out_data
.rdata
= data_blob_null
;
378 talloc_free_children(p
->mem_ctx
);
382 struct rpcint_bh_state
{
383 struct pipes_struct
*p
;
386 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle
*h
)
388 struct rpcint_bh_state
*hs
= dcerpc_binding_handle_data(h
,
389 struct rpcint_bh_state
);
398 struct rpcint_bh_raw_call_state
{
404 static struct tevent_req
*rpcint_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
405 struct tevent_context
*ev
,
406 struct dcerpc_binding_handle
*h
,
407 const struct GUID
*object
,
410 const uint8_t *in_data
,
413 struct rpcint_bh_state
*hs
=
414 dcerpc_binding_handle_data(h
,
415 struct rpcint_bh_state
);
416 struct tevent_req
*req
;
417 struct rpcint_bh_raw_call_state
*state
;
421 req
= tevent_req_create(mem_ctx
, &state
,
422 struct rpcint_bh_raw_call_state
);
426 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
427 state
->in_data
.length
= in_length
;
429 ok
= rpcint_bh_is_connected(h
);
431 tevent_req_nterror(req
, NT_STATUS_INVALID_CONNECTION
);
432 return tevent_req_post(req
, ev
);
435 /* TODO: allow async */
436 status
= rpcint_dispatch(hs
->p
, state
, opnum
,
439 if (!NT_STATUS_IS_OK(status
)) {
440 tevent_req_nterror(req
, status
);
441 return tevent_req_post(req
, ev
);
444 tevent_req_done(req
);
445 return tevent_req_post(req
, ev
);
448 static NTSTATUS
rpcint_bh_raw_call_recv(struct tevent_req
*req
,
454 struct rpcint_bh_raw_call_state
*state
=
456 struct rpcint_bh_raw_call_state
);
459 if (tevent_req_is_nterror(req
, &status
)) {
460 tevent_req_received(req
);
464 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
465 *out_length
= state
->out_data
.length
;
467 tevent_req_received(req
);
471 struct rpcint_bh_disconnect_state
{
475 static struct tevent_req
*rpcint_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
476 struct tevent_context
*ev
,
477 struct dcerpc_binding_handle
*h
)
479 struct rpcint_bh_state
*hs
= dcerpc_binding_handle_data(h
,
480 struct rpcint_bh_state
);
481 struct tevent_req
*req
;
482 struct rpcint_bh_disconnect_state
*state
;
485 req
= tevent_req_create(mem_ctx
, &state
,
486 struct rpcint_bh_disconnect_state
);
491 ok
= rpcint_bh_is_connected(h
);
493 tevent_req_nterror(req
, NT_STATUS_INVALID_CONNECTION
);
494 return tevent_req_post(req
, ev
);
498 * TODO: do a real async disconnect ...
500 * For now the caller needs to free pipes_struct
504 tevent_req_done(req
);
505 return tevent_req_post(req
, ev
);
508 static NTSTATUS
rpcint_bh_disconnect_recv(struct tevent_req
*req
)
512 if (tevent_req_is_nterror(req
, &status
)) {
513 tevent_req_received(req
);
517 tevent_req_received(req
);
521 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
526 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle
*h
,
528 const void *_struct_ptr
,
529 const struct ndr_interface_call
*call
)
531 void *struct_ptr
= discard_const(_struct_ptr
);
533 if (DEBUGLEVEL
< 10) {
537 if (ndr_flags
& NDR_IN
) {
538 ndr_print_function_debug(call
->ndr_print
,
543 if (ndr_flags
& NDR_OUT
) {
544 ndr_print_function_debug(call
->ndr_print
,
551 static const struct dcerpc_binding_handle_ops rpcint_bh_ops
= {
553 .is_connected
= rpcint_bh_is_connected
,
554 .raw_call_send
= rpcint_bh_raw_call_send
,
555 .raw_call_recv
= rpcint_bh_raw_call_recv
,
556 .disconnect_send
= rpcint_bh_disconnect_send
,
557 .disconnect_recv
= rpcint_bh_disconnect_recv
,
559 .ref_alloc
= rpcint_bh_ref_alloc
,
560 .do_ndr_print
= rpcint_bh_do_ndr_print
,
563 /* initialise a wbint binding handle */
564 static struct dcerpc_binding_handle
*rpcint_binding_handle(struct pipes_struct
*p
)
566 struct dcerpc_binding_handle
*h
;
567 struct rpcint_bh_state
*hs
;
569 h
= dcerpc_binding_handle_create(p
,
574 struct rpcint_bh_state
,
585 * @brief Create a new RPC client context which uses a local dispatch function.
587 * @param[in] mem_ctx The memory context to use.
589 * @param[in] abstract_syntax Normally the syntax_id of the autogenerated
592 * @param[in] dispatch The corresponding autogenerated dispatch function
593 * rpc_<name>_dispatch.
595 * @param[in] serversupplied_info The server supplied authentication function.
597 * @param[out] presult A pointer to store the connected rpc client pipe.
599 * @return NT_STATUS_OK on success, a corresponding NT status if an
603 * struct rpc_pipe_client *winreg_pipe;
606 * status = rpc_pipe_open_internal(tmp_ctx,
607 * &ndr_table_winreg.syntax_id,
608 * rpc_winreg_dispatch,
613 NTSTATUS
rpc_pipe_open_internal(TALLOC_CTX
*mem_ctx
,
614 const struct ndr_syntax_id
*abstract_syntax
,
615 struct auth_serversupplied_info
*serversupplied_info
,
616 struct messaging_context
*msg_ctx
,
617 struct rpc_pipe_client
**presult
)
619 struct rpc_pipe_client
*result
;
621 result
= TALLOC_ZERO_P(mem_ctx
, struct rpc_pipe_client
);
622 if (result
== NULL
) {
623 return NT_STATUS_NO_MEMORY
;
626 result
->abstract_syntax
= *abstract_syntax
;
627 result
->transfer_syntax
= ndr_transfer_syntax
;
628 result
->dispatch
= rpc_pipe_internal_dispatch
;
630 result
->pipes_struct
= make_internal_rpc_pipe_p(
631 result
, abstract_syntax
, "", serversupplied_info
, msg_ctx
);
632 if (result
->pipes_struct
== NULL
) {
634 return NT_STATUS_NO_MEMORY
;
637 result
->max_xmit_frag
= -1;
638 result
->max_recv_frag
= -1;
640 result
->binding_handle
= rpcint_binding_handle(result
->pipes_struct
);
641 if (result
->binding_handle
== NULL
) {
643 return NT_STATUS_NO_MEMORY
;