Fix bug #8807 - dcerpc_lsa_lookup_sids_noalloc() crashes when groups has more than...
[Samba/gebeck_regimport.git] / source3 / winbindd / winbindd_dual_ndr.c
blobf3611be786377abe623c5192b9a8aa4a77b27d67
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 "ntdomain.h"
33 #include "librpc/gen_ndr/srv_wbint.h"
35 struct wbint_bh_state {
36 struct winbindd_domain *domain;
37 struct winbindd_child *child;
40 static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
42 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
43 struct wbint_bh_state);
45 if (!hs->child) {
46 return false;
49 return true;
52 static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
53 uint32_t timeout)
55 /* TODO: implement timeouts */
56 return UINT32_MAX;
59 struct wbint_bh_raw_call_state {
60 struct winbindd_domain *domain;
61 uint32_t opnum;
62 DATA_BLOB in_data;
63 struct winbindd_request request;
64 struct winbindd_response *response;
65 DATA_BLOB out_data;
68 static void wbint_bh_raw_call_done(struct tevent_req *subreq);
70 static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
71 struct tevent_context *ev,
72 struct dcerpc_binding_handle *h,
73 const struct GUID *object,
74 uint32_t opnum,
75 uint32_t in_flags,
76 const uint8_t *in_data,
77 size_t in_length)
79 struct wbint_bh_state *hs =
80 dcerpc_binding_handle_data(h,
81 struct wbint_bh_state);
82 struct tevent_req *req;
83 struct wbint_bh_raw_call_state *state;
84 bool ok;
85 struct tevent_req *subreq;
87 req = tevent_req_create(mem_ctx, &state,
88 struct wbint_bh_raw_call_state);
89 if (req == NULL) {
90 return NULL;
92 state->domain = hs->domain;
93 state->opnum = opnum;
94 state->in_data.data = discard_const_p(uint8_t, in_data);
95 state->in_data.length = in_length;
97 ok = wbint_bh_is_connected(h);
98 if (!ok) {
99 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
100 return tevent_req_post(req, ev);
103 if ((state->domain != NULL)
104 && wcache_fetch_ndr(state, state->domain, state->opnum,
105 &state->in_data, &state->out_data)) {
106 tevent_req_done(req);
107 return tevent_req_post(req, ev);
110 state->request.cmd = WINBINDD_DUAL_NDRCMD;
111 state->request.data.ndrcmd = state->opnum;
112 state->request.extra_data.data = (char *)state->in_data.data;
113 state->request.extra_len = state->in_data.length;
115 subreq = wb_child_request_send(state, ev, hs->child,
116 &state->request);
117 if (tevent_req_nomem(subreq, req)) {
118 return tevent_req_post(req, ev);
120 tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
122 return req;
125 static void wbint_bh_raw_call_done(struct tevent_req *subreq)
127 struct tevent_req *req =
128 tevent_req_callback_data(subreq,
129 struct tevent_req);
130 struct wbint_bh_raw_call_state *state =
131 tevent_req_data(req,
132 struct wbint_bh_raw_call_state);
133 int ret, err;
135 ret = wb_child_request_recv(subreq, state, &state->response, &err);
136 TALLOC_FREE(subreq);
137 if (ret == -1) {
138 NTSTATUS status = map_nt_error_from_unix(err);
139 tevent_req_nterror(req, status);
140 return;
143 state->out_data = data_blob_talloc(state,
144 state->response->extra_data.data,
145 state->response->length - sizeof(struct winbindd_response));
146 if (state->response->extra_data.data && !state->out_data.data) {
147 tevent_req_oom(req);
148 return;
151 if (state->domain != NULL) {
152 wcache_store_ndr(state->domain, state->opnum,
153 &state->in_data, &state->out_data);
156 tevent_req_done(req);
159 static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
160 TALLOC_CTX *mem_ctx,
161 uint8_t **out_data,
162 size_t *out_length,
163 uint32_t *out_flags)
165 struct wbint_bh_raw_call_state *state =
166 tevent_req_data(req,
167 struct wbint_bh_raw_call_state);
168 NTSTATUS status;
170 if (tevent_req_is_nterror(req, &status)) {
171 tevent_req_received(req);
172 return status;
175 *out_data = talloc_move(mem_ctx, &state->out_data.data);
176 *out_length = state->out_data.length;
177 *out_flags = 0;
178 tevent_req_received(req);
179 return NT_STATUS_OK;
182 struct wbint_bh_disconnect_state {
183 uint8_t _dummy;
186 static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
187 struct tevent_context *ev,
188 struct dcerpc_binding_handle *h)
190 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
191 struct wbint_bh_state);
192 struct tevent_req *req;
193 struct wbint_bh_disconnect_state *state;
194 bool ok;
196 req = tevent_req_create(mem_ctx, &state,
197 struct wbint_bh_disconnect_state);
198 if (req == NULL) {
199 return NULL;
202 ok = wbint_bh_is_connected(h);
203 if (!ok) {
204 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
205 return tevent_req_post(req, ev);
209 * TODO: do a real async disconnect ...
211 * For now the caller needs to free rpc_cli
213 hs->child = NULL;
215 tevent_req_done(req);
216 return tevent_req_post(req, ev);
219 static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
221 NTSTATUS status;
223 if (tevent_req_is_nterror(req, &status)) {
224 tevent_req_received(req);
225 return status;
228 tevent_req_received(req);
229 return NT_STATUS_OK;
232 static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
234 return true;
237 static void wbint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
238 int ndr_flags,
239 const void *_struct_ptr,
240 const struct ndr_interface_call *call)
242 void *struct_ptr = discard_const(_struct_ptr);
244 if (DEBUGLEVEL < 10) {
245 return;
248 if (ndr_flags & NDR_IN) {
249 ndr_print_function_debug(call->ndr_print,
250 call->name,
251 ndr_flags,
252 struct_ptr);
254 if (ndr_flags & NDR_OUT) {
255 ndr_print_function_debug(call->ndr_print,
256 call->name,
257 ndr_flags,
258 struct_ptr);
262 static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
263 .name = "wbint",
264 .is_connected = wbint_bh_is_connected,
265 .set_timeout = wbint_bh_set_timeout,
266 .raw_call_send = wbint_bh_raw_call_send,
267 .raw_call_recv = wbint_bh_raw_call_recv,
268 .disconnect_send = wbint_bh_disconnect_send,
269 .disconnect_recv = wbint_bh_disconnect_recv,
271 .ref_alloc = wbint_bh_ref_alloc,
272 .do_ndr_print = wbint_bh_do_ndr_print,
275 /* initialise a wbint binding handle */
276 struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
277 struct winbindd_domain *domain,
278 struct winbindd_child *child)
280 struct dcerpc_binding_handle *h;
281 struct wbint_bh_state *hs;
283 h = dcerpc_binding_handle_create(mem_ctx,
284 &wbint_bh_ops,
285 NULL,
286 &ndr_table_wbint,
287 &hs,
288 struct wbint_bh_state,
289 __location__);
290 if (h == NULL) {
291 return NULL;
293 hs->domain = domain;
294 hs->child = child;
296 return h;
299 enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
300 struct winbindd_cli_state *state)
302 struct pipes_struct p;
303 struct api_struct *fns;
304 int num_fns;
305 bool ret;
307 wbint_get_pipe_fns(&fns, &num_fns);
309 if (state->request->data.ndrcmd >= num_fns) {
310 return WINBINDD_ERROR;
313 DEBUG(10, ("winbindd_dual_ndrcmd: Running command %s (%s)\n",
314 fns[state->request->data.ndrcmd].name,
315 domain ? domain->name : "no domain"));
317 ZERO_STRUCT(p);
318 p.mem_ctx = talloc_stackframe();
319 p.in_data.data = data_blob_const(state->request->extra_data.data,
320 state->request->extra_len);
322 ret = fns[state->request->data.ndrcmd].fn(&p);
323 if (!ret) {
324 TALLOC_FREE(p.mem_ctx);
325 return WINBINDD_ERROR;
328 state->response->extra_data.data =
329 talloc_move(state->mem_ctx, &p.out_data.rdata.data);
330 state->response->length += p.out_data.rdata.length;
331 p.out_data.rdata.length = 0;
333 TALLOC_FREE(p.mem_ctx);
335 if (state->response->extra_data.data == NULL) {
336 return WINBINDD_ERROR;
338 return WINBINDD_OK;