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 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
,
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
) {
118 return h
->ops
->transport_encrypted(h
);
121 NTSTATUS
dcerpc_binding_handle_transport_session_key(
122 struct dcerpc_binding_handle
*h
,
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
) {
155 h
->ops
->auth_info(h
, auth_type
, auth_level
);
158 NTSTATUS
dcerpc_binding_handle_auth_session_key(
159 struct dcerpc_binding_handle
*h
,
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
;
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
,
185 const uint8_t *in_data
,
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
);
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
218 subreq
= state
->ops
->raw_call_send(state
, ev
, h
,
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
);
229 static void dcerpc_binding_handle_raw_call_done(struct tevent_req
*subreq
)
231 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
233 struct dcerpc_binding_handle_raw_call_state
*state
=
235 struct dcerpc_binding_handle_raw_call_state
);
238 error
= state
->ops
->raw_call_recv(subreq
, state
,
243 if (tevent_req_nterror(req
, error
)) {
247 tevent_req_done(req
);
250 NTSTATUS
dcerpc_binding_handle_raw_call_recv(struct tevent_req
*req
,
256 struct dcerpc_binding_handle_raw_call_state
*state
=
258 struct dcerpc_binding_handle_raw_call_state
);
261 if (tevent_req_is_nterror(req
, &error
)) {
262 tevent_req_received(req
);
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
);
273 NTSTATUS
dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle
*h
,
274 const struct GUID
*object
,
277 const uint8_t *in_data
,
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
296 ev
= samba_tevent_context_init(frame
);
302 subreq
= dcerpc_binding_handle_raw_call_send(frame
, ev
,
307 if (subreq
== NULL
) {
311 if (!tevent_req_poll_ntstatus(subreq
, ev
, &status
)) {
315 status
= dcerpc_binding_handle_raw_call_recv(subreq
,
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
);
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
);
356 static void dcerpc_binding_handle_disconnect_done(struct tevent_req
*subreq
)
358 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
360 struct dcerpc_binding_handle_disconnect_state
*state
=
362 struct dcerpc_binding_handle_disconnect_state
);
365 error
= state
->ops
->disconnect_recv(subreq
);
367 if (tevent_req_nterror(req
, error
)) {
371 tevent_req_done(req
);
374 NTSTATUS
dcerpc_binding_handle_disconnect_recv(struct tevent_req
*req
)
378 if (tevent_req_is_nterror(req
, &error
)) {
379 tevent_req_received(req
);
383 tevent_req_received(req
);
387 struct dcerpc_binding_handle_call_state
{
388 struct dcerpc_binding_handle
*h
;
389 const struct ndr_interface_call
*call
;
392 struct ndr_push
*push
;
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
,
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
);
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
);
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
)) {
463 error
= ndr_map_error2ntstatus(ndr_err
);
464 if (h
->ops
->ndr_push_failed
) {
465 h
->ops
->ndr_push_failed(h
, error
,
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
) {
478 error
= h
->ops
->ndr_validate_in(h
, state
,
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
,
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
);
500 static void dcerpc_binding_handle_call_done(struct tevent_req
*subreq
)
502 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
504 struct dcerpc_binding_handle_call_state
*state
=
506 struct dcerpc_binding_handle_call_state
);
507 struct dcerpc_binding_handle
*h
= state
->h
;
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
,
517 if (tevent_req_nterror(req
, error
)) {
521 state
->pull
= ndr_pull_init_blob(&state
->response
, state
);
522 if (tevent_req_nomem(state
->pull
, req
)) {
525 state
->pull
->flags
= state
->push
->flags
;
527 if (out_flags
& LIBNDR_FLAG_BIGENDIAN
) {
528 state
->pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
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
,
544 tevent_req_nterror(req
, error
);
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
,
558 if (!NT_STATUS_IS_OK(error
)) {
559 tevent_req_nterror(req
, error
);
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
,
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
591 ev
= samba_tevent_context_init(frame
);
597 subreq
= dcerpc_binding_handle_call_send(frame
, ev
,
599 opnum
, r_mem
, r_ptr
);
600 if (subreq
== NULL
) {
604 if (!tevent_req_poll_ntstatus(subreq
, ev
, &status
)) {
608 status
= dcerpc_binding_handle_call_recv(subreq
);