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