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"
33 #include "librpc/rpc/dcesrv_core.h"
34 #include "librpc/gen_ndr/ndr_winbind.h"
36 struct wbint_bh_state {
37 struct winbindd_domain *domain;
38 struct winbindd_child *child;
41 static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
43 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
44 struct wbint_bh_state);
46 if ((hs->domain == NULL) && (hs->child == NULL)) {
53 static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
56 /* TODO: implement timeouts */
60 struct wbint_bh_raw_call_state {
61 struct winbindd_domain *domain;
64 struct winbindd_request request;
65 struct winbindd_response *response;
69 static void wbint_bh_raw_call_child_done(struct tevent_req *subreq);
70 static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq);
72 static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
73 struct tevent_context *ev,
74 struct dcerpc_binding_handle *h,
75 const struct GUID *object,
78 const uint8_t *in_data,
81 struct wbint_bh_state *hs =
82 dcerpc_binding_handle_data(h,
83 struct wbint_bh_state);
84 struct tevent_req *req;
85 struct wbint_bh_raw_call_state *state;
87 struct tevent_req *subreq;
89 req = tevent_req_create(mem_ctx, &state,
90 struct wbint_bh_raw_call_state);
94 state->domain = hs->domain;
96 state->in_data.data = discard_const_p(uint8_t, in_data);
97 state->in_data.length = in_length;
99 ok = wbint_bh_is_connected(h);
101 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
102 return tevent_req_post(req, ev);
105 if ((state->domain != NULL)
106 && wcache_fetch_ndr(state, state->domain, state->opnum,
107 &state->in_data, &state->out_data)) {
108 DBG_DEBUG("Got opnum %"PRIu32" for domain %s from cache\n",
109 state->opnum, state->domain->name);
110 tevent_req_done(req);
111 return tevent_req_post(req, ev);
114 state->request.cmd = WINBINDD_DUAL_NDRCMD;
115 state->request.data.ndrcmd = state->opnum;
116 state->request.extra_data.data = (char *)state->in_data.data;
117 state->request.extra_len = state->in_data.length;
119 if (hs->child != NULL) {
120 subreq = wb_child_request_send(state, ev, hs->child,
122 if (tevent_req_nomem(subreq, req)) {
123 return tevent_req_post(req, ev);
125 tevent_req_set_callback(
126 subreq, wbint_bh_raw_call_child_done, req);
130 subreq = wb_domain_request_send(state, ev, hs->domain,
132 if (tevent_req_nomem(subreq, req)) {
133 return tevent_req_post(req, ev);
135 tevent_req_set_callback(subreq, wbint_bh_raw_call_domain_done, req);
140 static void wbint_bh_raw_call_child_done(struct tevent_req *subreq)
142 struct tevent_req *req =
143 tevent_req_callback_data(subreq,
145 struct wbint_bh_raw_call_state *state =
147 struct wbint_bh_raw_call_state);
150 ret = wb_child_request_recv(subreq, state, &state->response, &err);
153 NTSTATUS status = map_nt_error_from_unix(err);
154 tevent_req_nterror(req, status);
158 state->out_data = data_blob_talloc(state,
159 state->response->extra_data.data,
160 state->response->length - sizeof(struct winbindd_response));
161 if (state->response->extra_data.data && !state->out_data.data) {
166 if (state->domain != NULL) {
167 wcache_store_ndr(state->domain, state->opnum,
168 &state->in_data, &state->out_data);
171 tevent_req_done(req);
174 static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq)
176 struct tevent_req *req =
177 tevent_req_callback_data(subreq,
179 struct wbint_bh_raw_call_state *state =
181 struct wbint_bh_raw_call_state);
184 ret = wb_domain_request_recv(subreq, state, &state->response, &err);
187 NTSTATUS status = map_nt_error_from_unix(err);
188 tevent_req_nterror(req, status);
192 state->out_data = data_blob_talloc(state,
193 state->response->extra_data.data,
194 state->response->length - sizeof(struct winbindd_response));
195 if (state->response->extra_data.data && !state->out_data.data) {
200 if (state->domain != NULL) {
201 wcache_store_ndr(state->domain, state->opnum,
202 &state->in_data, &state->out_data);
205 tevent_req_done(req);
208 static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
214 struct wbint_bh_raw_call_state *state =
216 struct wbint_bh_raw_call_state);
219 if (tevent_req_is_nterror(req, &status)) {
220 tevent_req_received(req);
224 *out_data = talloc_move(mem_ctx, &state->out_data.data);
225 *out_length = state->out_data.length;
227 tevent_req_received(req);
231 struct wbint_bh_disconnect_state {
235 static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
236 struct tevent_context *ev,
237 struct dcerpc_binding_handle *h)
239 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
240 struct wbint_bh_state);
241 struct tevent_req *req;
242 struct wbint_bh_disconnect_state *state;
245 req = tevent_req_create(mem_ctx, &state,
246 struct wbint_bh_disconnect_state);
251 ok = wbint_bh_is_connected(h);
253 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
254 return tevent_req_post(req, ev);
258 * TODO: do a real async disconnect ...
263 tevent_req_done(req);
264 return tevent_req_post(req, ev);
267 static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
271 if (tevent_req_is_nterror(req, &status)) {
272 tevent_req_received(req);
276 tevent_req_received(req);
280 static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
285 static void wbint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
287 const void *_struct_ptr,
288 const struct ndr_interface_call *call)
290 void *struct_ptr = discard_const(_struct_ptr);
292 if (DEBUGLEVEL < 10) {
296 if (ndr_flags & NDR_IN) {
297 ndr_print_function_debug(call->ndr_print,
302 if (ndr_flags & NDR_OUT) {
303 ndr_print_function_debug(call->ndr_print,
310 static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
312 .is_connected = wbint_bh_is_connected,
313 .set_timeout = wbint_bh_set_timeout,
314 .raw_call_send = wbint_bh_raw_call_send,
315 .raw_call_recv = wbint_bh_raw_call_recv,
316 .disconnect_send = wbint_bh_disconnect_send,
317 .disconnect_recv = wbint_bh_disconnect_recv,
319 .ref_alloc = wbint_bh_ref_alloc,
320 .do_ndr_print = wbint_bh_do_ndr_print,
323 /* initialise a wbint binding handle */
324 struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
325 struct winbindd_domain *domain,
326 struct winbindd_child *child)
328 struct dcerpc_binding_handle *h;
329 struct wbint_bh_state *hs;
331 h = dcerpc_binding_handle_create(mem_ctx,
336 struct wbint_bh_state,
347 enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
348 struct winbindd_cli_state *state)
350 const struct dcesrv_endpoint_server *ep_server = NULL;
351 struct dcesrv_interface iface;
352 const struct ndr_syntax_id *abstract_syntax;
354 uint32_t opnum = state->request->data.ndrcmd;
355 struct pipes_struct *p;
361 DBG_DEBUG("Running command %s (domain '%s')\n",
362 ndr_table_winbind.calls[opnum].name,
363 domain ? domain->name : "(null)");
365 ep_server = dcesrv_ep_server_byname(ndr_table_winbind.name);
366 if (ep_server == NULL) {
367 DBG_ERR("Failed to get DCE/RPC endpoint server '%s'\n",
368 ndr_table_winbind.name);
369 return WINBINDD_ERROR;
372 abstract_syntax = &ndr_table_winbind.syntax_id;
373 ok = ep_server->interface_by_uuid(&iface, &abstract_syntax->uuid,
374 abstract_syntax->if_version);
376 DBG_ERR("Failed to get DCE/RPC interface\n");
377 return WINBINDD_ERROR;
380 mem_ctx = talloc_stackframe();
381 if (mem_ctx == NULL) {
382 DBG_ERR("No memory");
383 return WINBINDD_ERROR;
386 p = talloc_zero(mem_ctx, struct pipes_struct);
388 DBG_ERR("No memory\n");
389 return WINBINDD_ERROR;
391 p->mem_ctx = mem_ctx;
393 in = data_blob_const(state->request->extra_data.data,
394 state->request->extra_len);
396 status = iface.local(p, opnum, mem_ctx, &in, &out);
397 if (!NT_STATUS_IS_OK(status)) {
398 TALLOC_FREE(mem_ctx);
399 return WINBINDD_ERROR;
402 state->response->extra_data.data =
403 talloc_steal(state->mem_ctx, out.data);
404 state->response->length += out.length;
406 TALLOC_FREE(mem_ctx);
408 if (state->response->extra_data.data == NULL) {
409 return WINBINDD_ERROR;