build: moved librpc/rpc/*.c into a rpccommon library
[Samba.git] / librpc / rpc / binding_handle.c
blob9ad7a9bde874e0068a3c903d5a8fcbced6aa486b
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 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,
96 uint32_t timeout)
98 return h->ops->set_timeout(h, timeout);
101 struct dcerpc_binding_handle_raw_call_state {
102 const struct dcerpc_binding_handle_ops *ops;
103 uint8_t *out_data;
104 size_t out_length;
105 uint32_t out_flags;
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,
114 uint32_t opnum,
115 uint32_t in_flags,
116 const uint8_t *in_data,
117 size_t in_length)
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);
125 if (req == NULL) {
126 return NULL;
128 state->ops = h->ops;
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,
134 object, opnum,
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);
141 return req;
144 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
146 struct tevent_req *req = tevent_req_callback_data(subreq,
147 struct tevent_req);
148 struct dcerpc_binding_handle_raw_call_state *state =
149 tevent_req_data(req,
150 struct dcerpc_binding_handle_raw_call_state);
151 NTSTATUS error;
153 error = state->ops->raw_call_recv(subreq, state,
154 &state->out_data,
155 &state->out_length,
156 &state->out_flags);
157 TALLOC_FREE(subreq);
158 if (!NT_STATUS_IS_OK(error)) {
159 tevent_req_nterror(req, error);
160 return;
163 tevent_req_done(req);
166 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
167 TALLOC_CTX *mem_ctx,
168 uint8_t **out_data,
169 size_t *out_length,
170 uint32_t *out_flags)
172 struct dcerpc_binding_handle_raw_call_state *state =
173 tevent_req_data(req,
174 struct dcerpc_binding_handle_raw_call_state);
175 NTSTATUS error;
177 if (tevent_req_is_nterror(req, &error)) {
178 tevent_req_received(req);
179 return error;
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);
186 return NT_STATUS_OK;
189 struct dcerpc_binding_handle_disconnect_state {
190 const struct dcerpc_binding_handle_ops *ops;
193 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
195 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
196 struct tevent_context *ev,
197 struct dcerpc_binding_handle *h)
199 struct tevent_req *req;
200 struct dcerpc_binding_handle_disconnect_state *state;
201 struct tevent_req *subreq;
203 req = tevent_req_create(mem_ctx, &state,
204 struct dcerpc_binding_handle_disconnect_state);
205 if (req == NULL) {
206 return NULL;
209 state->ops = h->ops;
211 subreq = state->ops->disconnect_send(state, ev, h);
212 if (tevent_req_nomem(subreq, req)) {
213 return tevent_req_post(req, ev);
215 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
217 return req;
220 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
222 struct tevent_req *req = tevent_req_callback_data(subreq,
223 struct tevent_req);
224 struct dcerpc_binding_handle_disconnect_state *state =
225 tevent_req_data(req,
226 struct dcerpc_binding_handle_disconnect_state);
227 NTSTATUS error;
229 error = state->ops->disconnect_recv(subreq);
230 TALLOC_FREE(subreq);
231 if (!NT_STATUS_IS_OK(error)) {
232 tevent_req_nterror(req, error);
233 return;
236 tevent_req_done(req);
239 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
241 NTSTATUS error;
243 if (tevent_req_is_nterror(req, &error)) {
244 tevent_req_received(req);
245 return error;
248 tevent_req_received(req);
249 return NT_STATUS_OK;
252 struct dcerpc_binding_handle_call_state {
253 struct dcerpc_binding_handle *h;
254 const struct ndr_interface_call *call;
255 TALLOC_CTX *r_mem;
256 void *r_ptr;
257 struct ndr_push *push;
258 DATA_BLOB request;
259 DATA_BLOB response;
260 struct ndr_pull *pull;
263 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
265 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
266 struct tevent_context *ev,
267 struct dcerpc_binding_handle *h,
268 const struct GUID *object,
269 const struct ndr_interface_table *table,
270 uint32_t opnum,
271 TALLOC_CTX *r_mem,
272 void *r_ptr)
274 struct tevent_req *req;
275 struct dcerpc_binding_handle_call_state *state;
276 struct tevent_req *subreq;
277 enum ndr_err_code ndr_err;
279 req = tevent_req_create(mem_ctx, &state,
280 struct dcerpc_binding_handle_call_state);
281 if (req == NULL) {
282 return NULL;
285 #if 0 /* TODO: activate this when the callers are fixed */
286 if (table != h->table) {
287 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
288 return tevent_req_post(req, ev);
290 #endif
292 if (opnum >= table->num_calls) {
293 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
294 return tevent_req_post(req, ev);
297 state->h = h;
298 state->call = &table->calls[opnum];
300 state->r_mem = r_mem;
301 state->r_ptr = r_ptr;
303 /* setup for a ndr_push_* call */
304 state->push = ndr_push_init_ctx(state);
305 if (tevent_req_nomem(state->push, req)) {
306 return tevent_req_post(req, ev);
309 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
310 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
313 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
314 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
317 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
318 state->push->flags |= LIBNDR_FLAG_NDR64;
321 if (h->ops->do_ndr_print) {
322 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
323 state->r_ptr, state->call);
326 /* push the structure into a blob */
327 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
328 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
329 NTSTATUS error;
330 error = ndr_map_error2ntstatus(ndr_err);
331 if (h->ops->ndr_push_failed) {
332 h->ops->ndr_push_failed(h, error,
333 state->r_ptr,
334 state->call);
336 tevent_req_nterror(req, error);
337 return tevent_req_post(req, ev);
340 /* retrieve the blob */
341 state->request = ndr_push_blob(state->push);
343 if (h->ops->ndr_validate_in) {
344 NTSTATUS error;
345 error = h->ops->ndr_validate_in(h, state,
346 &state->request,
347 state->call);
348 if (!NT_STATUS_IS_OK(error)) {
349 tevent_req_nterror(req, error);
350 return tevent_req_post(req, ev);
354 subreq = dcerpc_binding_handle_raw_call_send(state, ev,
355 h, object, opnum,
356 state->push->flags,
357 state->request.data,
358 state->request.length);
359 if (tevent_req_nomem(subreq, req)) {
360 return tevent_req_post(req, ev);
362 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
364 return req;
367 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
369 struct tevent_req *req = tevent_req_callback_data(subreq,
370 struct tevent_req);
371 struct dcerpc_binding_handle_call_state *state =
372 tevent_req_data(req,
373 struct dcerpc_binding_handle_call_state);
374 struct dcerpc_binding_handle *h = state->h;
375 NTSTATUS error;
376 uint32_t out_flags = 0;
377 enum ndr_err_code ndr_err;
379 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
380 &state->response.data,
381 &state->response.length,
382 &out_flags);
383 TALLOC_FREE(subreq);
384 if (!NT_STATUS_IS_OK(error)) {
385 tevent_req_nterror(req, error);
386 return;
389 state->pull = ndr_pull_init_blob(&state->response, state);
390 if (tevent_req_nomem(state->pull, req)) {
391 return;
393 state->pull->flags = state->push->flags;
395 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
396 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
397 } else {
398 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
401 state->pull->current_mem_ctx = state->r_mem;
403 /* pull the structure from the blob */
404 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
405 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
406 error = ndr_map_error2ntstatus(ndr_err);
407 if (h->ops->ndr_pull_failed) {
408 h->ops->ndr_pull_failed(h, error,
409 &state->response,
410 state->call);
412 tevent_req_nterror(req, error);
413 return;
416 if (h->ops->do_ndr_print) {
417 h->ops->do_ndr_print(h, NDR_OUT,
418 state->r_ptr, state->call);
421 if (h->ops->ndr_validate_out) {
422 error = h->ops->ndr_validate_out(h,
423 state->pull,
424 state->r_ptr,
425 state->call);
426 if (!NT_STATUS_IS_OK(error)) {
427 tevent_req_nterror(req, error);
428 return;
432 tevent_req_done(req);
435 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
437 NTSTATUS error;
439 if (tevent_req_is_nterror(req, &error)) {
440 tevent_req_received(req);
441 return error;
444 tevent_req_received(req);
445 return NT_STATUS_OK;
448 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
449 const struct GUID *object,
450 const struct ndr_interface_table *table,
451 uint32_t opnum,
452 TALLOC_CTX *r_mem,
453 void *r_ptr)
455 TALLOC_CTX *frame = talloc_stackframe();
456 struct tevent_context *ev;
457 struct tevent_req *subreq;
458 NTSTATUS status;
461 * TODO: allow only one sync call
464 if (h->sync_ev) {
465 ev = h->sync_ev;
466 } else {
467 ev = tevent_context_init(frame);
469 if (ev == NULL) {
470 talloc_free(frame);
471 return NT_STATUS_NO_MEMORY;
474 subreq = dcerpc_binding_handle_call_send(frame, ev,
475 h, object, table,
476 opnum, r_mem, r_ptr);
477 if (subreq == NULL) {
478 talloc_free(frame);
479 return NT_STATUS_NO_MEMORY;
482 if (!tevent_req_poll(subreq, ev)) {
483 status = map_nt_error_from_unix(errno);
484 talloc_free(frame);
485 return status;
488 status = dcerpc_binding_handle_call_recv(subreq);
489 if (!NT_STATUS_IS_OK(status)) {
490 talloc_free(frame);
491 return status;
494 TALLOC_FREE(frame);
495 return NT_STATUS_OK;