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