librpc/rpc: add dcerpc_binding_handle_raw_call()
[nivanova/samba-autobuild/.git] / librpc / rpc / binding_handle.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    dcerpc binding handle functions
5
6    Copyright (C) Stefan Metzmacher 2010
7
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.
12
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.
17
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/>.
20 */
21
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"
27
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;
35 };
36
37 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38 {
39         return 0;
40 }
41
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)
50 {
51         struct dcerpc_binding_handle *h;
52         void **ppstate = (void **)pstate;
53         void *state;
54
55         h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
56         if (h == NULL) {
57                 return NULL;
58         }
59         h->ops          = ops;
60         h->location     = location;
61         h->object       = object;
62         h->table        = table;
63
64         state = talloc_zero_size(h, psize);
65         if (state == NULL) {
66                 talloc_free(h);
67                 return NULL;
68         }
69         talloc_set_name_const(state, type);
70
71         h->private_data = state;
72
73         talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74
75         *ppstate = state;
76         return h;
77 }
78
79 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80 {
81         return h->private_data;
82 }
83
84 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85                                        struct tevent_context *ev)
86 {
87         h->sync_ev = ev;
88 }
89
90 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91 {
92         return h->ops->is_connected(h);
93 }
94
95 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
96                                            uint32_t timeout)
97 {
98         return h->ops->set_timeout(h, timeout);
99 }
100
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;
106 };
107
108 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
109
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)
118 {
119         struct tevent_req *req;
120         struct dcerpc_binding_handle_raw_call_state *state;
121         struct tevent_req *subreq;
122
123         req = tevent_req_create(mem_ctx, &state,
124                                 struct dcerpc_binding_handle_raw_call_state);
125         if (req == NULL) {
126                 return NULL;
127         }
128         state->ops = h->ops;
129         state->out_data = NULL;
130         state->out_length = 0;
131         state->out_flags = 0;
132
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);
138         }
139         tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
140
141         return req;
142 }
143
144 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
145 {
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;
152
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;
161         }
162
163         tevent_req_done(req);
164 }
165
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)
171 {
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;
176
177         if (tevent_req_is_nterror(req, &error)) {
178                 tevent_req_received(req);
179                 return error;
180         }
181
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;
187 }
188
189 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
190                                         const struct GUID *object,
191                                         uint32_t opnum,
192                                         uint32_t in_flags,
193                                         const uint8_t *in_data,
194                                         size_t in_length,
195                                         TALLOC_CTX *mem_ctx,
196                                         uint8_t **out_data,
197                                         size_t *out_length,
198                                         uint32_t *out_flags)
199 {
200         TALLOC_CTX *frame = talloc_stackframe();
201         struct tevent_context *ev;
202         struct tevent_req *subreq;
203         NTSTATUS status;
204
205         /*
206          * TODO: allow only one sync call
207          */
208
209         if (h->sync_ev) {
210                 ev = h->sync_ev;
211         } else {
212                 ev = tevent_context_init(frame);
213         }
214         if (ev == NULL) {
215                 talloc_free(frame);
216                 return NT_STATUS_NO_MEMORY;
217         }
218
219         subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
220                                                      h, object, opnum,
221                                                      in_flags,
222                                                      in_data,
223                                                      in_length);
224         if (subreq == NULL) {
225                 talloc_free(frame);
226                 return NT_STATUS_NO_MEMORY;
227         }
228
229         if (!tevent_req_poll(subreq, ev)) {
230                 status = map_nt_error_from_unix(errno);
231                 talloc_free(frame);
232                 return status;
233         }
234
235         status = dcerpc_binding_handle_raw_call_recv(subreq,
236                                                      mem_ctx,
237                                                      out_data,
238                                                      out_length,
239                                                      out_flags);
240         if (!NT_STATUS_IS_OK(status)) {
241                 talloc_free(frame);
242                 return status;
243         }
244
245         TALLOC_FREE(frame);
246         return NT_STATUS_OK;
247 }
248
249 struct dcerpc_binding_handle_disconnect_state {
250         const struct dcerpc_binding_handle_ops *ops;
251 };
252
253 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
254
255 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
256                                                 struct tevent_context *ev,
257                                                 struct dcerpc_binding_handle *h)
258 {
259         struct tevent_req *req;
260         struct dcerpc_binding_handle_disconnect_state *state;
261         struct tevent_req *subreq;
262
263         req = tevent_req_create(mem_ctx, &state,
264                                 struct dcerpc_binding_handle_disconnect_state);
265         if (req == NULL) {
266                 return NULL;
267         }
268
269         state->ops = h->ops;
270
271         subreq = state->ops->disconnect_send(state, ev, h);
272         if (tevent_req_nomem(subreq, req)) {
273                 return tevent_req_post(req, ev);
274         }
275         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
276
277         return req;
278 }
279
280 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
281 {
282         struct tevent_req *req = tevent_req_callback_data(subreq,
283                                  struct tevent_req);
284         struct dcerpc_binding_handle_disconnect_state *state =
285                 tevent_req_data(req,
286                 struct dcerpc_binding_handle_disconnect_state);
287         NTSTATUS error;
288
289         error = state->ops->disconnect_recv(subreq);
290         TALLOC_FREE(subreq);
291         if (!NT_STATUS_IS_OK(error)) {
292                 tevent_req_nterror(req, error);
293                 return;
294         }
295
296         tevent_req_done(req);
297 }
298
299 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
300 {
301         NTSTATUS error;
302
303         if (tevent_req_is_nterror(req, &error)) {
304                 tevent_req_received(req);
305                 return error;
306         }
307
308         tevent_req_received(req);
309         return NT_STATUS_OK;
310 }
311
312 struct dcerpc_binding_handle_call_state {
313         struct dcerpc_binding_handle *h;
314         const struct ndr_interface_call *call;
315         TALLOC_CTX *r_mem;
316         void *r_ptr;
317         struct ndr_push *push;
318         DATA_BLOB request;
319         DATA_BLOB response;
320         struct ndr_pull *pull;
321 };
322
323 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
324
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,
330                                         uint32_t opnum,
331                                         TALLOC_CTX *r_mem,
332                                         void *r_ptr)
333 {
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;
338
339         req = tevent_req_create(mem_ctx, &state,
340                                 struct dcerpc_binding_handle_call_state);
341         if (req == NULL) {
342                 return NULL;
343         }
344
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);
349         }
350 #endif
351
352         if (opnum >= table->num_calls) {
353                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
354                 return tevent_req_post(req, ev);
355         }
356
357         state->h = h;
358         state->call = &table->calls[opnum];
359
360         state->r_mem = r_mem;
361         state->r_ptr = r_ptr;
362
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);
367         }
368
369         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
370                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
371         }
372
373         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
374                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
375         }
376
377         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
378                 state->push->flags |= LIBNDR_FLAG_NDR64;
379         }
380
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);
384         }
385
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)) {
389                 NTSTATUS error;
390                 error = ndr_map_error2ntstatus(ndr_err);
391                 if (h->ops->ndr_push_failed) {
392                         h->ops->ndr_push_failed(h, error,
393                                                 state->r_ptr,
394                                                 state->call);
395                 }
396                 tevent_req_nterror(req, error);
397                 return tevent_req_post(req, ev);
398         }
399
400         /* retrieve the blob */
401         state->request = ndr_push_blob(state->push);
402
403         if (h->ops->ndr_validate_in) {
404                 NTSTATUS error;
405                 error = h->ops->ndr_validate_in(h, state,
406                                                 &state->request,
407                                                 state->call);
408                 if (!NT_STATUS_IS_OK(error)) {
409                         tevent_req_nterror(req, error);
410                         return tevent_req_post(req, ev);
411                 }
412         }
413
414         subreq = dcerpc_binding_handle_raw_call_send(state, ev,
415                                                      h, object, opnum,
416                                                      state->push->flags,
417                                                      state->request.data,
418                                                      state->request.length);
419         if (tevent_req_nomem(subreq, req)) {
420                 return tevent_req_post(req, ev);
421         }
422         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
423
424         return req;
425 }
426
427 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
428 {
429         struct tevent_req *req = tevent_req_callback_data(subreq,
430                                  struct tevent_req);
431         struct dcerpc_binding_handle_call_state *state =
432                 tevent_req_data(req,
433                 struct dcerpc_binding_handle_call_state);
434         struct dcerpc_binding_handle *h = state->h;
435         NTSTATUS error;
436         uint32_t out_flags = 0;
437         enum ndr_err_code ndr_err;
438
439         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
440                                                     &state->response.data,
441                                                     &state->response.length,
442                                                     &out_flags);
443         TALLOC_FREE(subreq);
444         if (!NT_STATUS_IS_OK(error)) {
445                 tevent_req_nterror(req, error);
446                 return;
447         }
448
449         state->pull = ndr_pull_init_blob(&state->response, state);
450         if (tevent_req_nomem(state->pull, req)) {
451                 return;
452         }
453         state->pull->flags = state->push->flags;
454
455         if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
456                 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
457         } else {
458                 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
459         }
460
461         state->pull->current_mem_ctx = state->r_mem;
462
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,
469                                                 &state->response,
470                                                 state->call);
471                 }
472                 tevent_req_nterror(req, error);
473                 return;
474         }
475
476         if (h->ops->do_ndr_print) {
477                 h->ops->do_ndr_print(h, NDR_OUT,
478                                      state->r_ptr, state->call);
479         }
480
481         if (h->ops->ndr_validate_out) {
482                 error = h->ops->ndr_validate_out(h,
483                                                  state->pull,
484                                                  state->r_ptr,
485                                                  state->call);
486                 if (!NT_STATUS_IS_OK(error)) {
487                         tevent_req_nterror(req, error);
488                         return;
489                 }
490         }
491
492         tevent_req_done(req);
493 }
494
495 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
496 {
497         NTSTATUS error;
498
499         if (tevent_req_is_nterror(req, &error)) {
500                 tevent_req_received(req);
501                 return error;
502         }
503
504         tevent_req_received(req);
505         return NT_STATUS_OK;
506 }
507
508 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
509                                     const struct GUID *object,
510                                     const struct ndr_interface_table *table,
511                                     uint32_t opnum,
512                                     TALLOC_CTX *r_mem,
513                                     void *r_ptr)
514 {
515         TALLOC_CTX *frame = talloc_stackframe();
516         struct tevent_context *ev;
517         struct tevent_req *subreq;
518         NTSTATUS status;
519
520         /*
521          * TODO: allow only one sync call
522          */
523
524         if (h->sync_ev) {
525                 ev = h->sync_ev;
526         } else {
527                 ev = tevent_context_init(frame);
528         }
529         if (ev == NULL) {
530                 talloc_free(frame);
531                 return NT_STATUS_NO_MEMORY;
532         }
533
534         subreq = dcerpc_binding_handle_call_send(frame, ev,
535                                                  h, object, table,
536                                                  opnum, r_mem, r_ptr);
537         if (subreq == NULL) {
538                 talloc_free(frame);
539                 return NT_STATUS_NO_MEMORY;
540         }
541
542         if (!tevent_req_poll(subreq, ev)) {
543                 status = map_nt_error_from_unix(errno);
544                 talloc_free(frame);
545                 return status;
546         }
547
548         status = dcerpc_binding_handle_call_recv(subreq);
549         if (!NT_STATUS_IS_OK(status)) {
550                 talloc_free(frame);
551                 return status;
552         }
553
554         TALLOC_FREE(frame);
555         return NT_STATUS_OK;
556 }