Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
[kai/samba.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Jelmer Vernooij 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33
34 _PUBLIC_ NTSTATUS dcerpc_init(void)
35 {
36         gensec_init(global_loadparm);
37
38         return NT_STATUS_OK;
39 }
40
41 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
42 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
43
44 /* destroy a dcerpc connection */
45 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
46 {
47         if (conn->dead) {
48                 conn->free_skipped = true;
49                 return -1;
50         }
51         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
52         return 0;
53 }
54
55
56 /* initialise a dcerpc connection. 
57    the event context is optional
58 */
59 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
60                                                  struct event_context *ev,
61                                                  struct smb_iconv_convenience *ic)
62 {
63         struct dcerpc_connection *c;
64
65         c = talloc_zero(mem_ctx, struct dcerpc_connection);
66         if (!c) {
67                 return NULL;
68         }
69
70         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         /* the bind_ack might contain a reply set of credentials */
662         if (conn->security_state.auth_info &&
663             pkt->u.bind_ack.auth_info.length) {
664                 enum ndr_err_code ndr_err;
665                 ndr_err = ndr_pull_struct_blob(
666                         &pkt->u.bind_ack.auth_info, conn,
667                         NULL,
668                         conn->security_state.auth_info,
669                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
670                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
671                         c->status = ndr_map_error2ntstatus(ndr_err);
672                         if (!composite_is_ok(c)) return;
673                 }
674         }
675
676         req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
677
678         composite_done(c);
679 }
680
681 /*
682   handle timeouts of individual dcerpc requests
683 */
684 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te, 
685                                    struct timeval t, void *private)
686 {
687         struct rpc_request *req = talloc_get_type(private, struct rpc_request);
688
689         if (req->ignore_timeout) {
690                 dcerpc_req_dequeue(req);
691                 req->state = RPC_REQUEST_DONE;
692                 req->status = NT_STATUS_IO_TIMEOUT;
693                 if (req->async.callback) {
694                         req->async.callback(req);
695                 }
696                 return;
697         }
698
699         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
700 }
701
702 /*
703   send a async dcerpc bind request
704 */
705 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
706                                            TALLOC_CTX *mem_ctx,
707                                            const struct ndr_syntax_id *syntax,
708                                            const struct ndr_syntax_id *transfer_syntax)
709 {
710         struct composite_context *c;
711         struct ncacn_packet pkt;
712         DATA_BLOB blob;
713         struct rpc_request *req;
714
715         c = composite_create(mem_ctx,p->conn->event_ctx);
716         if (c == NULL) return NULL;
717
718         c->private_data = p;
719
720         p->syntax = *syntax;
721         p->transfer_syntax = *transfer_syntax;
722
723         init_ncacn_hdr(p->conn, &pkt);
724
725         pkt.ptype = DCERPC_PKT_BIND;
726         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
727         pkt.call_id = p->conn->call_id;
728         pkt.auth_length = 0;
729
730         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
731                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
732         }
733
734         pkt.u.bind.max_xmit_frag = 5840;
735         pkt.u.bind.max_recv_frag = 5840;
736         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
737         pkt.u.bind.num_contexts = 1;
738         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
739         if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
740         pkt.u.bind.ctx_list[0].context_id = p->context_id;
741         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
742         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
743         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
744         pkt.u.bind.auth_info = data_blob(NULL, 0);
745
746         /* construct the NDR form of the packet */
747         c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
748                                     p->conn->security_state.auth_info);
749         if (!composite_is_ok(c)) return c;
750
751         p->conn->transport.recv_data = dcerpc_recv_data;
752
753         /*
754          * we allocate a dcerpc_request so we can be in the same
755          * request queue as normal requests
756          */
757         req = talloc_zero(c, struct rpc_request);
758         if (composite_nomem(req, c)) return c;
759
760         req->state = RPC_REQUEST_PENDING;
761         req->call_id = pkt.call_id;
762         req->async.private_data = c;
763         req->async.callback = dcerpc_composite_fail;
764         req->p = p;
765         req->recv_handler = dcerpc_bind_recv_handler;
766         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
767         talloc_set_destructor(req, dcerpc_req_dequeue);
768
769         c->status = p->conn->transport.send_request(p->conn, &blob,
770                                                     true);
771         if (!composite_is_ok(c)) return c;
772
773         event_add_timed(c->event_ctx, req,
774                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
775                         dcerpc_timeout_handler, req);
776
777         return c;
778 }
779
780 /*
781   recv side of async dcerpc bind request
782 */
783 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
784 {
785         NTSTATUS result = composite_wait(ctx);
786         talloc_free(ctx);
787         return result;
788 }
789
790 /* 
791    perform a continued bind (and auth3)
792 */
793 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c, 
794                       TALLOC_CTX *mem_ctx)
795 {
796         struct ncacn_packet pkt;
797         NTSTATUS status;
798         DATA_BLOB blob;
799
800         init_ncacn_hdr(c, &pkt);
801
802         pkt.ptype = DCERPC_PKT_AUTH3;
803         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
804         pkt.call_id = next_call_id(c);
805         pkt.auth_length = 0;
806         pkt.u.auth3._pad = 0;
807         pkt.u.auth3.auth_info = data_blob(NULL, 0);
808
809         /* construct the NDR form of the packet */
810         status = ncacn_push_auth(&blob, mem_ctx, c->iconv_convenience, &pkt, c->security_state.auth_info);
811         if (!NT_STATUS_IS_OK(status)) {
812                 return status;
813         }
814
815         /* send it on its way */
816         status = c->transport.send_request(c, &blob, false);
817         if (!NT_STATUS_IS_OK(status)) {
818                 return status;
819         }
820
821         return NT_STATUS_OK;    
822 }
823
824
825 /*
826   process a fragment received from the transport layer during a
827   request
828
829   This function frees the data 
830 */
831 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
832                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
833 {
834         struct rpc_request *req;
835         uint_t length;
836         NTSTATUS status = NT_STATUS_OK;
837
838         /*
839           if this is an authenticated connection then parse and check
840           the auth info. We have to do this before finding the
841           matching packet, as the request structure might have been
842           removed due to a timeout, but if it has been we still need
843           to run the auth routines so that we don't get the sign/seal
844           info out of step with the server
845         */
846         if (c->security_state.auth_info && c->security_state.generic_state &&
847             pkt->ptype == DCERPC_PKT_RESPONSE) {
848                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
849         }
850
851         /* find the matching request */
852         for (req=c->pending;req;req=req->next) {
853                 if (pkt->call_id == req->call_id) break;
854         }
855
856 #if 0
857         /* useful for testing certain vendors RPC servers */
858         if (req == NULL && c->pending && pkt->call_id == 0) {
859                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
860                 req = c->pending;
861         }
862 #endif
863
864         if (req == NULL) {
865                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
866                 data_blob_free(raw_packet);
867                 return;
868         }
869
870         talloc_steal(req, raw_packet->data);
871
872         if (req->recv_handler != NULL) {
873                 dcerpc_req_dequeue(req);
874                 req->state = RPC_REQUEST_DONE;
875                 req->recv_handler(req, raw_packet, pkt);
876                 return;
877         }
878
879         if (pkt->ptype == DCERPC_PKT_FAULT) {
880                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
881                 req->fault_code = pkt->u.fault.status;
882                 req->status = NT_STATUS_NET_WRITE_FAULT;
883                 goto req_done;
884         }
885
886         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
887                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
888                          (int)pkt->ptype)); 
889                 req->fault_code = DCERPC_FAULT_OTHER;
890                 req->status = NT_STATUS_NET_WRITE_FAULT;
891                 goto req_done;
892         }
893
894         /* now check the status from the auth routines, and if it failed then fail
895            this request accordingly */
896         if (!NT_STATUS_IS_OK(status)) {
897                 req->status = status;
898                 goto req_done;
899         }
900
901         length = pkt->u.response.stub_and_verifier.length;
902
903         if (length > 0) {
904                 req->payload.data = talloc_realloc(req, 
905                                                    req->payload.data, 
906                                                    uint8_t,
907                                                    req->payload.length + length);
908                 if (!req->payload.data) {
909                         req->status = NT_STATUS_NO_MEMORY;
910                         goto req_done;
911                 }
912                 memcpy(req->payload.data+req->payload.length, 
913                        pkt->u.response.stub_and_verifier.data, length);
914                 req->payload.length += length;
915         }
916
917         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
918                 c->transport.send_read(c);
919                 return;
920         }
921
922         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
923                 req->flags |= DCERPC_PULL_BIGENDIAN;
924         } else {
925                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
926         }
927
928
929 req_done:
930         /* we've got the full payload */
931         req->state = RPC_REQUEST_DONE;
932         DLIST_REMOVE(c->pending, req);
933
934         if (c->request_queue != NULL) {
935                 /* We have to look at shipping further requests before calling
936                  * the async function, that one might close the pipe */
937                 dcerpc_ship_next_request(c);
938         }
939
940         if (req->async.callback) {
941                 req->async.callback(req);
942         }
943 }
944
945 /*
946   perform the send side of a async dcerpc request
947 */
948 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
949                                                const struct GUID *object,
950                                                uint16_t opnum,
951                                                bool async,
952                                                DATA_BLOB *stub_data)
953 {
954         struct rpc_request *req;
955
956         p->conn->transport.recv_data = dcerpc_recv_data;
957
958         req = talloc(p, struct rpc_request);
959         if (req == NULL) {
960                 return NULL;
961         }
962
963         req->p = p;
964         req->call_id = next_call_id(p->conn);
965         req->status = NT_STATUS_OK;
966         req->state = RPC_REQUEST_QUEUED;
967         req->payload = data_blob(NULL, 0);
968         req->flags = 0;
969         req->fault_code = 0;
970         req->async_call = async;
971         req->ignore_timeout = false;
972         req->async.callback = NULL;
973         req->async.private_data = NULL;
974         req->recv_handler = NULL;
975
976         if (object != NULL) {
977                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
978                 if (req->object == NULL) {
979                         talloc_free(req);
980                         return NULL;
981                 }
982         } else {
983                 req->object = NULL;
984         }
985
986         req->opnum = opnum;
987         req->request_data.length = stub_data->length;
988         req->request_data.data = talloc_reference(req, stub_data->data);
989         if (req->request_data.length && req->request_data.data == NULL) {
990                 return NULL;
991         }
992
993         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
994         talloc_set_destructor(req, dcerpc_req_dequeue);
995
996         dcerpc_ship_next_request(p->conn);
997
998         if (p->request_timeout) {
999                 event_add_timed(dcerpc_event_context(p), req, 
1000                                 timeval_current_ofs(p->request_timeout, 0), 
1001                                 dcerpc_timeout_handler, req);
1002         }
1003
1004         return req;
1005 }
1006
1007 /*
1008   Send a request using the transport
1009 */
1010
1011 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1012 {
1013         struct rpc_request *req;
1014         struct dcerpc_pipe *p;
1015         DATA_BLOB *stub_data;
1016         struct ncacn_packet pkt;
1017         DATA_BLOB blob;
1018         uint32_t remaining, chunk_size;
1019         bool first_packet = true;
1020
1021         req = c->request_queue;
1022         if (req == NULL) {
1023                 return;
1024         }
1025
1026         p = req->p;
1027         stub_data = &req->request_data;
1028
1029         if (!req->async_call && (c->pending != NULL)) {
1030                 return;
1031         }
1032
1033         DLIST_REMOVE(c->request_queue, req);
1034         DLIST_ADD(c->pending, req);
1035         req->state = RPC_REQUEST_PENDING;
1036
1037         init_ncacn_hdr(p->conn, &pkt);
1038
1039         remaining = stub_data->length;
1040
1041         /* we can write a full max_recv_frag size, minus the dcerpc
1042            request header size */
1043         chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1044
1045         pkt.ptype = DCERPC_PKT_REQUEST;
1046         pkt.call_id = req->call_id;
1047         pkt.auth_length = 0;
1048         pkt.pfc_flags = 0;
1049         pkt.u.request.alloc_hint = remaining;
1050         pkt.u.request.context_id = p->context_id;
1051         pkt.u.request.opnum = req->opnum;
1052
1053         if (req->object) {
1054                 pkt.u.request.object.object = *req->object;
1055                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1056                 chunk_size -= ndr_size_GUID(req->object,0);
1057         }
1058
1059         /* we send a series of pdus without waiting for a reply */
1060         while (remaining > 0 || first_packet) {
1061                 uint32_t chunk = MIN(chunk_size, remaining);
1062                 bool last_frag = false;
1063
1064                 first_packet = false;
1065                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1066
1067                 if (remaining == stub_data->length) {
1068                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1069                 }
1070                 if (chunk == remaining) {
1071                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1072                         last_frag = true;
1073                 }
1074
1075                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1076                         (stub_data->length - remaining);
1077                 pkt.u.request.stub_and_verifier.length = chunk;
1078
1079                 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1080                 if (!NT_STATUS_IS_OK(req->status)) {
1081                         req->state = RPC_REQUEST_DONE;
1082                         DLIST_REMOVE(p->conn->pending, req);
1083                         return;
1084                 }
1085                 
1086                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1087                 if (!NT_STATUS_IS_OK(req->status)) {
1088                         req->state = RPC_REQUEST_DONE;
1089                         DLIST_REMOVE(p->conn->pending, req);
1090                         return;
1091                 }               
1092
1093                 remaining -= chunk;
1094         }
1095 }
1096
1097 /*
1098   return the event context for a dcerpc pipe
1099   used by callers who wish to operate asynchronously
1100 */
1101 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1102 {
1103         return p->conn->event_ctx;
1104 }
1105
1106
1107
1108 /*
1109   perform the receive side of a async dcerpc request
1110 */
1111 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1112                              TALLOC_CTX *mem_ctx,
1113                              DATA_BLOB *stub_data)
1114 {
1115         NTSTATUS status;
1116
1117         while (req->state != RPC_REQUEST_DONE) {
1118                 struct event_context *ctx = dcerpc_event_context(req->p);
1119                 if (event_loop_once(ctx) != 0) {
1120                         return NT_STATUS_CONNECTION_DISCONNECTED;
1121                 }
1122         }
1123         *stub_data = req->payload;
1124         status = req->status;
1125         if (stub_data->data) {
1126                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1127         }
1128         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1129                 req->p->last_fault_code = req->fault_code;
1130         }
1131         talloc_free(req);
1132         return status;
1133 }
1134
1135 /*
1136   perform a full request/response pair on a dcerpc pipe
1137 */
1138 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1139                         struct GUID *object,
1140                         uint16_t opnum,
1141                         bool async,
1142                         TALLOC_CTX *mem_ctx,
1143                         DATA_BLOB *stub_data_in,
1144                         DATA_BLOB *stub_data_out)
1145 {
1146         struct rpc_request *req;
1147
1148         req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1149         if (req == NULL) {
1150                 return NT_STATUS_NO_MEMORY;
1151         }
1152
1153         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1154 }
1155
1156
1157 /*
1158   this is a paranoid NDR validator. For every packet we push onto the wire
1159   we pull it back again, then push it again. Then we compare the raw NDR data
1160   for that to the NDR we initially generated. If they don't match then we know
1161   we must have a bug in either the pull or push side of our code
1162 */
1163 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1164                                        TALLOC_CTX *mem_ctx,
1165                                        DATA_BLOB blob,
1166                                        size_t struct_size,
1167                                        ndr_push_flags_fn_t ndr_push,
1168                                        ndr_pull_flags_fn_t ndr_pull)
1169 {
1170         void *st;
1171         struct ndr_pull *pull;
1172         struct ndr_push *push;
1173         DATA_BLOB blob2;
1174         enum ndr_err_code ndr_err;
1175
1176         st = talloc_size(mem_ctx, struct_size);
1177         if (!st) {
1178                 return NT_STATUS_NO_MEMORY;
1179         }
1180
1181         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1182         if (!pull) {
1183                 return NT_STATUS_NO_MEMORY;
1184         }
1185         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1186
1187         ndr_err = ndr_pull(pull, NDR_IN, st);
1188         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1190                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1191                                          "failed input validation pull - %s",
1192                                          nt_errstr(status));
1193                 return ndr_map_error2ntstatus(ndr_err);
1194         }
1195
1196         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1197         if (!push) {
1198                 return NT_STATUS_NO_MEMORY;
1199         }       
1200
1201         ndr_err = ndr_push(push, NDR_IN, st);
1202         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1203                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1204                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1205                                          "failed input validation push - %s",
1206                                          nt_errstr(status));
1207                 return ndr_map_error2ntstatus(ndr_err);
1208         }
1209
1210         blob2 = ndr_push_blob(push);
1211
1212         if (data_blob_cmp(&blob, &blob2) != 0) {
1213                 DEBUG(3,("original:\n"));
1214                 dump_data(3, blob.data, blob.length);
1215                 DEBUG(3,("secondary:\n"));
1216                 dump_data(3, blob2.data, blob2.length);
1217                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1218                                          "failed input validation blobs doesn't match");
1219                 return ndr_map_error2ntstatus(ndr_err);
1220         }
1221
1222         return NT_STATUS_OK;
1223 }
1224
1225 /*
1226   this is a paranoid NDR input validator. For every packet we pull
1227   from the wire we push it back again then pull and push it
1228   again. Then we compare the raw NDR data for that to the NDR we
1229   initially generated. If they don't match then we know we must have a
1230   bug in either the pull or push side of our code
1231 */
1232 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1233                                         struct ndr_pull *pull_in,
1234                                         void *struct_ptr,
1235                                         size_t struct_size,
1236                                         ndr_push_flags_fn_t ndr_push,
1237                                         ndr_pull_flags_fn_t ndr_pull,
1238                                         ndr_print_function_t ndr_print)
1239 {
1240         void *st;
1241         struct ndr_pull *pull;
1242         struct ndr_push *push;
1243         DATA_BLOB blob, blob2;
1244         TALLOC_CTX *mem_ctx = pull_in;
1245         char *s1, *s2;
1246         enum ndr_err_code ndr_err;
1247
1248         st = talloc_size(mem_ctx, struct_size);
1249         if (!st) {
1250                 return NT_STATUS_NO_MEMORY;
1251         }
1252         memcpy(st, struct_ptr, struct_size);
1253
1254         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1255         if (!push) {
1256                 return NT_STATUS_NO_MEMORY;
1257         }       
1258
1259         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1260         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1261                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1262                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1263                                          "failed output validation push - %s",
1264                                          nt_errstr(status));
1265                 return ndr_map_error2ntstatus(ndr_err);
1266         }
1267
1268         blob = ndr_push_blob(push);
1269
1270         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1271         if (!pull) {
1272                 return NT_STATUS_NO_MEMORY;
1273         }
1274
1275         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1276         ndr_err = ndr_pull(pull, NDR_OUT, st);
1277         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1280                                          "failed output validation pull - %s",
1281                                          nt_errstr(status));
1282                 return ndr_map_error2ntstatus(ndr_err);
1283         }
1284
1285         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1286         if (!push) {
1287                 return NT_STATUS_NO_MEMORY;
1288         }       
1289
1290         ndr_err = ndr_push(push, NDR_OUT, st);
1291         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1292                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1293                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1294                                          "failed output validation push2 - %s",
1295                                          nt_errstr(status));
1296                 return ndr_map_error2ntstatus(ndr_err);
1297         }
1298
1299         blob2 = ndr_push_blob(push);
1300
1301         if (data_blob_cmp(&blob, &blob2) != 0) {
1302                 DEBUG(3,("original:\n"));
1303                 dump_data(3, blob.data, blob.length);
1304                 DEBUG(3,("secondary:\n"));
1305                 dump_data(3, blob2.data, blob2.length);
1306                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1307                                          "failed output validation blobs doesn't match");
1308                 return ndr_map_error2ntstatus(ndr_err);
1309         }
1310
1311         /* this checks the printed forms of the two structures, which effectively
1312            tests all of the value() attributes */
1313         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1314                                        NDR_OUT, struct_ptr);
1315         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1316                                        NDR_OUT, st);
1317         if (strcmp(s1, s2) != 0) {
1318 #if 1
1319                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1320 #else
1321                 /* this is sometimes useful */
1322                 printf("VALIDATE ERROR\n");
1323                 file_save("wire.dat", s1, strlen(s1));
1324                 file_save("gen.dat", s2, strlen(s2));
1325                 system("diff -u wire.dat gen.dat");
1326 #endif
1327                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1328                                          "failed output validation strings doesn't match");
1329                 return ndr_map_error2ntstatus(ndr_err);
1330         }
1331
1332         return NT_STATUS_OK;
1333 }
1334
1335
1336 /**
1337  send a rpc request given a dcerpc_call structure 
1338  */
1339 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1340                                                 const struct GUID *object,
1341                                                 const struct ndr_interface_table *table,
1342                                                 uint32_t opnum, 
1343                                                 TALLOC_CTX *mem_ctx, 
1344                                                 void *r)
1345 {
1346         const struct ndr_interface_call *call;
1347         struct ndr_push *push;
1348         NTSTATUS status;
1349         DATA_BLOB request;
1350         struct rpc_request *req;
1351         enum ndr_err_code ndr_err;
1352
1353         call = &table->calls[opnum];
1354
1355         /* setup for a ndr_push_* call */
1356         push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1357         if (!push) {
1358                 return NULL;
1359         }
1360
1361         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1362                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1363         }
1364
1365         /* push the structure into a blob */
1366         ndr_err = call->ndr_push(push, NDR_IN, r);
1367         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1368                 status = ndr_map_error2ntstatus(ndr_err);
1369                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1370                          nt_errstr(status)));
1371                 talloc_free(push);
1372                 return NULL;
1373         }
1374
1375         /* retrieve the blob */
1376         request = ndr_push_blob(push);
1377
1378         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1379                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1380                                                 call->ndr_push, call->ndr_pull);
1381                 if (!NT_STATUS_IS_OK(status)) {
1382                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1383                                  nt_errstr(status)));
1384                         talloc_free(push);
1385                         return NULL;
1386                 }
1387         }
1388
1389         DEBUG(10,("rpc request data:\n"));
1390         dump_data(10, request.data, request.length);
1391
1392         /* make the actual dcerpc request */
1393         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1394                                   &request);
1395
1396         if (req != NULL) {
1397                 req->ndr.table = table;
1398                 req->ndr.opnum = opnum;
1399                 req->ndr.struct_ptr = r;
1400                 req->ndr.mem_ctx = mem_ctx;
1401         }
1402
1403         talloc_free(push);
1404
1405         return req;
1406 }
1407
1408 /*
1409   receive the answer from a dcerpc_ndr_request_send()
1410 */
1411 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1412 {
1413         struct dcerpc_pipe *p = req->p;
1414         NTSTATUS status;
1415         DATA_BLOB response;
1416         struct ndr_pull *pull;
1417         uint_t flags;
1418         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1419         void *r = req->ndr.struct_ptr;
1420         uint32_t opnum = req->ndr.opnum;
1421         const struct ndr_interface_table *table = req->ndr.table;
1422         const struct ndr_interface_call *call = &table->calls[opnum];
1423         enum ndr_err_code ndr_err;
1424
1425         /* make sure the recv code doesn't free the request, as we
1426            need to grab the flags element before it is freed */
1427         if (talloc_reference(p, req) == NULL) {
1428                 return NT_STATUS_NO_MEMORY;
1429         }
1430
1431         status = dcerpc_request_recv(req, mem_ctx, &response);
1432         if (!NT_STATUS_IS_OK(status)) {
1433                 talloc_unlink(p, req);
1434                 return status;
1435         }
1436
1437         flags = req->flags;
1438
1439         /* prepare for ndr_pull_* */
1440         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1441         if (!pull) {
1442                 talloc_unlink(p, req);
1443                 return NT_STATUS_NO_MEMORY;
1444         }
1445
1446         if (pull->data) {
1447                 pull->data = talloc_steal(pull, pull->data);
1448         }
1449         talloc_unlink(p, req);
1450
1451         if (flags & DCERPC_PULL_BIGENDIAN) {
1452                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1453         }
1454
1455         DEBUG(10,("rpc reply data:\n"));
1456         dump_data(10, pull->data, pull->data_size);
1457
1458         /* pull the structure from the blob */
1459         ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1460         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1461                 status = ndr_map_error2ntstatus(ndr_err);
1462                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1463                                   &response);
1464                 return status;
1465         }
1466
1467         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1468                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1469                                                  call->ndr_push, call->ndr_pull, 
1470                                                  call->ndr_print);
1471                 if (!NT_STATUS_IS_OK(status)) {
1472                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1473                                   &response);
1474                         return status;
1475                 }
1476         }
1477
1478         if (pull->offset != pull->data_size) {
1479                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1480                          pull->data_size - pull->offset));
1481                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1482                    but it turns out that early versions of NT
1483                    (specifically NT3.1) add junk onto the end of rpc
1484                    packets, so if we want to interoperate at all with
1485                    those versions then we need to ignore this error */
1486         }
1487
1488         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1489
1490         return NT_STATUS_OK;
1491 }
1492
1493
1494 /*
1495   a useful helper function for synchronous rpc requests 
1496
1497   this can be used when you have ndr push/pull functions in the
1498   standard format
1499 */
1500 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1501                             const struct GUID *object,
1502                             const struct ndr_interface_table *table,
1503                             uint32_t opnum, 
1504                             TALLOC_CTX *mem_ctx, 
1505                             void *r)
1506 {
1507         struct rpc_request *req;
1508
1509         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1510         if (req == NULL) {
1511                 return NT_STATUS_NO_MEMORY;
1512         }
1513
1514         return dcerpc_ndr_request_recv(req);
1515 }
1516
1517
1518 /*
1519   a useful function for retrieving the server name we connected to
1520 */
1521 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1522 {
1523         if (!p->conn->transport.target_hostname) {
1524                 if (!p->conn->transport.peer_name) {
1525                         return "";
1526                 }
1527                 return p->conn->transport.peer_name(p->conn);
1528         }
1529         return p->conn->transport.target_hostname(p->conn);
1530 }
1531
1532
1533 /*
1534   get the dcerpc auth_level for a open connection
1535 */
1536 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1537 {
1538         uint8_t auth_level;
1539
1540         if (c->flags & DCERPC_SEAL) {
1541                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1542         } else if (c->flags & DCERPC_SIGN) {
1543                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1544         } else if (c->flags & DCERPC_CONNECT) {
1545                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1546         } else {
1547                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1548         }
1549         return auth_level;
1550 }
1551
1552 /*
1553   Receive an alter reply from the transport
1554 */
1555 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1556                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1557 {
1558         struct composite_context *c;
1559         struct dcerpc_pipe *recv_pipe;
1560
1561         c = talloc_get_type(req->async.private_data, struct composite_context);
1562         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1563
1564         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1565             pkt->u.alter_resp.num_results == 1 &&
1566             pkt->u.alter_resp.ctx_list[0].result != 0) {
1567                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1568                          pkt->u.alter_resp.ctx_list[0].reason));
1569                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1570                 return;
1571         }
1572
1573         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1574             pkt->u.alter_resp.num_results == 0 ||
1575             pkt->u.alter_resp.ctx_list[0].result != 0) {
1576                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1577                 return;
1578         }
1579
1580         /* the alter_resp might contain a reply set of credentials */
1581         if (recv_pipe->conn->security_state.auth_info &&
1582             pkt->u.alter_resp.auth_info.length) {
1583                 enum ndr_err_code ndr_err;
1584                 ndr_err = ndr_pull_struct_blob(
1585                         &pkt->u.alter_resp.auth_info, recv_pipe,
1586                         NULL,
1587                         recv_pipe->conn->security_state.auth_info,
1588                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1589                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1590                         c->status = ndr_map_error2ntstatus(ndr_err);
1591                         if (!composite_is_ok(c)) return;
1592                 }
1593         }
1594
1595         composite_done(c);
1596 }
1597
1598 /* 
1599    send a dcerpc alter_context request
1600 */
1601 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1602                                                     TALLOC_CTX *mem_ctx,
1603                                                     const struct ndr_syntax_id *syntax,
1604                                                     const struct ndr_syntax_id *transfer_syntax)
1605 {
1606         struct composite_context *c;
1607         struct ncacn_packet pkt;
1608         DATA_BLOB blob;
1609         struct rpc_request *req;
1610
1611         c = composite_create(mem_ctx, p->conn->event_ctx);
1612         if (c == NULL) return NULL;
1613
1614         c->private_data = p;
1615
1616         p->syntax = *syntax;
1617         p->transfer_syntax = *transfer_syntax;
1618
1619         init_ncacn_hdr(p->conn, &pkt);
1620
1621         pkt.ptype = DCERPC_PKT_ALTER;
1622         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1623         pkt.call_id = p->conn->call_id;
1624         pkt.auth_length = 0;
1625
1626         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1627                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1628         }
1629
1630         pkt.u.alter.max_xmit_frag = 5840;
1631         pkt.u.alter.max_recv_frag = 5840;
1632         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1633         pkt.u.alter.num_contexts = 1;
1634         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1635         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1636         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1637         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1638         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1639         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1640         pkt.u.alter.auth_info = data_blob(NULL, 0);
1641
1642         /* construct the NDR form of the packet */
1643         c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1644                                     p->conn->security_state.auth_info);
1645         if (!composite_is_ok(c)) return c;
1646
1647         p->conn->transport.recv_data = dcerpc_recv_data;
1648
1649         /*
1650          * we allocate a dcerpc_request so we can be in the same
1651          * request queue as normal requests
1652          */
1653         req = talloc_zero(c, struct rpc_request);
1654         if (composite_nomem(req, c)) return c;
1655
1656         req->state = RPC_REQUEST_PENDING;
1657         req->call_id = pkt.call_id;
1658         req->async.private_data = c;
1659         req->async.callback = dcerpc_composite_fail;
1660         req->p = p;
1661         req->recv_handler = dcerpc_alter_recv_handler;
1662         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1663         talloc_set_destructor(req, dcerpc_req_dequeue);
1664
1665         c->status = p->conn->transport.send_request(p->conn, &blob, true);
1666         if (!composite_is_ok(c)) return c;
1667
1668         event_add_timed(c->event_ctx, req,
1669                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1670                         dcerpc_timeout_handler, req);
1671
1672         return c;
1673 }
1674
1675 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1676 {
1677         NTSTATUS result = composite_wait(ctx);
1678         talloc_free(ctx);
1679         return result;
1680 }
1681
1682 /* 
1683    send a dcerpc alter_context request
1684 */
1685 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1686                               TALLOC_CTX *mem_ctx,
1687                               const struct ndr_syntax_id *syntax,
1688                               const struct ndr_syntax_id *transfer_syntax)
1689 {
1690         struct composite_context *creq;
1691         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1692         return dcerpc_alter_context_recv(creq);
1693 }