2 Unix SMB/CIFS implementation.
4 Provide parent->child communication based on NDR marshalling
6 Copyright (C) Volker Lendecke 2009
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 * This file implements an RPC between winbind parent and child processes,
24 * leveraging the autogenerated marshalling routines for MSRPC. This is not
25 * MSRPC, as it does not go through the whole DCERPC fragmentation, we just
26 * leverage much the same infrastructure we already have for it.
30 #include "winbindd/winbindd.h"
31 #include "winbindd/winbindd_proto.h"
32 #include "librpc/gen_ndr/srv_wbint.h"
34 struct wb_ndr_transport_priv
{
35 struct winbindd_child
*child
;
38 struct wb_ndr_dispatch_state
{
39 const struct ndr_interface_call
*call
;
41 struct ndr_push
*push
;
42 struct winbindd_request request
;
43 struct winbindd_response
*response
;
46 static void wb_ndr_dispatch_done(struct tevent_req
*subreq
);
48 static struct tevent_req
*wb_ndr_dispatch_send(TALLOC_CTX
*mem_ctx
,
49 struct tevent_context
*ev
,
50 struct rpc_pipe_client
*cli
,
51 const struct ndr_interface_table
*table
,
55 struct tevent_req
*req
, *subreq
;
56 struct wb_ndr_dispatch_state
*state
;
57 struct wb_ndr_transport_priv
*transport
= talloc_get_type_abort(
58 cli
->transport
->priv
, struct wb_ndr_transport_priv
);
60 enum ndr_err_code ndr_err
;
62 req
= tevent_req_create(mem_ctx
, &state
,
63 struct wb_ndr_dispatch_state
);
69 state
->call
= &table
->calls
[opnum
];
71 state
->push
= ndr_push_init_ctx(state
, NULL
);
72 if (tevent_req_nomem(state
->push
, req
)) {
73 return tevent_req_post(req
, ev
);
76 ndr_err
= state
->call
->ndr_push(state
->push
, NDR_IN
, r
);
77 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
78 tevent_req_nterror(req
, ndr_map_error2ntstatus(ndr_err
));
79 TALLOC_FREE(state
->push
);
80 return tevent_req_post(req
, ev
);
83 blob
= ndr_push_blob(state
->push
);
85 state
->request
.cmd
= WINBINDD_DUAL_NDRCMD
;
86 state
->request
.data
.ndrcmd
= opnum
;
87 state
->request
.extra_data
.data
= (char *)blob
.data
;
88 state
->request
.extra_len
= blob
.length
;
90 subreq
= wb_child_request_send(state
, ev
, transport
->child
,
92 if (tevent_req_nomem(subreq
, req
)) {
93 return tevent_req_post(req
, ev
);
95 tevent_req_set_callback(subreq
, wb_ndr_dispatch_done
, req
);
99 static void wb_ndr_dispatch_done(struct tevent_req
*subreq
)
101 struct tevent_req
*req
= tevent_req_callback_data(
102 subreq
, struct tevent_req
);
103 struct wb_ndr_dispatch_state
*state
= tevent_req_data(
104 req
, struct wb_ndr_dispatch_state
);
107 ret
= wb_child_request_recv(subreq
, state
, &state
->response
, &err
);
110 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
113 tevent_req_done(req
);
116 static NTSTATUS
wb_ndr_dispatch_recv(struct tevent_req
*req
,
119 struct wb_ndr_dispatch_state
*state
= tevent_req_data(
120 req
, struct wb_ndr_dispatch_state
);
122 struct ndr_pull
*pull
;
123 enum ndr_err_code ndr_err
;
126 if (tevent_req_is_nterror(req
, &status
)) {
130 blob
.data
= (uint8_t *)state
->response
->extra_data
.data
;
131 blob
.length
= state
->response
->length
132 - sizeof(struct winbindd_response
);
134 pull
= ndr_pull_init_blob(&blob
, mem_ctx
, NULL
);
136 return NT_STATUS_NO_MEMORY
;
139 /* have the ndr parser alloc memory for us */
140 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
141 ndr_err
= state
->call
->ndr_pull(pull
, NDR_OUT
, state
->r
);
144 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
145 return ndr_map_error2ntstatus(ndr_err
);
151 static NTSTATUS
wb_ndr_dispatch(struct rpc_pipe_client
*cli
,
153 const struct ndr_interface_table
*table
,
154 uint32_t opnum
, void *r
)
156 TALLOC_CTX
*frame
= talloc_stackframe();
157 struct event_context
*ev
;
158 struct tevent_req
*req
;
159 NTSTATUS status
= NT_STATUS_OK
;
161 ev
= event_context_init(frame
);
163 status
= NT_STATUS_NO_MEMORY
;
167 req
= wb_ndr_dispatch_send(frame
, ev
, cli
, table
, opnum
, r
);
169 status
= NT_STATUS_NO_MEMORY
;
173 if (!tevent_req_poll(req
, ev
)) {
174 status
= map_nt_error_from_unix(errno
);
178 status
= wb_ndr_dispatch_recv(req
, mem_ctx
);
184 struct rpc_pipe_client
*wbint_rpccli_create(TALLOC_CTX
*mem_ctx
,
185 struct winbindd_child
*child
)
187 struct rpc_pipe_client
*result
;
188 struct wb_ndr_transport_priv
*transp
;
190 result
= talloc(mem_ctx
, struct rpc_pipe_client
);
191 if (result
== NULL
) {
194 result
->abstract_syntax
= ndr_table_wbint
.syntax_id
;
195 result
->transfer_syntax
= ndr_transfer_syntax
;
196 result
->dispatch
= wb_ndr_dispatch
;
197 result
->dispatch_send
= wb_ndr_dispatch_send
;
198 result
->dispatch_recv
= wb_ndr_dispatch_recv
;
199 result
->max_xmit_frag
= RPC_MAX_PDU_FRAG_LEN
;
200 result
->max_recv_frag
= RPC_MAX_PDU_FRAG_LEN
;
201 result
->desthost
= NULL
;
202 result
->srv_name_slash
= NULL
;
205 * Initialize a fake transport. Due to our own wb_ndr_dispatch
206 * function we don't use all the fragmentation engine in
207 * cli_pipe, which would use all the _read and _write
208 * functions in rpc_cli_transport. But we need a place to
209 * store the child struct in, and we're re-using
210 * result->transport->priv for that.
213 result
->transport
= talloc_zero(result
, struct rpc_cli_transport
);
214 if (result
->transport
== NULL
) {
218 transp
= talloc(result
->transport
, struct wb_ndr_transport_priv
);
219 if (transp
== NULL
) {
223 transp
->child
= child
;
224 result
->transport
->priv
= transp
;
228 enum winbindd_result
winbindd_dual_ndrcmd(struct winbindd_domain
*domain
,
229 struct winbindd_cli_state
*state
)
232 struct api_struct
*fns
;
236 wbint_get_pipe_fns(&fns
, &num_fns
);
238 if (state
->request
->data
.ndrcmd
>= num_fns
) {
239 return WINBINDD_ERROR
;
243 p
.mem_ctx
= talloc_stackframe();
244 p
.in_data
.data
.buffer_size
= state
->request
->extra_len
;
245 p
.in_data
.data
.data_p
= state
->request
->extra_data
.data
;
246 prs_init(&p
.out_data
.rdata
, 0, state
->mem_ctx
, false);
248 ret
= fns
[state
->request
->data
.ndrcmd
].fn(&p
);
249 TALLOC_FREE(p
.mem_ctx
);
251 return WINBINDD_ERROR
;
254 state
->response
->extra_data
.data
=
255 talloc_memdup(state
->mem_ctx
, p
.out_data
.rdata
.data_p
,
256 p
.out_data
.rdata
.data_offset
);
257 state
->response
->length
+= p
.out_data
.rdata
.data_offset
;
258 prs_mem_free(&p
.out_data
.rdata
);
259 if (state
->response
->extra_data
.data
== NULL
) {
260 return WINBINDD_ERROR
;
266 * Just a dummy to make srv_wbint.c happy
268 NTSTATUS
rpc_srv_register(int version
, const char *clnt
, const char *srv
,
269 const struct ndr_interface_table
*iface
,
270 const struct api_struct
*cmds
, int size
)