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/>.
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/rpc/dcerpc.h"
26 #include "rpc_common.h"
28 struct dcerpc_binding_handle {
30 const struct dcerpc_binding_handle_ops *ops;
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)
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,
51 struct dcerpc_binding_handle *h;
52 void **ppstate = (void **)pstate;
55 h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
60 h->location = location;
64 state = talloc_zero_size(h, psize);
69 talloc_set_name_const(state, type);
71 h->private_data = state;
73 talloc_set_destructor(h, dcerpc_binding_handle_destructor);
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)
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,
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) {
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;
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,
141 const uint8_t *in_data,
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);
154 state->out_data = NULL;
155 state->out_length = 0;
156 state->out_flags = 0;
158 if (h->object != NULL) {
160 * If an object is set on the binding handle,
161 * per request object passing is not allowed.
163 if (object != NULL) {
164 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
165 return tevent_req_post(req, ev);
169 * We use the object from the binding handle
174 subreq = state->ops->raw_call_send(state, ev, h,
176 in_flags, in_data, in_length);
177 if (tevent_req_nomem(subreq, req)) {
178 return tevent_req_post(req, ev);
180 tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
185 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
187 struct tevent_req *req = tevent_req_callback_data(subreq,
189 struct dcerpc_binding_handle_raw_call_state *state =
191 struct dcerpc_binding_handle_raw_call_state);
194 error = state->ops->raw_call_recv(subreq, state,
199 if (tevent_req_nterror(req, error)) {
203 tevent_req_done(req);
206 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
212 struct dcerpc_binding_handle_raw_call_state *state =
214 struct dcerpc_binding_handle_raw_call_state);
217 if (tevent_req_is_nterror(req, &error)) {
218 tevent_req_received(req);
222 *out_data = talloc_move(mem_ctx, &state->out_data);
223 *out_length = state->out_length;
224 *out_flags = state->out_flags;
225 tevent_req_received(req);
229 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
230 const struct GUID *object,
233 const uint8_t *in_data,
240 TALLOC_CTX *frame = talloc_stackframe();
241 struct tevent_context *ev;
242 struct tevent_req *subreq;
243 NTSTATUS status = NT_STATUS_NO_MEMORY;
246 * TODO: allow only one sync call
252 ev = samba_tevent_context_init(frame);
258 subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
263 if (subreq == NULL) {
267 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
271 status = dcerpc_binding_handle_raw_call_recv(subreq,
281 struct dcerpc_binding_handle_disconnect_state {
282 const struct dcerpc_binding_handle_ops *ops;
285 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
287 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
288 struct tevent_context *ev,
289 struct dcerpc_binding_handle *h)
291 struct tevent_req *req;
292 struct dcerpc_binding_handle_disconnect_state *state;
293 struct tevent_req *subreq;
295 req = tevent_req_create(mem_ctx, &state,
296 struct dcerpc_binding_handle_disconnect_state);
303 subreq = state->ops->disconnect_send(state, ev, h);
304 if (tevent_req_nomem(subreq, req)) {
305 return tevent_req_post(req, ev);
307 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
312 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
314 struct tevent_req *req = tevent_req_callback_data(subreq,
316 struct dcerpc_binding_handle_disconnect_state *state =
318 struct dcerpc_binding_handle_disconnect_state);
321 error = state->ops->disconnect_recv(subreq);
323 if (tevent_req_nterror(req, error)) {
327 tevent_req_done(req);
330 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
334 if (tevent_req_is_nterror(req, &error)) {
335 tevent_req_received(req);
339 tevent_req_received(req);
343 struct dcerpc_binding_handle_call_state {
344 struct dcerpc_binding_handle *h;
345 const struct ndr_interface_call *call;
348 struct ndr_push *push;
351 struct ndr_pull *pull;
354 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
356 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
357 struct tevent_context *ev,
358 struct dcerpc_binding_handle *h,
359 const struct GUID *object,
360 const struct ndr_interface_table *table,
365 struct tevent_req *req;
366 struct dcerpc_binding_handle_call_state *state;
367 struct tevent_req *subreq;
368 enum ndr_err_code ndr_err;
370 req = tevent_req_create(mem_ctx, &state,
371 struct dcerpc_binding_handle_call_state);
376 if (table != h->table) {
377 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
378 return tevent_req_post(req, ev);
381 if (opnum >= table->num_calls) {
382 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
383 return tevent_req_post(req, ev);
387 state->call = &table->calls[opnum];
389 state->r_mem = r_mem;
390 state->r_ptr = r_ptr;
392 /* setup for a ndr_push_* call */
393 state->push = ndr_push_init_ctx(state);
394 if (tevent_req_nomem(state->push, req)) {
395 return tevent_req_post(req, ev);
398 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
399 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
402 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
403 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
406 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
407 state->push->flags |= LIBNDR_FLAG_NDR64;
410 if (h->ops->do_ndr_print) {
411 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
412 state->r_ptr, state->call);
415 /* push the structure into a blob */
416 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
417 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
419 error = ndr_map_error2ntstatus(ndr_err);
420 if (h->ops->ndr_push_failed) {
421 h->ops->ndr_push_failed(h, error,
425 tevent_req_nterror(req, error);
426 return tevent_req_post(req, ev);
429 /* retrieve the blob */
430 state->request = ndr_push_blob(state->push);
432 if (h->ops->ndr_validate_in) {
434 error = h->ops->ndr_validate_in(h, state,
437 if (!NT_STATUS_IS_OK(error)) {
438 tevent_req_nterror(req, error);
439 return tevent_req_post(req, ev);
443 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
447 state->request.length);
448 if (tevent_req_nomem(subreq, req)) {
449 return tevent_req_post(req, ev);
451 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
456 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
458 struct tevent_req *req = tevent_req_callback_data(subreq,
460 struct dcerpc_binding_handle_call_state *state =
462 struct dcerpc_binding_handle_call_state);
463 struct dcerpc_binding_handle *h = state->h;
465 uint32_t out_flags = 0;
466 enum ndr_err_code ndr_err;
468 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
469 &state->response.data,
470 &state->response.length,
473 if (tevent_req_nterror(req, error)) {
477 state->pull = ndr_pull_init_blob(&state->response, state);
478 if (tevent_req_nomem(state->pull, req)) {
481 state->pull->flags = state->push->flags;
483 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
484 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
486 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
489 state->pull->current_mem_ctx = state->r_mem;
491 /* pull the structure from the blob */
492 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
493 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
494 error = ndr_map_error2ntstatus(ndr_err);
495 if (h->ops->ndr_pull_failed) {
496 h->ops->ndr_pull_failed(h, error,
500 tevent_req_nterror(req, error);
504 if (h->ops->do_ndr_print) {
505 h->ops->do_ndr_print(h, NDR_OUT,
506 state->r_ptr, state->call);
509 if (h->ops->ndr_validate_out) {
510 error = h->ops->ndr_validate_out(h,
514 if (!NT_STATUS_IS_OK(error)) {
515 tevent_req_nterror(req, error);
520 tevent_req_done(req);
523 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
525 return tevent_req_simple_recv_ntstatus(req);
528 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
529 const struct GUID *object,
530 const struct ndr_interface_table *table,
535 TALLOC_CTX *frame = talloc_stackframe();
536 struct tevent_context *ev;
537 struct tevent_req *subreq;
538 NTSTATUS status = NT_STATUS_NO_MEMORY;
541 * TODO: allow only one sync call
547 ev = samba_tevent_context_init(frame);
553 subreq = dcerpc_binding_handle_call_send(frame, ev,
555 opnum, r_mem, r_ptr);
556 if (subreq == NULL) {
560 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
564 status = dcerpc_binding_handle_call_recv(subreq);