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