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 /* push the structure into a blob */
315 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
316 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
318 error = ndr_map_error2ntstatus(ndr_err);
319 if (h->ops->ndr_push_failed) {
320 h->ops->ndr_push_failed(h, error,
324 tevent_req_nterror(req, error);
325 return tevent_req_post(req, ev);
328 /* retrieve the blob */
329 state->request = ndr_push_blob(state->push);
331 if (h->ops->ndr_validate_in) {
333 error = h->ops->ndr_validate_in(h, state,
336 if (!NT_STATUS_IS_OK(error)) {
337 tevent_req_nterror(req, error);
338 return tevent_req_post(req, ev);
342 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
346 state->request.length);
347 if (tevent_req_nomem(subreq, req)) {
348 return tevent_req_post(req, ev);
350 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
355 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
357 struct tevent_req *req = tevent_req_callback_data(subreq,
359 struct dcerpc_binding_handle_call_state *state =
361 struct dcerpc_binding_handle_call_state);
362 struct dcerpc_binding_handle *h = state->h;
364 uint32_t out_flags = 0;
365 enum ndr_err_code ndr_err;
367 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
368 &state->response.data,
369 &state->response.length,
372 if (!NT_STATUS_IS_OK(error)) {
373 tevent_req_nterror(req, error);
377 state->pull = ndr_pull_init_blob(&state->response, state);
378 if (tevent_req_nomem(state->pull, req)) {
381 state->pull->flags = state->push->flags;
383 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
384 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
386 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
389 state->pull->current_mem_ctx = state->r_mem;
391 /* pull the structure from the blob */
392 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
393 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
394 error = ndr_map_error2ntstatus(ndr_err);
395 if (h->ops->ndr_pull_failed) {
396 h->ops->ndr_pull_failed(h, error,
400 tevent_req_nterror(req, error);
404 if (h->ops->ndr_validate_out) {
405 error = h->ops->ndr_validate_out(h,
409 if (!NT_STATUS_IS_OK(error)) {
410 tevent_req_nterror(req, error);
415 tevent_req_done(req);
418 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
422 if (tevent_req_is_nterror(req, &error)) {
423 tevent_req_received(req);
427 tevent_req_received(req);
431 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
432 const struct GUID *object,
433 const struct ndr_interface_table *table,
438 TALLOC_CTX *frame = talloc_stackframe();
439 struct tevent_context *ev;
440 struct tevent_req *subreq;
444 * TODO: allow only one sync call
450 ev = tevent_context_init(frame);
454 return NT_STATUS_NO_MEMORY;
457 subreq = dcerpc_binding_handle_call_send(frame, ev,
459 opnum, r_mem, r_ptr);
460 if (subreq == NULL) {
462 return NT_STATUS_NO_MEMORY;
465 if (!tevent_req_poll(subreq, ev)) {
466 status = map_nt_error_from_unix(errno);
471 status = dcerpc_binding_handle_call_recv(subreq);
472 if (!NT_STATUS_IS_OK(status)) {