dcerpc.idl: add DCERPC_AUTH_TRAILER_LENGTH
[abartlet/samba.git/.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                                          struct ncacn_packet *pkt)
338 {
339         NTSTATUS status;
340         struct ndr_push *ndr;
341         DATA_BLOB creds2;
342         size_t payload_length;
343         enum ndr_err_code ndr_err;
344
345         /* non-signed packets are simpler */
346         if (!c->security_state.auth_info || 
347             !c->security_state.generic_state) {
348                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
349         }
350
351         ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
352         if (!ndr) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
357                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
358         }
359
360         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
361                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
362         }
363
364         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
365         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
366                 return ndr_map_error2ntstatus(ndr_err);
367         }
368         status = NT_STATUS_OK;
369
370         /* pad to 16 byte multiple in the payload portion of the
371            packet. This matches what w2k3 does */
372         c->security_state.auth_info->auth_pad_length = 
373                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
374         ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
375
376         payload_length = pkt->u.request.stub_and_verifier.length + 
377                 c->security_state.auth_info->auth_pad_length;
378
379         /* sign or seal the packet */
380         switch (c->security_state.auth_info->auth_level) {
381         case DCERPC_AUTH_LEVEL_PRIVACY:
382         case DCERPC_AUTH_LEVEL_INTEGRITY:
383                 /* We hope this length is accruate.  If must be if the
384                  * GENSEC mech does AEAD signing of the packet
385                  * headers */
386                 c->security_state.auth_info->credentials
387                         = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, 
388                                                                           payload_length));
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
1046         req = c->request_queue;
1047         if (req == NULL) {
1048                 return;
1049         }
1050
1051         p = req->p;
1052         stub_data = &req->request_data;
1053
1054         if (!req->async_call && (c->pending != NULL)) {
1055                 return;
1056         }
1057
1058         DLIST_REMOVE(c->request_queue, req);
1059         DLIST_ADD(c->pending, req);
1060         req->state = RPC_REQUEST_PENDING;
1061
1062         init_ncacn_hdr(p->conn, &pkt);
1063
1064         remaining = stub_data->length;
1065
1066         /* we can write a full max_recv_frag size, minus the dcerpc
1067            request header size */
1068         chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1069
1070         pkt.ptype = DCERPC_PKT_REQUEST;
1071         pkt.call_id = req->call_id;
1072         pkt.auth_length = 0;
1073         pkt.pfc_flags = 0;
1074         pkt.u.request.alloc_hint = remaining;
1075         pkt.u.request.context_id = p->context_id;
1076         pkt.u.request.opnum = req->opnum;
1077
1078         if (req->object) {
1079                 pkt.u.request.object.object = *req->object;
1080                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1081                 chunk_size -= ndr_size_GUID(req->object,0);
1082         }
1083
1084         /* we send a series of pdus without waiting for a reply */
1085         while (remaining > 0 || first_packet) {
1086                 uint32_t chunk = MIN(chunk_size, remaining);
1087                 bool last_frag = false;
1088
1089                 first_packet = false;
1090                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1091
1092                 if (remaining == stub_data->length) {
1093                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1094                 }
1095                 if (chunk == remaining) {
1096                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1097                         last_frag = true;
1098                 }
1099
1100                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1101                         (stub_data->length - remaining);
1102                 pkt.u.request.stub_and_verifier.length = chunk;
1103
1104                 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1105                 if (!NT_STATUS_IS_OK(req->status)) {
1106                         req->state = RPC_REQUEST_DONE;
1107                         DLIST_REMOVE(p->conn->pending, req);
1108                         return;
1109                 }
1110                 
1111                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1112                 if (!NT_STATUS_IS_OK(req->status)) {
1113                         req->state = RPC_REQUEST_DONE;
1114                         DLIST_REMOVE(p->conn->pending, req);
1115                         return;
1116                 }               
1117
1118                 remaining -= chunk;
1119         }
1120 }
1121
1122 /*
1123   return the event context for a dcerpc pipe
1124   used by callers who wish to operate asynchronously
1125 */
1126 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1127 {
1128         return p->conn->event_ctx;
1129 }
1130
1131
1132
1133 /*
1134   perform the receive side of a async dcerpc request
1135 */
1136 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1137                              TALLOC_CTX *mem_ctx,
1138                              DATA_BLOB *stub_data)
1139 {
1140         NTSTATUS status;
1141
1142         while (req->state != RPC_REQUEST_DONE) {
1143                 struct event_context *ctx = dcerpc_event_context(req->p);
1144                 if (event_loop_once(ctx) != 0) {
1145                         return NT_STATUS_CONNECTION_DISCONNECTED;
1146                 }
1147         }
1148         *stub_data = req->payload;
1149         status = req->status;
1150         if (stub_data->data) {
1151                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1152         }
1153         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1154                 req->p->last_fault_code = req->fault_code;
1155         }
1156         talloc_free(req);
1157         return status;
1158 }
1159
1160 /*
1161   perform a full request/response pair on a dcerpc pipe
1162 */
1163 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1164                         struct GUID *object,
1165                         uint16_t opnum,
1166                         bool async,
1167                         TALLOC_CTX *mem_ctx,
1168                         DATA_BLOB *stub_data_in,
1169                         DATA_BLOB *stub_data_out)
1170 {
1171         struct rpc_request *req;
1172
1173         req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1174         if (req == NULL) {
1175                 return NT_STATUS_NO_MEMORY;
1176         }
1177
1178         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1179 }
1180
1181
1182 /*
1183   this is a paranoid NDR validator. For every packet we push onto the wire
1184   we pull it back again, then push it again. Then we compare the raw NDR data
1185   for that to the NDR we initially generated. If they don't match then we know
1186   we must have a bug in either the pull or push side of our code
1187 */
1188 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1189                                        TALLOC_CTX *mem_ctx,
1190                                        DATA_BLOB blob,
1191                                        size_t struct_size,
1192                                        ndr_push_flags_fn_t ndr_push,
1193                                        ndr_pull_flags_fn_t ndr_pull)
1194 {
1195         void *st;
1196         struct ndr_pull *pull;
1197         struct ndr_push *push;
1198         DATA_BLOB blob2;
1199         enum ndr_err_code ndr_err;
1200
1201         st = talloc_size(mem_ctx, struct_size);
1202         if (!st) {
1203                 return NT_STATUS_NO_MEMORY;
1204         }
1205
1206         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1207         if (!pull) {
1208                 return NT_STATUS_NO_MEMORY;
1209         }
1210         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1211
1212         ndr_err = ndr_pull(pull, NDR_IN, st);
1213         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1214                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1215                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216                                          "failed input validation pull - %s",
1217                                          nt_errstr(status));
1218                 return ndr_map_error2ntstatus(ndr_err);
1219         }
1220
1221         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1222         if (!push) {
1223                 return NT_STATUS_NO_MEMORY;
1224         }       
1225
1226         ndr_err = ndr_push(push, NDR_IN, st);
1227         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1228                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1229                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1230                                          "failed input validation push - %s",
1231                                          nt_errstr(status));
1232                 return ndr_map_error2ntstatus(ndr_err);
1233         }
1234
1235         blob2 = ndr_push_blob(push);
1236
1237         if (data_blob_cmp(&blob, &blob2) != 0) {
1238                 DEBUG(3,("original:\n"));
1239                 dump_data(3, blob.data, blob.length);
1240                 DEBUG(3,("secondary:\n"));
1241                 dump_data(3, blob2.data, blob2.length);
1242                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1243                                          "failed input validation blobs doesn't match");
1244                 return ndr_map_error2ntstatus(ndr_err);
1245         }
1246
1247         return NT_STATUS_OK;
1248 }
1249
1250 /*
1251   this is a paranoid NDR input validator. For every packet we pull
1252   from the wire we push it back again then pull and push it
1253   again. Then we compare the raw NDR data for that to the NDR we
1254   initially generated. If they don't match then we know we must have a
1255   bug in either the pull or push side of our code
1256 */
1257 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1258                                         struct ndr_pull *pull_in,
1259                                         void *struct_ptr,
1260                                         size_t struct_size,
1261                                         ndr_push_flags_fn_t ndr_push,
1262                                         ndr_pull_flags_fn_t ndr_pull,
1263                                         ndr_print_function_t ndr_print)
1264 {
1265         void *st;
1266         struct ndr_pull *pull;
1267         struct ndr_push *push;
1268         DATA_BLOB blob, blob2;
1269         TALLOC_CTX *mem_ctx = pull_in;
1270         char *s1, *s2;
1271         enum ndr_err_code ndr_err;
1272
1273         st = talloc_size(mem_ctx, struct_size);
1274         if (!st) {
1275                 return NT_STATUS_NO_MEMORY;
1276         }
1277         memcpy(st, struct_ptr, struct_size);
1278
1279         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1280         if (!push) {
1281                 return NT_STATUS_NO_MEMORY;
1282         }       
1283
1284         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1285         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1286                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1287                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1288                                          "failed output validation push - %s",
1289                                          nt_errstr(status));
1290                 return ndr_map_error2ntstatus(ndr_err);
1291         }
1292
1293         blob = ndr_push_blob(push);
1294
1295         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1296         if (!pull) {
1297                 return NT_STATUS_NO_MEMORY;
1298         }
1299
1300         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1301         ndr_err = ndr_pull(pull, NDR_OUT, st);
1302         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1303                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1304                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1305                                          "failed output validation pull - %s",
1306                                          nt_errstr(status));
1307                 return ndr_map_error2ntstatus(ndr_err);
1308         }
1309
1310         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1311         if (!push) {
1312                 return NT_STATUS_NO_MEMORY;
1313         }       
1314
1315         ndr_err = ndr_push(push, NDR_OUT, st);
1316         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1317                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1318                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1319                                          "failed output validation push2 - %s",
1320                                          nt_errstr(status));
1321                 return ndr_map_error2ntstatus(ndr_err);
1322         }
1323
1324         blob2 = ndr_push_blob(push);
1325
1326         if (data_blob_cmp(&blob, &blob2) != 0) {
1327                 DEBUG(3,("original:\n"));
1328                 dump_data(3, blob.data, blob.length);
1329                 DEBUG(3,("secondary:\n"));
1330                 dump_data(3, blob2.data, blob2.length);
1331                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1332                                          "failed output validation blobs doesn't match");
1333                 return ndr_map_error2ntstatus(ndr_err);
1334         }
1335
1336         /* this checks the printed forms of the two structures, which effectively
1337            tests all of the value() attributes */
1338         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1339                                        NDR_OUT, struct_ptr);
1340         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1341                                        NDR_OUT, st);
1342         if (strcmp(s1, s2) != 0) {
1343 #if 1
1344                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1345 #else
1346                 /* this is sometimes useful */
1347                 printf("VALIDATE ERROR\n");
1348                 file_save("wire.dat", s1, strlen(s1));
1349                 file_save("gen.dat", s2, strlen(s2));
1350                 system("diff -u wire.dat gen.dat");
1351 #endif
1352                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1353                                          "failed output validation strings doesn't match");
1354                 return ndr_map_error2ntstatus(ndr_err);
1355         }
1356
1357         return NT_STATUS_OK;
1358 }
1359
1360
1361 /**
1362  send a rpc request given a dcerpc_call structure 
1363  */
1364 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1365                                                 const struct GUID *object,
1366                                                 const struct ndr_interface_table *table,
1367                                                 uint32_t opnum, 
1368                                                 TALLOC_CTX *mem_ctx, 
1369                                                 void *r)
1370 {
1371         const struct ndr_interface_call *call;
1372         struct ndr_push *push;
1373         NTSTATUS status;
1374         DATA_BLOB request;
1375         struct rpc_request *req;
1376         enum ndr_err_code ndr_err;
1377
1378         call = &table->calls[opnum];
1379
1380         /* setup for a ndr_push_* call */
1381         push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1382         if (!push) {
1383                 return NULL;
1384         }
1385
1386         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1387                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1388         }
1389
1390         /* push the structure into a blob */
1391         ndr_err = call->ndr_push(push, NDR_IN, r);
1392         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1393                 status = ndr_map_error2ntstatus(ndr_err);
1394                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1395                          nt_errstr(status)));
1396                 talloc_free(push);
1397                 return NULL;
1398         }
1399
1400         /* retrieve the blob */
1401         request = ndr_push_blob(push);
1402
1403         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1404                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1405                                                 call->ndr_push, call->ndr_pull);
1406                 if (!NT_STATUS_IS_OK(status)) {
1407                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1408                                  nt_errstr(status)));
1409                         talloc_free(push);
1410                         return NULL;
1411                 }
1412         }
1413
1414         DEBUG(10,("rpc request data:\n"));
1415         dump_data(10, request.data, request.length);
1416
1417         /* make the actual dcerpc request */
1418         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1419                                   &request);
1420
1421         if (req != NULL) {
1422                 req->ndr.table = table;
1423                 req->ndr.opnum = opnum;
1424                 req->ndr.struct_ptr = r;
1425                 req->ndr.mem_ctx = mem_ctx;
1426         }
1427
1428         talloc_free(push);
1429
1430         return req;
1431 }
1432
1433 /*
1434   receive the answer from a dcerpc_ndr_request_send()
1435 */
1436 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1437 {
1438         struct dcerpc_pipe *p = req->p;
1439         NTSTATUS status;
1440         DATA_BLOB response;
1441         struct ndr_pull *pull;
1442         uint_t flags;
1443         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1444         void *r = req->ndr.struct_ptr;
1445         uint32_t opnum = req->ndr.opnum;
1446         const struct ndr_interface_table *table = req->ndr.table;
1447         const struct ndr_interface_call *call = &table->calls[opnum];
1448         enum ndr_err_code ndr_err;
1449
1450         /* make sure the recv code doesn't free the request, as we
1451            need to grab the flags element before it is freed */
1452         if (talloc_reference(p, req) == NULL) {
1453                 return NT_STATUS_NO_MEMORY;
1454         }
1455
1456         status = dcerpc_request_recv(req, mem_ctx, &response);
1457         if (!NT_STATUS_IS_OK(status)) {
1458                 talloc_unlink(p, req);
1459                 return status;
1460         }
1461
1462         flags = req->flags;
1463
1464         /* prepare for ndr_pull_* */
1465         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1466         if (!pull) {
1467                 talloc_unlink(p, req);
1468                 return NT_STATUS_NO_MEMORY;
1469         }
1470
1471         if (pull->data) {
1472                 pull->data = talloc_steal(pull, pull->data);
1473         }
1474         talloc_unlink(p, req);
1475
1476         if (flags & DCERPC_PULL_BIGENDIAN) {
1477                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1478         }
1479
1480         DEBUG(10,("rpc reply data:\n"));
1481         dump_data(10, pull->data, pull->data_size);
1482
1483         /* pull the structure from the blob */
1484         ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1485         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1486                 status = ndr_map_error2ntstatus(ndr_err);
1487                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1488                                   &response);
1489                 return status;
1490         }
1491
1492         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1493                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1494                                                  call->ndr_push, call->ndr_pull, 
1495                                                  call->ndr_print);
1496                 if (!NT_STATUS_IS_OK(status)) {
1497                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1498                                   &response);
1499                         return status;
1500                 }
1501         }
1502
1503         if (pull->offset != pull->data_size) {
1504                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1505                          pull->data_size - pull->offset));
1506                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1507                    but it turns out that early versions of NT
1508                    (specifically NT3.1) add junk onto the end of rpc
1509                    packets, so if we want to interoperate at all with
1510                    those versions then we need to ignore this error */
1511         }
1512
1513         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1514
1515         return NT_STATUS_OK;
1516 }
1517
1518
1519 /*
1520   a useful helper function for synchronous rpc requests 
1521
1522   this can be used when you have ndr push/pull functions in the
1523   standard format
1524 */
1525 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1526                             const struct GUID *object,
1527                             const struct ndr_interface_table *table,
1528                             uint32_t opnum, 
1529                             TALLOC_CTX *mem_ctx, 
1530                             void *r)
1531 {
1532         struct rpc_request *req;
1533
1534         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1535         if (req == NULL) {
1536                 return NT_STATUS_NO_MEMORY;
1537         }
1538
1539         return dcerpc_ndr_request_recv(req);
1540 }
1541
1542
1543 /*
1544   a useful function for retrieving the server name we connected to
1545 */
1546 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1547 {
1548         if (!p->conn->transport.target_hostname) {
1549                 if (!p->conn->transport.peer_name) {
1550                         return "";
1551                 }
1552                 return p->conn->transport.peer_name(p->conn);
1553         }
1554         return p->conn->transport.target_hostname(p->conn);
1555 }
1556
1557
1558 /*
1559   get the dcerpc auth_level for a open connection
1560 */
1561 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1562 {
1563         uint8_t auth_level;
1564
1565         if (c->flags & DCERPC_SEAL) {
1566                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1567         } else if (c->flags & DCERPC_SIGN) {
1568                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1569         } else if (c->flags & DCERPC_CONNECT) {
1570                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1571         } else {
1572                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1573         }
1574         return auth_level;
1575 }
1576
1577 /*
1578   Receive an alter reply from the transport
1579 */
1580 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1581                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1582 {
1583         struct composite_context *c;
1584         struct dcerpc_pipe *recv_pipe;
1585
1586         c = talloc_get_type(req->async.private_data, struct composite_context);
1587         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1588
1589         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1590             pkt->u.alter_resp.num_results == 1 &&
1591             pkt->u.alter_resp.ctx_list[0].result != 0) {
1592                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1593                          pkt->u.alter_resp.ctx_list[0].reason));
1594                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1595                 return;
1596         }
1597
1598         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1599             pkt->u.alter_resp.num_results == 0 ||
1600             pkt->u.alter_resp.ctx_list[0].result != 0) {
1601                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1602                 return;
1603         }
1604
1605         /* the alter_resp might contain a reply set of credentials */
1606         if (recv_pipe->conn->security_state.auth_info &&
1607             pkt->u.alter_resp.auth_info.length) {
1608                 enum ndr_err_code ndr_err;
1609                 ndr_err = ndr_pull_struct_blob(
1610                         &pkt->u.alter_resp.auth_info, recv_pipe,
1611                         NULL,
1612                         recv_pipe->conn->security_state.auth_info,
1613                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1614                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1615                         c->status = ndr_map_error2ntstatus(ndr_err);
1616                         if (!composite_is_ok(c)) return;
1617                 }
1618         }
1619
1620         composite_done(c);
1621 }
1622
1623 /* 
1624    send a dcerpc alter_context request
1625 */
1626 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1627                                                     TALLOC_CTX *mem_ctx,
1628                                                     const struct ndr_syntax_id *syntax,
1629                                                     const struct ndr_syntax_id *transfer_syntax)
1630 {
1631         struct composite_context *c;
1632         struct ncacn_packet pkt;
1633         DATA_BLOB blob;
1634         struct rpc_request *req;
1635
1636         c = composite_create(mem_ctx, p->conn->event_ctx);
1637         if (c == NULL) return NULL;
1638
1639         c->private_data = p;
1640
1641         p->syntax = *syntax;
1642         p->transfer_syntax = *transfer_syntax;
1643
1644         init_ncacn_hdr(p->conn, &pkt);
1645
1646         pkt.ptype = DCERPC_PKT_ALTER;
1647         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1648         pkt.call_id = p->conn->call_id;
1649         pkt.auth_length = 0;
1650
1651         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1652                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1653         }
1654
1655         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1656                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1657         }
1658
1659         pkt.u.alter.max_xmit_frag = 5840;
1660         pkt.u.alter.max_recv_frag = 5840;
1661         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1662         pkt.u.alter.num_contexts = 1;
1663         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1664         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1665         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1666         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1667         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1668         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1669         pkt.u.alter.auth_info = data_blob(NULL, 0);
1670
1671         /* construct the NDR form of the packet */
1672         c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1673                                     p->conn->security_state.auth_info);
1674         if (!composite_is_ok(c)) return c;
1675
1676         p->conn->transport.recv_data = dcerpc_recv_data;
1677
1678         /*
1679          * we allocate a dcerpc_request so we can be in the same
1680          * request queue as normal requests
1681          */
1682         req = talloc_zero(c, struct rpc_request);
1683         if (composite_nomem(req, c)) return c;
1684
1685         req->state = RPC_REQUEST_PENDING;
1686         req->call_id = pkt.call_id;
1687         req->async.private_data = c;
1688         req->async.callback = dcerpc_composite_fail;
1689         req->p = p;
1690         req->recv_handler = dcerpc_alter_recv_handler;
1691         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1692         talloc_set_destructor(req, dcerpc_req_dequeue);
1693
1694         c->status = p->conn->transport.send_request(p->conn, &blob, true);
1695         if (!composite_is_ok(c)) return c;
1696
1697         event_add_timed(c->event_ctx, req,
1698                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1699                         dcerpc_timeout_handler, req);
1700
1701         return c;
1702 }
1703
1704 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1705 {
1706         NTSTATUS result = composite_wait(ctx);
1707         talloc_free(ctx);
1708         return result;
1709 }
1710
1711 /* 
1712    send a dcerpc alter_context request
1713 */
1714 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1715                               TALLOC_CTX *mem_ctx,
1716                               const struct ndr_syntax_id *syntax,
1717                               const struct ndr_syntax_id *transfer_syntax)
1718 {
1719         struct composite_context *creq;
1720         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1721         return dcerpc_alter_context_recv(creq);
1722 }