source: trunk/server/source3/winbindd/winbindd_dual_ndr.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 8.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Provide parent->child communication based on NDR marshalling
5
6 Copyright (C) Volker Lendecke 2009
7
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.
12
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.
17
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/>.
20*/
21
22/*
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.
27 */
28
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"
34
35struct wbint_bh_state {
36 struct winbindd_domain *domain;
37 struct winbindd_child *child;
38};
39
40static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h)
41{
42 struct wbint_bh_state *hs = dcerpc_binding_handle_data(h,
43 struct wbint_bh_state);
44
45 if (!hs->child) {
46 return false;
47 }
48
49 return true;
50}
51
52static uint32_t wbint_bh_set_timeout(struct dcerpc_binding_handle *h,
53 uint32_t timeout)
54{
55 /* TODO: implement timeouts */
56 return UINT32_MAX;
57}
58
59struct 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;
66};
67
68static void wbint_bh_raw_call_done(struct tevent_req *subreq);
69
70static 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)
78{
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;
86
87 req = tevent_req_create(mem_ctx, &state,
88 struct wbint_bh_raw_call_state);
89 if (req == NULL) {
90 return NULL;
91 }
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;
96
97 ok = wbint_bh_is_connected(h);
98 if (!ok) {
99 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
100 return tevent_req_post(req, ev);
101 }
102
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);
108 }
109
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;
114
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);
119 }
120 tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req);
121
122 return req;
123}
124
125static void wbint_bh_raw_call_done(struct tevent_req *subreq)
126{
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;
134
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;
141 }
142
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_nomem(NULL, req);
148 return;
149 }
150
151 if (state->domain != NULL) {
152 wcache_store_ndr(state->domain, state->opnum,
153 &state->in_data, &state->out_data);
154 }
155
156 tevent_req_done(req);
157}
158
159static 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)
164{
165 struct wbint_bh_raw_call_state *state =
166 tevent_req_data(req,
167 struct wbint_bh_raw_call_state);
168 NTSTATUS status;
169
170 if (tevent_req_is_nterror(req, &status)) {
171 tevent_req_received(req);
172 return status;
173 }
174
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;
180}
181
182struct wbint_bh_disconnect_state {
183 uint8_t _dummy;
184};
185
186static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
187 struct tevent_context *ev,
188 struct dcerpc_binding_handle *h)
189{
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;
195
196 req = tevent_req_create(mem_ctx, &state,
197 struct wbint_bh_disconnect_state);
198 if (req == NULL) {
199 return NULL;
200 }
201
202 ok = wbint_bh_is_connected(h);
203 if (!ok) {
204 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
205 return tevent_req_post(req, ev);
206 }
207
208 /*
209 * TODO: do a real async disconnect ...
210 *
211 * For now the caller needs to free rpc_cli
212 */
213 hs->child = NULL;
214
215 tevent_req_done(req);
216 return tevent_req_post(req, ev);
217}
218
219static NTSTATUS wbint_bh_disconnect_recv(struct tevent_req *req)
220{
221 NTSTATUS status;
222
223 if (tevent_req_is_nterror(req, &status)) {
224 tevent_req_received(req);
225 return status;
226 }
227
228 tevent_req_received(req);
229 return NT_STATUS_OK;
230}
231
232static bool wbint_bh_ref_alloc(struct dcerpc_binding_handle *h)
233{
234 return true;
235}
236
237static 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)
241{
242 void *struct_ptr = discard_const(_struct_ptr);
243
244 if (DEBUGLEVEL < 10) {
245 return;
246 }
247
248 if (ndr_flags & NDR_IN) {
249 ndr_print_function_debug(call->ndr_print,
250 call->name,
251 ndr_flags,
252 struct_ptr);
253 }
254 if (ndr_flags & NDR_OUT) {
255 ndr_print_function_debug(call->ndr_print,
256 call->name,
257 ndr_flags,
258 struct_ptr);
259 }
260}
261
262static 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,
270
271 .ref_alloc = wbint_bh_ref_alloc,
272 .do_ndr_print = wbint_bh_do_ndr_print,
273};
274
275/* initialise a wbint binding handle */
276struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
277 struct winbindd_domain *domain,
278 struct winbindd_child *child)
279{
280 struct dcerpc_binding_handle *h;
281 struct wbint_bh_state *hs;
282
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;
292 }
293 hs->domain = domain;
294 hs->child = child;
295
296 return h;
297}
298
299enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
300 struct winbindd_cli_state *state)
301{
302 struct pipes_struct p;
303 struct api_struct *fns;
304 int num_fns;
305 bool ret;
306
307 wbint_get_pipe_fns(&fns, &num_fns);
308
309 if (state->request->data.ndrcmd >= num_fns) {
310 return WINBINDD_ERROR;
311 }
312
313 DEBUG(10, ("winbindd_dual_ndrcmd: Running command %s (%s)\n",
314 fns[state->request->data.ndrcmd].name,
315 domain ? domain->name : "no domain"));
316
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);
321
322 ret = fns[state->request->data.ndrcmd].fn(&p);
323 if (!ret) {
324 TALLOC_FREE(p.mem_ctx);
325 return WINBINDD_ERROR;
326 }
327
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;
332
333 TALLOC_FREE(p.mem_ctx);
334
335 if (state->response->extra_data.data == NULL) {
336 return WINBINDD_ERROR;
337 }
338 return WINBINDD_OK;
339}
Note: See TracBrowser for help on using the repository browser.