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