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