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