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