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