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