librpc/rpc/binding_handle.c disconnect pipe before error
[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_response(struct tevent_req *req);
477 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req);
478 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p);
479
480 struct tevent_req *dcerpc_binding_handle_call_params_send(TALLOC_CTX *mem_ctx,
481                                 struct tevent_context *ev,
482                                 struct dcerpc_binding_handle *h,
483                                 const struct GUID *object,
484                                 const struct ndr_interface_table *table,
485                                 uint32_t opnum,
486                                 struct dcerpc_binding_handle_call_params *params)
487 {
488         struct tevent_req *req;
489         struct dcerpc_binding_handle_call_params_state *state;
490         enum ndr_err_code ndr_err;
491
492         req = tevent_req_create(mem_ctx, &state,
493                                 struct dcerpc_binding_handle_call_params_state);
494         if (req == NULL) {
495                 return NULL;
496         }
497
498         if (table != h->table) {
499                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
500                 return tevent_req_post(req, ev);
501         }
502
503         if (opnum >= table->num_calls) {
504                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
505                 return tevent_req_post(req, ev);
506         }
507
508         state->h = h;
509         state->call = &table->calls[opnum];
510         state->params = params;
511
512         if (params->in.num_pipes != state->call->in_pipes.num_pipes) {
513                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
514                 return tevent_req_post(req, ev);
515         }
516
517         if (params->out.num_pipes != state->call->out_pipes.num_pipes) {
518                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
519                 return tevent_req_post(req, ev);
520         }
521
522         /* setup for a ndr_push_* call */
523         state->push = ndr_push_init_ctx(state);
524         if (tevent_req_nomem(state->push, req)) {
525                 return tevent_req_post(req, ev);
526         }
527
528         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
529                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
530         }
531
532         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
533                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
534                 state->in_flags |= LIBNDR_FLAG_BIGENDIAN;
535         }
536
537         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
538                 state->push->flags |= LIBNDR_FLAG_NDR64;
539         }
540
541         if (h->ops->do_ndr_print) {
542                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
543                                      state->params->r_ptr, state->call);
544         }
545
546         /* push the structure into a blob */
547         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->params->r_ptr);
548         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
549                 NTSTATUS error;
550                 error = ndr_map_error2ntstatus(ndr_err);
551                 if (h->ops->ndr_push_failed) {
552                         h->ops->ndr_push_failed(h, error,
553                                                 state->params->r_ptr,
554                                                 state->call);
555                 }
556                 tevent_req_nterror(req, error);
557                 return tevent_req_post(req, ev);
558         }
559
560         /* retrieve the blob */
561         state->request = ndr_push_blob(state->push);
562
563         if (h->ops->ndr_validate_in) {
564                 NTSTATUS error;
565                 error = h->ops->ndr_validate_in(h, state,
566                                                 &state->request,
567                                                 state->call);
568                 if (!NT_STATUS_IS_OK(error)) {
569                         tevent_req_nterror(req, error);
570                         return tevent_req_post(req, ev);
571                 }
572         }
573
574         if (params->in.num_pipes != 0) {
575                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
576
577                 /*
578                  * push alignment for the next pipe chunk
579                  */
580                 ndr_err = ndr_push_align(state->push, 5);
581                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
582                         NTSTATUS error;
583                         error = ndr_map_error2ntstatus(ndr_err);
584                         tevent_req_nterror(req, error);
585                         return tevent_req_post(req, ev);
586                 }
587         }
588
589         if (params->out.num_pipes != 0) {
590                 /*
591                  * even if we only have output pipes we need to indicate that
592                  * we want to get incomplete results
593                  */
594                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
595         }
596
597         if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
598                 tevent_req_defer_callback(req, ev);
599                 dcerpc_binding_handle_call_params_pipe_setup(req);
600                 if (!tevent_req_is_in_progress(req)) {
601                         return tevent_req_post(req, ev);
602                 }
603         }
604
605         /* retrieve the blob - including possible pipe chunk alignment */
606         state->request = ndr_push_blob(state->push);
607
608         state->subreq = dcerpc_binding_handle_raw_call_send(state, ev,
609                                                 h, object, opnum,
610                                                 state->in_flags,
611                                                 state->request.data,
612                                                 state->request.length);
613         if (tevent_req_nomem(state->subreq, req)) {
614                 return tevent_req_post(req, ev);
615         }
616         tevent_req_set_callback(state->subreq,
617                                 dcerpc_binding_handle_call_params_done,
618                                 req);
619
620         if (!(state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
621                 /*
622                  * we didn't ask for any pipes
623                  *
624                  * Indicate that all pipes are done.
625                  */
626                 state->in_pipe_idx = UINT32_MAX;
627                 state->out_pipe_idx = UINT32_MAX;
628                 return req;
629         }
630
631         /*
632          * If the subreq is already finished, the backend
633          * may not support LIBNDR_FLAG_INCOMPLETE_BUFFER
634          */
635         if (!tevent_req_is_in_progress(state->subreq)) {
636                 return req;
637         }
638
639         dcerpc_binding_handle_call_params_next_pipe(req);
640         if (!tevent_req_is_in_progress(req)) {
641                 return tevent_req_post(req, ev);
642         }
643
644         if (state->params->in.num_pipes == 0) {
645                 struct tevent_req *subreq;
646
647                 /*
648                  * We have only out pipes,
649                  * so indicate that we're done with sending in_data.
650                  */
651                 state->in_pipe_idx = UINT32_MAX;
652                 state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
653                 subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
654                                                                 state->subreq,
655                                                                 state->in_flags,
656                                                                 NULL, /* in_data */
657                                                                 0); /* in_length */
658                 if (tevent_req_nomem(subreq, req)) {
659                         return tevent_req_post(req, ev);
660                 }
661                 tevent_req_set_callback(subreq,
662                                         dcerpc_binding_handle_call_params_in_done,
663                                         req);
664                 return req;
665         }
666
667         return req;
668 }
669
670 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq)
671 {
672         struct tevent_req *req = tevent_req_callback_data(subreq,
673                                  struct tevent_req);
674         NTSTATUS error;
675
676         error = dcerpc_binding_handle_raw_call_in_recv(subreq);
677         TALLOC_FREE(subreq);
678         if (tevent_req_nterror(req, error)) {
679                 return;
680         }
681
682         /*
683          * nothing to do here
684          */
685 }
686
687 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req)
688 {
689         struct dcerpc_binding_handle_call_params_state *state =
690                 tevent_req_data(req,
691                 struct dcerpc_binding_handle_call_params_state);
692         struct dcerpc_binding_handle_call_params *params = state->params;
693         bool ok;
694
695         dcerpc_pipe_handle_connection_disconnect(state->pc);
696         state->pc = NULL;
697         state->call_pipe = NULL;
698
699         if (state->in_pipe_idx < params->in.num_pipes) {
700                 uint32_t idx = state->in_pipe_idx++;
701
702                 state->pc = params->in.pipes[idx];
703                 state->call_pipe = &state->call->in_pipes.pipes[idx];
704
705                 ok = dcerpc_pipe_handle_connection_push_connect(state->pc,
706                                         state->call_pipe->chunk_struct_name,
707                                         state->call_pipe->chunk_struct_size,
708                                         state->ph);
709                 if (!ok) {
710                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
711                         return;
712                 }
713
714                 return;
715         }
716         state->in_pipe_idx = UINT32_MAX;
717
718         if (state->out_pipe_idx < params->out.num_pipes) {
719                 uint32_t idx = state->out_pipe_idx++;
720
721                 state->pc = params->out.pipes[idx];
722                 state->call_pipe = &state->call->out_pipes.pipes[idx];
723
724                 ok = dcerpc_pipe_handle_connection_pull_connect(state->pc,
725                                         state->call_pipe->chunk_struct_name,
726                                         state->call_pipe->chunk_struct_size,
727                                         state->ph);
728                 if (!ok) {
729                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
730                         return;
731                 }
732
733                 return;
734         }
735         state->out_pipe_idx = UINT32_MAX;
736
737         if (state->pull == NULL) {
738                 return;
739         }
740
741         if (state->pull->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
742                 return;
743         }
744
745         dcerpc_binding_handle_call_params_response(req);
746 }
747
748 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq)
749 {
750         struct tevent_req *req = tevent_req_callback_data(subreq,
751                                  struct tevent_req);
752         struct dcerpc_binding_handle_call_params_state *state =
753                 tevent_req_data(req,
754                 struct dcerpc_binding_handle_call_params_state);
755         struct dcerpc_binding_handle *h = state->h;
756         NTSTATUS error;
757         uint32_t out_flags = 0;
758         enum ndr_err_code ndr_err;
759
760         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
761                                                     &state->response.data,
762                                                     &state->response.length,
763                                                     &out_flags);
764         subreq = NULL;
765         if (!NT_STATUS_IS_OK(error)) {
766                 TALLOC_FREE(state->subreq);
767                 dcerpc_pipe_handle_connection_disconnect(state->pc);
768                 state->pc = NULL;
769                 state->call_pipe = NULL;
770                 tevent_req_nterror(req, error);
771                 return;
772         }
773
774         if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
775                 TALLOC_FREE(state->subreq);
776         }
777
778         if (state->in_pipe_idx != UINT32_MAX) {
779                 /*
780                  * we haven't send all data yet,
781                  * this is a protocol error
782                  */
783                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
784                 return;
785         }
786
787         if (state->pull == NULL) {
788                 state->pull = ndr_pull_init_blob(&state->response, state);
789                 if (tevent_req_nomem(state->pull, req)) {
790                         return;
791                 }
792                 state->pull->flags = state->push->flags;
793
794                 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
795                         state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
796                 } else {
797                         state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
798                 }
799
800                 if (out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
801                         state->pull->flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
802                 }
803         } else {
804                 if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
805                         state->pull->flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
806                 }
807
808                 ndr_err = ndr_pull_append(state->pull,
809                                           &state->response);
810                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
811                         error = ndr_map_error2ntstatus(ndr_err);
812                         if (h->ops->ndr_pull_failed) {
813                                 h->ops->ndr_pull_failed(h, error,
814                                                         &state->response,
815                                                         state->call);
816                         }
817                         tevent_req_nterror(req, error);
818                         return;
819                 }
820         }
821
822         if (state->out_pipe_idx != UINT32_MAX) {
823                 dcerpc_binding_handle_call_params_pipe_notify(state->ph);
824                 return;
825         }
826
827         dcerpc_binding_handle_call_params_response(req);
828 }
829
830 static void dcerpc_binding_handle_call_params_response(struct tevent_req *req)
831 {
832         struct dcerpc_binding_handle_call_params_state *state =
833                 tevent_req_data(req,
834                 struct dcerpc_binding_handle_call_params_state);
835         struct dcerpc_binding_handle *h = state->h;
836         NTSTATUS error;
837         enum ndr_err_code ndr_err;
838
839         state->pull->current_mem_ctx = state->params->r_mem;
840
841         /* pull the structure from the blob */
842         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT,
843                                         state->params->r_ptr);
844         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
845                 error = ndr_map_error2ntstatus(ndr_err);
846                 if (h->ops->ndr_pull_failed) {
847                         h->ops->ndr_pull_failed(h, error,
848                                                 &state->response,
849                                                 state->call);
850                 }
851                 tevent_req_nterror(req, error);
852                 return;
853         }
854
855         if (h->ops->do_ndr_print) {
856                 h->ops->do_ndr_print(h, NDR_OUT,
857                                      state->params->r_ptr, state->call);
858         }
859
860         if (h->ops->ndr_validate_out) {
861                 error = h->ops->ndr_validate_out(h,
862                                                  state->pull,
863                                                  state->params->r_ptr,
864                                                  state->call);
865                 if (!NT_STATUS_IS_OK(error)) {
866                         tevent_req_nterror(req, error);
867                         return;
868                 }
869         }
870
871         tevent_req_done(req);
872 }
873
874 NTSTATUS dcerpc_binding_handle_call_params_recv(struct tevent_req *req)
875 {
876         return tevent_req_simple_recv_ntstatus(req);
877 }
878
879 struct dcerpc_binding_handle_call_params_pipe {
880         struct tevent_req *call_req;
881         struct tevent_req *pull_req;
882 };
883
884 struct dcerpc_binding_handle_call_params_push_state {
885         struct tevent_context *ev;
886         struct dcerpc_pipe_handle *p;
887         struct ndr_push *push;
888         DATA_BLOB chunk_blob;
889         bool is_last_chunk;
890 };
891
892 static int dcerpc_binding_handle_call_params_push_state_destructor(
893         struct dcerpc_binding_handle_call_params_push_state *state)
894 {
895         struct dcerpc_binding_handle_call_params_pipe *pp =
896                 dcerpc_pipe_handle_data(state->p,
897                 struct dcerpc_binding_handle_call_params_pipe);
898
899         if (!state->is_last_chunk) {
900                 return 0;
901         }
902
903         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
904         return 0;
905 }
906
907 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq);
908
909 static struct tevent_req *dcerpc_binding_handle_call_params_push_send(TALLOC_CTX *mem_ctx,
910                                         struct tevent_context *ev,
911                                         struct dcerpc_pipe_handle *p,
912                                         const void *chunk_ptr)
913 {
914         struct dcerpc_binding_handle_call_params_pipe *pp =
915                 dcerpc_pipe_handle_data(p,
916                 struct dcerpc_binding_handle_call_params_pipe);
917         struct dcerpc_binding_handle_call_params_state *call_state =
918                 tevent_req_data(pp->call_req,
919                 struct dcerpc_binding_handle_call_params_state);
920         struct tevent_req *req;
921         struct dcerpc_binding_handle_call_params_push_state *state;
922         struct tevent_req *subreq;
923         enum ndr_err_code ndr_err;
924         const uint32_t *count = NULL;
925         bool is_last_pipe = false;
926
927         req = tevent_req_create(mem_ctx, &state,
928                                 struct dcerpc_binding_handle_call_params_push_state);
929         if (req == NULL) {
930                 return NULL;
931         }
932         state->ev = ev;
933         state->p = p;
934         state->is_last_chunk = true;
935
936         tevent_req_defer_callback(req, state->ev);
937
938         talloc_set_destructor(state,
939                               dcerpc_binding_handle_call_params_push_state_destructor);
940
941         /* setup for a ndr_push_* call */
942         state->push = ndr_push_init_ctx(state);
943         if (tevent_req_nomem(state->push, req)) {
944                 return tevent_req_post(req, ev);
945         }
946
947         state->push->flags = call_state->push->flags;
948
949         //if (h->ops->do_ndr_print) {
950         //      h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
951         //                           state->params->r_ptr, state->call);
952         //}
953
954         /* push the structure into a blob */
955         ndr_err = call_state->call_pipe->ndr_push(state->push,
956                                                   NDR_SCALARS|NDR_BUFFERS,
957                                                   chunk_ptr);
958         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
959                 NTSTATUS error;
960                 error = ndr_map_error2ntstatus(ndr_err);
961                 //if (h->ops->ndr_push_failed) {
962                 //      h->ops->ndr_push_failed(h, error,
963                 //                              state->params->r_ptr,
964                 //                              state->call);
965                 //}
966                 tevent_req_nterror(req, error);
967                 return tevent_req_post(req, ev);
968         }
969
970         /*
971          * Note: the first struct member is always
972          * 'uint32_t count;'
973          */
974         count = (const uint32_t *)chunk_ptr;
975
976         state->is_last_chunk = false;
977         if (*count == 0) {
978                 state->is_last_chunk = true;
979         }
980
981         if (call_state->in_pipe_idx >= call_state->params->in.num_pipes) {
982                 is_last_pipe = true;
983         }
984
985         if (is_last_pipe && state->is_last_chunk) {
986                 call_state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
987         } else {
988                 /*
989                  * push alignment for the next pipe chunk
990                  */
991                 ndr_err = ndr_push_align(state->push, 5);
992                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
993                         NTSTATUS error;
994                         error = ndr_map_error2ntstatus(ndr_err);
995                         tevent_req_nterror(req, error);
996                         return tevent_req_post(req, ev);
997                 }
998         }
999
1000         /* retrieve the blob - including possible alignment for the next chunk */
1001         state->chunk_blob = ndr_push_blob(state->push);
1002
1003         subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
1004                                                         call_state->subreq,
1005                                                         call_state->in_flags,
1006                                                         state->chunk_blob.data,
1007                                                         state->chunk_blob.length);
1008         if (tevent_req_nomem(subreq, req)) {
1009                 return tevent_req_post(req, ev);
1010         }
1011         tevent_req_set_callback(subreq,
1012                                 dcerpc_binding_handle_call_params_push_done,
1013                                 req);
1014
1015         return req;
1016 }
1017
1018 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq)
1019 {
1020         struct tevent_req *req =
1021                 tevent_req_callback_data(subreq,
1022                 struct tevent_req);
1023         struct dcerpc_binding_handle_call_params_push_state *state =
1024                 tevent_req_data(req,
1025                 struct dcerpc_binding_handle_call_params_push_state);
1026         struct dcerpc_binding_handle_call_params_pipe *pp =
1027                 dcerpc_pipe_handle_data(state->p,
1028                 struct dcerpc_binding_handle_call_params_pipe);
1029         NTSTATUS status;
1030
1031         status = dcerpc_binding_handle_raw_call_in_recv(subreq);
1032         TALLOC_FREE(subreq);
1033         TALLOC_FREE(state->push);
1034         if (tevent_req_nterror(req, status)) {
1035                 return;
1036         }
1037
1038         tevent_req_done(req);
1039 }
1040
1041 static NTSTATUS dcerpc_binding_handle_call_params_push_recv(struct tevent_req *req)
1042 {
1043         return tevent_req_simple_recv_ntstatus(req);
1044 }
1045
1046 struct dcerpc_binding_handle_call_params_pull_state {
1047         struct tevent_context *ev;
1048         struct dcerpc_pipe_handle *p;
1049         void *chunk_mem;
1050         void *chunk_ptr;
1051         bool is_last_chunk;
1052 };
1053
1054 static int dcerpc_binding_handle_call_params_pull_state_destructor(
1055         struct dcerpc_binding_handle_call_params_pull_state *state)
1056 {
1057         struct dcerpc_binding_handle_call_params_pipe *pp =
1058                 dcerpc_pipe_handle_data(state->p,
1059                 struct dcerpc_binding_handle_call_params_pipe);
1060
1061         pp->pull_req = NULL;
1062
1063         if (!state->is_last_chunk) {
1064                 return 0;
1065         }
1066
1067         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1068         return 0;
1069 }
1070
1071 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req);
1072
1073 static struct tevent_req *dcerpc_binding_handle_call_params_pull_send(TALLOC_CTX *mem_ctx,
1074                                         struct tevent_context *ev,
1075                                         struct dcerpc_pipe_handle *p,
1076                                         void *chunk_mem,
1077                                         void *chunk_ptr)
1078 {
1079         struct dcerpc_binding_handle_call_params_pipe *pp =
1080                 dcerpc_pipe_handle_data(p,
1081                 struct dcerpc_binding_handle_call_params_pipe);
1082         struct tevent_req *req;
1083         struct dcerpc_binding_handle_call_params_pull_state *state;
1084
1085         req = tevent_req_create(mem_ctx, &state,
1086                                 struct dcerpc_binding_handle_call_params_pull_state);
1087         if (req == NULL) {
1088                 return NULL;
1089         }
1090         state->ev = ev;
1091         state->p = p;
1092         state->chunk_mem = chunk_mem;
1093         state->chunk_ptr = chunk_ptr;
1094         state->is_last_chunk = true;
1095
1096         tevent_req_defer_callback(req, state->ev);
1097
1098         talloc_set_destructor(state,
1099                               dcerpc_binding_handle_call_params_pull_state_destructor);
1100         pp->pull_req = req;
1101
1102         dcerpc_binding_handle_call_params_pull_notify(req);
1103         if (!tevent_req_is_in_progress(req)) {
1104                 return tevent_req_post(req, ev);
1105         }
1106
1107         return req;
1108 }
1109
1110 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req)
1111 {
1112         struct dcerpc_binding_handle_call_params_pull_state *state =
1113                 tevent_req_data(req,
1114                 struct dcerpc_binding_handle_call_params_pull_state);
1115         struct dcerpc_binding_handle_call_params_pipe *pp =
1116                 dcerpc_pipe_handle_data(state->p,
1117                 struct dcerpc_binding_handle_call_params_pipe);
1118         struct dcerpc_binding_handle_call_params_state *call_state =
1119                 tevent_req_data(pp->call_req,
1120                 struct dcerpc_binding_handle_call_params_state);
1121         enum ndr_err_code ndr_err;
1122         const uint32_t *count = NULL;
1123
1124         if (call_state->pull == NULL) {
1125                 return;
1126         }
1127
1128         if (call_state->pull->data_size == 0) {
1129                 return;
1130         }
1131
1132         call_state->pull->current_mem_ctx = state->chunk_mem;
1133
1134         /* pull the structure from the blob */
1135         ndr_err = call_state->call_pipe->ndr_pull(call_state->pull,
1136                                                   NDR_SCALARS|NDR_BUFFERS,
1137                                                   state->chunk_ptr);
1138         if (ndr_err == NDR_ERR_INCOMPLETE_BUFFER) {
1139 //TODO clean up??
1140                 return;
1141         }
1142         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1143                 NTSTATUS error;
1144                 error = ndr_map_error2ntstatus(ndr_err);
1145                 //if (h->ops->ndr_pull_failed) {
1146                 //      h->ops->ndr_pull_failed(h, error,
1147                 //                              &state->response,
1148                 //                              state->call);
1149                 //}
1150                 tevent_req_nterror(req, error);
1151                 return;
1152         }
1153
1154         //if (h->ops->do_ndr_print) {
1155         //      h->ops->do_ndr_print(h, NDR_OUT,
1156         //                           state->params->r_ptr, state->call);
1157         //}
1158
1159         //if (h->ops->ndr_validate_out) {
1160         //      error = h->ops->ndr_validate_out(h,
1161         //                                       state->pull,
1162         //                                       state->params->r_ptr,
1163         //                                       state->call);
1164         //      if (!NT_STATUS_IS_OK(error)) {
1165         //              tevent_req_nterror(req, error);
1166         //              return;
1167         //      }
1168         //}
1169
1170         //ndr_err = ndr_pull_pop(call_state->pull);
1171         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1172                 NTSTATUS error;
1173                 error = ndr_map_error2ntstatus(ndr_err);
1174                 tevent_req_nterror(req, error);
1175                 return;
1176         }
1177
1178         /*
1179          * Note: the first struct member is always
1180          * 'uint32_t count;'
1181          */
1182         count = (const uint32_t *)state->chunk_ptr;
1183
1184         if (*count != 0) {
1185                 state->is_last_chunk = false;
1186                 tevent_req_done(req);
1187                 return;
1188         }
1189
1190         state->is_last_chunk = true;
1191         tevent_req_done(req);
1192
1193 }
1194
1195 static NTSTATUS dcerpc_binding_handle_call_params_pull_recv(struct tevent_req *req)
1196 {
1197         return tevent_req_simple_recv_ntstatus(req);
1198 }
1199
1200 static struct dcerpc_pipe_handle_ops dcerpc_binding_handle_call_params_pipe_ops = {
1201         .name = "dcerpc_binding_handle_call_params_pipe",
1202
1203         .chunk_push_send = dcerpc_binding_handle_call_params_push_send,
1204         .chunk_push_recv = dcerpc_binding_handle_call_params_push_recv,
1205
1206         .chunk_pull_send = dcerpc_binding_handle_call_params_pull_send,
1207         .chunk_pull_recv = dcerpc_binding_handle_call_params_pull_recv,
1208 };
1209
1210 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req)
1211 {
1212         struct dcerpc_binding_handle_call_params_state *call_state =
1213                 tevent_req_data(call_req,
1214                 struct dcerpc_binding_handle_call_params_state);
1215         struct dcerpc_binding_handle_call_params_pipe *pp;
1216
1217         call_state->ph = dcerpc_pipe_handle_create(call_state,
1218                                 &dcerpc_binding_handle_call_params_pipe_ops,
1219                                 &pp,
1220                                 struct dcerpc_binding_handle_call_params_pipe);
1221         if (tevent_req_nomem(call_state->ph, call_req)) {
1222                 return;
1223         }
1224
1225         pp->call_req = call_req;
1226 };
1227
1228 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p)
1229 {
1230         struct dcerpc_binding_handle_call_params_pipe *pp =
1231                 dcerpc_pipe_handle_data(p,
1232                 struct dcerpc_binding_handle_call_params_pipe);
1233
1234         if (pp->pull_req == NULL) {
1235                 return;
1236         }
1237
1238         dcerpc_binding_handle_call_params_pull_notify(pp->pull_req);
1239 }
1240
1241 struct dcerpc_binding_handle_call_state {
1242         struct dcerpc_binding_handle_call_params params;
1243 };
1244
1245 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
1246
1247 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
1248                                         struct tevent_context *ev,
1249                                         struct dcerpc_binding_handle *h,
1250                                         const struct GUID *object,
1251                                         const struct ndr_interface_table *table,
1252                                         uint32_t opnum,
1253                                         TALLOC_CTX *r_mem,
1254                                         void *r_ptr)
1255 {
1256         struct tevent_req *req;
1257         struct dcerpc_binding_handle_call_state *state;
1258         struct tevent_req *subreq;
1259
1260         req = tevent_req_create(mem_ctx, &state,
1261                                 struct dcerpc_binding_handle_call_state);
1262         if (req == NULL) {
1263                 return NULL;
1264         }
1265
1266         state->params.r_mem = r_mem;
1267         state->params.r_ptr = r_ptr;
1268
1269         subreq = dcerpc_binding_handle_call_params_send(state, ev, h,
1270                                                         object, table, opnum,
1271                                                         &state->params);
1272         if (tevent_req_nomem(subreq, req)) {
1273                 return tevent_req_post(req, ev);
1274         }
1275         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
1276
1277         return req;
1278 }
1279
1280 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
1281 {
1282         struct tevent_req *req = tevent_req_callback_data(subreq,
1283                                  struct tevent_req);
1284         NTSTATUS error;
1285
1286         error = dcerpc_binding_handle_call_params_recv(subreq);
1287         TALLOC_FREE(subreq);
1288         if (tevent_req_nterror(req, error)) {
1289                 return;
1290         }
1291
1292         tevent_req_done(req);
1293 }
1294
1295 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
1296 {
1297         return tevent_req_simple_recv_ntstatus(req);
1298 }
1299
1300 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
1301                                     const struct GUID *object,
1302                                     const struct ndr_interface_table *table,
1303                                     uint32_t opnum,
1304                                     TALLOC_CTX *r_mem,
1305                                     void *r_ptr)
1306 {
1307         TALLOC_CTX *frame = talloc_stackframe();
1308         struct tevent_context *ev;
1309         struct tevent_req *subreq;
1310         struct dcerpc_binding_handle_call_params params;
1311         NTSTATUS status = NT_STATUS_NO_MEMORY;
1312
1313         /*
1314          * TODO: allow only one sync call
1315          */
1316
1317         if (h->sync_ev) {
1318                 ev = h->sync_ev;
1319         } else {
1320                 ev = samba_tevent_context_init(frame);
1321         }
1322         if (ev == NULL) {
1323                 goto fail;
1324         }
1325
1326         ZERO_STRUCT(params);
1327         params.r_mem = r_mem;
1328         params.r_ptr = r_ptr;
1329
1330         subreq = dcerpc_binding_handle_call_params_send(frame, ev, h,
1331                                                         object, table, opnum,
1332                                                         &params);
1333         if (subreq == NULL) {
1334                 goto fail;
1335         }
1336
1337         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
1338                 goto fail;
1339         }
1340
1341         status = dcerpc_binding_handle_call_params_recv(subreq);
1342 fail:
1343         TALLOC_FREE(frame);
1344         return status;
1345 }