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