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