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;
128 struct tevent_context *ev;
129 struct tevent_req *subreq;
132 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
134 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
135 struct tevent_context *ev,
136 struct dcerpc_binding_handle *h,
137 const struct GUID *object,
140 const uint8_t *in_data,
143 struct tevent_req *req;
144 struct dcerpc_binding_handle_raw_call_state *state;
146 req = tevent_req_create(mem_ctx, &state,
147 struct dcerpc_binding_handle_raw_call_state);
154 if (h->object != NULL) {
156 * If an object is set on the binding handle,
157 * per request object passing is not allowed.
159 if (object != NULL) {
160 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
161 return tevent_req_post(req, ev);
165 * We use the object from the binding handle
170 state->subreq = state->ops->raw_call_send(state, ev, h,
172 in_flags, in_data, in_length);
173 if (tevent_req_nomem(state->subreq, req)) {
174 return tevent_req_post(req, ev);
176 tevent_req_set_callback(state->subreq,
177 dcerpc_binding_handle_raw_call_done,
183 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
185 struct tevent_req *req =
186 tevent_req_callback_data(subreq,
189 if (tevent_req_is_in_progress(subreq)) {
190 tevent_req_notify_callback(req);
194 tevent_req_done(req);
197 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
203 struct dcerpc_binding_handle_raw_call_state *state =
205 struct dcerpc_binding_handle_raw_call_state);
208 if (!tevent_req_is_in_progress(req)) {
209 if (tevent_req_is_nterror(req, &error)) {
210 tevent_req_received(req);
215 error = state->ops->raw_call_recv(state->subreq,
220 if (!NT_STATUS_IS_OK(error)) {
221 tevent_req_received(req);
225 if (tevent_req_is_in_progress(state->subreq)) {
229 tevent_req_received(req);
233 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
234 const struct GUID *object,
237 const uint8_t *in_data,
244 TALLOC_CTX *frame = talloc_stackframe();
245 struct tevent_context *ev;
246 struct tevent_req *subreq;
247 NTSTATUS status = NT_STATUS_NO_MEMORY;
250 * TODO: allow only one sync call
256 ev = samba_tevent_context_init(frame);
262 subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
267 if (subreq == NULL) {
271 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
275 status = dcerpc_binding_handle_raw_call_recv(subreq,
285 struct dcerpc_binding_handle_disconnect_state {
286 const struct dcerpc_binding_handle_ops *ops;
289 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
291 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
292 struct tevent_context *ev,
293 struct dcerpc_binding_handle *h)
295 struct tevent_req *req;
296 struct dcerpc_binding_handle_disconnect_state *state;
297 struct tevent_req *subreq;
299 req = tevent_req_create(mem_ctx, &state,
300 struct dcerpc_binding_handle_disconnect_state);
307 subreq = state->ops->disconnect_send(state, ev, h);
308 if (tevent_req_nomem(subreq, req)) {
309 return tevent_req_post(req, ev);
311 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
316 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
318 struct tevent_req *req = tevent_req_callback_data(subreq,
320 struct dcerpc_binding_handle_disconnect_state *state =
322 struct dcerpc_binding_handle_disconnect_state);
325 error = state->ops->disconnect_recv(subreq);
327 if (tevent_req_nterror(req, error)) {
331 tevent_req_done(req);
334 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
338 if (tevent_req_is_nterror(req, &error)) {
339 tevent_req_received(req);
343 tevent_req_received(req);
347 struct dcerpc_binding_handle_call_state {
348 struct dcerpc_binding_handle *h;
349 const struct ndr_interface_call *call;
352 struct ndr_push *push;
355 struct ndr_pull *pull;
358 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
360 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
361 struct tevent_context *ev,
362 struct dcerpc_binding_handle *h,
363 const struct GUID *object,
364 const struct ndr_interface_table *table,
369 struct tevent_req *req;
370 struct dcerpc_binding_handle_call_state *state;
371 struct tevent_req *subreq;
372 enum ndr_err_code ndr_err;
374 req = tevent_req_create(mem_ctx, &state,
375 struct dcerpc_binding_handle_call_state);
380 if (table != h->table) {
381 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
382 return tevent_req_post(req, ev);
385 if (opnum >= table->num_calls) {
386 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
387 return tevent_req_post(req, ev);
391 state->call = &table->calls[opnum];
393 state->r_mem = r_mem;
394 state->r_ptr = r_ptr;
396 /* setup for a ndr_push_* call */
397 state->push = ndr_push_init_ctx(state);
398 if (tevent_req_nomem(state->push, req)) {
399 return tevent_req_post(req, ev);
402 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
403 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
406 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
407 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
410 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
411 state->push->flags |= LIBNDR_FLAG_NDR64;
414 if (h->ops->do_ndr_print) {
415 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
416 state->r_ptr, state->call);
419 /* push the structure into a blob */
420 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
421 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
423 error = ndr_map_error2ntstatus(ndr_err);
424 if (h->ops->ndr_push_failed) {
425 h->ops->ndr_push_failed(h, error,
429 tevent_req_nterror(req, error);
430 return tevent_req_post(req, ev);
433 /* retrieve the blob */
434 state->request = ndr_push_blob(state->push);
436 if (h->ops->ndr_validate_in) {
438 error = h->ops->ndr_validate_in(h, state,
441 if (!NT_STATUS_IS_OK(error)) {
442 tevent_req_nterror(req, error);
443 return tevent_req_post(req, ev);
447 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
451 state->request.length);
452 if (tevent_req_nomem(subreq, req)) {
453 return tevent_req_post(req, ev);
455 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
460 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
462 struct tevent_req *req = tevent_req_callback_data(subreq,
464 struct dcerpc_binding_handle_call_state *state =
466 struct dcerpc_binding_handle_call_state);
467 struct dcerpc_binding_handle *h = state->h;
469 uint32_t out_flags = 0;
470 enum ndr_err_code ndr_err;
472 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
473 &state->response.data,
474 &state->response.length,
477 if (tevent_req_nterror(req, error)) {
481 state->pull = ndr_pull_init_blob(&state->response, state);
482 if (tevent_req_nomem(state->pull, req)) {
485 state->pull->flags = state->push->flags;
487 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
488 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
490 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
493 state->pull->current_mem_ctx = state->r_mem;
495 /* pull the structure from the blob */
496 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
497 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
498 error = ndr_map_error2ntstatus(ndr_err);
499 if (h->ops->ndr_pull_failed) {
500 h->ops->ndr_pull_failed(h, error,
504 tevent_req_nterror(req, error);
508 if (h->ops->do_ndr_print) {
509 h->ops->do_ndr_print(h, NDR_OUT,
510 state->r_ptr, state->call);
513 if (h->ops->ndr_validate_out) {
514 error = h->ops->ndr_validate_out(h,
518 if (!NT_STATUS_IS_OK(error)) {
519 tevent_req_nterror(req, error);
524 tevent_req_done(req);
527 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
529 return tevent_req_simple_recv_ntstatus(req);
532 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
533 const struct GUID *object,
534 const struct ndr_interface_table *table,
539 TALLOC_CTX *frame = talloc_stackframe();
540 struct tevent_context *ev;
541 struct tevent_req *subreq;
542 NTSTATUS status = NT_STATUS_NO_MEMORY;
545 * TODO: allow only one sync call
551 ev = samba_tevent_context_init(frame);
557 subreq = dcerpc_binding_handle_call_send(frame, ev,
559 opnum, r_mem, r_ptr);
560 if (subreq == NULL) {
564 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
568 status = dcerpc_binding_handle_call_recv(subreq);