r25920: ndr: change NTSTAUS into enum ndr_err_code (samba4 callers)
[tprouty/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/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "libcli/composite/composite.h"
30 #include "auth/gensec/gensec.h"
31
32 NTSTATUS dcerpc_init(void)
33 {
34         gensec_init();
35
36         return NT_STATUS_OK;
37 }
38
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
41
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
44 {
45         if (conn->dead) {
46                 conn->free_skipped = true;
47                 return -1;
48         }
49         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50         return 0;
51 }
52
53
54 /* initialise a dcerpc connection. 
55    the event context is optional
56 */
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
58                                                  struct event_context *ev)
59 {
60         struct dcerpc_connection *c;
61
62         c = talloc_zero(mem_ctx, struct dcerpc_connection);
63         if (!c) {
64                 return NULL;
65         }
66
67         if (ev == NULL) {
68                 ev = event_context_init(c);
69                 if (ev == NULL) {
70                         talloc_free(c);
71                         return NULL;
72                 }
73         }
74
75         c->event_ctx = ev;
76         
77         if (!talloc_reference(c, ev)) {
78                 talloc_free(c);
79                 return NULL;
80         }
81         c->call_id = 1;
82         c->security_state.auth_info = NULL;
83         c->security_state.session_key = dcerpc_generic_session_key;
84         c->security_state.generic_state = NULL;
85         c->binding_string = NULL;
86         c->flags = 0;
87         c->srv_max_xmit_frag = 0;
88         c->srv_max_recv_frag = 0;
89         c->pending = NULL;
90
91         talloc_set_destructor(c, dcerpc_connection_destructor);
92
93         return c;
94 }
95
96 /* initialise a dcerpc pipe. */
97 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
98 {
99         struct dcerpc_pipe *p;
100
101         p = talloc(mem_ctx, struct dcerpc_pipe);
102         if (!p) {
103                 return NULL;
104         }
105
106         p->conn = dcerpc_connection_init(p, ev);
107         if (p->conn == NULL) {
108                 talloc_free(p);
109                 return NULL;
110         }
111
112         p->last_fault_code = 0;
113         p->context_id = 0;
114         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
115         p->binding = NULL;
116
117         ZERO_STRUCT(p->syntax);
118         ZERO_STRUCT(p->transfer_syntax);
119
120         return p;
121 }
122
123
124 /* 
125    choose the next call id to use
126 */
127 static uint32_t next_call_id(struct dcerpc_connection *c)
128 {
129         c->call_id++;
130         if (c->call_id == 0) {
131                 c->call_id++;
132         }
133         return c->call_id;
134 }
135
136 /* we need to be able to get/set the fragment length without doing a full
137    decode */
138 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
139 {
140         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
141                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
142         } else {
143                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144         }
145 }
146
147 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
148 {
149         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
150                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
151         } else {
152                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153         }
154 }
155
156 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
157 {
158         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
159                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
160         } else {
161                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
162         }
163 }
164
165
166 /*
167   setup for a ndr pull, also setting up any flags from the binding string
168 */
169 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c, 
170                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
171 {
172         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
173
174         if (ndr == NULL) return ndr;
175
176         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
177                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
178         }
179
180         if (c->flags & DCERPC_NDR_REF_ALLOC) {
181                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
182         }
183
184         return ndr;
185 }
186
187 /* 
188    parse a data blob into a ncacn_packet structure. This handles both
189    input and output packets
190 */
191 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
192                             struct ncacn_packet *pkt)
193 {
194         struct ndr_pull *ndr;
195         enum ndr_err_code ndr_err;
196
197         ndr = ndr_pull_init_flags(c, blob, mem_ctx);
198         if (!ndr) {
199                 return NT_STATUS_NO_MEMORY;
200         }
201
202         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
203                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
204         }
205
206         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
207         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
208                 return ndr_map_error2ntstatus(ndr_err);
209         }
210
211         return NT_STATUS_OK;
212 }
213
214 /*
215   generate a CONNECT level verifier
216 */
217 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
218 {
219         *blob = data_blob_talloc(mem_ctx, NULL, 16);
220         if (blob->data == NULL) {
221                 return NT_STATUS_NO_MEMORY;
222         }
223         SIVAL(blob->data, 0, 1);
224         memset(blob->data+4, 0, 12);
225         return NT_STATUS_OK;
226 }
227
228 /*
229   check a CONNECT level verifier
230 */
231 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
232 {
233         if (blob->length != 16 ||
234             IVAL(blob->data, 0) != 1) {
235                 return NT_STATUS_ACCESS_DENIED;
236         }
237         return NT_STATUS_OK;
238 }
239
240 /* 
241    parse the authentication information on a dcerpc response packet
242 */
243 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx, 
244                                         DATA_BLOB *raw_packet,
245                                         struct ncacn_packet *pkt)
246 {
247         struct ndr_pull *ndr;
248         NTSTATUS status;
249         struct dcerpc_auth auth;
250         DATA_BLOB auth_blob;
251         enum ndr_err_code ndr_err;
252
253         if (pkt->auth_length == 0 &&
254             c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
255                 return NT_STATUS_OK;
256         }
257
258         auth_blob.length = 8 + pkt->auth_length;
259
260         /* check for a valid length */
261         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
262                 return NT_STATUS_INFO_LENGTH_MISMATCH;
263         }
264
265         auth_blob.data = 
266                 pkt->u.response.stub_and_verifier.data + 
267                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
268         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
269
270         /* pull the auth structure */
271         ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
272         if (!ndr) {
273                 return NT_STATUS_NO_MEMORY;
274         }
275
276         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
277                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
278         }
279
280         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
281         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282                 return ndr_map_error2ntstatus(ndr_err);
283         }
284         status = NT_STATUS_OK;
285
286         /* check signature or unseal the packet */
287         switch (c->security_state.auth_info->auth_level) {
288         case DCERPC_AUTH_LEVEL_PRIVACY:
289                 status = gensec_unseal_packet(c->security_state.generic_state, 
290                                               mem_ctx, 
291                                               raw_packet->data + DCERPC_REQUEST_LENGTH,
292                                               pkt->u.response.stub_and_verifier.length, 
293                                               raw_packet->data,
294                                               raw_packet->length - auth.credentials.length,
295                                               &auth.credentials);
296                 memcpy(pkt->u.response.stub_and_verifier.data,
297                        raw_packet->data + DCERPC_REQUEST_LENGTH,
298                        pkt->u.response.stub_and_verifier.length);
299                 break;
300                 
301         case DCERPC_AUTH_LEVEL_INTEGRITY:
302                 status = gensec_check_packet(c->security_state.generic_state, 
303                                              mem_ctx, 
304                                              pkt->u.response.stub_and_verifier.data, 
305                                              pkt->u.response.stub_and_verifier.length, 
306                                              raw_packet->data,
307                                              raw_packet->length - auth.credentials.length,
308                                              &auth.credentials);
309                 break;
310
311         case DCERPC_AUTH_LEVEL_CONNECT:
312                 status = dcerpc_check_connect_verifier(&auth.credentials);
313                 break;
314
315         case DCERPC_AUTH_LEVEL_NONE:
316                 break;
317
318         default:
319                 status = NT_STATUS_INVALID_LEVEL;
320                 break;
321         }
322         
323         /* remove the indicated amount of paddiing */
324         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
325                 return NT_STATUS_INFO_LENGTH_MISMATCH;
326         }
327         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
328
329         return status;
330 }
331
332
333 /* 
334    push a dcerpc request packet into a blob, possibly signing it.
335 */
336 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 
337                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
338                                          struct ncacn_packet *pkt)
339 {
340         NTSTATUS status;
341         struct ndr_push *ndr;
342         DATA_BLOB creds2;
343         size_t payload_length;
344         enum ndr_err_code ndr_err;
345
346         /* non-signed packets are simpler */
347         if (!c->security_state.auth_info || 
348             !c->security_state.generic_state) {
349                 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
350         }
351
352         ndr = ndr_push_init_ctx(mem_ctx);
353         if (!ndr) {
354                 return NT_STATUS_NO_MEMORY;
355         }
356
357         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
358                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
359         }
360
361         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
362                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
363         }
364
365         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
366         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
367                 return ndr_map_error2ntstatus(ndr_err);
368         }
369         status = NT_STATUS_OK;
370
371         /* pad to 16 byte multiple in the payload portion of the
372            packet. This matches what w2k3 does */
373         c->security_state.auth_info->auth_pad_length = 
374                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
375         ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
376
377         payload_length = pkt->u.request.stub_and_verifier.length + 
378                 c->security_state.auth_info->auth_pad_length;
379
380         /* sign or seal the packet */
381         switch (c->security_state.auth_info->auth_level) {
382         case DCERPC_AUTH_LEVEL_PRIVACY:
383         case DCERPC_AUTH_LEVEL_INTEGRITY:
384                 /* We hope this length is accruate.  If must be if the
385                  * GENSEC mech does AEAD signing of the packet
386                  * headers */
387                 c->security_state.auth_info->credentials
388                         = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, 
389                                                                           payload_length));
390                 data_blob_clear(&c->security_state.auth_info->credentials);
391                 break;
392
393         case DCERPC_AUTH_LEVEL_CONNECT:
394                 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
395                 break;
396                 
397         case DCERPC_AUTH_LEVEL_NONE:
398                 c->security_state.auth_info->credentials = data_blob(NULL, 0);
399                 break;
400                 
401         default:
402                 status = NT_STATUS_INVALID_LEVEL;
403                 break;
404         }
405         
406         if (!NT_STATUS_IS_OK(status)) {
407                 return status;
408         }       
409
410         /* add the auth verifier */
411         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
412         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
413                 return ndr_map_error2ntstatus(ndr_err);
414         }
415         status = NT_STATUS_OK;
416
417         /* extract the whole packet as a blob */
418         *blob = ndr_push_blob(ndr);
419
420         /* fill in the fragment length and auth_length, we can't fill
421            in these earlier as we don't know the signature length (it
422            could be variable length) */
423         dcerpc_set_frag_length(blob, blob->length);
424         /* We hope this value is accruate.  If must be if the GENSEC
425          * mech does AEAD signing of the packet headers */
426         dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
427
428         /* sign or seal the packet */
429         switch (c->security_state.auth_info->auth_level) {
430         case DCERPC_AUTH_LEVEL_PRIVACY:
431                 status = gensec_seal_packet(c->security_state.generic_state, 
432                                             mem_ctx, 
433                                             blob->data + DCERPC_REQUEST_LENGTH, 
434                                             payload_length,
435                                             blob->data,
436                                             blob->length - 
437                                             c->security_state.auth_info->credentials.length,
438                                             &creds2);
439                 if (!NT_STATUS_IS_OK(status)) {
440                         return status;
441                 }
442                 blob->length -= c->security_state.auth_info->credentials.length;
443                 if (!data_blob_append(mem_ctx, blob,
444                                           creds2.data, creds2.length)) {
445                         return NT_STATUS_NO_MEMORY;
446                 }
447                 dcerpc_set_auth_length(blob, creds2.length);
448                 if (c->security_state.auth_info->credentials.length == 0) {
449                         /* this is needed for krb5 only, to correct the total packet
450                            length */
451                         dcerpc_set_frag_length(blob, 
452                                                dcerpc_get_frag_length(blob)
453                                                +creds2.length);
454                 }
455                 break;
456
457         case DCERPC_AUTH_LEVEL_INTEGRITY:
458                 status = gensec_sign_packet(c->security_state.generic_state, 
459                                             mem_ctx, 
460                                             blob->data + DCERPC_REQUEST_LENGTH, 
461                                             payload_length, 
462                                             blob->data,
463                                             blob->length - 
464                                             c->security_state.auth_info->credentials.length,
465                                             &creds2);
466                 if (!NT_STATUS_IS_OK(status)) {
467                         return status;
468                 }
469                 blob->length -= c->security_state.auth_info->credentials.length;
470                 if (!data_blob_append(mem_ctx, blob,
471                                           creds2.data, creds2.length)) {
472                         return NT_STATUS_NO_MEMORY;
473                 }
474                 dcerpc_set_auth_length(blob, creds2.length);
475                 if (c->security_state.auth_info->credentials.length == 0) {
476                         /* this is needed for krb5 only, to correct the total packet
477                            length */
478                         dcerpc_set_frag_length(blob, 
479                                                dcerpc_get_frag_length(blob)
480                                                +creds2.length);
481                 }
482                 break;
483
484         case DCERPC_AUTH_LEVEL_CONNECT:
485                 break;
486
487         case DCERPC_AUTH_LEVEL_NONE:
488                 c->security_state.auth_info->credentials = data_blob(NULL, 0);
489                 break;
490
491         default:
492                 status = NT_STATUS_INVALID_LEVEL;
493                 break;
494         }
495
496         data_blob_free(&c->security_state.auth_info->credentials);
497
498         return NT_STATUS_OK;
499 }
500
501
502 /* 
503    fill in the fixed values in a dcerpc header 
504 */
505 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
506 {
507         pkt->rpc_vers = 5;
508         pkt->rpc_vers_minor = 0;
509         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
510                 pkt->drep[0] = 0;
511         } else {
512                 pkt->drep[0] = DCERPC_DREP_LE;
513         }
514         pkt->drep[1] = 0;
515         pkt->drep[2] = 0;
516         pkt->drep[3] = 0;
517 }
518
519 /*
520   map a bind nak reason to a NTSTATUS
521 */
522 static NTSTATUS dcerpc_map_reason(uint16_t reason)
523 {
524         switch (reason) {
525         case DCERPC_BIND_REASON_ASYNTAX:
526                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
527         case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
528                 return NT_STATUS_INVALID_PARAMETER;
529         }
530         return NT_STATUS_UNSUCCESSFUL;
531 }
532
533 /*
534   a bind or alter context has failed
535 */
536 static void dcerpc_composite_fail(struct rpc_request *req)
537 {
538         struct composite_context *c = talloc_get_type(req->async.private_data, 
539                                                       struct composite_context);
540         composite_error(c, req->status);
541 }
542
543 /*
544   remove requests from the pending or queued queues
545  */
546 static int dcerpc_req_dequeue(struct rpc_request *req)
547 {
548         switch (req->state) {
549         case RPC_REQUEST_QUEUED:
550                 DLIST_REMOVE(req->p->conn->request_queue, req);
551                 break;
552         case RPC_REQUEST_PENDING:
553                 DLIST_REMOVE(req->p->conn->pending, req);
554                 break;
555         case RPC_REQUEST_DONE:
556                 break;
557         }
558         return 0;
559 }
560
561
562 /*
563   mark the dcerpc connection dead. All outstanding requests get an error
564 */
565 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
566 {
567         if (conn->dead) return;
568
569         conn->dead = true;
570
571         if (conn->transport.shutdown_pipe) {
572                 conn->transport.shutdown_pipe(conn, status);
573         }
574
575         /* all pending requests get the error */
576         while (conn->pending) {
577                 struct rpc_request *req = conn->pending;
578                 dcerpc_req_dequeue(req);
579                 req->state = RPC_REQUEST_DONE;
580                 req->status = status;
581                 if (req->async.callback) {
582                         req->async.callback(req);
583                 }
584         }       
585
586         talloc_set_destructor(conn, NULL);
587         if (conn->free_skipped) {
588                 talloc_free(conn);
589         }
590 }
591
592 /*
593   forward declarations of the recv_data handlers for the types of
594   packets we need to handle
595 */
596 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
597                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
598
599 /*
600   receive a dcerpc reply from the transport. Here we work out what
601   type of reply it is (normal request, bind or alter context) and
602   dispatch to the appropriate handler
603 */
604 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
605 {
606         struct ncacn_packet pkt;
607
608         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
609                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
610         }
611
612         /* the transport may be telling us of a severe error, such as
613            a dropped socket */
614         if (!NT_STATUS_IS_OK(status)) {
615                 data_blob_free(blob);
616                 dcerpc_connection_dead(conn, status);
617                 return;
618         }
619
620         /* parse the basic packet to work out what type of response this is */
621         status = ncacn_pull(conn, blob, blob->data, &pkt);
622         if (!NT_STATUS_IS_OK(status)) {
623                 data_blob_free(blob);
624                 dcerpc_connection_dead(conn, status);
625         }
626
627         dcerpc_request_recv_data(conn, blob, &pkt);
628 }
629
630
631 /*
632   Receive a bind reply from the transport
633 */
634 static void dcerpc_bind_recv_handler(struct rpc_request *req, 
635                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
636 {
637         struct composite_context *c;
638         struct dcerpc_connection *conn;
639
640         c = talloc_get_type(req->async.private_data, struct composite_context);
641
642         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
643                 DEBUG(2,("dcerpc: bind_nak reason %d\n",
644                          pkt->u.bind_nak.reject_reason));
645                 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
646                                                      reject_reason));
647                 return;
648         }
649
650         if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
651             (pkt->u.bind_ack.num_results == 0) ||
652             (pkt->u.bind_ack.ctx_list[0].result != 0)) {
653                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
654                 return;
655         }
656
657         conn = req->p->conn;
658
659         conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
660         conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
661
662         /* the bind_ack might contain a reply set of credentials */
663         if (conn->security_state.auth_info &&
664             pkt->u.bind_ack.auth_info.length) {
665                 enum ndr_err_code ndr_err;
666                 ndr_err = ndr_pull_struct_blob(
667                         &pkt->u.bind_ack.auth_info, conn,
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, &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, &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 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);
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);
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);
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);
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 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 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1522 {
1523         if (!p->conn->transport.peer_name) {
1524                 return "";
1525         }
1526         return p->conn->transport.peer_name(p->conn);
1527 }
1528
1529
1530 /*
1531   get the dcerpc auth_level for a open connection
1532 */
1533 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1534 {
1535         uint8_t auth_level;
1536
1537         if (c->flags & DCERPC_SEAL) {
1538                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1539         } else if (c->flags & DCERPC_SIGN) {
1540                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1541         } else if (c->flags & DCERPC_CONNECT) {
1542                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1543         } else {
1544                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1545         }
1546         return auth_level;
1547 }
1548
1549 /*
1550   Receive an alter reply from the transport
1551 */
1552 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1553                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1554 {
1555         struct composite_context *c;
1556         struct dcerpc_pipe *recv_pipe;
1557
1558         c = talloc_get_type(req->async.private_data, struct composite_context);
1559         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1560
1561         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1562             pkt->u.alter_resp.num_results == 1 &&
1563             pkt->u.alter_resp.ctx_list[0].result != 0) {
1564                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1565                          pkt->u.alter_resp.ctx_list[0].reason));
1566                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1567                 return;
1568         }
1569
1570         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1571             pkt->u.alter_resp.num_results == 0 ||
1572             pkt->u.alter_resp.ctx_list[0].result != 0) {
1573                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1574                 return;
1575         }
1576
1577         /* the alter_resp might contain a reply set of credentials */
1578         if (recv_pipe->conn->security_state.auth_info &&
1579             pkt->u.alter_resp.auth_info.length) {
1580                 enum ndr_err_code ndr_err;
1581                 ndr_err = ndr_pull_struct_blob(
1582                         &pkt->u.alter_resp.auth_info, recv_pipe,
1583                         recv_pipe->conn->security_state.auth_info,
1584                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1585                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1586                         c->status = ndr_map_error2ntstatus(ndr_err);
1587                         if (!composite_is_ok(c)) return;
1588                 }
1589         }
1590
1591         composite_done(c);
1592 }
1593
1594 /* 
1595    send a dcerpc alter_context request
1596 */
1597 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1598                                                     TALLOC_CTX *mem_ctx,
1599                                                     const struct ndr_syntax_id *syntax,
1600                                                     const struct ndr_syntax_id *transfer_syntax)
1601 {
1602         struct composite_context *c;
1603         struct ncacn_packet pkt;
1604         DATA_BLOB blob;
1605         struct rpc_request *req;
1606
1607         c = composite_create(mem_ctx, p->conn->event_ctx);
1608         if (c == NULL) return NULL;
1609
1610         c->private_data = p;
1611
1612         p->syntax = *syntax;
1613         p->transfer_syntax = *transfer_syntax;
1614
1615         init_ncacn_hdr(p->conn, &pkt);
1616
1617         pkt.ptype = DCERPC_PKT_ALTER;
1618         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1619         pkt.call_id = p->conn->call_id;
1620         pkt.auth_length = 0;
1621
1622         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1623                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1624         }
1625
1626         pkt.u.alter.max_xmit_frag = 5840;
1627         pkt.u.alter.max_recv_frag = 5840;
1628         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1629         pkt.u.alter.num_contexts = 1;
1630         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1631         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1632         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1633         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1634         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1635         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1636         pkt.u.alter.auth_info = data_blob(NULL, 0);
1637
1638         /* construct the NDR form of the packet */
1639         c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1640                                     p->conn->security_state.auth_info);
1641         if (!composite_is_ok(c)) return c;
1642
1643         p->conn->transport.recv_data = dcerpc_recv_data;
1644
1645         /*
1646          * we allocate a dcerpc_request so we can be in the same
1647          * request queue as normal requests
1648          */
1649         req = talloc_zero(c, struct rpc_request);
1650         if (composite_nomem(req, c)) return c;
1651
1652         req->state = RPC_REQUEST_PENDING;
1653         req->call_id = pkt.call_id;
1654         req->async.private_data = c;
1655         req->async.callback = dcerpc_composite_fail;
1656         req->p = p;
1657         req->recv_handler = dcerpc_alter_recv_handler;
1658         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1659         talloc_set_destructor(req, dcerpc_req_dequeue);
1660
1661         c->status = p->conn->transport.send_request(p->conn, &blob, true);
1662         if (!composite_is_ok(c)) return c;
1663
1664         event_add_timed(c->event_ctx, req,
1665                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1666                         dcerpc_timeout_handler, req);
1667
1668         return c;
1669 }
1670
1671 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1672 {
1673         NTSTATUS result = composite_wait(ctx);
1674         talloc_free(ctx);
1675         return result;
1676 }
1677
1678 /* 
1679    send a dcerpc alter_context request
1680 */
1681 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1682                               TALLOC_CTX *mem_ctx,
1683                               const struct ndr_syntax_id *syntax,
1684                               const struct ndr_syntax_id *transfer_syntax)
1685 {
1686         struct composite_context *creq;
1687         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1688         return dcerpc_alter_context_recv(creq);
1689 }