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