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