s4:librpc/rpc: convert dcerpc_bind_send/recv to tevent_req
[sfrench/samba-autobuild/.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 "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.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
36 enum rpc_request_state {
37         RPC_REQUEST_QUEUED,
38         RPC_REQUEST_PENDING,
39         RPC_REQUEST_DONE
40 };
41
42 /*
43   handle for an async dcerpc request
44 */
45 struct rpc_request {
46         struct rpc_request *next, *prev;
47         struct dcerpc_pipe *p;
48         NTSTATUS status;
49         uint32_t call_id;
50         enum rpc_request_state state;
51         DATA_BLOB payload;
52         uint32_t flags;
53         uint32_t fault_code;
54
55         /* this is used to distinguish bind and alter_context requests
56            from normal requests */
57         void (*recv_handler)(struct rpc_request *conn, 
58                              DATA_BLOB *blob, struct ncacn_packet *pkt);
59
60         const struct GUID *object;
61         uint16_t opnum;
62         DATA_BLOB request_data;
63         bool ignore_timeout;
64
65         /* use by the ndr level async recv call */
66         struct {
67                 const struct ndr_interface_table *table;
68                 uint32_t opnum;
69                 void *struct_ptr;
70                 TALLOC_CTX *mem_ctx;
71         } ndr;
72
73         struct {
74                 void (*callback)(struct rpc_request *);
75                 void *private_data;
76         } async;
77 };
78
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 {
81         return gensec_init();
82 }
83
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86
87 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
88                                                const struct GUID *object,
89                                                uint16_t opnum,
90                                                DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
92                                     TALLOC_CTX *mem_ctx,
93                                     DATA_BLOB *stub_data);
94 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
95                                        TALLOC_CTX *mem_ctx,
96                                        DATA_BLOB blob,
97                                        size_t struct_size,
98                                        ndr_push_flags_fn_t ndr_push,
99                                        ndr_pull_flags_fn_t ndr_pull);
100 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
101                                         struct ndr_pull *pull_in,
102                                         void *struct_ptr,
103                                         size_t struct_size,
104                                         ndr_push_flags_fn_t ndr_push,
105                                         ndr_pull_flags_fn_t ndr_pull,
106                                         ndr_print_function_t ndr_print);
107
108 /* destroy a dcerpc connection */
109 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
110 {
111         if (conn->dead) {
112                 conn->free_skipped = true;
113                 return -1;
114         }
115         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
116         return 0;
117 }
118
119
120 /* initialise a dcerpc connection. 
121    the event context is optional
122 */
123 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
124                                                  struct tevent_context *ev)
125 {
126         struct dcecli_connection *c;
127
128         c = talloc_zero(mem_ctx, struct dcecli_connection);
129         if (!c) {
130                 return NULL;
131         }
132
133         c->event_ctx = ev;
134
135         if (c->event_ctx == NULL) {
136                 talloc_free(c);
137                 return NULL;
138         }
139
140         c->call_id = 1;
141         c->security_state.auth_info = NULL;
142         c->security_state.session_key = dcerpc_generic_session_key;
143         c->security_state.generic_state = NULL;
144         c->binding_string = NULL;
145         c->flags = 0;
146         c->srv_max_xmit_frag = 0;
147         c->srv_max_recv_frag = 0;
148         c->pending = NULL;
149
150         c->io_trigger = tevent_create_immediate(c);
151         if (c->io_trigger == NULL) {
152                 talloc_free(c);
153                 return NULL;
154         }
155
156         talloc_set_destructor(c, dcerpc_connection_destructor);
157
158         return c;
159 }
160
161 struct dcerpc_bh_state {
162         struct dcerpc_pipe *p;
163 };
164
165 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
166 {
167         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
168                                      struct dcerpc_bh_state);
169
170         if (!hs->p) {
171                 return false;
172         }
173
174         if (!hs->p->conn) {
175                 return false;
176         }
177
178         if (hs->p->conn->dead) {
179                 return false;
180         }
181
182         return true;
183 }
184
185 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
186                                       uint32_t timeout)
187 {
188         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
189                                      struct dcerpc_bh_state);
190         uint32_t old;
191
192         if (!hs->p) {
193                 return DCERPC_REQUEST_TIMEOUT;
194         }
195
196         old = hs->p->request_timeout;
197         hs->p->request_timeout = timeout;
198
199         return old;
200 }
201
202 struct dcerpc_bh_raw_call_state {
203         struct tevent_context *ev;
204         struct dcerpc_binding_handle *h;
205         DATA_BLOB in_data;
206         DATA_BLOB out_data;
207         uint32_t out_flags;
208 };
209
210 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
211
212 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
213                                                   struct tevent_context *ev,
214                                                   struct dcerpc_binding_handle *h,
215                                                   const struct GUID *object,
216                                                   uint32_t opnum,
217                                                   uint32_t in_flags,
218                                                   const uint8_t *in_data,
219                                                   size_t in_length)
220 {
221         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
222                                      struct dcerpc_bh_state);
223         struct tevent_req *req;
224         struct dcerpc_bh_raw_call_state *state;
225         bool ok;
226         struct rpc_request *subreq;
227
228         req = tevent_req_create(mem_ctx, &state,
229                                 struct dcerpc_bh_raw_call_state);
230         if (req == NULL) {
231                 return NULL;
232         }
233         state->ev = ev;
234         state->h = h;
235         state->in_data.data = discard_const_p(uint8_t, in_data);
236         state->in_data.length = in_length;
237
238         ok = dcerpc_bh_is_connected(h);
239         if (!ok) {
240                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
241                 return tevent_req_post(req, ev);
242         }
243
244         subreq = dcerpc_request_send(hs->p,
245                                      object,
246                                      opnum,
247                                      &state->in_data);
248         if (tevent_req_nomem(subreq, req)) {
249                 return tevent_req_post(req, ev);
250         }
251         subreq->async.callback = dcerpc_bh_raw_call_done;
252         subreq->async.private_data = req;
253
254         return req;
255 }
256
257 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
258 {
259         struct tevent_req *req =
260                 talloc_get_type_abort(subreq->async.private_data,
261                 struct tevent_req);
262         struct dcerpc_bh_raw_call_state *state =
263                 tevent_req_data(req,
264                 struct dcerpc_bh_raw_call_state);
265         NTSTATUS status;
266         uint32_t fault_code;
267
268         state->out_flags = 0;
269         if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
270                 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
271         }
272
273         fault_code = subreq->fault_code;
274
275         status = dcerpc_request_recv(subreq, state, &state->out_data);
276         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
277                 status = dcerpc_fault_to_nt_status(fault_code);
278         }
279
280         /*
281          * We trigger the callback in the next event run
282          * because the code in this file might trigger
283          * multiple request callbacks from within a single
284          * while loop.
285          *
286          * In order to avoid segfaults from within
287          * dcerpc_connection_dead() we call
288          * tevent_req_defer_callback().
289          */
290         tevent_req_defer_callback(req, state->ev);
291
292         if (!NT_STATUS_IS_OK(status)) {
293                 tevent_req_nterror(req, status);
294                 return;
295         }
296
297         tevent_req_done(req);
298 }
299
300 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
301                                         TALLOC_CTX *mem_ctx,
302                                         uint8_t **out_data,
303                                         size_t *out_length,
304                                         uint32_t *out_flags)
305 {
306         struct dcerpc_bh_raw_call_state *state =
307                 tevent_req_data(req,
308                 struct dcerpc_bh_raw_call_state);
309         NTSTATUS status;
310
311         if (tevent_req_is_nterror(req, &status)) {
312                 tevent_req_received(req);
313                 return status;
314         }
315
316         *out_data = talloc_move(mem_ctx, &state->out_data.data);
317         *out_length = state->out_data.length;
318         *out_flags = state->out_flags;
319         tevent_req_received(req);
320         return NT_STATUS_OK;
321 }
322
323 struct dcerpc_bh_disconnect_state {
324         uint8_t _dummy;
325 };
326
327 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
328                                                 struct tevent_context *ev,
329                                                 struct dcerpc_binding_handle *h)
330 {
331         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
332                                      struct dcerpc_bh_state);
333         struct tevent_req *req;
334         struct dcerpc_bh_disconnect_state *state;
335         bool ok;
336
337         req = tevent_req_create(mem_ctx, &state,
338                                 struct dcerpc_bh_disconnect_state);
339         if (req == NULL) {
340                 return NULL;
341         }
342
343         ok = dcerpc_bh_is_connected(h);
344         if (!ok) {
345                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
346                 return tevent_req_post(req, ev);
347         }
348
349         /* TODO: do a real disconnect ... */
350         hs->p = NULL;
351
352         tevent_req_done(req);
353         return tevent_req_post(req, ev);
354 }
355
356 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
357 {
358         NTSTATUS status;
359
360         if (tevent_req_is_nterror(req, &status)) {
361                 tevent_req_received(req);
362                 return status;
363         }
364
365         tevent_req_received(req);
366         return NT_STATUS_OK;
367 }
368
369 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
370 {
371         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
372                                      struct dcerpc_bh_state);
373
374         if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
375                 return true;
376         }
377
378         return false;
379 }
380
381 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
382 {
383         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
384                                      struct dcerpc_bh_state);
385
386         if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
387                 return true;
388         }
389
390         return false;
391 }
392
393 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
394 {
395         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
396                                      struct dcerpc_bh_state);
397
398         if (hs->p->conn->flags & DCERPC_NDR64) {
399                 return true;
400         }
401
402         return false;
403 }
404
405 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
406                                    int ndr_flags,
407                                    const void *_struct_ptr,
408                                    const struct ndr_interface_call *call)
409 {
410         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
411                                      struct dcerpc_bh_state);
412         void *struct_ptr = discard_const(_struct_ptr);
413
414         if (ndr_flags & NDR_IN) {
415                 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
416                         ndr_print_function_debug(call->ndr_print,
417                                                  call->name,
418                                                  ndr_flags,
419                                                  struct_ptr);
420                 }
421         }
422         if (ndr_flags & NDR_OUT) {
423                 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
424                         ndr_print_function_debug(call->ndr_print,
425                                                  call->name,
426                                                  ndr_flags,
427                                                  struct_ptr);
428                 }
429         }
430 }
431
432 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
433                                       NTSTATUS error,
434                                       const void *struct_ptr,
435                                       const struct ndr_interface_call *call)
436 {
437         DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
438                  call->name, nt_errstr(error)));
439 }
440
441 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
442                                       NTSTATUS error,
443                                       const DATA_BLOB *blob,
444                                       const struct ndr_interface_call *call)
445 {
446         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
447                                      struct dcerpc_bh_state);
448         const uint32_t num_examples = 20;
449         uint32_t i;
450
451         DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
452                  call->name, nt_errstr(error)));
453
454         if (hs->p->conn->packet_log_dir == NULL) return;
455
456         for (i=0;i<num_examples;i++) {
457                 char *name=NULL;
458                 asprintf(&name, "%s/rpclog/%s-out.%d",
459                          hs->p->conn->packet_log_dir,
460                          call->name, i);
461                 if (name == NULL) {
462                         return;
463                 }
464                 if (!file_exist(name)) {
465                         if (file_save(name, blob->data, blob->length)) {
466                                 DEBUG(10,("Logged rpc packet to %s\n", name));
467                         }
468                         free(name);
469                         break;
470                 }
471                 free(name);
472         }
473 }
474
475 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
476                                           TALLOC_CTX *mem_ctx,
477                                           const DATA_BLOB *blob,
478                                           const struct ndr_interface_call *call)
479 {
480         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
481                                      struct dcerpc_bh_state);
482
483         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
484                 NTSTATUS status;
485
486                 status = dcerpc_ndr_validate_in(hs->p->conn,
487                                                 mem_ctx,
488                                                 *blob,
489                                                 call->struct_size,
490                                                 call->ndr_push,
491                                                 call->ndr_pull);
492                 if (!NT_STATUS_IS_OK(status)) {
493                         DEBUG(0,("Validation [in] failed for %s - %s\n",
494                                  call->name, nt_errstr(status)));
495                         return status;
496                 }
497         }
498
499         DEBUG(10,("rpc request data:\n"));
500         dump_data(10, blob->data, blob->length);
501
502         return NT_STATUS_OK;
503 }
504
505 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
506                                            struct ndr_pull *pull_in,
507                                            const void *_struct_ptr,
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         void *struct_ptr = discard_const(_struct_ptr);
513
514         DEBUG(10,("rpc reply data:\n"));
515         dump_data(10, pull_in->data, pull_in->data_size);
516
517         if (pull_in->offset != pull_in->data_size) {
518                 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
519                          pull_in->data_size - pull_in->offset,
520                          pull_in->offset, pull_in->offset,
521                          call->name));
522                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
523                    but it turns out that early versions of NT
524                    (specifically NT3.1) add junk onto the end of rpc
525                    packets, so if we want to interoperate at all with
526                    those versions then we need to ignore this error */
527         }
528
529         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
530                 NTSTATUS status;
531
532                 status = dcerpc_ndr_validate_out(hs->p->conn,
533                                                  pull_in,
534                                                  struct_ptr,
535                                                  call->struct_size,
536                                                  call->ndr_push,
537                                                  call->ndr_pull,
538                                                  call->ndr_print);
539                 if (!NT_STATUS_IS_OK(status)) {
540                         DEBUG(2,("Validation [out] failed for %s - %s\n",
541                                  call->name, nt_errstr(status)));
542                         return status;
543                 }
544         }
545
546         return NT_STATUS_OK;
547 }
548
549 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
550         .name                   = "dcerpc",
551         .is_connected           = dcerpc_bh_is_connected,
552         .set_timeout            = dcerpc_bh_set_timeout,
553         .raw_call_send          = dcerpc_bh_raw_call_send,
554         .raw_call_recv          = dcerpc_bh_raw_call_recv,
555         .disconnect_send        = dcerpc_bh_disconnect_send,
556         .disconnect_recv        = dcerpc_bh_disconnect_recv,
557
558         .push_bigendian         = dcerpc_bh_push_bigendian,
559         .ref_alloc              = dcerpc_bh_ref_alloc,
560         .use_ndr64              = dcerpc_bh_use_ndr64,
561         .do_ndr_print           = dcerpc_bh_do_ndr_print,
562         .ndr_push_failed        = dcerpc_bh_ndr_push_failed,
563         .ndr_pull_failed        = dcerpc_bh_ndr_pull_failed,
564         .ndr_validate_in        = dcerpc_bh_ndr_validate_in,
565         .ndr_validate_out       = dcerpc_bh_ndr_validate_out,
566 };
567
568 /* initialise a dcerpc pipe. */
569 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
570 {
571         struct dcerpc_binding_handle *h;
572         struct dcerpc_bh_state *hs;
573
574         h = dcerpc_binding_handle_create(p,
575                                          &dcerpc_bh_ops,
576                                          NULL,
577                                          NULL, /* TODO */
578                                          &hs,
579                                          struct dcerpc_bh_state,
580                                          __location__);
581         if (h == NULL) {
582                 return NULL;
583         }
584         hs->p = p;
585
586         dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
587
588         return h;
589 }
590
591 /* initialise a dcerpc pipe. */
592 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
593 {
594         struct dcerpc_pipe *p;
595
596         p = talloc_zero(mem_ctx, struct dcerpc_pipe);
597         if (!p) {
598                 return NULL;
599         }
600
601         p->conn = dcerpc_connection_init(p, ev);
602         if (p->conn == NULL) {
603                 talloc_free(p);
604                 return NULL;
605         }
606
607         p->last_fault_code = 0;
608         p->context_id = 0;
609         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
610         p->binding = NULL;
611
612         ZERO_STRUCT(p->syntax);
613         ZERO_STRUCT(p->transfer_syntax);
614
615         if (DEBUGLVL(100)) {
616                 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
617         }
618
619         p->binding_handle = dcerpc_pipe_binding_handle(p);
620         if (p->binding_handle == NULL) {
621                 talloc_free(p);
622                 return NULL;
623         }
624
625         return p;
626 }
627
628
629 /* 
630    choose the next call id to use
631 */
632 static uint32_t next_call_id(struct dcecli_connection *c)
633 {
634         c->call_id++;
635         if (c->call_id == 0) {
636                 c->call_id++;
637         }
638         return c->call_id;
639 }
640
641 /**
642   setup for a ndr pull, also setting up any flags from the binding string
643 */
644 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c, 
645                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
646 {
647         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
648
649         if (ndr == NULL) return ndr;
650
651         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
652                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
653         }
654
655         if (c->flags & DCERPC_NDR_REF_ALLOC) {
656                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
657         }
658
659         if (c->flags & DCERPC_NDR64) {
660                 ndr->flags |= LIBNDR_FLAG_NDR64;
661         }
662
663         return ndr;
664 }
665
666 /* 
667    parse a data blob into a ncacn_packet structure. This handles both
668    input and output packets
669 */
670 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
671                             struct ncacn_packet *pkt)
672 {
673         struct ndr_pull *ndr;
674         enum ndr_err_code ndr_err;
675
676         ndr = ndr_pull_init_flags(c, blob, mem_ctx);
677         if (!ndr) {
678                 return NT_STATUS_NO_MEMORY;
679         }
680
681         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
682                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
683         }
684
685         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
686         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
687                 return ndr_map_error2ntstatus(ndr_err);
688         }
689
690         return NT_STATUS_OK;
691 }
692
693 /* 
694    parse the authentication information on a dcerpc response packet
695 */
696 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx, 
697                                         DATA_BLOB *raw_packet,
698                                         struct ncacn_packet *pkt)
699 {
700         NTSTATUS status;
701         struct dcerpc_auth auth;
702         uint32_t auth_length;
703
704         if (!c->security_state.auth_info ||
705             !c->security_state.generic_state) {
706                 return NT_STATUS_OK;
707         }
708
709         switch (c->security_state.auth_info->auth_level) {
710         case DCERPC_AUTH_LEVEL_PRIVACY:
711         case DCERPC_AUTH_LEVEL_INTEGRITY:
712                 break;
713
714         case DCERPC_AUTH_LEVEL_CONNECT:
715                 if (pkt->auth_length != 0) {
716                         break;
717                 }
718                 return NT_STATUS_OK;
719         case DCERPC_AUTH_LEVEL_NONE:
720                 if (pkt->auth_length != 0) {
721                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
722                 }
723                 return NT_STATUS_OK;
724
725         default:
726                 return NT_STATUS_INVALID_LEVEL;
727         }
728
729         status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
730                                           &pkt->u.response.stub_and_verifier,
731                                           &auth, &auth_length, false);
732         NT_STATUS_NOT_OK_RETURN(status);
733
734         pkt->u.response.stub_and_verifier.length -= auth_length;
735
736         /* check signature or unseal the packet */
737         switch (c->security_state.auth_info->auth_level) {
738         case DCERPC_AUTH_LEVEL_PRIVACY:
739                 status = gensec_unseal_packet(c->security_state.generic_state, 
740                                               raw_packet->data + DCERPC_REQUEST_LENGTH,
741                                               pkt->u.response.stub_and_verifier.length, 
742                                               raw_packet->data,
743                                               raw_packet->length - auth.credentials.length,
744                                               &auth.credentials);
745                 memcpy(pkt->u.response.stub_and_verifier.data,
746                        raw_packet->data + DCERPC_REQUEST_LENGTH,
747                        pkt->u.response.stub_and_verifier.length);
748                 break;
749                 
750         case DCERPC_AUTH_LEVEL_INTEGRITY:
751                 status = gensec_check_packet(c->security_state.generic_state, 
752                                              pkt->u.response.stub_and_verifier.data, 
753                                              pkt->u.response.stub_and_verifier.length, 
754                                              raw_packet->data,
755                                              raw_packet->length - auth.credentials.length,
756                                              &auth.credentials);
757                 break;
758
759         case DCERPC_AUTH_LEVEL_CONNECT:
760                 /* for now we ignore possible signatures here */
761                 status = NT_STATUS_OK;
762                 break;
763
764         default:
765                 status = NT_STATUS_INVALID_LEVEL;
766                 break;
767         }
768         
769         /* remove the indicated amount of padding */
770         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
771                 return NT_STATUS_INFO_LENGTH_MISMATCH;
772         }
773         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
774
775         return status;
776 }
777
778
779 /* 
780    push a dcerpc request packet into a blob, possibly signing it.
781 */
782 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, 
783                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
784                                          size_t sig_size,
785                                          struct ncacn_packet *pkt)
786 {
787         NTSTATUS status;
788         struct ndr_push *ndr;
789         DATA_BLOB creds2;
790         size_t payload_length;
791         enum ndr_err_code ndr_err;
792         size_t hdr_size = DCERPC_REQUEST_LENGTH;
793
794         /* non-signed packets are simpler */
795         if (sig_size == 0) {
796                 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
797         }
798
799         switch (c->security_state.auth_info->auth_level) {
800         case DCERPC_AUTH_LEVEL_PRIVACY:
801         case DCERPC_AUTH_LEVEL_INTEGRITY:
802                 break;
803
804         case DCERPC_AUTH_LEVEL_CONNECT:
805                 /* TODO: let the gensec mech decide if it wants to generate a signature */
806                 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
807
808         case DCERPC_AUTH_LEVEL_NONE:
809                 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
810
811         default:
812                 return NT_STATUS_INVALID_LEVEL;
813         }
814
815         ndr = ndr_push_init_ctx(mem_ctx);
816         if (!ndr) {
817                 return NT_STATUS_NO_MEMORY;
818         }
819
820         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
821                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
822         }
823
824         if (c->flags & DCERPC_NDR64) {
825                 ndr->flags |= LIBNDR_FLAG_NDR64;
826         }
827
828         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
829                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
830                 hdr_size += 16;
831         }
832
833         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
834         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
835                 return ndr_map_error2ntstatus(ndr_err);
836         }
837
838         /* pad to 16 byte multiple in the payload portion of the
839            packet. This matches what w2k3 does. Note that we can't use
840            ndr_push_align() as that is relative to the start of the
841            whole packet, whereas w2k8 wants it relative to the start
842            of the stub */
843         c->security_state.auth_info->auth_pad_length =
844                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
845         ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
846         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
847                 return ndr_map_error2ntstatus(ndr_err);
848         }
849
850         payload_length = pkt->u.request.stub_and_verifier.length + 
851                 c->security_state.auth_info->auth_pad_length;
852
853         /* we start without signature, it will appended later */
854         c->security_state.auth_info->credentials = data_blob(NULL,0);
855
856         /* add the auth verifier */
857         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
858         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
859                 return ndr_map_error2ntstatus(ndr_err);
860         }
861
862         /* extract the whole packet as a blob */
863         *blob = ndr_push_blob(ndr);
864
865         /*
866          * Setup the frag and auth length in the packet buffer.
867          * This is needed if the GENSEC mech does AEAD signing
868          * of the packet headers. The signature itself will be
869          * appended later.
870          */
871         dcerpc_set_frag_length(blob, blob->length + sig_size);
872         dcerpc_set_auth_length(blob, sig_size);
873
874         /* sign or seal the packet */
875         switch (c->security_state.auth_info->auth_level) {
876         case DCERPC_AUTH_LEVEL_PRIVACY:
877                 status = gensec_seal_packet(c->security_state.generic_state, 
878                                             mem_ctx, 
879                                             blob->data + hdr_size,
880                                             payload_length,
881                                             blob->data,
882                                             blob->length,
883                                             &creds2);
884                 if (!NT_STATUS_IS_OK(status)) {
885                         return status;
886                 }
887                 break;
888
889         case DCERPC_AUTH_LEVEL_INTEGRITY:
890                 status = gensec_sign_packet(c->security_state.generic_state, 
891                                             mem_ctx, 
892                                             blob->data + hdr_size,
893                                             payload_length, 
894                                             blob->data,
895                                             blob->length,
896                                             &creds2);
897                 if (!NT_STATUS_IS_OK(status)) {
898                         return status;
899                 }
900                 break;
901
902         default:
903                 status = NT_STATUS_INVALID_LEVEL;
904                 break;
905         }
906
907         if (creds2.length != sig_size) {
908                 /* this means the sig_size estimate for the signature
909                    was incorrect. We have to correct the packet
910                    sizes. That means we could go over the max fragment
911                    length */
912                 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
913                         (unsigned) creds2.length,
914                         (unsigned) sig_size,
915                         (unsigned) c->security_state.auth_info->auth_pad_length,
916                         (unsigned) pkt->u.request.stub_and_verifier.length));
917                 dcerpc_set_frag_length(blob, blob->length + creds2.length);
918                 dcerpc_set_auth_length(blob, creds2.length);
919         }
920
921         if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
922                 return NT_STATUS_NO_MEMORY;
923         }
924
925         return NT_STATUS_OK;
926 }
927
928
929 /* 
930    fill in the fixed values in a dcerpc header 
931 */
932 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
933 {
934         pkt->rpc_vers = 5;
935         pkt->rpc_vers_minor = 0;
936         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
937                 pkt->drep[0] = 0;
938         } else {
939                 pkt->drep[0] = DCERPC_DREP_LE;
940         }
941         pkt->drep[1] = 0;
942         pkt->drep[2] = 0;
943         pkt->drep[3] = 0;
944 }
945
946 /*
947   map a bind nak reason to a NTSTATUS
948 */
949 static NTSTATUS dcerpc_map_reason(uint16_t reason)
950 {
951         switch (reason) {
952         case DCERPC_BIND_REASON_ASYNTAX:
953                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
954         case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
955                 return NT_STATUS_INVALID_PARAMETER;
956         }
957         return NT_STATUS_UNSUCCESSFUL;
958 }
959
960 /*
961   a bind or alter context has failed
962 */
963 static void dcerpc_composite_fail(struct rpc_request *req)
964 {
965         struct composite_context *c = talloc_get_type(req->async.private_data, 
966                                                       struct composite_context);
967         composite_error(c, req->status);
968 }
969
970 /*
971   remove requests from the pending or queued queues
972  */
973 static int dcerpc_req_dequeue(struct rpc_request *req)
974 {
975         switch (req->state) {
976         case RPC_REQUEST_QUEUED:
977                 DLIST_REMOVE(req->p->conn->request_queue, req);
978                 break;
979         case RPC_REQUEST_PENDING:
980                 DLIST_REMOVE(req->p->conn->pending, req);
981                 break;
982         case RPC_REQUEST_DONE:
983                 break;
984         }
985         return 0;
986 }
987
988
989 /*
990   mark the dcerpc connection dead. All outstanding requests get an error
991 */
992 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
993 {
994         if (conn->dead) return;
995
996         conn->dead = true;
997
998         TALLOC_FREE(conn->io_trigger);
999         conn->io_trigger_pending = false;
1000
1001         conn->transport.recv_data = NULL;
1002
1003         if (conn->transport.shutdown_pipe) {
1004                 conn->transport.shutdown_pipe(conn, status);
1005         }
1006
1007         /* all pending requests get the error */
1008         while (conn->pending) {
1009                 struct rpc_request *req = conn->pending;
1010                 dcerpc_req_dequeue(req);
1011                 req->state = RPC_REQUEST_DONE;
1012                 req->status = status;
1013                 if (req->async.callback) {
1014                         req->async.callback(req);
1015                 }
1016         }       
1017
1018         /* all requests, which are not shipped */
1019         while (conn->request_queue) {
1020                 struct rpc_request *req = conn->request_queue;
1021                 dcerpc_req_dequeue(req);
1022                 req->state = RPC_REQUEST_DONE;
1023                 req->status = status;
1024                 if (req->async.callback) {
1025                         req->async.callback(req);
1026                 }
1027         }
1028
1029         talloc_set_destructor(conn, NULL);
1030         if (conn->free_skipped) {
1031                 talloc_free(conn);
1032         }
1033 }
1034
1035 /*
1036   forward declarations of the recv_data handlers for the types of
1037   packets we need to handle
1038 */
1039 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
1040                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1041
1042 /*
1043   receive a dcerpc reply from the transport. Here we work out what
1044   type of reply it is (normal request, bind or alter context) and
1045   dispatch to the appropriate handler
1046 */
1047 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1048 {
1049         struct ncacn_packet pkt;
1050
1051         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1052                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1053         }
1054
1055         /* the transport may be telling us of a severe error, such as
1056            a dropped socket */
1057         if (!NT_STATUS_IS_OK(status)) {
1058                 data_blob_free(blob);
1059                 dcerpc_connection_dead(conn, status);
1060                 return;
1061         }
1062
1063         /* parse the basic packet to work out what type of response this is */
1064         status = ncacn_pull(conn, blob, blob->data, &pkt);
1065         if (!NT_STATUS_IS_OK(status)) {
1066                 data_blob_free(blob);
1067                 dcerpc_connection_dead(conn, status);
1068                 return;
1069         }
1070
1071         dcerpc_request_recv_data(conn, blob, &pkt);
1072 }
1073
1074 /*
1075   handle timeouts of individual dcerpc requests
1076 */
1077 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
1078                                    struct timeval t, void *private_data)
1079 {
1080         struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1081
1082         if (req->ignore_timeout) {
1083                 dcerpc_req_dequeue(req);
1084                 req->state = RPC_REQUEST_DONE;
1085                 req->status = NT_STATUS_IO_TIMEOUT;
1086                 if (req->async.callback) {
1087                         req->async.callback(req);
1088                 }
1089                 return;
1090         }
1091
1092         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1093 }
1094
1095 struct dcerpc_bind_state {
1096         struct dcerpc_pipe *p;
1097 };
1098
1099 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1100 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1101                                      DATA_BLOB *raw_packet,
1102                                      struct ncacn_packet *pkt);
1103
1104 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1105                                     struct tevent_context *ev,
1106                                     struct dcerpc_pipe *p,
1107                                     const struct ndr_syntax_id *syntax,
1108                                     const struct ndr_syntax_id *transfer_syntax)
1109 {
1110         struct tevent_req *req;
1111         struct dcerpc_bind_state *state;
1112         struct ncacn_packet pkt;
1113         DATA_BLOB blob;
1114         NTSTATUS status;
1115         struct rpc_request *subreq;
1116
1117         req = tevent_req_create(mem_ctx, &state,
1118                                 struct dcerpc_bind_state);
1119         if (req == NULL) {
1120                 return NULL;
1121         }
1122
1123         state->p = p;
1124
1125         p->syntax = *syntax;
1126         p->transfer_syntax = *transfer_syntax;
1127
1128         init_ncacn_hdr(p->conn, &pkt);
1129
1130         pkt.ptype = DCERPC_PKT_BIND;
1131         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1132         pkt.call_id = p->conn->call_id;
1133         pkt.auth_length = 0;
1134
1135         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1136                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1137         }
1138
1139         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1140                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1141         }
1142
1143         pkt.u.bind.max_xmit_frag = 5840;
1144         pkt.u.bind.max_recv_frag = 5840;
1145         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1146         pkt.u.bind.num_contexts = 1;
1147         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1148         if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1149                 return tevent_req_post(req, ev);
1150         }
1151         pkt.u.bind.ctx_list[0].context_id = p->context_id;
1152         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1153         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1154         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1155         pkt.u.bind.auth_info = data_blob(NULL, 0);
1156
1157         /* construct the NDR form of the packet */
1158         status = ncacn_push_auth(&blob, state, &pkt,
1159                                  p->conn->security_state.auth_info);
1160         if (tevent_req_nterror(req, status)) {
1161                 return tevent_req_post(req, ev);
1162         }
1163
1164         p->conn->transport.recv_data = dcerpc_recv_data;
1165
1166         /*
1167          * we allocate a dcerpc_request so we can be in the same
1168          * request queue as normal requests
1169          */
1170         subreq = talloc_zero(state, struct rpc_request);
1171         if (tevent_req_nomem(subreq, req)) {
1172                 return tevent_req_post(req, ev);
1173         }
1174
1175         subreq->state = RPC_REQUEST_PENDING;
1176         subreq->call_id = pkt.call_id;
1177         subreq->async.private_data = req;
1178         subreq->async.callback = dcerpc_bind_fail_handler;
1179         subreq->p = p;
1180         subreq->recv_handler = dcerpc_bind_recv_handler;
1181         DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1182         talloc_set_destructor(subreq, dcerpc_req_dequeue);
1183
1184         status = p->conn->transport.send_request(p->conn, &blob, true);
1185         if (tevent_req_nterror(req, status)) {
1186                 return tevent_req_post(req, ev);
1187         }
1188
1189         tevent_add_timer(ev, subreq,
1190                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1191                          dcerpc_timeout_handler, subreq);
1192
1193         return req;
1194 }
1195
1196 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1197 {
1198         struct tevent_req *req =
1199                 talloc_get_type_abort(subreq->async.private_data,
1200                 struct tevent_req);
1201         NTSTATUS status = subreq->status;
1202
1203         TALLOC_FREE(subreq);
1204
1205         tevent_req_nterror(req, status);
1206 }
1207
1208 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1209                                      DATA_BLOB *raw_packet,
1210                                      struct ncacn_packet *pkt)
1211 {
1212         struct tevent_req *req =
1213                 talloc_get_type_abort(subreq->async.private_data,
1214                 struct tevent_req);
1215         struct dcerpc_bind_state *state =
1216                 tevent_req_data(req,
1217                 struct dcerpc_bind_state);
1218         struct dcecli_connection *conn = state->p->conn;
1219         NTSTATUS status;
1220
1221         /*
1222          * Note that pkt is allocated under raw_packet->data,
1223          * while raw_packet->data is a child of subreq.
1224          */
1225         talloc_steal(state, raw_packet->data);
1226         TALLOC_FREE(subreq);
1227
1228         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1229                 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1230
1231                 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1232                          pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1233
1234                 tevent_req_nterror(req, status);
1235                 return;
1236         }
1237
1238         if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1239             (pkt->u.bind_ack.num_results == 0) ||
1240             (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1241                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1242                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1243                 return;
1244         }
1245
1246         conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1247         conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1248
1249         if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1250             (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1251                 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1252         }
1253
1254         if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1255             (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1256                 conn->flags |= DCERPC_HEADER_SIGNING;
1257         }
1258
1259         /* the bind_ack might contain a reply set of credentials */
1260         if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1261                 uint32_t auth_length;
1262
1263                 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1264                                                   conn->security_state.auth_info, &auth_length, true);
1265                 if (tevent_req_nterror(req, status)) {
1266                         return;
1267                 }
1268         }
1269
1270         state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1271
1272         tevent_req_done(req);
1273 }
1274
1275 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1276 {
1277         return tevent_req_simple_recv_ntstatus(req);
1278 }
1279
1280 /* 
1281    perform a continued bind (and auth3)
1282 */
1283 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1284                       TALLOC_CTX *mem_ctx)
1285 {
1286         struct ncacn_packet pkt;
1287         NTSTATUS status;
1288         DATA_BLOB blob;
1289
1290         init_ncacn_hdr(p->conn, &pkt);
1291
1292         pkt.ptype = DCERPC_PKT_AUTH3;
1293         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1294         pkt.call_id = next_call_id(p->conn);
1295         pkt.auth_length = 0;
1296         pkt.u.auth3.auth_info = data_blob(NULL, 0);
1297
1298         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1299                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1300         }
1301
1302         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1303                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1304         }
1305
1306         /* construct the NDR form of the packet */
1307         status = ncacn_push_auth(&blob, mem_ctx,
1308                                  &pkt,
1309                                  p->conn->security_state.auth_info);
1310         if (!NT_STATUS_IS_OK(status)) {
1311                 return status;
1312         }
1313
1314         /* send it on its way */
1315         status = p->conn->transport.send_request(p->conn, &blob, false);
1316         if (!NT_STATUS_IS_OK(status)) {
1317                 return status;
1318         }
1319
1320         return NT_STATUS_OK;    
1321 }
1322
1323
1324 /*
1325   process a fragment received from the transport layer during a
1326   request
1327
1328   This function frees the data 
1329 */
1330 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
1331                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1332 {
1333         struct rpc_request *req;
1334         unsigned int length;
1335         NTSTATUS status = NT_STATUS_OK;
1336
1337         /*
1338           if this is an authenticated connection then parse and check
1339           the auth info. We have to do this before finding the
1340           matching packet, as the request structure might have been
1341           removed due to a timeout, but if it has been we still need
1342           to run the auth routines so that we don't get the sign/seal
1343           info out of step with the server
1344         */
1345         if (c->security_state.auth_info && c->security_state.generic_state &&
1346             pkt->ptype == DCERPC_PKT_RESPONSE) {
1347                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1348         }
1349
1350         /* find the matching request */
1351         for (req=c->pending;req;req=req->next) {
1352                 if (pkt->call_id == req->call_id) break;
1353         }
1354
1355 #if 0
1356         /* useful for testing certain vendors RPC servers */
1357         if (req == NULL && c->pending && pkt->call_id == 0) {
1358                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1359                 req = c->pending;
1360         }
1361 #endif
1362
1363         if (req == NULL) {
1364                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1365                 data_blob_free(raw_packet);
1366                 return;
1367         }
1368
1369         talloc_steal(req, raw_packet->data);
1370
1371         if (req->recv_handler != NULL) {
1372                 dcerpc_req_dequeue(req);
1373                 req->state = RPC_REQUEST_DONE;
1374                 req->recv_handler(req, raw_packet, pkt);
1375                 return;
1376         }
1377
1378         if (pkt->ptype == DCERPC_PKT_FAULT) {
1379                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1380                 req->fault_code = pkt->u.fault.status;
1381                 req->status = NT_STATUS_NET_WRITE_FAULT;
1382                 goto req_done;
1383         }
1384
1385         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1386                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1387                          (int)pkt->ptype)); 
1388                 req->fault_code = DCERPC_FAULT_OTHER;
1389                 req->status = NT_STATUS_NET_WRITE_FAULT;
1390                 goto req_done;
1391         }
1392
1393         /* now check the status from the auth routines, and if it failed then fail
1394            this request accordingly */
1395         if (!NT_STATUS_IS_OK(status)) {
1396                 req->status = status;
1397                 goto req_done;
1398         }
1399
1400         length = pkt->u.response.stub_and_verifier.length;
1401
1402         if (length > 0) {
1403                 req->payload.data = talloc_realloc(req, 
1404                                                    req->payload.data, 
1405                                                    uint8_t,
1406                                                    req->payload.length + length);
1407                 if (!req->payload.data) {
1408                         req->status = NT_STATUS_NO_MEMORY;
1409                         goto req_done;
1410                 }
1411                 memcpy(req->payload.data+req->payload.length, 
1412                        pkt->u.response.stub_and_verifier.data, length);
1413                 req->payload.length += length;
1414         }
1415
1416         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1417                 c->transport.send_read(c);
1418                 return;
1419         }
1420
1421         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1422                 req->flags |= DCERPC_PULL_BIGENDIAN;
1423         } else {
1424                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1425         }
1426
1427
1428 req_done:
1429         /* we've got the full payload */
1430         req->state = RPC_REQUEST_DONE;
1431         DLIST_REMOVE(c->pending, req);
1432
1433         /*
1434          * We have to look at shipping further requests before calling
1435          * the async function, that one might close the pipe
1436          */
1437         dcerpc_schedule_io_trigger(c);
1438
1439         if (req->async.callback) {
1440                 req->async.callback(req);
1441         }
1442 }
1443
1444 /*
1445   perform the send side of a async dcerpc request
1446 */
1447 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
1448                                                const struct GUID *object,
1449                                                uint16_t opnum,
1450                                                DATA_BLOB *stub_data)
1451 {
1452         struct rpc_request *req;
1453
1454         p->conn->transport.recv_data = dcerpc_recv_data;
1455
1456         req = talloc(p, struct rpc_request);
1457         if (req == NULL) {
1458                 return NULL;
1459         }
1460
1461         req->p = p;
1462         req->call_id = next_call_id(p->conn);
1463         req->status = NT_STATUS_OK;
1464         req->state = RPC_REQUEST_QUEUED;
1465         req->payload = data_blob(NULL, 0);
1466         req->flags = 0;
1467         req->fault_code = 0;
1468         req->ignore_timeout = false;
1469         req->async.callback = NULL;
1470         req->async.private_data = NULL;
1471         req->recv_handler = NULL;
1472
1473         if (object != NULL) {
1474                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1475                 if (req->object == NULL) {
1476                         talloc_free(req);
1477                         return NULL;
1478                 }
1479         } else {
1480                 req->object = NULL;
1481         }
1482
1483         req->opnum = opnum;
1484         req->request_data.length = stub_data->length;
1485         req->request_data.data = talloc_reference(req, stub_data->data);
1486         if (req->request_data.length && req->request_data.data == NULL) {
1487                 return NULL;
1488         }
1489
1490         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1491         talloc_set_destructor(req, dcerpc_req_dequeue);
1492
1493         dcerpc_schedule_io_trigger(p->conn);
1494
1495         if (p->request_timeout) {
1496                 tevent_add_timer(dcerpc_event_context(p), req,
1497                                 timeval_current_ofs(p->request_timeout, 0), 
1498                                 dcerpc_timeout_handler, req);
1499         }
1500
1501         return req;
1502 }
1503
1504 /*
1505   Send a request using the transport
1506 */
1507
1508 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1509 {
1510         struct rpc_request *req;
1511         struct dcerpc_pipe *p;
1512         DATA_BLOB *stub_data;
1513         struct ncacn_packet pkt;
1514         DATA_BLOB blob;
1515         uint32_t remaining, chunk_size;
1516         bool first_packet = true;
1517         size_t sig_size = 0;
1518         bool need_async = false;
1519
1520         req = c->request_queue;
1521         if (req == NULL) {
1522                 return;
1523         }
1524
1525         p = req->p;
1526         stub_data = &req->request_data;
1527
1528         if (c->pending) {
1529                 need_async = true;
1530         }
1531
1532         DLIST_REMOVE(c->request_queue, req);
1533         DLIST_ADD(c->pending, req);
1534         req->state = RPC_REQUEST_PENDING;
1535
1536         init_ncacn_hdr(p->conn, &pkt);
1537
1538         remaining = stub_data->length;
1539
1540         /* we can write a full max_recv_frag size, minus the dcerpc
1541            request header size */
1542         chunk_size = p->conn->srv_max_recv_frag;
1543         chunk_size -= DCERPC_REQUEST_LENGTH;
1544         if (c->security_state.auth_info &&
1545             c->security_state.generic_state) {
1546                 sig_size = gensec_sig_size(c->security_state.generic_state,
1547                                            p->conn->srv_max_recv_frag);
1548                 if (sig_size) {
1549                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1550                         chunk_size -= sig_size;
1551                 }
1552         }
1553         chunk_size -= (chunk_size % 16);
1554
1555         pkt.ptype = DCERPC_PKT_REQUEST;
1556         pkt.call_id = req->call_id;
1557         pkt.auth_length = 0;
1558         pkt.pfc_flags = 0;
1559         pkt.u.request.alloc_hint = remaining;
1560         pkt.u.request.context_id = p->context_id;
1561         pkt.u.request.opnum = req->opnum;
1562
1563         if (req->object) {
1564                 pkt.u.request.object.object = *req->object;
1565                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1566                 chunk_size -= ndr_size_GUID(req->object,0);
1567         }
1568
1569         /* we send a series of pdus without waiting for a reply */
1570         while (remaining > 0 || first_packet) {
1571                 uint32_t chunk = MIN(chunk_size, remaining);
1572                 bool last_frag = false;
1573                 bool do_trans = false;
1574
1575                 first_packet = false;
1576                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1577
1578                 if (remaining == stub_data->length) {
1579                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1580                 }
1581                 if (chunk == remaining) {
1582                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1583                         last_frag = true;
1584                 }
1585
1586                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1587                         (stub_data->length - remaining);
1588                 pkt.u.request.stub_and_verifier.length = chunk;
1589
1590                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1591                 if (!NT_STATUS_IS_OK(req->status)) {
1592                         req->state = RPC_REQUEST_DONE;
1593                         DLIST_REMOVE(p->conn->pending, req);
1594                         return;
1595                 }
1596
1597                 if (last_frag && !need_async) {
1598                         do_trans = true;
1599                 }
1600
1601                 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1602                 if (!NT_STATUS_IS_OK(req->status)) {
1603                         req->state = RPC_REQUEST_DONE;
1604                         DLIST_REMOVE(p->conn->pending, req);
1605                         return;
1606                 }               
1607
1608                 if (last_frag && !do_trans) {
1609                         req->status = p->conn->transport.send_read(p->conn);
1610                         if (!NT_STATUS_IS_OK(req->status)) {
1611                                 req->state = RPC_REQUEST_DONE;
1612                                 DLIST_REMOVE(p->conn->pending, req);
1613                                 return;
1614                         }
1615                 }
1616
1617                 remaining -= chunk;
1618         }
1619 }
1620
1621 static void dcerpc_io_trigger(struct tevent_context *ctx,
1622                               struct tevent_immediate *im,
1623                               void *private_data)
1624 {
1625         struct dcecli_connection *c =
1626                 talloc_get_type_abort(private_data,
1627                 struct dcecli_connection);
1628
1629         c->io_trigger_pending = false;
1630
1631         dcerpc_schedule_io_trigger(c);
1632
1633         dcerpc_ship_next_request(c);
1634 }
1635
1636 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1637 {
1638         if (c->dead) {
1639                 return;
1640         }
1641
1642         if (c->request_queue == NULL) {
1643                 return;
1644         }
1645
1646         if (c->io_trigger_pending) {
1647                 return;
1648         }
1649
1650         c->io_trigger_pending = true;
1651
1652         tevent_schedule_immediate(c->io_trigger,
1653                                   c->event_ctx,
1654                                   dcerpc_io_trigger,
1655                                   c);
1656 }
1657
1658 /*
1659   return the event context for a dcerpc pipe
1660   used by callers who wish to operate asynchronously
1661 */
1662 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1663 {
1664         return p->conn->event_ctx;
1665 }
1666
1667
1668
1669 /*
1670   perform the receive side of a async dcerpc request
1671 */
1672 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1673                                     TALLOC_CTX *mem_ctx,
1674                                     DATA_BLOB *stub_data)
1675 {
1676         NTSTATUS status;
1677
1678         while (req->state != RPC_REQUEST_DONE) {
1679                 struct tevent_context *ctx = dcerpc_event_context(req->p);
1680                 if (tevent_loop_once(ctx) != 0) {
1681                         return NT_STATUS_CONNECTION_DISCONNECTED;
1682                 }
1683         }
1684         *stub_data = req->payload;
1685         status = req->status;
1686         if (stub_data->data) {
1687                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1688         }
1689         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1690                 req->p->last_fault_code = req->fault_code;
1691         }
1692         talloc_unlink(talloc_parent(req), req);
1693         return status;
1694 }
1695
1696 /*
1697   this is a paranoid NDR validator. For every packet we push onto the wire
1698   we pull it back again, then push it again. Then we compare the raw NDR data
1699   for that to the NDR we initially generated. If they don't match then we know
1700   we must have a bug in either the pull or push side of our code
1701 */
1702 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c, 
1703                                        TALLOC_CTX *mem_ctx,
1704                                        DATA_BLOB blob,
1705                                        size_t struct_size,
1706                                        ndr_push_flags_fn_t ndr_push,
1707                                        ndr_pull_flags_fn_t ndr_pull)
1708 {
1709         void *st;
1710         struct ndr_pull *pull;
1711         struct ndr_push *push;
1712         DATA_BLOB blob2;
1713         enum ndr_err_code ndr_err;
1714
1715         st = talloc_size(mem_ctx, struct_size);
1716         if (!st) {
1717                 return NT_STATUS_NO_MEMORY;
1718         }
1719
1720         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1721         if (!pull) {
1722                 return NT_STATUS_NO_MEMORY;
1723         }
1724         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1725
1726         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1727                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1728         }
1729
1730         if (c->flags & DCERPC_NDR64) {
1731                 pull->flags |= LIBNDR_FLAG_NDR64;
1732         }
1733
1734         ndr_err = ndr_pull(pull, NDR_IN, st);
1735         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1736                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1737                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1738                                          "failed input validation pull - %s",
1739                                          nt_errstr(status));
1740                 return ndr_map_error2ntstatus(ndr_err);
1741         }
1742
1743         push = ndr_push_init_ctx(mem_ctx);
1744         if (!push) {
1745                 return NT_STATUS_NO_MEMORY;
1746         }       
1747
1748         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1749                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1750         }
1751
1752         if (c->flags & DCERPC_NDR64) {
1753                 push->flags |= LIBNDR_FLAG_NDR64;
1754         }
1755
1756         ndr_err = ndr_push(push, NDR_IN, st);
1757         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1758                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1759                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1760                                          "failed input validation push - %s",
1761                                          nt_errstr(status));
1762                 return ndr_map_error2ntstatus(ndr_err);
1763         }
1764
1765         blob2 = ndr_push_blob(push);
1766
1767         if (data_blob_cmp(&blob, &blob2) != 0) {
1768                 DEBUG(3,("original:\n"));
1769                 dump_data(3, blob.data, blob.length);
1770                 DEBUG(3,("secondary:\n"));
1771                 dump_data(3, blob2.data, blob2.length);
1772                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1773                                          "failed input validation blobs doesn't match");
1774                 return ndr_map_error2ntstatus(ndr_err);
1775         }
1776
1777         return NT_STATUS_OK;
1778 }
1779
1780 /*
1781   this is a paranoid NDR input validator. For every packet we pull
1782   from the wire we push it back again then pull and push it
1783   again. Then we compare the raw NDR data for that to the NDR we
1784   initially generated. If they don't match then we know we must have a
1785   bug in either the pull or push side of our code
1786 */
1787 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1788                                         struct ndr_pull *pull_in,
1789                                         void *struct_ptr,
1790                                         size_t struct_size,
1791                                         ndr_push_flags_fn_t ndr_push,
1792                                         ndr_pull_flags_fn_t ndr_pull,
1793                                         ndr_print_function_t ndr_print)
1794 {
1795         void *st;
1796         struct ndr_pull *pull;
1797         struct ndr_push *push;
1798         DATA_BLOB blob, blob2;
1799         TALLOC_CTX *mem_ctx = pull_in;
1800         char *s1, *s2;
1801         enum ndr_err_code ndr_err;
1802
1803         st = talloc_size(mem_ctx, struct_size);
1804         if (!st) {
1805                 return NT_STATUS_NO_MEMORY;
1806         }
1807         memcpy(st, struct_ptr, struct_size);
1808
1809         push = ndr_push_init_ctx(mem_ctx);
1810         if (!push) {
1811                 return NT_STATUS_NO_MEMORY;
1812         }       
1813
1814         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1815         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1816                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1817                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1818                                          "failed output validation push - %s",
1819                                          nt_errstr(status));
1820                 return ndr_map_error2ntstatus(ndr_err);
1821         }
1822
1823         blob = ndr_push_blob(push);
1824
1825         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1826         if (!pull) {
1827                 return NT_STATUS_NO_MEMORY;
1828         }
1829
1830         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1831         ndr_err = ndr_pull(pull, NDR_OUT, st);
1832         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1833                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1834                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1835                                          "failed output validation pull - %s",
1836                                          nt_errstr(status));
1837                 return ndr_map_error2ntstatus(ndr_err);
1838         }
1839
1840         push = ndr_push_init_ctx(mem_ctx);
1841         if (!push) {
1842                 return NT_STATUS_NO_MEMORY;
1843         }       
1844
1845         ndr_err = ndr_push(push, NDR_OUT, st);
1846         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1847                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1848                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1849                                          "failed output validation push2 - %s",
1850                                          nt_errstr(status));
1851                 return ndr_map_error2ntstatus(ndr_err);
1852         }
1853
1854         blob2 = ndr_push_blob(push);
1855
1856         if (data_blob_cmp(&blob, &blob2) != 0) {
1857                 DEBUG(3,("original:\n"));
1858                 dump_data(3, blob.data, blob.length);
1859                 DEBUG(3,("secondary:\n"));
1860                 dump_data(3, blob2.data, blob2.length);
1861                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1862                                          "failed output validation blobs doesn't match");
1863                 return ndr_map_error2ntstatus(ndr_err);
1864         }
1865
1866         /* this checks the printed forms of the two structures, which effectively
1867            tests all of the value() attributes */
1868         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1869                                        NDR_OUT, struct_ptr);
1870         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1871                                        NDR_OUT, st);
1872         if (strcmp(s1, s2) != 0) {
1873 #if 1
1874                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1875 #else
1876                 /* this is sometimes useful */
1877                 printf("VALIDATE ERROR\n");
1878                 file_save("wire.dat", s1, strlen(s1));
1879                 file_save("gen.dat", s2, strlen(s2));
1880                 system("diff -u wire.dat gen.dat");
1881 #endif
1882                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1883                                          "failed output validation strings doesn't match");
1884                 return ndr_map_error2ntstatus(ndr_err);
1885         }
1886
1887         return NT_STATUS_OK;
1888 }
1889
1890 /*
1891   a useful function for retrieving the server name we connected to
1892 */
1893 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1894 {
1895         if (!p->conn->transport.target_hostname) {
1896                 if (!p->conn->transport.peer_name) {
1897                         return "";
1898                 }
1899                 return p->conn->transport.peer_name(p->conn);
1900         }
1901         return p->conn->transport.target_hostname(p->conn);
1902 }
1903
1904
1905 /*
1906   get the dcerpc auth_level for a open connection
1907 */
1908 uint32_t dcerpc_auth_level(struct dcecli_connection *c) 
1909 {
1910         uint8_t auth_level;
1911
1912         if (c->flags & DCERPC_SEAL) {
1913                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1914         } else if (c->flags & DCERPC_SIGN) {
1915                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1916         } else if (c->flags & DCERPC_CONNECT) {
1917                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1918         } else {
1919                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1920         }
1921         return auth_level;
1922 }
1923
1924 /*
1925   Receive an alter reply from the transport
1926 */
1927 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1928                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1929 {
1930         struct composite_context *c;
1931         struct dcerpc_pipe *recv_pipe;
1932
1933         c = talloc_get_type(req->async.private_data, struct composite_context);
1934         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1935
1936         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1937             pkt->u.alter_resp.num_results == 1 &&
1938             pkt->u.alter_resp.ctx_list[0].result != 0) {
1939                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1940                          pkt->u.alter_resp.ctx_list[0].reason));
1941                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1942                 return;
1943         }
1944
1945         if (pkt->ptype == DCERPC_PKT_FAULT) {
1946                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1947                 recv_pipe->last_fault_code = pkt->u.fault.status;
1948                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1949                 return;
1950         }
1951
1952         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1953             pkt->u.alter_resp.num_results == 0 ||
1954             pkt->u.alter_resp.ctx_list[0].result != 0) {
1955                 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1956                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1957                 return;
1958         }
1959
1960         /* the alter_resp might contain a reply set of credentials */
1961         if (recv_pipe->conn->security_state.auth_info &&
1962             pkt->u.alter_resp.auth_info.length) {
1963                 struct dcecli_connection *conn = recv_pipe->conn;
1964                 NTSTATUS status;
1965                 uint32_t auth_length;
1966                 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1967                                                   conn->security_state.auth_info, &auth_length, true);
1968                 if (!NT_STATUS_IS_OK(status)) {
1969                         composite_error(c, status);
1970                         return;
1971                 }
1972         }
1973
1974         composite_done(c);
1975 }
1976
1977 /* 
1978    send a dcerpc alter_context request
1979 */
1980 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1981                                                     TALLOC_CTX *mem_ctx,
1982                                                     const struct ndr_syntax_id *syntax,
1983                                                     const struct ndr_syntax_id *transfer_syntax)
1984 {
1985         struct composite_context *c;
1986         struct ncacn_packet pkt;
1987         DATA_BLOB blob;
1988         struct rpc_request *req;
1989
1990         c = composite_create(mem_ctx, p->conn->event_ctx);
1991         if (c == NULL) return NULL;
1992
1993         c->private_data = p;
1994
1995         p->syntax = *syntax;
1996         p->transfer_syntax = *transfer_syntax;
1997
1998         init_ncacn_hdr(p->conn, &pkt);
1999
2000         pkt.ptype = DCERPC_PKT_ALTER;
2001         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2002         pkt.call_id = p->conn->call_id;
2003         pkt.auth_length = 0;
2004
2005         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2006                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2007         }
2008
2009         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
2010                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
2011         }
2012
2013         pkt.u.alter.max_xmit_frag = 5840;
2014         pkt.u.alter.max_recv_frag = 5840;
2015         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2016         pkt.u.alter.num_contexts = 1;
2017         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
2018         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
2019         pkt.u.alter.ctx_list[0].context_id = p->context_id;
2020         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2021         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2022         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2023         pkt.u.alter.auth_info = data_blob(NULL, 0);
2024
2025         /* construct the NDR form of the packet */
2026         c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
2027                                     p->conn->security_state.auth_info);
2028         if (!composite_is_ok(c)) return c;
2029
2030         p->conn->transport.recv_data = dcerpc_recv_data;
2031
2032         /*
2033          * we allocate a dcerpc_request so we can be in the same
2034          * request queue as normal requests
2035          */
2036         req = talloc_zero(c, struct rpc_request);
2037         if (composite_nomem(req, c)) return c;
2038
2039         req->state = RPC_REQUEST_PENDING;
2040         req->call_id = pkt.call_id;
2041         req->async.private_data = c;
2042         req->async.callback = dcerpc_composite_fail;
2043         req->p = p;
2044         req->recv_handler = dcerpc_alter_recv_handler;
2045         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
2046         talloc_set_destructor(req, dcerpc_req_dequeue);
2047
2048         c->status = p->conn->transport.send_request(p->conn, &blob, true);
2049         if (!composite_is_ok(c)) return c;
2050
2051         tevent_add_timer(c->event_ctx, req,
2052                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2053                         dcerpc_timeout_handler, req);
2054
2055         return c;
2056 }
2057
2058 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
2059 {
2060         NTSTATUS result = composite_wait(ctx);
2061         talloc_free(ctx);
2062         return result;
2063 }
2064
2065 /* 
2066    send a dcerpc alter_context request
2067 */
2068 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
2069                               TALLOC_CTX *mem_ctx,
2070                               const struct ndr_syntax_id *syntax,
2071                               const struct ndr_syntax_id *transfer_syntax)
2072 {
2073         struct composite_context *creq;
2074         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
2075         return dcerpc_alter_context_recv(creq);
2076 }
2077