TODO librpc/rpc: add DCERPC pipe support to dcerpc_binding_handle_call_params_send...
[metze/samba/wip.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 void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
102                                      enum dcerpc_AuthType *auth_type,
103                                      enum dcerpc_AuthLevel *auth_level)
104 {
105         enum dcerpc_AuthType _auth_type;
106         enum dcerpc_AuthLevel _auth_level;
107
108         if (auth_type == NULL) {
109                 auth_type = &_auth_type;
110         }
111
112         if (auth_level == NULL) {
113                 auth_level = &_auth_level;
114         }
115
116         *auth_type = DCERPC_AUTH_TYPE_NONE;
117         *auth_level = DCERPC_AUTH_LEVEL_NONE;
118
119         if (h->ops->auth_info == NULL) {
120                 return;
121         }
122
123         h->ops->auth_info(h, auth_type, auth_level);
124 }
125
126 struct dcerpc_binding_handle_raw_call_state {
127         const struct dcerpc_binding_handle_ops *ops;
128         struct tevent_context *ev;
129         struct tevent_req *subreq;
130 };
131
132 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
133
134 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
135                                                 struct tevent_context *ev,
136                                                 struct dcerpc_binding_handle *h,
137                                                 const struct GUID *object,
138                                                 uint32_t opnum,
139                                                 uint32_t in_flags,
140                                                 const uint8_t *in_data,
141                                                 size_t in_length)
142 {
143         struct tevent_req *req;
144         struct dcerpc_binding_handle_raw_call_state *state;
145
146         req = tevent_req_create(mem_ctx, &state,
147                                 struct dcerpc_binding_handle_raw_call_state);
148         if (req == NULL) {
149                 return NULL;
150         }
151         state->ops = h->ops;
152         state->ev = ev;
153
154         if (h->object != NULL) {
155                 /*
156                  * If an object is set on the binding handle,
157                  * per request object passing is not allowed.
158                  */
159                 if (object != NULL) {
160                         tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
161                         return tevent_req_post(req, ev);
162                 }
163
164                 /*
165                  * We use the object from the binding handle
166                  */
167                 object = h->object;
168         }
169
170         if (state->ops->raw_call_in_send == NULL) {
171                 if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
172                         tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
173                         return tevent_req_post(req, ev);
174                 }
175         }
176
177         state->subreq = state->ops->raw_call_send(state, ev, h,
178                                                   object, opnum,
179                                                   in_flags, in_data, in_length);
180         if (tevent_req_nomem(state->subreq, req)) {
181                 return tevent_req_post(req, ev);
182         }
183         tevent_req_set_callback(state->subreq,
184                                 dcerpc_binding_handle_raw_call_done,
185                                 req);
186
187         return req;
188 }
189
190 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
191 {
192         struct tevent_req *req =
193                 tevent_req_callback_data(subreq,
194                 struct tevent_req);
195
196         if (tevent_req_is_in_progress(subreq)) {
197                 tevent_req_notify_callback(req);
198                 return;
199         }
200
201         tevent_req_done(req);
202 }
203
204 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
205                                              TALLOC_CTX *mem_ctx,
206                                              uint8_t **out_data,
207                                              size_t *out_length,
208                                              uint32_t *out_flags)
209 {
210         struct dcerpc_binding_handle_raw_call_state *state =
211                 tevent_req_data(req,
212                 struct dcerpc_binding_handle_raw_call_state);
213         NTSTATUS error;
214
215         if (!tevent_req_is_in_progress(req)) {
216                 if (tevent_req_is_nterror(req, &error)) {
217                         tevent_req_received(req);
218                         return error;
219                 }
220         }
221
222         error = state->ops->raw_call_recv(state->subreq,
223                                           mem_ctx,
224                                           out_data,
225                                           out_length,
226                                           out_flags);
227         if (!NT_STATUS_IS_OK(error)) {
228                 tevent_req_received(req);
229                 return error;
230         }
231
232         if (tevent_req_is_in_progress(state->subreq)) {
233                 return NT_STATUS_OK;
234         }
235
236         tevent_req_received(req);
237         return NT_STATUS_OK;
238 }
239
240 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
241                                         const struct GUID *object,
242                                         uint32_t opnum,
243                                         uint32_t in_flags,
244                                         const uint8_t *in_data,
245                                         size_t in_length,
246                                         TALLOC_CTX *mem_ctx,
247                                         uint8_t **out_data,
248                                         size_t *out_length,
249                                         uint32_t *out_flags)
250 {
251         TALLOC_CTX *frame = talloc_stackframe();
252         struct tevent_context *ev;
253         struct tevent_req *subreq;
254         NTSTATUS status = NT_STATUS_NO_MEMORY;
255
256         /*
257          * TODO: allow only one sync call
258          */
259
260         if (h->sync_ev) {
261                 ev = h->sync_ev;
262         } else {
263                 ev = samba_tevent_context_init(frame);
264         }
265         if (ev == NULL) {
266                 goto fail;
267         }
268
269         if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
270                 talloc_free(frame);
271                 return NT_STATUS_INVALID_PARAMETER_MIX;
272         }
273
274         subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
275                                                      h, object, opnum,
276                                                      in_flags,
277                                                      in_data,
278                                                      in_length);
279         if (subreq == NULL) {
280                 goto fail;
281         }
282
283         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
284                 goto fail;
285         }
286
287         status = dcerpc_binding_handle_raw_call_recv(subreq,
288                                                      mem_ctx,
289                                                      out_data,
290                                                      out_length,
291                                                      out_flags);
292 fail:
293         TALLOC_FREE(frame);
294         return status;
295 }
296
297 struct dcerpc_binding_handle_raw_call_in_state {
298         const struct dcerpc_binding_handle_ops *ops;
299         struct tevent_context *ev;
300         struct tevent_req *subreq;
301 };
302
303 static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq);
304
305 struct tevent_req *dcerpc_binding_handle_raw_call_in_send(TALLOC_CTX *mem_ctx,
306                                                 struct tevent_context *ev,
307                                                 struct tevent_req *raw_call_req,
308                                                 uint32_t in_flags,
309                                                 const uint8_t *in_data,
310                                                 size_t in_length)
311 {
312         struct dcerpc_binding_handle_raw_call_state *raw_call_state =
313                 tevent_req_data(raw_call_req,
314                 struct dcerpc_binding_handle_raw_call_state);
315         struct tevent_req *req;
316         struct dcerpc_binding_handle_raw_call_in_state *state;
317
318         req = tevent_req_create(mem_ctx, &state,
319                                 struct dcerpc_binding_handle_raw_call_in_state);
320         if (req == NULL) {
321                 return NULL;
322         }
323         state->ops = raw_call_state->ops;
324         state->ev = ev;
325
326         if (state->ev != raw_call_state->ev) {
327                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
328                 return tevent_req_post(req, ev);
329         }
330
331         if (state->ops->raw_call_in_send == NULL) {
332                 tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
333                 return tevent_req_post(req, ev);
334         }
335
336         state->subreq = state->ops->raw_call_in_send(state, ev,
337                                                      raw_call_state->subreq,
338                                                      in_flags,
339                                                      in_data,
340                                                      in_length);
341         if (tevent_req_nomem(state->subreq, req)) {
342                 return tevent_req_post(req, ev);
343         }
344
345         tevent_req_set_callback(state->subreq,
346                                 dcerpc_binding_handle_raw_call_in_done,
347                                 req);
348         return req;
349 }
350
351 static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq)
352 {
353         struct tevent_req *req =
354                 tevent_req_callback_data(subreq,
355                 struct tevent_req);
356
357         if (tevent_req_is_in_progress(subreq)) {
358                 tevent_req_notify_callback(req);
359                 return;
360         }
361
362         tevent_req_done(req);
363 }
364
365 NTSTATUS dcerpc_binding_handle_raw_call_in_recv(struct tevent_req *req)
366 {
367         struct dcerpc_binding_handle_raw_call_in_state *state =
368                 tevent_req_data(req,
369                 struct dcerpc_binding_handle_raw_call_in_state);
370         NTSTATUS error;
371
372         if (!tevent_req_is_in_progress(req)) {
373                 if (tevent_req_is_nterror(req, &error)) {
374                         tevent_req_received(req);
375                         return error;
376                 }
377         }
378
379         error = state->ops->raw_call_in_recv(state->subreq);
380         if (!NT_STATUS_IS_OK(error)) {
381                 tevent_req_received(req);
382                 return error;
383         }
384
385         if (tevent_req_is_in_progress(state->subreq)) {
386                 return NT_STATUS_OK;
387         }
388
389         tevent_req_received(req);
390         return error;
391 }
392
393 struct dcerpc_binding_handle_disconnect_state {
394         const struct dcerpc_binding_handle_ops *ops;
395 };
396
397 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
398
399 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
400                                                 struct tevent_context *ev,
401                                                 struct dcerpc_binding_handle *h)
402 {
403         struct tevent_req *req;
404         struct dcerpc_binding_handle_disconnect_state *state;
405         struct tevent_req *subreq;
406
407         req = tevent_req_create(mem_ctx, &state,
408                                 struct dcerpc_binding_handle_disconnect_state);
409         if (req == NULL) {
410                 return NULL;
411         }
412
413         state->ops = h->ops;
414
415         subreq = state->ops->disconnect_send(state, ev, h);
416         if (tevent_req_nomem(subreq, req)) {
417                 return tevent_req_post(req, ev);
418         }
419         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
420
421         return req;
422 }
423
424 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
425 {
426         struct tevent_req *req = tevent_req_callback_data(subreq,
427                                  struct tevent_req);
428         struct dcerpc_binding_handle_disconnect_state *state =
429                 tevent_req_data(req,
430                 struct dcerpc_binding_handle_disconnect_state);
431         NTSTATUS error;
432
433         error = state->ops->disconnect_recv(subreq);
434         TALLOC_FREE(subreq);
435         if (tevent_req_nterror(req, error)) {
436                 return;
437         }
438
439         tevent_req_done(req);
440 }
441
442 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
443 {
444         NTSTATUS error;
445
446         if (tevent_req_is_nterror(req, &error)) {
447                 tevent_req_received(req);
448                 return error;
449         }
450
451         tevent_req_received(req);
452         return NT_STATUS_OK;
453 }
454
455 struct dcerpc_binding_handle_call_params_state {
456         struct dcerpc_binding_handle *h;
457         const struct ndr_interface_call *call;
458         struct dcerpc_binding_handle_call_params *params;
459         uint32_t in_flags;
460         struct ndr_push *push;
461         DATA_BLOB request;
462         struct tevent_req *subreq;
463         DATA_BLOB response;
464         struct ndr_pull *pull;
465
466         struct dcerpc_pipe_handle *ph;
467         struct dcerpc_pipe_handle_connection *pc;
468         const struct ndr_interface_call_pipe *call_pipe;
469         uint32_t in_pipe_idx;
470         uint32_t out_pipe_idx;
471 };
472
473 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq);
474 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req);
475 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq);
476 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req);
477 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p);
478
479 struct tevent_req *dcerpc_binding_handle_call_params_send(TALLOC_CTX *mem_ctx,
480                                 struct tevent_context *ev,
481                                 struct dcerpc_binding_handle *h,
482                                 const struct GUID *object,
483                                 const struct ndr_interface_table *table,
484                                 uint32_t opnum,
485                                 struct dcerpc_binding_handle_call_params *params)
486 {
487         struct tevent_req *req;
488         struct dcerpc_binding_handle_call_params_state *state;
489         enum ndr_err_code ndr_err;
490
491         req = tevent_req_create(mem_ctx, &state,
492                                 struct dcerpc_binding_handle_call_params_state);
493         if (req == NULL) {
494                 return NULL;
495         }
496
497         if (table != h->table) {
498                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
499                 return tevent_req_post(req, ev);
500         }
501
502         if (opnum >= table->num_calls) {
503                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
504                 return tevent_req_post(req, ev);
505         }
506
507         state->h = h;
508         state->call = &table->calls[opnum];
509         state->params = params;
510
511         if (params->in.num_pipes != state->call->in_pipes.num_pipes) {
512                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
513                 return tevent_req_post(req, ev);
514         }
515
516         if (params->out.num_pipes != state->call->out_pipes.num_pipes) {
517                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
518                 return tevent_req_post(req, ev);
519         }
520
521         /* setup for a ndr_push_* call */
522         state->push = ndr_push_init_ctx(state);
523         if (tevent_req_nomem(state->push, req)) {
524                 return tevent_req_post(req, ev);
525         }
526
527         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
528                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
529         }
530
531         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
532                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
533                 state->in_flags |= LIBNDR_FLAG_BIGENDIAN;
534         }
535
536         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
537                 state->push->flags |= LIBNDR_FLAG_NDR64;
538         }
539
540         if (h->ops->do_ndr_print) {
541                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
542                                      state->params->r_ptr, state->call);
543         }
544
545         /* push the structure into a blob */
546         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->params->r_ptr);
547         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
548                 NTSTATUS error;
549                 error = ndr_map_error2ntstatus(ndr_err);
550                 if (h->ops->ndr_push_failed) {
551                         h->ops->ndr_push_failed(h, error,
552                                                 state->params->r_ptr,
553                                                 state->call);
554                 }
555                 tevent_req_nterror(req, error);
556                 return tevent_req_post(req, ev);
557         }
558
559         /* retrieve the blob */
560         state->request = ndr_push_blob(state->push);
561
562         if (h->ops->ndr_validate_in) {
563                 NTSTATUS error;
564                 error = h->ops->ndr_validate_in(h, state,
565                                                 &state->request,
566                                                 state->call);
567                 if (!NT_STATUS_IS_OK(error)) {
568                         tevent_req_nterror(req, error);
569                         return tevent_req_post(req, ev);
570                 }
571         }
572
573         if (params->in.num_pipes != 0) {
574                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
575
576                 /*
577                  * push alignment for the next pipe chunk
578                  */
579                 ndr_err = ndr_push_align(state->push, 5);
580                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
581                         NTSTATUS error;
582                         error = ndr_map_error2ntstatus(ndr_err);
583                         tevent_req_nterror(req, error);
584                         return tevent_req_post(req, ev);
585                 }
586         }
587
588         if (params->out.num_pipes != 0) {
589                 /*
590                  * even if we only have output pipes we need to indicate that
591                  * we want to get incomplete results
592                  */
593                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
594         }
595
596         if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
597                 dcerpc_binding_handle_call_params_pipe_setup(req);
598                 if (!tevent_req_is_in_progress(state->subreq)) {
599                         return tevent_req_post(req, ev);
600                 }
601         }
602
603         /* retrieve the blob - including possible pipe chunk alignment */
604         state->request = ndr_push_blob(state->push);
605
606         state->subreq = dcerpc_binding_handle_raw_call_send(state, ev,
607                                                 h, object, opnum,
608                                                 state->in_flags,
609                                                 state->request.data,
610                                                 state->request.length);
611         if (tevent_req_nomem(state->subreq, req)) {
612                 return tevent_req_post(req, ev);
613         }
614         tevent_req_set_callback(state->subreq,
615                                 dcerpc_binding_handle_call_params_done,
616                                 req);
617
618         if (!(state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
619                 /*
620                  * we didn't ask for any pipes
621                  *
622                  * Indicate that all pipes are done.
623                  */
624                 state->in_pipe_idx = UINT32_MAX;
625                 state->out_pipe_idx = UINT32_MAX;
626                 return req;
627         }
628
629         /*
630          * If the subreq is already finished, the backend
631          * may not support LIBNDR_FLAG_INCOMPLETE_BUFFER
632          */
633         if (!tevent_req_is_in_progress(state->subreq)) {
634                 return req;
635         }
636
637         if (state->params->in.num_pipes == 0) {
638                 struct tevent_req *subreq;
639
640                 /*
641                  * We have only out pipes,
642                  * so indicate that we're done with sending in_data.
643                  */
644                 state->in_pipe_idx = UINT32_MAX;
645                 state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
646                 subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
647                                                                 state->subreq,
648                                                                 state->in_flags,
649                                                                 NULL, /* in_data */
650                                                                 0); /* in_length */
651                 if (tevent_req_nomem(subreq, req)) {
652                         return tevent_req_post(req, ev);
653                 }
654                 tevent_req_set_callback(subreq,
655                                         dcerpc_binding_handle_call_params_in_done,
656                                         req);
657                 return req;
658         }
659
660         dcerpc_binding_handle_call_params_next_pipe(req);
661         if (!tevent_req_is_in_progress(req)) {
662                 return tevent_req_post(req, ev);
663         }
664
665         return req;
666 }
667
668 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq)
669 {
670         struct tevent_req *req = tevent_req_callback_data(subreq,
671                                  struct tevent_req);
672         NTSTATUS error;
673
674         error = dcerpc_binding_handle_raw_call_in_recv(subreq);
675         TALLOC_FREE(subreq);
676         if (tevent_req_nterror(req, error)) {
677                 return;
678         }
679
680         dcerpc_binding_handle_call_params_next_pipe(req);
681 }
682
683 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req)
684 {
685         struct dcerpc_binding_handle_call_params_state *state =
686                 tevent_req_data(req,
687                 struct dcerpc_binding_handle_call_params_state);
688         struct dcerpc_binding_handle_call_params *params = state->params;
689         bool ok;
690
691         dcerpc_pipe_handle_connection_disconnect(state->pc);
692         state->pc = NULL;
693         state->call_pipe = NULL;
694
695         if (state->in_pipe_idx < params->in.num_pipes) {
696                 uint32_t idx = state->in_pipe_idx++;
697
698                 state->pc = params->in.pipes[idx];
699                 state->call_pipe = &state->call->in_pipes.pipes[idx];
700
701                 ok = dcerpc_pipe_handle_connection_push_connect(state->pc,
702                                         state->call_pipe->chunk_struct_name,
703                                         state->call_pipe->chunk_struct_size,
704                                         state->ph);
705                 if (!ok) {
706                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
707                         return;
708                 }
709
710                 return;
711         }
712         state->in_pipe_idx = UINT32_MAX;
713
714         if (state->out_pipe_idx < params->out.num_pipes) {
715                 uint32_t idx = state->out_pipe_idx++;
716
717                 state->pc = params->out.pipes[idx];
718                 state->call_pipe = &state->call->out_pipes.pipes[idx];
719
720                 ok = dcerpc_pipe_handle_connection_pull_connect(state->pc,
721                                         state->call_pipe->chunk_struct_name,
722                                         state->call_pipe->chunk_struct_size,
723                                         state->ph);
724                 if (!ok) {
725                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
726                         return;
727                 }
728
729                 return;
730         }
731         state->out_pipe_idx = UINT32_MAX;
732 }
733
734 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq)
735 {
736         struct tevent_req *req = tevent_req_callback_data(subreq,
737                                  struct tevent_req);
738         struct dcerpc_binding_handle_call_params_state *state =
739                 tevent_req_data(req,
740                 struct dcerpc_binding_handle_call_params_state);
741         struct dcerpc_binding_handle *h = state->h;
742         NTSTATUS error;
743         uint32_t out_flags = 0;
744         enum ndr_err_code ndr_err;
745
746         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
747                                                     &state->response.data,
748                                                     &state->response.length,
749                                                     &out_flags);
750         subreq = NULL;
751         if (!NT_STATUS_IS_OK(error)) {
752                 TALLOC_FREE(state->subreq);
753                 tevent_req_nterror(req, error);
754                 return;
755         }
756
757         if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
758                 TALLOC_FREE(state->subreq);
759         }
760
761         if (state->in_pipe_idx != UINT32_MAX) {
762                 /*
763                  * we haven't send all data yet,
764                  * this is a protocol error
765                  */
766                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
767                 return;
768         }
769
770         if (state->pull == NULL) {
771                 state->pull = ndr_pull_init_blob(&state->response, state);
772                 if (tevent_req_nomem(state->pull, req)) {
773                         return;
774                 }
775                 state->pull->flags = state->push->flags;
776
777                 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
778                         state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
779                 } else {
780                         state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
781                 }
782
783                 if (out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
784                         state->pull->flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
785                 }
786         } else {
787                 if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
788                         state->pull->flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
789                 }
790
791                 //ndr_err = ndr_pull_append_blob(state->pull,
792                 //                             &state->response);
793                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
794                         error = ndr_map_error2ntstatus(ndr_err);
795                         if (h->ops->ndr_pull_failed) {
796                                 h->ops->ndr_pull_failed(h, error,
797                                                         &state->response,
798                                                         state->call);
799                         }
800                         tevent_req_nterror(req, error);
801                         return;
802                 }
803         }
804
805         if (state->out_pipe_idx != UINT32_MAX) {
806                 dcerpc_binding_handle_call_params_pipe_notify(state->ph);
807                 return;
808         }
809
810         state->pull->current_mem_ctx = state->params->r_mem;
811
812         /* pull the structure from the blob */
813         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT,
814                                         state->params->r_ptr);
815         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
816                 error = ndr_map_error2ntstatus(ndr_err);
817                 if (h->ops->ndr_pull_failed) {
818                         h->ops->ndr_pull_failed(h, error,
819                                                 &state->response,
820                                                 state->call);
821                 }
822                 tevent_req_nterror(req, error);
823                 return;
824         }
825
826         if (h->ops->do_ndr_print) {
827                 h->ops->do_ndr_print(h, NDR_OUT,
828                                      state->params->r_ptr, state->call);
829         }
830
831         if (h->ops->ndr_validate_out) {
832                 error = h->ops->ndr_validate_out(h,
833                                                  state->pull,
834                                                  state->params->r_ptr,
835                                                  state->call);
836                 if (!NT_STATUS_IS_OK(error)) {
837                         tevent_req_nterror(req, error);
838                         return;
839                 }
840         }
841
842         tevent_req_done(req);
843 }
844
845 NTSTATUS dcerpc_binding_handle_call_params_recv(struct tevent_req *req)
846 {
847         return tevent_req_simple_recv_ntstatus(req);
848 }
849
850 struct dcerpc_binding_handle_call_params_pipe {
851         struct tevent_req *call_req;
852         struct tevent_req *pull_req;
853 };
854
855 struct dcerpc_binding_handle_call_params_push_state {
856         struct tevent_context *ev;
857         struct dcerpc_pipe_handle *p;
858         struct ndr_push *push;
859         DATA_BLOB chunk_blob;
860         bool is_last_chunk;
861 };
862
863 static int dcerpc_binding_handle_call_params_push_state_destructor(
864         struct dcerpc_binding_handle_call_params_push_state *state)
865 {
866         struct dcerpc_binding_handle_call_params_pipe *pp =
867                 dcerpc_pipe_handle_data(state->p,
868                 struct dcerpc_binding_handle_call_params_pipe);
869         struct dcerpc_binding_handle_call_params_state *call_state =
870                 tevent_req_data(pp->call_req,
871                 struct dcerpc_binding_handle_call_params_state);
872
873         dcerpc_pipe_handle_connection_disconnect(call_state->pc);
874         call_state->pc = NULL;
875         call_state->call_pipe = NULL;
876         return 0;
877 }
878
879 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq);
880
881 static struct tevent_req *dcerpc_binding_handle_call_params_push_send(TALLOC_CTX *mem_ctx,
882                                         struct tevent_context *ev,
883                                         struct dcerpc_pipe_handle *p,
884                                         const void *chunk_ptr)
885 {
886         struct dcerpc_binding_handle_call_params_pipe *pp =
887                 dcerpc_pipe_handle_data(p,
888                 struct dcerpc_binding_handle_call_params_pipe);
889         struct dcerpc_binding_handle_call_params_state *call_state =
890                 tevent_req_data(pp->call_req,
891                 struct dcerpc_binding_handle_call_params_state);
892         struct tevent_req *req;
893         struct dcerpc_binding_handle_call_params_push_state *state;
894         struct tevent_req *subreq;
895         enum ndr_err_code ndr_err;
896         const uint32_t *count = NULL;
897         bool is_last_pipe = false;
898
899         req = tevent_req_create(mem_ctx, &state,
900                                 struct dcerpc_binding_handle_call_params_push_state);
901         if (req == NULL) {
902                 return NULL;
903         }
904         state->ev = ev;
905         state->p = p;
906
907         talloc_set_destructor(state,
908                               dcerpc_binding_handle_call_params_push_state_destructor);
909
910         /* setup for a ndr_push_* call */
911         state->push = ndr_push_init_ctx(state);
912         if (tevent_req_nomem(state->push, req)) {
913                 return tevent_req_post(req, ev);
914         }
915
916         state->push->flags = call_state->push->flags;
917
918         //if (h->ops->do_ndr_print) {
919         //      h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
920         //                           state->params->r_ptr, state->call);
921         //}
922
923         /* push the structure into a blob */
924         ndr_err = call_state->call_pipe->ndr_push(state->push,
925                                                   NDR_SCALARS|NDR_BUFFERS,
926                                                   chunk_ptr);
927         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
928                 NTSTATUS error;
929                 error = ndr_map_error2ntstatus(ndr_err);
930                 //if (h->ops->ndr_push_failed) {
931                 //      h->ops->ndr_push_failed(h, error,
932                 //                              state->params->r_ptr,
933                 //                              state->call);
934                 //}
935                 tevent_req_nterror(req, error);
936                 return tevent_req_post(req, ev);
937         }
938
939         /*
940          * Note: the first struct member is always
941          * 'uint32_t count;'
942          */
943         count = (const uint32_t *)chunk_ptr;
944
945         state->is_last_chunk = false;
946         if (*count == 0) {
947                 state->is_last_chunk = true;
948         }
949
950         if (call_state->in_pipe_idx >= call_state->params->in.num_pipes) {
951                 is_last_pipe = true;
952         }
953
954         if (is_last_pipe && state->is_last_chunk) {
955                 call_state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
956         } else {
957                 /*
958                  * push alignment for the next pipe chunk
959                  */
960                 ndr_err = ndr_push_align(state->push, 5);
961                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
962                         NTSTATUS error;
963                         error = ndr_map_error2ntstatus(ndr_err);
964                         tevent_req_nterror(req, error);
965                         return tevent_req_post(req, ev);
966                 }
967         }
968
969         /* retrieve the blob - including possible alignment for the next chunk */
970         state->chunk_blob = ndr_push_blob(state->push);
971
972         subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
973                                                         call_state->subreq,
974                                                         call_state->in_flags,
975                                                         state->chunk_blob.data,
976                                                         state->chunk_blob.length);
977         if (tevent_req_nomem(subreq, req)) {
978                 return tevent_req_post(req, ev);
979         }
980         tevent_req_set_callback(subreq,
981                                 dcerpc_binding_handle_call_params_push_done,
982                                 req);
983
984         return req;
985 }
986
987 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq)
988 {
989         struct tevent_req *req =
990                 tevent_req_callback_data(subreq,
991                 struct tevent_req);
992         struct dcerpc_binding_handle_call_params_push_state *state =
993                 tevent_req_data(req,
994                 struct dcerpc_binding_handle_call_params_push_state);
995         struct dcerpc_binding_handle_call_params_pipe *pp =
996                 dcerpc_pipe_handle_data(state->p,
997                 struct dcerpc_binding_handle_call_params_pipe);
998         NTSTATUS status;
999
1000         status = dcerpc_binding_handle_raw_call_in_recv(subreq);
1001         TALLOC_FREE(subreq);
1002         TALLOC_FREE(state->push);
1003         if (tevent_req_nterror(req, status)) {
1004                 return;
1005         }
1006
1007         talloc_set_destructor(state, NULL);
1008
1009         if (!state->is_last_chunk) {
1010                 tevent_req_done(req);
1011                 return;
1012         }
1013
1014         tevent_req_defer_callback(req, state->ev);
1015         tevent_req_done(req);
1016         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1017 }
1018
1019 static NTSTATUS dcerpc_binding_handle_call_params_push_recv(struct tevent_req *req)
1020 {
1021         return tevent_req_simple_recv_ntstatus(req);
1022 }
1023
1024 struct dcerpc_binding_handle_call_params_pull_state {
1025         struct tevent_context *ev;
1026         struct dcerpc_pipe_handle *p;
1027         void *chunk_mem;
1028         void *chunk_ptr;
1029 };
1030
1031 static int dcerpc_binding_handle_call_params_pull_state_destructor(
1032         struct dcerpc_binding_handle_call_params_pull_state *state)
1033 {
1034         struct dcerpc_binding_handle_call_params_pipe *pp =
1035                 dcerpc_pipe_handle_data(state->p,
1036                 struct dcerpc_binding_handle_call_params_pipe);
1037         struct dcerpc_binding_handle_call_params_state *call_state =
1038                 tevent_req_data(pp->call_req,
1039                 struct dcerpc_binding_handle_call_params_state);
1040
1041         pp->pull_req = NULL;
1042
1043         dcerpc_pipe_handle_connection_disconnect(call_state->pc);
1044         call_state->pc = NULL;
1045         call_state->call_pipe = NULL;
1046         return 0;
1047 }
1048
1049 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req);
1050
1051 static struct tevent_req *dcerpc_binding_handle_call_params_pull_send(TALLOC_CTX *mem_ctx,
1052                                         struct tevent_context *ev,
1053                                         struct dcerpc_pipe_handle *p,
1054                                         void *chunk_mem,
1055                                         void *chunk_ptr)
1056 {
1057         struct dcerpc_binding_handle_call_params_pipe *pp =
1058                 dcerpc_pipe_handle_data(p,
1059                 struct dcerpc_binding_handle_call_params_pipe);
1060         struct tevent_req *req;
1061         struct dcerpc_binding_handle_call_params_pull_state *state;
1062
1063         req = tevent_req_create(mem_ctx, &state,
1064                                 struct dcerpc_binding_handle_call_params_pull_state);
1065         if (req == NULL) {
1066                 return NULL;
1067         }
1068         state->ev = ev;
1069         state->p = p;
1070         state->chunk_mem = chunk_mem;
1071         state->chunk_ptr = chunk_ptr;
1072
1073         dcerpc_binding_handle_call_params_pull_notify(req);
1074         if (!tevent_req_is_in_progress(req)) {
1075                 return tevent_req_post(req, ev);
1076         }
1077
1078         talloc_set_destructor(state,
1079                               dcerpc_binding_handle_call_params_pull_state_destructor);
1080         pp->pull_req = req;
1081
1082         return req;
1083 }
1084
1085 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req)
1086 {
1087         struct dcerpc_binding_handle_call_params_pull_state *state =
1088                 tevent_req_data(req,
1089                 struct dcerpc_binding_handle_call_params_pull_state);
1090         struct dcerpc_binding_handle_call_params_pipe *pp =
1091                 dcerpc_pipe_handle_data(state->p,
1092                 struct dcerpc_binding_handle_call_params_pipe);
1093         struct dcerpc_binding_handle_call_params_state *call_state =
1094                 tevent_req_data(pp->call_req,
1095                 struct dcerpc_binding_handle_call_params_state);
1096         enum ndr_err_code ndr_err;
1097         const uint32_t *count = NULL;
1098
1099         if (call_state->pull == NULL) {
1100                 return;
1101         }
1102
1103         if (call_state->pull->data_size == 0) {
1104                 return;
1105         }
1106
1107         call_state->pull->current_mem_ctx = state->chunk_mem;
1108
1109         /* pull the structure from the blob */
1110         ndr_err = call_state->call_pipe->ndr_pull(call_state->pull,
1111                                                   NDR_SCALARS|NDR_BUFFERS,
1112                                                   state->chunk_ptr);
1113         if (ndr_err == NDR_ERR_INCOMPLETE_BUFFER) {
1114                 return;
1115         }
1116         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1117                 NTSTATUS error;
1118                 error = ndr_map_error2ntstatus(ndr_err);
1119                 //if (h->ops->ndr_pull_failed) {
1120                 //      h->ops->ndr_pull_failed(h, error,
1121                 //                              &state->response,
1122                 //                              state->call);
1123                 //}
1124                 tevent_req_nterror(req, error);
1125                 return;
1126         }
1127
1128         //if (h->ops->do_ndr_print) {
1129         //      h->ops->do_ndr_print(h, NDR_OUT,
1130         //                           state->params->r_ptr, state->call);
1131         //}
1132
1133         //if (h->ops->ndr_validate_out) {
1134         //      error = h->ops->ndr_validate_out(h,
1135         //                                       state->pull,
1136         //                                       state->params->r_ptr,
1137         //                                       state->call);
1138         //      if (!NT_STATUS_IS_OK(error)) {
1139         //              tevent_req_nterror(req, error);
1140         //              return;
1141         //      }
1142         //}
1143
1144         //ndr_err = ndr_pull_pop(call_state->pull);
1145         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1146                 NTSTATUS error;
1147                 error = ndr_map_error2ntstatus(ndr_err);
1148                 tevent_req_nterror(req, error);
1149                 return;
1150         }
1151
1152         pp->pull_req = NULL;
1153         talloc_set_destructor(state, NULL);
1154
1155         /*
1156          * Note: the first struct member is always
1157          * 'uint32_t count;'
1158          */
1159         count = (const uint32_t *)state->chunk_ptr;
1160
1161         if (*count != 0) {
1162                 tevent_req_done(req);
1163                 return;
1164         }
1165
1166         tevent_req_defer_callback(req, state->ev);
1167         tevent_req_done(req);
1168         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1169
1170 }
1171
1172 static NTSTATUS dcerpc_binding_handle_call_params_pull_recv(struct tevent_req *req)
1173 {
1174         return tevent_req_simple_recv_ntstatus(req);
1175 }
1176
1177 static struct dcerpc_pipe_handle_ops dcerpc_binding_handle_call_params_pipe_ops = {
1178         .name = "dcerpc_binding_handle_call_params_pipe",
1179
1180         .chunk_push_send = dcerpc_binding_handle_call_params_push_send,
1181         .chunk_push_recv = dcerpc_binding_handle_call_params_push_recv,
1182
1183         .chunk_pull_send = dcerpc_binding_handle_call_params_pull_send,
1184         .chunk_pull_recv = dcerpc_binding_handle_call_params_pull_recv,
1185 };
1186
1187 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req)
1188 {
1189         struct dcerpc_binding_handle_call_params_state *call_state =
1190                 tevent_req_data(call_req,
1191                 struct dcerpc_binding_handle_call_params_state);
1192         struct dcerpc_binding_handle_call_params_pipe *pp;
1193
1194         call_state->ph = dcerpc_pipe_handle_create(call_state,
1195                                 &dcerpc_binding_handle_call_params_pipe_ops,
1196                                 &pp,
1197                                 struct dcerpc_binding_handle_call_params_pipe);
1198         if (tevent_req_nomem(call_state->ph, call_req)) {
1199                 return;
1200         }
1201
1202         pp->call_req = call_req;
1203 };
1204
1205 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p)
1206 {
1207         struct dcerpc_binding_handle_call_params_pipe *pp =
1208                 dcerpc_pipe_handle_data(p,
1209                 struct dcerpc_binding_handle_call_params_pipe);
1210
1211         if (pp->pull_req == NULL) {
1212                 return;
1213         }
1214
1215         dcerpc_binding_handle_call_params_pull_notify(pp->pull_req);
1216 }
1217
1218 struct dcerpc_binding_handle_call_state {
1219         struct dcerpc_binding_handle_call_params params;
1220 };
1221
1222 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
1223
1224 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
1225                                         struct tevent_context *ev,
1226                                         struct dcerpc_binding_handle *h,
1227                                         const struct GUID *object,
1228                                         const struct ndr_interface_table *table,
1229                                         uint32_t opnum,
1230                                         TALLOC_CTX *r_mem,
1231                                         void *r_ptr)
1232 {
1233         struct tevent_req *req;
1234         struct dcerpc_binding_handle_call_state *state;
1235         struct tevent_req *subreq;
1236
1237         req = tevent_req_create(mem_ctx, &state,
1238                                 struct dcerpc_binding_handle_call_state);
1239         if (req == NULL) {
1240                 return NULL;
1241         }
1242
1243         state->params.r_mem = r_mem;
1244         state->params.r_ptr = r_ptr;
1245
1246         subreq = dcerpc_binding_handle_call_params_send(state, ev, h,
1247                                                         object, table, opnum,
1248                                                         &state->params);
1249         if (tevent_req_nomem(subreq, req)) {
1250                 return tevent_req_post(req, ev);
1251         }
1252         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
1253
1254         return req;
1255 }
1256
1257 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
1258 {
1259         struct tevent_req *req = tevent_req_callback_data(subreq,
1260                                  struct tevent_req);
1261         NTSTATUS error;
1262
1263         error = dcerpc_binding_handle_call_params_recv(subreq);
1264         TALLOC_FREE(subreq);
1265         if (tevent_req_nterror(req, error)) {
1266                 return;
1267         }
1268
1269         tevent_req_done(req);
1270 }
1271
1272 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
1273 {
1274         return tevent_req_simple_recv_ntstatus(req);
1275 }
1276
1277 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
1278                                     const struct GUID *object,
1279                                     const struct ndr_interface_table *table,
1280                                     uint32_t opnum,
1281                                     TALLOC_CTX *r_mem,
1282                                     void *r_ptr)
1283 {
1284         TALLOC_CTX *frame = talloc_stackframe();
1285         struct tevent_context *ev;
1286         struct tevent_req *subreq;
1287         struct dcerpc_binding_handle_call_params params;
1288         NTSTATUS status = NT_STATUS_NO_MEMORY;
1289
1290         /*
1291          * TODO: allow only one sync call
1292          */
1293
1294         if (h->sync_ev) {
1295                 ev = h->sync_ev;
1296         } else {
1297                 ev = samba_tevent_context_init(frame);
1298         }
1299         if (ev == NULL) {
1300                 goto fail;
1301         }
1302
1303         ZERO_STRUCT(params);
1304         params.r_mem = r_mem;
1305         params.r_ptr = r_ptr;
1306
1307         subreq = dcerpc_binding_handle_call_params_send(frame, ev, h,
1308                                                         object, table, opnum,
1309                                                         &params);
1310         if (subreq == NULL) {
1311                 goto fail;
1312         }
1313
1314         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
1315                 goto fail;
1316         }
1317
1318         status = dcerpc_binding_handle_call_params_recv(subreq);
1319 fail:
1320         TALLOC_FREE(frame);
1321         return status;
1322 }