librpc/rpc: call do_ndr_print hook in dcerpc_binding_handle_call*()
[Samba/ita.git] / librpc / rpc / binding_handle.c
blob75b2dedcb5ccf0706cd3812f33822229ccbe9554
1 /*
2 Unix SMB/CIFS implementation.
4 dcerpc binding handle functions
6 Copyright (C) Stefan Metzmacher 2010
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/>.
22 #include "includes.h"
23 #include <tevent.h>
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/rpc/dcerpc.h"
27 struct dcerpc_binding_handle {
28 void *private_data;
29 const struct dcerpc_binding_handle_ops *ops;
30 const char *location;
31 const struct GUID *object;
32 const struct ndr_interface_table *table;
33 struct tevent_context *sync_ev;
36 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38 return 0;
41 struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
42 const struct dcerpc_binding_handle_ops *ops,
43 const struct GUID *object,
44 const struct ndr_interface_table *table,
45 void *pstate,
46 size_t psize,
47 const char *type,
48 const char *location)
50 struct dcerpc_binding_handle *h;
51 void **ppstate = (void **)pstate;
52 void *state;
54 h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
55 if (h == NULL) {
56 return NULL;
58 h->ops = ops;
59 h->location = location;
60 h->object = object;
61 h->table = table;
63 state = talloc_zero_size(h, psize);
64 if (state == NULL) {
65 talloc_free(h);
66 return NULL;
68 talloc_set_name_const(state, type);
70 h->private_data = state;
72 talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74 *ppstate = state;
75 return h;
78 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80 return h->private_data;
83 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
84 struct tevent_context *ev)
86 h->sync_ev = ev;
89 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91 return h->ops->is_connected(h);
94 struct dcerpc_binding_handle_raw_call_state {
95 const struct dcerpc_binding_handle_ops *ops;
96 uint8_t *out_data;
97 size_t out_length;
98 uint32_t out_flags;
101 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
103 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
104 struct tevent_context *ev,
105 struct dcerpc_binding_handle *h,
106 const struct GUID *object,
107 uint32_t opnum,
108 uint32_t in_flags,
109 const uint8_t *in_data,
110 size_t in_length)
112 struct tevent_req *req;
113 struct dcerpc_binding_handle_raw_call_state *state;
114 struct tevent_req *subreq;
116 req = tevent_req_create(mem_ctx, &state,
117 struct dcerpc_binding_handle_raw_call_state);
118 if (req == NULL) {
119 return NULL;
121 state->ops = h->ops;
122 state->out_data = NULL;
123 state->out_length = 0;
124 state->out_flags = 0;
126 subreq = state->ops->raw_call_send(state, ev, h,
127 object, opnum,
128 in_flags, in_data, in_length);
129 if (tevent_req_nomem(subreq, req)) {
130 return tevent_req_post(req, ev);
132 tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
134 return req;
137 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
139 struct tevent_req *req = tevent_req_callback_data(subreq,
140 struct tevent_req);
141 struct dcerpc_binding_handle_raw_call_state *state =
142 tevent_req_data(req,
143 struct dcerpc_binding_handle_raw_call_state);
144 NTSTATUS error;
146 error = state->ops->raw_call_recv(subreq, state,
147 &state->out_data,
148 &state->out_length,
149 &state->out_flags);
150 TALLOC_FREE(subreq);
151 if (!NT_STATUS_IS_OK(error)) {
152 tevent_req_nterror(req, error);
153 return;
156 tevent_req_done(req);
159 NTSTATUS dcerpc_binding_handle_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 dcerpc_binding_handle_raw_call_state *state =
166 tevent_req_data(req,
167 struct dcerpc_binding_handle_raw_call_state);
168 NTSTATUS error;
170 if (tevent_req_is_nterror(req, &error)) {
171 tevent_req_received(req);
172 return error;
175 *out_data = talloc_move(mem_ctx, &state->out_data);
176 *out_length = state->out_length;
177 *out_flags = state->out_flags;
178 tevent_req_received(req);
179 return NT_STATUS_OK;
182 struct dcerpc_binding_handle_disconnect_state {
183 const struct dcerpc_binding_handle_ops *ops;
186 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
188 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
189 struct tevent_context *ev,
190 struct dcerpc_binding_handle *h)
192 struct tevent_req *req;
193 struct dcerpc_binding_handle_disconnect_state *state;
194 struct tevent_req *subreq;
196 req = tevent_req_create(mem_ctx, &state,
197 struct dcerpc_binding_handle_disconnect_state);
198 if (req == NULL) {
199 return NULL;
202 state->ops = h->ops;
204 subreq = state->ops->disconnect_send(state, ev, h);
205 if (tevent_req_nomem(subreq, req)) {
206 return tevent_req_post(req, ev);
208 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
210 return req;
213 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
215 struct tevent_req *req = tevent_req_callback_data(subreq,
216 struct tevent_req);
217 struct dcerpc_binding_handle_disconnect_state *state =
218 tevent_req_data(req,
219 struct dcerpc_binding_handle_disconnect_state);
220 NTSTATUS error;
222 error = state->ops->disconnect_recv(subreq);
223 TALLOC_FREE(subreq);
224 if (!NT_STATUS_IS_OK(error)) {
225 tevent_req_nterror(req, error);
226 return;
229 tevent_req_done(req);
232 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
234 NTSTATUS error;
236 if (tevent_req_is_nterror(req, &error)) {
237 tevent_req_received(req);
238 return error;
241 tevent_req_received(req);
242 return NT_STATUS_OK;
245 struct dcerpc_binding_handle_call_state {
246 struct dcerpc_binding_handle *h;
247 const struct ndr_interface_call *call;
248 TALLOC_CTX *r_mem;
249 void *r_ptr;
250 struct ndr_push *push;
251 DATA_BLOB request;
252 DATA_BLOB response;
253 struct ndr_pull *pull;
256 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
258 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
259 struct tevent_context *ev,
260 struct dcerpc_binding_handle *h,
261 const struct GUID *object,
262 const struct ndr_interface_table *table,
263 uint32_t opnum,
264 TALLOC_CTX *r_mem,
265 void *r_ptr)
267 struct tevent_req *req;
268 struct dcerpc_binding_handle_call_state *state;
269 struct tevent_req *subreq;
270 enum ndr_err_code ndr_err;
272 req = tevent_req_create(mem_ctx, &state,
273 struct dcerpc_binding_handle_call_state);
274 if (req == NULL) {
275 return NULL;
278 #if 0 /* TODO: activate this when the callers are fixed */
279 if (table != h->table) {
280 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
281 return tevent_req_post(req, ev);
283 #endif
285 if (opnum >= table->num_calls) {
286 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
287 return tevent_req_post(req, ev);
290 state->h = h;
291 state->call = &table->calls[opnum];
293 state->r_mem = r_mem;
294 state->r_ptr = r_ptr;
296 /* setup for a ndr_push_* call */
297 state->push = ndr_push_init_ctx(state);
298 if (tevent_req_nomem(state->push, req)) {
299 return tevent_req_post(req, ev);
302 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
303 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
306 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
307 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
310 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
311 state->push->flags |= LIBNDR_FLAG_NDR64;
314 if (h->ops->do_ndr_print) {
315 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
316 state->r_ptr, state->call);
319 /* push the structure into a blob */
320 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
321 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
322 NTSTATUS error;
323 error = ndr_map_error2ntstatus(ndr_err);
324 if (h->ops->ndr_push_failed) {
325 h->ops->ndr_push_failed(h, error,
326 state->r_ptr,
327 state->call);
329 tevent_req_nterror(req, error);
330 return tevent_req_post(req, ev);
333 /* retrieve the blob */
334 state->request = ndr_push_blob(state->push);
336 if (h->ops->ndr_validate_in) {
337 NTSTATUS error;
338 error = h->ops->ndr_validate_in(h, state,
339 &state->request,
340 state->call);
341 if (!NT_STATUS_IS_OK(error)) {
342 tevent_req_nterror(req, error);
343 return tevent_req_post(req, ev);
347 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
348 h, object, opnum,
349 state->push->flags,
350 state->request.data,
351 state->request.length);
352 if (tevent_req_nomem(subreq, req)) {
353 return tevent_req_post(req, ev);
355 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
357 return req;
360 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
362 struct tevent_req *req = tevent_req_callback_data(subreq,
363 struct tevent_req);
364 struct dcerpc_binding_handle_call_state *state =
365 tevent_req_data(req,
366 struct dcerpc_binding_handle_call_state);
367 struct dcerpc_binding_handle *h = state->h;
368 NTSTATUS error;
369 uint32_t out_flags = 0;
370 enum ndr_err_code ndr_err;
372 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
373 &state->response.data,
374 &state->response.length,
375 &out_flags);
376 TALLOC_FREE(subreq);
377 if (!NT_STATUS_IS_OK(error)) {
378 tevent_req_nterror(req, error);
379 return;
382 state->pull = ndr_pull_init_blob(&state->response, state);
383 if (tevent_req_nomem(state->pull, req)) {
384 return;
386 state->pull->flags = state->push->flags;
388 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
389 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
390 } else {
391 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
394 state->pull->current_mem_ctx = state->r_mem;
396 /* pull the structure from the blob */
397 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
398 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
399 error = ndr_map_error2ntstatus(ndr_err);
400 if (h->ops->ndr_pull_failed) {
401 h->ops->ndr_pull_failed(h, error,
402 &state->response,
403 state->call);
405 tevent_req_nterror(req, error);
406 return;
409 if (h->ops->do_ndr_print) {
410 h->ops->do_ndr_print(h, NDR_OUT,
411 state->r_ptr, state->call);
414 if (h->ops->ndr_validate_out) {
415 error = h->ops->ndr_validate_out(h,
416 state->pull,
417 state->r_ptr,
418 state->call);
419 if (!NT_STATUS_IS_OK(error)) {
420 tevent_req_nterror(req, error);
421 return;
425 tevent_req_done(req);
428 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
430 NTSTATUS error;
432 if (tevent_req_is_nterror(req, &error)) {
433 tevent_req_received(req);
434 return error;
437 tevent_req_received(req);
438 return NT_STATUS_OK;
441 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
442 const struct GUID *object,
443 const struct ndr_interface_table *table,
444 uint32_t opnum,
445 TALLOC_CTX *r_mem,
446 void *r_ptr)
448 TALLOC_CTX *frame = talloc_stackframe();
449 struct tevent_context *ev;
450 struct tevent_req *subreq;
451 NTSTATUS status;
454 * TODO: allow only one sync call
457 if (h->sync_ev) {
458 ev = h->sync_ev;
459 } else {
460 ev = tevent_context_init(frame);
462 if (ev == NULL) {
463 talloc_free(frame);
464 return NT_STATUS_NO_MEMORY;
467 subreq = dcerpc_binding_handle_call_send(frame, ev,
468 h, object, table,
469 opnum, r_mem, r_ptr);
470 if (subreq == NULL) {
471 talloc_free(frame);
472 return NT_STATUS_NO_MEMORY;
475 if (!tevent_req_poll(subreq, ev)) {
476 status = map_nt_error_from_unix(errno);
477 talloc_free(frame);
478 return status;
481 status = dcerpc_binding_handle_call_recv(subreq);
482 if (!NT_STATUS_IS_OK(status)) {
483 talloc_free(frame);
484 return status;
487 TALLOC_FREE(frame);
488 return NT_STATUS_OK;