WHATSNEW: Start release notes for Samba 4.23.0pre1.
[samba.git] / librpc / rpc / binding_handle.c
blob8ace6722a432d665e1441949ff6b3402b9cc3ce5
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 const struct dcerpc_binding *dcerpc_binding_handle_get_binding(struct dcerpc_binding_handle *h)
92 return h->ops->get_binding(h);
95 enum dcerpc_transport_t dcerpc_binding_handle_get_transport(struct dcerpc_binding_handle *h)
97 const struct dcerpc_binding *b = dcerpc_binding_handle_get_binding(h);
98 return dcerpc_binding_get_transport(b);
101 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
103 return h->ops->is_connected(h);
106 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
107 uint32_t timeout)
109 return h->ops->set_timeout(h, timeout);
112 bool dcerpc_binding_handle_transport_encrypted(struct dcerpc_binding_handle *h)
114 if (h->ops->transport_encrypted == NULL) {
115 return false;
118 return h->ops->transport_encrypted(h);
121 NTSTATUS dcerpc_binding_handle_transport_session_key(
122 struct dcerpc_binding_handle *h,
123 TALLOC_CTX *mem_ctx,
124 DATA_BLOB *session_key)
126 if (h->ops->transport_session_key == NULL) {
127 return NT_STATUS_NO_USER_SESSION_KEY;
130 return h->ops->transport_session_key(h, mem_ctx, session_key);
133 void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
134 enum dcerpc_AuthType *auth_type,
135 enum dcerpc_AuthLevel *auth_level)
137 enum dcerpc_AuthType _auth_type;
138 enum dcerpc_AuthLevel _auth_level;
140 if (auth_type == NULL) {
141 auth_type = &_auth_type;
144 if (auth_level == NULL) {
145 auth_level = &_auth_level;
148 *auth_type = DCERPC_AUTH_TYPE_NONE;
149 *auth_level = DCERPC_AUTH_LEVEL_NONE;
151 if (h->ops->auth_info == NULL) {
152 return;
155 h->ops->auth_info(h, auth_type, auth_level);
158 NTSTATUS dcerpc_binding_handle_auth_session_key(
159 struct dcerpc_binding_handle *h,
160 TALLOC_CTX *mem_ctx,
161 DATA_BLOB *session_key)
163 if (h->ops->auth_session_key == NULL) {
164 return NT_STATUS_NO_USER_SESSION_KEY;
167 return h->ops->auth_session_key(h, mem_ctx, session_key);
170 struct dcerpc_binding_handle_raw_call_state {
171 const struct dcerpc_binding_handle_ops *ops;
172 uint8_t *out_data;
173 size_t out_length;
174 uint32_t out_flags;
177 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
179 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
180 struct tevent_context *ev,
181 struct dcerpc_binding_handle *h,
182 const struct GUID *object,
183 uint32_t opnum,
184 uint32_t in_flags,
185 const uint8_t *in_data,
186 size_t in_length)
188 struct tevent_req *req;
189 struct dcerpc_binding_handle_raw_call_state *state;
190 struct tevent_req *subreq;
192 req = tevent_req_create(mem_ctx, &state,
193 struct dcerpc_binding_handle_raw_call_state);
194 if (req == NULL) {
195 return NULL;
197 state->ops = h->ops;
198 state->out_data = NULL;
199 state->out_length = 0;
200 state->out_flags = 0;
202 if (h->object != NULL) {
204 * If an object is set on the binding handle,
205 * per request object passing is not allowed.
207 if (object != NULL) {
208 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
209 return tevent_req_post(req, ev);
213 * We use the object from the binding handle
215 object = h->object;
218 subreq = state->ops->raw_call_send(state, ev, h,
219 object, opnum,
220 in_flags, in_data, in_length);
221 if (tevent_req_nomem(subreq, req)) {
222 return tevent_req_post(req, ev);
224 tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
226 return req;
229 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
231 struct tevent_req *req = tevent_req_callback_data(subreq,
232 struct tevent_req);
233 struct dcerpc_binding_handle_raw_call_state *state =
234 tevent_req_data(req,
235 struct dcerpc_binding_handle_raw_call_state);
236 NTSTATUS error;
238 error = state->ops->raw_call_recv(subreq, state,
239 &state->out_data,
240 &state->out_length,
241 &state->out_flags);
242 TALLOC_FREE(subreq);
243 if (tevent_req_nterror(req, error)) {
244 return;
247 tevent_req_done(req);
250 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
251 TALLOC_CTX *mem_ctx,
252 uint8_t **out_data,
253 size_t *out_length,
254 uint32_t *out_flags)
256 struct dcerpc_binding_handle_raw_call_state *state =
257 tevent_req_data(req,
258 struct dcerpc_binding_handle_raw_call_state);
259 NTSTATUS error;
261 if (tevent_req_is_nterror(req, &error)) {
262 tevent_req_received(req);
263 return error;
266 *out_data = talloc_move(mem_ctx, &state->out_data);
267 *out_length = state->out_length;
268 *out_flags = state->out_flags;
269 tevent_req_received(req);
270 return NT_STATUS_OK;
273 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
274 const struct GUID *object,
275 uint32_t opnum,
276 uint32_t in_flags,
277 const uint8_t *in_data,
278 size_t in_length,
279 TALLOC_CTX *mem_ctx,
280 uint8_t **out_data,
281 size_t *out_length,
282 uint32_t *out_flags)
284 TALLOC_CTX *frame = talloc_stackframe();
285 struct tevent_context *ev;
286 struct tevent_req *subreq;
287 NTSTATUS status = NT_STATUS_NO_MEMORY;
290 * TODO: allow only one sync call
293 if (h->sync_ev) {
294 ev = h->sync_ev;
295 } else {
296 ev = samba_tevent_context_init(frame);
298 if (ev == NULL) {
299 goto fail;
302 subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
303 h, object, opnum,
304 in_flags,
305 in_data,
306 in_length);
307 if (subreq == NULL) {
308 goto fail;
311 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
312 goto fail;
315 status = dcerpc_binding_handle_raw_call_recv(subreq,
316 mem_ctx,
317 out_data,
318 out_length,
319 out_flags);
320 fail:
321 TALLOC_FREE(frame);
322 return status;
325 struct dcerpc_binding_handle_disconnect_state {
326 const struct dcerpc_binding_handle_ops *ops;
329 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
331 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
332 struct tevent_context *ev,
333 struct dcerpc_binding_handle *h)
335 struct tevent_req *req;
336 struct dcerpc_binding_handle_disconnect_state *state;
337 struct tevent_req *subreq;
339 req = tevent_req_create(mem_ctx, &state,
340 struct dcerpc_binding_handle_disconnect_state);
341 if (req == NULL) {
342 return NULL;
345 state->ops = h->ops;
347 subreq = state->ops->disconnect_send(state, ev, h);
348 if (tevent_req_nomem(subreq, req)) {
349 return tevent_req_post(req, ev);
351 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
353 return req;
356 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
358 struct tevent_req *req = tevent_req_callback_data(subreq,
359 struct tevent_req);
360 struct dcerpc_binding_handle_disconnect_state *state =
361 tevent_req_data(req,
362 struct dcerpc_binding_handle_disconnect_state);
363 NTSTATUS error;
365 error = state->ops->disconnect_recv(subreq);
366 TALLOC_FREE(subreq);
367 if (tevent_req_nterror(req, error)) {
368 return;
371 tevent_req_done(req);
374 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
376 NTSTATUS error;
378 if (tevent_req_is_nterror(req, &error)) {
379 tevent_req_received(req);
380 return error;
383 tevent_req_received(req);
384 return NT_STATUS_OK;
387 struct dcerpc_binding_handle_call_state {
388 struct dcerpc_binding_handle *h;
389 const struct ndr_interface_call *call;
390 TALLOC_CTX *r_mem;
391 void *r_ptr;
392 struct ndr_push *push;
393 DATA_BLOB request;
394 DATA_BLOB response;
395 struct ndr_pull *pull;
398 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
400 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
401 struct tevent_context *ev,
402 struct dcerpc_binding_handle *h,
403 const struct GUID *object,
404 const struct ndr_interface_table *table,
405 uint32_t opnum,
406 TALLOC_CTX *r_mem,
407 void *r_ptr)
409 struct tevent_req *req;
410 struct dcerpc_binding_handle_call_state *state;
411 struct tevent_req *subreq;
412 enum ndr_err_code ndr_err;
414 req = tevent_req_create(mem_ctx, &state,
415 struct dcerpc_binding_handle_call_state);
416 if (req == NULL) {
417 return NULL;
420 if (table != h->table) {
421 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
422 return tevent_req_post(req, ev);
425 if (opnum >= table->num_calls) {
426 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
427 return tevent_req_post(req, ev);
430 state->h = h;
431 state->call = &table->calls[opnum];
433 state->r_mem = r_mem;
434 state->r_ptr = r_ptr;
436 /* setup for a ndr_push_* call */
437 state->push = ndr_push_init_ctx(state);
438 if (tevent_req_nomem(state->push, req)) {
439 return tevent_req_post(req, ev);
442 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
443 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
446 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
447 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
450 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
451 state->push->flags |= LIBNDR_FLAG_NDR64;
454 if (h->ops->do_ndr_print) {
455 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
456 state->r_ptr, state->call);
459 /* push the structure into a blob */
460 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
461 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
462 NTSTATUS error;
463 error = ndr_map_error2ntstatus(ndr_err);
464 if (h->ops->ndr_push_failed) {
465 h->ops->ndr_push_failed(h, error,
466 state->r_ptr,
467 state->call);
469 tevent_req_nterror(req, error);
470 return tevent_req_post(req, ev);
473 /* retrieve the blob */
474 state->request = ndr_push_blob(state->push);
476 if (h->ops->ndr_validate_in) {
477 NTSTATUS error;
478 error = h->ops->ndr_validate_in(h, state,
479 &state->request,
480 state->call);
481 if (!NT_STATUS_IS_OK(error)) {
482 tevent_req_nterror(req, error);
483 return tevent_req_post(req, ev);
487 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
488 h, object, opnum,
489 state->push->flags,
490 state->request.data,
491 state->request.length);
492 if (tevent_req_nomem(subreq, req)) {
493 return tevent_req_post(req, ev);
495 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
497 return req;
500 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
502 struct tevent_req *req = tevent_req_callback_data(subreq,
503 struct tevent_req);
504 struct dcerpc_binding_handle_call_state *state =
505 tevent_req_data(req,
506 struct dcerpc_binding_handle_call_state);
507 struct dcerpc_binding_handle *h = state->h;
508 NTSTATUS error;
509 uint32_t out_flags = 0;
510 enum ndr_err_code ndr_err;
512 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
513 &state->response.data,
514 &state->response.length,
515 &out_flags);
516 TALLOC_FREE(subreq);
517 if (tevent_req_nterror(req, error)) {
518 return;
521 state->pull = ndr_pull_init_blob(&state->response, state);
522 if (tevent_req_nomem(state->pull, req)) {
523 return;
525 state->pull->flags = state->push->flags;
527 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
528 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
529 } else {
530 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
533 state->pull->current_mem_ctx = state->r_mem;
535 /* pull the structure from the blob */
536 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
537 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
538 error = ndr_map_error2ntstatus(ndr_err);
539 if (h->ops->ndr_pull_failed) {
540 h->ops->ndr_pull_failed(h, error,
541 &state->response,
542 state->call);
544 tevent_req_nterror(req, error);
545 return;
548 if (h->ops->do_ndr_print) {
549 h->ops->do_ndr_print(h, NDR_OUT,
550 state->r_ptr, state->call);
553 if (h->ops->ndr_validate_out) {
554 error = h->ops->ndr_validate_out(h,
555 state->pull,
556 state->r_ptr,
557 state->call);
558 if (!NT_STATUS_IS_OK(error)) {
559 tevent_req_nterror(req, error);
560 return;
564 tevent_req_done(req);
567 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
569 return tevent_req_simple_recv_ntstatus(req);
572 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
573 const struct GUID *object,
574 const struct ndr_interface_table *table,
575 uint32_t opnum,
576 TALLOC_CTX *r_mem,
577 void *r_ptr)
579 TALLOC_CTX *frame = talloc_stackframe();
580 struct tevent_context *ev;
581 struct tevent_req *subreq;
582 NTSTATUS status = NT_STATUS_NO_MEMORY;
585 * TODO: allow only one sync call
588 if (h->sync_ev) {
589 ev = h->sync_ev;
590 } else {
591 ev = samba_tevent_context_init(frame);
593 if (ev == NULL) {
594 goto fail;
597 subreq = dcerpc_binding_handle_call_send(frame, ev,
598 h, object, table,
599 opnum, r_mem, r_ptr);
600 if (subreq == NULL) {
601 goto fail;
604 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
605 goto fail;
608 status = dcerpc_binding_handle_call_recv(subreq);
609 fail:
610 TALLOC_FREE(frame);
611 return status;