ctdb-tests: Extend ctdb stub to support "ptrans", "pdelete", "catdb"
[Samba.git] / librpc / rpc / binding_handle.c
blob5a9414464e28363dc66f1f5d52a262d5d6f36219
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"
26 #include "rpc_common.h"
28 struct 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;
37 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
39 return 0;
42 struct 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)
51 struct dcerpc_binding_handle *h;
52 void **ppstate = (void **)pstate;
53 void *state;
55 h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
56 if (h == NULL) {
57 return NULL;
59 h->ops = ops;
60 h->location = location;
61 h->object = object;
62 h->table = table;
64 state = talloc_zero_size(h, psize);
65 if (state == NULL) {
66 talloc_free(h);
67 return NULL;
69 talloc_set_name_const(state, type);
71 h->private_data = state;
73 talloc_set_destructor(h, dcerpc_binding_handle_destructor);
75 *ppstate = state;
76 return h;
79 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
81 return h->private_data;
84 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85 struct tevent_context *ev)
87 h->sync_ev = ev;
90 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
92 return h->ops->is_connected(h);
95 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
96 uint32_t timeout)
98 return h->ops->set_timeout(h, timeout);
101 void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
102 enum dcerpc_AuthType *auth_type,
103 enum dcerpc_AuthLevel *auth_level)
105 enum dcerpc_AuthType _auth_type;
106 enum dcerpc_AuthLevel _auth_level;
108 if (auth_type == NULL) {
109 auth_type = &_auth_type;
112 if (auth_level == NULL) {
113 auth_level = &_auth_level;
116 *auth_type = DCERPC_AUTH_TYPE_NONE;
117 *auth_level = DCERPC_AUTH_LEVEL_NONE;
119 if (h->ops->auth_info == NULL) {
120 return;
123 h->ops->auth_info(h, auth_type, auth_level);
126 struct dcerpc_binding_handle_raw_call_state {
127 const struct dcerpc_binding_handle_ops *ops;
128 uint8_t *out_data;
129 size_t out_length;
130 uint32_t out_flags;
133 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
135 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
136 struct tevent_context *ev,
137 struct dcerpc_binding_handle *h,
138 const struct GUID *object,
139 uint32_t opnum,
140 uint32_t in_flags,
141 const uint8_t *in_data,
142 size_t in_length)
144 struct tevent_req *req;
145 struct dcerpc_binding_handle_raw_call_state *state;
146 struct tevent_req *subreq;
148 req = tevent_req_create(mem_ctx, &state,
149 struct dcerpc_binding_handle_raw_call_state);
150 if (req == NULL) {
151 return NULL;
153 state->ops = h->ops;
154 state->out_data = NULL;
155 state->out_length = 0;
156 state->out_flags = 0;
158 subreq = state->ops->raw_call_send(state, ev, h,
159 object, opnum,
160 in_flags, in_data, in_length);
161 if (tevent_req_nomem(subreq, req)) {
162 return tevent_req_post(req, ev);
164 tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
166 return req;
169 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
171 struct tevent_req *req = tevent_req_callback_data(subreq,
172 struct tevent_req);
173 struct dcerpc_binding_handle_raw_call_state *state =
174 tevent_req_data(req,
175 struct dcerpc_binding_handle_raw_call_state);
176 NTSTATUS error;
178 error = state->ops->raw_call_recv(subreq, state,
179 &state->out_data,
180 &state->out_length,
181 &state->out_flags);
182 TALLOC_FREE(subreq);
183 if (tevent_req_nterror(req, error)) {
184 return;
187 tevent_req_done(req);
190 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
191 TALLOC_CTX *mem_ctx,
192 uint8_t **out_data,
193 size_t *out_length,
194 uint32_t *out_flags)
196 struct dcerpc_binding_handle_raw_call_state *state =
197 tevent_req_data(req,
198 struct dcerpc_binding_handle_raw_call_state);
199 NTSTATUS error;
201 if (tevent_req_is_nterror(req, &error)) {
202 tevent_req_received(req);
203 return error;
206 *out_data = talloc_move(mem_ctx, &state->out_data);
207 *out_length = state->out_length;
208 *out_flags = state->out_flags;
209 tevent_req_received(req);
210 return NT_STATUS_OK;
213 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
214 const struct GUID *object,
215 uint32_t opnum,
216 uint32_t in_flags,
217 const uint8_t *in_data,
218 size_t in_length,
219 TALLOC_CTX *mem_ctx,
220 uint8_t **out_data,
221 size_t *out_length,
222 uint32_t *out_flags)
224 TALLOC_CTX *frame = talloc_stackframe();
225 struct tevent_context *ev;
226 struct tevent_req *subreq;
227 NTSTATUS status;
230 * TODO: allow only one sync call
233 if (h->sync_ev) {
234 ev = h->sync_ev;
235 } else {
236 ev = samba_tevent_context_init(frame);
238 if (ev == NULL) {
239 talloc_free(frame);
240 return NT_STATUS_NO_MEMORY;
243 subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
244 h, object, opnum,
245 in_flags,
246 in_data,
247 in_length);
248 if (subreq == NULL) {
249 talloc_free(frame);
250 return NT_STATUS_NO_MEMORY;
253 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
254 talloc_free(frame);
255 return status;
258 status = dcerpc_binding_handle_raw_call_recv(subreq,
259 mem_ctx,
260 out_data,
261 out_length,
262 out_flags);
263 if (!NT_STATUS_IS_OK(status)) {
264 talloc_free(frame);
265 return status;
268 TALLOC_FREE(frame);
269 return NT_STATUS_OK;
272 struct dcerpc_binding_handle_disconnect_state {
273 const struct dcerpc_binding_handle_ops *ops;
276 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
278 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
279 struct tevent_context *ev,
280 struct dcerpc_binding_handle *h)
282 struct tevent_req *req;
283 struct dcerpc_binding_handle_disconnect_state *state;
284 struct tevent_req *subreq;
286 req = tevent_req_create(mem_ctx, &state,
287 struct dcerpc_binding_handle_disconnect_state);
288 if (req == NULL) {
289 return NULL;
292 state->ops = h->ops;
294 subreq = state->ops->disconnect_send(state, ev, h);
295 if (tevent_req_nomem(subreq, req)) {
296 return tevent_req_post(req, ev);
298 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
300 return req;
303 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
305 struct tevent_req *req = tevent_req_callback_data(subreq,
306 struct tevent_req);
307 struct dcerpc_binding_handle_disconnect_state *state =
308 tevent_req_data(req,
309 struct dcerpc_binding_handle_disconnect_state);
310 NTSTATUS error;
312 error = state->ops->disconnect_recv(subreq);
313 TALLOC_FREE(subreq);
314 if (tevent_req_nterror(req, error)) {
315 return;
318 tevent_req_done(req);
321 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
323 NTSTATUS error;
325 if (tevent_req_is_nterror(req, &error)) {
326 tevent_req_received(req);
327 return error;
330 tevent_req_received(req);
331 return NT_STATUS_OK;
334 struct dcerpc_binding_handle_call_state {
335 struct dcerpc_binding_handle *h;
336 const struct ndr_interface_call *call;
337 TALLOC_CTX *r_mem;
338 void *r_ptr;
339 struct ndr_push *push;
340 DATA_BLOB request;
341 DATA_BLOB response;
342 struct ndr_pull *pull;
345 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
347 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
348 struct tevent_context *ev,
349 struct dcerpc_binding_handle *h,
350 const struct GUID *object,
351 const struct ndr_interface_table *table,
352 uint32_t opnum,
353 TALLOC_CTX *r_mem,
354 void *r_ptr)
356 struct tevent_req *req;
357 struct dcerpc_binding_handle_call_state *state;
358 struct tevent_req *subreq;
359 enum ndr_err_code ndr_err;
361 req = tevent_req_create(mem_ctx, &state,
362 struct dcerpc_binding_handle_call_state);
363 if (req == NULL) {
364 return NULL;
367 #if 0 /* TODO: activate this when the callers are fixed */
368 if (table != h->table) {
369 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
370 return tevent_req_post(req, ev);
372 #endif
374 if (opnum >= table->num_calls) {
375 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
376 return tevent_req_post(req, ev);
379 state->h = h;
380 state->call = &table->calls[opnum];
382 state->r_mem = r_mem;
383 state->r_ptr = r_ptr;
385 /* setup for a ndr_push_* call */
386 state->push = ndr_push_init_ctx(state);
387 if (tevent_req_nomem(state->push, req)) {
388 return tevent_req_post(req, ev);
391 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
392 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
395 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
396 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
399 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
400 state->push->flags |= LIBNDR_FLAG_NDR64;
403 if (h->ops->do_ndr_print) {
404 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
405 state->r_ptr, state->call);
408 /* push the structure into a blob */
409 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
410 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
411 NTSTATUS error;
412 error = ndr_map_error2ntstatus(ndr_err);
413 if (h->ops->ndr_push_failed) {
414 h->ops->ndr_push_failed(h, error,
415 state->r_ptr,
416 state->call);
418 tevent_req_nterror(req, error);
419 return tevent_req_post(req, ev);
422 /* retrieve the blob */
423 state->request = ndr_push_blob(state->push);
425 if (h->ops->ndr_validate_in) {
426 NTSTATUS error;
427 error = h->ops->ndr_validate_in(h, state,
428 &state->request,
429 state->call);
430 if (!NT_STATUS_IS_OK(error)) {
431 tevent_req_nterror(req, error);
432 return tevent_req_post(req, ev);
436 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
437 h, object, opnum,
438 state->push->flags,
439 state->request.data,
440 state->request.length);
441 if (tevent_req_nomem(subreq, req)) {
442 return tevent_req_post(req, ev);
444 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
446 return req;
449 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
451 struct tevent_req *req = tevent_req_callback_data(subreq,
452 struct tevent_req);
453 struct dcerpc_binding_handle_call_state *state =
454 tevent_req_data(req,
455 struct dcerpc_binding_handle_call_state);
456 struct dcerpc_binding_handle *h = state->h;
457 NTSTATUS error;
458 uint32_t out_flags = 0;
459 enum ndr_err_code ndr_err;
461 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
462 &state->response.data,
463 &state->response.length,
464 &out_flags);
465 TALLOC_FREE(subreq);
466 if (tevent_req_nterror(req, error)) {
467 return;
470 state->pull = ndr_pull_init_blob(&state->response, state);
471 if (tevent_req_nomem(state->pull, req)) {
472 return;
474 state->pull->flags = state->push->flags;
476 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
477 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
478 } else {
479 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
482 state->pull->current_mem_ctx = state->r_mem;
484 /* pull the structure from the blob */
485 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
486 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
487 error = ndr_map_error2ntstatus(ndr_err);
488 if (h->ops->ndr_pull_failed) {
489 h->ops->ndr_pull_failed(h, error,
490 &state->response,
491 state->call);
493 tevent_req_nterror(req, error);
494 return;
497 if (h->ops->do_ndr_print) {
498 h->ops->do_ndr_print(h, NDR_OUT,
499 state->r_ptr, state->call);
502 if (h->ops->ndr_validate_out) {
503 error = h->ops->ndr_validate_out(h,
504 state->pull,
505 state->r_ptr,
506 state->call);
507 if (!NT_STATUS_IS_OK(error)) {
508 tevent_req_nterror(req, error);
509 return;
513 tevent_req_done(req);
516 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
518 return tevent_req_simple_recv_ntstatus(req);
521 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
522 const struct GUID *object,
523 const struct ndr_interface_table *table,
524 uint32_t opnum,
525 TALLOC_CTX *r_mem,
526 void *r_ptr)
528 TALLOC_CTX *frame = talloc_stackframe();
529 struct tevent_context *ev;
530 struct tevent_req *subreq;
531 NTSTATUS status = NT_STATUS_NO_MEMORY;
534 * TODO: allow only one sync call
537 if (h->sync_ev) {
538 ev = h->sync_ev;
539 } else {
540 ev = samba_tevent_context_init(frame);
542 if (ev == NULL) {
543 goto fail;
546 subreq = dcerpc_binding_handle_call_send(frame, ev,
547 h, object, table,
548 opnum, r_mem, r_ptr);
549 if (subreq == NULL) {
550 goto fail;
553 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
554 goto fail;
557 status = dcerpc_binding_handle_call_recv(subreq);
558 fail:
559 TALLOC_FREE(frame);
560 return status;