source: trunk/server/librpc/rpc/binding_handle.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: 13.7 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 dcerpc binding handle functions
5
6 Copyright (C) Stefan Metzmacher 2010
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#include "includes.h"
23#include <tevent.h>
24#include "../lib/util/tevent_ntstatus.h"
25#include "librpc/rpc/dcerpc.h"
26#include "rpc_common.h"
27
28struct dcerpc_binding_handle {
29 void *private_data;
30 const struct dcerpc_binding_handle_ops *ops;
31 const char *location;
32 const struct GUID *object;
33 const struct ndr_interface_table *table;
34 struct tevent_context *sync_ev;
35};
36
37static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38{
39 return 0;
40}
41
42struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
43 const struct dcerpc_binding_handle_ops *ops,
44 const struct GUID *object,
45 const struct ndr_interface_table *table,
46 void *pstate,
47 size_t psize,
48 const char *type,
49 const char *location)
50{
51 struct dcerpc_binding_handle *h;
52 void **ppstate = (void **)pstate;
53 void *state;
54
55 h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
56 if (h == NULL) {
57 return NULL;
58 }
59 h->ops = ops;
60 h->location = location;
61 h->object = object;
62 h->table = table;
63
64 state = talloc_zero_size(h, psize);
65 if (state == NULL) {
66 talloc_free(h);
67 return NULL;
68 }
69 talloc_set_name_const(state, type);
70
71 h->private_data = state;
72
73 talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74
75 *ppstate = state;
76 return h;
77}
78
79void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80{
81 return h->private_data;
82}
83
84void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85 struct tevent_context *ev)
86{
87 h->sync_ev = ev;
88}
89
90bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91{
92 return h->ops->is_connected(h);
93}
94
95uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
96 uint32_t timeout)
97{
98 return h->ops->set_timeout(h, timeout);
99}
100
101struct dcerpc_binding_handle_raw_call_state {
102 const struct dcerpc_binding_handle_ops *ops;
103 uint8_t *out_data;
104 size_t out_length;
105 uint32_t out_flags;
106};
107
108static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
109
110struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
111 struct tevent_context *ev,
112 struct dcerpc_binding_handle *h,
113 const struct GUID *object,
114 uint32_t opnum,
115 uint32_t in_flags,
116 const uint8_t *in_data,
117 size_t in_length)
118{
119 struct tevent_req *req;
120 struct dcerpc_binding_handle_raw_call_state *state;
121 struct tevent_req *subreq;
122
123 req = tevent_req_create(mem_ctx, &state,
124 struct dcerpc_binding_handle_raw_call_state);
125 if (req == NULL) {
126 return NULL;
127 }
128 state->ops = h->ops;
129 state->out_data = NULL;
130 state->out_length = 0;
131 state->out_flags = 0;
132
133 subreq = state->ops->raw_call_send(state, ev, h,
134 object, opnum,
135 in_flags, in_data, in_length);
136 if (tevent_req_nomem(subreq, req)) {
137 return tevent_req_post(req, ev);
138 }
139 tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
140
141 return req;
142}
143
144static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
145{
146 struct tevent_req *req = tevent_req_callback_data(subreq,
147 struct tevent_req);
148 struct dcerpc_binding_handle_raw_call_state *state =
149 tevent_req_data(req,
150 struct dcerpc_binding_handle_raw_call_state);
151 NTSTATUS error;
152
153 error = state->ops->raw_call_recv(subreq, state,
154 &state->out_data,
155 &state->out_length,
156 &state->out_flags);
157 TALLOC_FREE(subreq);
158 if (!NT_STATUS_IS_OK(error)) {
159 tevent_req_nterror(req, error);
160 return;
161 }
162
163 tevent_req_done(req);
164}
165
166NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
167 TALLOC_CTX *mem_ctx,
168 uint8_t **out_data,
169 size_t *out_length,
170 uint32_t *out_flags)
171{
172 struct dcerpc_binding_handle_raw_call_state *state =
173 tevent_req_data(req,
174 struct dcerpc_binding_handle_raw_call_state);
175 NTSTATUS error;
176
177 if (tevent_req_is_nterror(req, &error)) {
178 tevent_req_received(req);
179 return error;
180 }
181
182 *out_data = talloc_move(mem_ctx, &state->out_data);
183 *out_length = state->out_length;
184 *out_flags = state->out_flags;
185 tevent_req_received(req);
186 return NT_STATUS_OK;
187}
188
189NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
190 const struct GUID *object,
191 uint32_t opnum,
192 uint32_t in_flags,
193 const uint8_t *in_data,
194 size_t in_length,
195 TALLOC_CTX *mem_ctx,
196 uint8_t **out_data,
197 size_t *out_length,
198 uint32_t *out_flags)
199{
200 TALLOC_CTX *frame = talloc_stackframe();
201 struct tevent_context *ev;
202 struct tevent_req *subreq;
203 NTSTATUS status;
204
205 /*
206 * TODO: allow only one sync call
207 */
208
209 if (h->sync_ev) {
210 ev = h->sync_ev;
211 } else {
212 ev = tevent_context_init(frame);
213 }
214 if (ev == NULL) {
215 talloc_free(frame);
216 return NT_STATUS_NO_MEMORY;
217 }
218
219 subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
220 h, object, opnum,
221 in_flags,
222 in_data,
223 in_length);
224 if (subreq == NULL) {
225 talloc_free(frame);
226 return NT_STATUS_NO_MEMORY;
227 }
228
229 if (!tevent_req_poll(subreq, ev)) {
230 status = map_nt_error_from_unix(errno);
231 talloc_free(frame);
232 return status;
233 }
234
235 status = dcerpc_binding_handle_raw_call_recv(subreq,
236 mem_ctx,
237 out_data,
238 out_length,
239 out_flags);
240 if (!NT_STATUS_IS_OK(status)) {
241 talloc_free(frame);
242 return status;
243 }
244
245 TALLOC_FREE(frame);
246 return NT_STATUS_OK;
247}
248
249struct dcerpc_binding_handle_disconnect_state {
250 const struct dcerpc_binding_handle_ops *ops;
251};
252
253static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
254
255struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
256 struct tevent_context *ev,
257 struct dcerpc_binding_handle *h)
258{
259 struct tevent_req *req;
260 struct dcerpc_binding_handle_disconnect_state *state;
261 struct tevent_req *subreq;
262
263 req = tevent_req_create(mem_ctx, &state,
264 struct dcerpc_binding_handle_disconnect_state);
265 if (req == NULL) {
266 return NULL;
267 }
268
269 state->ops = h->ops;
270
271 subreq = state->ops->disconnect_send(state, ev, h);
272 if (tevent_req_nomem(subreq, req)) {
273 return tevent_req_post(req, ev);
274 }
275 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
276
277 return req;
278}
279
280static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
281{
282 struct tevent_req *req = tevent_req_callback_data(subreq,
283 struct tevent_req);
284 struct dcerpc_binding_handle_disconnect_state *state =
285 tevent_req_data(req,
286 struct dcerpc_binding_handle_disconnect_state);
287 NTSTATUS error;
288
289 error = state->ops->disconnect_recv(subreq);
290 TALLOC_FREE(subreq);
291 if (!NT_STATUS_IS_OK(error)) {
292 tevent_req_nterror(req, error);
293 return;
294 }
295
296 tevent_req_done(req);
297}
298
299NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
300{
301 NTSTATUS error;
302
303 if (tevent_req_is_nterror(req, &error)) {
304 tevent_req_received(req);
305 return error;
306 }
307
308 tevent_req_received(req);
309 return NT_STATUS_OK;
310}
311
312struct dcerpc_binding_handle_call_state {
313 struct dcerpc_binding_handle *h;
314 const struct ndr_interface_call *call;
315 TALLOC_CTX *r_mem;
316 void *r_ptr;
317 struct ndr_push *push;
318 DATA_BLOB request;
319 DATA_BLOB response;
320 struct ndr_pull *pull;
321};
322
323static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
324
325struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
326 struct tevent_context *ev,
327 struct dcerpc_binding_handle *h,
328 const struct GUID *object,
329 const struct ndr_interface_table *table,
330 uint32_t opnum,
331 TALLOC_CTX *r_mem,
332 void *r_ptr)
333{
334 struct tevent_req *req;
335 struct dcerpc_binding_handle_call_state *state;
336 struct tevent_req *subreq;
337 enum ndr_err_code ndr_err;
338
339 req = tevent_req_create(mem_ctx, &state,
340 struct dcerpc_binding_handle_call_state);
341 if (req == NULL) {
342 return NULL;
343 }
344
345#if 0 /* TODO: activate this when the callers are fixed */
346 if (table != h->table) {
347 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
348 return tevent_req_post(req, ev);
349 }
350#endif
351
352 if (opnum >= table->num_calls) {
353 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
354 return tevent_req_post(req, ev);
355 }
356
357 state->h = h;
358 state->call = &table->calls[opnum];
359
360 state->r_mem = r_mem;
361 state->r_ptr = r_ptr;
362
363 /* setup for a ndr_push_* call */
364 state->push = ndr_push_init_ctx(state);
365 if (tevent_req_nomem(state->push, req)) {
366 return tevent_req_post(req, ev);
367 }
368
369 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
370 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
371 }
372
373 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
374 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
375 }
376
377 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
378 state->push->flags |= LIBNDR_FLAG_NDR64;
379 }
380
381 if (h->ops->do_ndr_print) {
382 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
383 state->r_ptr, state->call);
384 }
385
386 /* push the structure into a blob */
387 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
388 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
389 NTSTATUS error;
390 error = ndr_map_error2ntstatus(ndr_err);
391 if (h->ops->ndr_push_failed) {
392 h->ops->ndr_push_failed(h, error,
393 state->r_ptr,
394 state->call);
395 }
396 tevent_req_nterror(req, error);
397 return tevent_req_post(req, ev);
398 }
399
400 /* retrieve the blob */
401 state->request = ndr_push_blob(state->push);
402
403 if (h->ops->ndr_validate_in) {
404 NTSTATUS error;
405 error = h->ops->ndr_validate_in(h, state,
406 &state->request,
407 state->call);
408 if (!NT_STATUS_IS_OK(error)) {
409 tevent_req_nterror(req, error);
410 return tevent_req_post(req, ev);
411 }
412 }
413
414 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
415 h, object, opnum,
416 state->push->flags,
417 state->request.data,
418 state->request.length);
419 if (tevent_req_nomem(subreq, req)) {
420 return tevent_req_post(req, ev);
421 }
422 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
423
424 return req;
425}
426
427static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
428{
429 struct tevent_req *req = tevent_req_callback_data(subreq,
430 struct tevent_req);
431 struct dcerpc_binding_handle_call_state *state =
432 tevent_req_data(req,
433 struct dcerpc_binding_handle_call_state);
434 struct dcerpc_binding_handle *h = state->h;
435 NTSTATUS error;
436 uint32_t out_flags = 0;
437 enum ndr_err_code ndr_err;
438
439 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
440 &state->response.data,
441 &state->response.length,
442 &out_flags);
443 TALLOC_FREE(subreq);
444 if (!NT_STATUS_IS_OK(error)) {
445 tevent_req_nterror(req, error);
446 return;
447 }
448
449 state->pull = ndr_pull_init_blob(&state->response, state);
450 if (tevent_req_nomem(state->pull, req)) {
451 return;
452 }
453 state->pull->flags = state->push->flags;
454
455 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
456 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
457 } else {
458 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
459 }
460
461 state->pull->current_mem_ctx = state->r_mem;
462
463 /* pull the structure from the blob */
464 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
466 error = ndr_map_error2ntstatus(ndr_err);
467 if (h->ops->ndr_pull_failed) {
468 h->ops->ndr_pull_failed(h, error,
469 &state->response,
470 state->call);
471 }
472 tevent_req_nterror(req, error);
473 return;
474 }
475
476 if (h->ops->do_ndr_print) {
477 h->ops->do_ndr_print(h, NDR_OUT,
478 state->r_ptr, state->call);
479 }
480
481 if (h->ops->ndr_validate_out) {
482 error = h->ops->ndr_validate_out(h,
483 state->pull,
484 state->r_ptr,
485 state->call);
486 if (!NT_STATUS_IS_OK(error)) {
487 tevent_req_nterror(req, error);
488 return;
489 }
490 }
491
492 tevent_req_done(req);
493}
494
495NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
496{
497 NTSTATUS error;
498
499 if (tevent_req_is_nterror(req, &error)) {
500 tevent_req_received(req);
501 return error;
502 }
503
504 tevent_req_received(req);
505 return NT_STATUS_OK;
506}
507
508NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
509 const struct GUID *object,
510 const struct ndr_interface_table *table,
511 uint32_t opnum,
512 TALLOC_CTX *r_mem,
513 void *r_ptr)
514{
515 TALLOC_CTX *frame = talloc_stackframe();
516 struct tevent_context *ev;
517 struct tevent_req *subreq;
518 NTSTATUS status;
519
520 /*
521 * TODO: allow only one sync call
522 */
523
524 if (h->sync_ev) {
525 ev = h->sync_ev;
526 } else {
527 ev = tevent_context_init(frame);
528 }
529 if (ev == NULL) {
530 talloc_free(frame);
531 return NT_STATUS_NO_MEMORY;
532 }
533
534 subreq = dcerpc_binding_handle_call_send(frame, ev,
535 h, object, table,
536 opnum, r_mem, r_ptr);
537 if (subreq == NULL) {
538 talloc_free(frame);
539 return NT_STATUS_NO_MEMORY;
540 }
541
542 if (!tevent_req_poll(subreq, ev)) {
543 status = map_nt_error_from_unix(errno);
544 talloc_free(frame);
545 return status;
546 }
547
548 status = dcerpc_binding_handle_call_recv(subreq);
549 if (!NT_STATUS_IS_OK(status)) {
550 talloc_free(frame);
551 return status;
552 }
553
554 TALLOC_FREE(frame);
555 return NT_STATUS_OK;
556}
Note: See TracBrowser for help on using the repository browser.