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