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