r7633: this patch started as an attempt to make the dcerpc code use a given
[kamenim/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
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         DATA_BLOB *reply_blob;
517         NTSTATUS status;
518 };
519
520 /*
521   receive a reply to a full request
522  */
523 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob, 
524                               NTSTATUS status)
525 {
526         struct full_request_state *state = c->full_request_private;
527
528         if (!NT_STATUS_IS_OK(status)) {
529                 state->status = status;
530                 return;
531         }
532         state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
533         state->reply_blob = NULL;
534 }
535
536 /*
537   handle timeouts of full dcerpc requests
538 */
539 static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te, 
540                                         struct timeval t, void *private)
541 {
542         struct full_request_state *state = talloc_get_type(private, 
543                                                            struct full_request_state);
544         state->status = NT_STATUS_IO_TIMEOUT;
545 }
546
547 /*
548   perform a single pdu synchronous request - used for the bind code
549   this cannot be mixed with normal async requests
550 */
551 static NTSTATUS full_request(struct dcerpc_connection *c, 
552                              TALLOC_CTX *mem_ctx,
553                              DATA_BLOB *request_blob,
554                              DATA_BLOB *reply_blob)
555 {
556         struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
557         NTSTATUS status;
558
559         if (state == NULL) {
560                 return NT_STATUS_NO_MEMORY;
561         }
562
563         state->reply_blob = reply_blob;
564         state->status = NT_STATUS_OK;
565
566         c->transport.recv_data = full_request_recv;
567         c->full_request_private = state;
568
569         status = c->transport.send_request(c, request_blob, True);
570         if (!NT_STATUS_IS_OK(status)) {
571                 return status;
572         }
573
574         event_add_timed(c->event_ctx, state, 
575                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0), 
576                         dcerpc_full_timeout_handler, state);
577
578         while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
579                 if (event_loop_once(c->event_ctx) != 0) {
580                         return NT_STATUS_CONNECTION_DISCONNECTED;
581                 }
582         }
583
584         return state->status;
585 }
586
587 /*
588   map a bind nak reason to a NTSTATUS
589 */
590 static NTSTATUS dcerpc_map_reason(uint16_t reason)
591 {
592         switch (reason) {
593         case DCERPC_BIND_REASON_ASYNTAX:
594                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
595         }
596         return NT_STATUS_UNSUCCESSFUL;
597 }
598
599
600 /* 
601    perform a bind using the given syntax 
602
603    the auth_info structure is updated with the reply authentication info
604    on success
605 */
606 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
607                      TALLOC_CTX *mem_ctx,
608                      const struct dcerpc_syntax_id *syntax,
609                      const struct dcerpc_syntax_id *transfer_syntax)
610 {
611         struct ncacn_packet pkt;
612         NTSTATUS status;
613         DATA_BLOB blob;
614
615         p->syntax = *syntax;
616         p->transfer_syntax = *transfer_syntax;
617
618         init_ncacn_hdr(p->conn, &pkt);
619
620         pkt.ptype = DCERPC_PKT_BIND;
621         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
622         pkt.call_id = p->conn->call_id;
623         pkt.auth_length = 0;
624
625         pkt.u.bind.max_xmit_frag = 5840;
626         pkt.u.bind.max_recv_frag = 5840;
627         pkt.u.bind.assoc_group_id = 0;
628         pkt.u.bind.num_contexts = 1;
629         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
630         if (!pkt.u.bind.ctx_list) {
631                 return NT_STATUS_NO_MEMORY;
632         }
633         pkt.u.bind.ctx_list[0].context_id = p->context_id;
634         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
635         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
636         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
637         pkt.u.bind.auth_info = data_blob(NULL, 0);
638
639         /* construct the NDR form of the packet */
640         status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
641         if (!NT_STATUS_IS_OK(status)) {
642                 return status;
643         }
644
645         /* send it on its way */
646         status = full_request(p->conn, mem_ctx, &blob, &blob);
647         if (!NT_STATUS_IS_OK(status)) {
648                 return status;
649         }
650
651         /* unmarshall the NDR */
652         status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
653         if (!NT_STATUS_IS_OK(status)) {
654                 return status;
655         }
656
657         if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
658                 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
659                 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
660         }
661
662         if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
663             pkt.u.bind_ack.num_results == 0 ||
664             pkt.u.bind_ack.ctx_list[0].result != 0) {
665                 return NT_STATUS_UNSUCCESSFUL;
666         }
667
668         p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
669         p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
670
671         /* the bind_ack might contain a reply set of credentials */
672         if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
673                 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
674                                               mem_ctx,
675                                               p->conn->security_state.auth_info,
676                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
677         }
678
679         return status;  
680 }
681
682 /* 
683    perform a continued bind (and auth3)
684 */
685 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c, 
686                       TALLOC_CTX *mem_ctx)
687 {
688         struct ncacn_packet pkt;
689         NTSTATUS status;
690         DATA_BLOB blob;
691
692         init_ncacn_hdr(c, &pkt);
693
694         pkt.ptype = DCERPC_PKT_AUTH3;
695         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
696         pkt.call_id = next_call_id(c);
697         pkt.auth_length = 0;
698         pkt.u.auth3._pad = 0;
699         pkt.u.auth3.auth_info = data_blob(NULL, 0);
700
701         /* construct the NDR form of the packet */
702         status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
703         if (!NT_STATUS_IS_OK(status)) {
704                 return status;
705         }
706
707         /* send it on its way */
708         status = c->transport.send_request(c, &blob, False);
709         if (!NT_STATUS_IS_OK(status)) {
710                 return status;
711         }
712
713         return status;  
714 }
715
716
717 /* perform a dcerpc bind, using the uuid as the key */
718 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
719                             TALLOC_CTX *mem_ctx,
720                             const char *uuid, uint_t version)
721 {
722         struct dcerpc_syntax_id syntax;
723         struct dcerpc_syntax_id transfer_syntax;
724         NTSTATUS status;
725
726         status = GUID_from_string(uuid, &syntax.uuid);
727         if (!NT_STATUS_IS_OK(status)) {
728                 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
729                 return status;
730         }
731         syntax.if_version = version;
732
733         status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
734         if (!NT_STATUS_IS_OK(status)) {
735                 return status;
736         }
737         transfer_syntax.if_version = NDR_GUID_VERSION;
738
739         return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
740 }
741
742 /*
743   process a fragment received from the transport layer during a
744   request
745 */
746 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
747                                      DATA_BLOB *data,
748                                      NTSTATUS status)
749 {
750         struct ncacn_packet pkt;
751         struct rpc_request *req;
752         uint_t length;
753         
754         if (!NT_STATUS_IS_OK(status)) {
755                 /* all pending requests get the error */
756                 while (c->pending) {
757                         req = c->pending;
758                         req->state = RPC_REQUEST_DONE;
759                         req->status = status;
760                         DLIST_REMOVE(c->pending, req);
761                         if (req->async.callback) {
762                                 req->async.callback(req);
763                         }
764                 }
765                 return;
766         }
767
768         pkt.call_id = 0;
769
770         status = ncacn_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
771
772         /* find the matching request. Notice we match before we check
773            the status.  this is ok as a pending call_id can never be
774            zero */
775         for (req=c->pending;req;req=req->next) {
776                 if (pkt.call_id == req->call_id) break;
777         }
778
779         if (req == NULL) {
780                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
781                 return;
782         }
783
784         if (!NT_STATUS_IS_OK(status)) {
785                 req->status = status;
786                 req->state = RPC_REQUEST_DONE;
787                 DLIST_REMOVE(c->pending, req);
788                 if (req->async.callback) {
789                         req->async.callback(req);
790                 }
791                 return;
792         }
793
794         if (pkt.ptype == DCERPC_PKT_FAULT) {
795                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
796                 req->fault_code = pkt.u.fault.status;
797                 req->status = NT_STATUS_NET_WRITE_FAULT;
798                 req->state = RPC_REQUEST_DONE;
799                 DLIST_REMOVE(c->pending, req);
800                 if (req->async.callback) {
801                         req->async.callback(req);
802                 }
803                 return;
804         }
805
806         if (pkt.ptype != DCERPC_PKT_RESPONSE) {
807                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
808                          (int)pkt.ptype)); 
809                 req->fault_code = DCERPC_FAULT_OTHER;
810                 req->status = NT_STATUS_NET_WRITE_FAULT;
811                 req->state = RPC_REQUEST_DONE;
812                 DLIST_REMOVE(c->pending, req);
813                 if (req->async.callback) {
814                         req->async.callback(req);
815                 }
816                 return;
817         }
818
819         length = pkt.u.response.stub_and_verifier.length;
820
821         if (length > 0) {
822                 req->payload.data = talloc_realloc(req, 
823                                                    req->payload.data, 
824                                                    uint8_t,
825                                                    req->payload.length + length);
826                 if (!req->payload.data) {
827                         req->status = NT_STATUS_NO_MEMORY;
828                         req->state = RPC_REQUEST_DONE;
829                         DLIST_REMOVE(c->pending, req);
830                         if (req->async.callback) {
831                                 req->async.callback(req);
832                         }
833                         return;
834                 }
835                 memcpy(req->payload.data+req->payload.length, 
836                        pkt.u.response.stub_and_verifier.data, length);
837                 req->payload.length += length;
838         }
839
840         if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
841                 c->transport.send_read(c);
842                 return;
843         }
844
845         /* we've got the full payload */
846         req->state = RPC_REQUEST_DONE;
847         DLIST_REMOVE(c->pending, req);
848
849         if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
850                 req->flags |= DCERPC_PULL_BIGENDIAN;
851         } else {
852                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
853         }
854
855         if (req->async.callback) {
856                 req->async.callback(req);
857         }
858 }
859
860 /*
861   handle timeouts of individual dcerpc requests
862 */
863 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te, 
864                                    struct timeval t, void *private)
865 {
866         struct rpc_request *req = talloc_get_type(private, struct rpc_request);
867
868         if (req->state != RPC_REQUEST_PENDING) {
869                 return;
870         }
871
872         req->status = NT_STATUS_IO_TIMEOUT;
873         req->state = RPC_REQUEST_DONE;
874         DLIST_REMOVE(req->p->conn->pending, req);
875         if (req->async.callback) {
876                 req->async.callback(req);
877         }
878 }
879
880
881 /*
882   make sure requests are cleaned up 
883  */
884 static int dcerpc_req_destructor(void *ptr)
885 {
886         struct rpc_request *req = ptr;
887         DLIST_REMOVE(req->p->conn->pending, req);
888         return 0;
889 }
890
891 /*
892   perform the send side of a async dcerpc request
893 */
894 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
895                                         const struct GUID *object,
896                                         uint16_t opnum,
897                                         DATA_BLOB *stub_data)
898 {
899         struct rpc_request *req;
900         struct ncacn_packet pkt;
901         DATA_BLOB blob;
902         uint32_t remaining, chunk_size;
903         BOOL first_packet = True;
904
905         p->conn->transport.recv_data = dcerpc_request_recv_data;
906
907         req = talloc(p, struct rpc_request);
908         if (req == NULL) {
909                 return NULL;
910         }
911
912         req->p = p;
913         req->call_id = next_call_id(p->conn);
914         req->status = NT_STATUS_OK;
915         req->state = RPC_REQUEST_PENDING;
916         req->payload = data_blob(NULL, 0);
917         req->flags = 0;
918         req->fault_code = 0;
919         req->async.callback = NULL;
920
921         init_ncacn_hdr(p->conn, &pkt);
922
923         remaining = stub_data->length;
924
925         /* we can write a full max_recv_frag size, minus the dcerpc
926            request header size */
927         chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
928
929         pkt.ptype = DCERPC_PKT_REQUEST;
930         pkt.call_id = req->call_id;
931         pkt.auth_length = 0;
932         pkt.pfc_flags = 0;
933         pkt.u.request.alloc_hint = remaining;
934         pkt.u.request.context_id = p->context_id;
935         pkt.u.request.opnum = opnum;
936
937         if (object) {
938                 pkt.u.request.object.object = *object;
939                 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
940                 chunk_size -= ndr_size_GUID(object,0);
941         }
942
943         DLIST_ADD(p->conn->pending, req);
944
945         /* we send a series of pdus without waiting for a reply */
946         while (remaining > 0 || first_packet) {
947                 uint32_t chunk = MIN(chunk_size, remaining);
948                 BOOL last_frag = False;
949
950                 first_packet = False;
951                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
952
953                 if (remaining == stub_data->length) {
954                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
955                 }
956                 if (chunk == remaining) {
957                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
958                         last_frag = True;
959                 }
960
961                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
962                         (stub_data->length - remaining);
963                 pkt.u.request.stub_and_verifier.length = chunk;
964
965                 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
966                 if (!NT_STATUS_IS_OK(req->status)) {
967                         req->state = RPC_REQUEST_DONE;
968                         DLIST_REMOVE(p->conn->pending, req);
969                         return req;
970                 }
971                 
972                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
973                 if (!NT_STATUS_IS_OK(req->status)) {
974                         req->state = RPC_REQUEST_DONE;
975                         DLIST_REMOVE(p->conn->pending, req);
976                         return req;
977                 }               
978
979                 remaining -= chunk;
980         }
981
982         if (p->request_timeout) {
983                 event_add_timed(dcerpc_event_context(p), req, 
984                                 timeval_current_ofs(p->request_timeout, 0), 
985                                 dcerpc_timeout_handler, req);
986         }
987
988         talloc_set_destructor(req, dcerpc_req_destructor);
989
990         return req;
991 }
992
993 /*
994   return the event context for a dcerpc pipe
995   used by callers who wish to operate asynchronously
996 */
997 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
998 {
999         return p->conn->event_ctx;
1000 }
1001
1002
1003
1004 /*
1005   perform the receive side of a async dcerpc request
1006 */
1007 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1008                              TALLOC_CTX *mem_ctx,
1009                              DATA_BLOB *stub_data)
1010 {
1011         NTSTATUS status;
1012
1013         while (req->state == RPC_REQUEST_PENDING) {
1014                 struct event_context *ctx = dcerpc_event_context(req->p);
1015                 if (event_loop_once(ctx) != 0) {
1016                         return NT_STATUS_CONNECTION_DISCONNECTED;
1017                 }
1018         }
1019         *stub_data = req->payload;
1020         status = req->status;
1021         if (stub_data->data) {
1022                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1023         }
1024         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1025                 req->p->last_fault_code = req->fault_code;
1026         }
1027         talloc_free(req);
1028         return status;
1029 }
1030
1031 /*
1032   perform a full request/response pair on a dcerpc pipe
1033 */
1034 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1035                         struct GUID *object,
1036                         uint16_t opnum,
1037                         TALLOC_CTX *mem_ctx,
1038                         DATA_BLOB *stub_data_in,
1039                         DATA_BLOB *stub_data_out)
1040 {
1041         struct rpc_request *req;
1042
1043         req = dcerpc_request_send(p, object, opnum, stub_data_in);
1044         if (req == NULL) {
1045                 return NT_STATUS_NO_MEMORY;
1046         }
1047
1048         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1049 }
1050
1051
1052 /*
1053   this is a paranoid NDR validator. For every packet we push onto the wire
1054   we pull it back again, then push it again. Then we compare the raw NDR data
1055   for that to the NDR we initially generated. If they don't match then we know
1056   we must have a bug in either the pull or push side of our code
1057 */
1058 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1059                                        TALLOC_CTX *mem_ctx,
1060                                        DATA_BLOB blob,
1061                                        size_t struct_size,
1062                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1063                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1064 {
1065         void *st;
1066         struct ndr_pull *pull;
1067         struct ndr_push *push;
1068         NTSTATUS status;
1069         DATA_BLOB blob2;
1070
1071         st = talloc_size(mem_ctx, struct_size);
1072         if (!st) {
1073                 return NT_STATUS_NO_MEMORY;
1074         }
1075
1076         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1077         if (!pull) {
1078                 return NT_STATUS_NO_MEMORY;
1079         }
1080         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1081
1082         status = ndr_pull(pull, NDR_IN, st);
1083         if (!NT_STATUS_IS_OK(status)) {
1084                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1085                                       "failed input validation pull - %s",
1086                                       nt_errstr(status));
1087         }
1088
1089         push = ndr_push_init_ctx(mem_ctx);
1090         if (!push) {
1091                 return NT_STATUS_NO_MEMORY;
1092         }       
1093
1094         status = ndr_push(push, NDR_IN, st);
1095         if (!NT_STATUS_IS_OK(status)) {
1096                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1097                                       "failed input validation push - %s",
1098                                       nt_errstr(status));
1099         }
1100
1101         blob2 = ndr_push_blob(push);
1102
1103         if (!data_blob_equal(&blob, &blob2)) {
1104                 DEBUG(3,("original:\n"));
1105                 dump_data(3, blob.data, blob.length);
1106                 DEBUG(3,("secondary:\n"));
1107                 dump_data(3, blob2.data, blob2.length);
1108                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1109                                       "failed input validation data - %s",
1110                                       nt_errstr(status));
1111         }
1112
1113         return NT_STATUS_OK;
1114 }
1115
1116 /*
1117   this is a paranoid NDR input validator. For every packet we pull
1118   from the wire we push it back again then pull and push it
1119   again. Then we compare the raw NDR data for that to the NDR we
1120   initially generated. If they don't match then we know we must have a
1121   bug in either the pull or push side of our code
1122 */
1123 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1124                                         TALLOC_CTX *mem_ctx,
1125                                         void *struct_ptr,
1126                                         size_t struct_size,
1127                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1128                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1129 {
1130         void *st;
1131         struct ndr_pull *pull;
1132         struct ndr_push *push;
1133         NTSTATUS status;
1134         DATA_BLOB blob, blob2;
1135
1136         st = talloc_size(mem_ctx, struct_size);
1137         if (!st) {
1138                 return NT_STATUS_NO_MEMORY;
1139         }
1140         memcpy(st, struct_ptr, struct_size);
1141
1142         push = ndr_push_init_ctx(mem_ctx);
1143         if (!push) {
1144                 return NT_STATUS_NO_MEMORY;
1145         }       
1146
1147         status = ndr_push(push, NDR_OUT, struct_ptr);
1148         if (!NT_STATUS_IS_OK(status)) {
1149                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1150                                       "failed output validation push - %s",
1151                                       nt_errstr(status));
1152         }
1153
1154         blob = ndr_push_blob(push);
1155
1156         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1157         if (!pull) {
1158                 return NT_STATUS_NO_MEMORY;
1159         }
1160
1161         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1162         status = ndr_pull(pull, NDR_OUT, st);
1163         if (!NT_STATUS_IS_OK(status)) {
1164                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1165                                       "failed output validation pull - %s",
1166                                       nt_errstr(status));
1167         }
1168
1169         push = ndr_push_init_ctx(mem_ctx);
1170         if (!push) {
1171                 return NT_STATUS_NO_MEMORY;
1172         }       
1173
1174         status = ndr_push(push, NDR_OUT, st);
1175         if (!NT_STATUS_IS_OK(status)) {
1176                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1177                                       "failed output validation push2 - %s",
1178                                       nt_errstr(status));
1179         }
1180
1181         blob2 = ndr_push_blob(push);
1182
1183         if (!data_blob_equal(&blob, &blob2)) {
1184                 DEBUG(3,("original:\n"));
1185                 dump_data(3, blob.data, blob.length);
1186                 DEBUG(3,("secondary:\n"));
1187                 dump_data(3, blob2.data, blob2.length);
1188                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1189                                       "failed output validation data - %s",
1190                                       nt_errstr(status));
1191         }
1192
1193         return NT_STATUS_OK;
1194 }
1195
1196
1197 /*
1198  send a rpc request given a dcerpc_call structure 
1199  */
1200 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1201                                                 const struct GUID *object,
1202                                                 const struct dcerpc_interface_table *table,
1203                                                 uint32_t opnum, 
1204                                                 TALLOC_CTX *mem_ctx, 
1205                                                 void *r)
1206 {
1207         const struct dcerpc_interface_call *call;
1208         struct ndr_push *push;
1209         NTSTATUS status;
1210         DATA_BLOB request;
1211         struct rpc_request *req;
1212
1213         call = &table->calls[opnum];
1214
1215         /* setup for a ndr_push_* call */
1216         push = ndr_push_init_ctx(mem_ctx);
1217         if (!push) {
1218                 return NULL;
1219         }
1220
1221         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1222                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1223         }
1224
1225         /* push the structure into a blob */
1226         status = call->ndr_push(push, NDR_IN, r);
1227         if (!NT_STATUS_IS_OK(status)) {
1228                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1229                          nt_errstr(status)));
1230                 talloc_free(push);
1231                 return NULL;
1232         }
1233
1234         /* retrieve the blob */
1235         request = ndr_push_blob(push);
1236
1237         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1238                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1239                                                 call->ndr_push, call->ndr_pull);
1240                 if (!NT_STATUS_IS_OK(status)) {
1241                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1242                                  nt_errstr(status)));
1243                         talloc_free(push);
1244                         return NULL;
1245                 }
1246         }
1247
1248         DEBUG(10,("rpc request data:\n"));
1249         dump_data(10, request.data, request.length);
1250
1251         /* make the actual dcerpc request */
1252         req = dcerpc_request_send(p, object, opnum, &request);
1253
1254         if (req != NULL) {
1255                 req->ndr.table = table;
1256                 req->ndr.opnum = opnum;
1257                 req->ndr.struct_ptr = r;
1258                 req->ndr.mem_ctx = mem_ctx;
1259         }
1260
1261         talloc_free(push);
1262
1263         return req;
1264 }
1265
1266 /*
1267   receive the answer from a dcerpc_ndr_request_send()
1268 */
1269 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1270 {
1271         struct dcerpc_pipe *p = req->p;
1272         NTSTATUS status;
1273         DATA_BLOB response;
1274         struct ndr_pull *pull;
1275         uint_t flags;
1276         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1277         void *r = req->ndr.struct_ptr;
1278         uint32_t opnum = req->ndr.opnum;
1279         const struct dcerpc_interface_table *table = req->ndr.table;
1280         const struct dcerpc_interface_call *call = &table->calls[opnum];
1281
1282         /* make sure the recv code doesn't free the request, as we
1283            need to grab the flags element before it is freed */
1284         talloc_increase_ref_count(req);
1285
1286         status = dcerpc_request_recv(req, mem_ctx, &response);
1287         if (!NT_STATUS_IS_OK(status)) {
1288                 return status;
1289         }
1290
1291         flags = req->flags;
1292
1293         /* prepare for ndr_pull_* */
1294         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1295         if (!pull) {
1296                 talloc_free(req);
1297                 return NT_STATUS_NO_MEMORY;
1298         }
1299
1300         if (pull->data) {
1301                 pull->data = talloc_steal(pull, pull->data);
1302         }
1303         talloc_free(req);
1304
1305         if (flags & DCERPC_PULL_BIGENDIAN) {
1306                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1307         }
1308
1309         DEBUG(10,("rpc reply data:\n"));
1310         dump_data(10, pull->data, pull->data_size);
1311
1312         /* pull the structure from the blob */
1313         status = call->ndr_pull(pull, NDR_OUT, r);
1314         if (!NT_STATUS_IS_OK(status)) {
1315                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1316                                   &response);
1317                 return status;
1318         }
1319
1320         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1321                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1322                                                  call->ndr_push, call->ndr_pull);
1323                 if (!NT_STATUS_IS_OK(status)) {
1324                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1325                                   &response);
1326                         return status;
1327                 }
1328         }
1329
1330         if (pull->offset != pull->data_size) {
1331                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1332                          pull->data_size - pull->offset));
1333                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1334                    but it turns out that early versions of NT
1335                    (specifically NT3.1) add junk onto the end of rpc
1336                    packets, so if we want to interoperate at all with
1337                    those versions then we need to ignore this error */
1338         }
1339
1340         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1341
1342         return NT_STATUS_OK;
1343 }
1344
1345
1346 /*
1347   a useful helper function for synchronous rpc requests 
1348
1349   this can be used when you have ndr push/pull functions in the
1350   standard format
1351 */
1352 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1353                             const struct GUID *object,
1354                             const struct dcerpc_interface_table *table,
1355                             uint32_t opnum, 
1356                             TALLOC_CTX *mem_ctx, 
1357                             void *r)
1358 {
1359         struct rpc_request *req;
1360
1361         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1362         if (req == NULL) {
1363                 return NT_STATUS_NO_MEMORY;
1364         }
1365
1366         return dcerpc_ndr_request_recv(req);
1367 }
1368
1369
1370 /*
1371   a useful function for retrieving the server name we connected to
1372 */
1373 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1374 {
1375         if (!p->conn->transport.peer_name) {
1376                 return "";
1377         }
1378         return p->conn->transport.peer_name(p->conn);
1379 }
1380
1381
1382 /*
1383   get the dcerpc auth_level for a open connection
1384 */
1385 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1386 {
1387         uint8_t auth_level;
1388
1389         if (c->flags & DCERPC_SEAL) {
1390                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1391         } else if (c->flags & DCERPC_SIGN) {
1392                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1393         } else if (c->flags & DCERPC_CONNECT) {
1394                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1395         } else {
1396                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1397         }
1398         return auth_level;
1399 }
1400
1401
1402 /* 
1403    send a dcerpc alter_context request
1404 */
1405 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1406                               TALLOC_CTX *mem_ctx,
1407                               const struct dcerpc_syntax_id *syntax,
1408                               const struct dcerpc_syntax_id *transfer_syntax)
1409 {
1410         struct ncacn_packet pkt;
1411         NTSTATUS status;
1412         DATA_BLOB blob;
1413
1414         p->syntax = *syntax;
1415         p->transfer_syntax = *transfer_syntax;
1416
1417         init_ncacn_hdr(p->conn, &pkt);
1418
1419         pkt.ptype = DCERPC_PKT_ALTER;
1420         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1421         pkt.call_id = p->conn->call_id;
1422         pkt.auth_length = 0;
1423
1424         pkt.u.alter.max_xmit_frag = 5840;
1425         pkt.u.alter.max_recv_frag = 5840;
1426         pkt.u.alter.assoc_group_id = 0;
1427         pkt.u.alter.num_contexts = 1;
1428         pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1429         if (!pkt.u.alter.ctx_list) {
1430                 return NT_STATUS_NO_MEMORY;
1431         }
1432         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1433         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1434         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1435         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1436         pkt.u.alter.auth_info = data_blob(NULL, 0);
1437
1438         /* construct the NDR form of the packet */
1439         status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1440         if (!NT_STATUS_IS_OK(status)) {
1441                 return status;
1442         }
1443
1444         /* send it on its way */
1445         status = full_request(p->conn, mem_ctx, &blob, &blob);
1446         if (!NT_STATUS_IS_OK(status)) {
1447                 return status;
1448         }
1449
1450         /* unmarshall the NDR */
1451         status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1452         if (!NT_STATUS_IS_OK(status)) {
1453                 return status;
1454         }
1455
1456         if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1457             pkt.u.alter_resp.num_results == 1 &&
1458             pkt.u.alter_resp.ctx_list[0].result != 0) {
1459                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1460                          pkt.u.alter_resp.ctx_list[0].reason));
1461                 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1462         }
1463
1464         if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1465             pkt.u.alter_resp.num_results == 0 ||
1466             pkt.u.alter_resp.ctx_list[0].result != 0) {
1467                 return NT_STATUS_UNSUCCESSFUL;
1468         }
1469
1470         /* the alter_resp might contain a reply set of credentials */
1471         if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1472                 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1473                                               mem_ctx,
1474                                               p->conn->security_state.auth_info,
1475                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1476         }
1477
1478         return status;  
1479 }