build: Do not recurse on symlinks to directories when building tarballs
[Samba.git] / source3 / winbindd / winbindd_dual_ndr.c
blob00c7df1f863f6c956ab6f66274d93ba7ca0dc3f2
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_winbind.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 DBG_DEBUG("Got opnum %"PRIu32" for domain %s from cache\n",
107 state->opnum, state->domain->name);
108 tevent_req_done(req);
109 return tevent_req_post(req, ev);
112 state->request.cmd = WINBINDD_DUAL_NDRCMD;
113 state->request.data.ndrcmd = state->opnum;
114 state->request.extra_data.data = (char *)state->in_data.data;
115 state->request.extra_len = state->in_data.length;
117 subreq = wb_child_request_send(state, ev, hs->child,
118 &state->request);
119 if (tevent_req_nomem(subreq, req)) {
120 return tevent_req_post(req, ev);
122 tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
124 return req;
127 static void wbint_bh_raw_call_done(struct tevent_req *subreq)
129 struct tevent_req *req =
130 tevent_req_callback_data(subreq,
131 struct tevent_req);
132 struct wbint_bh_raw_call_state *state =
133 tevent_req_data(req,
134 struct wbint_bh_raw_call_state);
135 int ret, err;
137 ret = wb_child_request_recv(subreq, state, &state->response, &err);
138 TALLOC_FREE(subreq);
139 if (ret == -1) {
140 NTSTATUS status = map_nt_error_from_unix(err);
141 tevent_req_nterror(req, status);
142 return;
145 state->out_data = data_blob_talloc(state,
146 state->response->extra_data.data,
147 state->response->length - sizeof(struct winbindd_response));
148 if (state->response->extra_data.data && !state->out_data.data) {
149 tevent_req_oom(req);
150 return;
153 if (state->domain != NULL) {
154 wcache_store_ndr(state->domain, state->opnum,
155 &state->in_data, &state->out_data);
158 tevent_req_done(req);
161 static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req,
162 TALLOC_CTX *mem_ctx,
163 uint8_t **out_data,
164 size_t *out_length,
165 uint32_t *out_flags)
167 struct wbint_bh_raw_call_state *state =
168 tevent_req_data(req,
169 struct wbint_bh_raw_call_state);
170 NTSTATUS status;
172 if (tevent_req_is_nterror(req, &status)) {
173 tevent_req_received(req);
174 return status;
177 *out_data = talloc_move(mem_ctx, &state->out_data.data);
178 *out_length = state->out_data.length;
179 *out_flags = 0;
180 tevent_req_received(req);
181 return NT_STATUS_OK;
184 struct wbint_bh_disconnect_state {
185 uint8_t _dummy;
188 static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
189 struct tevent_context *ev,
190 struct dcerpc_binding_handle *h)
192 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
193 struct wbint_bh_state);
194 struct tevent_req *req;
195 struct wbint_bh_disconnect_state *state;
196 bool ok;
198 req = tevent_req_create(mem_ctx, &state,
199 struct wbint_bh_disconnect_state);
200 if (req == NULL) {
201 return NULL;
204 ok = wbint_bh_is_connected(h);
205 if (!ok) {
206 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
207 return tevent_req_post(req, ev);
211 * TODO: do a real async disconnect ...
213 * For now the caller needs to free rpc_cli
215 hs->child = NULL;
217 tevent_req_done(req);
218 return tevent_req_post(req, ev);
221 static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
223 NTSTATUS status;
225 if (tevent_req_is_nterror(req, &status)) {
226 tevent_req_received(req);
227 return status;
230 tevent_req_received(req);
231 return NT_STATUS_OK;
234 static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
236 return true;
239 static void wbint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
240 int ndr_flags,
241 const void *_struct_ptr,
242 const struct ndr_interface_call *call)
244 void *struct_ptr = discard_const(_struct_ptr);
246 if (DEBUGLEVEL < 10) {
247 return;
250 if (ndr_flags & NDR_IN) {
251 ndr_print_function_debug(call->ndr_print,
252 call->name,
253 ndr_flags,
254 struct_ptr);
256 if (ndr_flags & NDR_OUT) {
257 ndr_print_function_debug(call->ndr_print,
258 call->name,
259 ndr_flags,
260 struct_ptr);
264 static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
265 .name = "wbint",
266 .is_connected = wbint_bh_is_connected,
267 .set_timeout = wbint_bh_set_timeout,
268 .raw_call_send = wbint_bh_raw_call_send,
269 .raw_call_recv = wbint_bh_raw_call_recv,
270 .disconnect_send = wbint_bh_disconnect_send,
271 .disconnect_recv = wbint_bh_disconnect_recv,
273 .ref_alloc = wbint_bh_ref_alloc,
274 .do_ndr_print = wbint_bh_do_ndr_print,
277 /* initialise a wbint binding handle */
278 struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
279 struct winbindd_domain *domain,
280 struct winbindd_child *child)
282 struct dcerpc_binding_handle *h;
283 struct wbint_bh_state *hs;
285 h = dcerpc_binding_handle_create(mem_ctx,
286 &wbint_bh_ops,
287 NULL,
288 &ndr_table_winbind,
289 &hs,
290 struct wbint_bh_state,
291 __location__);
292 if (h == NULL) {
293 return NULL;
295 hs->domain = domain;
296 hs->child = child;
298 return h;
301 enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
302 struct winbindd_cli_state *state)
304 struct pipes_struct p;
305 const struct api_struct *fns;
306 int num_fns;
307 bool ret;
309 fns = winbind_get_pipe_fns(&num_fns);
311 if (state->request->data.ndrcmd >= num_fns) {
312 return WINBINDD_ERROR;
315 DEBUG(10, ("winbindd_dual_ndrcmd: Running command %s (%s)\n",
316 fns[state->request->data.ndrcmd].name,
317 domain ? domain->name : "no domain"));
319 ZERO_STRUCT(p);
320 p.mem_ctx = talloc_stackframe();
321 p.in_data.data = data_blob_const(state->request->extra_data.data,
322 state->request->extra_len);
324 ret = fns[state->request->data.ndrcmd].fn(&p);
325 if (!ret) {
326 TALLOC_FREE(p.mem_ctx);
327 return WINBINDD_ERROR;
330 state->response->extra_data.data =
331 talloc_move(state->mem_ctx, &p.out_data.rdata.data);
332 state->response->length += p.out_data.rdata.length;
333 p.out_data.rdata.length = 0;
335 TALLOC_FREE(p.mem_ctx);
337 if (state->response->extra_data.data == NULL) {
338 return WINBINDD_ERROR;
340 return WINBINDD_OK;