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