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