selftest split $PERL into multiple arguments for Test::More check
[Samba.git] / source3 / winbindd / winbindd_dual_ndr.c
blobe400b6110d4e73f98924f196c94aeebec32f7f99
1 /*
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.
29 #include "includes.h"
30 #include "winbindd/winbindd.h"
31 #include "winbindd/winbindd_proto.h"
32 #include "librpc/gen_ndr/srv_wbint.h"
34 struct wbint_bh_state {
35 struct winbindd_domain *domain;
36 struct winbindd_child *child;
39 static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
41 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
42 struct wbint_bh_state);
44 if (!hs->child) {
45 return false;
48 return true;
51 static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
52 uint32_t timeout)
54 /* TODO: implement timeouts */
55 return UINT32_MAX;
58 struct wbint_bh_raw_call_state {
59 struct winbindd_domain *domain;
60 uint32_t opnum;
61 DATA_BLOB in_data;
62 struct winbindd_request request;
63 struct winbindd_response *response;
64 DATA_BLOB out_data;
67 static void wbint_bh_raw_call_done(struct tevent_req *subreq);
69 static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
70 struct tevent_context *ev,
71 struct dcerpc_binding_handle *h,
72 const struct GUID *object,
73 uint32_t opnum,
74 uint32_t in_flags,
75 const uint8_t *in_data,
76 size_t in_length)
78 struct wbint_bh_state *hs =
79 dcerpc_binding_handle_data(h,
80 struct wbint_bh_state);
81 struct tevent_req *req;
82 struct wbint_bh_raw_call_state *state;
83 bool ok;
84 struct tevent_req *subreq;
86 req = tevent_req_create(mem_ctx, &state,
87 struct wbint_bh_raw_call_state);
88 if (req == NULL) {
89 return NULL;
91 state->domain = hs->domain;
92 state->opnum = opnum;
93 state->in_data.data = discard_const_p(uint8_t, in_data);
94 state->in_data.length = in_length;
96 ok = wbint_bh_is_connected(h);
97 if (!ok) {
98 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
99 return tevent_req_post(req, ev);
102 if ((state->domain != NULL)
103 && wcache_fetch_ndr(state, state->domain, state->opnum,
104 &state->in_data, &state->out_data)) {
105 tevent_req_done(req);
106 return tevent_req_post(req, ev);
109 state->request.cmd = WINBINDD_DUAL_NDRCMD;
110 state->request.data.ndrcmd = state->opnum;
111 state->request.extra_data.data = (char *)state->in_data.data;
112 state->request.extra_len = state->in_data.length;
114 subreq = wb_child_request_send(state, ev, hs->child,
115 &state->request);
116 if (tevent_req_nomem(subreq, req)) {
117 return tevent_req_post(req, ev);
119 tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
121 return req;
124 static void wbint_bh_raw_call_done(struct tevent_req *subreq)
126 struct tevent_req *req =
127 tevent_req_callback_data(subreq,
128 struct tevent_req);
129 struct wbint_bh_raw_call_state *state =
130 tevent_req_data(req,
131 struct wbint_bh_raw_call_state);
132 int ret, err;
134 ret = wb_child_request_recv(subreq, state, &state->response, &err);
135 TALLOC_FREE(subreq);
136 if (ret == -1) {
137 NTSTATUS status = map_nt_error_from_unix(err);
138 tevent_req_nterror(req, status);
139 return;
142 state->out_data = data_blob_talloc(state,
143 state->response->extra_data.data,
144 state->response->length - sizeof(struct winbindd_response));
145 if (state->response->extra_data.data && !state->out_data.data) {
146 tevent_req_nomem(NULL, req);
147 return;
150 if (state->domain != NULL) {
151 wcache_store_ndr(state->domain, state->opnum,
152 &state->in_data, &state->out_data);
155 tevent_req_done(req);
158 static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
159 TALLOC_CTX *mem_ctx,
160 uint8_t **out_data,
161 size_t *out_length,
162 uint32_t *out_flags)
164 struct wbint_bh_raw_call_state *state =
165 tevent_req_data(req,
166 struct wbint_bh_raw_call_state);
167 NTSTATUS status;
169 if (tevent_req_is_nterror(req, &status)) {
170 tevent_req_received(req);
171 return status;
174 *out_data = talloc_move(mem_ctx, &state->out_data.data);
175 *out_length = state->out_data.length;
176 *out_flags = 0;
177 tevent_req_received(req);
178 return NT_STATUS_OK;
181 struct wbint_bh_disconnect_state {
182 uint8_t _dummy;
185 static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
186 struct tevent_context *ev,
187 struct dcerpc_binding_handle *h)
189 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
190 struct wbint_bh_state);
191 struct tevent_req *req;
192 struct wbint_bh_disconnect_state *state;
193 bool ok;
195 req = tevent_req_create(mem_ctx, &state,
196 struct wbint_bh_disconnect_state);
197 if (req == NULL) {
198 return NULL;
201 ok = wbint_bh_is_connected(h);
202 if (!ok) {
203 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
204 return tevent_req_post(req, ev);
208 * TODO: do a real async disconnect ...
210 * For now the caller needs to free rpc_cli
212 hs->child = NULL;
214 tevent_req_done(req);
215 return tevent_req_post(req, ev);
218 static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
220 NTSTATUS status;
222 if (tevent_req_is_nterror(req, &status)) {
223 tevent_req_received(req);
224 return status;
227 tevent_req_received(req);
228 return NT_STATUS_OK;
231 static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
233 return true;
236 static void wbint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
237 int ndr_flags,
238 const void *_struct_ptr,
239 const struct ndr_interface_call *call)
241 void *struct_ptr = discard_const(_struct_ptr);
243 if (DEBUGLEVEL < 10) {
244 return;
247 if (ndr_flags & NDR_IN) {
248 ndr_print_function_debug(call->ndr_print,
249 call->name,
250 ndr_flags,
251 struct_ptr);
253 if (ndr_flags & NDR_OUT) {
254 ndr_print_function_debug(call->ndr_print,
255 call->name,
256 ndr_flags,
257 struct_ptr);
261 static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
262 .name = "wbint",
263 .is_connected = wbint_bh_is_connected,
264 .set_timeout = wbint_bh_set_timeout,
265 .raw_call_send = wbint_bh_raw_call_send,
266 .raw_call_recv = wbint_bh_raw_call_recv,
267 .disconnect_send = wbint_bh_disconnect_send,
268 .disconnect_recv = wbint_bh_disconnect_recv,
270 .ref_alloc = wbint_bh_ref_alloc,
271 .do_ndr_print = wbint_bh_do_ndr_print,
274 /* initialise a wbint binding handle */
275 struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
276 struct winbindd_domain *domain,
277 struct winbindd_child *child)
279 struct dcerpc_binding_handle *h;
280 struct wbint_bh_state *hs;
282 h = dcerpc_binding_handle_create(mem_ctx,
283 &wbint_bh_ops,
284 NULL,
285 &ndr_table_wbint,
286 &hs,
287 struct wbint_bh_state,
288 __location__);
289 if (h == NULL) {
290 return NULL;
292 hs->domain = domain;
293 hs->child = child;
295 return h;
298 enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
299 struct winbindd_cli_state *state)
301 struct pipes_struct p;
302 struct api_struct *fns;
303 int num_fns;
304 bool ret;
306 wbint_get_pipe_fns(&fns, &num_fns);
308 if (state->request->data.ndrcmd >= num_fns) {
309 return WINBINDD_ERROR;
312 DEBUG(10, ("winbindd_dual_ndrcmd: Running command %s (%s)\n",
313 fns[state->request->data.ndrcmd].name,
314 domain ? domain->name : "no domain"));
316 ZERO_STRUCT(p);
317 p.mem_ctx = talloc_stackframe();
318 p.in_data.data = data_blob_const(state->request->extra_data.data,
319 state->request->extra_len);
321 ret = fns[state->request->data.ndrcmd].fn(&p);
322 if (!ret) {
323 TALLOC_FREE(p.mem_ctx);
324 return WINBINDD_ERROR;
327 state->response->extra_data.data =
328 talloc_move(state->mem_ctx, &p.out_data.rdata.data);
329 state->response->length += p.out_data.rdata.length;
330 p.out_data.rdata.length = 0;
332 TALLOC_FREE(p.mem_ctx);
334 if (state->response->extra_data.data == NULL) {
335 return WINBINDD_ERROR;
337 return WINBINDD_OK;