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