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