source4/librpc/rpc/dcerpc.c bla...
[metze/samba/wip.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Jelmer Vernooij 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
37
38
39 enum rpc_request_state {
40         RPC_REQUEST_QUEUED,
41         RPC_REQUEST_PENDING,
42         RPC_REQUEST_DONE
43 };
44
45 /*
46   handle for an async dcerpc request
47 */
48 struct rpc_request {
49         struct rpc_request *next, *prev;
50         struct dcerpc_pipe *p;
51         NTSTATUS status;
52         uint32_t call_id;
53         enum rpc_request_state state;
54         DATA_BLOB payload;
55         uint32_t flags;
56         uint32_t fault_code;
57
58         /* this is used to distinguish bind and alter_context requests
59            from normal requests */
60         void (*recv_handler)(struct rpc_request *conn, 
61                              DATA_BLOB *blob, struct ncacn_packet *pkt);
62
63         const struct GUID *object;
64         uint16_t opnum;
65         DATA_BLOB request_data;
66         bool request_data_allocated;
67         struct tevent_req *stub_subreq;
68         bool ignore_timeout;
69         bool wait_for_sync;
70         bool verify_bitmask1;
71         bool verify_pcontext;
72         bool first_pdu_done;
73         bool incomplete_request_data;
74         bool last_pdu_done;
75
76         struct {
77                 void (*callback)(struct rpc_request *);
78                 void *private_data;
79         } async;
80 };
81
82 _PUBLIC_ NTSTATUS dcerpc_init(void)
83 {
84         return gensec_init();
85 }
86
87 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
88 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
89
90 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
91                                                struct dcerpc_pipe *p,
92                                                const struct GUID *object,
93                                                uint16_t opnum,
94                                                DATA_BLOB *stub_data);
95 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
96                                     TALLOC_CTX *mem_ctx,
97                                     DATA_BLOB *stub_data);
98 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
99                                        TALLOC_CTX *mem_ctx,
100                                        DATA_BLOB blob,
101                                        size_t struct_size,
102                                        ndr_push_flags_fn_t ndr_push,
103                                        ndr_pull_flags_fn_t ndr_pull);
104 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
105                                         struct ndr_pull *pull_in,
106                                         void *struct_ptr,
107                                         size_t struct_size,
108                                         ndr_push_flags_fn_t ndr_push,
109                                         ndr_pull_flags_fn_t ndr_pull,
110                                         ndr_print_function_t ndr_print);
111 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
112 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
113                              bool trigger_read);
114 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
115
116 /* destroy a dcerpc connection */
117 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
118 {
119         if (conn->dead) {
120                 conn->free_skipped = true;
121                 return -1;
122         }
123         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
124         return 0;
125 }
126
127
128 /* initialise a dcerpc connection. 
129    the event context is optional
130 */
131 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
132                                                  struct tevent_context *ev)
133 {
134         struct dcecli_connection *c;
135
136         c = talloc_zero(mem_ctx, struct dcecli_connection);
137         if (!c) {
138                 return NULL;
139         }
140
141         c->event_ctx = ev;
142
143         if (c->event_ctx == NULL) {
144                 talloc_free(c);
145                 return NULL;
146         }
147
148         c->call_id = 1;
149         c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
150         c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
151         c->security_state.auth_context_id = 0;
152         c->security_state.session_key = dcerpc_generic_session_key;
153         c->security_state.generic_state = NULL;
154         c->flags = 0;
155         /*
156          * Windows uses 5840 for ncacn_ip_tcp,
157          * so we also use it (for every transport)
158          * by default. But we give the transport
159          * the chance to overwrite it.
160          */
161         c->srv_max_xmit_frag = 5840;
162         c->srv_max_recv_frag = 5840;
163         c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
164         c->pending = NULL;
165
166         c->io_trigger = tevent_create_immediate(c);
167         if (c->io_trigger == NULL) {
168                 talloc_free(c);
169                 return NULL;
170         }
171
172         talloc_set_destructor(c, dcerpc_connection_destructor);
173
174         return c;
175 }
176
177 struct dcerpc_bh_state {
178         struct dcerpc_pipe *p;
179 };
180
181 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
182 {
183         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
184                                      struct dcerpc_bh_state);
185
186         if (!hs->p) {
187                 return false;
188         }
189
190         if (!hs->p->conn) {
191                 return false;
192         }
193
194         if (hs->p->conn->dead) {
195                 return false;
196         }
197
198         return true;
199 }
200
201 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
202                                       uint32_t timeout)
203 {
204         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
205                                      struct dcerpc_bh_state);
206         uint32_t old;
207
208         if (!hs->p) {
209                 return DCERPC_REQUEST_TIMEOUT;
210         }
211
212         old = hs->p->request_timeout;
213         hs->p->request_timeout = timeout;
214
215         return old;
216 }
217
218 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
219                                 enum dcerpc_AuthType *auth_type,
220                                 enum dcerpc_AuthLevel *auth_level)
221 {
222         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
223                                      struct dcerpc_bh_state);
224
225         if (hs->p == NULL) {
226                 return;
227         }
228
229         if (hs->p->conn == NULL) {
230                 return;
231         }
232
233         *auth_type = hs->p->conn->security_state.auth_type;
234         *auth_level = hs->p->conn->security_state.auth_level;
235 }
236
237 struct dcerpc_bh_raw_call_state {
238         struct tevent_context *ev;
239         struct dcerpc_binding_handle *h;
240         uint32_t in_flags;
241         DATA_BLOB in_data;
242         DATA_BLOB out_data;
243         uint32_t out_flags;
244         struct rpc_request *subreq;
245 };
246
247 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
248
249 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
250                                                   struct tevent_context *ev,
251                                                   struct dcerpc_binding_handle *h,
252                                                   const struct GUID *object,
253                                                   uint32_t opnum,
254                                                   uint32_t in_flags,
255                                                   const uint8_t *in_data,
256                                                   size_t in_length)
257 {
258         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
259                                      struct dcerpc_bh_state);
260         struct tevent_req *req;
261         struct dcerpc_bh_raw_call_state *state;
262         bool ok;
263
264         req = tevent_req_create(mem_ctx, &state,
265                                 struct dcerpc_bh_raw_call_state);
266         if (req == NULL) {
267                 return NULL;
268         }
269         state->ev = ev;
270         state->h = h;
271         state->in_flags = in_flags;
272         state->in_data.data = discard_const_p(uint8_t, in_data);
273         state->in_data.length = in_length;
274
275         ok = dcerpc_bh_is_connected(h);
276         if (!ok) {
277                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
278                 return tevent_req_post(req, ev);
279         }
280
281         state->subreq = dcerpc_request_send(state,
282                                             hs->p,
283                                             object,
284                                             opnum,
285                                             &state->in_data);
286         if (tevent_req_nomem(state->subreq, req)) {
287                 return tevent_req_post(req, ev);
288         }
289         state->subreq->async.callback = dcerpc_bh_raw_call_done;
290         state->subreq->async.private_data = req;
291
292         if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
293                 state->subreq->incomplete_request_data = true;
294         }
295
296         return req;
297 }
298
299 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
300 {
301         struct tevent_req *req =
302                 talloc_get_type_abort(subreq->async.private_data,
303                 struct tevent_req);
304         struct dcerpc_bh_raw_call_state *state =
305                 tevent_req_data(req,
306                 struct dcerpc_bh_raw_call_state);
307         NTSTATUS status;
308         uint32_t fault_code;
309
310         state->out_flags = 0;
311         if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
312                 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
313         }
314
315         if (subreq->state == RPC_REQUEST_PENDING) {
316                 state->out_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
317         } else {
318                 state->subreq = NULL;
319                 state->out_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
320         }
321
322         fault_code = subreq->fault_code;
323
324         status = dcerpc_request_recv(subreq, state, &state->out_data);
325         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
326                 status = dcerpc_fault_to_nt_status(fault_code);
327         }
328
329         /*
330          * We trigger the callback in the next event run
331          * because the code in this file might trigger
332          * multiple request callbacks from within a single
333          * while loop.
334          *
335          * In order to avoid segfaults from within
336          * dcerpc_connection_dead() we call
337          * tevent_req_defer_callback().
338          */
339         tevent_req_defer_callback(req, state->ev);
340
341         if (!NT_STATUS_IS_OK(status)) {
342                 tevent_req_nterror(req, status);
343                 return;
344         }
345
346         if (state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
347                 tevent_req_notify_callback(req);
348                 return;
349         }
350
351         tevent_req_done(req);
352 }
353
354 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
355                                         TALLOC_CTX *mem_ctx,
356                                         uint8_t **out_data,
357                                         size_t *out_length,
358                                         uint32_t *out_flags)
359 {
360         struct dcerpc_bh_raw_call_state *state =
361                 tevent_req_data(req,
362                 struct dcerpc_bh_raw_call_state);
363         NTSTATUS status;
364
365         if (tevent_req_is_nterror(req, &status)) {
366                 tevent_req_received(req);
367                 return status;
368         }
369
370         *out_data = talloc_move(mem_ctx, &state->out_data.data);
371         *out_length = state->out_data.length;
372         *out_flags = state->out_flags;
373         if (!(state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
374                 tevent_req_received(req);
375         }
376         return NT_STATUS_OK;
377 }
378
379 struct dcerpc_bh_raw_call_in_state {
380
381 };
382
383 static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
384                                         struct tevent_context *ev,
385                                         struct tevent_req *raw_call_req,
386                                         uint32_t in_flags,
387                                         const uint8_t *in_data,
388                                         size_t in_length)
389 {
390         struct dcerpc_bh_raw_call_state *raw_call_state = NULL;
391         struct tevent_req *req;
392         struct dcerpc_bh_raw_call_in_state *state;
393
394         req = tevent_req_create(mem_ctx, &state,
395                                 struct dcerpc_bh_raw_call_in_state);
396         if (req == NULL) {
397                 return NULL;
398         }
399
400         if (!tevent_req_is_in_progress(raw_call_req)) {
401                 tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
402                 return tevent_req_post(req, ev);
403         }
404
405         raw_call_state = tevent_req_data(raw_call_req,
406                                          struct dcerpc_bh_raw_call_state);
407
408         
409         struct rpc_request *subreq;
410         
411         return req;
412 }
413
414 static NTSTATUS dcerpc_bh_raw_call_in__recv(struct tevent_req *req)
415 {
416
417 }
418
419 struct dcerpc_bh_disconnect_state {
420         uint8_t _dummy;
421 };
422
423 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
424                                                 struct tevent_context *ev,
425                                                 struct dcerpc_binding_handle *h)
426 {
427         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
428                                      struct dcerpc_bh_state);
429         struct tevent_req *req;
430         struct dcerpc_bh_disconnect_state *state;
431         bool ok;
432
433         req = tevent_req_create(mem_ctx, &state,
434                                 struct dcerpc_bh_disconnect_state);
435         if (req == NULL) {
436                 return NULL;
437         }
438
439         ok = dcerpc_bh_is_connected(h);
440         if (!ok) {
441                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
442                 return tevent_req_post(req, ev);
443         }
444
445         /* TODO: do a real disconnect ... */
446         hs->p = NULL;
447
448         tevent_req_done(req);
449         return tevent_req_post(req, ev);
450 }
451
452 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
453 {
454         NTSTATUS status;
455
456         if (tevent_req_is_nterror(req, &status)) {
457                 tevent_req_received(req);
458                 return status;
459         }
460
461         tevent_req_received(req);
462         return NT_STATUS_OK;
463 }
464
465 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
466 {
467         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
468                                      struct dcerpc_bh_state);
469
470         if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
471                 return true;
472         }
473
474         return false;
475 }
476
477 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
478 {
479         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
480                                      struct dcerpc_bh_state);
481
482         if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
483                 return true;
484         }
485
486         return false;
487 }
488
489 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
490 {
491         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
492                                      struct dcerpc_bh_state);
493
494         if (hs->p->conn->flags & DCERPC_NDR64) {
495                 return true;
496         }
497
498         return false;
499 }
500
501 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
502                                    int ndr_flags,
503                                    const void *_struct_ptr,
504                                    const struct ndr_interface_call *call)
505 {
506         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
507                                      struct dcerpc_bh_state);
508         void *struct_ptr = discard_const(_struct_ptr);
509         bool print_in = false;
510         bool print_out = false;
511
512         if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
513                 print_in = true;
514         }
515
516         if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
517                 print_out = true;
518         }
519
520         if (DEBUGLEVEL >= 11) {
521                 print_in = true;
522                 print_out = true;
523         }
524
525         if (ndr_flags & NDR_IN) {
526                 if (print_in) {
527                         ndr_print_function_debug(call->ndr_print,
528                                                  call->name,
529                                                  ndr_flags,
530                                                  struct_ptr);
531                 }
532         }
533         if (ndr_flags & NDR_OUT) {
534                 if (print_out) {
535                         ndr_print_function_debug(call->ndr_print,
536                                                  call->name,
537                                                  ndr_flags,
538                                                  struct_ptr);
539                 }
540         }
541 }
542
543 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
544                                       NTSTATUS error,
545                                       const void *struct_ptr,
546                                       const struct ndr_interface_call *call)
547 {
548         DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
549                  call->name, nt_errstr(error)));
550 }
551
552 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
553                                       NTSTATUS error,
554                                       const DATA_BLOB *blob,
555                                       const struct ndr_interface_call *call)
556 {
557         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
558                                      struct dcerpc_bh_state);
559         const uint32_t num_examples = 20;
560         uint32_t i;
561
562         DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
563                  call->name, nt_errstr(error)));
564
565         if (hs->p->conn->packet_log_dir == NULL) return;
566
567         for (i=0;i<num_examples;i++) {
568                 char *name=NULL;
569                 int ret;
570
571                 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
572                                hs->p->conn->packet_log_dir,
573                                call->name, i);
574                 if (ret == -1) {
575                         return;
576                 }
577                 if (!file_exist(name)) {
578                         if (file_save(name, blob->data, blob->length)) {
579                                 DEBUG(10,("Logged rpc packet to %s\n", name));
580                         }
581                         free(name);
582                         break;
583                 }
584                 free(name);
585         }
586 }
587
588 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
589                                           TALLOC_CTX *mem_ctx,
590                                           const DATA_BLOB *blob,
591                                           const struct ndr_interface_call *call)
592 {
593         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
594                                      struct dcerpc_bh_state);
595
596         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
597                 NTSTATUS status;
598
599                 status = dcerpc_ndr_validate_in(hs->p->conn,
600                                                 mem_ctx,
601                                                 *blob,
602                                                 call->struct_size,
603                                                 call->ndr_push,
604                                                 call->ndr_pull);
605                 if (!NT_STATUS_IS_OK(status)) {
606                         DEBUG(0,("Validation [in] failed for %s - %s\n",
607                                  call->name, nt_errstr(status)));
608                         return status;
609                 }
610         }
611
612         DEBUG(10,("rpc request data:\n"));
613         dump_data(10, blob->data, blob->length);
614
615         return NT_STATUS_OK;
616 }
617
618 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
619                                            struct ndr_pull *pull_in,
620                                            const void *_struct_ptr,
621                                            const struct ndr_interface_call *call)
622 {
623         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
624                                      struct dcerpc_bh_state);
625         void *struct_ptr = discard_const(_struct_ptr);
626
627         DEBUG(10,("rpc reply data:\n"));
628         dump_data(10, pull_in->data, pull_in->data_size);
629
630         if (pull_in->offset != pull_in->data_size) {
631                 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
632                          pull_in->data_size - pull_in->offset,
633                          pull_in->offset, pull_in->offset,
634                          call->name));
635                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
636                    but it turns out that early versions of NT
637                    (specifically NT3.1) add junk onto the end of rpc
638                    packets, so if we want to interoperate at all with
639                    those versions then we need to ignore this error */
640         }
641
642         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
643                 NTSTATUS status;
644
645                 status = dcerpc_ndr_validate_out(hs->p->conn,
646                                                  pull_in,
647                                                  struct_ptr,
648                                                  call->struct_size,
649                                                  call->ndr_push,
650                                                  call->ndr_pull,
651                                                  call->ndr_print);
652                 if (!NT_STATUS_IS_OK(status)) {
653                         DEBUG(2,("Validation [out] failed for %s - %s\n",
654                                  call->name, nt_errstr(status)));
655                         return status;
656                 }
657         }
658
659         return NT_STATUS_OK;
660 }
661
662 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
663         .name                   = "dcerpc",
664         .is_connected           = dcerpc_bh_is_connected,
665         .set_timeout            = dcerpc_bh_set_timeout,
666         .auth_info              = dcerpc_bh_auth_info,
667         .raw_call_send          = dcerpc_bh_raw_call_send,
668         .raw_call_recv          = dcerpc_bh_raw_call_recv,
669         .disconnect_send        = dcerpc_bh_disconnect_send,
670         .disconnect_recv        = dcerpc_bh_disconnect_recv,
671
672         .push_bigendian         = dcerpc_bh_push_bigendian,
673         .ref_alloc              = dcerpc_bh_ref_alloc,
674         .use_ndr64              = dcerpc_bh_use_ndr64,
675         .do_ndr_print           = dcerpc_bh_do_ndr_print,
676         .ndr_push_failed        = dcerpc_bh_ndr_push_failed,
677         .ndr_pull_failed        = dcerpc_bh_ndr_pull_failed,
678         .ndr_validate_in        = dcerpc_bh_ndr_validate_in,
679         .ndr_validate_out       = dcerpc_bh_ndr_validate_out,
680 };
681
682 /* initialise a dcerpc pipe. */
683 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
684                                                          const struct GUID *object,
685                                                          const struct ndr_interface_table *table)
686 {
687         struct dcerpc_binding_handle *h;
688         struct dcerpc_bh_state *hs;
689
690         h = dcerpc_binding_handle_create(p,
691                                          &dcerpc_bh_ops,
692                                          object,
693                                          table,
694                                          &hs,
695                                          struct dcerpc_bh_state,
696                                          __location__);
697         if (h == NULL) {
698                 return NULL;
699         }
700         hs->p = p;
701
702         dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
703
704         return h;
705 }
706
707 /* initialise a dcerpc pipe. */
708 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
709 {
710         struct dcerpc_pipe *p;
711
712         p = talloc_zero(mem_ctx, struct dcerpc_pipe);
713         if (!p) {
714                 return NULL;
715         }
716
717         p->conn = dcerpc_connection_init(p, ev);
718         if (p->conn == NULL) {
719                 talloc_free(p);
720                 return NULL;
721         }
722
723         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
724
725         if (DEBUGLVL(100)) {
726                 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
727         }
728
729         return p;
730 }
731
732
733 /* 
734    choose the next call id to use
735 */
736 static uint32_t next_call_id(struct dcecli_connection *c)
737 {
738         c->call_id++;
739         if (c->call_id == 0) {
740                 c->call_id++;
741         }
742         return c->call_id;
743 }
744
745 /**
746   setup for a ndr pull, also setting up any flags from the binding string
747 */
748 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c, 
749                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
750 {
751         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
752
753         if (ndr == NULL) return ndr;
754
755         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
756                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
757         }
758
759         if (c->flags & DCERPC_NDR_REF_ALLOC) {
760                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
761         }
762
763         if (c->flags & DCERPC_NDR64) {
764                 ndr->flags |= LIBNDR_FLAG_NDR64;
765         }
766
767         return ndr;
768 }
769
770 /* 
771    parse the authentication information on a dcerpc response packet
772 */
773 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
774                                     TALLOC_CTX *mem_ctx,
775                                     enum dcerpc_pkt_type ptype,
776                                     uint8_t required_flags,
777                                     uint8_t optional_flags,
778                                     uint8_t payload_offset,
779                                     DATA_BLOB *payload_and_verifier,
780                                     DATA_BLOB *raw_packet,
781                                     const struct ncacn_packet *pkt)
782 {
783         const struct dcerpc_auth tmp_auth = {
784                 .auth_type = c->security_state.auth_type,
785                 .auth_level = c->security_state.auth_level,
786                 .auth_context_id = c->security_state.auth_context_id,
787         };
788         NTSTATUS status;
789
790         status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
791                                             c->security_state.generic_state,
792                                             mem_ctx,
793                                             ptype,
794                                             required_flags,
795                                             optional_flags,
796                                             payload_offset,
797                                             payload_and_verifier,
798                                             raw_packet,
799                                             pkt);
800         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
801                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
802         }
803         if (!NT_STATUS_IS_OK(status)) {
804                 return status;
805         }
806
807         return NT_STATUS_OK;
808 }
809
810
811 /* 
812    push a dcerpc request packet into a blob, possibly signing it.
813 */
814 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, 
815                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
816                                          size_t sig_size,
817                                          struct ncacn_packet *pkt)
818 {
819         const struct dcerpc_auth tmp_auth = {
820                 .auth_type = c->security_state.auth_type,
821                 .auth_level = c->security_state.auth_level,
822                 .auth_context_id = c->security_state.auth_context_id,
823         };
824         NTSTATUS status;
825         uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
826
827         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
828                 payload_offset += 16;
829         }
830
831         status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
832                                             c->security_state.generic_state,
833                                             mem_ctx, blob,
834                                             sig_size,
835                                             payload_offset,
836                                             &pkt->u.request.stub_and_verifier,
837                                             pkt);
838         if (!NT_STATUS_IS_OK(status)) {
839                 return status;
840         }
841
842         return NT_STATUS_OK;
843 }
844
845
846 /* 
847    fill in the fixed values in a dcerpc header 
848 */
849 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
850 {
851         pkt->rpc_vers = 5;
852         pkt->rpc_vers_minor = 0;
853         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
854                 pkt->drep[0] = 0;
855         } else {
856                 pkt->drep[0] = DCERPC_DREP_LE;
857         }
858         pkt->drep[1] = 0;
859         pkt->drep[2] = 0;
860         pkt->drep[3] = 0;
861 }
862
863 /*
864   map a bind nak reason to a NTSTATUS
865 */
866 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
867 {
868         switch (reason) {
869         case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
870                 return NT_STATUS_REVISION_MISMATCH;
871         case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
872                 return NT_STATUS_INVALID_PARAMETER;
873         default:
874                 break;
875         }
876         return NT_STATUS_UNSUCCESSFUL;
877 }
878
879 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
880 {
881         if (ack == NULL) {
882                 return NT_STATUS_RPC_PROTOCOL_ERROR;
883         }
884
885         switch (ack->result) {
886         case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
887                 /*
888                  * We have not asked for this...
889                  */
890                 return NT_STATUS_RPC_PROTOCOL_ERROR;
891         default:
892                 break;
893         }
894
895         switch (ack->reason.value) {
896         case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
897                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
898         case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
899                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
900         default:
901                 break;
902         }
903         return NT_STATUS_UNSUCCESSFUL;
904 }
905
906 /*
907   remove requests from the pending or queued queues
908  */
909 static int dcerpc_req_dequeue(struct rpc_request *req)
910 {
911         switch (req->state) {
912         case RPC_REQUEST_QUEUED:
913                 DLIST_REMOVE(req->p->conn->request_queue, req);
914                 break;
915         case RPC_REQUEST_PENDING:
916                 DLIST_REMOVE(req->p->conn->pending, req);
917                 break;
918         case RPC_REQUEST_DONE:
919                 break;
920         }
921         return 0;
922 }
923
924
925 /*
926   mark the dcerpc connection dead. All outstanding requests get an error
927 */
928 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
929 {
930         if (conn->dead) return;
931
932         conn->dead = true;
933
934         TALLOC_FREE(conn->io_trigger);
935         conn->io_trigger_pending = false;
936
937         dcerpc_shutdown_pipe(conn, status);
938
939         /* all pending requests get the error */
940         while (conn->pending) {
941                 struct rpc_request *req = conn->pending;
942                 dcerpc_req_dequeue(req);
943                 req->state = RPC_REQUEST_DONE;
944                 req->status = status;
945                 if (req->async.callback) {
946                         req->async.callback(req);
947                 }
948         }       
949
950         /* all requests, which are not shipped */
951         while (conn->request_queue) {
952                 struct rpc_request *req = conn->request_queue;
953                 dcerpc_req_dequeue(req);
954                 req->state = RPC_REQUEST_DONE;
955                 req->status = status;
956                 if (req->async.callback) {
957                         req->async.callback(req);
958                 }
959         }
960
961         talloc_set_destructor(conn, NULL);
962         if (conn->free_skipped) {
963                 talloc_free(conn);
964         }
965 }
966
967 /*
968   forward declarations of the recv_data handlers for the types of
969   packets we need to handle
970 */
971 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
972                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
973
974 /*
975   receive a dcerpc reply from the transport. Here we work out what
976   type of reply it is (normal request, bind or alter context) and
977   dispatch to the appropriate handler
978 */
979 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
980 {
981         struct ncacn_packet pkt;
982
983         if (conn->dead) {
984                 return;
985         }
986
987         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
988                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
989         }
990
991         /* the transport may be telling us of a severe error, such as
992            a dropped socket */
993         if (!NT_STATUS_IS_OK(status)) {
994                 data_blob_free(blob);
995                 dcerpc_connection_dead(conn, status);
996                 return;
997         }
998
999         /* parse the basic packet to work out what type of response this is */
1000         status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
1001         if (!NT_STATUS_IS_OK(status)) {
1002                 data_blob_free(blob);
1003                 dcerpc_connection_dead(conn, status);
1004                 return;
1005         }
1006
1007         dcerpc_request_recv_data(conn, blob, &pkt);
1008 }
1009
1010 /*
1011   handle timeouts of individual dcerpc requests
1012 */
1013 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
1014                                    struct timeval t, void *private_data)
1015 {
1016         struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1017
1018         if (req->ignore_timeout) {
1019                 dcerpc_req_dequeue(req);
1020                 req->state = RPC_REQUEST_DONE;
1021                 req->status = NT_STATUS_IO_TIMEOUT;
1022                 if (req->async.callback) {
1023                         req->async.callback(req);
1024                 }
1025                 return;
1026         }
1027
1028         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1029 }
1030
1031 struct dcerpc_bind_state {
1032         struct tevent_context *ev;
1033         struct dcerpc_pipe *p;
1034 };
1035
1036 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1037 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1038                                      DATA_BLOB *raw_packet,
1039                                      struct ncacn_packet *pkt);
1040
1041 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1042                                     struct tevent_context *ev,
1043                                     struct dcerpc_pipe *p,
1044                                     const struct ndr_syntax_id *syntax,
1045                                     const struct ndr_syntax_id *transfer_syntax)
1046 {
1047         struct tevent_req *req;
1048         struct dcerpc_bind_state *state;
1049         struct ncacn_packet pkt;
1050         DATA_BLOB blob;
1051         NTSTATUS status;
1052         struct rpc_request *subreq;
1053         uint32_t flags;
1054         struct ndr_syntax_id bind_time_features;
1055
1056         bind_time_features = dcerpc_construct_bind_time_features(
1057                         DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1058                         DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1059
1060         req = tevent_req_create(mem_ctx, &state,
1061                                 struct dcerpc_bind_state);
1062         if (req == NULL) {
1063                 return NULL;
1064         }
1065
1066         state->ev = ev;
1067         state->p = p;
1068
1069         p->syntax = *syntax;
1070         p->transfer_syntax = *transfer_syntax;
1071
1072         flags = dcerpc_binding_get_flags(p->binding);
1073
1074         init_ncacn_hdr(p->conn, &pkt);
1075
1076         pkt.ptype = DCERPC_PKT_BIND;
1077         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1078         pkt.call_id = p->conn->call_id;
1079         pkt.auth_length = 0;
1080
1081         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1082                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1083         }
1084
1085         if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1086                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1087         }
1088
1089         pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1090         pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1091         pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1092         pkt.u.bind.num_contexts = 2;
1093         pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1094                                                 pkt.u.bind.num_contexts);
1095         if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1096                 return tevent_req_post(req, ev);
1097         }
1098         pkt.u.bind.ctx_list[0].context_id = p->context_id;
1099         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1100         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1101         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1102         pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1103         pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1104         pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1105         pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1106         pkt.u.bind.auth_info = data_blob(NULL, 0);
1107
1108         /* construct the NDR form of the packet */
1109         status = ncacn_push_auth(&blob, state, &pkt,
1110                                  p->conn->security_state.tmp_auth_info.out);
1111         if (tevent_req_nterror(req, status)) {
1112                 return tevent_req_post(req, ev);
1113         }
1114
1115         /*
1116          * we allocate a dcerpc_request so we can be in the same
1117          * request queue as normal requests
1118          */
1119         subreq = talloc_zero(state, struct rpc_request);
1120         if (tevent_req_nomem(subreq, req)) {
1121                 return tevent_req_post(req, ev);
1122         }
1123
1124         subreq->state = RPC_REQUEST_PENDING;
1125         subreq->call_id = pkt.call_id;
1126         subreq->async.private_data = req;
1127         subreq->async.callback = dcerpc_bind_fail_handler;
1128         subreq->p = p;
1129         subreq->recv_handler = dcerpc_bind_recv_handler;
1130         DLIST_ADD_END(p->conn->pending, subreq);
1131         talloc_set_destructor(subreq, dcerpc_req_dequeue);
1132
1133         status = dcerpc_send_request(p->conn, &blob, true);
1134         if (tevent_req_nterror(req, status)) {
1135                 return tevent_req_post(req, ev);
1136         }
1137
1138         tevent_add_timer(ev, subreq,
1139                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1140                          dcerpc_timeout_handler, subreq);
1141
1142         return req;
1143 }
1144
1145 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1146 {
1147         struct tevent_req *req =
1148                 talloc_get_type_abort(subreq->async.private_data,
1149                 struct tevent_req);
1150         struct dcerpc_bind_state *state =
1151                 tevent_req_data(req,
1152                 struct dcerpc_bind_state);
1153         NTSTATUS status = subreq->status;
1154
1155         TALLOC_FREE(subreq);
1156
1157         /*
1158          * We trigger the callback in the next event run
1159          * because the code in this file might trigger
1160          * multiple request callbacks from within a single
1161          * while loop.
1162          *
1163          * In order to avoid segfaults from within
1164          * dcerpc_connection_dead() we call
1165          * tevent_req_defer_callback().
1166          */
1167         tevent_req_defer_callback(req, state->ev);
1168
1169         tevent_req_nterror(req, status);
1170 }
1171
1172 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1173                                      DATA_BLOB *raw_packet,
1174                                      struct ncacn_packet *pkt)
1175 {
1176         struct tevent_req *req =
1177                 talloc_get_type_abort(subreq->async.private_data,
1178                 struct tevent_req);
1179         struct dcerpc_bind_state *state =
1180                 tevent_req_data(req,
1181                 struct dcerpc_bind_state);
1182         struct dcecli_connection *conn = state->p->conn;
1183         struct dcecli_security *sec = &conn->security_state;
1184         struct dcerpc_binding *b = NULL;
1185         NTSTATUS status;
1186         uint32_t flags;
1187
1188         /*
1189          * Note that pkt is allocated under raw_packet->data,
1190          * while raw_packet->data is a child of subreq.
1191          */
1192         talloc_steal(state, raw_packet->data);
1193         TALLOC_FREE(subreq);
1194
1195         /*
1196          * We trigger the callback in the next event run
1197          * because the code in this file might trigger
1198          * multiple request callbacks from within a single
1199          * while loop.
1200          *
1201          * In order to avoid segfaults from within
1202          * dcerpc_connection_dead() we call
1203          * tevent_req_defer_callback().
1204          */
1205         tevent_req_defer_callback(req, state->ev);
1206
1207         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1208                 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1209
1210                 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1211                          pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1212
1213                 tevent_req_nterror(req, status);
1214                 return;
1215         }
1216
1217         status = dcerpc_verify_ncacn_packet_header(pkt,
1218                                         DCERPC_PKT_BIND_ACK,
1219                                         pkt->u.bind_ack.auth_info.length,
1220                                         DCERPC_PFC_FLAG_FIRST |
1221                                         DCERPC_PFC_FLAG_LAST,
1222                                         DCERPC_PFC_FLAG_CONC_MPX |
1223                                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1224         if (!NT_STATUS_IS_OK(status)) {
1225                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1226                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1227                 return;
1228         }
1229
1230         if (pkt->u.bind_ack.num_results < 1) {
1231                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1232                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1233                 return;
1234         }
1235
1236         if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1237                 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1238                 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1239                          pkt->u.bind_ack.ctx_list[0].reason.value,
1240                          nt_errstr(status)));
1241                 tevent_req_nterror(req, status);
1242                 return;
1243         }
1244
1245         if (pkt->u.bind_ack.num_results >= 2) {
1246                 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1247                         conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1248                 } else {
1249                         status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1250                         DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1251                                  pkt->u.bind_ack.ctx_list[1].reason.value,
1252                                  nt_errstr(status)));
1253                         status = NT_STATUS_OK;
1254                 }
1255         }
1256
1257         /*
1258          * DCE-RPC 1.1 (c706) specifies
1259          * CONST_MUST_RCV_FRAG_SIZE as 1432
1260          */
1261         if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1262                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1263                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1264                 return;
1265         }
1266         if (pkt->u.bind_ack.max_recv_frag < 1432) {
1267                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1268                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1269                 return;
1270         }
1271         conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1272                                       pkt->u.bind_ack.max_xmit_frag);
1273         conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1274                                       pkt->u.bind_ack.max_recv_frag);
1275
1276         flags = dcerpc_binding_get_flags(state->p->binding);
1277
1278         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1279                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1280                         conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1281                 } else {
1282                         conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1283                 }
1284         }
1285
1286         if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1287                 struct dcerpc_binding *pb =
1288                         discard_const_p(struct dcerpc_binding, state->p->binding);
1289                 /*
1290                  * clear DCERPC_CONCURRENT_MULTIPLEX
1291                  */
1292                 status = dcerpc_binding_set_flags(pb, 0,
1293                                                   DCERPC_CONCURRENT_MULTIPLEX);
1294                 if (tevent_req_nterror(req, status)) {
1295                         return;
1296                 }
1297         }
1298         if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1299             (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1300                 conn->flags |= DCERPC_HEADER_SIGNING;
1301         }
1302
1303         /* the bind_ack might contain a reply set of credentials */
1304         if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1305                 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1306                                                   &pkt->u.bind_ack.auth_info,
1307                                                   sec->tmp_auth_info.in,
1308                                                   NULL, true);
1309                 if (tevent_req_nterror(req, status)) {
1310                         return;
1311                 }
1312         }
1313
1314         /*
1315          * We're the owner of the binding, so we're allowed to modify it.
1316          */
1317         b = discard_const_p(struct dcerpc_binding, state->p->binding);
1318         status = dcerpc_binding_set_assoc_group_id(b,
1319                                                    pkt->u.bind_ack.assoc_group_id);
1320         if (tevent_req_nterror(req, status)) {
1321                 return;
1322         }
1323
1324         tevent_req_done(req);
1325 }
1326
1327 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1328 {
1329         return tevent_req_simple_recv_ntstatus(req);
1330 }
1331
1332 /* 
1333    perform a continued bind (and auth3)
1334 */
1335 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1336                       TALLOC_CTX *mem_ctx)
1337 {
1338         struct ncacn_packet pkt;
1339         NTSTATUS status;
1340         DATA_BLOB blob;
1341         uint32_t flags;
1342
1343         flags = dcerpc_binding_get_flags(p->binding);
1344
1345         init_ncacn_hdr(p->conn, &pkt);
1346
1347         pkt.ptype = DCERPC_PKT_AUTH3;
1348         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1349         pkt.call_id = next_call_id(p->conn);
1350         pkt.auth_length = 0;
1351         pkt.u.auth3.auth_info = data_blob(NULL, 0);
1352
1353         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1354                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1355         }
1356
1357         /* construct the NDR form of the packet */
1358         status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1359                                  p->conn->security_state.tmp_auth_info.out);
1360         if (!NT_STATUS_IS_OK(status)) {
1361                 return status;
1362         }
1363
1364         /* send it on its way */
1365         status = dcerpc_send_request(p->conn, &blob, false);
1366         if (!NT_STATUS_IS_OK(status)) {
1367                 return status;
1368         }
1369
1370         return NT_STATUS_OK;    
1371 }
1372
1373
1374 /*
1375   process a fragment received from the transport layer during a
1376   request
1377
1378   This function frees the data 
1379 */
1380 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
1381                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1382 {
1383         struct rpc_request *req;
1384         unsigned int length;
1385         NTSTATUS status = NT_STATUS_OK;
1386
1387         /*
1388           if this is an authenticated connection then parse and check
1389           the auth info. We have to do this before finding the
1390           matching packet, as the request structure might have been
1391           removed due to a timeout, but if it has been we still need
1392           to run the auth routines so that we don't get the sign/seal
1393           info out of step with the server
1394         */
1395         switch (pkt->ptype) {
1396         case DCERPC_PKT_RESPONSE:
1397                 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1398                                    DCERPC_PKT_RESPONSE,
1399                                    0, /* required_flags */
1400                                    DCERPC_PFC_FLAG_FIRST |
1401                                    DCERPC_PFC_FLAG_LAST,
1402                                    DCERPC_REQUEST_LENGTH,
1403                                    &pkt->u.response.stub_and_verifier,
1404                                    raw_packet, pkt);
1405                 break;
1406         default:
1407                 break;
1408         }
1409
1410         /* find the matching request */
1411         for (req=c->pending;req;req=req->next) {
1412                 if (pkt->call_id == req->call_id) break;
1413         }
1414
1415 #if 0
1416         /* useful for testing certain vendors RPC servers */
1417         if (req == NULL && c->pending && pkt->call_id == 0) {
1418                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1419                 req = c->pending;
1420         }
1421 #endif
1422
1423         if (req == NULL) {
1424                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1425                 data_blob_free(raw_packet);
1426                 return;
1427         }
1428
1429         talloc_steal(req, raw_packet->data);
1430
1431         if (req->recv_handler != NULL) {
1432                 dcerpc_req_dequeue(req);
1433                 req->state = RPC_REQUEST_DONE;
1434
1435                 /*
1436                  * We have to look at shipping further requests before calling
1437                  * the async function, that one might close the pipe
1438                  */
1439                 dcerpc_schedule_io_trigger(c);
1440
1441                 req->recv_handler(req, raw_packet, pkt);
1442                 return;
1443         }
1444
1445         if (pkt->ptype == DCERPC_PKT_FAULT) {
1446                 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1447                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1448                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1449                         dcerpc_connection_dead(c, status);
1450                         return;
1451                 }
1452                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1453                         dcerpc_connection_dead(c, status);
1454                         return;
1455                 }
1456                 req->fault_code = pkt->u.fault.status;
1457                 req->status = NT_STATUS_NET_WRITE_FAULT;
1458                 goto req_done;
1459         }
1460
1461         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1462                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1463                          (int)pkt->ptype)); 
1464                 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1465                 return;
1466         }
1467
1468         /* now check the status from the auth routines, and if it failed then fail
1469            this request accordingly */
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 dcerpc_connection_dead(c, status);
1472                 return;
1473         }
1474
1475         if (req->state != RPC_REQUEST_PENDING) {
1476                 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1477                 goto req_done;
1478         }
1479
1480         if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1481                 if (req->first_pdu_done) {
1482                         req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1483                         goto req_done;
1484                 }
1485                 req->first_pdu_done = true;
1486
1487                 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1488                         req->flags |= DCERPC_PULL_BIGENDIAN;
1489                 } else {
1490                         req->flags &= ~DCERPC_PULL_BIGENDIAN;
1491                 }
1492         }
1493
1494         if (!req->first_pdu_done) {
1495                 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1496                 goto req_done;
1497         }
1498
1499         length = pkt->u.response.stub_and_verifier.length;
1500
1501         if (req->payload.length + length > c->max_total_response_size) {
1502                 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1503                          (unsigned)req->payload.length + length,
1504                          (unsigned)c->max_total_response_size));
1505                 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1506                 return;
1507         }
1508
1509         if (length > 0) {
1510                 req->payload.data = talloc_realloc(req, 
1511                                                    req->payload.data, 
1512                                                    uint8_t,
1513                                                    req->payload.length + length);
1514                 if (!req->payload.data) {
1515                         req->status = NT_STATUS_NO_MEMORY;
1516                         goto req_done;
1517                 }
1518                 memcpy(req->payload.data+req->payload.length, 
1519                        pkt->u.response.stub_and_verifier.data, length);
1520                 req->payload.length += length;
1521         }
1522
1523         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1524                 data_blob_free(raw_packet);
1525
1526                 req->status = dcerpc_send_read(c);
1527                 if (!NT_STATUS_IS_OK(req->status)) {
1528                         goto req_done;
1529                 }
1530
1531                 if (!req->incomplete_request_data) {
1532                         return;
1533                 }
1534
1535                 if (req->async.callback) {
1536                         req->async.callback(req);
1537                 }
1538                 return;
1539         }
1540
1541         if (req->verify_bitmask1) {
1542                 req->p->conn->security_state.verified_bitmask1 = true;
1543         }
1544         if (req->verify_pcontext) {
1545                 req->p->verified_pcontext = true;
1546         }
1547
1548         req->incomplete_request_data = false;
1549
1550 req_done:
1551         data_blob_free(raw_packet);
1552
1553         /* we've got the full payload */
1554         dcerpc_req_dequeue(req);
1555         req->state = RPC_REQUEST_DONE;
1556
1557         /*
1558          * We have to look at shipping further requests before calling
1559          * the async function, that one might close the pipe
1560          */
1561         dcerpc_schedule_io_trigger(c);
1562
1563         if (req->async.callback) {
1564                 req->async.callback(req);
1565         }
1566 }
1567
1568 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1569
1570 /*
1571   perform the send side of a async dcerpc request
1572 */
1573 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1574                                                struct dcerpc_pipe *p,
1575                                                const struct GUID *object,
1576                                                uint16_t opnum,
1577                                                DATA_BLOB *stub_data)
1578 {
1579         struct rpc_request *req;
1580         NTSTATUS status;
1581
1582         req = talloc_zero(mem_ctx, struct rpc_request);
1583         if (req == NULL) {
1584                 return NULL;
1585         }
1586
1587         req->p = p;
1588         req->call_id = next_call_id(p->conn);
1589         req->state = RPC_REQUEST_QUEUED;
1590
1591         if (object != NULL) {
1592                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1593                 if (req->object == NULL) {
1594                         talloc_free(req);
1595                         return NULL;
1596                 }
1597         }
1598
1599         req->opnum = opnum;
1600         req->request_data.length = stub_data->length;
1601         req->request_data.data = stub_data->data;
1602
1603         status = dcerpc_request_prepare_vt(req);
1604         if (!NT_STATUS_IS_OK(status)) {
1605                 talloc_free(req);
1606                 return NULL;
1607         }
1608
1609         DLIST_ADD_END(p->conn->request_queue, req);
1610         talloc_set_destructor(req, dcerpc_req_dequeue);
1611
1612         dcerpc_schedule_io_trigger(p->conn);
1613
1614         if (p->request_timeout) {
1615                 tevent_add_timer(p->conn->event_ctx, req,
1616                                 timeval_current_ofs(p->request_timeout, 0), 
1617                                 dcerpc_timeout_handler, req);
1618         }
1619
1620         return req;
1621 }
1622
1623 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1624 {
1625         struct dcecli_security *sec = &req->p->conn->security_state;
1626         struct dcerpc_sec_verification_trailer *t;
1627         struct dcerpc_sec_vt *c = NULL;
1628         struct ndr_push *ndr = NULL;
1629         enum ndr_err_code ndr_err;
1630
1631         if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1632                 return NT_STATUS_OK;
1633         }
1634
1635         t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1636         if (t == NULL) {
1637                 return NT_STATUS_NO_MEMORY;
1638         }
1639
1640         if (!sec->verified_bitmask1) {
1641                 t->commands = talloc_realloc(t, t->commands,
1642                                              struct dcerpc_sec_vt,
1643                                              t->count.count + 1);
1644                 if (t->commands == NULL) {
1645                         return NT_STATUS_NO_MEMORY;
1646                 }
1647                 c = &t->commands[t->count.count++];
1648                 ZERO_STRUCTP(c);
1649
1650                 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1651                 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1652                         c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1653                 }
1654                 req->verify_bitmask1 = true;
1655         }
1656
1657         if (!req->p->verified_pcontext) {
1658                 t->commands = talloc_realloc(t, t->commands,
1659                                              struct dcerpc_sec_vt,
1660                                              t->count.count + 1);
1661                 if (t->commands == NULL) {
1662                         return NT_STATUS_NO_MEMORY;
1663                 }
1664                 c = &t->commands[t->count.count++];
1665                 ZERO_STRUCTP(c);
1666
1667                 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1668                 c->u.pcontext.abstract_syntax = req->p->syntax;
1669                 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1670
1671                 req->verify_pcontext = true;
1672         }
1673
1674         if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1675                 t->commands = talloc_realloc(t, t->commands,
1676                                              struct dcerpc_sec_vt,
1677                                              t->count.count + 1);
1678                 if (t->commands == NULL) {
1679                         return NT_STATUS_NO_MEMORY;
1680                 }
1681                 c = &t->commands[t->count.count++];
1682                 ZERO_STRUCTP(c);
1683
1684                 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1685                 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1686                 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1687                         c->u.header2.drep[0] = 0;
1688                 } else {
1689                         c->u.header2.drep[0] = DCERPC_DREP_LE;
1690                 }
1691                 c->u.header2.drep[1] = 0;
1692                 c->u.header2.drep[2] = 0;
1693                 c->u.header2.drep[3] = 0;
1694                 c->u.header2.call_id = req->call_id;
1695                 c->u.header2.context_id = req->p->context_id;
1696                 c->u.header2.opnum = req->opnum;
1697         }
1698
1699         if (t->count.count == 0) {
1700                 TALLOC_FREE(t);
1701                 return NT_STATUS_OK;
1702         }
1703
1704         c = &t->commands[t->count.count - 1];
1705         c->command |= DCERPC_SEC_VT_COMMAND_END;
1706
1707         if (DEBUGLEVEL >= 10) {
1708                 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1709         }
1710
1711         ndr = ndr_push_init_ctx(req);
1712         if (ndr == NULL) {
1713                 return NT_STATUS_NO_MEMORY;
1714         }
1715
1716         /*
1717          * for now we just copy and append
1718          */
1719
1720         ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1721                                  req->request_data.length);
1722         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1723                 return ndr_map_error2ntstatus(ndr_err);
1724         }
1725
1726         ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1727                                                 NDR_SCALARS | NDR_BUFFERS,
1728                                                 t);
1729         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1730                 return ndr_map_error2ntstatus(ndr_err);
1731         }
1732         req->request_data = ndr_push_blob(ndr);
1733
1734         return NT_STATUS_OK;
1735 }
1736
1737 /*
1738   Send a request using the transport
1739 */
1740
1741 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1742 {
1743         struct rpc_request *req;
1744         struct dcerpc_pipe *p;
1745         DATA_BLOB *stub_data;
1746         struct ncacn_packet pkt;
1747         DATA_BLOB blob;
1748         uint32_t remaining, chunk_size;
1749         size_t sig_size = 0;
1750         bool need_async = false;
1751         bool can_async = true;
1752
1753         req = c->request_queue;
1754         if (req == NULL) {
1755                 return;
1756         }
1757
1758         p = req->p;
1759         stub_data = &req->request_data;
1760
1761         if (c->pending) {
1762                 need_async = true;
1763         }
1764
1765         if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1766                 can_async = gensec_have_feature(c->security_state.generic_state,
1767                                                 GENSEC_FEATURE_ASYNC_REPLIES);
1768         }
1769
1770         if (need_async && !can_async) {
1771                 req->wait_for_sync = true;
1772                 return;
1773         }
1774
1775         init_ncacn_hdr(p->conn, &pkt);
1776
1777         remaining = stub_data->length;
1778
1779         /* we can write a full max_recv_frag size, minus the dcerpc
1780            request header size */
1781         chunk_size = p->conn->srv_max_recv_frag;
1782         chunk_size -= DCERPC_REQUEST_LENGTH;
1783         if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1784                 size_t max_payload = chunk_size;
1785
1786                 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1787                 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1788
1789                 sig_size = gensec_sig_size(c->security_state.generic_state,
1790                                            max_payload);
1791                 if (sig_size) {
1792                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1793                         chunk_size -= sig_size;
1794                 }
1795         }
1796         chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1797
1798         pkt.ptype = DCERPC_PKT_REQUEST;
1799         pkt.call_id = req->call_id;
1800         pkt.auth_length = 0;
1801         pkt.pfc_flags = 0;
1802         pkt.u.request.context_id = p->context_id;
1803         pkt.u.request.opnum = req->opnum;
1804
1805         if (req->object) {
1806                 pkt.u.request.object.object = *req->object;
1807                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1808                 chunk_size -= ndr_size_GUID(req->object,0);
1809         }
1810
1811         /* we send a series of pdus without waiting for a reply */
1812         while (remaining > 0 || !req->first_pdu_done) {
1813                 uint32_t chunk = MIN(chunk_size, remaining);
1814                 bool last_frag = false;
1815                 bool do_trans = false;
1816
1817                 if ((chunk == remaining) && !req->incomplete_request_data) {
1818                         last_frag = true;
1819                 }
1820
1821                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1822
1823                 if (!req->first_pdu_done) {
1824                         req->first_pdu_done = true;
1825                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1826                 }
1827                 if (last_frag) {
1828                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1829                 }
1830
1831                 pkt.u.request.alloc_hint = remaining;
1832                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1833                         (stub_data->length - remaining);
1834                 pkt.u.request.stub_and_verifier.length = chunk;
1835
1836                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1837                 if (!NT_STATUS_IS_OK(req->status)) {
1838                         req->state = RPC_REQUEST_DONE;
1839                         DLIST_REMOVE(c->request_queue, req);
1840                         return;
1841                 }
1842
1843                 if (last_frag && !need_async) {
1844                         do_trans = true;
1845                 }
1846
1847                 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1848                 if (!NT_STATUS_IS_OK(req->status)) {
1849                         req->state = RPC_REQUEST_DONE;
1850                         DLIST_REMOVE(c->request_queue, req);
1851                         return;
1852                 }               
1853
1854                 if (last_frag && !do_trans) {
1855                         req->status = dcerpc_send_read(p->conn);
1856                         if (!NT_STATUS_IS_OK(req->status)) {
1857                                 req->state = RPC_REQUEST_DONE;
1858                                 DLIST_REMOVE(c->request_queue, req);
1859                                 return;
1860                         }
1861                 }
1862
1863                 remaining -= chunk;
1864
1865         }
1866
1867         if (req->request_data_allocated) {
1868                 data_blob_free(&req->request_data);
1869         }
1870         req->request_data_allocated = false;
1871         req->request_data = data_blob_null;
1872
1873         if (!req->incomplete_request_data) {
1874                 DLIST_REMOVE(c->request_queue, req);
1875                 DLIST_ADD(c->pending, req);
1876                 req->state = RPC_REQUEST_PENDING;
1877                 /*
1878                  * we reuse first_pdu_done for the receive side
1879                  */
1880                 req->first_pdu_done = false;
1881         }
1882
1883                 if (req->stub_subreq == NULL) {
1884                         return;
1885                 }
1886
1887                 tevent_req_done(req->stub_subreq);
1888                 return;
1889         }
1890
1891 }
1892
1893 static void dcerpc_io_trigger(struct tevent_context *ctx,
1894                               struct tevent_immediate *im,
1895                               void *private_data)
1896 {
1897         struct dcecli_connection *c =
1898                 talloc_get_type_abort(private_data,
1899                 struct dcecli_connection);
1900
1901         c->io_trigger_pending = false;
1902
1903         dcerpc_schedule_io_trigger(c);
1904
1905         dcerpc_ship_next_request(c);
1906 }
1907
1908 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1909 {
1910         if (c->dead) {
1911                 return;
1912         }
1913
1914         if (c->request_queue == NULL) {
1915                 return;
1916         }
1917
1918         if (c->request_queue->wait_for_sync && c->pending) {
1919                 return;
1920         }
1921
1922         if (c->io_trigger_pending) {
1923                 return;
1924         }
1925
1926         c->io_trigger_pending = true;
1927
1928         tevent_schedule_immediate(c->io_trigger,
1929                                   c->event_ctx,
1930                                   dcerpc_io_trigger,
1931                                   c);
1932 }
1933
1934 /*
1935   perform the receive side of a async dcerpc request
1936 */
1937 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1938                                     TALLOC_CTX *mem_ctx,
1939                                     DATA_BLOB *stub_data)
1940 {
1941         NTSTATUS status;
1942
1943         *stub_data = req->payload;
1944         req->payload = data_blob_null;
1945         status = req->status;
1946         if (stub_data->data) {
1947                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1948         }
1949         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1950                 req->p->last_fault_code = req->fault_code;
1951         }
1952         if (req->state == RPC_REQUEST_PENDING) {
1953                 if (NT_STATUS_IS_OK(status)) {
1954                         return status;
1955                 }
1956         }
1957         talloc_unlink(talloc_parent(req), req);
1958         return status;
1959 }
1960
1961 /*
1962   this is a paranoid NDR validator. For every packet we push onto the wire
1963   we pull it back again, then push it again. Then we compare the raw NDR data
1964   for that to the NDR we initially generated. If they don't match then we know
1965   we must have a bug in either the pull or push side of our code
1966 */
1967 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c, 
1968                                        TALLOC_CTX *mem_ctx,
1969                                        DATA_BLOB blob,
1970                                        size_t struct_size,
1971                                        ndr_push_flags_fn_t ndr_push,
1972                                        ndr_pull_flags_fn_t ndr_pull)
1973 {
1974         void *st;
1975         struct ndr_pull *pull;
1976         struct ndr_push *push;
1977         DATA_BLOB blob2;
1978         enum ndr_err_code ndr_err;
1979
1980         st = talloc_size(mem_ctx, struct_size);
1981         if (!st) {
1982                 return NT_STATUS_NO_MEMORY;
1983         }
1984
1985         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1986         if (!pull) {
1987                 return NT_STATUS_NO_MEMORY;
1988         }
1989         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1990
1991         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1992                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1993         }
1994
1995         if (c->flags & DCERPC_NDR64) {
1996                 pull->flags |= LIBNDR_FLAG_NDR64;
1997         }
1998
1999         ndr_err = ndr_pull(pull, NDR_IN, st);
2000         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2001                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2002                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2003                                          "failed input validation pull - %s",
2004                                          nt_errstr(status));
2005                 return ndr_map_error2ntstatus(ndr_err);
2006         }
2007
2008         push = ndr_push_init_ctx(mem_ctx);
2009         if (!push) {
2010                 return NT_STATUS_NO_MEMORY;
2011         }       
2012
2013         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2014                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2015         }
2016
2017         if (c->flags & DCERPC_NDR64) {
2018                 push->flags |= LIBNDR_FLAG_NDR64;
2019         }
2020
2021         ndr_err = ndr_push(push, NDR_IN, st);
2022         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2023                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2024                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2025                                          "failed input validation push - %s",
2026                                          nt_errstr(status));
2027                 return ndr_map_error2ntstatus(ndr_err);
2028         }
2029
2030         blob2 = ndr_push_blob(push);
2031
2032         if (data_blob_cmp(&blob, &blob2) != 0) {
2033                 DEBUG(3,("original:\n"));
2034                 dump_data(3, blob.data, blob.length);
2035                 DEBUG(3,("secondary:\n"));
2036                 dump_data(3, blob2.data, blob2.length);
2037                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2038                                          "failed input validation blobs doesn't match");
2039                 return ndr_map_error2ntstatus(ndr_err);
2040         }
2041
2042         return NT_STATUS_OK;
2043 }
2044
2045 /*
2046   this is a paranoid NDR input validator. For every packet we pull
2047   from the wire we push it back again then pull and push it
2048   again. Then we compare the raw NDR data for that to the NDR we
2049   initially generated. If they don't match then we know we must have a
2050   bug in either the pull or push side of our code
2051 */
2052 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2053                                         struct ndr_pull *pull_in,
2054                                         void *struct_ptr,
2055                                         size_t struct_size,
2056                                         ndr_push_flags_fn_t ndr_push,
2057                                         ndr_pull_flags_fn_t ndr_pull,
2058                                         ndr_print_function_t ndr_print)
2059 {
2060         void *st;
2061         struct ndr_pull *pull;
2062         struct ndr_push *push;
2063         DATA_BLOB blob, blob2;
2064         TALLOC_CTX *mem_ctx = pull_in;
2065         char *s1, *s2;
2066         enum ndr_err_code ndr_err;
2067
2068         st = talloc_size(mem_ctx, struct_size);
2069         if (!st) {
2070                 return NT_STATUS_NO_MEMORY;
2071         }
2072         memcpy(st, struct_ptr, struct_size);
2073
2074         push = ndr_push_init_ctx(mem_ctx);
2075         if (!push) {
2076                 return NT_STATUS_NO_MEMORY;
2077         }       
2078
2079         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2080         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2081                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2082                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2083                                          "failed output validation push - %s",
2084                                          nt_errstr(status));
2085                 return ndr_map_error2ntstatus(ndr_err);
2086         }
2087
2088         blob = ndr_push_blob(push);
2089
2090         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2091         if (!pull) {
2092                 return NT_STATUS_NO_MEMORY;
2093         }
2094
2095         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2096         ndr_err = ndr_pull(pull, NDR_OUT, st);
2097         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2098                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2099                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2100                                          "failed output validation pull - %s",
2101                                          nt_errstr(status));
2102                 return ndr_map_error2ntstatus(ndr_err);
2103         }
2104
2105         push = ndr_push_init_ctx(mem_ctx);
2106         if (!push) {
2107                 return NT_STATUS_NO_MEMORY;
2108         }       
2109
2110         ndr_err = ndr_push(push, NDR_OUT, st);
2111         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2112                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2113                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2114                                          "failed output validation push2 - %s",
2115                                          nt_errstr(status));
2116                 return ndr_map_error2ntstatus(ndr_err);
2117         }
2118
2119         blob2 = ndr_push_blob(push);
2120
2121         if (data_blob_cmp(&blob, &blob2) != 0) {
2122                 DEBUG(3,("original:\n"));
2123                 dump_data(3, blob.data, blob.length);
2124                 DEBUG(3,("secondary:\n"));
2125                 dump_data(3, blob2.data, blob2.length);
2126                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2127                                          "failed output validation blobs doesn't match");
2128                 return ndr_map_error2ntstatus(ndr_err);
2129         }
2130
2131         /* this checks the printed forms of the two structures, which effectively
2132            tests all of the value() attributes */
2133         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
2134                                        NDR_OUT, struct_ptr);
2135         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
2136                                        NDR_OUT, st);
2137         if (strcmp(s1, s2) != 0) {
2138 #if 1
2139                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2140 #else
2141                 /* this is sometimes useful */
2142                 printf("VALIDATE ERROR\n");
2143                 file_save("wire.dat", s1, strlen(s1));
2144                 file_save("gen.dat", s2, strlen(s2));
2145                 system("diff -u wire.dat gen.dat");
2146 #endif
2147                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2148                                          "failed output validation strings doesn't match");
2149                 return ndr_map_error2ntstatus(ndr_err);
2150         }
2151
2152         return NT_STATUS_OK;
2153 }
2154
2155 /*
2156   a useful function for retrieving the server name we connected to
2157 */
2158 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2159 {
2160         return p->conn ? p->conn->server_name : NULL;
2161 }
2162
2163
2164 /*
2165   get the dcerpc auth_level for a open connection
2166 */
2167 uint32_t dcerpc_auth_level(struct dcecli_connection *c) 
2168 {
2169         uint8_t auth_level;
2170
2171         if (c->flags & DCERPC_SEAL) {
2172                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2173         } else if (c->flags & DCERPC_SIGN) {
2174                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2175         } else if (c->flags & DCERPC_PACKET) {
2176                 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2177         } else if (c->flags & DCERPC_CONNECT) {
2178                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2179         } else {
2180                 auth_level = DCERPC_AUTH_LEVEL_NONE;
2181         }
2182         return auth_level;
2183 }
2184
2185 struct dcerpc_alter_context_state {
2186         struct tevent_context *ev;
2187         struct dcerpc_pipe *p;
2188 };
2189
2190 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2191 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2192                                               DATA_BLOB *raw_packet,
2193                                               struct ncacn_packet *pkt);
2194
2195 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2196                                              struct tevent_context *ev,
2197                                              struct dcerpc_pipe *p,
2198                                              const struct ndr_syntax_id *syntax,
2199                                              const struct ndr_syntax_id *transfer_syntax)
2200 {
2201         struct tevent_req *req;
2202         struct dcerpc_alter_context_state *state;
2203         struct ncacn_packet pkt;
2204         DATA_BLOB blob;
2205         NTSTATUS status;
2206         struct rpc_request *subreq;
2207         uint32_t flags;
2208
2209         req = tevent_req_create(mem_ctx, &state,
2210                                 struct dcerpc_alter_context_state);
2211         if (req == NULL) {
2212                 return NULL;
2213         }
2214
2215         state->ev = ev;
2216         state->p = p;
2217
2218         p->syntax = *syntax;
2219         p->transfer_syntax = *transfer_syntax;
2220
2221         flags = dcerpc_binding_get_flags(p->binding);
2222
2223         init_ncacn_hdr(p->conn, &pkt);
2224
2225         pkt.ptype = DCERPC_PKT_ALTER;
2226         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2227         pkt.call_id = p->conn->call_id;
2228         pkt.auth_length = 0;
2229
2230         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2231                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2232         }
2233
2234         pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2235         pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2236         pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2237         pkt.u.alter.num_contexts = 1;
2238         pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2239                                                  pkt.u.alter.num_contexts);
2240         if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2241                 return tevent_req_post(req, ev);
2242         }
2243         pkt.u.alter.ctx_list[0].context_id = p->context_id;
2244         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2245         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2246         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2247         pkt.u.alter.auth_info = data_blob(NULL, 0);
2248
2249         /* construct the NDR form of the packet */
2250         status = ncacn_push_auth(&blob, state, &pkt,
2251                                  p->conn->security_state.tmp_auth_info.out);
2252         if (tevent_req_nterror(req, status)) {
2253                 return tevent_req_post(req, ev);
2254         }
2255
2256         /*
2257          * we allocate a dcerpc_request so we can be in the same
2258          * request queue as normal requests
2259          */
2260         subreq = talloc_zero(state, struct rpc_request);
2261         if (tevent_req_nomem(subreq, req)) {
2262                 return tevent_req_post(req, ev);
2263         }
2264
2265         subreq->state = RPC_REQUEST_PENDING;
2266         subreq->call_id = pkt.call_id;
2267         subreq->async.private_data = req;
2268         subreq->async.callback = dcerpc_alter_context_fail_handler;
2269         subreq->p = p;
2270         subreq->recv_handler = dcerpc_alter_context_recv_handler;
2271         DLIST_ADD_END(p->conn->pending, subreq);
2272         talloc_set_destructor(subreq, dcerpc_req_dequeue);
2273
2274         status = dcerpc_send_request(p->conn, &blob, true);
2275         if (tevent_req_nterror(req, status)) {
2276                 return tevent_req_post(req, ev);
2277         }
2278
2279         tevent_add_timer(ev, subreq,
2280                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2281                          dcerpc_timeout_handler, subreq);
2282
2283         return req;
2284 }
2285
2286 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2287 {
2288         struct tevent_req *req =
2289                 talloc_get_type_abort(subreq->async.private_data,
2290                 struct tevent_req);
2291         struct dcerpc_alter_context_state *state =
2292                 tevent_req_data(req,
2293                 struct dcerpc_alter_context_state);
2294         NTSTATUS status = subreq->status;
2295
2296         TALLOC_FREE(subreq);
2297
2298         /*
2299          * We trigger the callback in the next event run
2300          * because the code in this file might trigger
2301          * multiple request callbacks from within a single
2302          * while loop.
2303          *
2304          * In order to avoid segfaults from within
2305          * dcerpc_connection_dead() we call
2306          * tevent_req_defer_callback().
2307          */
2308         tevent_req_defer_callback(req, state->ev);
2309
2310         tevent_req_nterror(req, status);
2311 }
2312
2313 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2314                                               DATA_BLOB *raw_packet,
2315                                               struct ncacn_packet *pkt)
2316 {
2317         struct tevent_req *req =
2318                 talloc_get_type_abort(subreq->async.private_data,
2319                 struct tevent_req);
2320         struct dcerpc_alter_context_state *state =
2321                 tevent_req_data(req,
2322                 struct dcerpc_alter_context_state);
2323         struct dcecli_connection *conn = state->p->conn;
2324         struct dcecli_security *sec = &conn->security_state;
2325         NTSTATUS status;
2326
2327         /*
2328          * Note that pkt is allocated under raw_packet->data,
2329          * while raw_packet->data is a child of subreq.
2330          */
2331         talloc_steal(state, raw_packet->data);
2332         TALLOC_FREE(subreq);
2333
2334         /*
2335          * We trigger the callback in the next event run
2336          * because the code in this file might trigger
2337          * multiple request callbacks from within a single
2338          * while loop.
2339          *
2340          * In order to avoid segfaults from within
2341          * dcerpc_connection_dead() we call
2342          * tevent_req_defer_callback().
2343          */
2344         tevent_req_defer_callback(req, state->ev);
2345
2346         if (pkt->ptype == DCERPC_PKT_FAULT) {
2347                 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2348                          dcerpc_errstr(state, pkt->u.fault.status)));
2349                 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2350                         state->p->last_fault_code = pkt->u.fault.status;
2351                         tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2352                 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2353                         state->p->last_fault_code = pkt->u.fault.status;
2354                         tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2355                 } else {
2356                         state->p->last_fault_code = pkt->u.fault.status;
2357                         status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2358                         tevent_req_nterror(req, status);
2359                 }
2360                 return;
2361         }
2362
2363         status = dcerpc_verify_ncacn_packet_header(pkt,
2364                                         DCERPC_PKT_ALTER_RESP,
2365                                         pkt->u.alter_resp.auth_info.length,
2366                                         DCERPC_PFC_FLAG_FIRST |
2367                                         DCERPC_PFC_FLAG_LAST,
2368                                         DCERPC_PFC_FLAG_CONC_MPX |
2369                                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2370         if (!NT_STATUS_IS_OK(status)) {
2371                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2372                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2373                 return;
2374         }
2375
2376         if (pkt->u.alter_resp.num_results != 1) {
2377                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2378                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2379                 return;
2380         }
2381
2382         if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2383                 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2384                 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2385                          pkt->u.alter_resp.ctx_list[0].reason.value,
2386                          nt_errstr(status)));
2387                 tevent_req_nterror(req, status);
2388                 return;
2389         }
2390
2391         /* the alter_resp might contain a reply set of credentials */
2392         if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2393                 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2394                                                   &pkt->u.alter_resp.auth_info,
2395                                                   sec->tmp_auth_info.in,
2396                                                   NULL, true);
2397                 if (tevent_req_nterror(req, status)) {
2398                         return;
2399                 }
2400         }
2401
2402         tevent_req_done(req);
2403 }
2404
2405 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2406 {
2407         return tevent_req_simple_recv_ntstatus(req);
2408 }
2409
2410 /* 
2411    send a dcerpc alter_context request
2412 */
2413 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
2414                               TALLOC_CTX *mem_ctx,
2415                               const struct ndr_syntax_id *syntax,
2416                               const struct ndr_syntax_id *transfer_syntax)
2417 {
2418         struct tevent_req *subreq;
2419         struct tevent_context *ev = p->conn->event_ctx;
2420         bool ok;
2421
2422         /* TODO: create a new event context here */
2423
2424         subreq = dcerpc_alter_context_send(mem_ctx, ev,
2425                                            p, syntax, transfer_syntax);
2426         if (subreq == NULL) {
2427                 return NT_STATUS_NO_MEMORY;
2428         }
2429
2430         ok = tevent_req_poll(subreq, ev);
2431         if (!ok) {
2432                 NTSTATUS status;
2433                 status = map_nt_error_from_unix_common(errno);
2434                 return status;
2435         }
2436
2437         return dcerpc_alter_context_recv(subreq);
2438 }
2439
2440 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2441 {
2442         if (c->transport.stream == NULL) {
2443                 return;
2444         }
2445
2446         tevent_queue_stop(c->transport.write_queue);
2447         TALLOC_FREE(c->transport.read_subreq);
2448         TALLOC_FREE(c->transport.stream);
2449
2450         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2451                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2452         }
2453
2454         if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2455                 status = NT_STATUS_END_OF_FILE;
2456         }
2457
2458         dcerpc_recv_data(c, NULL, status);
2459 }
2460
2461
2462 /*
2463    shutdown SMB pipe connection
2464 */
2465 struct dcerpc_shutdown_pipe_state {
2466         struct dcecli_connection *c;
2467         NTSTATUS status;
2468 };
2469
2470 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2471
2472 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2473 {
2474         struct dcerpc_shutdown_pipe_state *state;
2475         struct tevent_req *subreq;
2476
2477         if (c->transport.stream == NULL) {
2478                 return NT_STATUS_OK;
2479         }
2480
2481         state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2482         if (state == NULL) {
2483                 return NT_STATUS_NO_MEMORY;
2484         }
2485         state->c = c;
2486         state->status = status;
2487
2488         subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2489         if (subreq == NULL) {
2490                 return NT_STATUS_NO_MEMORY;
2491         }
2492         tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2493
2494         return status;
2495 }
2496
2497 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2498 {
2499         struct dcerpc_shutdown_pipe_state *state =
2500                 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2501         struct dcecli_connection *c = state->c;
2502         NTSTATUS status = state->status;
2503         int error;
2504
2505         /*
2506          * here we ignore the return values...
2507          */
2508         tstream_disconnect_recv(subreq, &error);
2509         TALLOC_FREE(subreq);
2510
2511         TALLOC_FREE(state);
2512
2513         dcerpc_transport_dead(c, status);
2514 }
2515
2516
2517
2518 struct dcerpc_send_read_state {
2519         struct dcecli_connection *p;
2520 };
2521
2522 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2523 {
2524         struct dcecli_connection *p = state->p;
2525
2526         p->transport.read_subreq = NULL;
2527
2528         return 0;
2529 }
2530
2531 static void dcerpc_send_read_done(struct tevent_req *subreq);
2532
2533 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2534 {
2535         struct dcerpc_send_read_state *state;
2536
2537         if (p->transport.read_subreq != NULL) {
2538                 p->transport.pending_reads++;
2539                 return NT_STATUS_OK;
2540         }
2541
2542         state = talloc_zero(p, struct dcerpc_send_read_state);
2543         if (state == NULL) {
2544                 return NT_STATUS_NO_MEMORY;
2545         }
2546         state->p = p;
2547
2548         talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2549
2550         p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2551                                                           p->event_ctx,
2552                                                           p->transport.stream);
2553         if (p->transport.read_subreq == NULL) {
2554                 return NT_STATUS_NO_MEMORY;
2555         }
2556         tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2557
2558         return NT_STATUS_OK;
2559 }
2560
2561 static void dcerpc_send_read_done(struct tevent_req *subreq)
2562 {
2563         struct dcerpc_send_read_state *state =
2564                 tevent_req_callback_data(subreq,
2565                                          struct dcerpc_send_read_state);
2566         struct dcecli_connection *p = state->p;
2567         NTSTATUS status;
2568         struct ncacn_packet *pkt;
2569         DATA_BLOB blob;
2570
2571         status = dcerpc_read_ncacn_packet_recv(subreq, state,
2572                                                &pkt, &blob);
2573         TALLOC_FREE(subreq);
2574         if (!NT_STATUS_IS_OK(status)) {
2575                 TALLOC_FREE(state);
2576                 dcerpc_transport_dead(p, status);
2577                 return;
2578         }
2579
2580         /*
2581          * here we steal into thet connection context,
2582          * but p->transport.recv_data() will steal or free it again
2583          */
2584         talloc_steal(p, blob.data);
2585         TALLOC_FREE(state);
2586
2587         if (p->transport.pending_reads > 0) {
2588                 p->transport.pending_reads--;
2589
2590                 status = dcerpc_send_read(p);
2591                 if (!NT_STATUS_IS_OK(status)) {
2592                         dcerpc_transport_dead(p, status);
2593                         return;
2594                 }
2595         }
2596
2597         dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2598 }
2599
2600 struct dcerpc_send_request_state {
2601         struct dcecli_connection *p;
2602         DATA_BLOB blob;
2603         struct iovec iov;
2604 };
2605
2606 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2607 {
2608         struct dcecli_connection *p = state->p;
2609
2610         p->transport.read_subreq = NULL;
2611
2612         return 0;
2613 }
2614
2615 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2616 static void dcerpc_send_request_done(struct tevent_req *subreq);
2617
2618 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2619                                     bool trigger_read)
2620 {
2621         struct dcerpc_send_request_state *state;
2622         struct tevent_req *subreq;
2623         bool use_trans = trigger_read;
2624
2625         if (p->transport.stream == NULL) {
2626                 return NT_STATUS_CONNECTION_DISCONNECTED;
2627         }
2628
2629         state = talloc_zero(p, struct dcerpc_send_request_state);
2630         if (state == NULL) {
2631                 return NT_STATUS_NO_MEMORY;
2632         }
2633         state->p = p;
2634
2635         state->blob = data_blob_talloc(state, data->data, data->length);
2636         if (state->blob.data == NULL) {
2637                 TALLOC_FREE(state);
2638                 return NT_STATUS_NO_MEMORY;
2639         }
2640         state->iov.iov_base = (void *)state->blob.data;
2641         state->iov.iov_len = state->blob.length;
2642
2643         if (p->transport.read_subreq != NULL) {
2644                 use_trans = false;
2645         }
2646
2647         if (!tstream_is_smbXcli_np(p->transport.stream)) {
2648                 use_trans = false;
2649         }
2650
2651         if (use_trans) {
2652                 /*
2653                  * we need to block reads until our write is
2654                  * the next in the write queue.
2655                  */
2656                 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2657                                                              p->transport.write_queue);
2658                 if (p->transport.read_subreq == NULL) {
2659                         TALLOC_FREE(state);
2660                         return NT_STATUS_NO_MEMORY;
2661                 }
2662                 tevent_req_set_callback(p->transport.read_subreq,
2663                                         dcerpc_send_request_wait_done,
2664                                         state);
2665
2666                 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2667
2668                 trigger_read = false;
2669         }
2670
2671         subreq = tstream_writev_queue_send(state, p->event_ctx,
2672                                            p->transport.stream,
2673                                            p->transport.write_queue,
2674                                            &state->iov, 1);
2675         if (subreq == NULL) {
2676                 TALLOC_FREE(state);
2677                 return NT_STATUS_NO_MEMORY;
2678         }
2679         tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2680
2681         if (trigger_read) {
2682                 dcerpc_send_read(p);
2683         }
2684
2685         return NT_STATUS_OK;
2686 }
2687
2688 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2689 {
2690         struct dcerpc_send_request_state *state =
2691                 tevent_req_callback_data(subreq,
2692                 struct dcerpc_send_request_state);
2693         struct dcecli_connection *p = state->p;
2694         NTSTATUS status;
2695         bool ok;
2696
2697         p->transport.read_subreq = NULL;
2698         talloc_set_destructor(state, NULL);
2699
2700         ok = tevent_queue_wait_recv(subreq);
2701         if (!ok) {
2702                 TALLOC_FREE(state);
2703                 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2704                 return;
2705         }
2706
2707         if (tevent_queue_length(p->transport.write_queue) <= 2) {
2708                 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2709                 if (!NT_STATUS_IS_OK(status)) {
2710                         TALLOC_FREE(state);
2711                         dcerpc_transport_dead(p, status);
2712                         return;
2713                 }
2714         }
2715
2716         /* we free subreq after tstream_cli_np_use_trans */
2717         TALLOC_FREE(subreq);
2718
2719         dcerpc_send_read(p);
2720 }
2721
2722 static void dcerpc_send_request_done(struct tevent_req *subreq)
2723 {
2724         struct dcerpc_send_request_state *state =
2725                 tevent_req_callback_data(subreq,
2726                 struct dcerpc_send_request_state);
2727         int ret;
2728         int error;
2729
2730         ret = tstream_writev_queue_recv(subreq, &error);
2731         TALLOC_FREE(subreq);
2732         if (ret == -1) {
2733                 struct dcecli_connection *p = state->p;
2734                 NTSTATUS status = map_nt_error_from_unix_common(error);
2735
2736                 TALLOC_FREE(state);
2737                 dcerpc_transport_dead(p, status);
2738                 return;
2739         }
2740
2741         TALLOC_FREE(state);
2742 }