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