4e07cc7b57c89e4233da1df00f7fdca70131de8e
[kai/samba-autobuild/.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Jelmer Vernooij 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33
34 _PUBLIC_ NTSTATUS dcerpc_init(void)
35 {
36         return gensec_init(global_loadparm);
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 event_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 event_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 event_context *ev, struct timed_event *te, 
656                                    struct timeval t, void *private)
657 {
658         struct rpc_request *req = talloc_get_type(private, 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,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
1062                 first_packet = false;
1063                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1064
1065                 if (remaining == stub_data->length) {
1066                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1067                 }
1068                 if (chunk == remaining) {
1069                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1070                         last_frag = true;
1071                 }
1072
1073                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1074                         (stub_data->length - remaining);
1075                 pkt.u.request.stub_and_verifier.length = chunk;
1076
1077                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1078                 if (!NT_STATUS_IS_OK(req->status)) {
1079                         req->state = RPC_REQUEST_DONE;
1080                         DLIST_REMOVE(p->conn->pending, req);
1081                         return;
1082                 }
1083                 
1084                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1085                 if (!NT_STATUS_IS_OK(req->status)) {
1086                         req->state = RPC_REQUEST_DONE;
1087                         DLIST_REMOVE(p->conn->pending, req);
1088                         return;
1089                 }               
1090
1091                 remaining -= chunk;
1092         }
1093 }
1094
1095 /*
1096   return the event context for a dcerpc pipe
1097   used by callers who wish to operate asynchronously
1098 */
1099 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1100 {
1101         return p->conn->event_ctx;
1102 }
1103
1104
1105
1106 /*
1107   perform the receive side of a async dcerpc request
1108 */
1109 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1110                              TALLOC_CTX *mem_ctx,
1111                              DATA_BLOB *stub_data)
1112 {
1113         NTSTATUS status;
1114
1115         while (req->state != RPC_REQUEST_DONE) {
1116                 struct event_context *ctx = dcerpc_event_context(req->p);
1117                 if (event_loop_once(ctx) != 0) {
1118                         return NT_STATUS_CONNECTION_DISCONNECTED;
1119                 }
1120         }
1121         *stub_data = req->payload;
1122         status = req->status;
1123         if (stub_data->data) {
1124                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1125         }
1126         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1127                 req->p->last_fault_code = req->fault_code;
1128         }
1129         talloc_free(req);
1130         return status;
1131 }
1132
1133 /*
1134   perform a full request/response pair on a dcerpc pipe
1135 */
1136 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1137                         struct GUID *object,
1138                         uint16_t opnum,
1139                         bool async,
1140                         TALLOC_CTX *mem_ctx,
1141                         DATA_BLOB *stub_data_in,
1142                         DATA_BLOB *stub_data_out)
1143 {
1144         struct rpc_request *req;
1145
1146         req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1147         if (req == NULL) {
1148                 return NT_STATUS_NO_MEMORY;
1149         }
1150
1151         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1152 }
1153
1154
1155 /*
1156   this is a paranoid NDR validator. For every packet we push onto the wire
1157   we pull it back again, then push it again. Then we compare the raw NDR data
1158   for that to the NDR we initially generated. If they don't match then we know
1159   we must have a bug in either the pull or push side of our code
1160 */
1161 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1162                                        TALLOC_CTX *mem_ctx,
1163                                        DATA_BLOB blob,
1164                                        size_t struct_size,
1165                                        ndr_push_flags_fn_t ndr_push,
1166                                        ndr_pull_flags_fn_t ndr_pull)
1167 {
1168         void *st;
1169         struct ndr_pull *pull;
1170         struct ndr_push *push;
1171         DATA_BLOB blob2;
1172         enum ndr_err_code ndr_err;
1173
1174         st = talloc_size(mem_ctx, struct_size);
1175         if (!st) {
1176                 return NT_STATUS_NO_MEMORY;
1177         }
1178
1179         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1180         if (!pull) {
1181                 return NT_STATUS_NO_MEMORY;
1182         }
1183         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1184
1185         ndr_err = ndr_pull(pull, NDR_IN, st);
1186         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1187                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1188                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1189                                          "failed input validation pull - %s",
1190                                          nt_errstr(status));
1191                 return ndr_map_error2ntstatus(ndr_err);
1192         }
1193
1194         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1195         if (!push) {
1196                 return NT_STATUS_NO_MEMORY;
1197         }       
1198
1199         ndr_err = ndr_push(push, NDR_IN, st);
1200         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1202                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1203                                          "failed input validation push - %s",
1204                                          nt_errstr(status));
1205                 return ndr_map_error2ntstatus(ndr_err);
1206         }
1207
1208         blob2 = ndr_push_blob(push);
1209
1210         if (data_blob_cmp(&blob, &blob2) != 0) {
1211                 DEBUG(3,("original:\n"));
1212                 dump_data(3, blob.data, blob.length);
1213                 DEBUG(3,("secondary:\n"));
1214                 dump_data(3, blob2.data, blob2.length);
1215                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216                                          "failed input validation blobs doesn't match");
1217                 return ndr_map_error2ntstatus(ndr_err);
1218         }
1219
1220         return NT_STATUS_OK;
1221 }
1222
1223 /*
1224   this is a paranoid NDR input validator. For every packet we pull
1225   from the wire we push it back again then pull and push it
1226   again. Then we compare the raw NDR data for that to the NDR we
1227   initially generated. If they don't match then we know we must have a
1228   bug in either the pull or push side of our code
1229 */
1230 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1231                                         struct ndr_pull *pull_in,
1232                                         void *struct_ptr,
1233                                         size_t struct_size,
1234                                         ndr_push_flags_fn_t ndr_push,
1235                                         ndr_pull_flags_fn_t ndr_pull,
1236                                         ndr_print_function_t ndr_print)
1237 {
1238         void *st;
1239         struct ndr_pull *pull;
1240         struct ndr_push *push;
1241         DATA_BLOB blob, blob2;
1242         TALLOC_CTX *mem_ctx = pull_in;
1243         char *s1, *s2;
1244         enum ndr_err_code ndr_err;
1245
1246         st = talloc_size(mem_ctx, struct_size);
1247         if (!st) {
1248                 return NT_STATUS_NO_MEMORY;
1249         }
1250         memcpy(st, struct_ptr, struct_size);
1251
1252         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1253         if (!push) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }       
1256
1257         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1258         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1259                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1260                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1261                                          "failed output validation push - %s",
1262                                          nt_errstr(status));
1263                 return ndr_map_error2ntstatus(ndr_err);
1264         }
1265
1266         blob = ndr_push_blob(push);
1267
1268         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1269         if (!pull) {
1270                 return NT_STATUS_NO_MEMORY;
1271         }
1272
1273         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1274         ndr_err = ndr_pull(pull, NDR_OUT, st);
1275         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1276                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1277                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1278                                          "failed output validation pull - %s",
1279                                          nt_errstr(status));
1280                 return ndr_map_error2ntstatus(ndr_err);
1281         }
1282
1283         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1284         if (!push) {
1285                 return NT_STATUS_NO_MEMORY;
1286         }       
1287
1288         ndr_err = ndr_push(push, NDR_OUT, st);
1289         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1290                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1291                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1292                                          "failed output validation push2 - %s",
1293                                          nt_errstr(status));
1294                 return ndr_map_error2ntstatus(ndr_err);
1295         }
1296
1297         blob2 = ndr_push_blob(push);
1298
1299         if (data_blob_cmp(&blob, &blob2) != 0) {
1300                 DEBUG(3,("original:\n"));
1301                 dump_data(3, blob.data, blob.length);
1302                 DEBUG(3,("secondary:\n"));
1303                 dump_data(3, blob2.data, blob2.length);
1304                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1305                                          "failed output validation blobs doesn't match");
1306                 return ndr_map_error2ntstatus(ndr_err);
1307         }
1308
1309         /* this checks the printed forms of the two structures, which effectively
1310            tests all of the value() attributes */
1311         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1312                                        NDR_OUT, struct_ptr);
1313         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1314                                        NDR_OUT, st);
1315         if (strcmp(s1, s2) != 0) {
1316 #if 1
1317                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1318 #else
1319                 /* this is sometimes useful */
1320                 printf("VALIDATE ERROR\n");
1321                 file_save("wire.dat", s1, strlen(s1));
1322                 file_save("gen.dat", s2, strlen(s2));
1323                 system("diff -u wire.dat gen.dat");
1324 #endif
1325                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1326                                          "failed output validation strings doesn't match");
1327                 return ndr_map_error2ntstatus(ndr_err);
1328         }
1329
1330         return NT_STATUS_OK;
1331 }
1332
1333
1334 /**
1335  send a rpc request given a dcerpc_call structure 
1336  */
1337 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1338                                                 const struct GUID *object,
1339                                                 const struct ndr_interface_table *table,
1340                                                 uint32_t opnum, 
1341                                                 TALLOC_CTX *mem_ctx, 
1342                                                 void *r)
1343 {
1344         const struct ndr_interface_call *call;
1345         struct ndr_push *push;
1346         NTSTATUS status;
1347         DATA_BLOB request;
1348         struct rpc_request *req;
1349         enum ndr_err_code ndr_err;
1350
1351         call = &table->calls[opnum];
1352
1353         /* setup for a ndr_push_* call */
1354         push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1355         if (!push) {
1356                 return NULL;
1357         }
1358
1359         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1360                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1361         }
1362
1363         /* push the structure into a blob */
1364         ndr_err = call->ndr_push(push, NDR_IN, r);
1365         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1366                 status = ndr_map_error2ntstatus(ndr_err);
1367                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1368                          nt_errstr(status)));
1369                 talloc_free(push);
1370                 return NULL;
1371         }
1372
1373         /* retrieve the blob */
1374         request = ndr_push_blob(push);
1375
1376         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1377                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1378                                                 call->ndr_push, call->ndr_pull);
1379                 if (!NT_STATUS_IS_OK(status)) {
1380                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1381                                  nt_errstr(status)));
1382                         talloc_free(push);
1383                         return NULL;
1384                 }
1385         }
1386
1387         DEBUG(10,("rpc request data:\n"));
1388         dump_data(10, request.data, request.length);
1389
1390         /* make the actual dcerpc request */
1391         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1392                                   &request);
1393
1394         if (req != NULL) {
1395                 req->ndr.table = table;
1396                 req->ndr.opnum = opnum;
1397                 req->ndr.struct_ptr = r;
1398                 req->ndr.mem_ctx = mem_ctx;
1399         }
1400
1401         talloc_free(push);
1402
1403         return req;
1404 }
1405
1406 /*
1407   receive the answer from a dcerpc_ndr_request_send()
1408 */
1409 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1410 {
1411         struct dcerpc_pipe *p = req->p;
1412         NTSTATUS status;
1413         DATA_BLOB response;
1414         struct ndr_pull *pull;
1415         uint_t flags;
1416         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1417         void *r = req->ndr.struct_ptr;
1418         uint32_t opnum = req->ndr.opnum;
1419         const struct ndr_interface_table *table = req->ndr.table;
1420         const struct ndr_interface_call *call = &table->calls[opnum];
1421         enum ndr_err_code ndr_err;
1422
1423         /* make sure the recv code doesn't free the request, as we
1424            need to grab the flags element before it is freed */
1425         if (talloc_reference(p, req) == NULL) {
1426                 return NT_STATUS_NO_MEMORY;
1427         }
1428
1429         status = dcerpc_request_recv(req, mem_ctx, &response);
1430         if (!NT_STATUS_IS_OK(status)) {
1431                 talloc_unlink(p, req);
1432                 return status;
1433         }
1434
1435         flags = req->flags;
1436
1437         /* prepare for ndr_pull_* */
1438         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1439         if (!pull) {
1440                 talloc_unlink(p, req);
1441                 return NT_STATUS_NO_MEMORY;
1442         }
1443
1444         if (pull->data) {
1445                 pull->data = talloc_steal(pull, pull->data);
1446         }
1447         talloc_unlink(p, req);
1448
1449         if (flags & DCERPC_PULL_BIGENDIAN) {
1450                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1451         }
1452
1453         DEBUG(10,("rpc reply data:\n"));
1454         dump_data(10, pull->data, pull->data_size);
1455
1456         /* pull the structure from the blob */
1457         ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1458         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1459                 status = ndr_map_error2ntstatus(ndr_err);
1460                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1461                                   &response);
1462                 return status;
1463         }
1464
1465         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1466                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1467                                                  call->ndr_push, call->ndr_pull, 
1468                                                  call->ndr_print);
1469                 if (!NT_STATUS_IS_OK(status)) {
1470                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1471                                   &response);
1472                         return status;
1473                 }
1474         }
1475
1476         if (pull->offset != pull->data_size) {
1477                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1478                          pull->data_size - pull->offset));
1479                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1480                    but it turns out that early versions of NT
1481                    (specifically NT3.1) add junk onto the end of rpc
1482                    packets, so if we want to interoperate at all with
1483                    those versions then we need to ignore this error */
1484         }
1485
1486         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1487
1488         return NT_STATUS_OK;
1489 }
1490
1491
1492 /*
1493   a useful helper function for synchronous rpc requests 
1494
1495   this can be used when you have ndr push/pull functions in the
1496   standard format
1497 */
1498 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1499                             const struct GUID *object,
1500                             const struct ndr_interface_table *table,
1501                             uint32_t opnum, 
1502                             TALLOC_CTX *mem_ctx, 
1503                             void *r)
1504 {
1505         struct rpc_request *req;
1506
1507         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1508         if (req == NULL) {
1509                 return NT_STATUS_NO_MEMORY;
1510         }
1511
1512         return dcerpc_ndr_request_recv(req);
1513 }
1514
1515
1516 /*
1517   a useful function for retrieving the server name we connected to
1518 */
1519 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1520 {
1521         if (!p->conn->transport.target_hostname) {
1522                 if (!p->conn->transport.peer_name) {
1523                         return "";
1524                 }
1525                 return p->conn->transport.peer_name(p->conn);
1526         }
1527         return p->conn->transport.target_hostname(p->conn);
1528 }
1529
1530
1531 /*
1532   get the dcerpc auth_level for a open connection
1533 */
1534 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1535 {
1536         uint8_t auth_level;
1537
1538         if (c->flags & DCERPC_SEAL) {
1539                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1540         } else if (c->flags & DCERPC_SIGN) {
1541                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1542         } else if (c->flags & DCERPC_CONNECT) {
1543                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1544         } else {
1545                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1546         }
1547         return auth_level;
1548 }
1549
1550 /*
1551   Receive an alter reply from the transport
1552 */
1553 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1554                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1555 {
1556         struct composite_context *c;
1557         struct dcerpc_pipe *recv_pipe;
1558
1559         c = talloc_get_type(req->async.private_data, struct composite_context);
1560         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1561
1562         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1563             pkt->u.alter_resp.num_results == 1 &&
1564             pkt->u.alter_resp.ctx_list[0].result != 0) {
1565                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1566                          pkt->u.alter_resp.ctx_list[0].reason));
1567                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1568                 return;
1569         }
1570
1571         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1572             pkt->u.alter_resp.num_results == 0 ||
1573             pkt->u.alter_resp.ctx_list[0].result != 0) {
1574                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1575                 return;
1576         }
1577
1578         /* the alter_resp might contain a reply set of credentials */
1579         if (recv_pipe->conn->security_state.auth_info &&
1580             pkt->u.alter_resp.auth_info.length) {
1581                 enum ndr_err_code ndr_err;
1582                 ndr_err = ndr_pull_struct_blob(
1583                         &pkt->u.alter_resp.auth_info, recv_pipe,
1584                         NULL,
1585                         recv_pipe->conn->security_state.auth_info,
1586                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1587                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1588                         c->status = ndr_map_error2ntstatus(ndr_err);
1589                         if (!composite_is_ok(c)) return;
1590                 }
1591         }
1592
1593         composite_done(c);
1594 }
1595
1596 /* 
1597    send a dcerpc alter_context request
1598 */
1599 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1600                                                     TALLOC_CTX *mem_ctx,
1601                                                     const struct ndr_syntax_id *syntax,
1602                                                     const struct ndr_syntax_id *transfer_syntax)
1603 {
1604         struct composite_context *c;
1605         struct ncacn_packet pkt;
1606         DATA_BLOB blob;
1607         struct rpc_request *req;
1608
1609         c = composite_create(mem_ctx, p->conn->event_ctx);
1610         if (c == NULL) return NULL;
1611
1612         c->private_data = p;
1613
1614         p->syntax = *syntax;
1615         p->transfer_syntax = *transfer_syntax;
1616
1617         init_ncacn_hdr(p->conn, &pkt);
1618
1619         pkt.ptype = DCERPC_PKT_ALTER;
1620         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1621         pkt.call_id = p->conn->call_id;
1622         pkt.auth_length = 0;
1623
1624         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1625                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1626         }
1627
1628         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1629                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1630         }
1631
1632         pkt.u.alter.max_xmit_frag = 5840;
1633         pkt.u.alter.max_recv_frag = 5840;
1634         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1635         pkt.u.alter.num_contexts = 1;
1636         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1637         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1638         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1639         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1640         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1641         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1642         pkt.u.alter.auth_info = data_blob(NULL, 0);
1643
1644         /* construct the NDR form of the packet */
1645         c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1646                                     p->conn->security_state.auth_info);
1647         if (!composite_is_ok(c)) return c;
1648
1649         p->conn->transport.recv_data = dcerpc_recv_data;
1650
1651         /*
1652          * we allocate a dcerpc_request so we can be in the same
1653          * request queue as normal requests
1654          */
1655         req = talloc_zero(c, struct rpc_request);
1656         if (composite_nomem(req, c)) return c;
1657
1658         req->state = RPC_REQUEST_PENDING;
1659         req->call_id = pkt.call_id;
1660         req->async.private_data = c;
1661         req->async.callback = dcerpc_composite_fail;
1662         req->p = p;
1663         req->recv_handler = dcerpc_alter_recv_handler;
1664         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1665         talloc_set_destructor(req, dcerpc_req_dequeue);
1666
1667         c->status = p->conn->transport.send_request(p->conn, &blob, true);
1668         if (!composite_is_ok(c)) return c;
1669
1670         event_add_timed(c->event_ctx, req,
1671                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1672                         dcerpc_timeout_handler, req);
1673
1674         return c;
1675 }
1676
1677 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1678 {
1679         NTSTATUS result = composite_wait(ctx);
1680         talloc_free(ctx);
1681         return result;
1682 }
1683
1684 /* 
1685    send a dcerpc alter_context request
1686 */
1687 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1688                               TALLOC_CTX *mem_ctx,
1689                               const struct ndr_syntax_id *syntax,
1690                               const struct ndr_syntax_id *transfer_syntax)
1691 {
1692         struct composite_context *creq;
1693         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1694         return dcerpc_alter_context_recv(creq);
1695 }