s4:librpc/rpc: pass async as argument to dcerpc_ndr_request_send()
[ira/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 "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33
34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
35 {
36         return gensec_init(lp_ctx);
37 }
38
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
41
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
44 {
45         if (conn->dead) {
46                 conn->free_skipped = true;
47                 return -1;
48         }
49         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50         return 0;
51 }
52
53
54 /* initialise a dcerpc connection. 
55    the event context is optional
56 */
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
58                                                  struct tevent_context *ev,
59                                                  struct smb_iconv_convenience *ic)
60 {
61         struct dcerpc_connection *c;
62
63         c = talloc_zero(mem_ctx, struct dcerpc_connection);
64         if (!c) {
65                 return NULL;
66         }
67
68         c->iconv_convenience = talloc_reference(c, ic);
69
70         c->event_ctx = talloc_reference(c, ev);
71
72         if (c->event_ctx == NULL) {
73                 talloc_free(c);
74                 return NULL;
75         }
76
77         c->call_id = 1;
78         c->security_state.auth_info = NULL;
79         c->security_state.session_key = dcerpc_generic_session_key;
80         c->security_state.generic_state = NULL;
81         c->binding_string = NULL;
82         c->flags = 0;
83         c->srv_max_xmit_frag = 0;
84         c->srv_max_recv_frag = 0;
85         c->pending = NULL;
86
87         talloc_set_destructor(c, dcerpc_connection_destructor);
88
89         return c;
90 }
91
92 /* initialise a dcerpc pipe. */
93 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
94                                      struct smb_iconv_convenience *ic)
95 {
96         struct dcerpc_pipe *p;
97
98         p = talloc(mem_ctx, struct dcerpc_pipe);
99         if (!p) {
100                 return NULL;
101         }
102
103         p->conn = dcerpc_connection_init(p, ev, ic);
104         if (p->conn == NULL) {
105                 talloc_free(p);
106                 return NULL;
107         }
108
109         p->last_fault_code = 0;
110         p->context_id = 0;
111         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
112         p->binding = NULL;
113
114         ZERO_STRUCT(p->syntax);
115         ZERO_STRUCT(p->transfer_syntax);
116
117         return p;
118 }
119
120
121 /* 
122    choose the next call id to use
123 */
124 static uint32_t next_call_id(struct dcerpc_connection *c)
125 {
126         c->call_id++;
127         if (c->call_id == 0) {
128                 c->call_id++;
129         }
130         return c->call_id;
131 }
132
133 /* we need to be able to get/set the fragment length without doing a full
134    decode */
135 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
136 {
137         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
138                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
139         } else {
140                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
141         }
142 }
143
144 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
145 {
146         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
147                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
148         } else {
149                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
150         }
151 }
152
153 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
154 {
155         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
156                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
157         } else {
158                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159         }
160 }
161
162
163 /**
164   setup for a ndr pull, also setting up any flags from the binding string
165 */
166 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c, 
167                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
168 {
169         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
170
171         if (ndr == NULL) return ndr;
172
173         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
174                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
175         }
176
177         if (c->flags & DCERPC_NDR_REF_ALLOC) {
178                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
179         }
180
181         return ndr;
182 }
183
184 /* 
185    parse a data blob into a ncacn_packet structure. This handles both
186    input and output packets
187 */
188 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
189                             struct ncacn_packet *pkt)
190 {
191         struct ndr_pull *ndr;
192         enum ndr_err_code ndr_err;
193
194         ndr = ndr_pull_init_flags(c, blob, mem_ctx);
195         if (!ndr) {
196                 return NT_STATUS_NO_MEMORY;
197         }
198
199         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
201         }
202
203         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
204         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
205                 return ndr_map_error2ntstatus(ndr_err);
206         }
207
208         return NT_STATUS_OK;
209 }
210
211 /* 
212    parse the authentication information on a dcerpc response packet
213 */
214 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx, 
215                                         DATA_BLOB *raw_packet,
216                                         struct ncacn_packet *pkt)
217 {
218         struct ndr_pull *ndr;
219         NTSTATUS status;
220         struct dcerpc_auth auth;
221         DATA_BLOB auth_blob;
222         enum ndr_err_code ndr_err;
223
224         if (!c->security_state.auth_info ||
225             !c->security_state.generic_state) {
226                 return NT_STATUS_OK;
227         }
228
229         switch (c->security_state.auth_info->auth_level) {
230         case DCERPC_AUTH_LEVEL_PRIVACY:
231         case DCERPC_AUTH_LEVEL_INTEGRITY:
232                 break;
233
234         case DCERPC_AUTH_LEVEL_CONNECT:
235                 if (pkt->auth_length != 0) {
236                         break;
237                 }
238                 return NT_STATUS_OK;
239         case DCERPC_AUTH_LEVEL_NONE:
240                 if (pkt->auth_length != 0) {
241                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
242                 }
243                 return NT_STATUS_OK;
244
245         default:
246                 return NT_STATUS_INVALID_LEVEL;
247         }
248
249         auth_blob.length = 8 + pkt->auth_length;
250
251         /* check for a valid length */
252         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
253                 return NT_STATUS_INFO_LENGTH_MISMATCH;
254         }
255
256         auth_blob.data = 
257                 pkt->u.response.stub_and_verifier.data + 
258                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
259         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
260
261         /* pull the auth structure */
262         ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
263         if (!ndr) {
264                 return NT_STATUS_NO_MEMORY;
265         }
266
267         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
268                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
269         }
270
271         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
272         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
273                 return ndr_map_error2ntstatus(ndr_err);
274         }
275         status = NT_STATUS_OK;
276
277         /* check signature or unseal the packet */
278         switch (c->security_state.auth_info->auth_level) {
279         case DCERPC_AUTH_LEVEL_PRIVACY:
280                 status = gensec_unseal_packet(c->security_state.generic_state, 
281                                               mem_ctx, 
282                                               raw_packet->data + DCERPC_REQUEST_LENGTH,
283                                               pkt->u.response.stub_and_verifier.length, 
284                                               raw_packet->data,
285                                               raw_packet->length - auth.credentials.length,
286                                               &auth.credentials);
287                 memcpy(pkt->u.response.stub_and_verifier.data,
288                        raw_packet->data + DCERPC_REQUEST_LENGTH,
289                        pkt->u.response.stub_and_verifier.length);
290                 break;
291                 
292         case DCERPC_AUTH_LEVEL_INTEGRITY:
293                 status = gensec_check_packet(c->security_state.generic_state, 
294                                              mem_ctx, 
295                                              pkt->u.response.stub_and_verifier.data, 
296                                              pkt->u.response.stub_and_verifier.length, 
297                                              raw_packet->data,
298                                              raw_packet->length - auth.credentials.length,
299                                              &auth.credentials);
300                 break;
301
302         case DCERPC_AUTH_LEVEL_CONNECT:
303                 /* for now we ignore possible signatures here */
304                 status = NT_STATUS_OK;
305                 break;
306
307         default:
308                 status = NT_STATUS_INVALID_LEVEL;
309                 break;
310         }
311         
312         /* remove the indicated amount of paddiing */
313         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
314                 return NT_STATUS_INFO_LENGTH_MISMATCH;
315         }
316         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
317
318         return status;
319 }
320
321
322 /* 
323    push a dcerpc request packet into a blob, possibly signing it.
324 */
325 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 
326                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
327                                          size_t sig_size,
328                                          struct ncacn_packet *pkt)
329 {
330         NTSTATUS status;
331         struct ndr_push *ndr;
332         DATA_BLOB creds2;
333         size_t payload_length;
334         enum ndr_err_code ndr_err;
335         size_t hdr_size = DCERPC_REQUEST_LENGTH;
336
337         /* non-signed packets are simpler */
338         if (sig_size == 0) {
339                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
340         }
341
342         switch (c->security_state.auth_info->auth_level) {
343         case DCERPC_AUTH_LEVEL_PRIVACY:
344         case DCERPC_AUTH_LEVEL_INTEGRITY:
345                 break;
346
347         case DCERPC_AUTH_LEVEL_CONNECT:
348                 /* TODO: let the gensec mech decide if it wants to generate a signature */
349                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
350
351         case DCERPC_AUTH_LEVEL_NONE:
352                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
353
354         default:
355                 return NT_STATUS_INVALID_LEVEL;
356         }
357
358         ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
359         if (!ndr) {
360                 return NT_STATUS_NO_MEMORY;
361         }
362
363         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
364                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
365         }
366
367         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
368                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
369                 hdr_size += 16;
370         }
371
372         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
373         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374                 return ndr_map_error2ntstatus(ndr_err);
375         }
376         status = NT_STATUS_OK;
377
378         /* pad to 16 byte multiple in the payload portion of the
379            packet. This matches what w2k3 does */
380         c->security_state.auth_info->auth_pad_length = 
381                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
382         ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
383         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384                 return ndr_map_error2ntstatus(ndr_err);
385         }
386         status = NT_STATUS_OK;
387
388         payload_length = pkt->u.request.stub_and_verifier.length + 
389                 c->security_state.auth_info->auth_pad_length;
390
391         /* we start without signature, it will appended later */
392         c->security_state.auth_info->credentials = data_blob(NULL,0);
393
394         /* add the auth verifier */
395         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
396         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
397                 return ndr_map_error2ntstatus(ndr_err);
398         }
399         status = NT_STATUS_OK;
400
401         /* extract the whole packet as a blob */
402         *blob = ndr_push_blob(ndr);
403
404         /*
405          * Setup the frag and auth length in the packet buffer.
406          * This is needed if the GENSEC mech does AEAD signing
407          * of the packet headers. The signature itself will be
408          * appended later.
409          */
410         dcerpc_set_frag_length(blob, blob->length + sig_size);
411         dcerpc_set_auth_length(blob, sig_size);
412
413         /* sign or seal the packet */
414         switch (c->security_state.auth_info->auth_level) {
415         case DCERPC_AUTH_LEVEL_PRIVACY:
416                 status = gensec_seal_packet(c->security_state.generic_state, 
417                                             mem_ctx, 
418                                             blob->data + hdr_size,
419                                             payload_length,
420                                             blob->data,
421                                             blob->length,
422                                             &creds2);
423                 if (!NT_STATUS_IS_OK(status)) {
424                         return status;
425                 }
426                 break;
427
428         case DCERPC_AUTH_LEVEL_INTEGRITY:
429                 status = gensec_sign_packet(c->security_state.generic_state, 
430                                             mem_ctx, 
431                                             blob->data + hdr_size,
432                                             payload_length, 
433                                             blob->data,
434                                             blob->length,
435                                             &creds2);
436                 if (!NT_STATUS_IS_OK(status)) {
437                         return status;
438                 }
439                 break;
440
441         default:
442                 status = NT_STATUS_INVALID_LEVEL;
443                 break;
444         }
445
446         if (creds2.length != sig_size) {
447                 DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
448                         creds2.length, (uint32_t)sig_size,
449                         c->security_state.auth_info->auth_pad_length,
450                         pkt->u.request.stub_and_verifier.length));
451                 return NT_STATUS_INTERNAL_ERROR;
452         }
453
454         if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
455                 return NT_STATUS_NO_MEMORY;
456         }
457
458         return NT_STATUS_OK;
459 }
460
461
462 /* 
463    fill in the fixed values in a dcerpc header 
464 */
465 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
466 {
467         pkt->rpc_vers = 5;
468         pkt->rpc_vers_minor = 0;
469         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
470                 pkt->drep[0] = 0;
471         } else {
472                 pkt->drep[0] = DCERPC_DREP_LE;
473         }
474         pkt->drep[1] = 0;
475         pkt->drep[2] = 0;
476         pkt->drep[3] = 0;
477 }
478
479 /*
480   map a bind nak reason to a NTSTATUS
481 */
482 static NTSTATUS dcerpc_map_reason(uint16_t reason)
483 {
484         switch (reason) {
485         case DCERPC_BIND_REASON_ASYNTAX:
486                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
487         case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
488                 return NT_STATUS_INVALID_PARAMETER;
489         }
490         return NT_STATUS_UNSUCCESSFUL;
491 }
492
493 /*
494   a bind or alter context has failed
495 */
496 static void dcerpc_composite_fail(struct rpc_request *req)
497 {
498         struct composite_context *c = talloc_get_type(req->async.private_data, 
499                                                       struct composite_context);
500         composite_error(c, req->status);
501 }
502
503 /*
504   remove requests from the pending or queued queues
505  */
506 static int dcerpc_req_dequeue(struct rpc_request *req)
507 {
508         switch (req->state) {
509         case RPC_REQUEST_QUEUED:
510                 DLIST_REMOVE(req->p->conn->request_queue, req);
511                 break;
512         case RPC_REQUEST_PENDING:
513                 DLIST_REMOVE(req->p->conn->pending, req);
514                 break;
515         case RPC_REQUEST_DONE:
516                 break;
517         }
518         return 0;
519 }
520
521
522 /*
523   mark the dcerpc connection dead. All outstanding requests get an error
524 */
525 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
526 {
527         if (conn->dead) return;
528
529         conn->dead = true;
530
531         if (conn->transport.shutdown_pipe) {
532                 conn->transport.shutdown_pipe(conn, status);
533         }
534
535         /* all pending requests get the error */
536         while (conn->pending) {
537                 struct rpc_request *req = conn->pending;
538                 dcerpc_req_dequeue(req);
539                 req->state = RPC_REQUEST_DONE;
540                 req->status = status;
541                 if (req->async.callback) {
542                         req->async.callback(req);
543                 }
544         }       
545
546         talloc_set_destructor(conn, NULL);
547         if (conn->free_skipped) {
548                 talloc_free(conn);
549         }
550 }
551
552 /*
553   forward declarations of the recv_data handlers for the types of
554   packets we need to handle
555 */
556 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
557                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
558
559 /*
560   receive a dcerpc reply from the transport. Here we work out what
561   type of reply it is (normal request, bind or alter context) and
562   dispatch to the appropriate handler
563 */
564 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
565 {
566         struct ncacn_packet pkt;
567
568         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
569                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
570         }
571
572         /* the transport may be telling us of a severe error, such as
573            a dropped socket */
574         if (!NT_STATUS_IS_OK(status)) {
575                 data_blob_free(blob);
576                 dcerpc_connection_dead(conn, status);
577                 return;
578         }
579
580         /* parse the basic packet to work out what type of response this is */
581         status = ncacn_pull(conn, blob, blob->data, &pkt);
582         if (!NT_STATUS_IS_OK(status)) {
583                 data_blob_free(blob);
584                 dcerpc_connection_dead(conn, status);
585         }
586
587         dcerpc_request_recv_data(conn, blob, &pkt);
588 }
589
590
591 /*
592   Receive a bind reply from the transport
593 */
594 static void dcerpc_bind_recv_handler(struct rpc_request *req, 
595                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
596 {
597         struct composite_context *c;
598         struct dcerpc_connection *conn;
599
600         c = talloc_get_type(req->async.private_data, struct composite_context);
601
602         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
603                 DEBUG(2,("dcerpc: bind_nak reason %d\n",
604                          pkt->u.bind_nak.reject_reason));
605                 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
606                                                      reject_reason));
607                 return;
608         }
609
610         if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
611             (pkt->u.bind_ack.num_results == 0) ||
612             (pkt->u.bind_ack.ctx_list[0].result != 0)) {
613                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
614                 return;
615         }
616
617         conn = req->p->conn;
618
619         conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
620         conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
621
622         if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
623             (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
624                 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
625         }
626
627         if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
628             (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
629                 conn->flags |= DCERPC_HEADER_SIGNING;
630         }
631
632         /* the bind_ack might contain a reply set of credentials */
633         if (conn->security_state.auth_info &&
634             pkt->u.bind_ack.auth_info.length) {
635                 enum ndr_err_code ndr_err;
636                 ndr_err = ndr_pull_struct_blob(
637                         &pkt->u.bind_ack.auth_info, conn,
638                         NULL,
639                         conn->security_state.auth_info,
640                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
641                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
642                         c->status = ndr_map_error2ntstatus(ndr_err);
643                         if (!composite_is_ok(c)) return;
644                 }
645         }
646
647         req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
648
649         composite_done(c);
650 }
651
652 /*
653   handle timeouts of individual dcerpc requests
654 */
655 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
656                                    struct timeval t, void *private_data)
657 {
658         struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
659
660         if (req->ignore_timeout) {
661                 dcerpc_req_dequeue(req);
662                 req->state = RPC_REQUEST_DONE;
663                 req->status = NT_STATUS_IO_TIMEOUT;
664                 if (req->async.callback) {
665                         req->async.callback(req);
666                 }
667                 return;
668         }
669
670         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
671 }
672
673 /*
674   send a async dcerpc bind request
675 */
676 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
677                                            TALLOC_CTX *mem_ctx,
678                                            const struct ndr_syntax_id *syntax,
679                                            const struct ndr_syntax_id *transfer_syntax)
680 {
681         struct composite_context *c;
682         struct ncacn_packet pkt;
683         DATA_BLOB blob;
684         struct rpc_request *req;
685
686         c = composite_create(mem_ctx,p->conn->event_ctx);
687         if (c == NULL) return NULL;
688
689         c->private_data = p;
690
691         p->syntax = *syntax;
692         p->transfer_syntax = *transfer_syntax;
693
694         init_ncacn_hdr(p->conn, &pkt);
695
696         pkt.ptype = DCERPC_PKT_BIND;
697         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
698         pkt.call_id = p->conn->call_id;
699         pkt.auth_length = 0;
700
701         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
702                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
703         }
704
705         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
706                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
707         }
708
709         pkt.u.bind.max_xmit_frag = 5840;
710         pkt.u.bind.max_recv_frag = 5840;
711         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
712         pkt.u.bind.num_contexts = 1;
713         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
714         if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
715         pkt.u.bind.ctx_list[0].context_id = p->context_id;
716         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
717         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
718         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
719         pkt.u.bind.auth_info = data_blob(NULL, 0);
720
721         /* construct the NDR form of the packet */
722         c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
723                                     p->conn->security_state.auth_info);
724         if (!composite_is_ok(c)) return c;
725
726         p->conn->transport.recv_data = dcerpc_recv_data;
727
728         /*
729          * we allocate a dcerpc_request so we can be in the same
730          * request queue as normal requests
731          */
732         req = talloc_zero(c, struct rpc_request);
733         if (composite_nomem(req, c)) return c;
734
735         req->state = RPC_REQUEST_PENDING;
736         req->call_id = pkt.call_id;
737         req->async.private_data = c;
738         req->async.callback = dcerpc_composite_fail;
739         req->p = p;
740         req->recv_handler = dcerpc_bind_recv_handler;
741         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
742         talloc_set_destructor(req, dcerpc_req_dequeue);
743
744         c->status = p->conn->transport.send_request(p->conn, &blob,
745                                                     true);
746         if (!composite_is_ok(c)) return c;
747
748         event_add_timed(c->event_ctx, req,
749                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
750                         dcerpc_timeout_handler, req);
751
752         return c;
753 }
754
755 /*
756   recv side of async dcerpc bind request
757 */
758 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
759 {
760         NTSTATUS result = composite_wait(ctx);
761         talloc_free(ctx);
762         return result;
763 }
764
765 /* 
766    perform a continued bind (and auth3)
767 */
768 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
769                       TALLOC_CTX *mem_ctx)
770 {
771         struct ncacn_packet pkt;
772         NTSTATUS status;
773         DATA_BLOB blob;
774
775         init_ncacn_hdr(p->conn, &pkt);
776
777         pkt.ptype = DCERPC_PKT_AUTH3;
778         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
779         pkt.call_id = next_call_id(p->conn);
780         pkt.auth_length = 0;
781         pkt.u.auth3._pad = 0;
782         pkt.u.auth3.auth_info = data_blob(NULL, 0);
783
784         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
785                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
786         }
787
788         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
789                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
790         }
791
792         /* construct the NDR form of the packet */
793         status = ncacn_push_auth(&blob, mem_ctx,
794                                  p->conn->iconv_convenience,
795                                  &pkt,
796                                  p->conn->security_state.auth_info);
797         if (!NT_STATUS_IS_OK(status)) {
798                 return status;
799         }
800
801         /* send it on its way */
802         status = p->conn->transport.send_request(p->conn, &blob, false);
803         if (!NT_STATUS_IS_OK(status)) {
804                 return status;
805         }
806
807         return NT_STATUS_OK;    
808 }
809
810
811 /*
812   process a fragment received from the transport layer during a
813   request
814
815   This function frees the data 
816 */
817 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
818                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
819 {
820         struct rpc_request *req;
821         uint_t length;
822         NTSTATUS status = NT_STATUS_OK;
823
824         /*
825           if this is an authenticated connection then parse and check
826           the auth info. We have to do this before finding the
827           matching packet, as the request structure might have been
828           removed due to a timeout, but if it has been we still need
829           to run the auth routines so that we don't get the sign/seal
830           info out of step with the server
831         */
832         if (c->security_state.auth_info && c->security_state.generic_state &&
833             pkt->ptype == DCERPC_PKT_RESPONSE) {
834                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
835         }
836
837         /* find the matching request */
838         for (req=c->pending;req;req=req->next) {
839                 if (pkt->call_id == req->call_id) break;
840         }
841
842 #if 0
843         /* useful for testing certain vendors RPC servers */
844         if (req == NULL && c->pending && pkt->call_id == 0) {
845                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
846                 req = c->pending;
847         }
848 #endif
849
850         if (req == NULL) {
851                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
852                 data_blob_free(raw_packet);
853                 return;
854         }
855
856         talloc_steal(req, raw_packet->data);
857
858         if (req->recv_handler != NULL) {
859                 dcerpc_req_dequeue(req);
860                 req->state = RPC_REQUEST_DONE;
861                 req->recv_handler(req, raw_packet, pkt);
862                 return;
863         }
864
865         if (pkt->ptype == DCERPC_PKT_FAULT) {
866                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
867                 req->fault_code = pkt->u.fault.status;
868                 req->status = NT_STATUS_NET_WRITE_FAULT;
869                 goto req_done;
870         }
871
872         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
873                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
874                          (int)pkt->ptype)); 
875                 req->fault_code = DCERPC_FAULT_OTHER;
876                 req->status = NT_STATUS_NET_WRITE_FAULT;
877                 goto req_done;
878         }
879
880         /* now check the status from the auth routines, and if it failed then fail
881            this request accordingly */
882         if (!NT_STATUS_IS_OK(status)) {
883                 req->status = status;
884                 goto req_done;
885         }
886
887         length = pkt->u.response.stub_and_verifier.length;
888
889         if (length > 0) {
890                 req->payload.data = talloc_realloc(req, 
891                                                    req->payload.data, 
892                                                    uint8_t,
893                                                    req->payload.length + length);
894                 if (!req->payload.data) {
895                         req->status = NT_STATUS_NO_MEMORY;
896                         goto req_done;
897                 }
898                 memcpy(req->payload.data+req->payload.length, 
899                        pkt->u.response.stub_and_verifier.data, length);
900                 req->payload.length += length;
901         }
902
903         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
904                 c->transport.send_read(c);
905                 return;
906         }
907
908         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
909                 req->flags |= DCERPC_PULL_BIGENDIAN;
910         } else {
911                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
912         }
913
914
915 req_done:
916         /* we've got the full payload */
917         req->state = RPC_REQUEST_DONE;
918         DLIST_REMOVE(c->pending, req);
919
920         if (c->request_queue != NULL) {
921                 /* We have to look at shipping further requests before calling
922                  * the async function, that one might close the pipe */
923                 dcerpc_ship_next_request(c);
924         }
925
926         if (req->async.callback) {
927                 req->async.callback(req);
928         }
929 }
930
931 /*
932   perform the send side of a async dcerpc request
933 */
934 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
935                                                const struct GUID *object,
936                                                uint16_t opnum,
937                                                bool async,
938                                                DATA_BLOB *stub_data)
939 {
940         struct rpc_request *req;
941
942         p->conn->transport.recv_data = dcerpc_recv_data;
943
944         req = talloc(p, struct rpc_request);
945         if (req == NULL) {
946                 return NULL;
947         }
948
949         req->p = p;
950         req->call_id = next_call_id(p->conn);
951         req->status = NT_STATUS_OK;
952         req->state = RPC_REQUEST_QUEUED;
953         req->payload = data_blob(NULL, 0);
954         req->flags = 0;
955         req->fault_code = 0;
956         req->async_call = async;
957         req->ignore_timeout = false;
958         req->async.callback = NULL;
959         req->async.private_data = NULL;
960         req->recv_handler = NULL;
961
962         if (object != NULL) {
963                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
964                 if (req->object == NULL) {
965                         talloc_free(req);
966                         return NULL;
967                 }
968         } else {
969                 req->object = NULL;
970         }
971
972         req->opnum = opnum;
973         req->request_data.length = stub_data->length;
974         req->request_data.data = talloc_reference(req, stub_data->data);
975         if (req->request_data.length && req->request_data.data == NULL) {
976                 return NULL;
977         }
978
979         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
980         talloc_set_destructor(req, dcerpc_req_dequeue);
981
982         dcerpc_ship_next_request(p->conn);
983
984         if (p->request_timeout) {
985                 event_add_timed(dcerpc_event_context(p), req, 
986                                 timeval_current_ofs(p->request_timeout, 0), 
987                                 dcerpc_timeout_handler, req);
988         }
989
990         return req;
991 }
992
993 /*
994   Send a request using the transport
995 */
996
997 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
998 {
999         struct rpc_request *req;
1000         struct dcerpc_pipe *p;
1001         DATA_BLOB *stub_data;
1002         struct ncacn_packet pkt;
1003         DATA_BLOB blob;
1004         uint32_t remaining, chunk_size;
1005         bool first_packet = true;
1006         size_t sig_size = 0;
1007
1008         req = c->request_queue;
1009         if (req == NULL) {
1010                 return;
1011         }
1012
1013         p = req->p;
1014         stub_data = &req->request_data;
1015
1016         if (!req->async_call && (c->pending != NULL)) {
1017                 return;
1018         }
1019
1020         DLIST_REMOVE(c->request_queue, req);
1021         DLIST_ADD(c->pending, req);
1022         req->state = RPC_REQUEST_PENDING;
1023
1024         init_ncacn_hdr(p->conn, &pkt);
1025
1026         remaining = stub_data->length;
1027
1028         /* we can write a full max_recv_frag size, minus the dcerpc
1029            request header size */
1030         chunk_size = p->conn->srv_max_recv_frag;
1031         chunk_size -= DCERPC_REQUEST_LENGTH;
1032         if (c->security_state.auth_info &&
1033             c->security_state.generic_state) {
1034                 sig_size = gensec_sig_size(c->security_state.generic_state,
1035                                            p->conn->srv_max_recv_frag);
1036                 if (sig_size) {
1037                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1038                         chunk_size -= sig_size;
1039                 }
1040         }
1041         chunk_size -= (chunk_size % 16);
1042
1043         pkt.ptype = DCERPC_PKT_REQUEST;
1044         pkt.call_id = req->call_id;
1045         pkt.auth_length = 0;
1046         pkt.pfc_flags = 0;
1047         pkt.u.request.alloc_hint = remaining;
1048         pkt.u.request.context_id = p->context_id;
1049         pkt.u.request.opnum = req->opnum;
1050
1051         if (req->object) {
1052                 pkt.u.request.object.object = *req->object;
1053                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1054                 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1055         }
1056
1057         /* we send a series of pdus without waiting for a reply */
1058         while (remaining > 0 || first_packet) {
1059                 uint32_t chunk = MIN(chunk_size, remaining);
1060                 bool last_frag = false;
1061                 bool do_trans = false;
1062
1063                 first_packet = false;
1064                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1065
1066                 if (remaining == stub_data->length) {
1067                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1068                 }
1069                 if (chunk == remaining) {
1070                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1071                         last_frag = true;
1072                 }
1073
1074                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1075                         (stub_data->length - remaining);
1076                 pkt.u.request.stub_and_verifier.length = chunk;
1077
1078                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1079                 if (!NT_STATUS_IS_OK(req->status)) {
1080                         req->state = RPC_REQUEST_DONE;
1081                         DLIST_REMOVE(p->conn->pending, req);
1082                         return;
1083                 }
1084
1085                 if (last_frag && !req->async_call) {
1086                         do_trans = true;
1087                 }
1088
1089                 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1090                 if (!NT_STATUS_IS_OK(req->status)) {
1091                         req->state = RPC_REQUEST_DONE;
1092                         DLIST_REMOVE(p->conn->pending, req);
1093                         return;
1094                 }               
1095
1096                 if (last_frag && !do_trans) {
1097                         req->status = p->conn->transport.send_read(p->conn);
1098                         if (!NT_STATUS_IS_OK(req->status)) {
1099                                 req->state = RPC_REQUEST_DONE;
1100                                 DLIST_REMOVE(p->conn->pending, req);
1101                                 return;
1102                         }
1103                 }
1104
1105                 remaining -= chunk;
1106         }
1107 }
1108
1109 /*
1110   return the event context for a dcerpc pipe
1111   used by callers who wish to operate asynchronously
1112 */
1113 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1114 {
1115         return p->conn->event_ctx;
1116 }
1117
1118
1119
1120 /*
1121   perform the receive side of a async dcerpc request
1122 */
1123 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1124                              TALLOC_CTX *mem_ctx,
1125                              DATA_BLOB *stub_data)
1126 {
1127         NTSTATUS status;
1128
1129         while (req->state != RPC_REQUEST_DONE) {
1130                 struct tevent_context *ctx = dcerpc_event_context(req->p);
1131                 if (event_loop_once(ctx) != 0) {
1132                         return NT_STATUS_CONNECTION_DISCONNECTED;
1133                 }
1134         }
1135         *stub_data = req->payload;
1136         status = req->status;
1137         if (stub_data->data) {
1138                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1139         }
1140         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1141                 req->p->last_fault_code = req->fault_code;
1142         }
1143         talloc_free(req);
1144         return status;
1145 }
1146
1147 /*
1148   perform a full request/response pair on a dcerpc pipe
1149 */
1150 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1151                         struct GUID *object,
1152                         uint16_t opnum,
1153                         TALLOC_CTX *mem_ctx,
1154                         DATA_BLOB *stub_data_in,
1155                         DATA_BLOB *stub_data_out)
1156 {
1157         struct rpc_request *req;
1158
1159         req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1160         if (req == NULL) {
1161                 return NT_STATUS_NO_MEMORY;
1162         }
1163
1164         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1165 }
1166
1167
1168 /*
1169   this is a paranoid NDR validator. For every packet we push onto the wire
1170   we pull it back again, then push it again. Then we compare the raw NDR data
1171   for that to the NDR we initially generated. If they don't match then we know
1172   we must have a bug in either the pull or push side of our code
1173 */
1174 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1175                                        TALLOC_CTX *mem_ctx,
1176                                        DATA_BLOB blob,
1177                                        size_t struct_size,
1178                                        ndr_push_flags_fn_t ndr_push,
1179                                        ndr_pull_flags_fn_t ndr_pull)
1180 {
1181         void *st;
1182         struct ndr_pull *pull;
1183         struct ndr_push *push;
1184         DATA_BLOB blob2;
1185         enum ndr_err_code ndr_err;
1186
1187         st = talloc_size(mem_ctx, struct_size);
1188         if (!st) {
1189                 return NT_STATUS_NO_MEMORY;
1190         }
1191
1192         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1193         if (!pull) {
1194                 return NT_STATUS_NO_MEMORY;
1195         }
1196         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1197
1198         ndr_err = ndr_pull(pull, NDR_IN, st);
1199         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1200                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1201                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1202                                          "failed input validation pull - %s",
1203                                          nt_errstr(status));
1204                 return ndr_map_error2ntstatus(ndr_err);
1205         }
1206
1207         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1208         if (!push) {
1209                 return NT_STATUS_NO_MEMORY;
1210         }       
1211
1212         ndr_err = ndr_push(push, NDR_IN, st);
1213         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1214                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1215                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216                                          "failed input validation push - %s",
1217                                          nt_errstr(status));
1218                 return ndr_map_error2ntstatus(ndr_err);
1219         }
1220
1221         blob2 = ndr_push_blob(push);
1222
1223         if (data_blob_cmp(&blob, &blob2) != 0) {
1224                 DEBUG(3,("original:\n"));
1225                 dump_data(3, blob.data, blob.length);
1226                 DEBUG(3,("secondary:\n"));
1227                 dump_data(3, blob2.data, blob2.length);
1228                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1229                                          "failed input validation blobs doesn't match");
1230                 return ndr_map_error2ntstatus(ndr_err);
1231         }
1232
1233         return NT_STATUS_OK;
1234 }
1235
1236 /*
1237   this is a paranoid NDR input validator. For every packet we pull
1238   from the wire we push it back again then pull and push it
1239   again. Then we compare the raw NDR data for that to the NDR we
1240   initially generated. If they don't match then we know we must have a
1241   bug in either the pull or push side of our code
1242 */
1243 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1244                                         struct ndr_pull *pull_in,
1245                                         void *struct_ptr,
1246                                         size_t struct_size,
1247                                         ndr_push_flags_fn_t ndr_push,
1248                                         ndr_pull_flags_fn_t ndr_pull,
1249                                         ndr_print_function_t ndr_print)
1250 {
1251         void *st;
1252         struct ndr_pull *pull;
1253         struct ndr_push *push;
1254         DATA_BLOB blob, blob2;
1255         TALLOC_CTX *mem_ctx = pull_in;
1256         char *s1, *s2;
1257         enum ndr_err_code ndr_err;
1258
1259         st = talloc_size(mem_ctx, struct_size);
1260         if (!st) {
1261                 return NT_STATUS_NO_MEMORY;
1262         }
1263         memcpy(st, struct_ptr, struct_size);
1264
1265         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1266         if (!push) {
1267                 return NT_STATUS_NO_MEMORY;
1268         }       
1269
1270         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1271         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1272                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1273                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1274                                          "failed output validation push - %s",
1275                                          nt_errstr(status));
1276                 return ndr_map_error2ntstatus(ndr_err);
1277         }
1278
1279         blob = ndr_push_blob(push);
1280
1281         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1282         if (!pull) {
1283                 return NT_STATUS_NO_MEMORY;
1284         }
1285
1286         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1287         ndr_err = ndr_pull(pull, NDR_OUT, st);
1288         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1289                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1290                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1291                                          "failed output validation pull - %s",
1292                                          nt_errstr(status));
1293                 return ndr_map_error2ntstatus(ndr_err);
1294         }
1295
1296         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1297         if (!push) {
1298                 return NT_STATUS_NO_MEMORY;
1299         }       
1300
1301         ndr_err = ndr_push(push, NDR_OUT, st);
1302         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1303                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1304                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1305                                          "failed output validation push2 - %s",
1306                                          nt_errstr(status));
1307                 return ndr_map_error2ntstatus(ndr_err);
1308         }
1309
1310         blob2 = ndr_push_blob(push);
1311
1312         if (data_blob_cmp(&blob, &blob2) != 0) {
1313                 DEBUG(3,("original:\n"));
1314                 dump_data(3, blob.data, blob.length);
1315                 DEBUG(3,("secondary:\n"));
1316                 dump_data(3, blob2.data, blob2.length);
1317                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1318                                          "failed output validation blobs doesn't match");
1319                 return ndr_map_error2ntstatus(ndr_err);
1320         }
1321
1322         /* this checks the printed forms of the two structures, which effectively
1323            tests all of the value() attributes */
1324         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1325                                        NDR_OUT, struct_ptr);
1326         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1327                                        NDR_OUT, st);
1328         if (strcmp(s1, s2) != 0) {
1329 #if 1
1330                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1331 #else
1332                 /* this is sometimes useful */
1333                 printf("VALIDATE ERROR\n");
1334                 file_save("wire.dat", s1, strlen(s1));
1335                 file_save("gen.dat", s2, strlen(s2));
1336                 system("diff -u wire.dat gen.dat");
1337 #endif
1338                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1339                                          "failed output validation strings doesn't match");
1340                 return ndr_map_error2ntstatus(ndr_err);
1341         }
1342
1343         return NT_STATUS_OK;
1344 }
1345
1346
1347 /**
1348  send a rpc request given a dcerpc_call structure 
1349  */
1350 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1351                                             const struct GUID *object,
1352                                             const struct ndr_interface_table *table,
1353                                             uint32_t opnum,
1354                                             bool async,
1355                                             TALLOC_CTX *mem_ctx,
1356                                             void *r)
1357 {
1358         const struct ndr_interface_call *call;
1359         struct ndr_push *push;
1360         NTSTATUS status;
1361         DATA_BLOB request;
1362         struct rpc_request *req;
1363         enum ndr_err_code ndr_err;
1364
1365         call = &table->calls[opnum];
1366
1367         /* setup for a ndr_push_* call */
1368         push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1369         if (!push) {
1370                 return NULL;
1371         }
1372
1373         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1374                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1375         }
1376
1377         /* push the structure into a blob */
1378         ndr_err = call->ndr_push(push, NDR_IN, r);
1379         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1380                 status = ndr_map_error2ntstatus(ndr_err);
1381                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1382                          nt_errstr(status)));
1383                 talloc_free(push);
1384                 return NULL;
1385         }
1386
1387         /* retrieve the blob */
1388         request = ndr_push_blob(push);
1389
1390         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1391                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1392                                                 call->ndr_push, call->ndr_pull);
1393                 if (!NT_STATUS_IS_OK(status)) {
1394                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1395                                  nt_errstr(status)));
1396                         talloc_free(push);
1397                         return NULL;
1398                 }
1399         }
1400
1401         DEBUG(10,("rpc request data:\n"));
1402         dump_data(10, request.data, request.length);
1403
1404         /* make the actual dcerpc request */
1405         req = dcerpc_request_send(p, object, opnum, async, &request);
1406
1407         if (req != NULL) {
1408                 req->ndr.table = table;
1409                 req->ndr.opnum = opnum;
1410                 req->ndr.struct_ptr = r;
1411                 req->ndr.mem_ctx = mem_ctx;
1412         }
1413
1414         talloc_free(push);
1415
1416         return req;
1417 }
1418
1419 /*
1420   receive the answer from a dcerpc_ndr_request_send()
1421 */
1422 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1423 {
1424         struct dcerpc_pipe *p = req->p;
1425         NTSTATUS status;
1426         DATA_BLOB response;
1427         struct ndr_pull *pull;
1428         uint_t flags;
1429         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1430         void *r = req->ndr.struct_ptr;
1431         uint32_t opnum = req->ndr.opnum;
1432         const struct ndr_interface_table *table = req->ndr.table;
1433         const struct ndr_interface_call *call = &table->calls[opnum];
1434         enum ndr_err_code ndr_err;
1435
1436         /* make sure the recv code doesn't free the request, as we
1437            need to grab the flags element before it is freed */
1438         if (talloc_reference(p, req) == NULL) {
1439                 return NT_STATUS_NO_MEMORY;
1440         }
1441
1442         status = dcerpc_request_recv(req, mem_ctx, &response);
1443         if (!NT_STATUS_IS_OK(status)) {
1444                 talloc_unlink(p, req);
1445                 return status;
1446         }
1447
1448         flags = req->flags;
1449
1450         /* prepare for ndr_pull_* */
1451         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1452         if (!pull) {
1453                 talloc_unlink(p, req);
1454                 return NT_STATUS_NO_MEMORY;
1455         }
1456
1457         if (pull->data) {
1458                 pull->data = talloc_steal(pull, pull->data);
1459         }
1460         talloc_unlink(p, req);
1461
1462         if (flags & DCERPC_PULL_BIGENDIAN) {
1463                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1464         }
1465
1466         DEBUG(10,("rpc reply data:\n"));
1467         dump_data(10, pull->data, pull->data_size);
1468
1469         /* pull the structure from the blob */
1470         ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1471         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1472                 status = ndr_map_error2ntstatus(ndr_err);
1473                 dcerpc_log_packet(p->conn->packet_log_dir,
1474                                                   table, opnum, NDR_OUT, 
1475                                                   &response);
1476                 return status;
1477         }
1478
1479         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1480                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1481                                                  call->ndr_push, call->ndr_pull, 
1482                                                  call->ndr_print);
1483                 if (!NT_STATUS_IS_OK(status)) {
1484                         dcerpc_log_packet(p->conn->packet_log_dir, 
1485                                                           table, opnum, NDR_OUT, 
1486                                   &response);
1487                         return status;
1488                 }
1489         }
1490
1491         if (pull->offset != pull->data_size) {
1492                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1493                          pull->data_size - pull->offset));
1494                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1495                    but it turns out that early versions of NT
1496                    (specifically NT3.1) add junk onto the end of rpc
1497                    packets, so if we want to interoperate at all with
1498                    those versions then we need to ignore this error */
1499         }
1500
1501         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1502
1503         return NT_STATUS_OK;
1504 }
1505
1506
1507 /*
1508   a useful helper function for synchronous rpc requests 
1509
1510   this can be used when you have ndr push/pull functions in the
1511   standard format
1512 */
1513 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1514                             const struct GUID *object,
1515                             const struct ndr_interface_table *table,
1516                             uint32_t opnum, 
1517                             TALLOC_CTX *mem_ctx, 
1518                             void *r)
1519 {
1520         struct rpc_request *req;
1521
1522         req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1523         if (req == NULL) {
1524                 return NT_STATUS_NO_MEMORY;
1525         }
1526
1527         return dcerpc_ndr_request_recv(req);
1528 }
1529
1530
1531 /*
1532   a useful function for retrieving the server name we connected to
1533 */
1534 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1535 {
1536         if (!p->conn->transport.target_hostname) {
1537                 if (!p->conn->transport.peer_name) {
1538                         return "";
1539                 }
1540                 return p->conn->transport.peer_name(p->conn);
1541         }
1542         return p->conn->transport.target_hostname(p->conn);
1543 }
1544
1545
1546 /*
1547   get the dcerpc auth_level for a open connection
1548 */
1549 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1550 {
1551         uint8_t auth_level;
1552
1553         if (c->flags & DCERPC_SEAL) {
1554                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1555         } else if (c->flags & DCERPC_SIGN) {
1556                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1557         } else if (c->flags & DCERPC_CONNECT) {
1558                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1559         } else {
1560                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1561         }
1562         return auth_level;
1563 }
1564
1565 /*
1566   Receive an alter reply from the transport
1567 */
1568 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1569                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1570 {
1571         struct composite_context *c;
1572         struct dcerpc_pipe *recv_pipe;
1573
1574         c = talloc_get_type(req->async.private_data, struct composite_context);
1575         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1576
1577         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1578             pkt->u.alter_resp.num_results == 1 &&
1579             pkt->u.alter_resp.ctx_list[0].result != 0) {
1580                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1581                          pkt->u.alter_resp.ctx_list[0].reason));
1582                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1583                 return;
1584         }
1585
1586         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1587             pkt->u.alter_resp.num_results == 0 ||
1588             pkt->u.alter_resp.ctx_list[0].result != 0) {
1589                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1590                 return;
1591         }
1592
1593         /* the alter_resp might contain a reply set of credentials */
1594         if (recv_pipe->conn->security_state.auth_info &&
1595             pkt->u.alter_resp.auth_info.length) {
1596                 enum ndr_err_code ndr_err;
1597                 ndr_err = ndr_pull_struct_blob(
1598                         &pkt->u.alter_resp.auth_info, recv_pipe,
1599                         NULL,
1600                         recv_pipe->conn->security_state.auth_info,
1601                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1602                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1603                         c->status = ndr_map_error2ntstatus(ndr_err);
1604                         if (!composite_is_ok(c)) return;
1605                 }
1606         }
1607
1608         composite_done(c);
1609 }
1610
1611 /* 
1612    send a dcerpc alter_context request
1613 */
1614 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1615                                                     TALLOC_CTX *mem_ctx,
1616                                                     const struct ndr_syntax_id *syntax,
1617                                                     const struct ndr_syntax_id *transfer_syntax)
1618 {
1619         struct composite_context *c;
1620         struct ncacn_packet pkt;
1621         DATA_BLOB blob;
1622         struct rpc_request *req;
1623
1624         c = composite_create(mem_ctx, p->conn->event_ctx);
1625         if (c == NULL) return NULL;
1626
1627         c->private_data = p;
1628
1629         p->syntax = *syntax;
1630         p->transfer_syntax = *transfer_syntax;
1631
1632         init_ncacn_hdr(p->conn, &pkt);
1633
1634         pkt.ptype = DCERPC_PKT_ALTER;
1635         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1636         pkt.call_id = p->conn->call_id;
1637         pkt.auth_length = 0;
1638
1639         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1640                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1641         }
1642
1643         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1644                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1645         }
1646
1647         pkt.u.alter.max_xmit_frag = 5840;
1648         pkt.u.alter.max_recv_frag = 5840;
1649         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1650         pkt.u.alter.num_contexts = 1;
1651         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1652         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1653         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1654         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1655         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1656         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1657         pkt.u.alter.auth_info = data_blob(NULL, 0);
1658
1659         /* construct the NDR form of the packet */
1660         c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1661                                     p->conn->security_state.auth_info);
1662         if (!composite_is_ok(c)) return c;
1663
1664         p->conn->transport.recv_data = dcerpc_recv_data;
1665
1666         /*
1667          * we allocate a dcerpc_request so we can be in the same
1668          * request queue as normal requests
1669          */
1670         req = talloc_zero(c, struct rpc_request);
1671         if (composite_nomem(req, c)) return c;
1672
1673         req->state = RPC_REQUEST_PENDING;
1674         req->call_id = pkt.call_id;
1675         req->async.private_data = c;
1676         req->async.callback = dcerpc_composite_fail;
1677         req->p = p;
1678         req->recv_handler = dcerpc_alter_recv_handler;
1679         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1680         talloc_set_destructor(req, dcerpc_req_dequeue);
1681
1682         c->status = p->conn->transport.send_request(p->conn, &blob, true);
1683         if (!composite_is_ok(c)) return c;
1684
1685         event_add_timed(c->event_ctx, req,
1686                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1687                         dcerpc_timeout_handler, req);
1688
1689         return c;
1690 }
1691
1692 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1693 {
1694         NTSTATUS result = composite_wait(ctx);
1695         talloc_free(ctx);
1696         return result;
1697 }
1698
1699 /* 
1700    send a dcerpc alter_context request
1701 */
1702 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1703                               TALLOC_CTX *mem_ctx,
1704                               const struct ndr_syntax_id *syntax,
1705                               const struct ndr_syntax_id *transfer_syntax)
1706 {
1707         struct composite_context *creq;
1708         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1709         return dcerpc_alter_context_recv(creq);
1710 }