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 struct dcerpc_binding_handle_raw_call_state
{
102 const struct dcerpc_binding_handle_ops
*ops
;
108 static void dcerpc_binding_handle_raw_call_done(struct tevent_req
*subreq
);
110 struct tevent_req
*dcerpc_binding_handle_raw_call_send(TALLOC_CTX
*mem_ctx
,
111 struct tevent_context
*ev
,
112 struct dcerpc_binding_handle
*h
,
113 const struct GUID
*object
,
116 const uint8_t *in_data
,
119 struct tevent_req
*req
;
120 struct dcerpc_binding_handle_raw_call_state
*state
;
121 struct tevent_req
*subreq
;
123 req
= tevent_req_create(mem_ctx
, &state
,
124 struct dcerpc_binding_handle_raw_call_state
);
129 state
->out_data
= NULL
;
130 state
->out_length
= 0;
131 state
->out_flags
= 0;
133 subreq
= state
->ops
->raw_call_send(state
, ev
, h
,
135 in_flags
, in_data
, in_length
);
136 if (tevent_req_nomem(subreq
, req
)) {
137 return tevent_req_post(req
, ev
);
139 tevent_req_set_callback(subreq
, dcerpc_binding_handle_raw_call_done
, req
);
144 static void dcerpc_binding_handle_raw_call_done(struct tevent_req
*subreq
)
146 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
148 struct dcerpc_binding_handle_raw_call_state
*state
=
150 struct dcerpc_binding_handle_raw_call_state
);
153 error
= state
->ops
->raw_call_recv(subreq
, state
,
158 if (!NT_STATUS_IS_OK(error
)) {
159 tevent_req_nterror(req
, error
);
163 tevent_req_done(req
);
166 NTSTATUS
dcerpc_binding_handle_raw_call_recv(struct tevent_req
*req
,
172 struct dcerpc_binding_handle_raw_call_state
*state
=
174 struct dcerpc_binding_handle_raw_call_state
);
177 if (tevent_req_is_nterror(req
, &error
)) {
178 tevent_req_received(req
);
182 *out_data
= talloc_move(mem_ctx
, &state
->out_data
);
183 *out_length
= state
->out_length
;
184 *out_flags
= state
->out_flags
;
185 tevent_req_received(req
);
189 NTSTATUS
dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle
*h
,
190 const struct GUID
*object
,
193 const uint8_t *in_data
,
200 TALLOC_CTX
*frame
= talloc_stackframe();
201 struct tevent_context
*ev
;
202 struct tevent_req
*subreq
;
206 * TODO: allow only one sync call
212 ev
= samba_tevent_context_init(frame
);
216 return NT_STATUS_NO_MEMORY
;
219 subreq
= dcerpc_binding_handle_raw_call_send(frame
, ev
,
224 if (subreq
== NULL
) {
226 return NT_STATUS_NO_MEMORY
;
229 if (!tevent_req_poll(subreq
, ev
)) {
230 status
= map_nt_error_from_unix_common(errno
);
235 status
= dcerpc_binding_handle_raw_call_recv(subreq
,
240 if (!NT_STATUS_IS_OK(status
)) {
249 struct dcerpc_binding_handle_disconnect_state
{
250 const struct dcerpc_binding_handle_ops
*ops
;
253 static void dcerpc_binding_handle_disconnect_done(struct tevent_req
*subreq
);
255 struct tevent_req
*dcerpc_binding_handle_disconnect_send(TALLOC_CTX
*mem_ctx
,
256 struct tevent_context
*ev
,
257 struct dcerpc_binding_handle
*h
)
259 struct tevent_req
*req
;
260 struct dcerpc_binding_handle_disconnect_state
*state
;
261 struct tevent_req
*subreq
;
263 req
= tevent_req_create(mem_ctx
, &state
,
264 struct dcerpc_binding_handle_disconnect_state
);
271 subreq
= state
->ops
->disconnect_send(state
, ev
, h
);
272 if (tevent_req_nomem(subreq
, req
)) {
273 return tevent_req_post(req
, ev
);
275 tevent_req_set_callback(subreq
, dcerpc_binding_handle_disconnect_done
, req
);
280 static void dcerpc_binding_handle_disconnect_done(struct tevent_req
*subreq
)
282 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
284 struct dcerpc_binding_handle_disconnect_state
*state
=
286 struct dcerpc_binding_handle_disconnect_state
);
289 error
= state
->ops
->disconnect_recv(subreq
);
291 if (!NT_STATUS_IS_OK(error
)) {
292 tevent_req_nterror(req
, error
);
296 tevent_req_done(req
);
299 NTSTATUS
dcerpc_binding_handle_disconnect_recv(struct tevent_req
*req
)
303 if (tevent_req_is_nterror(req
, &error
)) {
304 tevent_req_received(req
);
308 tevent_req_received(req
);
312 struct dcerpc_binding_handle_call_state
{
313 struct dcerpc_binding_handle
*h
;
314 const struct ndr_interface_call
*call
;
317 struct ndr_push
*push
;
320 struct ndr_pull
*pull
;
323 static void dcerpc_binding_handle_call_done(struct tevent_req
*subreq
);
325 struct tevent_req
*dcerpc_binding_handle_call_send(TALLOC_CTX
*mem_ctx
,
326 struct tevent_context
*ev
,
327 struct dcerpc_binding_handle
*h
,
328 const struct GUID
*object
,
329 const struct ndr_interface_table
*table
,
334 struct tevent_req
*req
;
335 struct dcerpc_binding_handle_call_state
*state
;
336 struct tevent_req
*subreq
;
337 enum ndr_err_code ndr_err
;
339 req
= tevent_req_create(mem_ctx
, &state
,
340 struct dcerpc_binding_handle_call_state
);
345 #if 0 /* TODO: activate this when the callers are fixed */
346 if (table
!= h
->table
) {
347 tevent_req_nterror(req
, NT_STATUS_INVALID_HANDLE
);
348 return tevent_req_post(req
, ev
);
352 if (opnum
>= table
->num_calls
) {
353 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
354 return tevent_req_post(req
, ev
);
358 state
->call
= &table
->calls
[opnum
];
360 state
->r_mem
= r_mem
;
361 state
->r_ptr
= r_ptr
;
363 /* setup for a ndr_push_* call */
364 state
->push
= ndr_push_init_ctx(state
);
365 if (tevent_req_nomem(state
->push
, req
)) {
366 return tevent_req_post(req
, ev
);
369 if (h
->ops
->ref_alloc
&& h
->ops
->ref_alloc(h
)) {
370 state
->push
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
373 if (h
->ops
->push_bigendian
&& h
->ops
->push_bigendian(h
)) {
374 state
->push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
377 if (h
->ops
->use_ndr64
&& h
->ops
->use_ndr64(h
)) {
378 state
->push
->flags
|= LIBNDR_FLAG_NDR64
;
381 if (h
->ops
->do_ndr_print
) {
382 h
->ops
->do_ndr_print(h
, NDR_IN
| NDR_SET_VALUES
,
383 state
->r_ptr
, state
->call
);
386 /* push the structure into a blob */
387 ndr_err
= state
->call
->ndr_push(state
->push
, NDR_IN
, state
->r_ptr
);
388 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
390 error
= ndr_map_error2ntstatus(ndr_err
);
391 if (h
->ops
->ndr_push_failed
) {
392 h
->ops
->ndr_push_failed(h
, error
,
396 tevent_req_nterror(req
, error
);
397 return tevent_req_post(req
, ev
);
400 /* retrieve the blob */
401 state
->request
= ndr_push_blob(state
->push
);
403 if (h
->ops
->ndr_validate_in
) {
405 error
= h
->ops
->ndr_validate_in(h
, state
,
408 if (!NT_STATUS_IS_OK(error
)) {
409 tevent_req_nterror(req
, error
);
410 return tevent_req_post(req
, ev
);
414 subreq
= dcerpc_binding_handle_raw_call_send(state
, ev
,
418 state
->request
.length
);
419 if (tevent_req_nomem(subreq
, req
)) {
420 return tevent_req_post(req
, ev
);
422 tevent_req_set_callback(subreq
, dcerpc_binding_handle_call_done
, req
);
427 static void dcerpc_binding_handle_call_done(struct tevent_req
*subreq
)
429 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
431 struct dcerpc_binding_handle_call_state
*state
=
433 struct dcerpc_binding_handle_call_state
);
434 struct dcerpc_binding_handle
*h
= state
->h
;
436 uint32_t out_flags
= 0;
437 enum ndr_err_code ndr_err
;
439 error
= dcerpc_binding_handle_raw_call_recv(subreq
, state
,
440 &state
->response
.data
,
441 &state
->response
.length
,
444 if (!NT_STATUS_IS_OK(error
)) {
445 tevent_req_nterror(req
, error
);
449 state
->pull
= ndr_pull_init_blob(&state
->response
, state
);
450 if (tevent_req_nomem(state
->pull
, req
)) {
453 state
->pull
->flags
= state
->push
->flags
;
455 if (out_flags
& LIBNDR_FLAG_BIGENDIAN
) {
456 state
->pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
458 state
->pull
->flags
&= ~LIBNDR_FLAG_BIGENDIAN
;
461 state
->pull
->current_mem_ctx
= state
->r_mem
;
463 /* pull the structure from the blob */
464 ndr_err
= state
->call
->ndr_pull(state
->pull
, NDR_OUT
, state
->r_ptr
);
465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
466 error
= ndr_map_error2ntstatus(ndr_err
);
467 if (h
->ops
->ndr_pull_failed
) {
468 h
->ops
->ndr_pull_failed(h
, error
,
472 tevent_req_nterror(req
, error
);
476 if (h
->ops
->do_ndr_print
) {
477 h
->ops
->do_ndr_print(h
, NDR_OUT
,
478 state
->r_ptr
, state
->call
);
481 if (h
->ops
->ndr_validate_out
) {
482 error
= h
->ops
->ndr_validate_out(h
,
486 if (!NT_STATUS_IS_OK(error
)) {
487 tevent_req_nterror(req
, error
);
492 tevent_req_done(req
);
495 NTSTATUS
dcerpc_binding_handle_call_recv(struct tevent_req
*req
)
499 if (tevent_req_is_nterror(req
, &error
)) {
500 tevent_req_received(req
);
504 tevent_req_received(req
);
508 NTSTATUS
dcerpc_binding_handle_call(struct dcerpc_binding_handle
*h
,
509 const struct GUID
*object
,
510 const struct ndr_interface_table
*table
,
515 TALLOC_CTX
*frame
= talloc_stackframe();
516 struct tevent_context
*ev
;
517 struct tevent_req
*subreq
;
521 * TODO: allow only one sync call
527 ev
= samba_tevent_context_init(frame
);
531 return NT_STATUS_NO_MEMORY
;
534 subreq
= dcerpc_binding_handle_call_send(frame
, ev
,
536 opnum
, r_mem
, r_ptr
);
537 if (subreq
== NULL
) {
539 return NT_STATUS_NO_MEMORY
;
542 if (!tevent_req_poll(subreq
, ev
)) {
543 status
= map_nt_error_from_unix_common(errno
);
548 status
= dcerpc_binding_handle_call_recv(subreq
);
549 if (!NT_STATUS_IS_OK(status
)) {