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