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