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"
27 struct dcerpc_binding_handle
{
29 const struct dcerpc_binding_handle_ops
*ops
;
31 const struct GUID
*object
;
32 const struct ndr_interface_table
*table
;
33 struct tevent_context
*sync_ev
;
36 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle
*b
)
41 struct dcerpc_binding_handle
*_dcerpc_binding_handle_create(TALLOC_CTX
*mem_ctx
,
42 const struct dcerpc_binding_handle_ops
*ops
,
43 const struct GUID
*object
,
44 const struct ndr_interface_table
*table
,
50 struct dcerpc_binding_handle
*h
;
51 void **ppstate
= (void **)pstate
;
54 h
= talloc_zero(mem_ctx
, struct dcerpc_binding_handle
);
59 h
->location
= location
;
63 state
= talloc_zero_size(h
, psize
);
68 talloc_set_name_const(state
, type
);
70 h
->private_data
= state
;
72 talloc_set_destructor(h
, dcerpc_binding_handle_destructor
);
78 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle
*h
)
80 return h
->private_data
;
83 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle
*h
,
84 struct tevent_context
*ev
)
89 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle
*h
)
91 return h
->ops
->is_connected(h
);
94 struct dcerpc_binding_handle_raw_call_state
{
95 const struct dcerpc_binding_handle_ops
*ops
;
101 static void dcerpc_binding_handle_raw_call_done(struct tevent_req
*subreq
);
103 struct tevent_req
*dcerpc_binding_handle_raw_call_send(TALLOC_CTX
*mem_ctx
,
104 struct tevent_context
*ev
,
105 struct dcerpc_binding_handle
*h
,
106 const struct GUID
*object
,
109 const uint8_t *in_data
,
112 struct tevent_req
*req
;
113 struct dcerpc_binding_handle_raw_call_state
*state
;
114 struct tevent_req
*subreq
;
116 req
= tevent_req_create(mem_ctx
, &state
,
117 struct dcerpc_binding_handle_raw_call_state
);
122 state
->out_data
= NULL
;
123 state
->out_length
= 0;
124 state
->out_flags
= 0;
126 subreq
= state
->ops
->raw_call_send(state
, ev
, h
,
128 in_flags
, in_data
, in_length
);
129 if (tevent_req_nomem(subreq
, req
)) {
130 return tevent_req_post(req
, ev
);
132 tevent_req_set_callback(subreq
, dcerpc_binding_handle_raw_call_done
, req
);
137 static void dcerpc_binding_handle_raw_call_done(struct tevent_req
*subreq
)
139 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
141 struct dcerpc_binding_handle_raw_call_state
*state
=
143 struct dcerpc_binding_handle_raw_call_state
);
146 error
= state
->ops
->raw_call_recv(subreq
, state
,
151 if (!NT_STATUS_IS_OK(error
)) {
152 tevent_req_nterror(req
, error
);
156 tevent_req_done(req
);
159 NTSTATUS
dcerpc_binding_handle_raw_call_recv(struct tevent_req
*req
,
165 struct dcerpc_binding_handle_raw_call_state
*state
=
167 struct dcerpc_binding_handle_raw_call_state
);
170 if (tevent_req_is_nterror(req
, &error
)) {
171 tevent_req_received(req
);
175 *out_data
= talloc_move(mem_ctx
, &state
->out_data
);
176 *out_length
= state
->out_length
;
177 *out_flags
= state
->out_flags
;
178 tevent_req_received(req
);
182 struct dcerpc_binding_handle_disconnect_state
{
183 const struct dcerpc_binding_handle_ops
*ops
;
186 static void dcerpc_binding_handle_disconnect_done(struct tevent_req
*subreq
);
188 struct tevent_req
*dcerpc_binding_handle_disconnect_send(TALLOC_CTX
*mem_ctx
,
189 struct tevent_context
*ev
,
190 struct dcerpc_binding_handle
*h
)
192 struct tevent_req
*req
;
193 struct dcerpc_binding_handle_disconnect_state
*state
;
194 struct tevent_req
*subreq
;
196 req
= tevent_req_create(mem_ctx
, &state
,
197 struct dcerpc_binding_handle_disconnect_state
);
204 subreq
= state
->ops
->disconnect_send(state
, ev
, h
);
205 if (tevent_req_nomem(subreq
, req
)) {
206 return tevent_req_post(req
, ev
);
208 tevent_req_set_callback(subreq
, dcerpc_binding_handle_disconnect_done
, req
);
213 static void dcerpc_binding_handle_disconnect_done(struct tevent_req
*subreq
)
215 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
217 struct dcerpc_binding_handle_disconnect_state
*state
=
219 struct dcerpc_binding_handle_disconnect_state
);
222 error
= state
->ops
->disconnect_recv(subreq
);
224 if (!NT_STATUS_IS_OK(error
)) {
225 tevent_req_nterror(req
, error
);
229 tevent_req_done(req
);
232 NTSTATUS
dcerpc_binding_handle_disconnect_recv(struct tevent_req
*req
)
236 if (tevent_req_is_nterror(req
, &error
)) {
237 tevent_req_received(req
);
241 tevent_req_received(req
);
245 struct dcerpc_binding_handle_call_state
{
246 struct dcerpc_binding_handle
*h
;
247 const struct ndr_interface_call
*call
;
250 struct ndr_push
*push
;
253 struct ndr_pull
*pull
;
256 static void dcerpc_binding_handle_call_done(struct tevent_req
*subreq
);
258 struct tevent_req
*dcerpc_binding_handle_call_send(TALLOC_CTX
*mem_ctx
,
259 struct tevent_context
*ev
,
260 struct dcerpc_binding_handle
*h
,
261 const struct GUID
*object
,
262 const struct ndr_interface_table
*table
,
267 struct tevent_req
*req
;
268 struct dcerpc_binding_handle_call_state
*state
;
269 struct tevent_req
*subreq
;
270 enum ndr_err_code ndr_err
;
272 req
= tevent_req_create(mem_ctx
, &state
,
273 struct dcerpc_binding_handle_call_state
);
278 #if 0 /* TODO: activate this when the callers are fixed */
279 if (table
!= h
->table
) {
280 tevent_req_nterror(req
, NT_STATUS_INVALID_HANDLE
);
281 return tevent_req_post(req
, ev
);
285 if (opnum
>= table
->num_calls
) {
286 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
287 return tevent_req_post(req
, ev
);
291 state
->call
= &table
->calls
[opnum
];
293 state
->r_mem
= r_mem
;
294 state
->r_ptr
= r_ptr
;
296 /* setup for a ndr_push_* call */
297 state
->push
= ndr_push_init_ctx(state
);
298 if (tevent_req_nomem(state
->push
, req
)) {
299 return tevent_req_post(req
, ev
);
302 if (h
->ops
->ref_alloc
&& h
->ops
->ref_alloc(h
)) {
303 state
->push
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
306 if (h
->ops
->push_bigendian
&& h
->ops
->push_bigendian(h
)) {
307 state
->push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
310 if (h
->ops
->use_ndr64
&& h
->ops
->use_ndr64(h
)) {
311 state
->push
->flags
|= LIBNDR_FLAG_NDR64
;
314 if (h
->ops
->do_ndr_print
) {
315 h
->ops
->do_ndr_print(h
, NDR_IN
| NDR_SET_VALUES
,
316 state
->r_ptr
, state
->call
);
319 /* push the structure into a blob */
320 ndr_err
= state
->call
->ndr_push(state
->push
, NDR_IN
, state
->r_ptr
);
321 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
323 error
= ndr_map_error2ntstatus(ndr_err
);
324 if (h
->ops
->ndr_push_failed
) {
325 h
->ops
->ndr_push_failed(h
, error
,
329 tevent_req_nterror(req
, error
);
330 return tevent_req_post(req
, ev
);
333 /* retrieve the blob */
334 state
->request
= ndr_push_blob(state
->push
);
336 if (h
->ops
->ndr_validate_in
) {
338 error
= h
->ops
->ndr_validate_in(h
, state
,
341 if (!NT_STATUS_IS_OK(error
)) {
342 tevent_req_nterror(req
, error
);
343 return tevent_req_post(req
, ev
);
347 subreq
= dcerpc_binding_handle_raw_call_send(state
, ev
,
351 state
->request
.length
);
352 if (tevent_req_nomem(subreq
, req
)) {
353 return tevent_req_post(req
, ev
);
355 tevent_req_set_callback(subreq
, dcerpc_binding_handle_call_done
, req
);
360 static void dcerpc_binding_handle_call_done(struct tevent_req
*subreq
)
362 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
364 struct dcerpc_binding_handle_call_state
*state
=
366 struct dcerpc_binding_handle_call_state
);
367 struct dcerpc_binding_handle
*h
= state
->h
;
369 uint32_t out_flags
= 0;
370 enum ndr_err_code ndr_err
;
372 error
= dcerpc_binding_handle_raw_call_recv(subreq
, state
,
373 &state
->response
.data
,
374 &state
->response
.length
,
377 if (!NT_STATUS_IS_OK(error
)) {
378 tevent_req_nterror(req
, error
);
382 state
->pull
= ndr_pull_init_blob(&state
->response
, state
);
383 if (tevent_req_nomem(state
->pull
, req
)) {
386 state
->pull
->flags
= state
->push
->flags
;
388 if (out_flags
& LIBNDR_FLAG_BIGENDIAN
) {
389 state
->pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
391 state
->pull
->flags
&= ~LIBNDR_FLAG_BIGENDIAN
;
394 state
->pull
->current_mem_ctx
= state
->r_mem
;
396 /* pull the structure from the blob */
397 ndr_err
= state
->call
->ndr_pull(state
->pull
, NDR_OUT
, state
->r_ptr
);
398 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
399 error
= ndr_map_error2ntstatus(ndr_err
);
400 if (h
->ops
->ndr_pull_failed
) {
401 h
->ops
->ndr_pull_failed(h
, error
,
405 tevent_req_nterror(req
, error
);
409 if (h
->ops
->do_ndr_print
) {
410 h
->ops
->do_ndr_print(h
, NDR_OUT
,
411 state
->r_ptr
, state
->call
);
414 if (h
->ops
->ndr_validate_out
) {
415 error
= h
->ops
->ndr_validate_out(h
,
419 if (!NT_STATUS_IS_OK(error
)) {
420 tevent_req_nterror(req
, error
);
425 tevent_req_done(req
);
428 NTSTATUS
dcerpc_binding_handle_call_recv(struct tevent_req
*req
)
432 if (tevent_req_is_nterror(req
, &error
)) {
433 tevent_req_received(req
);
437 tevent_req_received(req
);
441 NTSTATUS
dcerpc_binding_handle_call(struct dcerpc_binding_handle
*h
,
442 const struct GUID
*object
,
443 const struct ndr_interface_table
*table
,
448 TALLOC_CTX
*frame
= talloc_stackframe();
449 struct tevent_context
*ev
;
450 struct tevent_req
*subreq
;
454 * TODO: allow only one sync call
460 ev
= tevent_context_init(frame
);
464 return NT_STATUS_NO_MEMORY
;
467 subreq
= dcerpc_binding_handle_call_send(frame
, ev
,
469 opnum
, r_mem
, r_ptr
);
470 if (subreq
== NULL
) {
472 return NT_STATUS_NO_MEMORY
;
475 if (!tevent_req_poll(subreq
, ev
)) {
476 status
= map_nt_error_from_unix(errno
);
481 status
= dcerpc_binding_handle_call_recv(subreq
);
482 if (!NT_STATUS_IS_OK(status
)) {