r12620: Get rid of automatically generated lists of init functions of subsystems.
[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                                         TALLOC_CTX *mem_ctx,
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 {
1225         void *st;
1226         struct ndr_pull *pull;
1227         struct ndr_push *push;
1228         NTSTATUS status;
1229         DATA_BLOB blob, blob2;
1230
1231         st = talloc_size(mem_ctx, struct_size);
1232         if (!st) {
1233                 return NT_STATUS_NO_MEMORY;
1234         }
1235         memcpy(st, struct_ptr, struct_size);
1236
1237         push = ndr_push_init_ctx(mem_ctx);
1238         if (!push) {
1239                 return NT_STATUS_NO_MEMORY;
1240         }       
1241
1242         status = ndr_push(push, NDR_OUT, struct_ptr);
1243         if (!NT_STATUS_IS_OK(status)) {
1244                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1245                                       "failed output validation push - %s",
1246                                       nt_errstr(status));
1247         }
1248
1249         blob = ndr_push_blob(push);
1250
1251         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1252         if (!pull) {
1253                 return NT_STATUS_NO_MEMORY;
1254         }
1255
1256         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1257         status = ndr_pull(pull, NDR_OUT, st);
1258         if (!NT_STATUS_IS_OK(status)) {
1259                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1260                                       "failed output validation pull - %s",
1261                                       nt_errstr(status));
1262         }
1263
1264         push = ndr_push_init_ctx(mem_ctx);
1265         if (!push) {
1266                 return NT_STATUS_NO_MEMORY;
1267         }       
1268
1269         status = ndr_push(push, NDR_OUT, st);
1270         if (!NT_STATUS_IS_OK(status)) {
1271                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1272                                       "failed output validation push2 - %s",
1273                                       nt_errstr(status));
1274         }
1275
1276         blob2 = ndr_push_blob(push);
1277
1278         if (!data_blob_equal(&blob, &blob2)) {
1279                 DEBUG(3,("original:\n"));
1280                 dump_data(3, blob.data, blob.length);
1281                 DEBUG(3,("secondary:\n"));
1282                 dump_data(3, blob2.data, blob2.length);
1283                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1284                                       "failed output validation data - %s",
1285                                       nt_errstr(status));
1286         }
1287
1288         return NT_STATUS_OK;
1289 }
1290
1291
1292 /*
1293  send a rpc request given a dcerpc_call structure 
1294  */
1295 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1296                                                 const struct GUID *object,
1297                                                 const struct dcerpc_interface_table *table,
1298                                                 uint32_t opnum, 
1299                                                 TALLOC_CTX *mem_ctx, 
1300                                                 void *r)
1301 {
1302         const struct dcerpc_interface_call *call;
1303         struct ndr_push *push;
1304         NTSTATUS status;
1305         DATA_BLOB request;
1306         struct rpc_request *req;
1307
1308         call = &table->calls[opnum];
1309
1310         /* setup for a ndr_push_* call */
1311         push = ndr_push_init_ctx(mem_ctx);
1312         if (!push) {
1313                 return NULL;
1314         }
1315
1316         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1317                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1318         }
1319
1320         /* push the structure into a blob */
1321         status = call->ndr_push(push, NDR_IN, r);
1322         if (!NT_STATUS_IS_OK(status)) {
1323                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1324                          nt_errstr(status)));
1325                 talloc_free(push);
1326                 return NULL;
1327         }
1328
1329         /* retrieve the blob */
1330         request = ndr_push_blob(push);
1331
1332         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1333                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1334                                                 call->ndr_push, call->ndr_pull);
1335                 if (!NT_STATUS_IS_OK(status)) {
1336                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1337                                  nt_errstr(status)));
1338                         talloc_free(push);
1339                         return NULL;
1340                 }
1341         }
1342
1343         DEBUG(10,("rpc request data:\n"));
1344         dump_data(10, request.data, request.length);
1345
1346         /* make the actual dcerpc request */
1347         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1348                                   &request);
1349
1350         if (req != NULL) {
1351                 req->ndr.table = table;
1352                 req->ndr.opnum = opnum;
1353                 req->ndr.struct_ptr = r;
1354                 req->ndr.mem_ctx = mem_ctx;
1355         }
1356
1357         talloc_free(push);
1358
1359         return req;
1360 }
1361
1362 /*
1363   receive the answer from a dcerpc_ndr_request_send()
1364 */
1365 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1366 {
1367         struct dcerpc_pipe *p = req->p;
1368         NTSTATUS status;
1369         DATA_BLOB response;
1370         struct ndr_pull *pull;
1371         uint_t flags;
1372         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1373         void *r = req->ndr.struct_ptr;
1374         uint32_t opnum = req->ndr.opnum;
1375         const struct dcerpc_interface_table *table = req->ndr.table;
1376         const struct dcerpc_interface_call *call = &table->calls[opnum];
1377
1378         /* make sure the recv code doesn't free the request, as we
1379            need to grab the flags element before it is freed */
1380         talloc_increase_ref_count(req);
1381
1382         status = dcerpc_request_recv(req, mem_ctx, &response);
1383         if (!NT_STATUS_IS_OK(status)) {
1384                 return status;
1385         }
1386
1387         flags = req->flags;
1388
1389         /* prepare for ndr_pull_* */
1390         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1391         if (!pull) {
1392                 talloc_free(req);
1393                 return NT_STATUS_NO_MEMORY;
1394         }
1395
1396         if (pull->data) {
1397                 pull->data = talloc_steal(pull, pull->data);
1398         }
1399         talloc_free(req);
1400
1401         if (flags & DCERPC_PULL_BIGENDIAN) {
1402                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1403         }
1404
1405         DEBUG(10,("rpc reply data:\n"));
1406         dump_data(10, pull->data, pull->data_size);
1407
1408         /* pull the structure from the blob */
1409         status = call->ndr_pull(pull, NDR_OUT, r);
1410         if (!NT_STATUS_IS_OK(status)) {
1411                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1412                                   &response);
1413                 return status;
1414         }
1415
1416         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1417                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1418                                                  call->ndr_push, call->ndr_pull);
1419                 if (!NT_STATUS_IS_OK(status)) {
1420                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1421                                   &response);
1422                         return status;
1423                 }
1424         }
1425
1426         if (pull->offset != pull->data_size) {
1427                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1428                          pull->data_size - pull->offset));
1429                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1430                    but it turns out that early versions of NT
1431                    (specifically NT3.1) add junk onto the end of rpc
1432                    packets, so if we want to interoperate at all with
1433                    those versions then we need to ignore this error */
1434         }
1435
1436         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1437
1438         return NT_STATUS_OK;
1439 }
1440
1441
1442 /*
1443   a useful helper function for synchronous rpc requests 
1444
1445   this can be used when you have ndr push/pull functions in the
1446   standard format
1447 */
1448 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1449                             const struct GUID *object,
1450                             const struct dcerpc_interface_table *table,
1451                             uint32_t opnum, 
1452                             TALLOC_CTX *mem_ctx, 
1453                             void *r)
1454 {
1455         struct rpc_request *req;
1456
1457         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1458         if (req == NULL) {
1459                 return NT_STATUS_NO_MEMORY;
1460         }
1461
1462         return dcerpc_ndr_request_recv(req);
1463 }
1464
1465
1466 /*
1467   a useful function for retrieving the server name we connected to
1468 */
1469 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1470 {
1471         if (!p->conn->transport.peer_name) {
1472                 return "";
1473         }
1474         return p->conn->transport.peer_name(p->conn);
1475 }
1476
1477
1478 /*
1479   get the dcerpc auth_level for a open connection
1480 */
1481 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1482 {
1483         uint8_t auth_level;
1484
1485         if (c->flags & DCERPC_SEAL) {
1486                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1487         } else if (c->flags & DCERPC_SIGN) {
1488                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1489         } else if (c->flags & DCERPC_CONNECT) {
1490                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1491         } else {
1492                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1493         }
1494         return auth_level;
1495 }
1496
1497 /*
1498   Receive an alter reply from the transport
1499 */
1500 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1501 {
1502         struct composite_context *c;
1503         struct dcerpc_pipe *pipe;
1504
1505         c = talloc_get_type(conn->alter_private, struct composite_context);
1506         pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1507
1508         /* mark the connection as not waiting for a alter context reply */
1509         conn->alter_private = NULL;
1510
1511         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1512             pkt->u.alter_resp.num_results == 1 &&
1513             pkt->u.alter_resp.ctx_list[0].result != 0) {
1514                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1515                          pkt->u.alter_resp.ctx_list[0].reason));
1516                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1517                 return;
1518         }
1519
1520         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1521             pkt->u.alter_resp.num_results == 0 ||
1522             pkt->u.alter_resp.ctx_list[0].result != 0) {
1523                 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1524                 return;
1525         }
1526
1527         /* the alter_resp might contain a reply set of credentials */
1528         if (pipe->conn->security_state.auth_info &&
1529             pkt->u.alter_resp.auth_info.length) {
1530                 c->status = ndr_pull_struct_blob(
1531                         &pkt->u.alter_resp.auth_info, pipe,
1532                         pipe->conn->security_state.auth_info,
1533                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1534                 if (!composite_is_ok(c)) return;
1535         }
1536
1537         composite_done(c);
1538 }
1539
1540 /* 
1541    send a dcerpc alter_context request
1542 */
1543 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1544                                                     TALLOC_CTX *mem_ctx,
1545                                                     const struct dcerpc_syntax_id *syntax,
1546                                                     const struct dcerpc_syntax_id *transfer_syntax)
1547 {
1548         struct composite_context *c;
1549         struct ncacn_packet pkt;
1550         DATA_BLOB blob;
1551
1552         c = talloc_zero(mem_ctx, struct composite_context);
1553         if (c == NULL) return NULL;
1554
1555         c->state = COMPOSITE_STATE_IN_PROGRESS;
1556         c->private_data = p;
1557         c->event_ctx = p->conn->event_ctx;
1558
1559         p->syntax = *syntax;
1560         p->transfer_syntax = *transfer_syntax;
1561
1562         init_ncacn_hdr(p->conn, &pkt);
1563
1564         pkt.ptype = DCERPC_PKT_ALTER;
1565         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1566         pkt.call_id = p->conn->call_id;
1567         pkt.auth_length = 0;
1568
1569         pkt.u.alter.max_xmit_frag = 5840;
1570         pkt.u.alter.max_recv_frag = 5840;
1571         pkt.u.alter.assoc_group_id = 0;
1572         pkt.u.alter.num_contexts = 1;
1573         pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1574                                                    struct dcerpc_ctx_list, 1);
1575         if (pkt.u.alter.ctx_list == NULL) {
1576                 c->status = NT_STATUS_NO_MEMORY;
1577                 goto failed;
1578         }
1579         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1580         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1581         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1582         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1583         pkt.u.alter.auth_info = data_blob(NULL, 0);
1584
1585         /* construct the NDR form of the packet */
1586         c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1587                                     p->conn->security_state.auth_info);
1588         if (!NT_STATUS_IS_OK(c->status)) {
1589                 goto failed;
1590         }
1591
1592         p->conn->transport.recv_data = dcerpc_recv_data;
1593         p->conn->alter_private = c;
1594
1595         c->status = p->conn->transport.send_request(p->conn, &blob, True);
1596         if (!NT_STATUS_IS_OK(c->status)) {
1597                 goto failed;
1598         }
1599
1600         event_add_timed(c->event_ctx, c,
1601                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1602                         bind_timeout_handler, c);
1603
1604         return c;
1605
1606  failed:
1607         composite_error(c, c->status);
1608         return c;
1609 }
1610
1611 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1612 {
1613         NTSTATUS result = composite_wait(ctx);
1614         talloc_free(ctx);
1615         return result;
1616 }
1617
1618 /* 
1619    send a dcerpc alter_context request
1620 */
1621 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1622                               TALLOC_CTX *mem_ctx,
1623                               const struct dcerpc_syntax_id *syntax,
1624                               const struct dcerpc_syntax_id *transfer_syntax)
1625 {
1626         struct composite_context *creq;
1627         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1628         return dcerpc_alter_context_recv(creq);
1629 }